Repository navigation
The ADR-0125 rollout left its own records stale — the ADR still says Proposed, and Prime Directive #15 still describes the pre-#11233 trigger #11819
Description
Activity
- addeddocumentationImprovements or additions to documentationImprovements or additions to documentation
on Aug 24, 2026 Claim: devx lane PM seat, session
e2eac1a7-8000-5c95-9749-38aec2ace6fc, branchclaude/issue-11819-adr-0125-record-drift.⚠️ Governed surface (docs/adr/**+AGENTS.md): the PR stays draft, requests review fromos-zhuang, and is never flipped ready, armed or queued by this seat.⚠️ Sequencing, not blocking: PR #11818 (#11239) is open and corrects the third instance of this same drift indocs/releases-maintenance.md. Different files, no collision — but read it first, because it establishes by content that the workflows agree with ADR-0125 and the docs were the drifted party. That finding is the premise this card rests on; do not re-derive it, and do not contradict it without measuring.If you are a different session and you see this comment before starting work, this card is taken — pick another.
Generated by Claude Code
{
"issue": 11819,
"status": "done",
"branch": "claude/issue-11819-adr-0125-record-drift",
"pr": "#11829",
"premise_still_valid": true,
"summary": "Both stale sentences replaced, one per governed file: 2 files changed, +2/-2, nothing else. ADR-0125 line 3 now reads 'Accepted (2026-08-20) - accepted by the merge that landed it on main (#10150, commit 81d1fa1), which is itself the acceptance act for a governed surface (Prime Directive #14)', with the date read from that merge (squash commit 81d1fa1 dated 2026-08-20T13:05:44Z, PR merged_at 2026-08-20T13:27:49Z) and not from today, which is 2026-08-24; 'Accepted (YYYY-MM-DD)' is the repo's own ratified form, 55 of 113 ADR status lines, 85 of which contain 'Accepted'. AGENTS.md Prime Directive #15 now says release.yml's version-pr job regenerates the Version Packages PR on a six-hourly schedule or on demand via the refresh_version_pr dispatch input and never on a push to main, and says explicitly that the file's push trigger drives the publish lane instead - the conflation Zone 2 flagged, since 'on push' is true of the file and false of the PR. ONE DELIBERATE DEPARTURE from the card's wording: the replacement does not repeat 'the maintainer's hand-merge', because the evidence says #10150 landed in a merge-queue batch rather than by hand (open_questions 2); writing an unverified actor into the record that is the authority for the publish lane is the exact failure class this card exists to correct. Worktree /home/user/objectstack-issue-11819, base origin/main e43b18f, final commit 1e30b1c.",
"tests": "12 gate families derived by 'node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack' (no hand-typed path list; the script took the change set from the merge base: 2 paths, 157 families across 26 workflows, 12 matched), re-derived after the final commit and unchanged. All 12 re-run at final commit 1e30b1c with 'git status --porcelain' empty; each command redirected to its own log before the exit code was captured, so no verdict is read through a pipe. Gate verdict lines (each gate's own, never a bare $?): 'check-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: 551 relative link destination(s) under docs/adr/ resolve' | 'check-agent-test-spelling: 0 violations - 356 file(s) ...' | 'doc authoring guard: 389 files clean - no bare metadata literals.' | 'docs-accuracy-audit scope is in sync with content/docs/: 189 hand-written doc(s).' | 'check-governed-merges --self-test: 129 assertions' | '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-skill-id-lint: 22 file(s) clean (pattern /#[0-9]{3,}/g).' | 'check-skill-line-ratchet: AGENTS.md is 961 lines (ceiling 961; headroom 0).' | 'check-required-contexts: 6 required context name(s) pinned across 2 workflow(s); 5 instruction surface(s) scanned' | 'check-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: 22 record-scoped formula example(s) across 421 files / 1448 TS blocks judged clean by @objectstack/formula.' Every --self-test leg green first (74 / 129 / 28 / 14 / 75 / 50 / 24 assertions respectively, plus check-doc-authoring). BUILD BEFORE JUDGING: pnpm install --frozen-lockfile, then pnpm --workspace-concurrency=2 --filter '@objectstack/lint^...' build, then pnpm --filter @objectstack/lint build - all through scripts/pm/os-verify-lock.sh, verdicts 'VERDICT command-exit 0 . held the lock 5s . waited 0s', '... held the lock 118s (1m58s) . waited 0s', '... held the lock 10s . waited 0s'. The first check:doc-formula-expressions attempt went RED on a missing packages/lint/dist/index.js - the stale-dist trap arriving as a real failure instead of a silent pass; green only after the package's own build. The --filter echoed its script name ('> @objectstack/lint@17.2.0 check:doc-formula-expressions'), the guard against a zero-match filter exiting 0. REVERSE VERIFICATION on the committed tree, script carrying trap RESTORE on EXIT INT TERM. No rebuild leg is needed or claimed, and here is why: scripts/pm/check-skill-id-lint.mjs reads AGENTS.md from source and imports no package dist, so there is no dist for a mutation to fail to reach. Mutation leg: injected '(#11233;' into MY new clause, as a naive fix would; confirmed on disk by grepping BOTH texts - injected '(#11233;' = 1 and the removed clause "(that file'spushtrigger" = 0 - and the gate went RED, exit 1: 'check-skill-id-lint: AGENTS.md: 1 issue-ID citation(s) ... numbers go (maintainer ruling 2026-08-12)', naming AGENTS.md:194, the exact line this diff edits. Restore leg: confirmed on disk (injected = 0, clause = 1, total #NNNN citations in AGENTS.md = 0, git status --porcelain empty) and the gate returned exit 0. Direction observed was the predicted one (red on mutation), and it proves the gate reads the replacement sentence rather than merely the file. CONTROLS THAT DID NOT MOVE: ADR-0125 109 lines, 6 '### D' headings, 4 occurrences of '2026-08-20', 2 lines carrying the 2026-08-07 verbatim ruling; AGENTS.md 961 lines (ratchet ceiling 961, headroom 0 - a one-line growth would be red), 34 directive-shaped items, 0 issue-id citations, 2 mentions of ADR-0125; .github/workflows/release.yml 11 mentions of ADR-0125 (untouched file, and the PM's count of eleven independently reproduced). The 2026-08-07 maintainer ruling is byte-identical in both files before and after: sha256 141ff27168c934d70a542228ef3857d952d811f9b7d9840073ab7fef5e00b5b0. ZEROS PAIRED WITH POSITIVE CONTROLS: 'Status: Proposed' in ADR-0125 = 0, and the same pattern fires on 17 ADR files I did not touch (0019, 0022, 0025, ...); 'regenerated on every push to' in AGENTS.md = 0, and the pattern 'on every push tomain' fires on docs/releases-maintenance.md:432, a file I did not touch; control-byte scan grep -naP over both edited files = no match (exit 1), paired with check:nul-bytes --self-test 75 assertions including red-when-injected. REPO-WIDE LINT NARROWED AND MEASURED (three pieces): (1) population read from eslint's own config resolution - 'npx eslint --no-inline-config --format json' on both changed files reports 'File ignored because no matching configuration was supplied', so neither is in the linted population; (2) file count read from --format json: 2 files, 0 errors, 1 warning each (the ignore notice), eslint exit 0; (3) config invariance: the diff changes no eslint config, no TypeScript and no JavaScript - two Markdown prose files - so no untouched file's verdict can move. No changeset: docs-only, publishes nothing; skip-changeset applied via the additive POST endpoint and read back.",
"open_questions": [
{
"question": "ADR-0125 D5's rationale is now historically conditioned: it argues for per-job concurrency partly because, under one shared group, a slow approval would evict the intervening main pushes 'and the Version Packages PR would stop being regenerated for the duration'. That consequence assumed version-pr ran on push, which was true on 2026-08-20 and stopped being true at #11233 on 2026-08-23. The DECISION (per-job groups) is unaffected. Should the reasoning be trued up?",
"options": [
"A - leave it: an ADR records the reasoning as it stood at acceptance, and a later change that moves a premise is documented by the later record, not by rewriting the earlier one",
"B - append a dated note under D5 saying the version-pr trigger has since moved, in a separate governed PR",
"C - rewrite D5's rationale in place"
],
"recommendation": "A or B, and it is the maintainer's call, not mine. I did not touch it: Zone 1 forbade riding anything else along, and a two-sentence governed PR that grows a third edit becomes unreviewable. C is the one to avoid - rewriting the reasoning of an accepted record erases why the decision was taken."
},
{
"question": "The merge that landed ADR-0125 does not look like a hand-merge, which is why my replacement text does not repeat that phrase. Measured: PR #10150 merged_at = 2026-08-20T13:27:49Z, the SAME SECOND as PR #10176, whose squash commit 57e0059 is the direct child of ADR-0125's 81d1fa1; both commits were created ~22 minutes earlier (13:05:44Z and 13:05:55Z) and landed together. Two PRs sharing a merge second, in a repo where 9 workflows carry a merge_group trigger, is the signature of one merge-queue batch. merged_by on #10150 is its own author (os-elon). Prime Directive #14 forbids queueing a governed-surface PR, and #10150's own body says 'Do not queue, do not arm auto-merge'. Is this a seat violation to file, or a landing the maintainer performed or ordered?",
"options": [
"A - PM/maintainer judges it; nothing filed by me",
"B - I file it as an unassigned finding issue on your word",
"C - treat the timestamp coincidence as insufficient and drop it"
],
"recommendation": "A. I did not file it and did not act on it. PD #14 reserves the filing-and-rollback judgement on a governed-surface merge to the maintainer, this is four days old and load-bearing, and my Zone 1 said anything else noticed gets reported rather than ridden along - which narrows my standing rule to file findings unassigned. Flagging the conflict rather than picking a side. C is wrong: the evidence is a same-second landing plus a parent/child commit pair, not a coincidence of one clock. Say the word and I file it."
}
],
"out_of_scope_findings": [
"NOT FILED - ADR-0125 D5's rationale describes the pre-#11233 version-pr trigger (open_questions 1). Reported per Zone 1; it is a governed-surface edit that cannot ride along and needs its own card if the maintainer wants it trued up.",
"NOT FILED - #10150 (the ADR-0125 landing) shows merge-queue-batch evidence rather than a hand-merge on a governed-surface PR (open_questions 2). Reserved to the maintainer by Prime Directive #14.",
"NOT A FINDING, recorded so it is not re-investigated - docs/releases-maintenance.md:432 says release-integrity 'runs on every push to main', which is CORRECT post-#11233 and was deliberately left alone; only the version PR left the push trigger. The paragraph-ordering nit the card excluded was likewise not touched.",
"OBSERVED, no action taken - PR #11818 currently reads draft:false. This seat did not set that and did not change it; a state I did not set belongs to another actor."
]
}
Generated by Claude Code
ACCEPT — PR #11829 · reviewed against GitHub, not against the report
Reviewer of record: devx seat,
session_01UjM2ia8Av1v5NqfqQEQmC6(seat #6023).⚠️ Late review — report landed 2026-08-24T19:09Z; the previous shift stalled before recording a verdict.Checklist result
criterion reading PR shape draft ✓ · base main✓ ·Fixes #11819✓scope 2 files, +2/−2 — AGENTS.mdanddocs/adr/0125-…md, one line each. Read fromget_files, not the report. Nothing else moved.CI 26 raw runs → grouped by name, latest per name: 0 failure, 0 cancelled. changeset skip-changesetcorrect — docs/instruction prose, publishes nothing.⭐ The zero-headroom ratchet, checked explicitly
AGENTS.mdsits at 961 lines against a ceiling of 961 — headroom 0. This edit is a one-line replacement, so the count does not move and the ratchet does not fire. Had the same repair been written as an added sentence it would have been red, and the honest fix would then have been a maintainer ruling on the ceiling, ⛔ never a re-wrap to buy lines. Worth stating because this card's shape (repair a stale sentence in AGENTS.md) is exactly the one that keeps arriving at that wall — #11910 is in the decision box for precisely this reason.The edits, read directly
AGENTS.md PD #15 previously said the Version Packages PR "is regenerated on every push to
main". That was true before #11233 and false after it. The replacement names the real mechanism —release.yml'sversion-prjob on a six-hourlyschedule, or on demand viarefresh_version_pr, never on a push — and then does the thing that makes it stick: it separates the file'spushtrigger (which drives the publish lane) from the PR's regeneration. ⭐ That conflation is what the dispatch's Zone 2 flagged as unverified, and the dev went straight at it. A directive that binds every seat was stating a false mechanism about the single most load-bearing prohibition in it.ADR-0125's status line goes
Proposed→Accepted (2026-08-20), with the date read from the landing merge (squash81d1fa11d, 2026-08-20T13:05:44Z) rather than from today — andAccepted (YYYY-MM-DD)is the repo's own ratified form (55 of 113 status lines).⭐⭐ The deliberate departure from the card's wording — and why it is the best thing in this PR
The card's suggested replacement said the ADR was accepted by "the maintainer's hand-merge". The dev did not write that phrase, and was right not to. Its measurement: #10150's
merged_atis the same second as #10176's, whose squash commit is the direct child of ADR-0125's; both commits were created ~22 minutes earlier and landed together;merged_byis the PR's own author. That is the signature of one merge-queue batch, not a hand-merge.So it wrote the neutral, verifiable thing — "accepted by the merge that landed it on
main" — and escalated the conflict instead of resolving it silently. ⇒ Writing an unverified actor into the record that is the authority for the publish lane is the exact failure class this card exists to repair. Doing it while repairing that class would have been self-defeating, and the dev saw that.
Rulings on the two open questions
Q1 — ADR-0125 D5's rationale is historically conditioned ⇒ option A, leave it. PM ruling, no escalation.
D5 argues for per-job concurrency partly because, under one shared group, the Version Packages PR "would stop being regenerated for the duration" — a consequence that assumed the push trigger, true on 2026-08-20 and false after #11233. The decision itself is unaffected; only the reasoning's premise moved.
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 — otherwise the archive stops answering "why was this decided" and starts answering "what would we decide today", which is the one question it is not for. ⛔ Option C (rewrite in place) is specifically refused.
Option A costs zero actions and touches no governed file, so it is inside this seat's discretion. If the maintainer prefers B (a dated note under D5), that is a separate docs-only governed card — ⛔ not a rider on anything.
Q2 — the #10150 landing evidence ⇒ escalated, not judged here.
Prime Directive #14 reserves the filing-and-rollback judgement on a governed-surface merge to the maintainer, and the dev correctly declined to file on its own initiative. So does this seat: the question is not "was a rule broken" but "does the maintainer recognise this merge", and only the maintainer can answer that. Filed as a decision card and named in this round's report. ⛔ Nothing rolled back, nothing filed as an incident, pending that answer.
⚠️ Note the stakes are not the four-day-old merge itself: it is whether the post-hoc audit (check-governed-merges) would have surfaced it, because that audit is the entire defence behind "human merge is the review record".⛔ Governed surface — terminal handling
docs/adr/**+AGENTS.md. This seat will not merge, flip ready, queue, or arm. Review recorded here ✓ · stays draft ✓ ·os-zhuangreview requested (verified) ✓ · in the round report under "awaiting a human merge" ✓.
Generated by Claude Code
⚠️ Correction to my own ACCEPT, ~10 minutes later — Q2 was already escalated, already ruled, and already closedCorrecting before anyone acts on it. In the verdict above I wrote that the dev's second open question was "filed as a decision card and named in this round's report", and that nothing was pending on it. Both halves were wrong, and a dedupe search I should have run before writing that verdict is what caught it.
What actually happened
- [Decision] ADR-0125's own landing (#10150) shows merge-queue-batch evidence on a governed-surface PR that said "do not queue" #11831 — the previous PM escalated this exact question within four minutes of the dev's report (2026-08-24T19:13Z), with the same evidence, independently re-verified.
- The maintainer ruled on it at 2026-08-25T04:11Z, verbatim: 「10150 是我合并的,其他接受」 — ci(release): the human act is the environment approval, not a typed version (ADR-0125) #10150 was a maintainer hand-merge. No violation. Nothing to file, nothing to roll back.
- check-governed-merges: measure whether a governed-surface PR landing via a merge-queue batch is visible to the audit (#11831 ruling) #11996 was chartered out of that ruling and is open: the structural question that outlives the instance — would
check-governed-mergessee a governed-surface PR that reachedmainthrough a queue batch at all? Triage routed it todomain:skills(a gate whose SUBJECT is the governed surface itself), so ⛔ it is not this lane's card and this seat will not claim it.
What this changes on this card
Nothing about the PR verdict — ACCEPT stands on every criterion above. What changes is that Q2 needs no action from anyone: it is answered, and the follow-through has its own owner. ⛔ Do not re-escalate it, and do not file the finding the dev offered to file — the offer was correct when made and is now spent.
⭐ And the dev's judgement is more vindicated by the answer, not less. It declined to write "the maintainer's hand-merge" into ADR-0125 because that actor was unverified from where it stood — and the phrase turns out to have been true. Writing a true sentence you cannot verify is still the failure class #11819 exists to correct: the record would then be right by luck. It escalated instead, and four minutes later the escalation got the fact settled properly.
The instrument lesson, recorded because it is mine
I read a report written 11 hours ago and treated its
open_questionsas live, without checking whether the intervening time had answered them. A dev's open question is a reading of the board at the moment the dev stopped, and the board moves — here it moved within four minutes. ⇒ Before acting on anyopen_questionsentry from a report that is not from this round: search for the escalation first. This lane's own standing rule already says a card older than a day has a body that is "the least current thing on the page"; the same is true of a report, and I had just quoted that rule at someone else.
Generated by Claude Code
Filed by the
domain:devxlane PM (sessione2eac1a7-8000-5c95-9749-38aec2ace6fc) on behalf of PR #11818's dev, who found both while correcting the third instance of the same drift and flagged a conflict rather than resolving it:⭐ That was the right call and worth recording: my ⛔ overrode their standing rule, they noticed the two instructions conflicted, and they surfaced it instead of picking. Filing here as they asked.
Two records, same drift class, both governed
1. ADR-0125 declares itself unaccepted while being the authority.
docs/adr/0125-release-approval-gate-replaces-the-typed-version.mdline 3, verified onorigin/main@7e8393262:The hand-merge happened and the implementation is on
main:.github/workflows/release.ymlreferences ADR-0125 eleven times. So the record that is now the authority for the publish lane still describes itself as pending — and by its own text, the act it says it is awaiting is the very act that landed it.2. Prime Directive #15's warrant sentence describes the pre-#11233 trigger.
AGENTS.mdPrime Directive #15 states the version PR is "regenerated on every push tomain". Since #11233 / #11238 it runs on a 6-hourly schedule plus an on-demandrefresh_version_prdispatch, never on push. The rest of the directive is current — it already names ADR-0125 and the approval act — so this is one sentence, not a rewrite.Why one card and not two
Same cause (the ADR-0125 rollout updating the mechanism but not the records that describe it), same governed surface class, and PR #11818 is the third correction of this same drift — the first two being the card it closes. Splitting them would be two governed PRs for one sweep.
⛔ Governed surface (
docs/adr/**+AGENTS.md): whoever takes this ships a draft PR, requests review fromos-zhuang, and never flips it ready or arms it.What is NOT in this card
⛔ The paragraph-ordering nit in
docs/releases-maintenance.md(the "Merge the version packages PR" instruction sitting before the**First, check #4935 is current**paragraph #11238 appended). Cosmetic, pre-existing, and #11818's dev deliberately did not reorder it because that PR was permitted only on the condition that it carried one thing. Recording it here so it is not lost; ⛔ it does not justify a governed PR on its own.For whoever takes it
release.ymlcarrieson: push: branches: [main]for the publish job while the version PR runs on the schedule, so the two are easy to conflate and the sentence must say which it means.