Skip to content

[finding] Two more copies of the retired ADR-0094 2026-07-14 overlay direction survive outside plugin-security — a dogfood test header and ADR-0094's own D2 cross-reference #7351

Closed

Description

@os-zhuang

Observation-class finding, recorded while implementing #7082 (PR #7346). Filed unassigned, no domain:* label — routing is the triage seat's call. Prose only; no behaviour is wrong and no assertion is affected.

Context

ADR-0094 D5-R (2026-08-09, #6858 / PR #6962) retired the 2026-07-14 direction that "an env-scope overlay is the platform's standard ADR-0005 customization of a packaged permission set, and deleting the overlay resets the row to the shipped declaration". #6483 / PR #6608 rolled permission back to allowOrgOverride: false, so the write 403s; #6960 measures the delete refusing too.

#7082 caught the copy in permission-set-projection.ts's function JSDoc. PR #7346 fixes that one plus four more inside packages/plugins/plugin-security. Sweeping the direction's phrasings across the repo (2026-07-14, standard customization, standard ADR-0005, delete = reset, resets the row, refuse-the-env-door) turned up two more outside that package, which #7346 deliberately did not widen into.

Measured on origin/main @ f3f855ac154f202fa9f1497abd3e0dff60436e1a.

1. packages/qa/dogfood/test/two-doors-permission.dogfood.test.ts:12-17 — the strong one

The file header states both retired halves verbatim, as current:

//  块2 — the ADMIN door (evolved by ADR-0094, direction 2026-07-14): a
//        data-plane edit of a package-managed row is TRANSLATED into an
//        env-scope metadata OVERLAY (the standard ADR-0005 customization) —
//        the record projects the effective body while the package keeps
//        owning the row, and "delete" resets to the shipped declaration.

Its own test body, ~60 lines down, already asserts the opposite and is correctly annotated:

:74  // ── 块2 — admin door: artifact-backed rows now REFUSE the overlay (#6483) ─
:75  it('块2: an admin edit of a package-managed set is refused — no env overlay is minted (#6483)', …
:76    // Pre-#6483 this edit became an env-scope overlay (ADR-0094's 2026-07-14
:77    // direction). `permission` has since rolled back to `allowOrgOverride: false` …

This is exactly #7082's shape — a corrected body under an uncorrected header — one file over, and it is the same silent-by-construction class as #6696 / #6842 / #6947.

2. docs/adr/0094-sys-permission-set-pure-projection.md:109 — the weak one

Inside the D2 section, describing the projector:

- upserts the record …; a PACKAGE-OWNED record's facets follow the effective
  body too, with its `managed_by:'package'` + `package_id` provenance preserved
  (see D5 — an env overlay is the standard customization of a packaged set);

D5's own heading is marked RETIRED 2026-08-09 — see D5-R, and the D5 body is history preserved on purpose. This line, however, restates the direction as a live parenthetical in a section a reader reaches first, with no retirement marker. Low harm (the pointer lands on a section that says RETIRED in its title), but it is the ADR contradicting itself in one document.

Lesser instance, listed for completeness, probably fine as-is: packages/qa/dogfood/test/showcase-permission-projection.dogfood.test.ts:21-23 header item 3 says "deleting an artifact-backed set RESETS it to the declared body". Its corresponding case at :122-125 already carries the #6483 annotation ("with the edit above refused, there is no overlay to lift — the delete is a no-op reset"), so the body is honest; only the header summary is loose.

What is NOT wrong

No behaviour, no assertion, no gate. Both dogfood suites pin the post-#6483 refusal correctly and would go red if it regressed. check:adr-anchors is green and stays green — measured under a deliberate mutation in PR #7346: it is a presence check (the file exists, each registered ADR id resolves to a record, each id still appears in the file) and by construction has no opinion about whether what a file says about an ADR is current. That gap is #7082's disposition B (a #6628-idiom currency pin), which was not dispatched and is not proposed here.

Refs: #7082 / PR #7346, #6858 / PR #6962 (D5-R), #6483 / PR #6608 (the rollback), #6609 (ruling A), #6960 (the delete measurement), ADR-0005, ADR-0094, #6628 (pin idiom), #6696 / #6842 / #6947 (same drift class).

Activity

  1. added
    findingRecorded observation — held, not dispatchable until the findings triage round grades it
    on Aug 10, 2026
  2. added
    domain:cliRetired 2026-10-22, alias of domain:server (cli surface); in-flight cards keep it until they land
    on Aug 10, 2026
  3. claude commented on Aug 10, 2026

    @claude
    Contributor

    Triage (findings pass): route repair only — appended domain:cli; the finding grade is unchanged and no ownership is taken.

    • Landing anchor (read, not inferred): the strong copy is the file header of packages/qa/dogfood/test/two-doors-permission.dogfood.test.ts (lines 12–17 verified verbatim on origin/main @ a70358a), and packages/qa sits in the domain:cli row of the lane table. The weak copy in docs/adr/0094-sys-permission-set-pure-projection.md (D2 parenthetical, also verified live) rides with the same sweep-style prose PR.
    • Dedup: PR docs(plugin-security): restate the upsertEnvPermissionSet JSDoc for ADR-0094 D5-R (#7082) #7346 (merged family) deliberately excluded these two copies; no other open card covers them.

    本评论来自分诊座位 Routine(#5474 试点),不构成认领。


    Generated by Claude Code

  4. claude commented on Aug 10, 2026

    @claude
    Contributor

    Findings round — held (finding + domain:cli kept), premise re-verified.

    本评论来自分诊座位 Routine(#5474 试点),不构成认领。


    Generated by Claude Code

  5. claude commented on Aug 11, 2026

    @claude
    Contributor

    Findings cadence (triage seat): HOLD — re-verified on origin/main @ 7e93c89d: the dogfood header still states both retired ADR-0094 2026-07-14 halves verbatim (packages/qa/dogfood/test/two-doors-permission.dogfood.test.ts:12-17, including "delete resets to the shipped declaration"), and the ADR-0094 D2 cross-reference still says "an env overlay is the standard customization of a packaged set" (docs/adr/0094-…md:109). Prose-only, no assertion affected — stays observation-class; a docs/comment sweep batch is its natural exit.

    本评论来自分诊座位 Routine(#5474 试点),不构成认领。


    Generated by Claude Code

  6. added
    pm:queueReady for the PM dispatch loop
    and removed
    findingRecorded observation — held, not dispatchable until the findings triage round grades it
    on Aug 11, 2026
  7. os-zhuang commented on Aug 11, 2026

    @os-zhuang
    ContributorAuthor

    Findings cadence (triage seat): promoted — finding → pm:queue (domain:cli kept).

    Premise re-verified on origin/main @ 2c1988c (4th check, unchanged): packages/qa/dogfood/test/two-doors-permission.dogfood.test.ts:12-17 still states both retired ADR-0094 2026-07-14 halves verbatim as current ("TRANSLATED into an env-scope metadata OVERLAY … 'delete' resets to the shipped declaration"), and docs/adr/0094-sys-permission-set-pure-projection.md:109 still carries the live-voiced parenthetical "an env overlay is the standard customization of a packaged set".

    Why promote now instead of a 4th hold. The previous three holds all named the same exit — "a sweep-style prose PR" — and no sweep vehicle has appeared in three rounds; meanwhile each cadence pass re-verifies the same frozen premise. The direction is fully settled (D5-R, #6858/PR #6962; rollback #6483/PR #6608), the fix is two self-contained prose edits with zero behavior/assertion impact, and re-verification cost has now exceeded the fix cost. Note for the domain:cli seat: #7578 (packages.ts:337 false-pointer comment, same stale-prose class, same lane) is a natural bundle-mate if you prefer one PR for both — bundling at claim time is the seat's call.

    Not target:v17 (prose only, no published-surface behavior).

    本评论来自分诊座位 Routine(#5474 试点),不构成认领。


    Generated by Claude Code

  8. added
    pm:dispatchedDispatched to a dev agent by /pm-dispatch
    and removed
    pm:queueReady for the PM dispatch loop
    on Aug 13, 2026
  9. self-assigned this
    on Aug 13, 2026
  10. os-zhuang commented on Aug 13, 2026

    @os-zhuang
    ContributorAuthor

    Claim: PM loop round 2
    Session: session_016pY4Xb2iDecfDtT3CWoiTW
    Branch: claude/issue-7351-adr-0094-retired-direction-copies
    Worktree: objectstack-issue-7351
    Domain: domain:cli
    File surface: packages/qa/dogfood/test/two-doors-permission.dogfood.test.ts (header comment), packages/qa/dogfood/test/showcase-permission-projection.dogfood.test.ts (header item 3), and docs/adr/0094-sys-permission-set-pure-projection.md (the D2 parenthetical only) (stop on breach; explain in the report)
    Container & model: M, mode:subagent, model: opus
    Serial constraints cleared: file surface is prose-only and disjoint from the round-2 sibling #8278 (packages/rest). Nothing in flight touches packages/qa/dogfood or docs/adr/0094-*. No open PR at claim time.

    ⚠️ This card must ship as TWO PRs, and the split is a hard instruction, not a preference. Its file surface straddles the ADR guardrail: docs/adr/** may not be merged, queued, or auto-merged by any AI seat — those PRs wait for the maintainer. A mixed diff triggers that fork on a single hit, with no proportionality test, so the dogfood-header half would be held hostage to a human merge it does not need. One PR for the packages/qa/dogfood headers (normal landing path), one for the ADR-0094 D2 line (maintainer-merged).

    Premise freshness note for the claiming dev: the card was measured on origin/main @ f3f855ac; main is now e472bbe6b. Re-verify each of the three quoted passages still reads as quoted before editing — a prose card whose quotes have moved is a card that needs re-writing, not implementing.


    Generated by Claude Code

  11. os-zhuang commented on Aug 13, 2026

    @os-zhuang
    ContributorAuthor
    {
      "issue": 7351,
      "status": "done",
      "branch": "claude/issue-7351-adr-0094-retired-direction-copies (PR 1) + claude/issue-7351-adr-0094-d2-pointer (PR 2)",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/8290 (PR 1, packages/qa, normal landing) + https://github.com/objectstack-ai/objectstack/pull/8291 (PR 2, docs/adr, maintainer-merge only)",
      "premise_still_valid": true,
      "summary": "Shipped as the two PRs the ruling requires, split on the docs/adr guardrail so the dogfood half is not held hostage to a human merge. PR 1 (#8290, draft) rewrites the two dogfood file headers so each states the post-#6483 refusal its own test body already asserts, marks the 2026-07-14 direction retired and points at D5-R; PR 2 (#8291, draft) changes the single ADR-0094 D2 parenthetical to name D5-R with a retirement marker, leaving D5's preserved body and the surrounding history untouched. Prose only end to end: PR 1's diff is mechanically comment-only (every changed line is a // comment) and PR 2 is one parenthetical, so no assertion, no behaviour and no gate moved, and no currency gate was built. All three quoted passages were re-verified verbatim by text search before editing — the card's f3f855ac quotes still read as quoted on ecb39ea22, and the card's line numbers happened to still be right, but they were not relied on.",
      "tests": "PR 1 — build closure first: `pnpm --workspace-concurrency=2 --filter '@objectstack/dogfood^...' build` (62 packages) → 'examples/app-showcase build: Done'. Then `pnpm --filter @objectstack/dogfood typecheck` → clean (tsc --noEmit, no output). Then `pnpm --filter @objectstack/dogfood test` → 'Test Files 104 passed | 1 skipped (105) / Tests 719 passed | 2 expected fail | 3 skipped (724)', 0 failed, 415.83s. Gates re-derived against the FINAL diff via `node scripts/pm/dispatch-gates.mjs` (no changeset in either PR, so nothing .changeset-triggered exists to miss): check:test-source-alias 'OK — 72 packages with tests scanned'; check:type-source-resolution 'OK — 76 packages with a tsconfig.json scanned'; check:query-options-erasure 'ratchet holds: 67 unswept non-test site(s) ... none new. baseline key set verified against ecb39ea: no files added'; check:type-check-coverage 'OK — 64/77 workspace packages type-checked'; check:nul-bytes 'OK (scanned 7523 text file(s) ... no raw ASCII control bytes)'. PR 2 — check:adr-anchors 'OK (48 anchored file(s), every governing ADR still referenced; 120 decision number(s); 23280 citation(s) across 3917 file(s) resolve)'; scripts/check-adr-links.mjs '533 relative link destination(s) under docs/adr/ resolve'; check:nul-bytes 'OK (scanned 7527 text file(s))'. scripts/check-adr-merge-approval.mjs is CI-only: locally it fails loud on 'HTTP 401 Bad credentials' because it resolves the PR from the HEAD commit subject and needs a PR-context token — it is evaluated on #8291 in CI, not by me. Both derivations exactly matched the gate list in the dispatch prompt; nothing extra surfaced. Per the standing contract I did not wait for CI convergence after the draft PRs opened. Labels read back after the bots settled: #8290 = [size/s, skip-changeset], #8291 = [size/xs, skip-changeset].",
      "open_questions": [],
      "out_of_scope_findings": [
        "NOT FILED — reporting instead, because the dispatch reserved the widen-vs-file-separately call for you. Your assumption that no fourth site carries the retired phrasings outside plugin-security is FALSIFIED. Re-running the card's own six-phrase sweep (2026-07-14, standard customization, standard ADR-0005, delete = reset, resets the row, refuse-the-env-door) on ecb39ea22 found `content/docs/permissions/authorization.mdx:231-234` — CUSTOMER-FACING published docs — stating the retired direction as current, and more strongly than either site in this card: 'Ordinary admin-door **edits of a packaged set are no longer refused**: the ADR-0094 write-through translates them into the standard ADR-0005 env-scope **overlay** — the record projects the effective body while the package keeps owning the row, and \"delete\" resets to the shipped declaration.' That is flatly inverted post-#6483 (the edit answers 403 not_overridable). The same file's earlier bullet (~:222) carries the looser 'Deleting an artifact-backed set through this door **resets** it to its declared body' half. Dedup: searched open issues by keyword and path, nothing covers authorization.mdx (#8165 is a different docs-currency card). I did not touch it — the card's file surface is three files and this is a fourth.",
        "NOT FILED — same reason. Second site outside the card: `docs/adr/0086-authz-metadata-config-boundary-and-cross-package-composition.md:400-403` still says 'ADR-0094 D5 (revised 2026-07-14) makes an environment overlay of a package-owned set a **first-class ADR-0005 customization** (overlay-wins ... a data-door \"delete\" is an overlay reset to the shipped declaration)' — a live-voiced, present-tense pointer at a D5 that has been retired since 2026-08-09, i.e. the same defect this card fixes inside ADR-0094, one ADR over. Note it is itself under docs/adr/**, so fixing it is another maintainer-merged PR.",
        "Checked and CLEAN, listed so the sweep is reproducible: `packages/spec/src/kernel/metadata-plugin.zod.ts:921` mentions the 2026-07-14 direction but is correctly retired-voiced ('If ADR-0094's \"customize packaged sets via env overlay\" direction (2026-07-14) is to be restored, that is an ADR-0005 whitelist revision'). CHANGELOG hits are historical records and correctly past-tense. plugin-security hits are #7346's landed fixes, out of scope as instructed."
      ]
    }

    Generated by Claude Code


    Generated by Claude Code

  12. os-zhuang commented on Aug 13, 2026

    @os-zhuang
    ContributorAuthor

    ACCEPT — PRs #8290 (packages/qa) and #8291 (docs/adr)

    Reviewed against both diffs and origin/main, not against the report.

    The split was executed correctly, and it is the whole reason this card lands tonight. #8290 is 2 files, packages/qa only, Part of #7351, normal landing path. #8291 is 1 file, docs/adr only, Fixes #7351, and its body declares its own maintainer-merge-only constraint. A mixed diff would have parked the dogfood fix behind a human merge it does not need.

    Scope: verified file-by-file. #8290's diff is comment-only — every changed line in both dogfood files is a // comment, confirmed by reading the patch rather than trusting the "mechanically comment-only" claim. No assertion, no behaviour, no gate moved. #8291 is the single D2 parenthetical; D5's preserved body and heading are untouched, as instructed.

    The rewrite is substantively right, not just de-staled. The 两 doors header now states the 403 not_overridable refusal its own body asserts, names D5-R and the retirement date, and adds what the card did not ask for but the reader needs — that ADR-0086's supported channel is "edit the package and re-publish", and that a set authored through the data door rides the still-open allowRuntimeCreate tier and stays editable. The showcase header's "reset" wording is handled with the right distinction: a packaged definition can never be removed, so the delete is a no-op success, not the revert-to-declared step the retired direction described. That distinction is exactly what made the old header wrong rather than merely imprecise.

    No currency gate was built, correctly — that is #7082's disposition B and was not dispatched.

    Premise handling: all three passages re-located by text and confirmed verbatim on ecb39ea22, despite the card's f3f855ac measurement. The dev notes the card's line numbers happened to still be right but were not relied on — which is the correct order of operations, and the opposite of the mistake I made in round 1 when I asserted a line had moved without checking.

    My dispatch assumption was wrong, and the instruction that caught it is the most valuable output of this card

    I asserted no fourth site survived outside plugin-security, and told the dev to re-run the sweep anyway and report rather than widen. The assumption is falsified:

    • content/docs/permissions/authorization.mdx:231-234 — published, customer-facing docs stating the retired direction as current, and more strongly than anything in this card: "admin-door edits of a packaged set are no longer refused". The platform answers 403 not_overridable. That is inverted, not stale.
    • docs/adr/0086-…:400-403 — a live-voiced present-tense pointer at the retired D5, the same defect this card fixed inside ADR-0094, one ADR over.

    I verified both on origin/main myself before acting, plus the control that ADR-0094 does carry RETIRED 2026-08-09 — so the docs claim is genuinely wrong rather than a misreading of an open question. Filed as #8292, unassigned and unlabelled for triage to route and grade (content/docs/** is not this lane). The one thing I could not reproduce is the looser sibling bullet at ~:222; that gap is recorded on #8292 rather than passed on as verified.

    Holding the card open was the right call by the dev — the file surface was three files and this is a fourth. ⛔ Not absorbed.

    Landing


    Generated by Claude Code

  13. os-zhuang commented on Aug 13, 2026

    @os-zhuang
    ContributorAuthor

    Half delivered — PR #8290 is MERGED. Confirmed with two readings: the merge event, and the corrected text present on origin/main @ 6500ebbdd in both files (two-doors-permission.dogfood.test.ts and showcase-permission-projection.dogfood.test.ts).

    Delivered: the two packages/qa dogfood headers. Each now states the post-#6483 refusal its own body asserts, marks the 2026-07-14 direction retired, and points at D5-R.

    Remaining: the ADR-0094 D2 parenthetical, in PR #8291 — open, reviewed, and ⛔ awaiting a maintainer's approving review and manual merge. Its ADR maintainer approval check is red by design; every other gate on it is green. No AI seat may clear it.

    Labels deliberately unchanged. This card keeps pm:dispatched rather than returning to the queue: #8291 carries the Fixes #7351, so the card is still in flight and still mine, with one half landed. Swapping it back to pm:queue now would advertise unclaimed work that is actually sitting in a human's review queue — and would invite a second seat to pick it up.

    This card closes when #8291 merges. If that ordering ever inverts — #8291 merging first and closing this card while a half is unlanded — I re-open or re-file the remainder rather than let it disappear.


    Generated by Claude Code

  14. os-zhuang commented on Aug 13, 2026

    @os-zhuang
    ContributorAuthor

    Seat standing down — handover note. This card is the only one still pm:dispatched under my claim, and it needs one action from whoever picks the lane up.

    The maintainer stood this domain:cli seat down at 2026-08-13. Recording the state here rather than leaving it in a session that is ending.

    State: both halves are implemented and reviewed.

    Why it still reads pm:dispatched: #8291 carries the Fixes #7351, so this card closes when that merges. Returning it to pm:queue would advertise unclaimed work that is actually finished and sitting in a human's review queue, and would invite a second seat to redo it. Leaving it dispatched is the honest state — but the claim on it belongs to a session that has ended.

    The one action for the next seat: when #8291 merges, GitHub closes this card via the Fixes; strip the stale pm:dispatched, leaving domain:cli. If #8291 is instead closed unmerged, this card returns to pm:queue with the ADR half as its remaining scope — the dogfood half is already on main and must not be redone.

    No other card carries an open claim from this seat. #8343 is pm:on-hold with its own restart condition; everything else was either merged or handed to triage.


    Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

domain:cliRetired 2026-10-22, alias of domain:server (cli surface); in-flight cards keep it until they land

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions