Repository navigation
service-settings has no typecheck script — turbo silently no-ops it, and ~5 test files carry pre-existing type errors behind the unwired gate #7925
Description
Activity
Triage: promoted
finding→pm:queue, routeddomain:services(the fix lands inpackages/services/service-settings: onetypecheckscript line + clearing the ~5 test files' pre-existing errors, each read for stale-test-vs-real-drift as the card specifies). Restore-invariant class with direct precedents the card names (#4855, #5475): a gate that reports green while never executing is the declared-but-unenforced shape, promoted on sight.Scope fence: the "sweep other packages for the same missing script" suggestion does NOT ride this card — it is the same gate-over-sweep class as #7849 (vitest-config invariant,
domain:devx, queued today) and should be folded into that card's gate design or filed as its sibling, so the mechanical invariant gets enforced once rather than swept twice. This card fixes the one measured package.Size/model suggestion: S–M,
mode:subagentacceptable, model: sonnet.
Generated by Claude Code
huangyiirene commented
on Aug 12, 2026 CollaboratorMore actionsClaim: PM loop round 6
Session:session_01JVfWSQN9RDDGwdVSmMc29x
Branch:claude/issue-7925-service-settings-typecheck
Worktree: cloud session's own clone (mode:cloud)
Domain:domain:services
File surface:packages/services/service-settings/package.json+ the five named test files (ai.manifest.test.ts,sms.manifest.test.ts,storage.manifest.test.ts,settings-service.test.ts,settings-translation-coverage.test.ts) + a workspace-widepackage.jsonsweep for the same missing-script shape.
Container & model: M (one-line script + judgement per type error: stale test vs real contract drift),mode:cloud,model: opus⚠️ #5536 ride-along, conditional — named because the seam is one file away. This lane's standing pre-dispatch check namesservice-settings/src/settings-service.ts:1200as a #5536 ride-along trigger. The declared surface above touchessettings-service.**test**.ts, not the source file, so the trigger does not fire as scoped. But if clearing a type error turns out to require editingsettings-service.tsitself, the ride-along is owed at that moment — the dispatch carries the obligation conditionally rather than pretending the adjacency doesn't exist. ⛔ Still no single-point fix of storagehasAny, and ⛔ no promotion of #5536 on the back of this card.Serial constraints cleared: no in-flight PR touches
service-settings. Same-round siblings #7902 (read-only survey, zero writes) and #7882 (service-automation/src/builtin/http-nodes.ts) are file-disjoint from this surface by construction.
Generated by Claude Code
huangyiirene commented
on Aug 12, 2026 CollaboratorMore actionsPR: #7959 (draft,
Fixes #7925) · Branch:claude/issue-7925-service-settings-typecheck· commitd90bfcbPremise: confirmed, measured on
6ff179dturbo run typecheck --filter=@objectstack/service-settingsexited 0 running 6 tasks, all^builddependencies — noservice-settings:typecheckamong them. After adding the script it runs 7, the new one being a real typecheck, and it is green. Ad-hoctsc --noEmitsurfaced 14 errors (the card said ~5 files; it was 14 errors across those 5 files). One refinement to the filed shape: the package's tests live undersrc/, so the tsconfigincludealways reached them — the only missing piece was the script.Per-error verdict — 14/14 stale test, 0 contract drift
No non-test file under
service-settings/src/**was changed.File n Error Verdict manifests/sms.manifest.test.ts3 TS2345 — handler called { values, ctx }stale test manifests/storage.manifest.test.ts4 TS2345 — same stale test manifests/ai.manifest.test.ts1 TS6133 — aiTestEmbedderActionHandlerimported, unusedstale test settings-service.test.ts1 TS2322 — number→void | Promise<void>stale test translations/settings-translation-coverage.test.ts5 TS2677 + 4 cascading stale test The 7 TS2345s are one drift:
SettingsActionHandlertakes{ namespace, actionId, values, payload?, ctx }andsettings-service.ts:1809(the only call site) passes all of it; the tests kept the older two-field shape. Fixed by calling handlers the way the service does.settings-service.test.ts:143returnedArray.push's number from avoidsink. The translation guard narrowed the manifests barrel through a hand-rolledManifesttype that had drifted from the spec's (labelisstring | Record<string,string>), making its predicate unassignable — the 4 downstream errors were cascades of that one; it now narrows to the spec's ownSettingsManifest.Nothing silenced: no
anyadded, no@ts-expect-error,includeuntouched. Going the other way, the five pre-existingas anycasts inai.manifest.test.tswere removed rather than copied into sms/storage — they were hiding the identical drift. And the unused import was there becausetest_embedder(a declared action button) had no coverage at all; two tests now exercise it instead of deleting the import. Package tests: 401/401 pass.The sweep — and a correction to both framings
⚠️ The filer's premise and my dispatch's §4 are both wrong on one point, and it's the load-bearing one: this invariant is already gated.scripts/check-type-check-coverage.mjs(#4311) enforces exactly it — every workspace package either declarestypecheckor carries a measured DEBT entry with an error count and tracking issue, and the ledger is closed to new debt. The silent no-op is not an unknown hole anywhere; it is 442 raw errors of already-tracked, already-counted debt.service-settingssat in that ledger aterrors: 13, with a note naming the very TS2345s this PR just fixed. So this card paid down ledgered debt rather than discovering an unenforced gate.Sweep over all 78 workspace
package.jsons → 13 remaining without the script, reconciling exactly with the ledger (13 DEBT + 1 EXEMPT; one DEBT entry is the workspace root, not a package dir):core98 ·metadata92 ·spec-monorepo(root) 80 ·metadata-protocol63 ·service-storage52 ·cloud-connection13 ·observability11 ·service-knowledge10 ·service-analytics10 ·service-automation5 ·knowledge-ragflow4 ·hono3 ·service-cluster1 — total 442. PlusconsoleEXEMPT (published objectui artifact, no TS sources).Scoping decision: wired none of them. Triage on this card already fenced the sweep out (→ #7849), and the measurement agrees: four entries are over 50 errors each. Since anything I wire I must also leave green, wiring any one means taking its burn-down onto a one-package card. No follow-up card filed either — #4311 already owns the burn-down and #7849 owns the mechanical invariant; a third card would just duplicate them.
Ratchets — moved down, neither raised
Deleting the ledger entry was required, not optional: the gate fails with "declares
typecheckbut still has a DEBT entry — it graduated; delete its entry".check:type-check-coverage: 63/77 → 64/77 covered · DEBT 14 → 13 entries · frozen raw errors 455 → 442. Self-test green (23 semantic + 24 observation + 15 re-measure + 12 built-closure + 9 auto-lowering).check:query-options-erasure: holds — 67 unswept non-test sites / 17 files, none new; baseline verified against6ff179d.check:engine-double-contract: OK — 166 pinned, 133 DEBT, 2 exempt. No engine fake touched.- ESLint clean over the changed surface.
§5 (#5536 ride-along): did not fire
Clearing all 14 errors required zero edits to
settings-service.ts— it was read-only here (cited at :1809 as evidence for the handler contract, nothing more). No single-point fix of storagehasAny; no promotion of #5536.Deliberately not done
- The 13 other ledgered packages (above).
check:type-check-debt --re-measureneeds a fully built workspace and re-runstscper ledger entry; it was still running at report time. CI covers it, and nothing in this diff can raise another package's count. I'll flag it on the PR if it reports anything.- No
content/docs/releases/**,docs/adr/**, or skills touched. Changeset added (.changeset/service-settings-typecheck-gate.md,@objectstack/service-settings: patch).
Generated by Claude Code
huangyiirene commented
on Aug 12, 2026 CollaboratorMore actionsAddendum to the report above — the outstanding ratchet reading came back clean, plus one pre-existing finding.
check:type-check-debt --re-measure(fully built workspace, 185.8s): OK — 35 ledger entries re-measured, 1975 raw tsc errors total,none above its recorded number. No ratchet raised.But it surfaced something worth recording, which is not caused by this PR and is not fixed in it: 272 raw errors of surplus across 9 ledger entries sitting below their recorded ceilings — headroom in which regressions can land while the gate still reports success (#6376, whose note cites driver-mongodb's 33 swallowing a whole signature reversion).
Layer Entry Recorded → measured DEBT metadata92 → 89 DEBT service-automation5 → 3 DEBT service-storage52 → 51 TEST_DEBT plugin-approvals547 → 348 TEST_DEBT plugin-auth131 → 108 TEST_DEBT mcp63 → 53 TEST_DEBT lint42 → 19 TEST_DEBT plugin-security21 → 11 TEST_DEBT http-conformance4 → 3 None is
service-settings.pnpm check:type-check-debt --lowercloses all nine in one write, but that rewrites nine entries across eight unrelated packages on a one-package card — the ballooning §4 forbids. Reported, not done; it's #6376's business, andplugin-approvalsat 199 errors of slack is the standout if anyone wants to pick it up.CI on #7959 so far: ESLint ✅, Build Core ✅, Test Core 3/3 ✅, Dogfood Regression Gate ✅ (all shards), Temporal Conformance ✅, Check Changeset ✅, Check PR Size ✅. TypeScript Type Check and Test Core 1/3 + 2/3 still running — I'm subscribed and will drive to green.
Generated by Claude Code
huangyiirene commented
on Aug 12, 2026 CollaboratorMore actionsPM 复核:ACCEPT —— PR #7959 转 ready + 已挂 auto-merge
28 个 check 全部 success/skipped,亲核 ESLint ✅(09:01:57Z)与 TypeScript Type Check ✅(09:09:49Z)两 job 的
conclusion;Check Changeset✅、ADR maintainer approval✅ 且 diff 不触docs/adr/**、skills/**。⚠️ 本席流程失误一笔,记在这里:09:2xZ 转 ready 之后漏挂 auto-merge,该 PR 因此在「已就绪但未入队」状态空停了约十分钟,直到本轮复查才发现。转 ready 与挂 auto-merge 是一对动作,顺序不可反也不可只做一半 —— 我做了前一半就去处理别的卡了。已补挂。证伪背书第十七笔 —— 卡片与派发令的共同前提都是假的
卡片的建议是「顺手扫一遍其它缺
typecheck脚本的包」,前提是这个静默 no-op 到处都没人管。我照抄进了派发令 §4。两者都错,而 dev 直说了:该不变量已经有门在守。
scripts/check-type-check-coverage.mjs(check:type-check-coverage/check:type-check-debt,#4311)已经在强制这件事 —— 每个 workspace 包要么声明typecheck,要么在台账里带一条实测过的 DEBT 条目(错误数 + 追踪单),且台账对新债关闭。service-settings本来就在台账里,记着errors: 13,注释甚至点名了本 PR 修掉的那几条(「TS2345 x7: manifest action handlers called withoutnamespace/actionId; TS2322」)。⇒ 这不是发现了一个无人看管的洞,是在偿还一笔已登记的债。两件事的处置完全不同,而卡片的措辞会把后者读成前者。
sweep 照跑了(
jq过全部 78 个package.json),13 个包仍无脚本,且与台账逐条对上(13 条 DEBT + 1 条 EXEMPT,其中一条 DEBT 是 workspace 根而非包目录),合计 442 条冻结原始错误,四个包超过 50。范围决定:一个都不在此卡接线 —— 判据给得干净:本 PR 必须让它接线的一切保持绿,所以接一个就得连它的燃尽一起付;而这些不是「几个干净的包」。survey 是交付物,燃尽归 #4311 的逐包卡。这正是我在派发令里要求的那个判断,他做出了相反于卡片建议的选择并给了理由 —— 判读正确。逐错判定表:14/14 全是 stale test,零静默
service-settings/src/**的非测试文件一个字没改。七处 action-handler 调用用的是旧的两字段形状,而唯一调用点settings-service.ts:1809早已传全 —— 测试漂了,契约没漂。ai.manifest.test.ts的五处调用本来就是as any预先静默过的同一漂移,他把那五个 cast 删掉而不是照抄到另外两个文件上;那条「未使用的导入」背后是aiTestEmbedderActionHandler从未被测,他补了两个分支而不是删导入(净 +2 测试)。settings-translation-coverage.test.ts的 TS2677 + 四条级联,根因是手搓的结构化Manifest/Specifier与真实形状漂移(label是string | Record而非string),改为收窄到 spec 自己的SettingsManifest并删掉本地副本。判据逐条对上:⛔ 无
any新增、⛔ 无@ts-expect-error、⛔ 未动 tsconfiginclude,且移除了五个既有as any。我在派发令里把这三种「假绿」列为发现即 REWORK —— 不仅没出现,方向还是反的。Ratchet:全部下移,无一抬高
check:type-check-coverage63/77 → 64/77,DEBT 14 → 13,冻结原始错误 455 → 442(从台账删除service-settings是必须的,门禁原话:「declarestypecheckbut still has a DEBT entry — it graduated; delete its entry」)。check:type-check-debt --re-measure:35 条重测,无一高于记录值。check:query-options-erasure持平(67 处未扫非测试点 / 17 文件,无新增)。附带发现:272 条余量,报告而未动 —— 判读正确
--re-measure报出 9 条台账条目合计 272 条原始错误的余量(低于记录上限的头寸),即回归可以静默落进去的空间(#6376)。pnpm check:type-check-debt --lower一次写入就能全关,但那会在一张单包卡上重写八个无关包的九条台账 —— 正是本卡范围禁止的膨胀。报告而不做,归 #6376。这与上面的 sweep 决定是同一条纪律的两次正确应用。#5536 ride-along:未触发,且是被核实过的未触发
条件触发点是
settings-service.ts:1200。清掉全部 14 条错误未编辑settings-service.ts(该文件在本工作中只读,其 1809 行仅作为 handler 契约的证据被引用)。⛔ 无 storagehasAny单点修,⛔ 无 #5536 晋级。条件式 ride-along 的正确结局就是这样:核过、未触发、写明。
Generated by Claude Code
- added a commit that references this issue
on Aug 17, 2026
Out-of-scope finding from the #7759 landing lap (PR #7759,
SECRET_MASKhoist — the lap ran consumer-package verification and hit this). Filed unassigned per the #4949 discipline.What was measured (2026-08-12, on the #7759 lap worktree @ merge of
origin/main)packages/services/service-settings/package.jsondefines onlybuildandtest— notypecheckscript. Its siblingservice-messaginghas one.turbo run typecheck --filter=@objectstack/service-settingsexits 0 while never running aservice-settings:typechecktask: turbo silently no-ops packages missing the script. So "typecheck green" for this package is a claim nothing enforces — the declared-but-unexecuted-gate shape.tsc --noEmitin the package directory DOES surface real type errors, inai.manifest.test.ts,sms.manifest.test.ts,storage.manifest.test.ts,settings-service.test.ts,settings-translation-coverage.test.ts. Git history shows these files last touched by old, unrelated commits (fix(service-settings): complete zh-CN coverage for auth/sms/ai settings (objectui#2851 P1) #3598–fix(service-settings): refuse a save whosevisiblepredicate cannot be evaluated (#7169) #7310 range) — the errors are pre-existing, not introduced by fix(spec): declare the eight-bullet credential read mask once, in spec (#7572) #7759 or the last 24h of main.Why this is an issue and not a lap fix
A landing lap makes no source-logic edits; and the fix has two halves that deserve one deliberate PR: (a) add the
typecheckscript (one line), (b) clear the accumulated type errors it immediately surfaces — which requires reading whether each error is a stale test or a real contract drift. The precedent shape is #4855 (qa/dogfood's unexecuted tsconfig hiding 14 errors) and #5475 (spec/scriptsoutside every tsconfig include): both were graded and fixed as restore-invariant cards.Suggested acceptance
turbo run typecheck --filter=@objectstack/service-settingsactually executes a typecheck task and it is green; the five files' errors are resolved or individually justified. Worth a quick sweep for OTHER packages missing the script in the same pass (jqover all workspacepackage.jsons) — the silent no-op applies to every one of them.