Skip to content

ci(typecheck): graduate the workspace root from the type-check DEBT ledger and run typecheck:root in lint.yml - #26339

Merged
os-zhuang merged 3 commits into
mainfrom
claude/project-thread-vq6idt
Oct 26, 2026
Merged

os-zhuang merged 3 commits into
mainfrom
claude/project-thread-vq6idt

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Requested by Steve · project thread
Fixes #26236

Clause-②: no
Metadata-protocol: none

⛔ Tier H. This diff touches .github/workflows/lint.yml, so it stays a draft until an authorized APPROVED review from a GOVERNED_APPROVERS account. No seat readies, queues or arms it before then.

What this does

Wanted 2 and 3 of the card. Wanted 1 (the root program at 0 errors) landed in #26280.

  1. The root graduates from the type-check DEBT ledger. scripts/check-type-check-coverage.mjs deletes the @objectstack/spec-monorepo entry, so DEBT is now empty. A graduation paragraph is added in the ledger's own style, and the ROOT_PROGRAM_COUPLED_SCRIPT comment no longer cites the 26.
  2. The root gets typecheck:root in package.json: tsc --noEmit -p tsconfig.json.
  3. lint.yml runs it. A new step, "Type-check the workspace root program", sits in the typecheck-source-gates lane, right after the coverage meta-gate. Like every gate step in that lane, it has continue-on-error: true and an id, so lane-verdict.mjs reads its outcome. The root program reads no package dist/: tsc --listFiles over it lists zero paths under packages/, so the step needs no build.
  4. Dispatch briefs name the new gate. In scripts/pm/dispatch-gates.data.mjs, the change kind for "adds or edits TypeScript in the ROOT tsc program" named check:type-check-debt. Once the root graduates, that gate no longer measures the root, so a card editing a root .mts would be sent to a gate that cannot red on it, and the error would first show in CI. The kind now names typecheck:root, and its why is rewritten to match.
    • For that name to resolve, the family parser in scripts/pm/dispatch-gates.mjs (extractCheckInvocations) reads pnpm typecheck:root as a family. This is the one non-check: name it admits.
    • Without that, the row renders STALE: "no workflow runs a gate under this name".
    • Self-test pins in scripts/pm/dispatch-gates.self-test.mjs follow the rename. Two parser cases are added: typecheck:root is read, and typecheck, typecheck:rooted and a filtered run typecheck are not.

Why the three move together

The coverage gate's root branch (around L2809) reports a finding when typecheck:root exists but lint.yml does not name it (ciInvokesRoot, around L4862). Without the script, deleting the entry reports "no typecheck:root script and no ledger entry". An entry of 0 is refused. Reverse check on this branch: with the entry deleted and the script added but no lint.yml step, node scripts/check-type-check-coverage.mjs exits 1 with ".github/workflows/lint.yml never invokes typecheck:root". With the step added, it exits 0.

Acceptance

All at head d750e1f unless stated, exit codes captured before any pipe.

  • pnpm typecheck:root: exit 0.
  • node scripts/check-type-check-coverage.mjs --self-test: exit 0 (58 semantic + 97 observation + 56 re-measure + 28 built-closure + 19 auto-lowering + 18 exit-code + 19 verify-lock cases). node scripts/check-type-check-coverage.mjs: exit 0, "0 in the DEBT ledger".
  • pnpm check:type-check-debt (self-test, then --re-measure under the verify lock): exit 0, "0 ledger entr(ies) re-measured in 540.7s, 0 raw tsc error(s) total".
  • Reverse check (see above): without the lint.yml step, the coverage gate exits 1. With it, the gate exits 0.
  • node scripts/pm/check-dispatch-gates.mjs --slow (both tiers): exit 0, "dispatch-gates self-test: 2166 cases pass" (fast 1901, slow 265). pnpm check:pm-dispatch-gates (fast tier) re-run at d750e1f: exit 0, 1901 cases.
  • Derived families (dispatch-gates --commands, unchanged between 24f2191 and d750e1f): 65 derived, 65 run, every one exit 0. --ran verdict: "65 derived famil(ies) accounted for — 65 run, 0 NOT-MEASURED (a DERIVED zero — all 65 recorded an exit code and none of them is 3)". check:pm-dispatch-gates first went red at 24f2191, on the pin "every zero-file family left is a pnpm workspace composite — UNEXPLAINED: typecheck:root". typecheck:root is a zero-file family by construction, so d750e1f names it in that pin with the reason. The other 64 families ran at 24f2191; the only file that differs at d750e1f is scripts/pm/dispatch-gates.self-test.mjs, which the re-run families cover.

Acceptance notes

  • scripts/check-exported-any-returns.mts (L105–110) and the "Why the ROOT-program entry does not weaken the ledger's discipline" docblock in scripts/pm/dispatch-gates.data.mjs still tell the history of the root DEBT entry. They are historical prose, and no assertion reads them, so they are left as they are.
  • A card that edits only .mjs files under scripts/ is not in the root program (no allowJs), so it does not derive typecheck:root. That is the existing, intended scope of the root-program kind.

维护者速读(草稿)

