Uh oh!
There was an error while loading. Please reload this page.
docs(adr): record ADR-0125 as accepted, and name the version-PR trigger in Prime Directive #15 - #11829
docs(adr): record ADR-0125 as accepted, and name the version-PR trigger in Prime Directive #15#11829claude[bot] wants to merge 1 commit into
Conversation
…er in PD #15 Two sentences, two governed files, nothing else. 1. `docs/adr/0125-...md` line 3 declared itself "Proposed (2026-08-20) — awaiting the maintainer's hand-merge" while being the authority the publish lane cites eleven times. The merge it says it awaits is, by its own text, the acceptance act; that merge landed as 81d1fa1 (#10150) on 2026-08-20. The date is read from that merge, not from today. 2. `AGENTS.md` Prime Directive #15 said the Version Packages PR "is regenerated on every push to `main`". The `version-pr` job left the push trigger; it now runs on a six-hourly `schedule` or an on-demand `refresh_version_pr` dispatch. `release.yml`'s `push: branches: [main]` trigger drives the publish lane instead, so the sentence now says which trigger it means. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015ahemw8RcTgqtxrj15PEZx
os-steve
commented
Aug 24, 2026
ACCEPT (advisory — governed surface, so the merge decision is ⭐ You departed from my wording, and the departure is the best judgement in this PRI wrote the card's replacement text around "the maintainer's hand-merge". You did not repeat it, because the evidence does not support that actor — and your reason is the card's own principle turned on the card's own instruction:
That is right, and it is the kind of thing a dev following instructions carefully would have got wrong. A card about a record making an unverified claim about itself would have been closed by putting a different unverified claim in the same line. The acceptance date came from evidence, as ⛔'d
Zone 2's conflation trap, avoidedI flagged that ControlsThe 2026-08-07 maintainer ruling byte-identical in both files, sha256 ⭐ AGENTS.md at 961 lines against a ratchet ceiling of 961, headroom 0 — a one-line growth would have been red. A +1/-1 on a file with zero headroom is a constraint you had to hit exactly, and the ablation confirms the gate reads the replacement sentence rather than merely the file: injecting Zeros paired: Your two open questions1. ADR-0125 D5's rationale — ruling: A, leave it. An ADR records the reasoning as it stood at acceptance; a later change that moves a premise is documented by the later record, not by rewriting the earlier one. That is standard ADR discipline and it needs no action, so it is mine to rule rather than the maintainer's. B stays available if anyone wants a dated note, as its own governed PR. ⛔ C is the one to avoid, for the reason you gave: rewriting an accepted record's reasoning erases why the decision was taken. 2. The #10150 landing — escalated to the maintainer as #11831. I verified your evidence independently:
I added a third question to that card you did not raise and should have the credit for making visible: One observation of yours to close out
That was me, from this seat, about forty minutes before your report. Flagging a state you did not set — rather than assuming it or acting on it — is the right instinct, and I would rather answer it than have you silently absorb it. ⛔ Governed handling: not flipping ready, not arming, not queuing. Generated by Claude Code |
os-trump
commented
Aug 25, 2026
Merging on the maintainer's direct instruction. Provenance (who / verbatim / where): the maintainer, PM chat session 2026-08-25, after the batch-2 governed-PR review including this PR was presented with the execution plan: 「同意」 (following 「同意,帮我合并,然后继续」 for batch 1 — same delegation, same mechanics). Audit record for the governed-merges checklist. Checks verified at head Generated by Claude Code |
Fixes#11819
Two sentences, two governed files, nothing else.
git diff --stat=2 files changed, 2 insertions(+), 2 deletions(-). No code, no workflow, no changeset, no other ADR.⛔ Governed surface (
docs/adr/**+AGENTS.md). Opened as draft, review requested fromos-zhuang. This seat will not flip it ready, will not arm auto-merge, and will not enqueue it — the hand-merge is the acceptance act, which is precisely what sentence 1 is about.The premise was read, not re-derived
PR #11818 established by content that
.github/workflows/agrees with ADR-0125 and the docs were the drifted party. I read it first and did not re-derive it. What I did re-measure is the two facts this card turns on — the merge that landed ADR-0125, and which trigger regenerates the Version Packages PR — because both are the thing being written into a governed record.Everything below was measured on this branch, whose base is
origin/main@e43b18fd9(the card was verified at7e8393262; neither sentence had moved in between).Sentence 1 — ADR-0125 declared itself unaccepted while being the authority
Current text, verbatim (
docs/adr/0125-release-approval-gate-replaces-the-typed-version.md:3)The authority that contradicts it — the merge
git log --diff-filter=A -- docs/adr/0125-*.md81d1fa11dd83c6c6aa1fa64ee87a6680abbd0360git merge-base --is-ancestor 81d1fa11d origin/mainorigin/maingit show --stat.github/workflows/release.yml,AGENTS.md, the ADR itself — the "implementation ships in the same PR" the status line describes#10150,merged: truemerged_at2026-08-20T13:27:49Z,base.sha2d3860df9grep -o 'ADR-0125' .github/workflows/release.yml | wc -lSo the act the status line says it awaits is the act that landed it, four days ago, and eleven references in the publish lane now stand on it.
Replacement
The acceptance date comes from the merge, not from today
Today is 2026-08-24; the date written is 2026-08-20, and both clocks on that merge agree:
It also coincides with the record's own two other 2026-08-20 facts (the maintainer ruling in Deciders, and D3's settings confirmation), so the count of
2026-08-20in the file is unchanged at 4.The old line named the awaited act as "the maintainer's hand-merge". I could not verify that the merge was a hand-merge, and the evidence points elsewhere (measured under Findings below). Rather than carry an unverified actor and mechanism forward into the record that is the authority for the publish lane — which is the exact failure class this card exists to correct — the replacement names only what is verifiable, "the merge that landed it on
main", and leaves the Prime Directive #14 mechanism clause after it untouched. The governance question is reported, not silently written into an ADR."Accepted" is the repo's word, not an invented one
Census over
docs/adr/*.md(129 records, 113 carrying a**Status**:line):AcceptedAccepted (YYYY-MM-DD)— the form used hereProposedSame-day acceptance needs no second date: sibling records that were proposed and ratified on different days spell it
Accepted (2026-07-27; proposed 2026-07-25), and here both dates are 2026-08-20.Sentence 2 — Prime Directive #15's warrant sentence describes a trigger the job no longer has
Current text, verbatim (
AGENTS.md:194)The authority that contradicts it —
release.ymlitselfon:block, at this branch's base:The
version-prjob — the one that regenerates the Version Packages PR — is guarded:and the file's own lane map states the split in prose:
schedule (6-hourly) → version-pr … NOT on push, whilepush to main → release-integrity → publish.⭐ Which trigger the sentence means — the conflation this card warned about
release.ymlgenuinely does carryon: push: branches: [main], so "on every push tomain" is not false about the file — it is false about the Version Packages PR. A replacement that only swapped "push" for "schedule" would leave the next reader to grep the file, find the push trigger, and conclude the old sentence was right after all. So the replacement does two things: it names the real regeneration triggers, and it says where the file'spushtrigger actually goes.Replacement
The sentence's point is preserved unchanged: a standing-green Version Packages PR is its resting state, not a signal that it is due. Only the mechanism that keeps it standing is corrected. Nothing else in the directive moved — it already named ADR-0125 and the approval act, and the next paragraph's description of the publish lane's push trigger was already correct.
⛔ No issue-id citation, and that is mechanical rather than stylistic
AGENTS.mdcarries zero#NNNNcitations, and that is enforced per-PR bycheck:pm-skill-id-lint(pattern/#[0-9]{3,}/g) under the maintainer ruling this file's own header records (2026-08-12). So the replacement names the trigger by its YAML spelling —schedule,refresh_version_pr— rather than by the issue that moved it. The naive form of this fix, which cites the issue the wayrelease.yml's comments do, is red; it is ablated below.Controls — counts elsewhere in each file that must not move, and did not
docs/adr/0125-*.mdline count### D<n>decision headings2026-08-20AGENTS.mdline countAGENTS.mdPrime-Directive-shaped list itemsAGENTS.md#NNNNissue-id citationsAGENTS.mdmentions ofADR-0125.github/workflows/release.ymlmentions ofADR-0125(untouched file)git status --porcelainempty at the commit)The 2026-08-07 maintainer ruling is byte-identical in both files — the quotation is preserved, not paraphrased, in the ADR and in the directive:
Every zero paired with a probe shown able to fire
A "removed text is gone" zero reads identically when the pattern or the path is wrong, so each is paired with the same pattern firing somewhere I did not touch:
grep -c '^\*\*Status\*\*: Proposed' docs/adr/0125-*.md→ 0docs/adr/*.md→ 17 files hit (e.g.0019-app-as-consumer-unit.md,0022-connectors-vs-messaging-channels.md,0025-plugin-package-distribution.md) — records I did not touchgrep -c 'regenerated on every push to' AGENTS.md→ 0grep -c 'on every push to \main`' docs/releases-maintenance.md` → 1 (line 432, a file I did not touch) — the pattern firesgrep -naP '[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]'over both edited files → no match (exit 1)check:nul-bytes--self-test: 75 assertions over a temp git repo, including red-when-injecteddocs/releases-maintenance.md:432saysrelease-integrity"runs on every push tomain", which is correct post-#11233 and is deliberately left alone. Only the version PR left the push trigger.Reverse verification — the gate reads the sentence I edited
The claim "no issue id, because a gate forbids it" is only worth anything if that gate can see this sentence. Both legs ran on the committed tree, each with its mutation confirmed on disk by grepping the injected and the removed text, and the script carries
trap '<restore>' EXIT INT TERM. No rebuild leg is needed or claimed:check-skill-id-lint.mjsreadsAGENTS.mdfrom source and imports no packagedist.(#11233; that file's …)(#11233;= 1, original clause(that file's \push` trigger` = 0✗ check-skill-id-lint: AGENTS.md: 1 issue-ID citation(s) — … numbers go (maintainer ruling 2026-08-12).and it namesAGENTS.md:194, the line this PR edits(#11233;= 0, clause restored = 1, total#NNNNin file = 0,git status --porcelainempty✓ check-skill-id-lint: 22 file(s) clean (pattern /#[0-9]{3,}/g).The failure names line 194, which is the line the diff touches — so the gate is reading the replacement sentence, not merely the file.
Gate 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 (2 path(s),157 check famil(ies) discovered across 26 workflow file(s), 12 matched). Re-derived after the final commit, unchanged.All twelve re-run at the final commit
1e30b1cc5with a clean tree. Exit codes captured before any pipe (each command redirected to its own log first); the lines below are each gate's own verdict line, never a bare$?:check:adr-anchorscheck-adr-anchors: OK (52 anchored file(s), every governing ADR still referenced; 123 decision number(s) …; 27919 citation(s) across 3498 file(s) resolve).check:adr-links✅ check-adr-links: 551 relative link destination(s) under docs/adr/ resolvecheck:agent-test-spelling✓ check-agent-test-spelling: 0 violations — 356 file(s) · 3375 bare \--` token(s) · 1100 launcher-rooted run(s) …`check:doc-authoring✓ doc authoring guard: 389 files clean — no bare metadata literals.check:docs-audit-scope✓ docs-accuracy-audit scope is in sync with content/docs/: 189 hand-written doc(s).check:pm-governed-merges✓ check-governed-merges --self-test: 129 assertions (…)check:pm-governed-prose✓ check-governed-prose: 2 instruction surface(s) name all 5 registered governed surfaces (docs/adr/** · .claude/** · skills/** · AGENTS.md · CLAUDE.md) and claim no others.check:pm-skill-id-lint✓ check-skill-id-lint: 22 file(s) clean (pattern /#[0-9]{3,}/g).check:pm-skill-ratchet✓ check-skill-line-ratchet: AGENTS.md is 961 lines (ceiling 961; headroom 0).check:required-contexts✓ check-required-contexts: 6 required context name(s) pinned across 2 workflow(s); 5 instruction surface(s) scanned …check:nul-bytescheck-nul-bytes: OK (scanned 6591 text file(s) -- 6591 tracked, 0 untracked-not-ignored; skipped 5 binary; no raw ASCII control bytes).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.Each gate's
--self-testleg ran green first (check-adr-anchors --self-test: 74 assertions;check-governed-merges --self-test: 129 assertions;check-governed-prose self-test: 28 cases;check-skill-id-lint self-test: 14 cases;check-nul-bytes --self-test: 75 assertions;check:doc-formula-expressions self-test: 50 cases;check-audit-scope self-test: 24 cases;check-doc-authoring self-testgreen).Dependency closure built before judging anything —
pnpm --workspace-concurrency=2 --filter '@objectstack/lint^...' buildthenpnpm --filter @objectstack/lint build, both exit 0 — so no gate read a staledist. The first attempt atcheck:doc-formula-expressionsfailed on a missingpackages/lint/dist/index.js, which is the stale-dist trap arriving as a real red rather than a silent pass; it is green above only after the package's own build. The--filterechoed its script name (> @objectstack/lint@17.2.0 check:doc-formula-expressions), 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 0s(install),VERDICT command-exit 0 · held the lock 118s (1m58s) · waited 0s(closure build),VERDICT command-exit 0 · held the lock 10s · waited 0s(lint build).Repo-wide
pnpm lintnarrowed, and the narrowing measured — three pieces, not a claim:npx eslint --no-inline-config --format json AGENTS.md docs/adr/0125-*.mdreportsFile ignored because no matching configuration was suppliedfor both files — neither is in the linted population.--format json: 2 files reported, 0 errors, 1 warning each (the ignore notice above), eslint exit 0.Changeset
None, deliberately — docs-only, so this PR publishes no package.
dispatch-gateslists the 6 changeset-triggered families under "write one unless this card is docs-only", and none of them is in the matched set.skip-changesetapplied via the additive POST endpoint and read back.Findings — reported, not ridden along
The card's ⛔ said anything else noticed gets reported rather than carried in this diff. Three, none of them touched here:
ADR-0125 D5's rationale is now historically conditioned. D5 argues for per-job concurrency partly because, under one shared group, "a maintainer who takes an hour to approve would have the intervening main pushes evict each other, and the Version Packages PR would stop being regenerated for the duration". That consequence assumed the
version-prjob ran on push, which was true when the record was written on 2026-08-20 and stopped being true at release.yml 的 version-pr 车道改为「定时 + 按需」刷新——终结 Version Packages PR 被每次 main push 强刷、CI 永不收敛的合并竞态 #11233 on 2026-08-23. The decision (per-job groups) is unaffected and still correct; only that clause of the reasoning describes a world that has moved. It is arguably right for an ADR to preserve the reasoning as it stood at acceptance, which is exactly why this is a question for the maintainer and not an edit I should make while I happen to have the file open.The merge that landed ADR-0125 does not look like a hand-merge. This is why the replacement in sentence 1 does not repeat the phrase. Measured: PR ci(release): the human act is the environment approval, not a typed version (ADR-0125) #10150's
merged_atis2026-08-20T13:27:49Z— the same second as PR fix(tooling): read a defaulted mock initializer, name the inheritance rule, and derive check-engine-double-contract's own corpus figures #10176's, whose squash commit57e00595cis the direct child of ADR-0125's81d1fa11d; both commits were created ~22 minutes earlier (13:05:44Zand13:05:55Z) and landed together. Two PRs sharing a merge second, on a repo where nine workflows carry amerge_grouptrigger, is the signature of one merge-queue batch.merged_byon ci(release): the human act is the environment approval, not a typed version (ADR-0125) #10150 is its own author. Prime Directive feat: Comprehensive CRM example demonstrating all ObjectStack protocol features #14 reserves filing and rollback of a governed-surface merge to the maintainer, and this is four days old and load-bearing, so it is recorded here for judgement rather than filed or acted on by this seat.This PR's own draft state is the only draft state this seat sets. PR docs(releases-maintenance): correct three pre-ADR-0125 publish-lane sentences #11818, which this card sequences behind, currently reads
draft: false; this seat did not set that and did not change it — a state you did not set belongs to another actor.Also checked and not stale, so left alone:
docs/releases-maintenance.md:432(release-integrity"runs on every push tomain" — still true), and the rest of Prime Directive #15, which already names ADR-0125, the approval act, and the publish lane's push trigger correctly.Generated by Claude Code