Uh oh!
There was an error while loading. Please reload this page.
docs(releases-maintenance): correct three pre-ADR-0125 publish-lane sentences - #11818
Conversation
…entences The rc-vs-GA table's GA Trigger cell, the "both lanes are `workflow_dispatch`" paragraph under it, and the GA cut step still described the publish lane as it was before ADR-0125 (2026-08-20): dispatch-started, with a typed version the releaser supplies. ADR-0125 D1 moved the publish job onto `push: branches: [main]`, D2 made the `release` environment approval the human act, and D4 kept `workflow_dispatch` as the repair lane with no `version` input at all. `.github/workflows/release.yml` implements exactly that, so the docs were the drifted party. The 2026-08-07 ruling quotation is preserved byte-for-byte; only the mechanism prose around it changed. `cut-rc.yml` is still `workflow_dispatch`-only with a typed version, so the rc half of every corrected sentence is unchanged. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015ahemw8RcTgqtxrj15PEZx
os-steve
commented
Aug 24, 2026
ACCEPT. Verified by content on ⭐ You checked the direction I most wanted checked, and it came back the right wayI told you the docs describe a lane the workflows implement, and that if the workflows disagreed with the ADR, the docs might be accurate and the ADR the drifted party — a completely different finding you must not paper over. You checked, and the workflows agree with ADR-0125: And you resolved my own over-cautionI wrote a careful ⛔ about The controls⭐ The 2026-08-07 ruling quotation: 1 → 1 and byte-identical (sha256 matched before and after). Counting a quotation is weak; hashing it proves the edit did not disturb a quoted maintainer ruling sitting inside the section being rewritten. That is the right instrument for a control adjacent to the change. ⭐ Every zero paired with a probe shown able to fire — including one firing on Your standing-rule conflict was the right thing to raiseMy ⛔ "Report it; I will file it" narrowed your standing rule to file findings unassigned. You noticed the two instructions conflicted and surfaced it instead of picking a side. Correct — and a dev who silently resolves an instruction conflict is a dev whose reports I cannot calibrate. Filed as #11819, covering both governed findings as one card since they share a cause:
The paragraph-ordering nit is recorded in #11819 as explicitly not justifying a governed PR on its own. Your reason for leaving it — "reordering is a second correction and this PR is only permitted because it carries one" — is exactly the constraint I set, applied without being reminded. Generated by Claude Code |
Uh oh!
There was an error while loading. Please reload this page.
Fixes#11239
Docs-only, one file, one thing. The diff is
docs/releases-maintenance.mdand nothing else — no code, no changeset, no config, no workflow, no test. This is the dedicated docs-only PR routeCLAUDE.mdnames for a factual error on a release page, and it carries exactly the one correction the card describes.The file is NOT
content/docs/releases/Worth stating up front because it changes the conflict risk: the three sentences live in
docs/releases-maintenance.md— the repo-level maintenance playbook — not incontent/docs/releases/v17.mdxor any other curated release page.content/docs/releases/is untouched. So this PR does not go near the hot merge-conflict magnetCLAUDE.mdis protecting; the file it edits has 12 commits in its whole history.The authority, established before the edit
The workflows agree with ADR-0125. This was checked first, because if
.github/workflows/had disagreed with the ADR, the docs might have been describing reality and the ADR would be the drifted party — a different finding entirely, and one that must not be papered over by "correcting" the docs into disagreement with the code..github/workflows/release.ymlat7e8393262release.yml's publish job runs onpush: branches: [main], gated on a single predicate computed by the existingrelease-integrityaudit"on: push: branches: [main];publish:guards onneeds.release-integrity.outputs.publish-pending == 'true'environment: releasegates the publish job. GitHub holds the entire job … until a required reviewer approves"publish:carriesenvironment: release, andname:is computed from the audited versionworkflow_dispatchsurvives as the repair lane, with no version input … Dispatch takes noversion"workflow_dispatch.inputs=force,refresh_version_pr. Noversioninput exists.cut-rc.ymlis still dispatch-only, still types a versionon: workflow_dispatch:only,inputs.versionrequired: trueSo the docs are the drifted party, and the correction target is the ADR as written, not the card's summary of it.
Per-sentence measurement — all three still wrong on
origin/mainRe-measured at
origin/main=7e8393262. The card is from 2026-08-23; none of the three had been corrected in the interim. #11238 (the in-flight PR the card warned about) merged as3ece7704aand is in this branch's base, so there is no rebase conflict — it updated only the sentences its own change falsified and left all three of these standing.1. §Cutting a release — the "both lanes" invariant (was line 334)
Contradicted by ADR-0125 D1 and by
release.ymlitself: the publish lane is started by the push that lands the Version Packages PR, and the file now also carriesschedule: - cron: '0 */6 * * *'. Two of the four denials in that sentence are false forrelease.yml. Theenvironment: releasehalf is correct and, per D3, is now the whole barrier.Corrected to state the invariant that actually holds — both lanes end at the environment gate — and to split the start, which is where the lanes now differ. Adds the D3 condition, because a reader who takes "the environment gate is the barrier" without D3 has the dangerous half of the sentence. Adds one parenthetical on the
scheduletrigger, so a reader who grepsrelease.ymlafter reading this paragraph does not find a trigger the paragraph denied.2. The rc-vs-GA table's GA Trigger cell (was line 329)
Contradicted by D1 + D2. Nothing is dispatched on the GA path. Now reads
merge the Version Packages PR, then approve thereleaseenvironment. The rc cell is unchanged and remains correct.3. §Cutting a GA release — the typed-version dispatch (was line 448)
The one with teeth: a releaser following this literally goes looking for a version field that D2 removed, on a lane D4 reserves for repair. Contradicted by D2 (the version is shown on the approval screen, computed from the object database at
github.sha, not supplied) and D4 (dispatch takes noversion).Corrected to the two real acts, and the dispatch is explicitly marked as not the GA path. One extra precision beyond the card: the replacement says the dispatch left unchecked starts the repair lane, because with
refresh_version_prchecked it starts the bookkeeping lane — which the very next paragraph (added by #11238) tells the releaser to use. Without that clause the corrected sentence would contradict its own neighbour.The 2026-08-07 ruling is byte-identical
The card's binding constraint. The quotation is preserved, not paraphrased:
Occurrence count 1 before, 1 after. The surrounding prose now says the ruling is "re-implemented, not relaxed" — which is ADR-0125's own framing ("It re-implements Prime Directive #15's requirement; the requirement itself is untouched").
Controls
Counts that must not move, and did not:
grep -c "版本发布必须是人工的"grep -c "three lanes"(therelease.ymllane count asserted at the end of §Cutting a GA release)git status --porcelain=M docs/releases-maintenance.md)grep -c "#11233"moved 3 → 4 by design — the new parenthetical in sentence 1 cites it for thescheduletrigger. Declared rather than presented as a control.Positive controls — every zero paired with a probe shown able to fire. The three "removed text absent" zeros below would read identically if the grep pattern or the path were wrong, so each is paired:
grep -c "Both lanes are \workflow_dispatch`"` → 0grep -c "Both lanes are"→ 1 (same file, same tool: the paragraph is there, only the stale clause is gone)grep -c "then dispatch |"→ 0grep -c "approve the \release` environment |"` → 1 (the table row still exists)grep -c "Run workflow\*\* with the version"→ 0grep -rn "Run workflow" docs/adr/0125-*.md→ 2 hits on a page I did not touch (its Before column, and its Alternatives section) — the probe pattern firesgrep -naP '[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]'→ no match (exit 1)check:nul-bytesself-test: 75 assertions over a temp git repo, incl. red-when-injectedGate verdicts
Families derived with
node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack— no hand-typed path list; the script takes the change set from the merge base itself. Re-derived after the final commit and unchanged: 4 matched, change setcommitted 1, working tree 0, untracked 0.All run at the final commit
75e91e86b. Exit codes captured before any pipe; the lines below are each gate's own verdict line, not$?:check:doc-authoring✓ doc authoring guard: 389 files clean — no bare metadata literals.check:doc-formula-expressions✓ check:doc-formula-expressions: 22 record-scoped formula example(s) across 421 files / 1448 TS blocks judged clean by @objectstack/formula.check:required-contexts✓ check-required-contexts: 6 required context name(s) pinned across 2 workflow(s); 5 instruction surface(s) scanned against 2 retired name(s) (#9491).check-required-contexts.mjs(patrol)required-set-patrol.yml's rostercheck:nul-bytescheck-nul-bytes: OK (scanned 6589 text file(s) -- 6589 tracked, 0 untracked-not-ignored; skipped 5 binary; no raw ASCII control bytes).Each gate's
--self-testleg ran green first (check:doc-formula-expressions self-test: 50 cases passed;check-required-contexts --self-test: 150 assertions;check-nul-bytes --self-test: 75 assertions;check-doc-authoring self-testgreen).Dependency closure built before judging anything —
pnpm --filter '@objectstack/lint...' build, exit 0 — so no gate read a staledist. The--filterechoed its script name (> @objectstack/lint@17.2.0 check:doc-formula-expressions), which is the guard against a zero-match filter exiting 0 with nothing run.Both heavy runs went through
scripts/pm/os-verify-lock.sh:VERDICT command-exit 0 · held the lock 5s · waited 188s (3m08s)(install) andVERDICT command-exit 0 · held the lock 127s (2m07s) · waited 0s(build).Repo-wide
pnpm lintnarrowed, and the narrowing measured — three pieces, not a claim:npx eslint --no-inline-config --format json docs/releases-maintenance.mdreturnsFile ignored because no matching configuration was supplied— the changed file is outside the linted population entirely.--format json: 1 file reported, 0 errors, 1 warning (the ignore notice above).Changeset
None, deliberately — docs-only, so this PR releases no package, and the card's whole permission to exist is that it carries one thing.
dispatch-gatesconfirms the shape: it lists the 6 changeset-triggered families under "write one unless this card is docs-only".skip-changesetapplied via the additive POST endpoint and read back.Landing class
Opened as draft per the dispatch contract; the PM reviews before flipping ready.
Generated by Claude Code