改了什么:仓库根目录的 scripts/ 程序在上一个 PR(#26280)里已经做到 0 个类型错误。这个 PR 把它从类型债账本里正式毕业:删掉账本条目,新增 pnpm typecheck:root,并在 lint 工作流的 Type Check 流水线里加一步运行它。派发工具对「改了根目录 TS 文件」的提示也改成指向这一步。

为什么改:之前根目录的脚本(门禁、PM 工具、发布脚本)没有任何 PR 检查会做类型检查,账本里那 26 条错误一直挂着,新脚本带进来的类型错误也拦不住。现在每个 PR 都会跑一遍,新错误当场变红。

风险与代价(含回滚):新增的一步只跑一次 tsc,不需要构建,耗时几秒。风险是以后改根目录脚本的人会多遇到一种红灯,这正是要的效果。回滚就是 revert 这个 PR,账本条目、脚本和工作流这一步会一起回去。

席位意见:

你要做的:因为改了 .github/workflows/lint.yml,这个 PR 需要你(GOVERNED_APPROVERS)批准,批准后由席位排队合并。


Generated by Claude Code

…edger

The root program (tsconfig.json: scripts/ and the top-level configs)
measures 0 errors, so its @objectstack/spec-monorepo DEBT entry is
deleted. The root gains a typecheck:root script, and the Type Check
source-gates lane runs it, which the coverage gate's root branch requires
once the script exists.

Claude-Session: https://claude.ai/code/session_01ENjVvxdwZxosWSS4Fqazu1
Co-authored-by: Claude <noreply@anthropic.com>
With the root graduated, check:type-check-debt no longer measures the
root program, so a card editing a root TypeScript file was sent to a gate
that cannot red on it. The family parser now reads pnpm typecheck:root as
a family, and the root-program change kind names it with a rewritten why.

Claude-Session: https://claude.ai/code/session_01ENjVvxdwZxosWSS4Fqazu1
Co-authored-by: Claude <noreply@anthropic.com>
@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

席位核对 · ACCEPT · devx seat 2 · 2026-10-26T22:06Z

Seat domain:devx#2 (#20163) · session_01Q4MDXRbEJCNdPAP4SiXwp9 · reviewed head d750e1f1fb · card #26236, claim 6422728461 (PR 2: Wanted 2 + Wanted 3). PR carries Fixes #26236.

  • Scope: 6 files, +65/−39: .github/workflows/lint.yml (one step), root package.json (typecheck:root), scripts/check-type-check-coverage.mjs (DEBT → {}), scripts/pm/dispatch-gates.data.mjs, scripts/pm/dispatch-gates.mjs and scripts/pm/dispatch-gates.self-test.mjs. No other workflow, no root ci.yml, no ui/ path, no type rule loosened, no exclude widened.
  • Surface note: dispatch-gates.mjs was outside the amended surface. The 7-line change makes extractCheckInvocations read typecheck:root as a family. Without it, the root-ts-program row would name a check nobody can resolve and render STALE, so it is the direct consequence of the 20:35Z line. The seat amended the claim to record it.
  • Graduation is the root's way: typecheck:root is tsc --noEmit -p tsconfig.json, and the lint.yml step runs it in the source-gates lane right after the coverage gate, with continue-on-error like its neighbours. The lane verdict reads toJSON(steps), so the new step id needs no registration. evaluate's root branch (~L3011–3046) requires both the script and the lint.yml invocation and refuses a leftover DEBT entry, so the three pieces can only land together.
  • Change-kind row: the root-ts-program gate is now typecheck:root. Its why drops the ratchet and build prerequisites, which are true for this program (it reads no package dist/). The regex exception is anchored (typecheck:root(?![\w:-])), and a control pins that pnpm typecheck, typecheck:rooted and a filtered run typecheck are not read. The zero-file family exception is named for this one script only.
  • Self-test: I ran dispatch-gates.mjs --self-test on this head locally and it produced 0 ✗, including the new and re-pointed cases (the run reached the slow tier before my local time limit, and CI's Lint · PM dispatch-gates runs it in full).
  • Serial: draft ci(governed-surface-guard): the pull_request leg checks out commits and trees only and installs the toolchain on demand #26311 also edits dispatch-gates.self-test.mjs, in another region. Whichever lands second merges main.
  • Landing: ⛔ Tier H (lint.yml, governed workflows surface). This stays a draft until os-zhuang or hotlong approves the current head. After that, and once every check is green or skipped, the seat runs ready + auto-merge.

Generated by Claude Code

@os-zhuang
os-zhuang marked this pull request as ready for review October 26, 2026 22:48
@os-zhuang
os-zhuang added this pull request to the merge queue Oct 26, 2026
Merged via the queue into main with commit f60f4ea Oct 26, 2026
53 checks passed
@os-zhuang
os-zhuang deleted the claude/project-thread-vq6idt branch October 26, 2026 23:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ci/cd dependencies Pull requests that update a dependency file size/m skip-changeset PR has no user-facing published change; bypasses the changeset gate

Projects

None yet

Development

Successfully merging this pull request may close these issues.

tooling(typecheck): graduate the workspace root's DEBT entry (26 errors in scripts/) and give the root program its own typecheck step

3 participants