Skip to content

Green was the thing forcing the safe path (revert T-1503, harden the handoff) - #766

Merged
MongLong0214 merged 3 commits into
mainfrom
revert-t1503
Aug 18, 2026
Merged

Green was the thing forcing the safe path (revert T-1503, harden the handoff)#766
MongLong0214 merged 3 commits into
mainfrom
revert-t1503

Conversation

@MongLong0214

Copy link
Copy Markdown
Owner

Reverts 532c30f4 and hardens the handoff it was built on top of.

Why T-1503 is rejected rather than fixed

It made a source-only pull request green. Green is mergeable, and the button then lands src/ with no rebuilt dist/main carrying a bundle that does not match its source until the next push run goes red, after the fact rather than before it.

#761 was red, and that redness is why it went through canonical-merge instead of through its own merge button. The friction was the mechanism.

What T-1503 was written to fix is already fixed by T-1502, without the risk: a contributor opens the source-only pull request and never rebuilds anything. Its checks being red is a statement about the artifact, not a demand on them.

The measurement T-1503 produced is kept in the ticket, because it is the part worth having: "drop the diff line" was wrong, since CI rebuilds before it verifies and a source-only pull request dies at artifact:verify without ever reaching the diff.

The handoff was proven against a pull request the owner wrote

publish carried a comment saying it "only moves bytes it verifies", and it verified none of them.

what before now
bundle contents force-pushed as received merge recomputed here from main + the PR ref; both parents pinned; a difference allowed only inside dist/ and the manifest
PR head race unchecked refused if #N's head moved since the rebuild fetched it, and if the ref no longer resolves to it
push result git push exit code ref read back by sha; refused if the server holds anything else
App token body-less mint — every permission on every repository the installation holds scoped to this repository, contents: write + pull_requests: write

The rebuild job runs a contributor's package.json and every lifecycle script npm ci pulls in. Anything there could add a commit touching src/, scripts/ or .github/, and this job would have force-pushed it under the App's identity for a reviewer to read as a rebuild.

T-1504 and the PRD

T-1504's acceptance moves from a person-observation"a non-Linux contributor completing a source change unaided" — to the system properties it was standing in for. That gate cannot be satisfied from inside the repository, so it left the work permanently unfinished for a reason unrelated to the work. It was also indifferent to what it named: the canonical build never runs on a contributor's machine, so "non-Linux" was a proxy for "cannot run the canonical build" and the mechanism does not distinguish the two.

Field experience is recorded as a Limit instead: adoption evidence, not a correctness gate. A real-world failure reopens #719 or opens a defect issue.

The PRD's success criteria are fixed against the runs that show them. The old first criterion — "no pull request carries dist/" — is contradicted by the thing that was built: the canonical pull request carries exactly that, and carrying it is how the required contexts run on the tree that lands.

Verified

Reverting the hardening fails all three new workflow assertions; restoring it passes nineteen.

The ordering assertion for the credential step was matching the other job's identically-named step after a rename — both jobs check that main stood still — so it was asserting nothing about the publishing job. Re-anchored on the renamed step and extended to cover the new verification.

ci.yml's locked digest is back to 473b1fc0… and matches the file.

Still open, and it needs the owner

Merge-commit-only is not enforced. It is a sentence in a pull request body, which is a check somebody has to read — the exact shape that cost #752 its merged label during the 1.1.3 release. The repository still allows squash and rebase, and the merge button remembers the last method used.

gh api -X PUT repos/MongLong0214/commitlore -F allow_squash_merge=false -F allow_rebase_merge=false

Recorded as the Limit on this commit until it is done.

Reverts 532c30f and hardens the handoff it was built on top of.

T-1503 made a source-only pull request green. Green is mergeable, and the
button then lands `src/` with no rebuilt `dist/` -- `main` carrying a bundle
that does not match its source until the next push run goes red, after the fact
rather than before it. #761 was red, and that redness is why it went through
`canonical-merge` instead of through its own merge button. The friction was the
mechanism.

What T-1503 was written to fix is already fixed by T-1502 and without the risk:
a contributor opens the source-only pull request and never rebuilds anything.
Its checks being red is a statement about the artifact, not a demand on them.
The measurement T-1503 produced is kept in the ticket, because it is the part
worth having: "drop the diff line" was wrong, since CI rebuilds before it
verifies and a source-only pull request dies at `artifact:verify`.

Then the handoff, which was proven against a pull request the owner wrote and
not against one a stranger wrote.

