feat(governance): add downstream sync provenance mode - #33
Conversation
Conflicted main -> internal/main sync pull requests had no resolution route that could satisfy the required reconcile check.
…ummary Review found the mode could not pass CI at all: writeEvidence fell through to the upstream-import renderer and dereferenced mergeParents. It also found the ahead/identical containment check was satisfied by any branch that merges main, leaving one approval to authorise unrestricted paths.
|
Review found two real defects. Both fixed in 7c989b1. The mode could not pass CI at all. The containment check did not constrain content. Also addressed: Not addressed, deliberately: Tests 41 -> 44, format and lint clean. |
GitHub refuses to let a PR author approve their own pull request, so the self-approval fix in #34 was necessary but not sufficient: a solo-maintainer PR could still never produce an APPROVED review, which permanently deadlocked the required reconcile status check. Provenance metadata is the audit trail now; no mode asserts a review.
# Conflicts: # docs/fork-governance.md # scripts/check-upstream-provenance.mjs
…nance # Conflicts: # docs/fork-governance.md # scripts/check-upstream-provenance.mjs
|
Rebased onto #35 ( #35 found something that invalidates part of this PR's design, and I want it on the record rather than buried in a rebase. Sync mode required a human approval. GitHub blocks self-approval at the platform level, and the other four Changes in the rebase:
What sync mode now guarantees, stated plainly so nobody has to re-derive it: the merge shape constrains commit topology, not tree content. A merge commit can carry arbitrary content as "conflict resolution" and this gate will pass it. With review gone repo-wide, nothing mechanical stops an unrelated edit riding along in a sync pull request. That is a deliberate choice, not an oversight — the alternative considered was recomputing the merge with Tests 38/38 (the count moved because #35 removed the approval suite), format and lint clean. |
# Conflicts: # docs/fork-governance.md # scripts/check-upstream-provenance.mjs # scripts/check-upstream-provenance.test.mjs
Downstream governance: true
Problem
The
internal/mainandmainrulesets were active but their ref patterns contained literal quotes (refs/heads/"internal/main"), so they matched no refs and enforced nothing. With the patterns corrected, a conflictedmain->internal/mainsync pull request became unresolvable by anyone but the sync app:internal/main— blocked by thepull_requestrulemain, breaking the mirrorreconcileis a required check and no existing mode passes (upstream-importwants per-PR upstream metadata;downstream-governancerestricts paths to the allowlist;downstream-featureforbids.github/workflows/**, which upstream merges always touch)Change
Adds a fourth exception mode,
Downstream sync: true. It is gated on the pull-request head containing forkmainverbatim (comparison statusaheadoridentical) plus one non-author human approval of the current head, so it cannot be used to smuggle unrelated work in. Changed paths are unrestricted because the content is upstream's plus the conflict resolution.Test plan
node --test scripts/check-upstream-provenance.test.mjs— 16/16npm run format:checkclean,npm run typecheckcleanDOWNSTREAM_GOVERNANCE_PATHS, so this PR qualifies for its ownDownstream governance: truemarker