Skip to content
Skip to main content
Novel Systems home
Decision log
D-090August 5, 2026

Publish the workflow definitions, not a run history

Affects: scripts/build-pipeline-report.mjs, public/pipeline.yml, public/pipeline.json, lib/engineering-evidence.ts, lib/engineering-practice.ts, app/engineering/page.tsx, app/security/page.tsx, next.config.mjs, package.json

Decision

The CI workflows are published as fetchable artifacts — /pipeline.yml for the definitions verbatim, /pipeline.json for the derived shape the page renders — generated from .github/workflows and drift-checked on every build by check:pipeline, the twentieth check in the verify chain. /engineering#ci renders every workflow, job and step from that JSON, and states in as many words why there is no status badge beside it.

What is not published is a run history. No run numbers, no conclusions, no "last build passed". That absence is deliberate and is written on the page.

What produced it

The Task 5 review said the tests were "not fully accomplished in a public, inspectable way", and listed what was missing. Four of the five items were closed by the coverage work in D-086 and the /security figures shipped in 745655b. The fifth was not: *"no public CI log or badge tied to test execution."*

A three-route probe of served bytes confirmed it exactly. /engineering and /security between them said work is checked "on every push" four times, and neither page contained the string GitHub Actions, a badge, a run id, a workflow filename, or a single job name. The site asserted a pipeline and published nothing a stranger could open.

public/schema.sql had already said so. Its generated preamble carries the line -- Rendered inventory, coverage and CI history: /engineering — a published artifact promising a section that did not exist, written before anyone noticed the gap.

Why not a badge

Because it does not work here, and the reason is structural rather than a matter of effort. This repository is private. A shields.io workflow badge against a private repo renders "not found", and an Actions run log answers a stranger with a 404 or a login wall. The conventional proof of "our CI runs" is genuinely closed off, and no amount of markup opens it.

That leaves two options: publish something else, or leave four sentences unsupported. Leaving them unsupported is what produced the finding, and a reviewer who looks for evidence and finds none does not record "inconclusive" — they record "there is none", which is the ninth time this repository has been told that about an artifact it actually had.

Why the definitions are the honest exhibit

A workflow file is not a claim about a run; it is the thing that runs. It names the jobs, the versions, the commands, the Postgres service, the coverage flags and the order they execute in. A reader who wants to know what npm run verify is gated on can read the twenty checks in ci.yml rather than take our word for the number — and check:pipeline fails the build if the copy they read has drifted from the copy that executes.

It is weaker evidence than a run log in exactly one respect: it proves what is configured to happen, not that it happened. That gap is why the coverage artifact exists and why the page points at it. public/coverage.json records one real execution — achieved figures, test counts, runner invocation, timestamp, and a SHA-256 of the backend source tree that produced them — so a figure that outlives its code fails check:coverage. Between the two, a reviewer has what runs and what one run achieved.

Why not commit a run history

It was the obvious next step and it is the wrong one. Run conclusions live behind an authenticated GitHub API. A file in this repository asserting "run #86 of CI completed successfully" would be a hand-entered claim about a system the reader cannot open to check — which is precisely the defect this whole chain of work exists to remove, reintroduced in the act of appearing to close it. Worse, it would look identical to evidence.

The honest form of that sentence is the one now on the page: run logs exist, we cannot make them public because the repository is private, and they are available in the security package on request.

What would make this wrong

Making the repository public. At that point a badge and a linked run log are both real, strictly better than a static definition, and this artifact becomes redundant to everything except the drift check. If that happens, keep check:pipeline — the value of a published definition that provably matches the executing one does not depend on the repository's visibility — and replace the "why there is no status badge here" panel with the badge.