Repository navigation
Description
Found while implementing #13935 (packages/lint field-rule root vocabulary). Out of that card's scope — recorded, not fixed.
Same class as #14062 (packages/plugins/**), #13676 (packages/objectql) and #12542 (packages/rest, closed). This instance is packages/lint, which no card names yet — and it is the package whose job is hosting the platform's static-analysis rules.
Measurement
packages/lint/tsconfig.json:
{
"extends": "../../tsconfig.json",
"compilerOptions": { "outDir": "./dist", "rootDir": "./src", "types": ["node"] },
"include": ["src/**/*"],
"exclude": ["node_modules", "dist", "**/*.spec.ts", "**/*.test.ts"]
}The package's typecheck script is a bare tsc --noEmit, there is no sibling tsconfig.test.json, and packages/lint carries no test-typecheck-debt.json — the four packages wired to scripts/check-test-typecheck.mts are client, objectql, rest, spec.
Verified with --listFiles on this checkout rather than inferred from the config:
npx tsc --noEmit --listFiles | grep -c 'validate-expressions.test.ts' -> 0
npx tsc --noEmit --listFiles | grep -c 'validate-expressions.ts' -> 1
So pnpm --filter @objectstack/lint typecheck renders a green verdict having read the implementation and none of its tests.
Why this instance is worth naming separately
The count is not the point; what is sitting in the untyped zone is. packages/lint/src/validate-expressions.test.ts alone is roughly 2,700 lines and is built almost entirely out of compile-time and meta pins — the #5017 receiver scan that reads the rule's own source text, the TRACKED_UNDECLARED_READS shrink-only list, the residual-root table generated from the real baseline, the FieldSchema.shape key cross-checks. AGENTS.md names this exact shape as how a pin becomes a phantom check: an assertion in a file no tsc program compiles asserts nothing about types, and weakening it is invisible to every gate.
It also has a second-order effect the sibling cards do not: this package's rules are consumed by scripts/check-doc-formula-expressions.mjs and by os validate, so a pin that quietly stops meaning what it says takes a published diagnostic surface with it.
Not proposing the remedy
Two routes exist in-repo and choosing between them is a maintainer/triage call, not this finding's: the packages/spec pattern (a sibling tsconfig.test.json named in the typecheck script) or onboarding to scripts/check-test-typecheck.mts with a measured shrink-only ledger. Onboarding by wiring, never by copying, per AGENTS.md. ⛔ I am not proposing a severity.
Provenance
Measured in /home/user/objectstack-issue-13935 at origin/main base 2bff79ae3, during #13935.
Generated by Claude Code
Activity
huangyiirene commentedon Sep 2, 2026
Triage (R+89, triage seat, session
session_019kDRpB7D2XzVzkaLp57T5D): graded →pm:queue·priority:p3·domain:devx(re-routed from the filer'sdomain:engine) · type Task.findingremoved.Lands in:
packages/lint/tsconfig*.json+ itstypecheckscript — the package's own build/typecheck plumbing, which the lane table routes to devx (packages/lint), and which is the same remedy surface as the class card #14062 (domain:devx). Rationale for the re-route: the defect is "no tsc program compiles the tests", not anything in the rules' semantics; the anchoring rule reads the fix's landing file, not the package's subject. Ruled route: onboard by wiring to whichever of the two in-repo routes #14062 lands on (siblingtsconfig.test.jsonnamed intypecheck, or thescripts/check-test-typecheck.mtsledger with a measured shrink-only baseline) — ⛔ do not pick independently; if #14062 has not landed when this is dispatched, follow thepackages/specpattern, which is the one already in service. p3 because vitest still runs and passes these tests; the untyped zone is a phantom-pin risk, not a live wrong verdict.Family: #14062 (plugins), #14181 (service-cluster) — same class; the devx seat answers fold-or-serial once for the family.
Size/model suggestion: S mechanical,
sonnet/opus; the deliverable is the--listFilescount forvalidate-expressions.test.tsgoing 0 → 1 and the resulting error ledger (if any) recorded, never suppressed.Generated by Claude Code
claude commentedon Sep 2, 2026
Claim: session
session_01WLJQhde67SeTccsmnBVarV(domain:devx execution seat, seat post #6023) — R1 wave 7.claude/issue-14173-lint-test-typecheck../objectstack-14173(dedicated per-task worktree, offorigin/main)domain:devx(packages/lintbuild/typecheck plumbing; same remedy surface as the landed class card [finding] No plugin package has a tsc program that compiles its tests — plugin-approvals alone hides 345 type errors, and 0 of 14 are in the test-typecheck ledger #14062)ad54eb342) on thescripts/check-test-typecheck.mtsinstrument — per package atsconfig.test.jsonNAMED by thetypecheckscript, acheck:test-typecheck+gen:test-typecheck-debtscript pair, and a per-packagetest-typecheck-debt.jsonshrink-only ledger.packages/plugins/plugin-auth/package.json:24–26onorigin/main6aea1f559is the shape to wire to (never copy the ledger numbers — measure them).packages/lint/tsconfig.test.json(new),packages/lint/package.json(scriptsblock only:typecheck+ the two new script lines),packages/lint/test-typecheck-debt.json(new, generated bygen:test-typecheck-debt),scripts/check-type-check-coverage.mjstwo regions only — the'@objectstack/lint'TEST_DEBT entry (:1039,errors: 16) is deleted and the#14062graduation docblock (:911–) gains lint's line, mirroring what feat(tooling): onboard packages/plugins/** into check:test-typecheck (#14062) #14420 did forplugin-approvals/plugin-auth/plugin-sharing— and one.changeset/*.md(@objectstack/lint: patch). ⛔ No edits topackages/lint/src/**(test errors the new program surfaces are LEDGERED, never fixed here — the triage: "recorded, never suppressed"); ⛔ no otherscripts/**file.scripts/check-type-check-coverage.mjsatisUncheckedSourceCandidate/uncheckedByDir(:1585–:1668) and the--self-testtables (:3700+) — region-disjoint from this card's ledger entry + docblock, so the two run in parallel; whichever lands second mergesorigin/mainbefore reporting. PR fix(lint): resolve dotted dashboard filter fields on the object graph and drop the SYSTEM_FIELDS union #14437 ([finding]dashboard-filter-field-unknownstill skips every dotted filter field and resolves against the flatSYSTEM_FIELDSunion — the seam next to it now answers both #14275, this seat, CI running) editspackages/lint/src/validate-widget-bindings.test.tsandsystem-fields-consumers.test.ts— disjoint from this surface, but the measured ledger must be taken AFTER a finalgit merge origin/mainso the count reflects whatever of fix(lint): resolve dotted dashboard filter fields on the object graph and drop the SYSTEM_FIELDS union #14437 has landed. 144 of 154 scripts/** self-tests exit 0 when an early return leaves them before their verdict — 137 printing nothing at all #13798 batch 1 (cloud dev) excludes both files by its dispatch order.Generated by Claude Code
fix(lint): wire test layer into check:test-typecheck, so its 2,700-li…
claude commentedon Sep 2, 2026
os-dev-report
{ "issue": 14173, "status": "done", "branch": "claude/issue-14173-lint-test-typecheck", "pr": "https://github.com/objectstack-ai/objectstack/pull/14494", "premise_still_valid": true, "summary": "Wired packages/lint's test layer into scripts/check-test-typecheck.mts per the triage ruling (comment 5502888897), following the #14062/PR #14420 shape (a sibling tsconfig.test.json named by typecheck, plus check:test-typecheck + gen:test-typecheck-debt scripts). Measured 6 residual TS6059 errors over 2 files (rootDir violations importing examples/app-showcase fixtures, pre-existing, config-tier) against the coverage gate's existing 16-error @objectstack/lint TEST_DEBT entry, well within the <=16 authority boundary, so this is a legitimate conversion. The TEST_DEBT entry was deleted and the #14062 graduation docblock in scripts/check-type-check-coverage.mjs gained lint's line. No packages/lint/src/** files were edited.", "tests": "Baseline (origin/main 6aea1f559, deps built): --listFiles validate-expressions.test.ts=0, validate-expressions.ts=1; pnpm typecheck clean (0 tsc errors, tests unread). New tsconfig.test.json (esnext/bundler/ES2022, rootDir+strictness inherited): errors under BUILD semantics (NodeNext, tests included)=22 (11 TS7006 + 5 TS2835 + 6 TS6059); errors under THIS config=6 (6 TS6059 only) -- the 16 TS7006/TS2835 dissolve under bundler resolution, matching the spec/rest/plugin family's config-tier effect; the 6 TS6059 are pre-existing rootDir violations the coverage gate's own prior note already excluded from the original 16. Authority check: measured 6 <= recorded 16, within bounds -- proceeded per Zone 2 item 3. check:test-typecheck: red before ledger (2 unledgered files, self-test 11 cases pass), gen:test-typecheck-debt -> 2 files/6 errors/2 signatures, authored _note, green after (verified verbatim-preserved on regen). check:type-check-coverage: GREEN post-edit (68/78 packages, no lint exception). I attempted to directly capture the coverage gate's RED state (TEST_DEBT entry restored via git checkout HEAD -- / git apply round-trip on top of the already-wired typecheck, nothing left uncommitted) but three consecutive attempts hit os-verify-lock queue-timeout (one holder alone held the lock 12m50s on an unrelated pnpm check:pm-dispatch-gates run) without ever acquiring the lock; recorded as NOT MEASURED for that one specific reading rather than fabricated -- the RECONCILED rule text and the final GREEN state stand as the evidence instead. check:type-source-resolution: GREEN, no re-baseline needed (112 programs/77 packages/55 entries, unchanged -- lint's test files import only @objectstack/formula and @objectstack/spec, both already reached by the existing entry). Merged origin/main twice (once mid-task at 416a53b34 picking up PR #14437's edits to packages/lint/src/validate-widget-bindings.test.ts and validate-functional-completeness.test.ts, once more right before opening the PR at 0a2b43d11 picking up a rewrite of scripts/pm/dispatch-gates.mjs itself) -- both times rebuilt deps, re-ran gen:test-typecheck-debt and typecheck, and the ledger re-generated byte-identical (2 files/6 errors/2 signatures) both times. Final `node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --ran RUN_RECORD_PATH` at 0a2b43d11 (no staleness warning): 46 derived, 46 run, 0 NOT-MEASURED, 0 UNRUN. Of the 46: 43 pass green; 3 exit 3 PREREQUISITE NOT MET (documented, not red) -- check:dual-build-cjs-loads and check:type-check-debt --re-measure (both need a full `pnpm build` workspace closure this task never ran) and check:test-completeness (needs a CI-produced turbo test log). Additionally ran (scripts/** touched): check:ratchet-remedy-authority (green, 183 scripts swept), check:declared-population-live (green, 157/201 families), check-self-test-wired.mjs (green, 163/163), check-self-test-workflow-commands.mjs (green), check-type-check-coverage.mjs --self-test (green, 47+65+43+28+19+18 cases). check:pm-dispatch-gates itself: green (self-test 1232 cases pass), run via a detached background process with its own 2400s timeout since it exceeds the foreground command cap. node scripts/check-nul-bytes.mjs: OK, 7919 files, no raw control bytes. All exit codes captured before any pipe (redirect-then-$?), quoting each gate's own printed verdict line, never bare $?.", "mcp_calls": 0, "open_questions": [], "out_of_scope_findings": [] }Generated by Claude Code
Generated by Claude Code
claude commentedon Sep 2, 2026
ACCEPT — #14173 landed. PR #14494 merged to
mainasfa7292c43via the merge queue (draft flipped + auto-merge armed 10:08Z,added_to_merge_queue10:08:29Z).Close-out probes executed on
origin/main(fresh fetch, throwaway worktree — not the shared checkout;origin/mainat447eee738,merge-base --is-ancestor fa7292c43 origin/mainconfirms):git show origin/main:packages/lint/test-typecheck-debt.json→ the ledger exists: generated_comment, authored_note(the CONVERSION argument: the coverage gate's 16-error@objectstack/lintTEST_DEBT entry is the authority, measured 6 TS6059 ≤ 16, the 6 explicitly excluded from the original 16 by that entry's own note),entries= 2 files ×TS6059× 3.git grep -n "gen:test-typecheck-debt\|check:test-typecheck" origin/main -- packages/lint/package.json→:36check:test-typecheck(--self-test && … --package packages/lint --project tsconfig.test.json),:37gen:test-typecheck-debt(--update …),:35typecheckchainspnpm check:test-typecheck.scripts/regen-artifacts.mjscarries the one new row:path: 'packages/lint/test-typecheck-debt.json',gen: 'gen:test-typecheck-debt',owner: '@objectstack/lint'(:533-537, shrink-only rationale mirrored from the plugin family).packages/plugins/**ledger rows from [finding] No plugin package has a tsc program that compiles its tests — plugin-approvals alone hides 345 type errors, and 0 of 14 are in the test-typecheck ledger #14062 read at:486-518(unchanged).Unlocks (serial queue): lint cards #14394 / #14288 / #14268 and the
check-type-*half of #13798 batch 2 — dispatched off mergedmainfrom here on.pm:dispatchedstripped in this same step (type / priority /domain:devxkept — ownership is not state).Seat:
session_01WLJQhde67SeTccsmnBVarV(domain:devx, #6023).Generated by Claude Code