`publish` said it "only moves bytes it verifies" and verified none of them. The
rebuild job runs a contributor's `package.json` and every lifecycle script `npm
ci` pulls in; anything there could add a commit touching `src/`, `scripts/` or
`.github/`, and this job would force-push it under the App's identity for a
reviewer to read as a rebuild. It now recomputes the merge itself from `main`
and the pull request ref -- neither writable from the first job -- pins both
parents, and allows a difference only inside `dist/` and the manifest.

It also refuses a pull request that moved, not only a moved `main`: a
force-push between the first job's fetch and the push would leave the canonical
pull request carrying a head nobody reviewed while #N displays something else.

The push is read back by sha. `git push` exiting zero says the push was
accepted, not that the branch is still what this run put there.

The App token is asked for narrowly rather than taken whole. A body-less mint
carries every permission the installation holds on every repository it is
installed on, and grows silently as the installation grows; it is now scoped to
this repository with `contents: write` and `pull_requests: write`.

T-1504's acceptance moves from a person-observation to the system properties it
was standing in for, and the PRD's success criteria are fixed against the runs
that show them. The old first criterion -- "no pull request carries `dist/`" --
is contradicted by the thing that was built: the canonical pull request carries
exactly that, and carrying it is how the required contexts run on the tree that
lands.

Limit: merge-commit-only is still a sentence in a pull request body rather than a repository setting, so a squash remains one click away and would leave the source pull request open
Blast: module
Undo: easy
Certainty: firm
Verified: reverting the hardening fails all three new workflow assertions and restoring it passes nineteen; the ordering assertion for the credential step was matching the other job's identically-named step after a rename and was re-anchored; ci.yml's locked digest is back to 473b1fc0 and matches the file
Record-Id: r-t1503revert
Provenance: authored
CommitLore-Version: 2.0.0
@github-actions

github-actions Bot commented Aug 18, 2026

Copy link
Copy Markdown

CommitLore — record lint

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

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

The ticket said the method "is not enforceable from here" and handed the
choice to the owner. That was wrong in a specific way: it was enforceable, it
just was not enforced. `allow_squash_merge` and `allow_rebase_merge` are now
off, so a merge commit is the only method GitHub offers on this repository.

The canonical pull request depends on its head commit staying an ancestor, and
a squash lands new bytes instead -- leaving the source pull request open with
nothing to point at. Until now the only thing holding that was a sentence in
the body asking for a merge commit, which is a check somebody has to read.
#752 is what that costs: during the 1.1.3 release a body sentence failed in
the seat next to this one, and there is no API to convert a pull request from
closed to merged afterwards.

What this moves rather than removes is written down too. The guarantee now
lives in a repository setting, which nothing in this repository reads: a future
owner can re-enable squash and no test, workflow or gate here will notice --
only a canonical pull request quietly failing to close its source.

Limit: nothing in this repository can read the setting, so the only signal that it was reverted is a source pull request left open after a canonical merge
Blast: local
Undo: easy
Certainty: firm
Record-Id: r-squashoff818
Provenance: authored
Verified: read back from the API after the change -- merge=true squash=false rebase=false
CommitLore-Version: 2.0.0
@MongLong0214

Copy link
Copy Markdown
Owner Author

Merge-commit-only is now enforced. The owner directed it and it landed; I read it back from the API rather than taking it on report:

merge=true  squash=false  rebase=false

So the Limit on the first commit here is out of date, and c5287b2 corrects it rather than amending — the branch is pushed, and the record's Record-Id cannot appear twice.

The ticket said the method "is not enforceable from here" and handed the choice to the owner. That was wrong in a specific way: it was enforceable, it just was not enforced.

before   the body asks for a merge commit        the seat where the name is written
after    squash does not exist on this repo      the seat where it is enforced

The canonical pull request's body still says it, for a reader who wants to know why the branch is shaped that way. It is no longer what holds the property.

What moved rather than disappeared, recorded as the new Limit: the guarantee now lives in a repository setting that nothing in this repository reads. A future owner can re-enable squash and no test, workflow or gate here will notice — only a canonical pull request quietly failing to close its source. Smaller surface than a sentence in a body, and not zero.

The inline version required the canonical branch tip to have two parents. A
real tip has one. #762's `6a88f2f4` is a rebuild commit whose parent
`acfed4a5` is the two-parent merge, because the rebuild commits on top of the
merge whenever `dist/` actually changes -- which is the ordinary case, not an
edge one.

The tests I wrote for it passed. They grep the workflow as text, and text
cannot be run. So the check moves into `scripts/verify-canonical-handoff.mjs`,
where the invariant is a commit graph and a graph can be built and mutated.

`test/verify-canonical-handoff.test.ts` builds a repository shaped like a real
run -- main with a committed bundle, a source-only branch, a `--no-ff` merge, a
rebuild on top -- and applies one mutation per case:

  a workflow file added to the rebuild commit      refused, names the path
  a source file added to the rebuild commit        refused, names the path
  the merge's second parent replaced               refused, names both commits
  an edit amended into the merge itself            refused on the tree, right parents
  a source branch carrying `dist/` itself          refused before anything else
  two commits stacked on the merge                 refused -- one rebuild, not two
  the two honest shapes                            accepted

The tree check is the one the parent check cannot do. `git merge-tree
--write-tree` recomputes the merge here from the two commits the caller
resolved from GitHub, so a merge with the right parents and a smuggled edit
does not survive having the right shape.

The workflow-text test now asserts the inline form is *gone*, so it cannot
return without the graph tests coming with it.

Limit: the script trusts the two shas it is given, so it is only as good as the caller resolving them from GitHub rather than from the bundle
Blast: module
Undo: easy
Certainty: firm
Record-Id: r-handoffgraph
Provenance: authored
Verified: run against the real #762 handoff -- base ba9b0cf, source 09a1890, tip 6a88f2f -- which it accepts and which the inline version would have refused; deleting the script fails all eight graph tests and restoring it passes them
CommitLore-Version: 2.0.0
@MongLong0214
MongLong0214 merged commit bc24ea2 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