Skip to content

finding(tooling): check-dispatcher-error-vocabulary's new glob pin counts DIRECTORIES where its floor counts PUBLISHED MEMBERS — the self-test that justifies the pin is green against the wrong population #17145

Description

@os-bill

Filed by the domain:spec execution seat (session_01MkQhmuuJAVDjmeWNixwDDH, 2026-09-09T13:1xZ) from the contract-review-tier verdict on PR #17056 / card #16649. That verdict was a PASS with no binding findings; these are its four non-binding items, carded rather than patched because a post-PASS commit moves the head, which under the carrier rule invalidates the PASS and would cost a second full at-tier review for cosmetic and latent-only defects. ⛔ Not claiming. No domain:* and no pm-state applied — those are triage's to produce.

Routing, so grading is one read: the file is scripts/check-dispatcher-error-vocabulary.mjs; its SUBJECT is the packages/spec error-code ledger contract, and its parent card #16649 is domain:spec. The scripts/ gate family otherwise routes domain:devx. The seat's own view is that it follows the parent, but the call is triage's.

The substantive one: a self-test that is green for the wrong reason

PR #17056 added emptyWorkspaceGlobs, a pin that refuses any non-exclusion workspace glob expanding to nothing. The pin works and has a lit red control (adding packages/nonexistent/* to pnpm-workspace.yaml exits 1 naming the glob). ⛔ Nothing here says the pin is wrong.

What is wrong is the arithmetic that justifies it, and it is wrong in the way this whole class of gate exists to prevent — the check answers a question next to the one it claims to answer.

quantity what the floor uses what the pin and its self-test use
population derivePublishedFaces70 published members expandWorkspaceGlob88 directories
largest glob packages/* = 23 published members packages/* = 31 directories

The 31 includes 8 category directories that carry no manifest at all (packages/adapters, apps, connectors, drivers, plugins, qa, services, triggers). So:

  • The self-test at :5762-5772 asserts total − max(perGlob) > PUBLISHED_SOURCE_FACE_FLOOR, i.e. 88 − 31 = 57 > 40. ⭐ It is not green-by-construction — it reads the live tree and can flip. But it flips on the wrong number. The real margin is 70 − 23 = 47 > 40, a margin of 7, not the 17 the docblock claims.
  • ⇒ There exists a tree where published falls to ≤ 62 while packages/* holds 23. There the floor would catch a lost packages/*, making the docblock's "a floor of 40 would not notice" false — and this assertion still reads 80 − 31 = 49 > 40 and stays green. The sentence it exists to protect would have gone stale with no red.

The pin measures directory existence, not member existence

Measured by the reviewer in a disposable worktree, three controls, tree restored after each:

control change to pnpm-workspace.yaml result
vanished parent (lit red) - packages/nonexistent/* exit 1 — "declares 1 glob(s) that expand to NO member"
exclusion carve-out - '!packages/nonexistent' exit 0 — correct, exclusion globs enumerate empty by pnpm semantics
glob resolving only to NON-member dirs - content/* (content/blog, content/docs, neither has a manifest) exit 0 — the pin is silent

The realistic failure is members moving one level deeper while pnpm-workspace.yaml does not follow: the parent still exists, the glob still resolves to category directories, the pin stays quiet, and the floor stays quiet too. The thrown message "expand to NO member" is therefore inaccurate — it counts directories.

Scope

  1. main()'s expand gains a manifest filter, so "NO member" means what it says:
    expand: (g) => expandWorkspaceGlob(ROOT, g).filter((d) => existsSync(join(ROOT, d, 'package.json')))
    The three existing self-test cases pass unchanged.
  2. The :5762-5772 assertion computes on the published (or at minimum manifest-filtered) set, so it guards the number the floor actually uses.
  3. The PUBLISHED_SOURCE_FACE_FLOOR docblock's numbers: packages/* 31 → 23, total 88 → 80 (published 70), "leaves 57" → 47 from the published view.
  4. PR lint: widen the vocabulary gate's face refusal to every published package and retire boot-refusal #17056's body carries the same wrong figures, contradicts itself (80 in one paragraph, 88 in the next), says "Five precedents" where the final head has six, and asserts that the earlier review's "23" was a miscount. ⛔ It was not — the review was right and the implementer had silently changed which quantity was being measured. The body cannot be rewritten after merge, so this item is history, not work: it is recorded here so the next reader of that PR is not misled by it.

⚠️ Known-stale by design: the commit message

0292e14f7's message carries "31 of 88 members" verbatim and ⛔ will not be rewritten — no force-push, no rewriting landed history. This card is the correction of record for it.

Dedup

⚠️ Declared rather than implied, because the normal channel is not answering. MCP search_issues free-text returns total_count: 0 with incomplete_results: false for terms that certainly exist (measured this session against spec and ElementDataSourceSchema, the latter present in an open issue's title; written up on #16762), and raw REST /search/issues is refused for repo-scoped sessions.

The dedup argument here does not rest on search: the subject did not exist until commit 0292e14f7 earlier today. emptyWorkspaceGlobs, PUBLISHED_SOURCE_FACE_FLOOR and the assertion in question are all introduced by the PR this card descends from, so no prior card can be about them.

Refs #16649 (parent) · PR #17056 (the change) · #16762 (the search channel).

🤖 Generated with Claude Code

https://claude.ai/code/session_01MkQhmuuJAVDjmeWNixwDDH

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions