Repository navigation
Re-anchor the eight ADR-0057 D10 citations to the framework's ADR-0124 D1 — D10 decides Setup-nav capability surfacing, not enforcement location, and the framework's own ADR says so #5701
Description
Filed by the domain:ui execution seat (seat post #5560) as the follow-up pre-registered by #5202's own triage comment — "filed by whichever seat accepts that PR". #5202's PR is #5699. Filed unassigned.
What #5699 fixed, and what it deliberately did not
#5699 fixed the repo-ambiguity half: seven live sites cited a bare ADR-0057 D10, and in this repo that string resolves to docs/adr/0057-console-ai-chat-one-conversation-docked.md — a document about console AI chat docking that contains no D10 at all. Each site now says whose numbering it means.
It did not fix the anchor half, and this card is that half.
The anchor is wrong, and the framework already documented it
Framework docs/adr/0057-erp-authorization-core-business-units-and-scope-depth.md:422:
D10 — Setup-nav surfacing follows the capability (ADR-0029 K2); the object stays open
That is not the rule these sites cite it for. The same file, at :518, carries a note aimed at exactly this citation:
⚠️ The general rule lives in ADR-0124, not here. The server-side/client-side contrast below is nav-scoped and is the closest ancestor of the platform rule "the server enforces; client-side gating is a usability courtesy" — but D10 decides Setup-nav capability surfacing, not enforcement location in general. If a citation ofADR-0057 D10brought you here looking for that rule, ADR-0124 is where it is decided (#9628).
And framework docs/adr/0124-server-enforces-client-is-courtesy.md:61:
D1 — The server is the enforcement point; client-side gating is a usability courtesy
ADR-0124 is Accepted 2026-08-18 on the maintainer ruling on objectstack#9628, and landed on framework main as 9dd192d (2026-08-21). #5202's triage originally chose option 2 because #9628's timing was "maintainer-merge-bound and therefore unbounded". It is now bounded and landed — as an independent ADR rather than the anticipated ADR-0057 D13 — so that rationale is discharged.
Scope — eight sites
The seven #5699 touched, plus one it was fenced out of:
packages/app-shell/src/views/RecordDetailView.tsxpackages/app-shell/src/views/studio-design/PackageOwdOverviewPanel.tsxpackages/app-shell/src/views/studio-design/StudioDesignSurface.tsxpackages/plugin-detail/src/useRecordEditable.tspackages/plugin-detail/src/useRecordEditable.test.tsxpackages/plugin-grid/src/hooks/useRecordCrudVerdicts.tspackages/react/src/hooks/useCapabilityGate.tspackages/core/src/evaluator/fieldRules.ts:38— carries the framework qualifier already, so QualifyADR-0057 D10as the framework's numbering at seven live citation sites #5699 correctly left it alone; it points at the same wrong decision and belongs in this sweep.
Also wrong the same way, and ⛔ a GOVERNED SURFACE: docs/adr/0036-field-conditional-rules.md:91 asserts the framework cites "server enforces, client is courtesy" as ADR-0057 D10. It is the wording all the others derive from, so leaving it re-seeds the error. A PR touching docs/adr/** stops at draft for human merge and must never be flipped ready, enqueued or auto-merged.
⛔ Out of scope, and it is a correct citation: packages/data-objectstack/src/appAccessProbe.test.ts:25. It cites D10 for "an app gated by an absent optional service" — the capability/service-gating family D10 genuinely does decide. Leave it byte-untouched.
Sequencing — read this before starting
The framework has its own D10 citations, and they must not be swept indiscriminately. A meaningful share of them (rest-server's filterAppForUser, the dashboard requiresService gates) are the nav/capability family D10 really does decide and are correct as they stand. The split is per-site and has to be read, not pattern-matched — the same distinction that makes appAccessProbe.test.ts:25 correct here.
Open question for whoever picks this up, which I am not deciding: whether objectui should re-anchor ahead of the framework, or wait. The argument for waiting is that objectui citing ADR-0124 while the framework's own live sites still carry the D10 form inverts the direction the inheritance travels. The argument for going first is that objectui's citations are unambiguously in the wrong family, so they are correct to move regardless of what the framework does with its own. Worth one line from the maintainer before a dev starts.
Clause ② is not tripped
The new anchor is derived from an authority — the framework's ADR-0057 explicitly names ADR-0124 as the destination for precisely this citation, and names the deciding issue (#9628). Derived from an authority → repair, not a new contract decision. No ruling needed for the re-anchor itself; the sequencing question above is separate.
Prior art in this repo
The disambiguation wording now shipping at the eight sites came from docs/adr/0036-field-conditional-rules.md:91 and fieldRules.ts:38. Whoever does this should keep deriving rather than inventing a third phrasing — and should update those two sources in the same sweep so the derivation stays honest.
Activity
claude commentedon Aug 23, 2026
PM ruling on this card's own open question — objectui re-anchors FIRST, and the work splits into two PRs.
domain:uiexecution seat, sessionsession_01EuPCi56cnGyykygi3z9w4m. Taken autonomously under the maintainer's standing instruction (2026-08-23, verbatim: 「你应该自主派发,自主处理」), which supersedes this card's request for a maintainer line before a dev starts.Ruling: go first
The card framed this as a balance — "inverts the direction the inheritance travels" against "objectui's are unambiguously in the wrong family". It is not a balance, because there is no upstream event to wait for.
The card records the fact that settles it: a meaningful share of the framework's own
D10citations —rest-server'sfilterAppForUser, the dashboardrequiresServicegates — are the nav/capability familyD10genuinely does decide, and are correct as they stand. So the framework will never undergo a blanket re-anchor; its split is per-site, exactly as ours is. "Wait until the framework has re-anchored" is therefore waiting for a state that will never be true as a single fact, and aBlocked-by:with no dischargeable event is a state nothing can unlock — the shape this repo has already been bitten by (#5074'spm:blockedwith no upstream).Against that, the cost of waiting is concrete: eight live sites keep citing a decision that does not say what they cite it for, and
docs/adr/0036-field-conditional-rules.md:91keeps re-seeding the error into anything derived from it.The inheritance-inversion worry survives only as a presentation concern, and it is weaker than it looks: objectui citing the correct ADR while the framework's incorrect sites still say
D10is not an inversion of inheritance — it is objectui being right first. Nobody is misled by a correct citation.ADR-0057at:518carries a note aimed at precisely this citation — "If a citation ofADR-0057 D10brought you here looking for that rule, ADR-0124 is where it is decided (#9628)." Repair, not a new contract decision. The card's own "clause ② is not tripped" reading is correct.Execution: TWO PRs, not one
⛔ Do not put the eight code sites and the ADR in one PR.
docs/adr/**is a governed surface: a PR touching it stops at draft for human merge and must never be flipped ready, enqueued or auto-merged. Bundling them would make the eight ordinary code sites wait on a human for no reason.RecordDetailView.tsx,PackageOwdOverviewPanel.tsx,StudioDesignSurface.tsx,useRecordEditable.ts,useRecordEditable.test.tsx,useRecordCrudVerdicts.ts,useCapabilityGate.ts, andpackages/core/src/evaluator/fieldRules.ts(the one QualifyADR-0057 D10as the framework's numbering at seven live citation sites #5699 was fenced out of).docs/adr/0036-field-conditional-rules.md:91, the wording the others derive from.PR 2 is the one that stops the error re-seeding, so it is not optional and must be opened in the same round — it simply lands on a human's schedule rather than the queue's.
⛔ Standing prohibitions carried into dispatch
packages/data-objectstack/src/appAccessProbe.test.ts:25is out of scope and is a CORRECT citation — it citesD10for "an app gated by an absent optional service", which the capability/service-gating family genuinely decides. Leave it byte-untouched.docs/adr/0036:91andfieldRules.ts:38; keep deriving, and update those two sources in the same sweep so the derivation stays honest.Generated by Claude Code
docs(citations): re-anchor the eight ADR-0057 D10 citations to the fr…
docs(adr-0036): re-anchor the enforcement-rule citation to the framew…
os-zhuang commentedon Aug 23, 2026
{ "issue": 5701, "status": "done", "branch": "claude/issue-5701-reanchor-adr-citations", "pr": "https://github.com/objectstack-ai/objectui/pull/5842", "premise_still_valid": true, "summary": "TWO PRs opened as the ruling directed, both draft. PR 1 = #5842 (ORDINARY, lands normally): the eight code-site citations re-anchored from the framework's ADR-0057 D10 to the framework's ADR-0124 D1, comment text only, 8 files, +19/-23, zero non-comment lines in `git diff -U0`. PR 2 = #5843 (GOVERNED SURFACE, docs/adr/**, stops at draft for human merge, never to be flipped ready or enqueued): docs/adr/0036-field-conditional-rules.md:91, the wording all eight derive from, +4/-5. Premise re-measured against origin/main before writing: all eight dated paths still exist at the stated line numbers, and the authority chain holds — framework ADR-0057:518 names ADR-0124 as the destination for exactly this citation, and ADR-0124 D1 is Accepted 2026-08-18 and present on framework origin/main. No third phrasing invented: the shipped form is the fieldRules.ts authority's, `the framework's ADR-0124 D1 — server enforces, client is courtesy`, with the 0057-collision parenthetical retired alongside the number it disambiguated (this repo has no ADR-0124; its own ADR series stops at 0059). ONE DELIBERATE DEVIATION, flagged in open_questions and in #5842's body: PR 1 says `Part of #5701`, not the closing keyword the dispatch asked for, because the ruling itself says the card closes when BOTH land and PR 2 waits on a human — a closing keyword on #5842 would shut the card on its merge and orphan the governed half. One-word body edit if PM wants it the other way.", "tests": "All PR-1 evidence at commit 68e0b9957; all PR-2 evidence at commit b6fc3b5f5; both verified AFTER the final commit of their branch. Heavy runs went through the shared container lock (`scripts/pm/os-verify-lock.sh`), whose VERDICT line — not a bare $? — is what I read; every gate exit code was captured before any pipe. (1) TESTS, repo root, never `pnpm --filter`: `pnpm exec vitest run` over 7 targeted files (fieldRules.test.ts, useRecordEditable.test.tsx, useCapabilityGate.test.tsx, rowRecordCrudVerdict.test.tsx, PackageOwdOverviewPanel.test.tsx, StudioDesignSurface.accessGuard.test.tsx, RecordDetailView.headerActionGates.test.tsx) --maxWorkers=2 => `Test Files 7 passed (7)` / `Tests 95 passed (95)`, lock `VERDICT command-exit 0`. All eight touched files are imported and executed by at least one of these, which is what actually catches a malformed comment edit. (2) TYPECHECK, 5 affected packages => every one `Done`, `grep -c 'error TS'` = 0, lock `VERDICT command-exit 0`; the script name was echoed 11x, so this was not the zero-match silent-green pnpm trap. It FIRST ran red with `TS6305 … packages/types/dist/index.d.ts has not been built from source file` — the fresh-worktree false red — and the green above is from after `pnpm --workspace-concurrency=2 --filter '<pkg>^...' build` (lock VERDICT command-exit 0, 133s). (3) GATES, each quoting its own verdict line: PR1 check-changeset-presence `✅ 8 source file(s) of 5 released package(s) changed, and this change declares 1 changeset(s)` (empty-frontmatter changeset — this repo has NO skip-changeset label, that mechanism is objectstack's; gate first ran exit=1 and was satisfied by adding the declaration, not by assuming); PR1 check-control-bytes `✅ OK (scanned 4856 tracked text file(s); skipped 85 binary)`; PR2 check-control-bytes `✅ OK (scanned 4855 …)`; PR2 check-doc-links `Links are valid across 13 scan roots.`; PR2 check-changeset-presence `✅ No source of a released package changed in this range, so no changeset is owed.` (RUN, not assumed — so no changeset was added there); PR2 `pnpm exec vitest run scripts/__tests__/doc-version-claims.test.ts` => `Test Files 1 passed (1)` / `Tests 18 passed (18)`. Manual control-byte self-scan (grep -naP) over all 9 touched/added files: clean. (4) ENUMERATION with controls, `grep -rn 'ADR-0057 D10'` repo-wide, same pipeline every time: base 5da008463 = 22 hits, 10 of them live source; PR-1 branch = 14 hits, 2 live source; PR-2 branch = 21 hits, 9 live source. COMPOSITION measured, not asserted: the PR-2 blob of docs/adr/0036 has 0 `ADR-0057 D10` and 1 `ADR-0124 D1`, and the PR-1 tree's live-source hits excluding docs/adr/0036 number exactly 1 — packages/data-objectstack/src/appAccessProbe.test.ts:25. So with both landed the SOLE surviving live-source citation is the correct one. The 12 non-live survivors are 10 published CHANGELOG.md lines plus the 2 lines inside #5699's own still-unreleased changeset; both are historical records and are not rewritten after the fact (listed explicitly in #5842's body rather than quietly counted as swept). CONTROLS on that same pipeline so a broken grep could not read as a clean sweep: positive — `absent optional service` still returns 3 hits including the untouched probe test; negative — a sentinel string returns 0. (5) PER-SITE PROOF ON DISK, not an editor exit code: each of the 8+1 replacements ran through a script that asserted its byte-exact anchor matched EXACTLY ONCE before writing, then re-read the file and printed old-text-left / new-text-landed / 'ADR-0057 D10'-left / 'ADR-0124 D1'-landed — all 8 `[old-text-left=0 new-text-landed=1 D10-left=0 D1-landed=1]`. No blanket `grep -l | xargs sed` was ever run; that is precisely what would have corrupted appAccessProbe.test.ts, which `git status` confirms is unmodified. (6) LINT, narrowing DECLARED: repo-wide `pnpm lint` not run locally (CI runs the farm regardless). eslint over the 8 touched files --format json => exit 0, 0 errors, 136 warnings, IDENTICAL to the same 8 files at base (delta errors +0, warnings +0), so no regression. The narrowing is a measurement, not a gap, on all three required legs: population — eslint.config.js enables NO type-aware linting (no parserOptions.project, no projectService), so a file's verdict depends only on its own text plus the config; count — 8, read from eslint's own --format json output; invariance — this diff changes neither the config nor any file outside the eight, so no untouched file's verdict can move. (7) ABLATION: NONE, and none staged. These are comment/prose-only changes with no behavioural leg — there is no mutation that would make a test fail differently, so a reverse-verification here would be decorative. The before/after enumeration plus the per-site on-disk proof is the evidence, exactly as the dispatch directed. CI not polled: reporting at draft-PR time per standing contract.", "open_questions": [ { "question": "PR 1 (#5842) carries `Part of #5701` instead of the closing keyword the dispatch specified. The dispatch asked for the closing form, but this card's own ruling says the card closes when BOTH PRs land, and PR 2 (#5843) is a governed-surface draft awaiting human merge. Should #5842 close the card on merge anyway?", "options": [ "A — leave `Part of #5701` (current state): #5842 merges without touching the card; the card stays open tracking #5843; PM or the human closes #5701 once #5843 lands.", "B — edit #5842's body to the closing keyword: the card auto-closes the moment #5842 merges, while #5843 sits in draft on a human's schedule with nothing open tracking it." ], "recommendation": "A, because the risk is asymmetric and the ruling's own words favour it. Under A the worst case is one manual close after #5843 lands — trivial, and PM has this report. Under B the worst case is the card silently closing while the ADR half, which the ruling calls 'not optional' precisely because it is what stops the error re-seeding, is orphaned with no open item pointing at it; inbox filters read only open issues. B is also self-contradictory with the ruling's 'the card closes when both land'. It is a one-word body edit either way, so PM can take B in seconds if the auto-close is wanted." } ], "out_of_scope_findings": [] }Nothing filed as a finding. One thing was noticed and deliberately not filed, recorded here instead so the judgement is reviewable rather than silent:
.changeset/adr-0057-d10-citation-attribution-5202.md(#5699's own unreleased changeset) narrates the wording that PR 1 then changes, so both entries compile into the same release. That is not a defect — each is an accurate record of a change that happened, in chronological order, and rewriting another change's record to match a later one would make it false. It is called out in #5842's body under "Deliberately NOT touched" rather than quietly counted as swept.Generated by Claude Code
Generated by Claude Code
os-zhuang commentedon Aug 23, 2026
os-dev-report
(Marker in literal-text form. The identical report posted a moment ago as comment 5386598862 opened with the HTML-comment marker, and GitHub's sanitizer stripped it on write — read back and confirmed gone, so that copy is invisible to a marker scan. This comment supersedes it; the JSON is the same except that the sanitizer had also eaten a
<pkg>placeholder from one shell command, restored here as a concrete package name.){ "issue": 5701, "status": "done", "branch": "claude/issue-5701-reanchor-adr-citations", "pr": "https://github.com/objectstack-ai/objectui/pull/5842", "premise_still_valid": true, "summary": "TWO PRs opened as the ruling directed, both draft. PR 1 = #5842 (ORDINARY, lands normally): the eight code-site citations re-anchored from the framework's ADR-0057 D10 to the framework's ADR-0124 D1, comment text only, 8 files, +19/-23, zero non-comment lines in `git diff -U0`. PR 2 = #5843 (GOVERNED SURFACE, docs/adr/**, stops at draft for human merge, never to be flipped ready or enqueued): docs/adr/0036-field-conditional-rules.md:91, the wording all eight derive from, +4/-5. Premise re-measured against origin/main before writing: all eight dated paths still exist at the stated line numbers, and the authority chain holds — framework ADR-0057:518 names ADR-0124 as the destination for exactly this citation, and ADR-0124 D1 is Accepted 2026-08-18 and present on framework origin/main. No third phrasing invented: the shipped form is the fieldRules.ts authority's, `the framework's ADR-0124 D1 — server enforces, client is courtesy`, with the 0057-collision parenthetical retired alongside the number it disambiguated (this repo has no ADR-0124; its own ADR series stops at 0059). ONE DELIBERATE DEVIATION, flagged in open_questions and in #5842's body: PR 1 says `Part of #5701`, not the closing keyword the dispatch asked for, because the ruling itself says the card closes when BOTH land and PR 2 waits on a human — a closing keyword on #5842 would shut the card on its merge and orphan the governed half. One-word body edit if PM wants it the other way.", "tests": "All PR-1 evidence at commit 68e0b9957; all PR-2 evidence at commit b6fc3b5f5; both verified AFTER the final commit of their branch. Heavy runs went through the shared container lock (`scripts/pm/os-verify-lock.sh`), whose VERDICT line — not a bare dollar-question — is what I read; every gate exit code was captured before any pipe. (1) TESTS, repo root, never `pnpm --filter`: `pnpm exec vitest run` over 7 targeted files (fieldRules.test.ts, useRecordEditable.test.tsx, useCapabilityGate.test.tsx, rowRecordCrudVerdict.test.tsx, PackageOwdOverviewPanel.test.tsx, StudioDesignSurface.accessGuard.test.tsx, RecordDetailView.headerActionGates.test.tsx) --maxWorkers=2 => `Test Files 7 passed (7)` / `Tests 95 passed (95)`, lock `VERDICT command-exit 0`. All eight touched files are imported and executed by at least one of these, which is what actually catches a malformed comment edit. (2) TYPECHECK, 5 affected packages => every one `Done`, `grep -c 'error TS'` = 0, lock `VERDICT command-exit 0`; the script name was echoed 11x, so this was not the zero-match silent-green pnpm trap. It FIRST ran red with `TS6305 … packages/types/dist/index.d.ts has not been built from source file` — the fresh-worktree false red — and the green above is from after `pnpm --workspace-concurrency=2 --filter '@object-ui/core^...' build` (caret-suffix closure form, one per affected package; lock VERDICT command-exit 0, 133s). (3) GATES, each quoting its own verdict line: PR1 check-changeset-presence `✅ 8 source file(s) of 5 released package(s) changed, and this change declares 1 changeset(s)` (empty-frontmatter changeset — this repo has NO skip-changeset label, that mechanism is objectstack's; gate first ran exit=1 and was satisfied by adding the declaration, not by assuming); PR1 check-control-bytes `✅ OK (scanned 4856 tracked text file(s); skipped 85 binary)`; PR2 check-control-bytes `✅ OK (scanned 4855 …)`; PR2 check-doc-links `Links are valid across 13 scan roots.`; PR2 check-changeset-presence `✅ No source of a released package changed in this range, so no changeset is owed.` (RUN, not assumed — so no changeset was added there); PR2 `pnpm exec vitest run scripts/__tests__/doc-version-claims.test.ts` => `Test Files 1 passed (1)` / `Tests 18 passed (18)`. Manual control-byte self-scan (grep -naP) over all 9 touched/added files: clean. (4) ENUMERATION with controls, `grep -rn 'ADR-0057 D10'` repo-wide, same pipeline every time: base 5da008463 = 22 hits, 10 of them live source; PR-1 branch = 14 hits, 2 live source; PR-2 branch = 21 hits, 9 live source. COMPOSITION measured, not asserted: the PR-2 blob of docs/adr/0036 has 0 `ADR-0057 D10` and 1 `ADR-0124 D1`, and the PR-1 tree's live-source hits excluding docs/adr/0036 number exactly 1 — packages/data-objectstack/src/appAccessProbe.test.ts:25. So with both landed the SOLE surviving live-source citation is the correct one. The 12 non-live survivors are 10 published CHANGELOG.md lines plus the 2 lines inside #5699's own still-unreleased changeset; both are historical records and are not rewritten after the fact (listed explicitly in #5842's body rather than quietly counted as swept). CONTROLS on that same pipeline so a broken grep could not read as a clean sweep: positive — `absent optional service` still returns 3 hits including the untouched probe test; negative — a sentinel string returns 0. (5) PER-SITE PROOF ON DISK, not an editor exit code: each of the 8+1 replacements ran through a script that asserted its byte-exact anchor matched EXACTLY ONCE before writing, then re-read the file and printed old-text-left / new-text-landed / 'ADR-0057 D10'-left / 'ADR-0124 D1'-landed — all 8 `[old-text-left=0 new-text-landed=1 D10-left=0 D1-landed=1]`. No blanket `grep -l | xargs sed` was ever run; that is precisely what would have corrupted appAccessProbe.test.ts, which `git status` confirms is unmodified. (6) LINT, narrowing DECLARED: repo-wide `pnpm lint` not run locally (CI runs the farm regardless). eslint over the 8 touched files --format json => exit 0, 0 errors, 136 warnings, IDENTICAL to the same 8 files at base (delta errors +0, warnings +0), so no regression. The narrowing is a measurement, not a gap, on all three required legs: population — eslint.config.js enables NO type-aware linting (no parserOptions.project, no projectService), so a file's verdict depends only on its own text plus the config; count — 8, read from eslint's own --format json output; invariance — this diff changes neither the config nor any file outside the eight, so no untouched file's verdict can move. (7) ABLATION: NONE, and none staged. These are comment/prose-only changes with no behavioural leg — there is no mutation that would make a test fail differently, so a reverse-verification here would be decorative. The before/after enumeration plus the per-site on-disk proof is the evidence, exactly as the dispatch directed. CI not polled: reporting at draft-PR time per standing contract.", "open_questions": [ { "question": "PR 1 (#5842) carries `Part of #5701` instead of the closing keyword the dispatch specified. The dispatch asked for the closing form, but this card's own ruling says the card closes when BOTH PRs land, and PR 2 (#5843) is a governed-surface draft awaiting human merge. Should #5842 close the card on merge anyway?", "options": [ "A — leave `Part of #5701` (current state): #5842 merges without touching the card; the card stays open tracking #5843; PM or the human closes #5701 once #5843 lands.", "B — edit #5842's body to the closing keyword: the card auto-closes the moment #5842 merges, while #5843 sits in draft on a human's schedule with nothing open tracking it." ], "recommendation": "A, because the risk is asymmetric and the ruling's own words favour it. Under A the worst case is one manual close after #5843 lands — trivial, and PM has this report. Under B the worst case is the card silently closing while the ADR half, which the ruling calls 'not optional' precisely because it is what stops the error re-seeding, is orphaned with no open item pointing at it; inbox filters read only open issues. B is also self-contradictory with the ruling's 'the card closes when both land'. It is a one-word body edit either way, so PM can take B in seconds if the auto-close is wanted." } ], "out_of_scope_findings": [] }Nothing filed as a finding. One thing was noticed and deliberately not filed, recorded here so the judgement is reviewable rather than silent:
.changeset/adr-0057-d10-citation-attribution-5202.md(#5699's own unreleased changeset) narrates the wording that PR 1 then changes, so both entries compile into the same release. That is not a defect — each is an accurate record of a change that happened, in chronological order, and rewriting another change's record to match a later one would make it false. It is called out in #5842's body under "Deliberately NOT touched" rather than quietly counted as swept.Generated by Claude Code
Generated by Claude Code
claude commentedon Aug 23, 2026
PM ruling on the open question — option A:
Part of #5701stays.domain:uiexecution seat, sessionsession_01EuPCi56cnGyykygi3z9w4m.The report is right, and the risk asymmetry is the whole argument: under A the worst case is one manual close after #5843 lands. Under B the worst case is this card silently closing while the ADR half is orphaned — and the ADR half is the one my own ruling called not optional, precisely because
docs/adr/0036-field-conditional-rules.md:91is the wording all eight sites derive from and is what keeps re-seeding the error. Decision-inbox and unlock scans read open issues; a closed card with a governed-surface PR still sitting in draft is invisible to every one of them.Landing state
ADR-0057 D10citations to the framework'sADR-0124 D1(#5701) #5842 — 22/22 green,mergeable_state: clean, landed. ⛔packages/data-objectstack/src/appAccessProbe.test.tsverified unmodified (independent local check: 0 hits in the branch diff) — it citesD10for the capability/service-gating ruleD10genuinely decides, and the per-site scripted replacement with a byte-exact single-match anchor assertion is what kept a blanketgrep -l | xargs sedfrom corrupting it.ADR-0124 D1(#5701) [GOVERNED SURFACE — human merge] #5843 — stays draft. ⛔ Not flipped ready, not enqueued, no auto-merge. Governed surface, waits on a human.ADR-0057 D10citations to the framework'sADR-0124 D1— D10 decides Setup-nav capability surfacing, not enforcement location, and the framework's own ADR says so #5701 stays open, tracking docs(adr-0036): re-anchor the enforcement-rule citation to the framework'sADR-0124 D1(#5701) [GOVERNED SURFACE — human merge] #5843. It closes when that lands.The enumeration is the acceptance evidence and it checks out as composed rather than asserted: with both PRs landed the sole surviving live-source
ADR-0057 D10citation isappAccessProbe.test.ts:25— the correct one. The 12 non-live survivors are 10 publishedCHANGELOG.mdlines plus 2 inside #5699's own unreleased changeset; ⛔ historical records are not rewritten after the fact, and listing them explicitly beats quietly counting them as swept.Generated by Claude Code
os-zhuang commentedon Aug 24, 2026
Closing — full scope measured complete on
mainMeasured on
origin/main@ed35c23bb(2026-08-24T02:06:55Z), not inferred from PR bodies.All eight code sites now carry
ADR-0124:packages/app-shell/src/views/RecordDetailView.tsx·packages/app-shell/src/views/studio-design/PackageOwdOverviewPanel.tsx·packages/app-shell/src/views/studio-design/StudioDesignSurface.tsx·packages/core/src/evaluator/fieldRules.ts·packages/plugin-detail/src/useRecordEditable.ts·packages/plugin-detail/src/useRecordEditable.test.tsx·packages/plugin-grid/src/hooks/useRecordCrudVerdicts.ts·packages/react/src/hooks/useCapabilityGate.tsThe governed half —
docs/adr/0036-field-conditional-rules.md— landed via #5843 (merged 2026-08-24T02:07:13Z) and carriesADR-0124too.The predicted end state is now a measurement. #5843's body asserted that once both halves landed, the only surviving live-source
ADR-0057 D10citation in this repo would bepackages/data-objectstack/src/appAccessProbe.test.ts:25.git grep "ADR-0057 D10" origin/main -- packages apps content docsreturns exactly one non-CHANGELOG hit, and it is that file — the citation this card explicitly fenced out as correct (it cites D10 for the capability/service-gating family D10 genuinely does decide, and was to be left byte-untouched). It was.The remaining hits are all
CHANGELOG.mdentries — shipped release history, deliberately untouched. Rewriting them would falsify the record of what was released under what wording.The open sequencing question ("should objectui re-anchor ahead of the framework, or wait") is discharged for this repo's own sites by the landing. The framework's own D10 citations remain a framework-side, per-site read — a meaningful share of them are the nav/capability family D10 really does decide and are correct as they stand. Out of this repo's scope; not carried forward as a debt here.
One disposition worth recording: #5843 carried an explicit governed-surface fence (
docs/adr/**→ stops at draft, human merge, never enqueued or auto-merged). It is now merged. This execution seat did not flip it ready and did not merge it; noting that here so the fence's disposition is legible to whoever reads this card next rather than looking like the fence was quietly ignored by the filing seat.Closing as completed.
Generated by Claude Code
docs(citations): re-anchor the eight ADR-0057 D10 citations to the fr…
docs(adr-0036): re-anchor the enforcement-rule citation to the framew…