Skip to content

ci: run the TypeScript suite, and make its type checker pass (v1.43.1) - #65

Open
lapc506 wants to merge 1 commit into
mainfrom
andres/ci-run-the-typescript-suite
Open

ci: run the TypeScript suite, and make its type checker pass (v1.43.1)#65
lapc506 wants to merge 1 commit into
mainfrom
andres/ci-run-the-typescript-suite

Conversation

@lapc506

@lapc506 lapc506 commented Aug 4, 2026

Copy link
Copy Markdown
Collaborator

Merge this before the rest of the open queue (#52, #41, #44, #59, #58, #46). Those six carry ~4,100 added lines that no CI would otherwise look at.

The gap

Three workflows, none running vitest or tsc:

Workflow Trigger Covers
test-hooks.yml hooks/**, scripts/build-rules.mjs 346 shell tests
shellcheck.yml **.sh shell lint
publish.yml push of a v* tag npm run build

publish.yml effectively never fires — the note at the top of CHANGELOG.md records that this project shipped without v* tags. So src/, the published library, had no gate at all: 60 tests that ran when somebody remembered, and a tsc that had been red on three errors.

This is shape 1 from this toolkit's own ENF audit — "it does not look." And the partial coverage made it worse than an outright gap: the hook suite is gated, so every PR went green, and green reads as verified. A check covering part of a surface while reporting like it covers all of it is shape 4 applied to scope rather than to an assertion — correct, and binding nothing where it matters.

No paths: filter, deliberately

The one place test.yml departs from its siblings. A path filter is how this gap was built: scoping test-hooks.yml to the directory it tests is right for that workflow, and is exactly what left src/ uncovered.

Enumerating the paths that can break a type check means maintaining a second copy of the dependency graph, and the second copy is what drifts. The suite costs ~1.4 s. There is nothing to buy by scoping it.

Neither step is continue-on-error — an advisory test run is a correct verdict that stops nothing.

The type fix

printHumanResult demanded Record<string, unknown> while its body only calls Object.entries and never indexes by an arbitrary key. No *Result interface in src/lib/ declares an index signature, so none satisfied it.

-function printHumanResult(result: Record<string, unknown>): void {
+function printHumanResult(result: object): void {
...
-      printHumanResult(result as unknown as Record<string, unknown>);
+      printHumanResult(result);

Two lines. Fixes all three failing call sites and makes the cast at the fourth — the doctor path — unnecessary. Object.entries accepts both types identically, so no behaviour changes.

The cast is the artifact worth naming. Somebody hit this error at one of four call sites, silenced it with as unknown as, and the other three stayed red because nothing ever ran tsc. The fix is smaller than the workaround because the workaround never asked what the signature was demanding.

Verification

Run locally — exactly what the workflow will run:

tsc --noEmit          0 errors  (was 3)
npm test              60 passed
hooks/test-hooks.sh   346 passed

Not fixed here

The CHANGELOG link footer is missing entries for 1.39.0, 1.40.0, 1.41.0 and 1.43.0, and [Unreleased] still compares against v1.38.0. Four releases of drift, so it belongs in its own change rather than riding along here.

Created by Claude Code on behalf of @lapc506

🤖 Generated with Claude Code

Three workflows, none of which ran `vitest` or `tsc`. `test-hooks.yml` covers
`hooks/**`, `shellcheck.yml` covers `**.sh`, and `publish.yml` runs
`npm run build` only on a `v*` tag push — which the CHANGELOG's own header
records as something this project never does, having shipped without tags. So
`src/`, the published library, had no gate: 60 tests that ran when somebody
remembered, and a type checker that had been red long enough for one of four
call sites to be silenced with a cast while the other three stayed broken.

This is shape 1 from the toolkit's own enforcement audit — "it does not look" —
and the partial coverage made it worse than an outright gap. The hook suite IS
gated, so every pull request went green, and green reads as verified. A check
that covers part of a surface while reporting like it covers all of it is
shape 4 applied to scope instead of to an assertion: correct, and binding
nothing where it matters.

NO `paths:` FILTER, which is the one place `test.yml` departs from its two
siblings. A path filter is how this gap was built: scoping `test-hooks.yml` to
the directory it tests is right for that workflow and is exactly what left
`src/` uncovered. Enumerating the paths that can break a type check means
maintaining a second copy of the dependency graph, and the second copy drifts.
The suite costs ~1.4 s; scoping buys nothing. Neither step is
`continue-on-error`, because an advisory test run is a correct verdict that
stops nothing.

THE TYPE FIX. `printHumanResult` demanded `Record<string, unknown>` while its
body only calls `Object.entries` and never indexes by an arbitrary key. No
`*Result` interface in `src/lib/` declares an index signature, so none of them
could satisfy it. Widening the parameter to `object` fixes all three failing
call sites and makes the `as unknown as Record<string, unknown>` at the fourth
unnecessary; it is removed. `Object.entries` accepts both types identically, so
there is no behaviour change.

The cast is the artifact worth naming: somebody hit this at one call site,
silenced it there, and the other three stayed red because nothing ran `tsc`.
The fix is smaller than the workaround because the workaround never asked what
the signature was demanding.

Verified locally, exactly what the workflow will run:
  tsc --noEmit          0 errors (was 3)
  npm test              60 passed
  hooks/test-hooks.sh   346 passed

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

@dojo-code-reviewer dojo-code-reviewer Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Approved

Approved — 0 blockers, 1 P3. Confidence: 4.80/5.00.

Walkthrough

⚠️ Governance Warning: This PR targets main directly instead of following GitFlow expectations (feature → develop → main). This is a non-blocking informative notice, and does not affect the review verdict of the code itself.

Review Walkthrough

This PR establishes a TypeScript CI workflow (test.yml) running on every pull request and push to main to typecheck and run the Vitest test suite. It also fixes a compilation error in src/cli.ts by widening the parameter of printHumanResult from Record<string, unknown> to object, making the tsc compiler pass successfully.

Areas Reviewed

  • CI Workflows: Reviewed .github/workflows/test.yml configuration, actions, and runner settings.
  • CLI Code: Reviewed src/cli.ts for typings of printHumanResult and usage of Object.entries.
  • Project Metadata: Reviewed .claude-plugin/marketplace.json, .claude-plugin/plugin.json, package.json, and CHANGELOG.md version bump consistency.

Safety Rationale

Widening the input type of printHumanResult to object has zero runtime impact and resolves static analysis errors due to missing index signatures on return types from src/lib/ functions. The test CI setup runs identical commands to those executed locally, ensuring continuous stability without impacting deployment or release flows.

Approved — 0 blockers, 1 P3.

🔵 P3 — Minor

  • .github/workflows/test.yml:53 — 🔵 P3 (minor) — Adding a "typecheck": "tsc --noEmit" script to package.json and calling npm run typecheck here aligns CI commands with local developer tooling. Currently, developers must manually run npx tsc --noEmit which can drift from CI patterns over time if not declared as a standard package script.

[pass 1]


Total findings: 1 business context (1 total)

run: npm ci

# Before the suite: a type error is a fact about the code that does not
# need a test to run, and reporting it first makes a red build easier to

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 P3 (minor) — Adding a "typecheck": "tsc --noEmit" script to package.json and calling npm run typecheck here aligns CI commands with local developer tooling. Currently, developers must manually run npx tsc --noEmit which can drift from CI patterns over time if not declared as a standard package script.

[pass 1]

lapc506 added a commit that referenced this pull request Aug 6, 2026
…and not `any`

PR #65 (`ci: run the TypeScript suite`, MERGEABLE) adds a workflow running
`npx tsc --noEmit` and `npm test` on every PR with **no `paths:` filter**. Its
own changelog reports tsc "failing on three errors in `src/cli.ts`" — measured
against `main`, where `src/audit/worktree-cleanup.test.ts` does not exist yet.
This PR introduces that file carrying **9 errors of its own**, so whichever of
the two lands second goes red on a gate the other one built. Fixed here rather
than left as a merge-order trap.

The fix is a declaration file, not a suppression. `scripts/worktree-cleanup.mjs`
stays plain ESM because a slash command invokes it as `node scripts/...` with no
build step available; `scripts/worktree-cleanup.d.mts` sits beside it and
TypeScript resolves it automatically for the `.mjs` import.

It is worth more than the error count. The suite was `any` throughout, and
every case is `{ ...clean, oneField: x }` — an excess-property check does not
reach inside a spread, so under `any` a MISSPELLED field name is not an error,
it is a fact the classifier never reads. The test then passes while asserting
nothing whatsoever about the guard named in its own title. That is precisely
the "regression test that still passes while proving nothing" this suite was
written to avoid, present in the suite itself.

Typing `clean` as `WorktreeFacts` surfaced it immediately: `mergedBy: 'pr'`
widened to `string` and failed against the `'ancestor' | 'cherry' | 'pr' | null`
union, in every one of the spread cases. `ahead` and `midOperation` now carry
their `null`-means-unmeasured meaning in the type rather than only in a comment.

Measured: `tsc --noEmit` on worktree-cleanup files 9 errors -> 0. Repo total
15 -> 6, and all 6 remaining are the pre-existing `src/cli.ts` ones that PR #65
fixes — so after either merge order the gate is green. `npm run build` green,
109 tests passing.

Created by Claude Opus 5 on behalf of @lapc506
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant