Skip to content

fix(service-analytics): wire the typecheck script and clear the 10 errors the unwired gate hid - #13188

Merged
os-elon merged 2 commits into
mainfrom
claude/issue-12939-analytics-typecheck-script
Aug 29, 2026
Merged

fix(service-analytics): wire the typecheck script and clear the 10 errors the unwired gate hid#13188
os-elon merged 2 commits into
mainfrom
claude/issue-12939-analytics-typecheck-script

Conversation

@os-elon

@os-elonos-elon commented Aug 29, 2026

Copy link
Copy Markdown
Collaborator

Fixes#12939

packages/services/service-analytics/package.json declared only build and test. Root typecheck is turbo run typecheck, which no-ops a package that has no such script and reports success; build is tsup (esbuild — its DTS pass processes declarations only) and test is vitest (esbuild transform). Neither type-checks.

This wires the one-line script, clears all 10 standing errors, and graduates the package out of the check:type-check-coverage DEBT ledger.

Authored in Claude Code session session_012WkdHQwHr2KQmaX7P1BHzi (https://claude.ai/code/session_012WkdHQwHr2KQmaX7P1BHzi) — recorded here in prose because the signature footer's session URL does not survive a body edit.

The star reading: the new gate is real, not a phantom

The cheap way to make a new typecheck script green is to exclude the tests from the program. That was not done, and the evidence is direct — tsc --noEmit --listFiles in the package, counted against what is on disk:

readingbeforeafter
*.test.ts files on disk under src/8383
package-own *.test.ts files listed in the tsc program8383
total files in the program534534
error TS lines100

tsconfig.json is byte-identical — include is src, exclude is node_modules and dist. No any was added, no @ts-expect-error, no @ts-nocheck, strict untouched.

Ablation, to prove the gate can fail. With the fix committed, the TS6133 import was reintroduced into src/__tests__/analytics-service.test.ts; the mutation was confirmed on disk by blob hash (b1e1af24 to cf7b0dd4) before measuring. pnpm --filter @objectstack/service-analytics typecheck then exited 2 with analytics-service.test.ts(10,1): error TS6133. Restored with git checkout HEAD -- on an absolute path; the blob is back to b1e1af24 and git diff HEAD is empty. So the gate reads the test files at runtime, not merely in --listFiles.

Which precedent, and why this one

The two in-repo precedents for this class differ, and the choice between them is a measurement rather than a preference:

service-analytics has no test exclusion and its tests sit in src/__tests__/** inside an include of src, so it is the first shape. No third pattern was invented.

The 10 errors — all 10 repaired, none deferred

Every one was a stale test, not a source defect. No non-test source file changed.

  • 7 x TS2339, src/__tests__/measure-source-field-gate.test.ts. promise.catch(fn) does not drop the resolved branch from the type, so service.query(...).catch((e) => e as Error) was the union AnalyticsResult | Error and every err.message / err.field / err.member / err.param read was a property access against AnalyticsResult. A local refusalOf() helper narrows once through then, giving the fulfilled branch the never type. One deliberate behaviour note, confined to the test failure path: a query that is not refused now fails by name instead of surfacing later as expect(undefined).toMatch(...).
  • 2 x TS7053, src/__tests__/objectql-timedimension-projection.test.ts. The TABLE fixture was inferred as an array of { id: number; due_date: string; priority: string } while the engine.aggregate() stand-in indexes it by a computed string key. Annotated as the Row alias the file already declares (a Record keyed by string with unknown values).
  • 1 x TS6133, src/__tests__/analytics-service.test.ts. An unused AnalyticsDriverCapabilities type import. The capability literals in this file are inline ctx objects already checked contextually at each canHandle call site, so the import carried no coverage and is removed rather than artificially exercised.

One correction to the card's premise

The card states that "no CI lane runs tsc over this package at all". That is not quite right, and the difference matters for how the repair is read. lint.yml runs pnpm check:type-check-debt (check-type-check-coverage.mjs --re-measure), which re-runs tsc --noEmit per ledger entry — and this package had a DEBT entry (errors: 10). So tsc did run over it in CI; what it asserted was only that the count must not grow, never that it is zero, and the entry's own note records the count walking 3 to 7 to 10 unremarked. The honest statement is that no lane required the package to be clean, and the typecheck lane skipped it entirely. Everything else in the card re-measured exactly: scripts build and test only, 10 errors, same three files, same error classes.

Column numbers drifted slightly from the card for the TS7053 pair — measured at (67,43) and (68,34), not (67,68).

Ledger graduation

check:type-check-coverage before and after, from the gate's own verdict line:

  • before — 65/78 workspace packages type-checked, 13 DEBT entries, 382 frozen raw errors
  • after — check-type-check-coverage: OK — 66/78 workspace packages type-checked (plus the root), 12 in the DEBT ledger (372 frozen raw errors)
  • check:type-check-debtsurplus: none — every entry sits exactly at its measurement, so any new error is red.

RECONCILED forbids carrying both a typecheck script and a DEBT entry, so the entry is deleted in the same commit as the script is added.

Out of scope

#12940 is not addressed here and remains open. It is held behind this card and touches the executeAggregate config-mirror annotations in the same package. Wiring the gate surfaced no errors on that surface — the package type-checks at 0 errors — so nothing was ledgered or deferred on its behalf. The gate now exists, so that card's narrowing will be type-checked when it lands.

Verification

All at final head 6cd14ca62.

  • pnpm --filter @objectstack/service-analytics typecheck — exit 0 (script name echoed, so not a zero-match no-op)
  • pnpm --filter @objectstack/service-analytics exec vitest run --maxWorkers=283 test files, 1805 tests, all passed
  • pnpm lint (repo-wide eslint . --no-inline-config) — exit 0
  • Gate families derived with node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack at edit time, from the real changed set, and re-derived after the changeset landed. All ran green, including check:type-check-coverage, check:type-check-debt, check:cross-package-test-inputs, check:engine-double-contract, check:where-matcher, check:test-source-alias, check:type-source-resolution, check:dual-build-cjs-loads, check:published-files and the changeset family.

Two gates in the derived family returned NOT MEASURED, neither a pass nor a failure:

  • scripts/pm/check-half-states.mjsexit 3, PREREQUISITE NOT MET: no usable GitHub credential in this container, so no issue was listed and no predicate ran. Its self-test half (pnpm check:pm-half-states, 1551 cases) passes. It is a PM board-hygiene gate pulled in by the changeset path, unrelated to this diff's content.
  • scripts/check-test-completeness.mjs — exit 1 on a usage error; it requires a turbo test log argument that only CI produces. Not a failing measurement.

Changeset

patch for @objectstack/service-analytics, matching the #7925 precedent, which shipped one for the same shape of repair. The published package.json gains a script, so this is not a skip-changeset diff.

@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

Nothing in this diff resolved to a documentable surface (no symbol, route or SDK anchor derived from 0 changed package(s)), so this run has no opinion about the docs.

What this run could not see
  • a page that states a rule by its inputs shares no identifier with the emitter that implements the rule, so an emitter-only diff cannot list it — not on this run and not on any run. Measured on fix(driver-sql): emit varchar(maxLength) for a text field a declared index keys on #11430: content/docs/protocol/objectql/types.mdx documents the text-family column mapping by the ObjectQL type names it maps FROM (text / textarea / html) while the diff changed createColumn; it went unlisted, and it was the page that diff falsified, in four places. No shared token exists to detect this on, so a rule your change carries has to be re-read by hand in the pages that restate it.

Coarse fallback — 0 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): node scripts/docs-audit/affected-docs.mjs --json 39d5d8a6001c210918f6f4dd716b3f2c44f72f8bpackageMentionDocs.

@github-actionsgithub-actionsBot added dependencies Pull requests that update a dependency file documentation Improvements or additions to documentation tests tooling labels Aug 29, 2026
@os-elon
os-elon marked this pull request as ready for review August 29, 2026 10:16
@os-elon
os-elon enabled auto-merge August 29, 2026 10:16
@os-elon
os-elon added this pull request to the merge queueAug 29, 2026
@github-actions

Copy link
Copy Markdown
Contributor

⛔ merge queue 构建失败 — 先分诊,再决定要不要重排

队列构建 33248059665 红了。队列跑的是全量套件(PR 侧 CI 只跑 affected 子集),
所以失败的测试可能在本 PR 没碰过的包里 —— 那不是重排能修的。每次盲目重排都会让排在后面的所有 PR 重建一轮。

失败的 job(日志抽取,best effort):

  • Test Core (1/6) — 失败步骤: Run this shard's tests

    @objectstack/cli:test: FAIL test/serve-publishes-bound-port.e2e.test.ts > #13062 the non-zero half — nothing an ordinary boot publishes may move > publishes exactly the port it was asked for when th
    ↳ 失败原因: @objectstack/cli:test: Error: ENOENT: no such file or directory, open '/tmp/os-bound-port-home-PvhnCl/runtime.env_local.json'
    

↳ 失败原因 是判读的关键:超时Test timed out in … / Hook timed out in …)多半是负载/时序,不是本 PR 的回归;
断言AssertionError: …)才指向真实的行为改变。两者的 FAIL 行长得一模一样,只有这一行能区分。

跨 PR 相同签名(24h,按失败测试文件聚合):

历史信号:

  • 本 PR 过去 24h 无队列失败记录(首次)。
  • 过去 24h 队列共有 17 个失败构建(不含本次)。

分诊清单:

  1. 失败测试在本 PR 改动的包里 → 真回归,修 PR。
  2. 失败测试与本 PR 无关 → 看上面的「跨 PR 相同签名」;已有汇总 issue ⇒ flaky/环境问题实锤,去那张 issue 上谈,修好前重排只会再烧一轮全队列。
  3. 两者都不是 → 可能与同组 PR 语义冲突;等前面的 PR 落地或失败出队后再重排一次即可,不要连续重排。

Generated by Claude Code · merge-queue-triage workflow (#4859)

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

dependenciesPull requests that update a dependency filedocumentationImprovements or additions to documentationsize/steststooling

Projects

None yet

1 participant

@os-elon