Repository navigation
tooling(services): service-knowledge has no typecheck script — its test layer is compiled by no tsc program (#14062 family, sibling of #14181) #15049
Description
Activity
- added a commit that references this issue
on Sep 4, 2026 os-dev-report
{ "issue": 15049, "status": "done", "branch": "claude/issue-15049-service-knowledge-typecheck", "pr": "https://github.com/objectstack-ai/objectstack/pull/15147", "premise_still_valid": true, "summary": "Gave service-knowledge the #14062 checked-test-zone shape (tsconfig.test.json + typecheck/check:test-typecheck scripts), copied from service-cluster (PR #15032) since its build tsconfig.json does not exclude tests. Measured BEFORE any fix: undivided (tsc -p tsconfig.json) = 10 errors, matching the deleted DEBT entry exactly (3 TS2835 config-tier + 4 TS7006 noise + 3 code-tier); the correct split (tsc -p tsconfig.test.json) = 4, not the ledger's 3-code-tier guess -- fixing the 3 TS2835 removed the any-cascade and re-enabled an excess-property check it had been suppressing, uncovering a 4th real error (a stale roles field the spec renamed to positions). Fixed all 4 code-tier defects (2 under-typed vi.fn() IDataEngine.find mocks, 1 stale field rename) plus the 3 missing .js extensions, all inside the test files only -- src/ (excluding tests) is byte-identical. Both readings are 0 after. DEBT entry deleted (graduated, not lowered); check:type-source-resolution's onboarding-limb registry gained an entry for the 3 workspace deps now reached only through tsconfig.test.json (paths measured and rejected: 0 -> 487 TS6059, all in other packages' source).", "tests": "pnpm --filter @objectstack/service-knowledge typecheck -- exit 0 (tsc --noEmit clean; check:test-typecheck: 0 file(s)/0 error(s)/0 pinned). pnpm --filter @objectstack/service-knowledge test -- 4 files / 40 tests passed. node scripts/check-type-check-coverage.mjs -- OK, 73/79 packages typechecked (was 72), 6 in DEBT (was 7, 107 frozen raw errors, down from 117), self-test OK. node scripts/check-type-source-resolution.mjs -- OK, 120 programs / 78 packages scanned, 59 registered (before 58/119/290 pairs/20 clean, after 59/120/293 pairs/19 clean -- +1 pkg/+1 program/+3 pairs, exactly the onboarding entry), self-test OK. Full derivation via node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commands on rebased head 2969cef816: 73 gate commands run (64 derived + 9 roster-silent families whose roster sits under a path this diff touches), 70 exit 0, 2 exit 3 NOT MEASURED (check:dual-build-cjs-loads, check:type-check-debt -- both quote their own 'PREREQUISITE NOT MET: some package has no dist/' text and do not mention service-knowledge), 1 exit 1 (check:published-readme-exports) that is substantively the same class -- its 84 findings are all OTHER unbuilt workspace packages' READMEs; it named service-knowledge twice before I built this package's own dist (pnpm --filter @objectstack/service-knowledge build), 0 after, confirmed by rebuild+rerun. 0 red. Exit codes captured redirect-then-read throughout, never across a pipe.", "mcp_calls": 7, "open_questions": [], "out_of_scope_findings": [] }
Generated by Claude Code
ACCEPT — PR #15147, head
2969cef816. Reviewed by thedomain:servicesseat as reviewer of record (session_01AUF1NoViznQK32gqpK8wS8).Everything below was verified against the diff on the tree, not read off the dev's report. Where I am relying on the dev's measurement rather than my own, I say so.
The card's criteria, checked
# Criterion Verdict ① Both error counts reported (undivided and split) ✅ undivided 10→0, split 4→0 ② DEBT entry deleted in the same PR ✅ deleted, not lowered ③ test-typecheck-debt.jsonnot grown✅ absent from the diff entirely ④ No @ts-expect-error/ narrowed program / loosened strictness✅ zero hits ⑤ check:type-source-resolutionvia the onboarding re-baseline limb, notpaths✅ registry entry, gate not weakened ⑥ packages/specuntouched (single-owner lane)✅ read-only Grepped the added lines for
ts-expect-error,ts-ignore,ts-nocheck,"strict",skipLibCheck,"paths",.skip(,.todo(— none found.tsconfig.jsonuntouched, non-testsrc/**untouched,content/docs/releases/**untouched.What raises this above a clean mechanical onboarding
The split contradicted the ledger and the dev said so. The DEBT entry's note guessed 3 code-tier errors; the split read 4. Fixing the 3 TS2835 removed the
anycascade, which re-enabled a TypeScript excess-property check the cascade had been silently suppressing, exposing a 4th real defect the undivided reading could not see. That is precisely the "a tier split read off an unrepaired config is a guess about what is UNDER it" lessoncheck-type-check-coverage.mjsalready records formetadataandservice-storage— applied to its own card rather than quoted.The gate change is a re-baseline, not a weakening. I read
scripts/check-type-source-resolution.mjsspecifically to check this, because "handle the red gate" and "silence the red gate" produce similar-looking diffs. It adds one entry toKNOWN_DIST_RESOLVED_TYPE_IMPORTS. Its provenance table varies only what thetypecheckscript names, on one checkout:- names
tsconfig.jsononly → absent, 119 programs / 290 pairs - names
tsconfig.test.json→ present, 120 / 293
Row 2 is the load-bearing one: the build program carries no dist-resolved workspace type import at all, so the exposure is not merely first seen through the onboarded program, it is only reachable through it. There is no pre-existing program a dep could have been laundered through.
pathswas measured and rejected at 0 → 487 TS6059, every one in another package's source.The test fixes tighten.
roles→positions(the spec renamed the field;ExecutionContextitself was correct and left alone), and twovi.fn()mocks given parameter types matching the call sites they stand in for. The clearest signal is a deletion:expect((find.mock.calls[0][1] as { context: … }).context.isSystem)becameexpect(find.mock.calls[0][1].context.isSystem). The fix removed a cast. A loosening fix adds them. Zero assertions were weakened.Changeset carries real frontmatter (
patch), so it is not the empty kind that stalls a release silently and greenly.Relied on the dev's measurement, not independently reproduced
The gate sweep (73 commands, 70 exit 0) and the ledger arithmetic. The arithmetic is at least internally consistent: frozen raw errors 117 → 107 is exactly the deleted entry's 10, and DEBT packages 7 → 6.
⚠️ Also taken from the dev rather than re-derived: that the three exit-3 / exit-1 gates are NOT MEASURED in substance. exit 3 = prerequisite unmet, which is neither a pass nor a finding — andcheck:published-readme-exports's exit 1 is a real finding code, so it deserves the sharper statement: its 84 findings are other unbuilt packages' READMEs, and the dev showed the 2 naming this package disappear after building this package's own dist. That is a prerequisite wearing a finding's exit code, not a pass.Landing
CI is still running at review time — the four
Type Check · …jobs and severalTest Coreshards arein_progress, 0 failures so far. ⛔ Not arming until those report: this PR's entire subject is the typecheck gates, so arming beforeType Check · debt ledgerandType Check · workspaceanswer would be arming blind on exactly the checks that matter.On green: undraft first, then arm (auto-merge does not survive a draft conversion). On MERGED:
pm:dispatchedcomes off this card.Siblings #15048 (
service-automation) and #15050 (service-storage) are still in flight and deliberately not folded in — the family-per-card split is the dispatch's, and this PR correctly declined to touch them.
Generated by Claude Code
- names
zhuangjianguo commented
on Sep 4, 2026 CollaboratorMore actionsACCEPT — PR #15147, driven to the queue
Reviewer of record: PM seat, maintainer direct-dispatch channel (maintainer asked this session to assess the open PR set and land what is landable, live chat 2026-09-04). Readings taken against GitHub at 2026-09-04T04:40Z, PR head
2969cef81602839be805052b3e05c3c69401b3af.Checklist
Item Reading PR shape non-draft, base main, first lineFixes #15049Path surface ( get_files, not the report)8 files: .changeset/,packages/services/service-knowledge/**,pnpm-lock.yaml,scripts/check-type-check-coverage.mjs,scripts/check-type-source-resolution.mjs. No governed path — nodocs/adr/**, no.claude/**, noskills/**, noAGENTS.md/CLAUDE.mdClause ② path limb not hit (no packages/spec/src/**); declaration limbClause-②: no, stated in the PR body. Gate does not fireChecks 35 check runs, all completed, zero failure —Lint & Repo Gates, all 6Test Coreshards, all 4Type Checkjobs, everyDogfoodshard,Temporal Conformance,Build Core/Build Docs,Governed Surface Queue Guard. Two deliberateskipped(Console Pin Gate,Packed-tarball smoke)Changeset present, patchon@objectstack/service-knowledge, matches the published-surface delta (typecheck/check:test-typecheckscripts + atsxdevDependency)Spot-checks I made against the diff rather than the narrative
src/**outside tests is untouched — the onlysrcedits in the diff are the two__tests__files. Thepatchclaim of "no shipped behaviour moves" holds.- The
DEBTentry for@objectstack/service-knowledgeis deleted, not lowered — the graduation the ratchet's own invariant requires, visible in thecheck-type-check-coverage.mjshunk. tsconfig.jsonis not in the diff, so the AGENTS.md prohibition on excluding tests was honoured; the newtsconfig.test.jsonredeclares module semantics andlibonly, with nopathsand no strictness key.- The
roles→positionsfix is in the test, andexecution-context.zod.tsis not in the diff — the contract was read, not moved.
Declared and accepted
check:type-source-resolutiongains a registry entry for three deps reached only via the newtsconfig.test.json. This is the onboarding re-baseline limb the gate's own doc-block opens, with all three terms supplied (provenance, +1 program/+3 pairs, and the measured 0 → 487TS6059that rulespathsout). Accepted as an onboarding entry, not a widening.- Three gates reported NOT MEASURED locally with unmet prerequisites; each is CI-owned and CI is green.
Serial note for the sibling cards. #15152 (
service-automation, #15048) and #15157 (service-storage, #15050) edit the same twoscripts/check-type-*.mjsfiles. This PR goes first; the other two will needmainmerged in before they can land. Recorded so the second and third in the family are not read as flakes when they conflict.Verdict: ACCEPT → ready, auto-merge armed, queue owns it from here. Tracking to MERGED.
Generated by Claude Code
Landing record — PR #15147 MERGED
2026-09-04T04:41:47Z, verified on the authoritative ref rather than on the API's merged flag alone:git log origin/main --oneline | grep '(#15147)' 8422acd fix(service-knowledge): put the test layer in front of tsc, and repair the four defects it was hiding (#15049) (#15147)origin/maintip at read time919beca(2026-09-04T05:43Z).pm:dispatchedstripped with a comparative read-back: pre-write set["tooling", "pm:dispatched"], target["tooling"], read back["tooling"]— union holds, nothing concurrent was stripped. Card was alreadyclosed/completedvia the PR'sFixesline.Recorded by the incoming
domain:servicesseat (session_01XpTx2tbq3pZRYAdoGt6E6Y,os-warren). This was the owed action the outgoing seat's shift-end briefing named as "the one owed action most likely to go stale" — it did go stale: the PR merged 24 minutes after that briefing was posted, with no session holding the seat.Sibling chain unchanged and still serial — #15048 / PR #15152 and #15050 / PR #15157 share
scripts/check-type-check-coverage.mjs,scripts/check-type-source-resolution.mjsandpnpm-lock.yaml, so they land one at a time. #15152 is next.
Generated by Claude Code
- added a commit that references this issue
on Sep 4, 2026
Filed by the
domain:servicesexecution seat as a sibling instance of the #14062 family, after #14181 closed the same gap forservice-cluster(PR #15032). Unassigned;domain:*, type and priority are triage's — this seat does not produce them.Named reader: whichever seat owns
packages/services/**(domain:serviceson the current lane table).The gap
packages/services/service-knowledgedeclares notypecheckscript, soturbo run typecheck— which selects only packages that declare the task — cannot reach it, and no tsc program compiles its test layer. Its errors are carried instead as a DEBT entry of 10 inscripts/check-type-check-coverage.mjs.Measured on
origin/main: of 16 packages underpackages/services/, 4 lacked atypecheckscript. #14181 graduated one (service-cluster), leaving three — this is one of them.Why this is worth a card rather than a note
A live instance was measured today, on PR #14994. A new test file in
@objectstack/service-automationcarried a… as nevercast that erased a contextual type, leaving a callback parameter implicitlyany— a plain TS7006. Where it was caught:typecheckscript to runType Check · workspaceType Check · source gatesType Check · consumer gatesType Check · debt ledgerAnd because the debt lane is a shrink-only ratchet, the author's own new error did not report as "you wrote an untyped test" — it reported as "DEBT records N raw tsc error(s),
tsc --noEmitnow reports N+1", in a gate whose remedy text is largely about not raising the entry. ⇒ A newly written type error arrives disguised as ledger drift. That is a materially worse failure mode than a plain type error in a packagetypecheck, and every package in this family is in it.The route, settled and demonstrated
#14062's settlement is the checked test zone: a
tsconfig.test.jsonplus atypecheckscript. PR #15032 is the worked example for this family and should be copied from — including its two non-obvious findings:plugin-auth/plugin-sharing/coreall exclude the test layer fromtsconfig.json, and AGENTS.md forbids adding such an exclusion, so their shape does not transfer.plugin-webhookswas the structural match forservice-cluster; check which one matches this package before copying.check:type-check-coveragefails a package that declarestypecheckwhile still sitting in the ledger, so the graduation is part of the change, not a follow-up.⛔ Constraints for whoever takes it
@objectstack/corereported 98 undivided → 4 after the split because an import that does not resolve makes every symbol it namesany, cascading into TS7006 everywhere;service-clusterby contrast read 1 both ways. Report both numbers: the contrast is the useful result either way.test-typecheck-debt.json— shrink-only and maintainer-only (@ts-expect-error退役 pin 在packages/spec里是幽灵检查:tsconfig 把**/*.test.ts排除出唯一的tsc --noEmit#5286). ⛔ Do not narrow the program,@ts-expect-errorthe residue away, or loosen strictness to manufacture green. ⛔ Never skip, disable or quarantine a test.check:type-source-resolutionmay go red purely because onboarding a test program moves the package's program set. PR fix(service-cluster): compile the test layer with tsc, and repair the TS2322 it hid #15032 took that gate's documented onboarding re-baseline limb (registry entry) rather than thepathsits failure text names —pathswas measured there at 0 → 435 errors, all in other packages' source. Read fix(service-cluster): compile the test layer with tsc, and repair the TS2322 it hid #15032's ruling before choosing.Refs: #14062 (the plugins-family class card) · #14181 / PR #15032 (
service-cluster, the worked example) · #14994 (the live incident) · #5286 (ledger is shrink-only, maintainer-only) · #4311 (the DEBT ledger)Generated by Claude Code