Skip to content

A pull request may arrive without the artifact (#719, T-1503) - #764

Merged
MongLong0214 merged 1 commit into
mainfrom
t1503-source-only-pr
Aug 18, 2026
Merged

A pull request may arrive without the artifact (#719, T-1503)#764
MongLong0214 merged 1 commit into
mainfrom
t1503-source-only-pr

Conversation

@MongLong0214

Copy link
Copy Markdown
Owner

T-1502 is proven on a real merge — #761 carried source only, canonical-merge rebuilt it, and e4e5154 landed with artifact:verify and git diff -- dist/ both clean and nobody having built anything by hand. That was T-1503's stated dependency, so this is the next step.

"Drop the diff line" was wrong, and #761 is the run that shows it

CI builds before it verifies. After build:canonical the tree holds a bundle made from the new source while the committed manifest still describes the old one, so on a source-only pull request all three checksum comparisons fail together and git diff is never reached:

ERROR: canonical artifact verification failed:
  - source checksum does not match this checkout
  - dist file list or a dist file checksum does not match the canonical manifest
  - dist aggregate checksum does not match the canonical manifest

That is exactly how #720 failed. Removing the diff line would not have moved it.

The second mode

--contract-only keeps what the manifest declares and drops what it records. Platform, image, build command, runtime asset list, source input list — none of those move when source moves, so a pull request has no honest reason to touch them, and this mode still refuses one that does.

Measured by exit code, read directly rather than through a pipe:

case strict --contract-only
clean tree 0 0
source moved, bundle did not 1 0
manifest's declared platform edited 1 1
with RELEASE_COMMIT set 2

The success line is worded differently on purpose — canonical artifact contract intact (checksums not compared) — so a reader scanning a log for canonical artifact verified cannot find it on a run that never compared them.

What this gives up

On the source-only path, nothing checks that the committed manifest tells the truth about the committed bundle.

That is not theoretical. It is the property #763 was built to falsify, and it did: a hand-edited dist/commitlore.mjs with src/ untouched passed artifact:verify completely and was caught only by the rebuild-and-diff after it (the run).

That property now lives on the push and tag paths, and in canonical-merge.yml, which regenerates the manifest rather than trusting one.

The relaxation is conditional, not blanket

A pull request that does carry dist/ or the manifest is checked exactly as before. The old path stays available as a fallback rather than being replaced. The decision is read from the commit range before the build runs, because afterwards the tree describes what the job just built rather than what the author pushed.

Reproducibility — two canonical builds compared byte for byte — runs in both modes. It asks whether the builder is deterministic, which has nothing to do with what the author pushed.

Verified

Reverting the second mode fails all three new tests; restoring it passes seven.

The tampered-contract test initially passed in both directions — with the mode and without it — because editing only the manifest leaves strict and relaxed reporting the same line. It was strengthened by moving source as well, so the two modes have something to disagree about, and it now fails on the negative control like the other two.

EXPECTED_CI_WORKFLOW_SHA256 re-locked to 24f749bb…; test/release-publish-prerequisites.test.ts passes 29.

Not in this pull request

T-1503's acceptance — a pull request touching src/ with no dist/ change is green — needs a pull request that touches src/. This one does not, so it will be observed on the next one after this lands.

… costs

T-1503, now that T-1502 has been proven on a real merge: #761 carried source
only, `canonical-merge` rebuilt it, and `e4e5154` landed with `artifact:verify`
and `git diff -- dist/` both clean and nobody having built anything by hand.

"Drop the diff line" was wrong, and the run that showed it is on #761. CI builds
before it verifies, so after `build:canonical` the tree holds a bundle made from
the new source while the committed manifest still describes the old one. All
three checksum comparisons fail together and the diff is never reached -- which
is exactly how #720 failed. So the verifier gets a second mode instead.

`--contract-only` keeps what the manifest *declares* and drops what it
*records*. The platform, the image, the build command, the runtime asset list
and the source input list do not move when source moves, so a pull request has
no honest reason to touch them and this mode still refuses one that does. It
refuses to combine with `RELEASE_COMMIT` as well: a release is the one place the
recorded checksums have to be the reason it is allowed.

**What is given up.** On the source-only path nothing checks that the committed
manifest tells the truth about the committed bundle. That is not theoretical --
it is the property #763 was built to falsify, and it did: a hand-edited
`dist/commitlore.mjs` with `src/` untouched passed `artifact:verify` completely
and was caught only by the rebuild-and-diff after it. That property now lives on
the push and tag paths, and in `canonical-merge.yml`, which regenerates the
manifest rather than trusting one.

The relaxation is conditional rather than blanket. A pull request that does
carry `dist/` or the manifest is still checked in full, so the old path stays
available as a fallback instead of being replaced. The decision is read from the
commit range before the build runs, because afterwards the tree describes what
this job just built.

Limit: the mode is chosen from the pull request's changed paths, so a pull request that carries the artifact unchanged from base is checked in full and one that carries none is not checked against a committed bundle at all
Blast: module
Undo: easy
Certainty: firm
Record-Id: r-t1503mode
Provenance: authored
Verified: reverting the second mode fails all three new tests and restoring it passes seven; the tampered-contract test was first passing in both directions and was strengthened until it could tell them apart; exit codes read directly rather than through a pipe -- 1 for a tampered contract, 2 for RELEASE_COMMIT, 0 for source-only
CommitLore-Version: 2.0.0
@github-actions

Copy link
Copy Markdown

CommitLore — record lint

Trailers: clean — 1 commit in origin/main..34af9068941edfe6089c5d74b33a3c3a789573db
Active constraints: not read — commitlore: git log --follow accepts exactly one pathspec, so renames are not followed for 4 paths; query one path at a time to follow its rename chain (4 changed paths)

Trailer violations fail this check. Active constraints are informational — they are what the repository already decided, not a verdict on this PR.

@MongLong0214
MongLong0214 merged commit 532c30f into main Aug 18, 2026
12 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant