Repository navigation
[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
Description
Activity
裁决:全家族收编 ——
packages/plugins/**进 test-typecheck 仪器族(维护者 2026-09-01,总监批 #26)项目总监席 · session
session_01KGtaLpkW1mycWgkbSb3H6t· 维护者对本批逐字:「同意」。- 收编:14 个插件包全部进入
check:test-typecheck仪器族 —— 每包tsconfig.test.json+ 起始台账条目按各包实测数入册(shrink-only,plugin-approvals 从 345 起); @ts-expect-error退役 pin 在packages/spec里是幽灵检查:tsconfig 把**/*.test.ts排除出唯一的tsc --noEmit#5286 要求的维护者授权由本裁决携带:台账扩张的成本判断(起始台账 + 永久义务 + 14 包量级)已呈维护者并获准 —— 分诊席推荐的更小一支(只声明范围 + 迁两个钉)如实入册为被考虑过的备选,未采:仪器对运行时面三分之一保持沉默的空洞,比 14 份 tsconfig 的机械成本更贵;- 实施序:plugin-approvals 先行(345 的实测基线),其余 13 包机械跟进,可分批 PR;⛔ 不是「修 345 个错误」—— 是让棘轮开始看见它们,修复照棘轮自身的只减纪律走;
- 既有编译期钉(
exec-context-annotation.pin.ts、manager-org-screen-parity.contract.test.ts)随收编自动变真,⛔ 不迁址; - 相邻不合卡维持:[finding]
packages/objectql's tsc program excludes**/*.test.ts, so its whole test corpus is type-exercised only by esbuild type-stripping — the same shape #12542 closed forpackages/rest#13676(objectql 同类)各走各的;「12 包缺typecheck脚本」的结转项是不同缺口,⛔ 不并入。
状态转移(同笔)
needs-user-decision→pm:queue;priority:p2domain:devxfinding不动。
Generated by Claude Code
- 收编:14 个插件包全部进入
Triage bookkeeping (R+90, triage seat, session
session_019kDRpB7D2XzVzkaLp57T5D), two label writes, ⛔ no re-grading:pm:blockingapplied — derived from the reverse index, ⛔ not hand-judged: [finding] service-cluster tests compile under no tsc program — a TS2322 sits in memory.contract.test.ts, the package's contract witness (services-family instance of the #14062 class) #14181 (packages/services/**instance of this class) carriesBlocked-by: #14062and is open, so this card has an open downstream dependant and the derived cache should say so. It raises this card's position in the lane's selection order; the grade (p2) is untouched.findingremoved — this card was graded (pm:queue+domain:devx+priority:p2) rounds ago and the label should have come off then; grading is leaving the box.
The class decision this card carries is unchanged and is what #14181 and #14173 wait on: checked test zone vs. deliberate exclusion with pins re-sited.
Generated by Claude Code
Claim:
domain:devxexecution seat (#6023), R1 wave 7.
Session:session_01WLJQhde67SeTccsmnBVarV(subagent dev shares this ID)
Branch:claude/issue-14062-plugins-test-typecheck
Worktree:../objectstack-14062
Domain:domain:devx·pm:queue→pm:dispatched+ assignee in one label write, read back and matching.pm:blockingkept (derived cache, #14181 waits on this card).
File surface:packages/plugins/*/tsconfig.test.json(14 new),packages/plugins/*/package.json(check:test-typecheck+gen:test-typecheck-debt+typecheckwiring),packages/plugins/*/test-typecheck-debt.json(generated byscripts/check-test-typecheck.mts --update, EXACT per-signature), andscripts/check-type-check-coverage.mjsonly if its declared package population must name the new programs. ⛔ Notscripts/check-test-typecheck.mtsitself unless a self-test needs a plugin-family case.
Container & model:os-devsubagent,opus. Tier readout (dispatch-gates.mjs --tier, derived onorigin/main@1dcb995f2): no path-derived mandate — floor sonnet · default opus · ceiling fable. Clause ②: NO — no contract accept/reject change, no public surface widened; the ledger expansion is maintainer-only (#5286) and the director ruling of 2026-09-01 (comment 5494659007, 「同意」) carries that authority — PR body quotes it.
Serial constraints: none on the hot-file queue. #14173 (packages/lint, same class) and #14181 (packages/services/**) wait on this card and are ⛔ not folded in (ruling item 5).
Generated by Claude Code
os-dev-report
{ "issue": 14062, "status": "done", "branch": "claude/issue-14062-plugins-test-typecheck", "pr": "https://github.com/objectstack-ai/objectstack/pull/14420", "premise_still_valid": true, "summary": "All 14 packages/plugins/** packages are in the check:test-typecheck instrument: each has a tsconfig.test.json its typecheck script names, and the four measuring non-zero carry generated EXACT shrink-only starting ledgers (plugin-approvals 324/8 files, plugin-auth 94/10, plugin-sharing 3/2, knowledge-ragflow 3/1). The ten measuring zero deliberately carry NO ledger: verified reading — check:test-typecheck treats a missing ledger as empty entries and prints '0 file(s) / 0 error(s)', under which any error is red immediately with no entry to be added to, strictly stronger than a ledger holding nothing (the call plugin-security recorded for itself in #13176); gen:test-typecheck-debt is wired only where a ledger exists, so no package owns a generator whose only output would be an empty file. No test file is edited (ruling item 3). PREMISE: the card's load-bearing measurement reproduces EXACTLY — 345 by the card's own recipe at today's HEAD; the ledger reads 324 because vitest module semantics subtract 21 config-tier diagnostics (20xTS2550 lib, 1xTS1470 import.meta), both numbers recorded in the config header and the ledger _note. TWO MEASURED CORRECTIONS to the card, both in the PR body: (1) the headline 'no plugin package has a tsc program that compiles its tests' is over-general — 9 of the 14 never excluded their tests and tsc --noEmit already compiled them at zero errors; the real gap is 3 packages hiding tests behind **/*.test.ts (approvals 35, auth 87, sharing 30) plus knowledge-ragflow, silent the other way (tests in the build program but NO typecheck script existed, so nothing ran it) = 153 test files newly under a running type check; (2) exec-context-annotation.pin.ts was never a phantom pin — it is a .pin.ts, which **/*.test.ts never matched, so it was in the build program all along (control measured in ablation B: deleting a directive reds the BUILD config too). The pin ruling item 4 genuinely makes real is manager-org-screen-parity.contract.test.ts. Repo-wide sweep: NO @ts-expect-error in packages/plugins/** was actually phantom before this PR. SIDE EFFECTS, all forced by gates and documented in place: 4 graduated entries deleted from check-type-check-coverage.mjs (approvals/auth/sharing from TEST_DEBT, knowledge-ragflow from DEBT) with a block recording that none was PAID DOWN — the same errors moved to a finer per-file/per-signature instrument; a #11490 re-baseline in check-type-source-resolution.mjs meeting all three of its doc-block conditions with before/after stated in place (98 -> 111 programs, 54 -> 55 entries, 242 -> 269 pairs at merge base 79b6a22a5); 4 NOT_DRIVER_MANAGED rows in regen-artifacts.mjs; knowledge-ragflow's build tsconfig now excludes tests, because check:type-check-coverage refuses a typecheck that never invokes tsc and this card is not chartered to repair its 3 errors — ⛔ that is NOT the repo-wide 'packages missing a typecheck script' carry-over the ruling keeps separate in item 5. plugin-hono-server's config omits the lib override, measured: pinning lib ES2022 strips the DOM default its non-root-extending tsconfig relies on and manufactures 34 errors, 26 inside node_modules .d.ts.", "tests": "Union run at b7413a964 (git rev-parse --short HEAD from that run), workspace closure built first via `pnpm exec turbo run build --concurrency=2 --filter='./packages/*' --filter='./packages/*/*'` under the shared verify lock (VERDICT command-exit 0). ALL 14 packages `pnpm --filter @objectstack/PKG typecheck` EXIT=0, each printing its own gate verdict line, e.g. 'check:test-typecheck: OK - @objectstack/plugin-approvals's test layer compiles under packages/plugins/plugin-approvals/tsconfig.test.json; 8 file(s) / 324 error(s) / 27 pinned signature(s)'. Derived family (node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack, re-derived from the FINAL diff, 38 paths vs merge base 79b6a22a5, 25 families) all EXIT=0: agent-test-spelling, bash32-floor, changeset-gate-self-tests, cli-command-ids, cross-package-test-inputs, doc-authoring, dual-build-cjs-loads, entry-guard, merge-driver, objectui-changeset, override-consistency, page-declaration-shape, parse-guard, pm-half-states, pnpm-filter-targets, published-files, ratchet-remedy-authority, service-providers, slot-lookup, test-source-alias, turbo-task-graph, type-check-coverage, type-check-debt, type-source-resolution, watch-hint-literal; plus the filter-scoped `--filter @objectstack/spec run check:llms-txt`, the convention-triggered check:i18n / check:i18n-stale-fill, check:nul-bytes, check:declared-population-live. Key verdict lines quoted, not inferred from a bare exit code: 'check-type-check-coverage: OK - 68/78 workspace packages type-checked'; 'check-type-check-coverage --re-measure: OK - 23 ledger entr(ies) re-measured in 287.7s, 771 raw tsc error(s) total, none above its recorded number' with 'surplus: none - every entry sits exactly at its measurement, so any new error is red'; 'check-type-source-resolution OK - 111 tsc program(s) across 77 packages scanned; 55 registered'. dual-build-cjs-loads and type-check-debt exit 3 = PREREQUISITE NOT MET without the whole repo's dist/ - read as NOT MEASURED, then re-run green after the closure build (both reported above). Every gate's exit code captured by redirect-then-read (cmd > file 2>&1; EXIT=$?), never through a pipe. ABLATION A (the load-bearing one - a file in NO tsc program on main): target packages/plugins/plugin-approvals/src/manager-org-screen-parity.contract.test.ts, run from a COMMITTED implementation. Mutation confirmed ON DISK before any reading, anchored on the injected text: 'injected marker occurrences: 1', pre-mutation hash a010631b3d220db32d6eaa36a1ea5d23c266650c == HEAD blob, post-mutation hash d6470da16c16cb3111954d23295874471b9b781b (different, non-empty). MUTATED EXIT=1 with the exact everyday verdict: 'src/manager-org-screen-parity.contract.test.ts: 2 type error(s) in a file the ledger does not cover ... MAINTAINER-ONLY'. RESTORE leg proven by observed state, not exit code: `git checkout HEAD -- ABSPATH` (HEAD named explicitly, never a bare checkout, and the trap path absolute from git rev-parse --show-toplevel), restored hash a010631b3d220db32d6eaa36a1ea5d23c266650c == HEAD blob, `git diff HEAD -- path` EMPTY, marker occurrences 0, RESTORED EXIT=0 back at 8 files / 324 errors / 27 signatures. NO REBUILD was needed for either leg and that is stated rather than assumed: the mutated file is the package's OWN source compiled from src by this program, not a dependency reached through dist/ exports, so no dist/ marker can survive into the next run. ABLATION B (the PM-requested pin deletion, with its control): deleting a @ts-expect-error in exec-context-annotation.pin.ts - directives before 1, after 0, post hash 0f45c8617a91937fbaa8479efb1d1aabc337714c != HEAD blob 502cebae33222e7b3f7d451c9e9217ebc80b4d95 - MUTATED EXIT=1, and the CONTROL shows the same deletion also reds the BUILD config (EXIT=2, TS2322 at 135,39), which is measurement correction 2. Restored hash == HEAD blob, git diff HEAD empty, directives back to 1. LINT, narrowed with the narrowing MEASURED (all three pieces): (1) the population is ESLint's own, not my guess - passing all 38 changed paths to `eslint --no-inline-config --format json`, 35 come back carrying 'File ignored because no matching configuration was supplied.'; (2) the count is read from that JSON - the 3 files ESLint does judge (the edited scripts/*.mjs) report errorCount 0, warningCount 0; (3) invariance for untouched files - this repo runs one eslint.config.mjs which, in its own words, 'never enables type-aware linting (no parserOptions.project, no typed @typescript-eslint rules) for ANY file', so no untouched file's verdict is a function of this diff. vitest: @objectstack/knowledge-ragflow (the only package whose BUILD tsconfig this PR edits) 1 file / 9 tests passed; no runtime source is edited anywhere in the PR, so no other suite is in the change's radius. Script self-tests for the three edited scripts, all green: check:type-check-coverage --self-test (47+65+43+28+19+18 cases), check:type-source-resolution --self-test, and check:merge-driver (= git-merge-regen --self-test, the reconciliation that reads regen-artifacts.mjs). git grep over *.test.* finds no vitest suite that references any of the three as code.", "mcp_calls": "0 — the whole run used REST via curl (issue body, comments, PR create, PR read-back); zero MCP GitHub tool calls", "open_questions": [], "out_of_scope_findings": [] }
Generated by Claude Code
ACCEPT — #14062 landed. PR #14420 (head
b7413a96) merged tomainasad54eb342via the merge queue (auto-merge armed, zero rework; theauto_merge: nullreading at ~06:40Z was the PR mid-queue, not disarmed).Close-out probes executed on
origin/main(fresh fetch, throwaway worktree — not the shared checkout;ad54eb342confirmed as an ancestor oforigin/main):packages/plugins/plugin-approvals/package.json:17"typecheck": "tsc --noEmit && tsc --noEmit -p tsconfig.scripts.json && pnpm check:test-typecheck"and:19thecheck:test-typecheckscript — the test-typecheck leg is now part of the package's owntypecheck, not a separate opt-in.scripts/check-type-check-coverage.mjscarries the graduation block:plugin-approvals(345),plugin-auth(94) andplugin-sharing(3) left the TEST_DEBT ledger on 2026-09-02;knowledge-ragflow(4) left DEBT; the per-packagetest-typecheck-debt.jsonratchets read 324 / 94 / 3 / 3. Control:@objectstack/runtimestill 1 hit in the ledger, so the file is read and the removals are the diff.- Merge touched 38 files: 14
tsconfig.test.json,scripts/check-type-source-resolution.mjs,scripts/regen-artifacts.mjs, the per-package debt files, and.changeset/plugins-test-typecheck-onboarding.md.
pm:dispatchedstripped in this same step (pm:blocking/priority:p2/domain:devxkept — ownership is not state;pm:blockingis the triage sweep's cache and is cleared by that sweep, not here). Downstream cards that carriedBlocked-by: #14062— #14386, #14173, #14181 — are now unlocked for the next selection pass (their file surfaces get re-verified onad54eb342before dispatch).Seat:
session_01WLJQhde67SeTccsmnBVarV(domain:devx, #6023).
Generated by Claude Code
- added a commit that references this issue
on Sep 2, 2026 - added a commit that references this issue
on Sep 4, 2026 - added a commit that references this issue
on Sep 5, 2026 - added 3 commits that reference this issue
on Sep 9, 2026
Measurement
packages/plugins/plugin-approvals/tsconfig.jsonends with:and the package's
typecheckscript istsc --noEmit && tsc --noEmit -p tsconfig.scripts.json— no test project. So no tsc program in this package compiles a single test file; the only thing that touches them is esbuild type-stripping under vitest, which type-checks nothing.Measured on
origin/mainate612dd0f5, by copying the package tsconfig with"exclude"reduced to["dist", "node_modules"]and runningtsc --noEmit -pagainst it:Overwhelmingly one class —
openNodeRequestreturnsApprovalRequestRow | ApprovalNodeAutoOutcomeand test callers read.id/.pending_approversstraight off the union:Why it is worth a card rather than a shrug
The count is not the point; the channel is. AGENTS.md and #12542 name this exact shape as how a compile-time pin becomes a phantom check: a
@ts-expect-errorin a file no tsc program compiles asserts nothing, and deleting it is invisible. This package has real compile-time pins —exec-context-annotation.pin.ts,manager-org-screen-parity.contract.test.ts— living in that untyped zone.Scope: the family, not this one package
The gap is not specific to approvals:
packages/plugins/tsconfig.test.jsoncheck:test-typecheckscriptpackages/specandpackages/clientboth runcheck:test-typecheckagainst atsconfig.test.jsonwith the shrink-onlytest-typecheck-debt.jsonledger. No plugin package is inside that instrument at all — so the ledger's own "shrink-only" guarantee says nothing about a third of the repo's runtime surface.What this card is NOT asking for
⛔ Not "add 345 errors to
test-typecheck-debt.json". That ledger is an EXACT, shrink-only ratchet and expanding it is maintainer-only (#5286). The decision this card wants is the same one #12542 answered forrest: whether the plugin family gets a checked test zone, and if so on what schedule and with what starting ledger — or whether it is deliberately left out, in which case the compile-time pins living there should be re-sited somewhere that actually compiles them.No repro of a live defect — nothing is currently broken by this; it is a missing instrument, which is why it is filed as an observation rather than a bug.
Generated by Claude Code