← All craftbooks

Type-Safety Pass

Build: software and codeevalv1.0.0released 2026-06-05workflow: build-loop

Tighten the types of a module — eliminate `any`/implicit-any, add precise annotations, narrow unions, and make illegal states unrepresentable — without changing runtime behavior. Audits FIRST to inventory every loose type, unsafe cast, and missing annotation, then replaces them with precise types, then a reviewer confirms the type-checker is clean under strict settings and behavior is unchanged. Covers killing `any`, strict null checks, discriminated unions, generics, type narrowing, removing unsafe casts, and compile-clean-under-strict verification.

Steps

Entry step: audit. Each step names the specialist role it wants; the full working prompt is expandable.

  1. Audit the typesdeveloperentry

    inventory every any, cast, and missing annotation

    Show working prompt
    Inventory the type weaknesses before fixing them. Step 1: Search the module for every `any` (explicit and implicit), every unsafe cast (`as`, `!` non-null assertions), and every untyped parameter/return. Step 2: For each, note what the CORRECT type should be (look at the values that actually flow through). Step 3: Identify spots where a union should be narrowed or a discriminated union / generic would make illegal states unrepresentable. Step 4: Note the strict compiler settings to enable (e.g. strict, noImplicitAny, strictNullChecks). Step 5: Write a numbered acceptance-criteria checklist of 5-9 items (e.g. 'no explicit or implicit any remains', 'no unsafe casts without justification', 'the type-checker passes under strict', 'runtime behavior is unchanged'). `write_task_note` the inventory + checklist and write the same to the produces path.
  2. Fix the typesdeveloper

    replace loose types with precise ones

    Show working prompt
    Apply precise types from the audit. Step 1: Annotate every parameter and return; replace each `any` with the real type the values demand. Step 2: Remove unsafe casts and non-null assertions by narrowing properly (type guards, discriminated unions) instead of asserting. Step 3: Where it helps, introduce generics or union types so illegal states cannot be constructed. Step 4: Enable the strict compiler settings and resolve every resulting error — do NOT silence them with `any` or `@ts-ignore`. Step 5: Confirm runtime behavior is unchanged (this is a types-only pass). Write the typed source to the produces path. On a loop-back, address only the remaining flagged spots. `write_task_note` the count of `any`s removed and which criteria now pass.
  3. Verify type safetyreviewer

    confirm strict-clean and behavior unchanged

    Show working prompt
    Verify the types are genuinely tighter and nothing was swept under the rug. Step 1: Run the type-checker under the strict settings and confirm zero errors. Step 2: Search for any remaining `any`, `as`, `!`, or `@ts-ignore`/`@ts-expect-error` and confirm each remaining one is justified (or gone). Step 3: Confirm the runtime behavior is unchanged (tests still green, no logic edits disguised as type edits). Step 4: Spot-check that the new types are precise, not just `unknown`-everywhere busywork. Write a verification note with the type-check result and the residual-escape-hatch count to the produces path.
  4. Evaluatereviewer

    Grade the deliverable against every acceptance criterion. All pass → finish; any fail → loop back and fix the gap.

    Show working prompt
    Run the type-checker under strict settings and the test suite. For EACH acceptance criterion: confirm no explicit/implicit `any` remains, confirm unsafe casts and ignore-comments are gone or justified, confirm the type-checker is clean under strict, and confirm runtime behavior is unchanged. Write PASS/FAIL per criterion; replacing one `any` with another or using `@ts-ignore` to pass is a FAIL.
    
    Then route — this is the whole point of the loop:
    
    - **Every criterion PASSES →** call `advance_task_step({ ref, stepId: "evaluate", next: "finish" })`.
    - **Any criterion FAILS →** write the specific gaps to notes, then call `advance_task_step({ ref, stepId: "evaluate", next: "fix" })` to loop back. The builder fixes exactly those gaps.
    
    Never route to `finish` while any criterion is unmet. The build phase's completion gate already blocked a grossly-incomplete deliverable; your job is the judgment an automated check cannot make (does it actually work, read well, look right). After ~3 unproductive loops, stop and report DONE_WITH_CONCERNS so the user can step in.
  5. Finishdeveloper

    All acceptance criteria met. Stamp a short summary and report DONE.

    Show working prompt
    Every acceptance criterion passed. Write a one-paragraph DONE summary to task notes via `write_task_note`: what was built, the deliverable path(s), and a one-line confirmation that each criterion is met. Then report DONE.

Triggers

Phrases that suggest this craftbook to a crew.

Source

View this craftbook on GitHub · MIT license