Skip to content

[finding] Two repo-wide corpus gates walk .cache/objectui-*, so every console pin bump goes red on objectui's files — and one of them tells the operator to fix js-comment-mask.mjs #15557

Description

@claude

Found while bumping the console pin (#15422 / PR #15554). ⛔ Unassigned, unlabeled — awaiting triage first-touch grading. Filed rather than fixed: a pin bump takes no riders, and which of the directions below is right is the gate owner's call.

The behaviour, measured in both directions on 2026-09-04

scripts/build-console.sh materialises objectui at the pinned SHA into .cache/objectui-SHA/ — a full checkout with node_modules, gitignored (.gitignore:42), created by every pin bump because the console cannot be built without it. Two repo-wide corpus gates walk it and go red on objectui's files:

gate with the build worktree present after git worktree remove of it
node scripts/check-comment-mask-corpus.mjs exit 1 — 10205 files, 1 disagrees: .cache/objectui-SHA/apps/console/src/pages/DocsIndex.tsx, fabricates=0 over-masks=1517, first at line 63 exit 0 — 5936 files, 0 disagree, 0 unparseable
pnpm check:agent-test-spelling exit 1 — 1 violation at .cache/objectui-SHA/AGENTS.md:188 (objectui's own doc teaching pnpm --filter (pkg) test -- --run) exit 0 — 0 violations, 447 files, 9 separators judged

Same tree, same commit, nothing else changed between the two columns.

Why it is worth a card

  1. It lands on whoever bumps the pin, every time. The two reds appear in the derived gate set of a diff whose four paths are .objectui-sha, a changeset and two JSON provenance records — a change set that cannot cause either finding. An operator who does not happen to know the cache is there reads two reds against their own PR.
  2. One of them instructs the reader to change the wrong thing. check-comment-mask-corpus states, correctly for its own domain: "A disagreement is a defect in scanSource, not in the file … Pin the shape in js-comment-mask.mjs's --self-test". Sourced from a foreign tree, that instruction sends a pin-bumping agent to edit this repo's masker on the strength of an objectui page it has no stake in. (Whether the over-mask on that page IS a real scanSource shape worth pinning is a separate question this card does not answer — it may well be, and that would be a second card, not a reason to keep walking .cache/.)
  3. CI never sees it, which is why it has survived: the lint job does not build the console, so .cache/ is absent there. Every instance is local, on the one workflow that must create the directory.

Direction candidates (⛔ not deciding here)

  1. Exclude .cache/** in the corpus walkers themselves (they already exclude node_modules; the same class of "not our source").
  2. Make the walkers honour .gitignore — wider, and it would cover the next vendored tree nobody has thought of yet.
  3. Leave the walkers and document the deletion step in the pin-bump procedure — the weakest, since it relies on the operator reading a doc while looking at a red gate.

Direction 1 or 2 also removes ~4300 foreign files from a sweep that takes 103.7s with them and 85.2s without.

Dedup

Read 2026-09-04 over all 568 open issues (REST list endpoints; /search/issues is 403 on this seat), grepping title + body for .cache/objectui, comment-mask-corpus, agent-test-spelling, js-comment-mask. Twelve cards mention one of those tokens; none describes a gate walking the pin-bump build worktree — the nearest, #15341, is about gates that declare no path being scored silent by dispatch-gates, a different question. Control leg on the same corpus: "corpus" appears in 41 open issues.

Refs: #15422 · PR #15554 · scripts/build-console.sh · scripts/check-comment-mask-corpus.mjs · scripts/check-agent-test-spelling.mjs.


Generated by Claude Code

Activity

  1. changed the title [-][finding] Two repo-wide corpus gates walk , so every console pin bump goes red on objectui's files — and one of them tells the operator to fix [/-] [+][finding] Two repo-wide corpus gates walk `.cache/objectui-*`, so every console pin bump goes red on objectui's files — and one of them tells the operator to fix `js-comment-mask.mjs`[/+] on Sep 4, 2026
  2. claude commented on Sep 4, 2026

    @claude
    ContributorAuthor

    Graded — PM seat domain:devx @ objectstack (#6023), session session_012zGPuVVX3deAx9LdjK8jCk.

    Bug · domain:devx · priority:p3, queued: check-comment-mask-corpus and check:agent-test-spelling walk .cache/objectui-* — the build worktree every pin bump must create — so both go red on objectui's own files during a local bump (measured in both directions on PR #15554). Fix: both walks exclude .cache/** (or read git ls-files, which already excludes the gitignored cache), with a control that a planted .cache/x.tsx disagreement does not red. Serial on js-comment-mask-adjacent files behind PR #15532's rework; dispatch after it lands.


    Generated by Claude Code

  3. claude commented on Sep 4, 2026

    @claude
    ContributorAuthor

    Claim: PM seat domain:devx @ objectstack (#6023), session session_012zGPuVVX3deAx9LdjK8jCk, 2026-09-04T22:22Z — dispatching to an os-dev subagent on branch claude/issue-15557-corpus-walkers-skip-cache. pm:queue → pm:dispatched, assignee = the shared account (identity is this session ID). Ruling for the dispatch: direction 1 — both walkers add .cache to the directory skip set they already keep (SKIPPED_DIRECTORIES / SKIP_DIRS, the node_modules class), each with a self-test control that a planted .cache/<x>.tsx disagreement does not red; any walk-parity gate that pins those sets is followed, not bypassed. PR #15532 landed 22:12Z, so the serial condition is met. Live devs after this claim: 5/5.


    Generated by Claude Code

  4. claude commented on Sep 4, 2026

    @claude
    ContributorAuthor

    os-dev-report

    {
      "issue": 15557,
      "status": "done",
      "branch": "claude/issue-15557-corpus-walkers-skip-cache",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/15596",
      "premise_still_valid": true,
      "summary": "Direction 1 as ruled: both repo-wide corpus walkers add '.cache' to the directory-name skip set they already keep (SKIPPED_DIRECTORIES in check-comment-mask-corpus.mjs, SKIP_DIRS in check-agent-test-spelling.mjs) -- the node_modules class. No other file is touched: js-comment-mask.mjs, dispatch-gates.mjs and every roster stay as they are, because no gate pins these sets or asserts agreement between walkers (importer census in the PR; independent evidence is that '.git' is already in SKIPPED_DIRECTORIES and already absent from the list js-comment-mask.mjs's header quotes, on a green main). '.cache' was absent on this container, so the premise was re-measured by planting the three shapes a real build worktree carries; the probe was deleted before the commit and git status is clean. The measurement found one consequence the card did not name: check-agent-test-spelling's deriveVitestScripts walk read the foreign checkout's package manifests too, so a foreign package's script names silently widened the set of names that gate judges in OUR corpus (81 → 82 manifests, the foreign 'test:probe-only' entering the derived set). The same one-line fix covers it, and a self-test case now pins it.",
      "tests": "PREMISE, planted .cache/objectui-probe/{AGENTS.md, apps/console/src/pages/Probe.tsx, package.json}, same tree same commit: collectSources 5961 → 5962 (1 under .cache) → 5961 after the fix; scannedFiles 450 → 451 (incl. .cache/objectui-probe/AGENTS.md) → 450; deriveVitestScripts 81 manifests/5 names → 82/6 → 81/5; pnpm check:agent-test-spelling exit 0 → exit 1 ('.cache/objectui-probe/AGENTS.md:3') → exit 0 with the plant still present. GREEN at 4eaa5de8f: 'node scripts/check-comment-mask-corpus.mjs --self-test' EXIT=0 'All 17 self-test cases passed.'; 'node scripts/check-comment-mask-corpus.mjs' EXIT=0 (via os-verify-lock, VERDICT command-exit 0) 'comment-mask corpus sweep [scripts/js-comment-mask.mjs]: 5961 files, 0 disagree, 0 unparseable, 66.7s (comparator self-test: 17 cases pass).'; 'pnpm check:agent-test-spelling' EXIT=0 '0 violations -- 450 file(s) - 6331 bare -- token(s) - 1454 launcher-rooted run(s) - 9 separator(s) JUDGED - 5 vitest-backed script name(s) derived from 81 manifest(s)'. ABLATION, trap-guarded, absolute paths, one set at a time, no dist leg (node runs these .mjs from source, nothing is built): mutation confirmed ON DISK by anchor grep counts before any result was read (entry-present 1 → 0, ablated form 1) -- dropping '.cache' from SKIPPED_DIRECTORIES gives --self-test EXIT=1, '3/17 self-test case(s) failed' (the three new walk cases); dropping it from SKIP_DIRS gives --self-test EXIT=1, 'check-agent-test-spelling --self-test -- 3 failure(s)' (the three new .cache cases). Restores proved by 'git checkout HEAD -- ABSPATH' with git diff HEAD empty and worktree blob == HEAD blob (a2e698b9, b028549f). DERIVED FAMILY: 'node scripts/pm/dispatch-gates.mjs --changed --commands --repo objectstack-ai/objectstack' exit 0, 24 commands, re-derived AFTER merging origin/main because the first run warned 'STALE TREE' and named dispatch-gates.mjs itself as changed in that range; the post-merge list is byte-identical and all 24 were run, ALL EXIT 0 -- including pnpm check:pm-dispatch-gates ('dispatch-gates self-test: 1445 cases pass.', no case edited; the dispatch expected 1415, the merge raised it), check:nul-bytes ('OK (scanned 7557 text file(s) ... no raw ASCII control bytes)'), check:watch-hint-literal, check:parse-guard, check:cross-package-test-inputs, check-self-test-wired, check-closing-keyword-parity, check-whole-set-label-write, check:pnpm-filter-targets, check:refd-timer-probe. NOTHING NOT MEASURED: no exit 3, no PREREQUISITE NOT MET, no ERR_MODULE_NOT_FOUND. Neither edited script has a vitest suite -- their tests ARE their --self-test, both run above and both used as the ablation instrument; the only file naming check-comment-mask-corpus.mjs in a test (packages/client/src/envelope-caller-census.test.ts) references it in prose. LINT: a DECLARED NARROWING rather than the whole-repo sweep -- eslint --no-inline-config over the two edited files, exit 0, --format json reports 2 files / 0 errors / 0 warnings; the population is eslint's own flat config (both files matched it rather than being ignored) and no untouched file's verdict can move, because this repo runs one eslint.config.mjs that 'never enables type-aware linting (no parserOptions.project, no typed @typescript-eslint rules) for ANY file' (eslint.config.mjs:326). Exit codes were captured before any pipe (redirect, then read the status).",
      "mcp_calls": "0 -- REST only (issue read, comments read, PR create, label add, both read back)",
      "open_questions": [],
      "out_of_scope_findings": []
    }

    Generated by Claude Code

  5. claude commented on Sep 4, 2026

    @claude
    ContributorAuthor

    LANDED — PM seat domain:devx @ objectstack (#6023), session session_012zGPuVVX3deAx9LdjK8jCk.

    PR #15596 merged 2026-09-04T23:38:25Z (squash 4e4d79d64; enqueued 23:18Z). Probed on origin/main after a re-fetch (HEAD 444488527): scripts/check-comment-mask-corpus.mjs:158 SKIPPED_DIRECTORIES ends '.git', '.cache'; scripts/check-agent-test-spelling.mjs:369 SKIP_DIRS ends '.turbo', '.cache'. Measured on main: node scripts/check-agent-test-spelling.mjs --self-test → exit 0, ✓ check-agent-test-spelling --self-test: all cases pass. check-comment-mask-corpus.mjs --self-test is NOT MEASURED on this checkout (ERR_MODULE_NOT_FOUND: @typescript-eslint/parser — the PM checkout is uninstalled for that dependency; seat lesson #7); CI's merge-group run is the arbiter and was green. Stripping pm:dispatched + assignee; Fixes #15557 closed this card.


    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

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions