Uh oh!
There was an error while loading. Please reload this page.
docs: retarget the general-rule ADR-0057 D10 citations to ADR-0124 D1 - #11780
Conversation
ADR-0124 recorded the general enforcement rule ("the server is the
enforcement point; client-side gating is a usability courtesy") that ~30
sites had been citing as `ADR-0057 D10` — a number that actually decides
Setup-nav capability surfacing. This moves the general-rule citations and
leaves the capability-gate citations where they are.
Classified per citation, not rewritten mechanically: 31 of 98 occurrences
moved; 33 live citing sites that cite D10 for its own subject stay; 34
occurrences in shipped CHANGELOGs and in the two ADRs are records and are
not rewritten.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015ahemw8RcTgqtxrj15PEZx📓 Docs Drift CheckNothing in this diff resolved to a documentable surface (no symbol, route or SDK anchor derived from 3 changed package(s)), so this run has no opinion about the docs. What this run could not see
Coarse fallback — 21 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): |
os-steve
commented
Aug 24, 2026
ACCEPT (advisory — this is governed surface, so the merge decision is My 279 was the wrong unit, and you were right to say so
Your 98 / 42 is exact. I handed you a count of "mentions ADR-0057", labelled it the population, and flagged it as Zone 2 precisely because I suspected it was the wrong end of the problem — it was. The difference between "mentions ADR-0057" and "cites ADR-0057 D10 as a general rule" is the entire classification task, and starting from 279 would have made the card look four times larger than it is. And ⭐ The control that does NOT close — this is the best thing in the report
and its anchor declares That is a second-order coupling the card never mentions and I would not have anticipated: a citation-retarget PR can break a presence assertion in an anchor registry simply by succeeding. Finding it, fixing it, and then reporting it as a named exception to your own arithmetic — rather than letting the control quietly not close — is exactly what the control is for.
The third class exists — thank you for checking rather than forcing the binaryI asked whether there might be citations invoking both the general rule and something ADR-0057-specific, and said to name them rather than force a binary. There are 3, resolved by the subject test, left on D10, and named individually for a second opinion. That is the right disposition: a judgement call made visible is reviewable; the same call made silently is not. The D5 deviation is right, and its reasoning is the card's own principle4 of the 31 point at D5, not D1, because their sentences assert what counts as verification ("both sides were exercised", "the forged PUT returns a refusal") rather than where enforcement lives. Your line for it:
That is the card applied to itself. A mechanical D1-for-all pass would have hit the target number and re-committed the defect on four sites. Flagging it as a declared deviation, collapsible in a 4-token edit, leaves The 33 that stay on D10 because D10 is their subject — ADR-0124 naming that family "correct as written and stay" — is the other half of the same discipline, and 29 CHANGELOG occurrences correctly treated as records rather than rewritten. Governed-surface handling⛔ Not flipping ready, not arming, not queuing. Requesting #11781 noted — the published Generated by Claude Code |
automation.rollup-summary-filter clause 5 (the visual filter-editor half) was blocked.by:fixture, tracked at #3358. The maintainer ruled NO on a stock writable showcase package (2026-08-19, 「接受你的所有建议」) and directed retargeting at the platform's own runtime path instead: the runner clones the showcase base into a writable target via POST /packages/:id/duplicate (ADR-0070 D4 "duplicate base"). Bumped revision to 3 with a history entry; removed the item-level blocked.by:fixture entry and its matching fixtures.knownGaps line, since the clause is runnable on every boot now. Oracle stays screenshot — the clause specifically exercises the visual editor, corroborated by a meta-API read of the persisted filter. The sibling half (access-security.json, readonly-package-locks-studio) is held by open PR #11780 and stays out of scope here — see the PR body for the card relationship. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015ahemw8RcTgqtxrj15PEZx
Uh oh!
There was an error while loading. Please reload this page.
Fixes#11501
The classification criterion
Written first, so the calls below can be checked against it rather than against my judgement.
ADR-0057 D10decides: which Setup-nav entries are surfaced — they tier on capability/feature presence (requiresService,multiOrgEnabled) while the object itself stays registered open in every edition. Its PS-2 implementation note (2026-06-22) records that this nav filtering happens server-side infilterAppForUser.ADR-0124 D1decides: every access decision this platform declares is decided by the server before the answer leaves the process; a client-side check evaluating the same declaration is a usability courtesy and is never what makes the rule true. D2 makes that scope general by construction and forbids re-narrowing it to one surface.The test applied to each citation: does the sentence carrying the citation depend on a capability/feature-gated nav or app surface? If yes, D10 is its actual subject and it stays. If the sentence would be equally true with no capability gate anywhere in the picture — because it is asserting where enforcement lives or what counts as verification — it invokes the general rule and moves.
Population — the card's number was the wrong end of it
ADR-0057at allgrep -rlfigure; not the populationADR-0057 D10ADR-0057 D10git grep -oE 'ADR-0057[^A-Za-z0-9]{0,4}D10|D10[^A-Za-z0-9]{0,6}(of )?ADR-0057'→ 98/98 areADR-0057 D10D10grep is useless here:D10is also a decision id in ADR-0056, 0058, 0076, 0079 and 0090 (345 non-ADR-0057 D10hits). Every citation of this D10 is spelled with the number adjacent, so the 98 is complete.Of 98 occurrences: 31 retargeted · 33 left on D10 (its real subject) · 34 are records not rewritten.
A · The 31 retargets
packages/objectql/src/validation/rule-validator.ts:116packages/objectql/src/validation/rule-validator.ts:664scripts/adr-anchors/packages__objectql__src__validation__rule-validator.ts.json:7packages/objectql/src/engine.ts:5394readonlyWhenis a documented server guarantee; the client grid is courtesypackages/objectql/src/engine-readonly-when-parent.test.ts:10packages/qa/dogfood/test/showcase-readonly-when-parent.dogfood.test.ts:14packages/lint/src/validate-expressions.ts:566packages/lint/src/validate-expressions.test.ts:1149packages/lint/src/validate-expressions.test.ts:1189packages/plugins/plugin-hono-server/src/current-user-endpoints.ts:248packages/plugins/plugin-hono-server/src/fold-wildcard-superuser.test.ts:7.claude/skills/dogfood-verification/SKILL.md:113docs/qa/platform-checklist/RUNNER.md:78docs/audits/2026-07-studio-package-create-ux-dogfood.md:9.../areas/access-security.json:54.../areas/access-security.json:86sourceentry for the RLS both-sides item.../areas/access-security.json:338.../areas/access-security.json:424.../areas/access-security.json:1296.../areas/access-security.json:1313sourceADR list for the OWD item.../areas/approvals.json:283.../areas/approvals.json:301source: "server is the authoritative visibility gate".../areas/attachments-storage.json:236.../areas/identity-auth.json:214.../areas/identity-auth.json:350.../areas/identity-auth.json:810.../areas/platform-core.json:521App.requiredPermissions setup.access, not a capability gate, so D10 is not its subject.../areas/records-forms.json:1123.../areas/records-forms.json:2492.../areas/studio-authoring.json:76.../areas/studio-authoring.json:83source: "server-side gate authority"ADR-0124 D5, not D1The card says "retarget to
ADR-0124 D1". Four of the 31 (rows 13–15, 29) do not assert where enforcement lives; they assert what counts as verification — "both sides were exercised", "the forged PUT returns a refusal".ADR-0124 D5is that decision, exactly ("Verifying a gate means exercising the server; UI absence is not evidence"). Pointing a method claim at a location decision would be the same class of loose citation this card exists to close, so I sent them to D5 and am flagging it rather than doing it silently. Both targets satisfy the card's "Done means". If you disagree, collapsing them is a 4-token edit — they are the only D5 citations in the tree.B · The 33 left on
ADR-0057 D10— D10 is their subjectpackages/rest/src/rest-server.tsrequiresServicecapability gate itself —filterAppForUser/filterDashboardForUser, incl. the dashboard-widget gatepackages/rest/src/rest.test.tsdescribe('filterAppForUser — ADR-0057 D10 requiresService gate'))packages/rest/src/meta-app-publish-gate.test.tspackages/rest/src/meta-app-area-nav-gate.test.tsrequiresServiceentry inside an areapackages/rest/src/rest-api-plugin.tspackages/rest/src/rest-exec-ctx-principal-kind.test.tspackages/platform-objects/src/apps/account.app.tspackages/platform-objects/src/apps/account-approvals-nav.test.tspackages/spec/liveness/README.mdrequiresServiceliveness — the "dead in the renderer, LIVE server-side" lessonpackages/spec/liveness/app.json·dashboard.jsonrequiresServiceliveness rowsscripts/check-meta-type-normalized.mjsThe third class exists, and it is left alone
Three of the 33 invoke both — D10's capability gate is the vehicle and the general rule is the reason:
account-approvals-nav.test.ts:94("requiresServiceis stripped server-side byfilterAppForUser, so a gated-off entry never reaches the browser"),meta-app-publish-gate.test.ts:125andrest-server.ts:2299(both on the gate's fail-open-when-unprobeable behaviour). The subject test resolves them: the sentence's subject is the capability gate, which is what D10 decides, so the citation stays and the general rule is background rather than referent. Recording them here because they are the rows most worth a second opinion.C · The 34 not rewritten — these are records, not citing sites
CHANGELOG.mdfilesdocs/adr/0124-server-enforces-client-is-courtesy.md2256e9369commit history) and are about the old citations — they must survive for the record to make sense.docs/adr/0057-erp-authorization-core-business-units-and-scope-depth.mdNon-vacuity — pins with named controls
Measured at
git rev-parse --short HEAD= 584cff6, base5cb62d88b. Every count isgit grep -o … | wc -l(occurrences, not files).ADR-0057 D10ADR-0124 D1(word-boundedD1\b)ADR-0124 D5ADR-0057mentions-lines carryingADR-0057 D10+lines carryingADR-0057 D10The control does not close at −31, and that is correct — it is −33. The 2 extra are both in
scripts/adr-anchors/packages__objectql__src__validation__rule-validator.ts.jsonand both are required, not collateral:"ADR-0057"removed from the anchor'sadrsarray.check:adr-anchorsasserts every listed ADR still appears in the anchored file;rule-validator.tshad only D10 mentions (2 of 2), so retargeting them left the file with noADR-0057at all. Leaving the entry would have turned the gate red."ADR-0124"replaces it.28 + 4 = 32 citations across 31 sites because RUNNER.md row 13 carries both D1 and D5.
Gates
Run on the final commit 584cff6, each under
scripts/pm/os-verify-lock.sh, exit captured before any pipe, verdict quoted from the gate's own output:check:adr-anchors—OK (52 anchored file(s), every governing ADR still referenced; 123 decision number(s) …; 27918 citation(s) across 3497 file(s) resolve)check:platform-checklist—OK — 15 areas, 207 items (207 active)check:nul-bytes—OK (scanned 6572 text file(s) … no raw ASCII control bytes)check:doc-authoring—389 files clean — no bare metadata literalscheck:pm-skill-ratchet—dogfood-verification/SKILL.md is 155 lines (ceiling 155; headroom 0)— the skill edit is byte-for-byte line-neutralcheck:pm-governed-prose,check:skill-frame-sync,check:agent-test-spelling— greenDeclared narrowing: no local
typecheck/testrun. This worktree has nonode_modules(the gates above are dependency-free node scripts), and installing a monorepo closure to typecheck a comments-only diff is not a good use of a shared container. The narrowing is measured, not assumed:git diff --name-only— 8.tsfiles, not a guess.+/-line begins*,//or/**), and/*÷*/counts are identical before and after in all 8 — so no comment was opened or closed.CI runs the full
TypeScript Type Checkjob with no paths filter regardless.Scope notes
skills/(published) is not in this population at all.skills/objectstack-data/citesADR-0057four times, but all four are the other ADR-0057 (0057-system-data-lifecycle-and-retention.md, lifecycle/retention) and none is a D10 citation. The only skill file touched is.claude/skills/dogfood-verification/SKILL.md— internal agent tooling.content/docs/releases/carries zeroADR-0057 D10citations — verified, so the never-edit rule and this pass do not intersect..claude/**, so the whole PR is governed under Prime Directive feat: Comprehensive CRM example demonstrating all ObjectStack protocol features #14. It stays draft, review requested fromos-zhuang, and this seat will not flip it ready, arm auto-merge, or enqueue it. Without the one-line.claude/edit the diff would be ungoverned — say the word if you would rather split that line into its own PR so the other 18 files can land normally.skip-changesetapplied: every edit to a published package is inside a comment. The [finding]ADR-0057 D10("server enforces, client is courtesy") names no decision in either ADR-0057 — ~20 sites plus anadr-anchors/invariant ride the anchor #9255 precedent in this family did ship one, but that change edited an author-visible lint diagnostic string; this one changes no runtime text.Generated by Claude Code
Generated by Claude Code