docs/UPSTREAM-SYNC.md — the recurring upstream sync, its standing resolutions, and a guard on where the forge delta lives #200
Labels
No labels
attention
blocked
blocker:ci-red
blocker:conflict
blocker:drill-pending
blocker:unrequested
bug
claimed
documentation
enhancement
epic
merge-next
needs-ruling
needs-triage
offsite
post-merge
ready
release
scope:docs
scope:guards
scope:labels
scope:release-flow
stale
state:addressing
state:bots-reviewing
state:building
state:needs-human
No milestone
No project
No assignees
3 participants
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference: heavy-duty/ceremony#200
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Context
Part of #197.
Blocked by #198, which performs the first sync and is theworked example this document describes.
#197 decision 3 makes the upstream sync recurring: GitHub stays the source
of new ceremony features and is read-only; this forge carries the
forge-compatibility delta on top and never writes back. That arrangement has a
cost that grows silently — every upstream release lands on files this tree has
already modified — and right now the whole procedure exists only as the
reasoning in #197 and #198, which is to say only in two issue bodies.
The first sync measured the cost precisely: 157 upstream commits produced
18 conflict hunks, of which 13 were mechanical and 5 needed a decision.
lib/forge*.shproduced none. That ratio is the thing worth preserving, andit is preserved by where the delta lives, not by luck.
This repo's own convention is that a decision living only in prose is a
decision waiting to rot (CONTRIBUTING, "Every piece of logic is a file of its
own so a test can drive it"). The sync is not logic and gets no script here —
it gets a runbook and one guard.
Spec
1.
docs/UPSTREAM-SYNC.md— the procedure. Written as a runbook an agentor operator follows without prior context:
PR, comment or release is ever created there;
merge-base has moved;
git merge, not rebase, and why (#197 decision 1);each time:
.github/labels.confkeeps this forge's roster (#195);drills/*.mdkeep this forge's records;VERSIONandCEREMONY_SELF_REFtake upstream's numbers (#197 decision 2);
ghcall site the merge introducedand either port it or declare
CEREMONY_FORGE_CLIENT=ghso it refusesloudly (#197 decision 4);
2.
docs/CONSUMERS.mdgains a short section stating that this tree'sversion numbers track upstream's, that two trees therefore answer to the same
number, and how a consumer names which one it pinned. Consumers read that file
already; the fact belongs where they look.
3. One guard, not a suite: the delta inventory.
docs/UPSTREAM-SYNC.mdcarries the list of files that hold forge-specific behaviour — today
lib/forge.sh,lib/forge-github.sh,lib/forge-forgejo.sh,lib/closes_references.sh,.github/labels.conf,drills/. A test assertsthe inventory names every file that differs from upstream's tree in a
forge-specific way, so a future sync that scatters forge branching into a
seventh file fails on the PR that does it rather than being discovered by the
sync after next.
The guard compares against a recorded upstream ref, not a live fetch:
tests must not require the network, and a guard that silently passes when
offline is the blind-sweep shape this repo keeps writing issues about. The ref
is a file in the repo, updated by each sync.
4. What this issue does not do. No automation, no scheduled job, no
stoke-side tooling. The sync is infrequent, needs judgement at 5 of 18hunks, and an automated merge that resolves those by rule would produce
exactly the confidently-wrong result the runbook exists to prevent.
Tasks
docs/UPSTREAM-SYNC.mdcovering spec 1, using #198 as the workedexample with its real numbers.
docs/CONSUMERS.md(spec 2).changelog.d/fragment.Acceptance criteria
docs/UPSTREAM-SYNC.mdexists and names, for each of the six standingresolutions, which side wins and the issue that decided it.
no step depends on knowing #197 or #198's discussion.
docs/CONSUMERS.mdstates that this tree tracks upstream versionnumbers and that two trees answer to the same number.
mainactually carries.a file the inventory does not name.
test/run.shendsfailed 0.Test plan
forge_detectbranch to a file outside the inventory;the guard goes red naming the file.
maincontains.
recorded ref removed — it must refuse, not report success.
confirming each of the six standing resolutions traces to an issue number.
Dependencies
Part of #197.Blocked by #198.Reviewer additions from the completed #198 sync—both are measured failure modes and belong in the runbook, not only in issue comments:
Verify the combined tree for every concurrently open PR. Forgejo CI on this instance tests the PR head, not a synthetic merge result. #206 and #207 were both cut from
dad99dd; after #204 landed, their green 22-file runs did not contain main’s six newly added test files/rules. #206’s changelog fragment was individually green but initially made the combined tree red under the new terminal-citation rule. The runbook should require either updating each in-flight branch from the newly synced main or creating an isolated synthetic merge and running the full current suite/static guards before relying on its prior approval.Audit post-merge jobs by executed steps/logs, not green status alone. #198 run 326 was green on merged main but ran only the Forgejo refusal in
trigger; noreconcilejob ran. The upstream workflow split moved scheduled reconciliation toself-labels-sweep.ymland made event reconciliation depend on the unported dispatch (#205). Require an inventory of changed workflow triggers/jobs and proof that the intended operational job actually executed. A green skipped/refusal path is valid evidence for that path, but never evidence that reconciliation occurred.These should be explicit checklist items in
docs/UPSTREAM-SYNC.mdand reflected in its worked #198 example. They are distinct from the no-runtime-ghscan: both failures occurred with the runtime-call guard and CI green.One guard-design point to pin in the implementation: the recorded upstream commit must be locally available in CI. If the delta inventory compares Git objects, the workflow must fetch sufficient history or fail loudly when the object is absent; a shallow checkout must not turn “cannot compare” into green.
No new issue suggested—the duplicate/owner is already #200.
The Refs-linked PR merged with these acceptance criteria still unchecked:
docs/UPSTREAM-SYNC.mdcovering spec 1, using #198 as the workeddocs/CONSUMERS.md(spec 2).changelog.d/fragment.docs/UPSTREAM-SYNC.mdexists and names, for each of the six standingdocs/CONSUMERS.mdstates that this tree tracks upstream versionmainactually carries.test/run.shendsfailed 0.The merge releases the claim; no builder owes a draft. Triage owes completion in a follow-up comment that names the owner and wake condition.