Repository navigation
check:role-word and check:corpus-claim-drift skip every references/ directory, so 12 of 46 published-catalog markdown files - incl. both hand-authored reference companions - are invisible to both scans #15061
Description
Activity
Triage — skills seat (session
session_019RfFHiRCSs3JXLK4cwcfox, os-steve), 2026-09-03T19:46Z. Gradedpriority:p3,domain:skills(both gates guard the published catalog this lane owns),tooling, statepm:queue, type Task. Applied and read back after this comment.Scope as queued (XS, two files, pure code):
scripts/check-role-word.mjsandscripts/check-corpus-claim-drift.mjsstop skipping every directory namedreferencesand skip only the generated root they mean —content/docs/references— by path, not by name; measure each gate's population before and after (expect the 12 catalog files to appear, the generatedcontent/docs/references/tree still absent), pin the population from the walk in each self-test the way the frame-sync fix did. Stop condition (evidence, not verdict): if either widened scan reds on a hand-authored companion, do not edit that page — leave the gate red on it and name the site in the report; if it reds on a generator-owned index page, that is a generator finding, reported, not hand-edited.
Generated by Claude Code
Claim: PM loop round 3
Session:session_019RfFHiRCSs3JXLK4cwcfox
Branch:claude/issue-15061-catalog-gates-scan-references
Worktree:objectstack-issue-15061
Domain:domain:skills
File surface:scripts/check-role-word.mjs+scripts/check-corpus-claim-drift.mjs(each gate's skip set and its self-test's population pin) (stop on breach; explain in the report). ⛔ No markdown file is edited by this flight.
Container & model: XS code (two skip sets narrowed from a name to the generated path, two population pins),mode:subagent,model: opus(tier: both paths arescripts/check-*.mjs— the frame-sync sibling read "no path-derived mandate … floor sonnet · default opus · ceiling fable" at82291fba, 19:17Z; PM's call: opus default — the edit reasons about which root each skip was for)
Clause-②: no
Serial constraints cleared: neither file is on the seat post's hot-file queue; no in-flight claim names them; no open PR touches them; the sibling fix oncheck-skill-frame-sync.mjsis PR #15060 (a different file, at the flip checkpoint). Not governed (check-governed-merges --testonscripts/check-*.mjsreads 0 hits for the sibling; the flight re-runs it on both), no.md⇒ pure-code landing: in-seat review → ready → auto-merge.Decision re-read (19:47Z): no maintainer ruling; the seat's triage (comment 5531177809) fixes the scope — skip the generated root by path (
content/docs/references), not by directory name; measure each population before and after; population pinned from the walk; a red on a hand-authored companion is reported, never patched in the page.
Generated by Claude Code
os-dev-report
{ "issue": 15061, "status": "needs_decision", "branch": "claude/issue-15061-catalog-gates-scan-references", "pr": "https://github.com/objectstack-ai/objectstack/pull/15073", "premise_still_valid": true, "summary": "Implementation is COMPLETE and pushed; the status reflects one gated decision, not an incomplete flight. Both gates now hold only installed-or-generated NAMES in SKIP_DIRS (node_modules, .git, dist) and exclude the generated tree by PATH through a new SKIP_SUBTREES set holding exactly 'content/docs/references' — matched against the walker's joined path, which is that literal because the walker is seeded with the ROOTS entries verbatim (measured, not assumed). Population per each gate's own verdict line: 224 to 236 files, content/docs 190 to 190, skills 34 to 46 — the 12 catalog files appear, the 214 generated pages stay absent. Each self-test pins that FROM THE WALK in both directions (reaches skills references, reaches no content/docs/references, reaches more than those, every SKIP_DIRS entry declared installed-or-generated, every SKIP_SUBTREES entry under a ROOT and existing), never as a typed count; both gates use the #13489 battery roster, so the rosters go 11 to 12 and 16 to 17 with their floors. STOP CONDITION HIT, exactly as triage anticipated: the widened check:role-word reds on the hand-authored companion skills/objectstack-data/references/data-hooks.md with 12 occurrences. The page is NOT edited and the baseline is NOT touched — the remedy the evidence supports is the one the gate itself marks MAINTAINER-ONLY. check:corpus-claim-drift is GREEN and its baseline does not move. No markdown file was edited. Not a governed surface (0 of 2 paths hit the register, quoted in the PR body); skip-changeset applied additively and read back.", "tests": "Head 7c660c57 (git rev-parse --short HEAD from the verification run; tree clean, both ablations restored first). Families re-derived from the commit with `node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack` (no paths) — 23 families, identical to the dispatch list, no additions; harvested with --commands. Every exit code captured by redirecting to a file BEFORE any pipe. 21 of 23 green; 1 red by design; 1 NOT MEASURED. RED: `pnpm check:role-word` exit 1 — self-test green, then the gate: 'skills/objectstack-data/references/data-hooks.md: NEW use of the reserved word \"role\" (12 occurrence(s)). ADR-0090 D3: use permission_set / position / business_unit.' plus its MAINTAINER-ONLY baseline clause. GREEN and relevant: `pnpm check:corpus-claim-drift` — 'OK, no new claim sites beside a pinned spelling. Scanned: 236 .md/.mdx file(s) read across 2 root(s) — content/docs 190, skills 46. Ledger: 2 baselined file(s)'; `check-self-test-wired` 'every one of the 166 script(s) CI runs that ship a --self-test has that self-test run by CI'; `check:ratchet-remedy-authority` '186 scripts swept; 12 mark the expanding remedy MAINTAINER-ONLY'; `check:watch-hint-literal` '48 declaration(s) across 4 rostered name(s)'; `bare-root-worklist --self-test` '57 live row(s), 49 recorded verdict(s) — none stale, none missing, none contradicted'; `check:pm-dispatch-gates` 'dispatch-gates self-test: 1291 cases pass'; `check:nul-bytes` 'scanned 8195 text file(s) ... no raw ASCII control bytes'. NOT MEASURED: `node scripts/check-test-completeness.mjs` exit 3, in its own words 'PREREQUISITE NOT MET — this gate grades a saved turbo run test log, and no log was named ... the local reading for this gate is NOT MEASURED. It is not a red'. Repo-wide ESLint run WHOLE, not narrowed, through the shared lock: `OS_VERIFY_LOCK_SLOT=issue-15061-lint bash scripts/pm/os-verify-lock.sh -c 'pnpm lint'` — 'VERDICT command-exit 0 · held the lock 61s · waited 0s'. BASELINE-CORPUS MEASUREMENT: none of check-corpus-claim-drift's four VOCABULARY spellings occurs in any of the 12 newly visible files (per-file count 0 for all twelve), so the baseline does not move and the gate's Ledger line is identical before and after. ABLATIONS, one per gate, each restoring the blanket `references` name-skip: NO REBUILD LEG APPLIES — both gates are plain .mjs run directly from source by path, resolved through no package exports, so there is no dist for a stale artifact to hide in. Mutation proved ON DISK, anchored at the target line: `grep -c -F` of the deleted text returned 0 and of the injected text returned 1 (never the editor's exit code), and the mutated blob hash differed from the HEAD blob. Result both times — the GATE exits 0, GREEN, printing 'Scanned: 224 ... skills 34', while its SELF-TEST exits 1 with 2 cases failing and naming themselves: 'x self-test: #15061 — the walk REACHES the published catalog's reference pages under skills/ ... Restoring the name-keyed skip empties this while the gate itself stays green, which is the dormancy this case exists for'. That is the dormancy the card asserts, reproduced per gate. RESTORE proved by STATE, not by an exit code: `git checkout HEAD -- ABSOLUTE_PATH` (never a bare checkout) inside a trap on EXIT INT TERM with an absolute REPO_ROOT, then `git diff HEAD` empty for the path AND the blob hash equal to the HEAD blob (0f3c2c64 for check-role-word.mjs, 1a81bdc8 for check-corpus-claim-drift.mjs; an empty hash was coded as FAILURE, not as nothing-to-compare), and `git status --porcelain` for each path empty. Gate-script clause: `git grep` over test files for either script name returns nothing — neither gate ships its own vitest suite, so that clause adds nothing beyond the 23 families.", "mcp_calls": "0 — zero MCP GitHub calls for the whole run. The card body and all comments came from the public-repo embedded JSON payload (zero quota); the sibling PR diff came from git; PR creation, the skip-changeset additive POST and both read-backs went through repo-scoped REST, probed live first (GET labels/skip-changeset returned 200). `gh` is absent from this container.", "open_questions": [ { "question": "check:role-word is now RED on the hand-authored companion skills/objectstack-data/references/data-hooks.md (12 occurrences of the reserved word). Every occurrence is ADR-0090 D3's own named legitimate KIND — quoted pre-rename history documenting the retirement of session.roles ('No role list — session.roles was retired in 17.0.0: it was declared but never produced, so every read was undefined') and a hook comment warning 'Do NOT gate this on a role name', plus one example query on a user field in the better-auth sys_member.role territory D3 already carves out. Which remedy lands, and by whom?", "options": [ "A — the maintainer runs `node scripts/check-role-word.mjs --update` and commits the baseline, admitting these 12 as the quoted-history KIND. Cost stated by the gate itself: --update rewrites the WHOLE baseline from the current tree, so it re-baselines every other file in one stroke, and it weakens a shrink-only ratchet. Marked MAINTAINER-ONLY by the gate; not this seat's act, and not any agent seat's.", "B — reword the page so the word disappears. Excluded by the card's own stop condition, and substantively wrong: the sentences ARE the retirement of the identifier they name, so renaming it makes them false — a page that teaches 'there is no role list' cannot say it without the word.", "C — mark the occurrences with the os:vendor-wire fence. Does not fit: most sites are prose and code comments rather than a third party's literal wire payload, and the fence exemption keys on a marked FENCE, which those sites are not.", "D — leave the gate red on main. Not an option: the two gates are required contexts in Lint and Repo Gates, so this PR cannot land and neither can anything behind it." ], "recommendation": "A, and it is the maintainer's act, not a seat's. By the four axes: (1) 实际业务需求 — the demand is real and measured, not speculative: these two companions ship verbatim to third-party projects via `npx skills add`, which is the distribution path that puts `skills` in ROOTS at all, so the coverage this PR restores is coverage of text an AI author actually reads in a codebase this repo cannot see; the 12 occurrences themselves are a real page teaching a real retirement. (2) 项目长远合理性 — A is the only option that keeps one strict contract: B falsifies documentation to satisfy a lint, and C would stretch a marking-bounded exemption over prose it was explicitly not extended to ('a backticked word in a sentence is prose with backticks around it'). Both are workarounds in Prime Directive 5's sense; A records the boundary in the ledger where it is greppable and reviewable. (3) 防 AI 写代码犯错 — A is the direction that makes the mistake harder to repeat: the page's whole subject is a declared-but-never-produced key that AI authors kept reading, and its remedy is to keep saying so loudly. Silencing it by rewording would remove the warning and leave the gate green — declared-not-enforced one layer up. Note the tightening this PR itself buys on the same axis: the dormant scan was a gate that ran, passed, and could not see a quarter of its population, which is the exact shape a tolerant consumer has. (4) 创业阶段不扩散需求 — A adds no surface at all: it is one ledger entry on an existing shrink-only baseline, no new exemption mechanism, no new vocabulary, no staged window. C by contrast would grow the exemption's blast radius, and B would spend author time rewriting correct pages. The one honest cost of A is the one the gate prints: --update re-baselines every file in one stroke, so the diff should be read as a whole rather than skimmed for the new row." } ], "out_of_scope_findings": [] }Generated by Claude Code
Generated by Claude Code
ACCEPT (delivery) — landing gated on a maintainer decision — skills seat (session
session_019RfFHiRCSs3JXLK4cwcfox), reviewer of record, 2026-09-03T20:10Z, verified against GitHub and a compare worktree at the PR head, not against the report.PR #15073 @
7c660c57— draft, basemain, first lineFixes #15061, two files+266/-13,skip-changeset, no other closing keyword, no model name, one footer, no control bytes.check-governed-merges --test: 0 of 2 hit — not governed.Content against the triage scope (comment 5531177809): both gates keep only installed-or-generated names in
SKIP_DIRSand exclude the generated tree by path through aSKIP_SUBTREESset holding exactlycontent/docs/references; the seat re-ran both at the head — self-tests green (the walk reaches 236 markdown file(s) … 12 of them published reference pages under skills/, and 0 under the generated content/docs/references),check:corpus-claim-driftgreen with its ledger unchanged (Scanned: 236 … content/docs 190, skills 46), andcheck:role-wordred by design onskills/objectstack-data/references/data-hooks.md(12 occurrences: the retirement history ofsession.rolesat:350, the "do NOT gate this on a role name" comments at:575/:837-841, one example query at:733). The stop condition fired exactly as triage wrote it: the page is not edited, the baseline is not touched, and the gate's own text marks the remedy (--update, whole-baseline rewrite on a shrink-only ratchet) MAINTAINER-ONLY. Ablations per gate reproduce the dormancy (gate green at 224 files while the population pin goes red) — good runs.Decision: the four options and the recommendation (A — the maintainer admits the twelve as the quoted-history kind via
--update, or authorises the seat to have the dev run it on this branch with the whole baseline diff read in review) go to the maintainer as decision batch 8. Until it is ruled, the PR stays draft (a required context is red, so it cannot enqueue), the card stayspm:dispatchedwith this open PR as its in-flight state, and no split is made: landing the corpus-claim-drift half alone would leave the role-word half a second PR and aPart of, for a wait the maintainer has been clearing within the hour today.Deviations: none. Report
mcp_calls: 0 — within contract. CI at 20:08Z on7c660c57: 32 check runs, 16success+ 11skipped, fivein_progress;Lint & Repo Gateswill report the role-word red — expected, not a rework signal.
Generated by Claude Code
Blocked-by: #15177
Maintainer ruling — B (2026-09-04): the page is rewritten first; PR #15073 then baselines the residue and lands
Director seat, summon 13, session_01WXyGTWPbbreqXow7Z2pZCk. Provenance: maintainer, live chat, after the director's re-evaluation of decision card #15075; verbatim 「按照你的建议,跟进并处理完这两个pr。」 (full record on #15075, comment 5535828546).
- skills/objectstack-data/references/data-hooks.md: rewrite the reserved word "role" to ADR-0090 D3 vocabulary, keeping one retirement note — the residue is what PR #15073 baselines #15177 (skills lane, p2): rewrite
skills/objectstack-data/references/data-hooks.mdto ADR-0090 D3 vocabulary, keeping one retirement note and one warning; governed, human merge. - Then PR fix(gates): scan the published catalog's references/ in role-word and corpus-claim-drift #15073: on a head that includes the merged page, run
node scripts/check-role-word.mjs --updateso the baseline admits the page's residue only (expected 3 to 4 occurrences, all quoted history) — the ⛔ MAINTAINER-ONLY act, authorized by the maintainer for the residue and for this PR; quote the authorization in the PR body. Then the normal landing (not governed: two gate scripts plus the baseline).
State:
pm:dispatched→pm:blockeduntil #15177 merges; the unlock scan returns it. TheBlocked-by:line above is the canonical spelling; the body sync is the seat's.
Generated by Claude Code
- skills/objectstack-data/references/data-hooks.md: rewrite the reserved word "role" to ADR-0090 D3 vocabulary, keeping one retirement note — the residue is what PR #15073 baselines #15177 (skills lane, p2): rewrite
Ruling acknowledged — skills seat (session
session_019RfFHiRCSs3JXLK4cwcfox, os-steve), 2026-09-04T05:02Z: B on #15075 (5535828546 / 5535830096). The card's body now carries the canonicalBlocked-by: #15177line (the director set the label and the comment; the body sync was the seat's). #15177 is claimed and dispatched (claim 5535911164; governed page rewrite, both approvers, human merge). When #15177 is MERGED the seat sends PR #15073's dev the patch round the ruling prescribes: mergemain, runnode scripts/check-role-word.mjs --updateso the baseline admits this page's residue only (the ⛔ MAINTAINER-ONLY act, authorised for the residue and for that PR — the authorisation quoted in the PR body), the full baseline diff in the PR body, the seat reviews every line, then the ordinary landing; nothing else in that PR changes.
Generated by Claude Code
Unblocked — the ruled patch round is sent — skills seat (session
session_019RfFHiRCSs3JXLK4cwcfox, os-steve), 2026-09-04T06:32Z. TheBlocked-by:target #15177 is done: PR #15186 MERGED5f5511f006:22:21Z by os-zhuang, soskills/objectstack-data/references/data-hooks.mdonmainnow carries 3 quoted-history occurrences. PR #15073 gets the round the ruling prescribes (#15075 → B, 5535828546; hotlong's PR comment 5535832006): mergemain, runnode scripts/check-role-word.mjs --updateso the baseline admits this page's residue only — the ⛔ MAINTAINER-ONLY act, authorised by the maintainer for the residue and for this PR — with the authorisation quoted in the PR body and the fullscripts/role-word-baseline.jsondiff pasted there for the seat's line-by-line review; nothing else in the PR changes; then the ordinary landing (not governed).pm:blocked→pm:dispatched.
Generated by Claude Code
os-dev-report
Patch round 2 — supersedes the report in comment 5531450646 (that round ended needs_decision on the red; the maintainer has since ruled and the round is complete).
{ "issue": 15061, "status": "done", "branch": "claude/issue-15061-catalog-gates-scan-references", "pr": "https://github.com/objectstack-ai/objectstack/pull/15073", "premise_still_valid": true, "summary": "Patch round complete; the PR is green and awaiting the seat's review of the baseline diff. origin/main merged as a merge commit 750b0655 (merging 9c1bcda3, clean, no conflicts, no os-regen deferral), bringing in PR #15186 / card #15177 (5f5511f0, confirmed an ancestor first), which rewrote skills/objectstack-data/references/data-hooks.md into ADR-0090 D3 vocabulary. At the merged head the gate reds with exactly 3 occurrences, inside the ruling's predicted 3-to-4 band, both sites quoted history that cannot be reworded without falsifying it (the retirement of session.roles being documented). The authorised MAINTAINER-ONLY `node scripts/check-role-word.mjs --update` was then run once, and its whole-baseline rewrite inspected key by key rather than skimmed: entries 43 to 44, occurrences 120 to 123, exactly one entry ADDED (data-hooks.md: 3), zero REMOVED, zero CHANGED. The stop-and-report condition did not trigger, so nothing was restored and nothing is owed. Nothing else in the PR changed: the SKIP_SUBTREES fix, both five-case population pins and both battery rosters are byte-identical to the reviewed commit, and corpus-claim-drift's ledger is untouched. Final head 085cd82d, pushed. PR body gained a 'Patch round — the residue baselined' section carrying the maintainer's verbatim quote, both authorisation records, the red-before / green-after lines and the FULL baseline diff as a fenced block for line-by-line review. PR stays DRAFT; skip-changeset still applied (read back alongside size/m, which the size labeler added).", "tests": "Head 085cd82d (git rev-parse --short HEAD from the verification run; tree clean). Dependencies reinstalled at the merged head first (pnpm install --frozen-lockfile, exit 0) — the worktree was recreated from the pushed branch, so nothing stale crossed the merge. Families re-derived at the final commit with `node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commands` (no paths): still 23, but NOT the same 23 as round 1 — main moved, so three --self-test spellings joined (check-closing-keyword-parity, check-self-test-wired, check-whole-set-label-write) and three left (check-cross-package-test-inputs.mjs, check-shard-attestation.mjs, check-test-completeness.mjs); all were re-run. Every exit code captured by redirecting to a file BEFORE any pipe. 23 of 23 GREEN — no reds, and nothing NOT MEASURED this round (round 1's check-test-completeness exit-3 PREREQUISITE NOT MET is no longer in the derived set). The two edited gates: `pnpm check:role-word` exit 0 — 'OK, no new occurrences of the reserved word. Scanned: 236 .md/.mdx file(s) read across 2 root(s) — content/docs 190, skills 46. Ledger: 44 baselined file(s) still carrying it (123 occurrence(s))'; `pnpm check:corpus-claim-drift` exit 0 — 'OK, no new claim sites beside a pinned spelling. Scanned: 236 ... content/docs 190, skills 46. Ledger: 2 baselined file(s)', and `git diff --stat` on scripts/corpus-claim-drift-baseline.json is EMPTY, so the ledger really is unchanged rather than merely reported so. Both self-tests still print their population pins from the walk, unchanged by the merge: 'the walk reaches 236 markdown file(s) across the roots, 12 of them published reference pages under skills/, and 0 under the generated content/docs/references/ tree'. RED BEFORE, quoted: at the merged head pre-update, exit 1, 'skills/objectstack-data/references/data-hooks.md: NEW use of the reserved word \"role\" (3 occurrence(s))'. The two sites: line 350 'No role list — session.roles was retired in 17.0.0: it was declared but never produced, so every read was undefined' (2 occurrences) and line 837 'Never gate this on a session claim: ctx.session?.roles?.includes' (1). GREEN AFTER, quoted above. BASELINE DIFF, the whole of it: one insertion, `\"skills/objectstack-data/references/data-hooks.md\": 3,`, and scripts/role-word-baseline.json is the only path in the commit. Verified twice — textually by `git diff --stat` (1 file changed, 1 insertion) and structurally by parsing both JSON objects and comparing key by key, because a textual diff can hide a reordering: ADDED exactly one key, REMOVED none, CHANGED none, occurrence total 120 to 123 delta 3. Selected verdict lines from the other 21, all exit 0: check-ci-filter-parity 'all 143 declared cross-package glob(s) (99 unique) are covered'; check-closing-keyword-parity 'sweep found 5 file(s) carrying the grammar across 8276 tracked file(s), all registered' and its self-test '24 assertions, 5 mutations of the shipped parsers each driven to red'; check-comment-mask-corpus '5874 files, 0 disagree, 0 unparseable'; check-self-test-wired '168 of those are run by 30 workflow(s)' and its self-test '7 declared batteries, 50 cases registered, every battery at or above its pinned floor'; check-whole-set-label-write --self-test '24 fixture trees + 5 refusals + 1 allowlist hatch'; bare-root-worklist --self-test '54 live row(s), 46 recorded verdict(s) — none stale, none missing, none contradicted'; check:nul-bytes 'scanned 8269 text file(s) ... no raw ASCII control bytes'; check:pm-dispatch-gates 'dispatch-gates self-test: 1353 cases pass'; check:ratchet-remedy-authority '188 scripts swept; 13 mark the expanding remedy MAINTAINER-ONLY'; check:entry-guard '209 scripts/ file(s) — every entry guard goes through invoked-as.mjs'. Repo-wide ESLint run WHOLE, not narrowed, through the shared lock: `OS_VERIFY_LOCK_SLOT=issue-15061-lint bash scripts/pm/os-verify-lock.sh -c 'pnpm lint'` — 'VERDICT command-exit 0 · held the lock 84s (1m24s) · waited 0s'. No ablation this round: the gate logic is byte-identical to the commit whose ablations were already run and reported, and this round adds a ledger row, not a predicate.", "mcp_calls": "0 — zero MCP GitHub calls in this round too, and zero across both rounds. The three authorisation records (5535828546, 5535832006, 5536658847) were read through repo-scoped REST issue-comments by id; the PR body PATCH, its read-back and the label read-back likewise. git supplied the merge and the sibling PR's contents. `gh` is absent from this container.", "open_questions": [ { "question": "Platform reading that diverges from the one AGENTS.md records, reported rather than acted on: the dispatch warned that an MCP update_pull_request PATCH deletes the attribution footer block and a raw REST PATCH appends a bare one, and AGENTS.md records that every PATCH normalises a session-URL footer DOWN to bare. Measured here on a raw REST PATCH of PR 15073 with a full read-back: the session-URL footer SURVIVED the edit verbatim, and a bare footer was appended under it — leaving two, which is the shape AGENTS.md documents for the issue-COMMENT surface, not for a PR-body edit. Everything else came back byte-identical across 22,533 characters. Should the recorded reading be re-measured?", "options": [ "A — record it as a second measured observation on the PR-body surface and leave both readings standing until a seat re-measures deliberately. One observation does not overturn a recorded one, and the divergence may be per-token or per-endpoint rather than per-surface.", "B — edit the AGENTS.md clause now. Rejected here: AGENTS.md is a governed surface, this is a single incidental observation taken while doing something else, and a rewritten platform reading based on one sample is how a wrong reading gets fossilised.", "C — repair the PR body to leave a single footer. Rejected: the body is correct and complete, the tail bare footer is the platform's own, and AGENTS.md is explicit that a rewrite destroys a correct card." ], "recommendation": "A. No action was taken on the PR beyond the read-back, and durable attribution was written into the section's prose anyway, so nothing depends on which reading is right. Flagging it because the recorded reading is what the next seat will plan around: it predicted attribution would be LOST on edit, and the measured outcome was the opposite direction." } ], "out_of_scope_findings": [] }
Generated by Claude Code
ACCEPT — contract-tier review of the patch round on PR #15073, head
085cd82d(skills seat, 2026-09-04T06:55Z).Implemented-by:
claude/issue-15061-catalog-gates-scan-references(os-dev subagent, taskaf582411c7967fac5)
Reviewed-by:session_019RfFHiRCSs3JXLK4cwcfox(skills seat)Verified in a detached compare worktree, not from the report:
- Gate logic unchanged since the reviewed head.
git diff 7c660c57 085cd82d -- scripts/check-role-word.mjs scripts/check-corpus-claim-drift.mjsis empty, and themainside of merge750b0655touches neither script. This round adds a ledger row, not a predicate — the earlier ablations stand. - Baseline diff is exactly the ruled residue. Against merge base
9c1bcda3the only change toscripts/role-word-baseline.jsonis one inserted key,"skills/objectstack-data/references/data-hooks.md": 3, in sorted position; entries 43 → 44, occurrences 120 → 123. The residue is the two quoted-history sites the [PM decision] skills lane batch 8 — admit data-hooks.md's twelve quoted-history uses of the reserved word to the role-word baseline so the widened catalog scan can land #15075 option-B ruling foresaw ("expected 3 to 4, all quoted history"), and the--updateact was the ⛔ MAINTAINER-ONLY act the maintainer authorised for the residue only (director record5535828546on [PM decision] skills lane batch 8 — admit data-hooks.md's twelve quoted-history uses of the reserved word to the role-word baseline so the widened catalog scan can land #15075, seat records5535832006on the PR and5536658847here — all three quoted in the PR body). - Green on the merged tree. Merged
origin/main1bc3c092(which now carries skills/objectstack-data/references/data-hooks.md: rewrite the reserved word "role" to ADR-0090 D3 vocabulary, keeping one retirement note — the residue is what PR #15073 baselines #15177's page5f5511f0and The internal dispatch runbook has no step that pastes the decision frame into the dev prompt — after #14685 item 4 (PR #14862) the dev definition expects it there and has no copy of its own #14869'sea53bae5) locally:node scripts/check-role-word.mjs→ "OK, no new occurrences … Ledger: 44 baselined file(s) still carrying it (123 occurrence(s))";node scripts/check-corpus-claim-drift.mjs→ "OK, no new claim sites … Ledger: 2 baselined file(s)"; both ledgers byte-identical after the runs;git merge-tree --write-tree origin/main 085cd82dclean. - CI on
085cd82dat 06:52Z: 24 success, 8 skipped (the changeset job is skipped byskip-changeset), 1 in progress (Lint & Repo Gates). Landing rule unchanged: pure code ⇒ ready + auto-mergeSQUASHfrom the seat once every check is green; not before.
Open question → A. The reading the dispatch handed you is the one recorded on #14133 in the platform-readings family (a raw REST PATCH of a PR body appends a bare footer and leaves a session-URL footer intact; the MCP
update_pull_requestPATCH is the channel that deletes the block). Your measurement agrees with that reading and diverges only from the older AGENTS.md clause; it is recorded as a second measured observation on the successor card #15192 (the third platform-readings increment), where the ceiling ruling for that increment is pending. No edit to the PR body and no governed edit from this card.Disposition:
pm:dispatchedstays until the PR reads MERGED; then the card is label-cleaned and closes by theFixeskeyword.
Generated by Claude Code
- Gate logic unchanged since the reviewed head.
Measured while implementing #15056 (branch
claude/issue-15056-frame-sync-scan-references, PR #15060) atorigin/main82291fba. Unassigned, bare, for triage. File surface:scripts/check-role-word.mjsandscripts/check-corpus-claim-drift.mjs.What
#15056 is
check:skill-frame-syncskipping every directory namedreferences, which hid 44% of its scan population. The same entry sits in two other gates whose roots include the published catalog, and there it hides the same kind of file:ROOTSSKIP_DIRSscripts/check-role-word.mjs['content/docs', 'skills']node_modules,.git,dist,referencesscripts/check-corpus-claim-drift.mjs['content/docs', 'skills']node_modules,.git,dist,referencesThe reason for the entry is stated in
check-corpus-claim-drift.mjsitself and is true of only one of its two roots:content/docs/references/is indeed generated from spec (AGENTS.md marks it AUTO-GEN).skills/*/references/is not the same population, and this repo has already ruled on it twice:scripts/check-skill-identifier-liveness.mjskeepsreferencesout of its skip set and pins the difference in its self-test: "underskills/**those files are hand-authored published content, unlike content/docs/references which is generated".scripts/check-doc-authoring.mjsgave its published-catalog rule a second walk rather than reuse its own skipping one, because reusing it "would have produced a gate that runs, passes, and cannot see a ninth of the population it exists to guard" — and it namesskills/objectstack-data/references/data-hooks.mdas a file that "alone carried 15 of these ids when the corpus was measured". It also refuses any exemption for the generated pages there: "A red here is fixed AT THE SPEC SOURCE, never by hand-editing the artifact".Measured
Markdown under
skills/(.md+.mdx, the extension set both gates use):skills/references/only)The 2 hand-authored companions are
skills/objectstack-data/references/data-hooks.mdandskills/objectstack-platform/references/plugin-hooks.md. Both ship verbatim to third-party projects vianpx skills add, which is the distribution path both gates give as their reason to readskills/at all. The 10 generator-owned pages are the ninereferences/_index.mdfiles plusskills/objectstack-ui/references/react-blocks.md.Not asserted
No claim that a role-word violation or a stale corpus claim is present in those 12 files today — this card was not the place to run either detector over a widened population, and #15056's flight was scoped to exactly one file. The defect asserted is the missing coverage.
Suggested shape (for triage, not a decision)
The narrow reading is that
referencesbelongs in the skip set for acontent/docsroot and not for askillsroot, so a directory-name skip set is the wrong shape for a gate with both: skip by path prefix (content/docs/references) rather than by bare directory name, or give the published catalog its own walk the waycheck-doc-authoring.mjsdid. Whether the generated pages underskills/**then earn an exemption is the same questioncheck-doc-authoring.mjsalready answered no to, and answering it differently here would need a reason.Dedup
Complete enumeration of open items, 2026-09-03: REST
GET /repos/objectstack-ai/objectstack/issues?state=open&per_page=100&page=1..6returned 100+100+100+100+100+32 = 532, reconciled against the repository's ownopen_issues_countof 532 (508 issues, 24 PRs); local grep over titles and bodies forcheck-role-word,role-word,corpus-claim-drift,SKIP_DIRS,references/,reference companion,check-doc-authoring. One targetedsearch_issuescovering closed items as well returned 18 results with the control (#15056) hitting, so the channel was live. Nearest neighbours, none of them this: #14659 (the role-word baseline is keyed by file path), #10107 (check-role-word'sskillsroot is invisible to dispatch-gates derivation — a derivation-visibility defect, not a scan-population one), #13335 and #11705 (both aboutskills/**/references/_index.mdbeing generator-owned, in the merge-driver and governed-fence senses). No carrier found.Generated by Claude Code