Repository navigation
[finding] ** in a hint does not match ZERO segments — scripts/**/*.d.mts names 3 tracked files and reaches 0, a dead hint by construction that #12300's new branch introduced #12329
Description
Activity
Claim:devx@objectstack seat (#6023) · sessionsession_01UjM2ia8Av1v5NqfqQEQmC6· R9
Branchclaude/issue-12329-glob-zero-segment· dedicated worktree · model tier: standard.Declared file surface:
scripts/pm/dispatch-gates.mjsand its--self-test. Nothing else.Serial: you hold the
scripts/pm/dispatch-gates.mjswriter slot. It was released minutes ago — #12299's dispatch returnedpremise_still_valid: falseand pushed nothing. #12074 and #12173 are held behind you. ⛔scripts/pm/bare-root-worklist.mjsis not yours: #12328 ispm:blockedon the decision card #12369, and itsTRIAGEmap is under a pending maintainer ruling.⭐ #12299 is
Blocked-by:you, and the ordering is mechanical: your change alters the covering rule, the covering rule determines the inert hint set, and #12299's residue repair describes that set. Built before you, it would be stale on arrival.
Zone 1 — rulings (scope, not facts; not renegotiable)
- The surface above is the whole surface.
- ⛔ Do not edit
bare-root-worklist.mjs— see the serial note. If your fix changes what anyTRIAGErow measures, report it, do not write it. - ⛔ Do not widen
hintCoversbeyond the zero-segment question. [Decision] extractWatchHints strips a module-relative literal's own depth, so a gate inside a package emits hints that are not repo paths — fix the producer (fleet-wide MATCHED widening) or explain it downstream? #12371 is an open decision on a fleet-wide MATCHED-column widening in this same function's neighbourhood; pre-empting it from here is out of bounds. - Falsification escape: if a Zone 2 item measures false, stop and return
premise_still_valid: falsewith the reading. Two dispatches this round did exactly that and both were right.
Zone 2 — assumptions; falsify before building on them
a. ⭐ Two independent readings agree that
scripts/**/*.d.mtsreaches 0 while 3 such files exist, and this seat verified the corpus directly atorigin/main:3 tracked scripts/check-regen-pending.d.mts scripts/invoked-as.d.mts scripts/js-comment-mask.d.mtsThe stated mechanism is that
**in a non-final segment matches one or more segments, never zero, so a top-level file is unreachable by that spelling.⚠️ That is still a reading of behaviour, not of the code — confirm it intriggerCovers/globInNonFinalSegmentbefore you fix it.b. The sibling spelling
scripts/*.d.mtsis reported as also dead — a final-segment glob still mangled bycollapseHinttoscripts/.d.mts. If true, this row has no working spelling and both halves need to be in your fix. Verify both.c.
⚠️ I assume the zero-segment behaviour is a defect and not a deliberate choice. #12300 introduced the branch; read its intent before you invert it. If**meaning "one or more" is load-bearing somewhere, changing it is a fleet-wide semantic change and belongs in a decision card, not this one — say so and stop.d.
⚠️ This function is where I have been wrong twice this shift. Both errors were the same shape: measuringcollapseHintwhenhintCoversshort-circuits past it. Drive every reading throughhintCovers, nevercollapseHintalone, and never a re-implementation.Zone 3 — suggested route (not binding)
Confirm the mechanism in code → establish whether both spellings are dead → fix so a top-level file under a
**root is reachable, without widening what the hint otherwise matches → pin both directions in--self-test, including a zero-segment case and a one-or-more case, so neither can regress into the other.⚠️ Report, do not fix: thescripts/check-declaration-mirrors.mjs SCRIPTS_DIR scriptsTRIAGErow records "everyscripts/**/*.d.mts, 2 of 261 (0.77%)". The tree has 3. That stale numerator is a real defect on a row this card is about, but it lives in the blocked file — measure it, put the number in your report, and leave the row alone.Ablate both ways, confirm the mutation on disk (not by an editor's exit code), restore under
trap … EXIT INT TERM, prove byte-identical withgit hash-object. Gate union at the final commit; re-derive onSTALE TREE. Exit codes captured before any pipe.
Generated by Claude Code
- added a commit that references this issue
on Aug 25, 2026 { "issue": 12329, "status": "done", "branch": "claude/issue-12329-glob-zero-segment", "pr": "https://github.com/objectstack-ai/objectstack/pull/12386", "premise_still_valid": true, "summary": "Zone 2a and 2b both measured TRUE at origin/main, driven through the real exported hintCovers (never collapseHint alone, never a re-implementation): 3 tracked scripts/*.d.mts mirrors, `scripts/**/*.d.mts` reached 0, `scripts/*.d.mts` reached 0, `scripts/**.d.mts` reached 0. Mechanism confirmed IN CODE, not inferred from behaviour: globInNonFinalSegment routes the hint to triggerCovers, and triggerPatternRegex('scripts/**/*.d.mts') is /^scripts\\/.*\\/[^/]*\\.d\\.mts$/ — the `/` written after `**` is a literal, so `**` there means one or more segments. Zone 2c answered with a distinction that changed the fix: `**` = one-or-more IS load-bearing, but only inside triggerPatternRegex, which is the CI mirror that triggerListCovers/coveringTrigger use to evaluate real workflow `paths:` lists (validate-deps.yml declares '**/package.json'). Changing it there would be the fleet-wide semantic change Zone 2c says to stop on. So the repair is confined to the HINT side: hintCovers now tests the hint plus every spelling reachable by deleting a subset of its whole-`**` NON-FINAL segments (zeroSegmentForms — the power set, since each `**` is zero-or-more independently). triggerPatternRegex/triggerCovers/triggerListCovers/coveringTrigger and collapseHint are byte-unchanged. Narrow by construction: only a segment that is exactly `**`, only non-final, and a single `*` never. Result: `scripts/**/*.d.mts` 0 -> 3 (exactly those 3 files, nothing else in the tree) with ZERO change to the live fleet. NOTE FOR PM — a route deviation you should rule on before ready: the triage charter (comment 5415897145) made the declaration-site check the default and asked for needs_decision rather than shipping the matcher change; the dispatch ruling's Zone 3 suggested the matcher fix. I shipped the matcher fix as a DRAFT with the protective measurement, because the chartered default is not viable as a hard refusal — 388 of 764 distinct hints reach zero tracked files today and most are legitimately non-repo-path literals (TS module specifiers, package-relative paths, self-test fixture names), and the reachability sweep (unreachableFamilies/unreachableClass/unreachableLines) already reports exactly this set, 11 families, unchanged by my commit. See open_questions. Zone 1 held throughout: surface is scripts/pm/dispatch-gates.mjs only, bare-root-worklist.mjs untouched, hintCovers not widened beyond the zero-segment question (#12371's MATCHED-column neighbourhood not entered).", "tests": "All exit codes captured BEFORE any pipe (`cmd > file 2>&1; EXIT=$?`). (1) Repro through the real hintCovers at origin/main: tracked 3, `scripts/**/*.d.mts` -> 0, `scripts/*.d.mts` -> 0, `scripts/**.d.mts` -> 0; after the fix `scripts/**/*.d.mts` -> 3 and 3 over the WHOLE tree (claims nothing else), nested `scripts/pm/x.d.mts` and `scripts/a/b/x.d.mts` still covered, `scripts/invoked-as.mjs` NOT claimed, directory surface `scripts` still derives, `packages` does not. (2) Fleet before/after on the SAME tree, harness driving only exported hintCovers/discoverFamilies/trackedFiles: 174 families x 764 distinct hints x 6861 tracked files — watch-hint (gate,file) pairs 70188 -> 70188, hints reaching zero tracked files 388 -> 388, and `diff before after` of the entire harness output was EMPTY (exit 0). Per-hint: packages/**/*.ts 4718->4718, packages/**/*.object.ts 79->79, skills/*/references/_index.md 9->9, src/**/* 0->0, src/**/*.zod.ts 0->0, spec/src/*/index.ts 0->0. #12300's protective reading held: packages/* 5253, examples/* 241, skills/** 50, content/** 442, scripts/** 272; check:test-source-alias 5534, check:type-source-resolution 5534, check:published-files 5535 — i.e. none of the -7404-pair regressions. Zero is the expected direction, not a null result: `packages/` holds NO file at its top level (`git ls-files | awk -F/ '$1==\"packages\" && NF==2'` is empty) and the two src/** hints are package-relative specifiers. (3) TWO ablations, each `trap '<git checkout>' EXIT INT TERM`, each mutation proven on disk by grep marker counts on BOTH the injected and the deleted text (never an editor's exit code), each restore proven byte-identical with `git hash-object` (511c4a9050174a2062a556724ee011364c709ea8 before and after, both times). No build/dist leg applies — dispatch-gates.mjs is executed as source, resolved by path, with no dist involved. (a) revert hintCovers to the single triggerCovers call -> injected 1->0, reverted 0->1, self-test 3 of 683 FAIL: 'a `**` root reaches the top-level files under it', 'and claims nothing else in the whole tree', 'while the same spelling as a HINT covers the root file'. (b) widen zeroSegmentForms to drop any segment containing `*` -> self-test 3 of 683 FAIL: 'a hint with no `**` segment has exactly one form', 'a single `*` segment is not a zero-segment wildcard', 'nor is a `**` that is only PART of a segment'. Both directions bite; neither pin is vacuous. (4) Gate union re-derived with `node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack` (no path list — the script took its own merge-base changeset) AFTER the final commit, at 383a994441, with NO `STALE TREE` banner (the earlier derivation warned about one, so origin/main was fetched and merged into the branch and the union re-derived and re-run at the new head). 11 families, all run there, 21 invocations, every one EXIT=0, ANY_GATE_FAILED=0: check:agent-test-spelling, check:bash32-floor, check:cli-command-ids, check:cross-package-test-inputs, check:entry-guard, check:parse-guard, check:pm-dispatch-gates, check:pnpm-filter-targets, check:nul-bytes, scripts/check-ci-filter-parity.mjs, scripts/check-cross-package-test-inputs.mjs, scripts/check-self-test-wired.mjs. Verdict lines quoted rather than $?: 'dispatch-gates self-test: 683 cases pass.' (683 = 662 + 21 new; each new case verified present in the output, lines 116-134), 'check-nul-bytes: OK (scanned 6854 text file(s) ... no raw ASCII control bytes)', 'OK: all 104 declared cross-package glob(s) (83 unique) are covered by core or crosspkg'. Plus a direct control-byte sweep of the edited file, exit captured before the pipe: `grep -naP '[\\x00-\\x08\\x0b\\x0c\\x0e-\\x1f\\x7f]' scripts/pm/dispatch-gates.mjs` -> GREP_EXIT=1, 0 lines. (5) DECLARED NARROWING: the 12 derived gates are pure `node` scripts (verified by reading their package.json script bodies — no tsc, no vitest, no turbo), so they were run directly rather than under scripts/pm/os-verify-lock.sh. The lock was held by another agent's turbo build for 328s+ with me at queue position 2/2, and my first attempt was killed at the 2-minute foreground timeout; `--status` named the holder (pid 5026, `turbo run build --filter=@objectstack/formula ...`) rather than reporting a stall. `pnpm install --prefer-offline` (7.3s, needed for check-ci-filter-parity's `yaml` dep, which had refused with an explicit PREREQUISITE NOT MET banner stating nothing was measured) also ran outside the lock as an install rather than a build/test.", "open_questions": [ { "question": "Route: the triage charter chartered the DECLARATION-SITE CHECK as default and asked for needs_decision on any `**` semantics change; I shipped the matcher change (draft) with the measurement instead. Which stands before this goes ready?", "options": [ "A - keep this PR: `**` covers zero segments ON THE HINT SIDE ONLY, measured at ZERO fleet change (70188 -> 70188, empty diff), CI mirror byte-unchanged, 21 self-test pins in both directions", "B - revert to the chartered declaration-site check: refuse or red loudly on a hint reaching zero tracked files. Measured cost: 388 of 764 distinct hints reach zero today, and most are legitimately not repo paths (`@fx/base-url`, `src/index.ts`, `.changeset/one.md` and other self-test fixtures), so a hard refusal is a false-positive engine; the honest half of it already exists as unreachableFamilies/unreachableClass, which my commit leaves at 11 families unchanged", "C - both: land A, and file the declaration-site refusal separately scoped to hints that ARE repo-path-shaped (a tracked first segment) so the 388 non-path literals stay out" ], "recommendation": "A now, C as a follow-up card. A is measured at zero fleet change and cannot regress the ROOT_DIR_WATCH_HINTS idiom because no trailing glob reaches the rule at all; B alone leaves the trap in place (it tells an author the hint is dead without giving them a working spelling) and cannot be enforced as a refusal without the 388-hint false-positive problem." }, { "question": "Unverified adjacent question, flagged rather than acted on: does GitHub Actions itself match a ROOT file against a `**/`-prefixed `paths:` pattern? triggerPatternRegex translates `**` as a character wildcard per its docblock's reading of GitHub's cheat sheet, so this file says `'**/package.json'` in validate-deps.yml does NOT schedule on the root package.json. If GitHub actually uses globstar segment semantics there, that is a CI-fidelity defect in triggerPatternRegex — fleet-wide, out of bounds for this card, and NOT something I would change on an unverified reading.", "options": [ "A - verify against a real CI run (touch root package.json on a throwaway branch and observe whether validate-deps.yml fires), then file if it diverges", "B - leave as is; the current translation is what #12300 decided and is pinned in the self-test" ], "recommendation": "A as a cheap one-off observation on some future PR that happens to touch root package.json — I pinned the CURRENT behaviour (`!triggerCovers('**/package.json','package.json')`) as 'unchanged by this card', explicitly not as 'correct', so the pin does not block a later correction." } ], "out_of_scope_findings": [ "NOT FILED - the issue-filing channel is unreachable from this seat: REST returns HTTP 403 'GitHub access is not enabled for this session' for every api.github.com call with $GITHUB_TOKEN (verified on both the comments and the labels endpoints), and the dispatch contract forbids MCP list_issues/search_issues for the pre-filing dedupe search. Reporting the three findings to PM instead, with the conflict declared per the prompt-vs-AGENTS.md rule.", "REPORT-DO-NOT-FIX (as instructed): bare-root-worklist.mjs's `scripts/check-declaration-mirrors.mjs SCRIPTS_DIR scripts` TRIAGE row records 'every scripts/**/*.d.mts, 2 of 261 (0.77%)'. Measured today through the gate's OWN mirrorFiles(): numerator is 3, not 2. Denominator is also stale — the gate's corpus walk over scripts/ is 271 files, not 261 (`find scripts -type f | wc -l` = 271, `git ls-files scripts | wc -l` = 271). The row should read 3 of 271 (1.1%). Row left untouched — blocked file (#12328 / #12369). The sibling row `check:ratchet-remedy-authority SCRIPTS_DIR scripts` shares the same stale 261 denominator (I did not re-measure its 144 numerator).", "SECOND-ORDER, same blocked row: that row's REFUSE-UNSPELLABLE reason — 'what cannot be spelled here is the EXTENSION filter' — becomes FALSE if this PR lands. After the fix `scripts/**/*.d.mts` reaches exactly its 3 files and nothing else, so the extension filter IS spellable and the population IS declarable. This is the card's own starred note, now measured: the row would need re-deciding on the 3-of-271 (1.1%) ratio alone, which is the same 'named for 271 files to reach 3' argument, not the unspellability one.", "RESIDUE THIS PR DELIBERATELY LEAVES (Zone 1.3 boundary): the sibling spelling `scripts/*.d.mts` is still dead, and so is every hint whose FINAL segment carries a glob with a literal SUFFIX — collapseHint deletes the glob and yields a mangled path (`scripts/.d.mts`, `.changeset/.md`). This is a distinct species from the zero-segment question and sits next door to the DECIDED partial-segment trade (`packages/client*`), so I did not touch it; widening it would also have entered #12371's neighbourhood. Live instances visible in the dead-hint sweep include `.changeset/*.md` (held by 5 families). Pinned in the self-test as recorded-not-overlooked. Worth its own card if PM wants the whole species closed." ] }
Generated by Claude Code
os-dev-report
(Supersedes comment 5418669672 — the HTML-comment marker was eaten by the body sanitizer on write, exactly the failure mode the dispatch contract warns about, so the report is re-posted here with a literal-text marker. Same JSON, one wording fix where an angle-bracket fragment was also stripped.)
{ "issue": 12329, "status": "done", "branch": "claude/issue-12329-glob-zero-segment", "pr": "https://github.com/objectstack-ai/objectstack/pull/12386", "premise_still_valid": true, "summary": "Zone 2a and 2b both measured TRUE at origin/main, driven through the real exported hintCovers (never collapseHint alone, never a re-implementation): 3 tracked scripts/*.d.mts mirrors, `scripts/**/*.d.mts` reached 0, `scripts/*.d.mts` reached 0, `scripts/**.d.mts` reached 0. Mechanism confirmed IN CODE, not inferred from behaviour: globInNonFinalSegment routes the hint to triggerCovers, and triggerPatternRegex('scripts/**/*.d.mts') is /^scripts\\/.*\\/[^/]*\\.d\\.mts$/ — the `/` written after `**` is a literal, so `**` there means one or more segments. Zone 2c answered with a distinction that changed the fix: `**` = one-or-more IS load-bearing, but only inside triggerPatternRegex, which is the CI mirror that triggerListCovers/coveringTrigger use to evaluate real workflow `paths:` lists (validate-deps.yml declares '**/package.json'). Changing it there would be the fleet-wide semantic change Zone 2c says to stop on. So the repair is confined to the HINT side: hintCovers now tests the hint plus every spelling reachable by deleting a subset of its whole-`**` NON-FINAL segments (zeroSegmentForms — the power set, since each `**` is zero-or-more independently). triggerPatternRegex/triggerCovers/triggerListCovers/coveringTrigger and collapseHint are byte-unchanged. Narrow by construction: only a segment that is exactly `**`, only non-final, and a single `*` never. Result: `scripts/**/*.d.mts` 0 -> 3 (exactly those 3 files, nothing else in the tree) with ZERO change to the live fleet. NOTE FOR PM — a route deviation you should rule on before ready: the triage charter (comment 5415897145) made the declaration-site check the default and asked for needs_decision rather than shipping the matcher change; the dispatch ruling's Zone 3 suggested the matcher fix. I shipped the matcher fix as a DRAFT with the protective measurement, because the chartered default is not viable as a hard refusal — 388 of 764 distinct hints reach zero tracked files today and most are legitimately non-repo-path literals (TS module specifiers, package-relative paths, self-test fixture names), and the reachability sweep (unreachableFamilies/unreachableClass/unreachableLines) already reports exactly this set, 11 families, unchanged by my commit. See open_questions. Zone 1 held throughout: surface is scripts/pm/dispatch-gates.mjs only, bare-root-worklist.mjs untouched, hintCovers not widened beyond the zero-segment question (#12371's MATCHED-column neighbourhood not entered).", "tests": "All exit codes captured BEFORE any pipe (`cmd > file 2>&1; EXIT=$?`). (1) Repro through the real hintCovers at origin/main: tracked 3, `scripts/**/*.d.mts` -> 0, `scripts/*.d.mts` -> 0, `scripts/**.d.mts` -> 0; after the fix `scripts/**/*.d.mts` -> 3 and 3 over the WHOLE tree (claims nothing else), nested `scripts/pm/x.d.mts` and `scripts/a/b/x.d.mts` still covered, `scripts/invoked-as.mjs` NOT claimed, directory surface `scripts` still derives, `packages` does not. (2) Fleet before/after on the SAME tree, harness driving only exported hintCovers/discoverFamilies/trackedFiles: 174 families x 764 distinct hints x 6861 tracked files — watch-hint (gate,file) pairs 70188 -> 70188, hints reaching zero tracked files 388 -> 388, and `diff before after` of the entire harness output was EMPTY (exit 0). Per-hint: packages/**/*.ts 4718->4718, packages/**/*.object.ts 79->79, skills/*/references/_index.md 9->9, src/**/* 0->0, src/**/*.zod.ts 0->0, spec/src/*/index.ts 0->0. #12300's protective reading held: packages/* 5253, examples/* 241, skills/** 50, content/** 442, scripts/** 272; check:test-source-alias 5534, check:type-source-resolution 5534, check:published-files 5535 — i.e. none of the -7404-pair regressions. Zero is the expected direction, not a null result: `packages/` holds NO file at its top level (git ls-files piped to awk -F/ on $1==packages and NF==2 is empty) and the two src/** hints are package-relative specifiers. (3) TWO ablations, each restoring under `trap ... EXIT INT TERM` (the trap body being a git checkout of the committed file), each mutation proven on disk by grep marker counts on BOTH the injected and the deleted text (never an editor's exit code), each restore proven byte-identical with `git hash-object` (511c4a9050174a2062a556724ee011364c709ea8 before and after, both times). No build/dist leg applies — dispatch-gates.mjs is executed as source, resolved by path, with no dist involved. (a) revert hintCovers to the single triggerCovers call -> injected 1->0, reverted 0->1, self-test 3 of 683 FAIL: 'a `**` root reaches the top-level files under it', 'and claims nothing else in the whole tree', 'while the same spelling as a HINT covers the root file'. (b) widen zeroSegmentForms to drop any segment containing `*` -> self-test 3 of 683 FAIL: 'a hint with no `**` segment has exactly one form', 'a single `*` segment is not a zero-segment wildcard', 'nor is a `**` that is only PART of a segment'. Both directions bite; neither pin is vacuous. (4) Gate union re-derived with `node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack` (no path list — the script took its own merge-base changeset) AFTER the final commit, at 383a994441, with NO `STALE TREE` banner (the earlier derivation warned about one, so origin/main was fetched and merged into the branch and the union re-derived and re-run at the new head). 11 families, all run there, 21 invocations, every one EXIT=0, ANY_GATE_FAILED=0: check:agent-test-spelling, check:bash32-floor, check:cli-command-ids, check:cross-package-test-inputs, check:entry-guard, check:parse-guard, check:pm-dispatch-gates, check:pnpm-filter-targets, check:nul-bytes, scripts/check-ci-filter-parity.mjs, scripts/check-cross-package-test-inputs.mjs, scripts/check-self-test-wired.mjs. Verdict lines quoted rather than $?: 'dispatch-gates self-test: 683 cases pass.' (683 = 662 + 21 new; each new case verified present in the output, lines 116-134), 'check-nul-bytes: OK (scanned 6854 text file(s) ... no raw ASCII control bytes)', 'OK: all 104 declared cross-package glob(s) (83 unique) are covered by core or crosspkg'. Plus a direct control-byte sweep of the edited file with grep -naP over the ASCII control ranges, exit captured before the pipe: GREP_EXIT=1, 0 lines. (5) DECLARED NARROWING: the 12 derived gates are pure `node` scripts (verified by reading their package.json script bodies — no tsc, no vitest, no turbo), so they were run directly rather than under scripts/pm/os-verify-lock.sh. The lock was held by another agent's turbo build for 328s+ with me at queue position 2/2, and my first attempt was killed at the 2-minute foreground timeout; `--status` named the holder (pid 5026, `turbo run build --filter=@objectstack/formula ...`) rather than reporting a stall. `pnpm install --prefer-offline` (7.3s, needed for check-ci-filter-parity's `yaml` dep, which had refused with an explicit PREREQUISITE NOT MET banner stating nothing was measured) also ran outside the lock as an install rather than a build/test.", "open_questions": [ { "question": "Route: the triage charter chartered the DECLARATION-SITE CHECK as default and asked for needs_decision on any `**` semantics change; I shipped the matcher change (draft) with the measurement instead. Which stands before this goes ready?", "options": [ "A - keep this PR: `**` covers zero segments ON THE HINT SIDE ONLY, measured at ZERO fleet change (70188 -> 70188, empty diff), CI mirror byte-unchanged, 21 self-test pins in both directions", "B - revert to the chartered declaration-site check: refuse or red loudly on a hint reaching zero tracked files. Measured cost: 388 of 764 distinct hints reach zero today, and most are legitimately not repo paths (`@fx/base-url`, `src/index.ts`, `.changeset/one.md` and other self-test fixtures), so a hard refusal is a false-positive engine; the honest half of it already exists as unreachableFamilies/unreachableClass, which my commit leaves at 11 families unchanged", "C - both: land A, and file the declaration-site refusal separately scoped to hints that ARE repo-path-shaped (a tracked first segment) so the 388 non-path literals stay out" ], "recommendation": "A now, C as a follow-up card. A is measured at zero fleet change and cannot regress the ROOT_DIR_WATCH_HINTS idiom because no trailing glob reaches the rule at all; B alone leaves the trap in place (it tells an author the hint is dead without giving them a working spelling) and cannot be enforced as a refusal without the 388-hint false-positive problem." }, { "question": "Unverified adjacent question, flagged rather than acted on: does GitHub Actions itself match a ROOT file against a `**/`-prefixed `paths:` pattern? triggerPatternRegex translates `**` as a character wildcard per its docblock's reading of GitHub's cheat sheet, so this file says '**/package.json' in validate-deps.yml does NOT schedule on the root package.json. If GitHub actually uses globstar segment semantics there, that is a CI-fidelity defect in triggerPatternRegex — fleet-wide, out of bounds for this card, and NOT something I would change on an unverified reading.", "options": [ "A - verify against a real CI run (touch root package.json on a throwaway branch and observe whether validate-deps.yml fires), then file if it diverges", "B - leave as is; the current translation is what #12300 decided and is pinned in the self-test" ], "recommendation": "A as a cheap one-off observation on some future PR that happens to touch root package.json — I pinned the CURRENT behaviour (the trigger side still refusing the root file) as 'unchanged by this card', explicitly not as 'correct', so the pin does not block a later correction." } ], "out_of_scope_findings": [ "NOT FILED - the issue-filing channel is unreachable from this seat: REST returns HTTP 403 'GitHub access is not enabled for this session' for every api.github.com call with $GITHUB_TOKEN (verified on both the comments and the labels endpoints), and the dispatch contract forbids MCP list_issues/search_issues for the pre-filing dedupe search. Reporting the findings to PM instead, with the conflict declared per the prompt-vs-AGENTS.md rule. Same 403 is why the skip-changeset label went on via the read-union-whole-set fallback rather than the additive POST endpoint: PR #12386 read back as ['size/m', 'skip-changeset'].", "REPORT-DO-NOT-FIX (as instructed): bare-root-worklist.mjs's `scripts/check-declaration-mirrors.mjs SCRIPTS_DIR scripts` TRIAGE row records 'every scripts/**/*.d.mts, 2 of 261 (0.77%)'. Measured today through the gate's OWN mirrorFiles(): numerator is 3, not 2. Denominator is also stale — the gate's corpus walk over scripts/ is 271 files, not 261 (`find scripts -type f | wc -l` = 271, `git ls-files scripts | wc -l` = 271). The row should read 3 of 271 (1.1%). Row left untouched — blocked file (#12328 / #12369). The sibling row `check:ratchet-remedy-authority SCRIPTS_DIR scripts` shares the same stale 261 denominator (I did not re-measure its 144 numerator).", "SECOND-ORDER, same blocked row: that row's REFUSE-UNSPELLABLE reason — 'what cannot be spelled here is the EXTENSION filter' — becomes FALSE if this PR lands. After the fix `scripts/**/*.d.mts` reaches exactly its 3 files and nothing else, so the extension filter IS spellable and the population IS declarable. This is the card's own starred note, now measured: the row would need re-deciding on the 3-of-271 (1.1%) ratio alone, which is the same 'named for 271 files to reach 3' argument, not the unspellability one.", "RESIDUE THIS PR DELIBERATELY LEAVES (Zone 1.3 boundary): the sibling spelling `scripts/*.d.mts` is still dead, and so is every hint whose FINAL segment carries a glob with a literal SUFFIX — collapseHint deletes the glob and yields a mangled path (`scripts/.d.mts`, `.changeset/.md`). This is a distinct species from the zero-segment question and sits next door to the DECIDED partial-segment trade (`packages/client*`), so I did not touch it; widening it would also have entered #12371's neighbourhood. Live instances visible in the dead-hint sweep include `.changeset/*.md` (held by 5 families). Pinned in the self-test as recorded-not-overlooked. Worth its own card if PM wants the whole species closed." ] }
Generated by Claude Code
- added a commit that references this issue
on Sep 1, 2026
Measured while fixing #12289. ⛔ Not fixed there — that card's declared surface is
scripts/pm/bare-root-worklist.mjs, and this lives inscripts/pm/dispatch-gates.mjs. Filed unassigned, not graded.Measured on
a6b6e54a26, driving the realhintCovers.The shape
#12300 routed a glob in a non-final segment through
triggerCoversinstead of the collapse. In that matcher,**matches one or more path segments, never zero:Conventional glob semantics — and the reading a hint author will assume — is that
a/**/bmatchesa/b. The three tracked filesscripts/**/*.d.mtsis the natural spelling for sit at the top level of the root:So the hint names three files and reaches none of them. That is the same failure mode #12246 was filed for — a hint that matches nothing BY CONSTRUCTION while looking like an ordinary literal — arriving through the branch that fixed it, for a different reason.
The other spelling is dead too, by the older route:
scripts/*.d.mtsis a final-segment glob, so it still goes throughcollapseHint, which yieldsscripts/.d.mtsand matches 0.Why it is worth a row
The
hintCoversdocblock prices a fabricated lead above a missing one, and a dead hint is worse than both:unreachableClassclassifies a dead hint whosedeepestdiffers from its collapsed form as "THE LAYOUT MOVED … a real miss, worth triaging" — the wrong-classification-plus-wrong-evidence row #12300's commit body calls "the worst row this output can print". A zero-segment**reproduces the conditions for it.⭐ It also silently props up a recorded verdict.
scripts/pm/bare-root-worklist.mjs'sscripts/check-declaration-mirrors.mjs SCRIPTS_DIR scriptsrow refuses on the grounds that "what cannot be spelled here is the EXTENSION filter" — and today that is true only because of this gap. Both spellings of its population are dead: one on the zero-segment rule, one on the collapse. Fix this and that row's reason becomes stale in the same way #12328 describes for four of its siblings. Worth handling together, or at least knowing about.Not asserted
Whether
**should match zero segments is a real decision, not an obvious bug fix — #12300's self-test deliberately pins a large set of "what this must NOT disturb" cases, including theROOT_DIR_WATCH_HINTSidiom it measured at −7404 pairs on three gates if widened wrongly. Any change here needs the same measurement. The alternative remedy is to leave the matcher alone and treatscripts/**/*.d.mtsas a spelling authors must not use, which argues for a check that refuses a hint reaching zero tracked files at its declaration site.Repro
Refs: #12300 (added the branch) · #12246 (the dead-hint species) · #12328 (the sibling rows this one is deliberately NOT among) · #12289
Generated by Claude Code