Repository navigation
[finding] packages/qa/dogfood/tsconfig.json includes src/**/*, a directory the package does not have #10899
Description
Activity
huangyiirene commented
on Aug 21, 2026 CollaboratorMore actionsTriage (finding first-touch): promoted to
pm:queue—domain:devx, type Task, S mechanical. Verified onorigin/main@58563be0:packages/qa/dogfood/has nosrc/(tree is CHANGELOG/README/package.json/test/tsconfig/vitest.config), and the package is test-only by design (dogfood QA harness), so disposition (1) — delete"src/**/*"from theincludearray — is the ruled fix. ⛔ Not disposition (3): a third invariant for a population of one with cosmetic impact fails the focus axis; the filer's own four-axis read agrees. Foldable into any devx family batch as a rider if one is passing nearby (it is its own file — no serial constraint).
Generated by Claude Code
Claim: PM loop round R4
Session:session_015ahemw8RcTgqtxrj15PEZx
Branch:claude/issue-10899-dogfood-tsconfig-include
Worktree:objectstack-issue-10899
Domain:domain:devx
File surface:packages/qa/dogfood/tsconfig.json. ⛔ Do not create asrc/directory to satisfy the glob — the fix is the declaration, not the tree (stop on breach; explain in the report)
Container & model:S,mode:subagent,model: opus(--tierfor this path: "no path-derived mandate". Judgement tier despite the size — see the trap below; the mechanical read of this card is the one that breaks the build)
Clause-②: no — a package-internal tsconfig. No schema, no accept/reject contract behaviour, no public surface.
Serial constraints cleared: disjoint from everything live. #10913 (dispatched this round) →packages/lint/**, different package. PR #11425 (awaiting human merge) →.claude/**+AGENTS.md.
Premise verified this round at
origin/mainb3723188packages/qa/dogfood/ -> CHANGELOG.md README.md package.json test tsconfig.json vitest.config.ts packages/qa/dogfood/tsconfig.json: "include": ["src/**/*", "test/**/*"] CONTROL — packages/lint/ -> ... package.json scripts src tsconfig.json (a package that DOES have src/)⇒
src/genuinely does not exist here,test/does. The card is right.⚠️ The trap, and why this is not a one-line deleteThe same file's
compilerOptionscarries a long, deliberate comment explaining thatrootDiris set to"../../.."on purpose — because the route-ledger ↔ live-mount parity gate (#7526) must import five sibling packages' ledgers as relative sources, each package-internal by design with no entry point to import from.⇒ This tsconfig's shape is load-bearing and was reasoned about. ⛔ Do not "tidy" anything else in it, and do not assume the
includewas written carelessly just because one of its two globs is dead. Establish whatincludecurrently resolves to before and after your change and show the file set is unchanged apart from the dead glob — atsc --showConfig-style reading, not an argument.⚠️ If removingsrc/**/*changes which files the program compiles, that is not a cleanup and you should stop and report.Gates
Derive from the tree against your actual changed paths, and treat the derived list as a floor (#11404 — gates whose script basename lacks
check-and which have nopackage.jsonscript are absent fromdispatch-gates' family universe entirely). A tsconfig edit can movecheck:type-check-coverage/check:type-source-resolution; check whether it does.
Generated by Claude Code
{ "issue": 10899, "status": "done", "branch": "claude/issue-10899-dogfood-tsconfig-include", "pr": "https://github.com/objectstack-ai/objectstack/pull/11474", "premise_still_valid": true, "summary": "Re-derived the premise at origin/main b3723188 and it holds: packages/qa/dogfood has no src/ (tree is CHANGELOG.md, README.md, package.json, test/, tsconfig.json, vitest.config.ts) while test/ holds 151 files. Removed the dead 'src/**/*' entry from the include array and nothing else - rootDir '../../..' and its comment are untouched. The change is proven inert rather than argued inert: tsc --showConfig before and after resolves a byte-identical 151-entry files array in the same order, with identical compilerOptions and exclude, so the only delta in the whole emitted config is the echoed glob itself. Nothing in the repo depends on this tsconfig's include shape: no project references, and the one invariant that reads include roots (GENERATED_COVERED in check-type-check-coverage.mjs) keys on whether a root is gitignored, which src here is not - the distinction #10880 drew deliberately.", "include_resolution": { "method": "tsc --showConfig -p packages/qa/dogfood/tsconfig.json, TypeScript 6.0.3 (the version the package declares), run on the clean tree and again after the edit", "before": { "include": [ "src/**/*", "test/**/*" ], "resolved_files": 151, "all_under": "./test/" }, "after": { "include": [ "test/**/*" ], "resolved_files": 151, "all_under": "./test/" }, "files_array_identical_order_and_content": true, "only_in_before": [], "only_in_after": [], "compilerOptions_identical": true, "exclude_identical": true, "full_showconfig_diff": "170d169 < \"src/**/*\", -- one line, the echoed glob itself", "verdict": "resolved file set unchanged apart from the dead glob; the compiled program is identical" }, "tests": "All at final commit 99eee07a, tree clean and byte-identical to that commit. Exit codes captured before any pipe (redirect-then-capture, never EXIT=$? after a tail), and each gate quoted from its own printed verdict line rather than from $?. Gate list derived by 'node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack' with NO paths passed (it took its own change set from merge base b37231883: 1 path, working tree) and treated as a floor. 13/13 green. Verdict lines: 'check-type-check-coverage: OK - 65/78 workspace packages type-checked (plus the root), 13 in the DEBT ledger (436 frozen raw errors), 1 exempt' | 'check-type-source-resolution OK - 77 packages with a tsconfig.json scanned; 51 registered as still resolving a workspace dep types through dist/' | 'check-nul-bytes: OK (scanned 6431 text files; no raw ASCII control bytes)'. REVERSE VERIFICATION - this is not an ablation and nothing needed rebuilding, because no build artifact stands between the edit and the gates: they read tsconfig.json off disk. Method: fix COMMITTED FIRST, then 'git restore --source=$BASE -- packages/qa/dogfood/tsconfig.json' stood the base file back up (tree only, no staging), confirmed on disk by grep reading back 'include: [src/**/*, test/**/*]' and by porcelain showing a lone ' M' and never 'MM'; both include-reading ratchets re-run at base; then 'git restore --source=HEAD' and porcelain confirmed empty. Predicted direction was NO CHANGE - a glob that matches nothing cannot move a count - and that is what was observed: both verdict lines diffed byte-identical between base and head, including the test-layer 1048-files-hidden and source-layer 9-files counts. Floor extension for #11404 checked mechanically: every CI-invoked node script whose basename lacks 'check-' was scanned for tsconfig reads; the only hit is dispatch-gates.mjs itself, the derivation tool, not a gate on this diff.", "gates": { "derived_and_run": [ { "gate": "pnpm --filter @objectstack/spec run check:empty-state", "exit": 0 }, { "gate": "pnpm --filter @objectstack/spec run check:liveness", "exit": 0 }, { "gate": "pnpm --filter @objectstack/spec run check:strictness-ledger", "exit": 0 }, { "gate": "pnpm --filter @objectstack/spec run check:variant-docs", "exit": 0 }, { "gate": "pnpm check:published-files", "exit": 0 }, { "gate": "pnpm check:slot-lookup", "exit": 0 }, { "gate": "pnpm check:test-source-alias", "exit": 0 }, { "gate": "pnpm check:type-source-resolution", "exit": 0 }, { "gate": "node scripts/check-ci-filter-parity.mjs", "exit": 0 }, { "gate": "node scripts/check-plugin-teardown-shape.mjs", "exit": 0 }, { "gate": "node scripts/docs-audit/check-affected-docs.mjs", "exit": 0 } ], "added_above_the_derived_list": [ { "gate": "pnpm check:type-check-coverage", "exit": 0, "why": "it reads every package's include array; the derivation did not name it" }, { "gate": "pnpm check:nul-bytes", "exit": 0, "why": "any edit" } ], "all_green": true, "union_run_at_sha": "99eee07a", "ci_at_report_time": "in_progress - 33 check runs on 99eee07a: 15 success, 5 skipped, 10 in_progress, 0 failures. Not waited on, per the dispatch contract." }, "line_budget": "not applicable - the diff touches no skills/** path (git diff origin/main...HEAD --name-only | grep -c '^skills/' = 0), so no published-skill line/token budget applies", "deviations": [ "DECLARED NARROWING - repo-wide 'pnpm lint' not run. Three pieces of evidence, all measured: (1) population read from eslint's own config, not guessed - 'pnpm exec eslint --no-inline-config --format json packages/qa/dogfood/tsconfig.json' returns one result whose only message is 'File ignored because no matching configuration was supplied.'; (2) count read from --format json - 1 result entry, 0 errors, 1 warning, and that warning IS the not-configured notice, so 0 files in this diff are linted; (3) invariance for untouched files - eslint.config.mjs states in-repo, backed by a positive control it documents, that this repo never enables type-aware linting (no parserOptions.project, no typed @typescript-eslint rules) for ANY file, so no tsconfig include change can move an eslint verdict on a file it does not appear in.", "DECLARED NARROWING - 'pnpm --filter @objectstack/dogfood typecheck' not run locally. It needs the ~25-package dependency closure built for its .d.ts. It is redundant here rather than merely expensive: tsc's behaviour is a function of its resolved program, and --showConfig proves that program byte-identical before and after (same 151 files, same order, same compilerOptions, same exclude), so running tsc twice cannot distinguish the two trees. CI runs it regardless in the required TypeScript Type Check and Dogfood Regression Gate jobs.", "No changeset. @objectstack/dogfood is private:true and the diff changes no published artifact. 'skip-changeset' applied via the additive POST endpoint and READ BACK after the bots settled: labels on PR 11474 are size/xs, tooling, skip-changeset - the size-labeler PUT did run (it added size/xs and tooling) and the label survived it." ], "files_changed": [ { "path": "packages/qa/dogfood/tsconfig.json", "insertions": 1, "deletions": 1, "note": "include array only; rootDir and its comment untouched" } ], "open_questions": [], "out_of_scope_findings": [ "filed as #11476: packages/qa/dogfood/tsconfig.json - the rootDir comment opens '// No `rootDir`.' on the line directly above '\"rootDir\": \"../../..\"'. Cosmetic only, and the comment's argument still holds (an explicit repo-root rootDir keeps every input under it, so the sibling-source imports it wants stay legal); what is wrong is the opening sentence, which denies the declaration two lines below it - stale knowledge sitting on the exact shape Zone 1 flagged as load-bearing. Unassigned, labelled 'finding', not queued. Provenance deliberately NOT claimed: this checkout is shallow (92 commits) and blame lands on the boundary commit, so whether rootDir was re-added or the comment predates the form is unanswerable from here. Deliberately NOT fixed in this PR - Zone 1 scopes the diff to the dead glob." ] }
Generated by Claude Code
ACCEPT — PR #11474, head
99eee07a.The claim comment on this card set one bar: don't argue the glob is dead, measure what
includeresolves to before and after. That bar is met, and I re-derived the load-bearing half independently rather than reading it back.Verified against the repo, not against the report
Current
origin/mainisf31ea1c4— three commits past theb3723188the dev measured at (#11468,#11449,#11467). Their file sets are disjoint frompackages/qa/dogfood/**and from both include-reading ratchets, so every reading below still stands at today's tip.1. The dead glob is dead, and the program is accounted for without re-running tsc.
git ls-tree -r origin/main packages/qa/dogfood/— the package isCHANGELOG.md,README.md,package.json,test/,tsconfig.json,vitest.config.ts. Nosrcat any depth. The zero-hit reading has a live positive control on the same instrument: the samels-treereturns 151 files undertest/, all 151 of them.ts(extension census, no other extension present).That is the corroboration that matters: the report's
--showConfigresolves a 151-entryfilesarray, andtest/**/*alone has exactly 151 typescript files. The two numbers meet with nothing left over, sosrc/**/*contributed zero — checkable from the tree alone, without trusting the tsc invocation.2.
GENERATED_COVEREDkeys on gitignored-ness — confirmed, with a correction to the instrument.
scripts/check-type-check-coverage.mjsatorigin/main: the population is built bygitIgnoredPaths()(git check-ignore --stdin -z), and the problem text fires only for "a path the repo's own ignore rules say is NOT checked in". So the question is whetherdogfood/srcis ignored.⚠️ My first control failed and the reading was not usable.git check-ignore packages/qa/dogfood/node_modulesreturned not ignored — because the rule isnode_modules/, directory-form, and a bare non-existent path does not match it. Re-run in directory form the controls come alive (node_modules/→ ignored,node_modules/foo→ ignored,dist/x.js→ ignored), and against those:path ignored? packages/qa/dogfood/src/no packages/qa/dogfood/src/foo.tsno packages/qa/dogfood/test/no (checked in) srcis neither checked in nor ignored, so it was never in that invariant's population. This also settles the sharper question the script itself raises — its ⛔ "deleting the glob is not automatically the repair" is scoped to generated (ignored) roots, where a missing producer makes tsc read green over nothing. That warning does not reach this diff. Recording the trailing-slash caveat because the next reader of that gate will hit it too.3. No project references. No
*.jsonoutside the package namesqa/dogfoodin areferencesposition; every repo-wide hit is prose indocs/qa/platform-checklist/areas/*.jsonciting dogfood test files as evidence refs, which theincludeshape cannot move.4.
rootDiruntouched — the diff is one line,includeonly. Confirmed on the patch:- "include": ["src/**/*", "test/**/*"]/+ "include": ["test/**/*"].CI
Computed by latest run per check name, never by raw aggregation: 35 raw runs → 32 distinct names, 28 success, 4 skipped, 0 failure, 0 cancelled, 0 pending. The four skipped are
Check PR Size,Check Changeset,Console Pin Gate,Build Docs;Auto Label,Check PR SizeandCheck Changeseteach carry a duplicate pair across two workflow runs, and taking the newest per name is what keeps that from reading as a false red. Notably green here:Type Check · workspace,Type Check · debt ledger,Dogfood Regression Gate(all 3 shards),Dogfood Verify CLI.Declared narrowings — both accepted
The
pnpm lintnarrowing is measured on all three legs (population from eslint's own config, count from--format json, invariance from the repo's no-type-aware-linting property), not asserted. The skipped localtypecheckis accepted for the reason given:--showConfigproving the program byte-identical means running tsc twice cannot distinguish the trees — and CI ran it anyway, green.Out-of-scope finding
#11476 confirmed open, unassigned, labelled
finding, not queued. Its premise is verbatim onmaintoday:// No \rootDir`.sits two lines above"rootDir": "../../.."`. Declining to claim provenance from a 92-commit shallow clone was the right call — the two readings imply different fixes, and guessing would have written a wrong reason into the record.Landing via the merge queue. Verification will be by content on
origin/main, not by sha.
Generated by Claude Code
LANDED — verified by content on
origin/main, not by sha and not by the merge event.origin/main = d41d9904 packages/qa/dogfood/tsconfig.json: "include": ["test/**/*"], carried by: d41d9904 chore(qa): drop dead `src/**/*` include glob from dogfood tsconfig (#11474)packages/qa/dogfood/still lists exactlyCHANGELOG.md,README.md,package.json,test/,tsconfig.json,vitest.config.ts— nosrcarrived in the meantime.Disposition 3 now has an empty population
This card offered a third invariant ("an
includeroot that is neither tracked nor ignored names nothing") and honestly declined to argue for it, noting the population was one entry — this one. That is worth closing out with a measurement rather than leaving as an open temptation.Re-censused every
includeroot in all 87tsconfig*.jsononorigin/maind41d9904, classifying each root as tracked / gitignored / neither:class count include roots total 106 gitignored (the #10880 GENERATED_COVEREDclass)3 — next-env.d.ts,.next/types/**/*.ts,.next/dev/types/**/*.ts, allapps/docsneither tracked nor ignored (this card's class) 0 The gitignored column is the positive control, and it reproduces the ratchet's own verdict line (
generated layer: 3 include entr(ies) across 1 package(s)) exactly. So the reading in the second column is a real zero, not a broken instrument: after this merge the class is empty repo-wide, which is the strongest available argument for not building a third invariant — the guard would ship with nothing to guard.⚠️ Two instrument corrections behind that table, recorded because both are traps for the next reader:git check-ignoreneeds directory form. The rule isnode_modules/; a barenode_modulespath answers not ignored. My first positive control failed for this reason and the reading was discarded, not published. Roots must be probed as<path>/.- A naive JSONC comment-stripper eats tsconfig globs.
/\*.*?\*/matches inside".next/types/**/*.ts"— the/**opens and the*/closes — so 9 of 87 tsconfigs silently failed to parse,apps/docsamong them, and the first census reported0gitignored roots. Zero in the control column is what caught it. The census above uses a string-aware scanner and parses 87/87.
Nothing further is owed on this card.
pm:dispatchedremoved; the card was auto-closed by the merged PR.
Generated by Claude Code
- added a commit that references this issue
on Aug 25, 2026 - added a commit that references this issue
on Sep 1, 2026
What
packages/qa/dogfood/tsconfig.jsondeclares:The package has no
srcdirectory. Its whole tree isCHANGELOG.md,README.md,package.json,test/,tsconfig.json,vitest.config.ts— measured onorigin/main@9faa9bc51d:Impact, stated honestly: low
Nothing is broken today.
test/**/*matches real files, so tsc has inputs andtypecheck(tsc --noEmit) behaves correctly; a non-matchingincludeglob is simply dropped. This is a dead config entry, not a coverage hole — worth recording, not worth interrupting anyone for.Why it is worth a line anyway
It is the neighbouring class to #10880 (
GENERATED_COVERED, PR #10896), and the two are worth keeping distinct rather than merged:check:type-check-coveragehas no invariant for a tsconfigincludethat names a GENERATED directory the package'stypecheckscript never generates #10880's class — anincluderoot that is gitignored, i.e. deliberately produced by something. Its absence makes tsc read green over files that were meant to be in the program. That is now guarded.includeroot that is neither checked in nor generated. It simply names nothing, in either direction.I deliberately did not widen the new invariant to cover it while implementing #10880. The detector there is "is this path gitignored", which cleanly separates "generated by design" from "names nothing"; folding this in would have meant flagging a dead glob with a message telling the author to declare a generator for it, which is the wrong remedy. It was the only instance the census turned up: of 101
includeroots across the workspace, 3 are gitignored (all inapps/docs) and exactly 1 is a non-ignored root that does not exist — this one.Possible dispositions, for triage rather than as a recommendation
"src/**/*"from the array — correct if the package is test-only by design.src/is expected to arrive.check-type-check-coverage.mjs("anincluderoot that is neither tracked nor ignored names nothing"), with the caveat that its population is currently one entry and its impact is cosmetic — the four-axis case for spending a guard on it is not obviously positive, and I am not making it here.Found while implementing #10880; deliberately kept out of PR #10896, whose diff is one file (
scripts/check-type-check-coverage.mjs). Unassigned, and not queued.