Skip to content

Post-1.0 maintenance directive (archived)

Archived 2026-07-06. Snapshot of the completed post-1.0 phases from .agent-state/directive.md, migrated out of the live directive so the queue tracks only in-flight work. Every item below is [x]/DONE. The WHY-per-commit record is preserved here; the live directive now carries only the RFC-0001 milestone. See also 1.0 stabilization.


Active queue — post-merge release + maintenance

Section titled “Active queue — post-merge release + maintenance”

Phase LF — library-fit decomposition (Epic LF, in PR)

Section titled “Phase LF — library-fit decomposition (Epic LF, in PR)”
  • LF-PR53 — ✅ PR #53 (Epic LF, branch feat/library-fit-decomposition) merged 2026-05-28 as main commit 4f442ba. All 21 commits across LF1–LF8 squashed in; Gemini review threads addressed in commit 2e58f64 and resolved via addPullRequestReviewThreadReply + resolveReviewThread graphql mutations; CodeRabbit hit its rate limit so no human-style review threads to reply to; CodeQL js/incomplete-sanitization regex meta-escape fix shipped in 7cab6b9.
  • G8 — ✅ Release flow exercised end-to-end 2026-05-28, but the deliverable identity changed mid-flight: the original medieval-hexagon-gameboard@1.0.0 release-please PR (#6) merged + cut a GH release but release.yml failed at workflow setup on a bad actions/attest-build-provenance SHA pin (the pinned SHA e7af5b09… didn’t exist in the action’s repo — 977bb373… is the real v3.0.0 SHA). That stale release + tag were deleted; the package was renamed to declarative-hex-worlds (PR #55 / commit b0964bc), release-please then cut a fresh declarative-hex-worlds@1.0.0 release via PR #56 (commit 0564ff2). The npm publish happens locally via NPMJS_TOKEN (in .env, gitignored); release.yml is then converted to OIDC trusted publishing so subsequent releases need no token. See [[rename-to-declarative-hex-worlds]].

Phase RB — bootstrap CI integration (continuation)

Section titled “Phase RB — bootstrap CI integration (continuation)”
  • RB-CI — ✅ commit (2026-05-27) established the browser-free visual gate. 2026-06-25 closeout keeps pnpm test:browser:free as the full local visual/screenshot gate and wires required CI Coverage through pnpm coverage:all:enforce (unit + browser-free coverage merged before threshold enforcement).

Phase E0 — coverage closure (continuation toward 100/100/100/100)

Section titled “Phase E0 — coverage closure (continuation toward 100/100/100/100)”

The A8 coverage ratchet floors at 64.5 / 62.3 / 76.4 / 64 (unit harness) as of 33d271b. The final PR #210 ratchets merged coverage to 100 / 100 / 100 / 100.

  • [DONE] E0a — Simulation + patrol files toward 100%. PR#10-#51 merged; no open PR remains for the old PR#52 note as of 2026-06-25. Current CI-measured merged coverage gate after browser-free integration is 76.74 / 70.87 / 84.69 / 76.48 (PR #106 Coverage); local reference-enabled runs read 78.19 / 72.18 / 86.11 / 77.94. CLI command batch PR #108 Coverage measured 78.32 / 72.80 / 85.69 / 78.06 and staged thresholds at 77.8 / 72.3 / 85.1 / 77.5. CLI shared-helper batch PR #109 Coverage measured 79.02 / 73.84 / 86.49 / 78.76 and staged thresholds at 78.3 / 73.0 / 85.6 / 78.0. CLI validation-command batch PR #110 Coverage measured 79.56 / 74.44 / 86.65 / 79.32 and staged thresholds at 78.8 / 73.5 / 85.9 / 78.5. CLI simulation-command batch PR #111 Coverage measured 80.29 / 75.00 / 86.91 / 80.04 and staged thresholds at 79.6 / 74.2 / 86.2 / 79.2. CLI layout/piece-command batch PR #112 Coverage measured 81.04 / 75.76 / 87.14 / 80.81 and staged thresholds at 80.3 / 75.1 / 86.6 / 80.2. CLI piece-registry batch PR #113 Coverage measured 82.30 / 77.02 / 88.60 / 82.08 and staged thresholds at 81.3 / 76.0 / 87.6 / 81.1. CLI summary-variant batch PR #114 Coverage measured 82.54 / 77.44 / 88.60 / 82.33 and staged thresholds at 81.8 / 76.5 / 87.9 / 81.6. CLI guide-output batch PR #115 Coverage measured 82.96 / 77.80 / 88.64 / 82.77 and staged thresholds at 82.2 / 77.0 / 88.0 / 82.0. CLI guide-render batch PR #116 Coverage measured 83.26 / 78.06 / 88.72 / 83.08 and staged thresholds at 82.5 / 77.4 / 88.1 / 82.4. CLI scenario/patrol batch PR #117 Coverage measured 83.98 / 78.47 / 89.18 / 83.82 and staged thresholds at 83.4 / 77.9 / 88.6 / 83.3. CLI declaration/piece batch PR #118 Coverage measured 84.40 / 78.82 / 89.29 / 84.24 and staged thresholds at 83.8 / 78.2 / 88.7 / 83.6. CLI readable command batch PR #119 Coverage measured 85.65 / 79.52 / 89.83 / 85.52 and staged thresholds at 84.8 / 79.1 / 89.4 / 84.8. CLI snapshot/piece batch PR #120 Coverage measured 86.17 / 80.32 / 90.02 / 86.07 and staged thresholds at 85.3 / 79.8 / 89.7 / 85.3. CLI reference generator script batch PR #121 Coverage measured 86.23 / 80.27 / 90.04 / 86.13 and staged thresholds at 85.7 / 79.8 / 89.7 / 85.7. Package-assets generator script batch PR #122 Coverage measured 86.48 / 80.44 / 90.09 / 86.38 and staged thresholds at 86.0 / 79.9 / 89.7 / 85.9. Packed consumer smoke orchestrator batch PR #123 Coverage measured 86.77 / 80.43 / 90.33 / 86.66 and staged thresholds at 86.2 / 80.0 / 90.0 / 86.2. Packed consumer types attestation batch PR #124 Coverage measured 86.81 / 80.41 / 90.38 / 86.70 and staged thresholds at 86.3 / 80.1 / 90.1 / 86.3. Packed consumer install smoke batch PR #125 Coverage measured 87.28 / 80.83 / 90.47 / 87.19 and staged thresholds at 86.7 / 80.5 / 90.2 / 86.7. Simulation engine defensive branch batch PR #126 Coverage measured 87.32 / 80.88 / 90.47 / 87.23 and stages thresholds at 86.8 / 80.6 / 90.3 / 86.8. Selectors edge-mask branch cleanup PR #127 Coverage measured 87.32 / 80.89 / 90.47 / 87.23 and stages thresholds at 86.8 / 80.7 / 90.3 / 86.8. Command handler branch batch PR #128 Coverage measured 87.37 / 80.98 / 90.47 / 87.28 and stages thresholds at 86.9 / 80.8 / 90.3 / 86.9. Ratchet against CI-measured merged coverage after each ≤200 LOC test batch; E8’s 100/100/100/100 flip is complete. NOTE: scenario.ts:1189 (spawn-group warning map) + 1204 (patrol warning map) effectively unreachable — spawn groups never emit warnings; patrol warning in patrol-route planning needs >1 waypoint + 0 segments (contradictory). Skip these arms.
    • World-rules system branch batch PR #129 Coverage measured 87.37 / 81.01 / 90.47 / 87.28, reached 100 / 100 / 100 / 100 for src/systems/world-rules-system.ts, and stages thresholds at 86.9 / 80.9 / 90.3 / 86.9.
    • Command-dispatch branch cleanup PR #130 Coverage measured 87.37 / 81.02 / 90.47 / 87.28, reached 100 / 100 / 100 / 100 for src/systems/command-dispatch.ts, and stages thresholds at 86.9 / 81.0 / 90.3 / 86.9.
    • Systems/runtime branch cleanup PR #131 Coverage measured 87.44 / 81.27 / 90.47 / 87.36, reached 100 / 100 / 100 / 100 for src/systems/systems.ts, src/systems/events.ts, src/systems/tick.ts, src/runtime/asset-root.ts, and src/runtime/runtime.ts, and staged thresholds at 87.0 / 81.1 / 90.3 / 87.0.
    • Simulation engine branch closure PR #132 Coverage measured 87.44 / 81.60 / 90.47 / 87.36, reached 100 / 100 / 100 / 100 for src/simulation/engine.ts, and staged thresholds at 87.0 / 81.2 / 90.3 / 87.0.
    • Script-validator branch cleanup PR #133 Coverage measured 87.44 / 81.73 / 90.47 / 87.36, reached 100 / 100 / 100 / 100 for src/simulation/script-validators.ts, and staged thresholds at 87.0 / 81.3 / 90.3 / 87.0.
    • Pieces branch cleanup PR #134 Coverage measured 87.44 / 81.80 / 90.47 / 87.36, reached 100 / 100 / 100 / 100 for src/pieces/pieces.ts, and staged thresholds at 87.0 / 81.4 / 90.3 / 87.0.
    • Occupancy branch cleanup PR #135 Coverage measured 87.44 / 81.81 / 90.47 / 87.36, reached 100 / 100 / 100 / 100 for src/gameboard/occupancy.ts, and staged thresholds at 87.0 / 81.5 / 90.3 / 87.0.
    • Manifest schema branch cleanup PR #136 Coverage measured 87.44 / 81.86 / 90.47 / 87.36, reached 100 / 100 / 100 / 100 for src/manifest/schema.ts, and staged thresholds at 87.0 / 81.6 / 90.3 / 87.0.
    • Catalog treatments branch cleanup PR #137 Coverage measured 87.44 / 81.89 / 90.47 / 87.36, reached 100 / 100 / 100 / 100 for src/scenario/catalog-treatments.ts, and staged thresholds at 87.0 / 81.7 / 90.3 / 87.0.
    • Catalog guide-data branch cleanup PR #138 Coverage measured 87.44 / 81.90 / 90.47 / 87.36, reached 100 / 100 / 100 / 100 for src/scenario/catalog-guide-data.ts, and staged thresholds at 87.0 / 81.8 / 90.3 / 87.0.
    • CLI/source-root branch cleanup PR #139 Coverage measured 88.25 / 82.55 / 91.27 / 88.19, reached 100 / 100 / 100 / 100 for scripts/smoke/types.ts, src/cli/commands/bootstrap/target.ts, src/cli/commands/manifest.ts, src/cli/commands/validate.ts, and src/guides/simple-rpg/exercises.ts; also closed branch gaps in src/cli/commands/extract.ts. Staged thresholds at 87.0 / 81.9 / 90.3 / 87.0.
    • Interop compatibility branch cleanup PR #140 Coverage measured 88.26 / 82.60 / 91.27 / 88.20, reached 100 / 100 / 100 / 100 for src/interop/compatibility.ts after KayKit tile placement, facing defaults, spawn fallback metadata, rigged default roles, idle/first animation fallback, and removal of an unreachable rigged-non-unit warning. Staged thresholds at 87.1 / 82.0 / 90.3 / 87.1.
    • CLI usage branch cleanup PR #141 Coverage measured 88.29 / 82.60 / 91.31 / 88.23, reached 100 / 100 / 100 / 100 for src/cli/usage.ts through direct import coverage of HELP_TEXT and usage(). Staged thresholds at 87.2 / 82.1 / 90.4 / 87.2.
    • Bootstrap upstream-layout cleanup PR #142 Coverage measured 88.31 / 82.62 / 91.31 / 88.25, reached 100 / 100 / 100 / 100 for src/cli/commands/bootstrap/upstream-layout.ts by covering the FREE-with-units rejection and removing redundant EXTRA units/nullish texture branches. Staged thresholds at 88.1 / 82.4 / 90.9 / 88.1.
    • CLI validate-plan exit cleanup PR #143 Coverage measured 88.37 / 82.64 / 91.42 / 88.29, reached focused 100 / 100 / 100 / 100 for src/cli/commands/validate-plan.ts by exercising the validation-error process.exit(1) path; merged report still carries a browser-map statement-id artifact for the same line. Staged thresholds at 88.2 / 82.5 / 91.0 / 88.2.
    • Gameboard terrain branch cleanup PR #144 Coverage measured 88.38 / 82.70 / 91.42 / 88.30, reached 100 / 100 / 100 / 100 for src/gameboard/terrain.ts by covering plan default fallbacks, same-order placement sort, custom tile tags, river crossing overlays, single-edge river masks, and sloped road overlays while removing unreachable internal terrain branches. Staged thresholds at 88.3 / 82.6 / 91.1 / 88.2.
    • CLI compatibility exit cleanup PR #145 Coverage measured 88.43 / 82.78 / 91.42 / 88.35, reached 100 / 100 / 100 / 100 for src/cli/commands/compatibility.ts by covering --failOnWarning warning exits and fatal bounds-error exits. Staged thresholds at 88.3 / 82.7 / 91.1 / 88.3.
    • CLI guide API/role cleanup PR #146 Coverage measured 88.46 / 82.84 / 91.42 / 88.39, reached 100 / 100 / 100 / 100 for src/cli/commands/guide-apis.ts and src/cli/commands/guide-roles.ts by covering empty selections, unfiltered API summary overflow, and removing unreachable selected-value/nullish and role truncation branches. Staged thresholds at 88.4 / 82.8 / 91.1 / 88.3.
    • CLI validate-recipe exit cleanup PR #147 Coverage measured 88.48 / 82.87 / 91.46 / 88.41, reached 100 / 100 / 100 / 100 for src/cli/commands/validate-recipe.ts by covering readable recipe validation errors and the fatal process.exit(1) branch. Staged thresholds at 88.4 / 82.8 / 91.2 / 88.4.
    • Coordinates projection cleanup PR #148 Coverage measured 88.50 / 82.93 / 91.46 / 88.43, reached 100 / 100 / 100 / 100 for src/coordinates/projection.ts by covering sloped road projection, river crossing projection, custom placement tie sorting, and removing unreachable projection defaults/helpers. Staged thresholds at 88.4 / 82.9 / 91.2 / 88.4.
    • Packed install smoke branch cleanup PR #149 Coverage measured 88.51 / 82.99 / 91.46 / 88.44, reached 100 / 100 / 100 / 100 for scripts/smoke/pack-install.ts by covering invalid pack metadata, missing plan/scenario count fallbacks, non-array SimpleRPG exercise evidence, and retained temp-app logging. Staged thresholds at 88.45 / 82.93 / 91.3 / 88.41.
    • CLI reference generator branch cleanup PR #150 Coverage measured 88.51 / 83.07 / 91.46 / 88.44, reached 100 / 100 / 100 / 100 for scripts/generate-cli-reference.ts by covering default generator option resolution, injected IO execution, direct-run predicate branches, and excluding only the thin executable entrypoint guard. Staged thresholds at 88.5 / 83.0 / 91.35 / 88.43.
    • SimpleRPG executable smoke branch cleanup PR #151 Coverage measured 88.55 / 83.11 / 91.54 / 88.47, reached 100 / 100 / 100 / 100 for src/guides/simple-rpg/smoke.ts by covering plan tile fallback/empty-plan failure, recipe error-count helpers, layout fill rule id fallback, and the FREE manifest asset lookup without the literal-key lint warning. Staged thresholds at 88.52 / 83.05 / 91.44 / 88.44.
    • Package-assets generator branch cleanup PR #152 Coverage measured 88.57 / 83.19 / 91.54 / 88.50, reached 100 / 100 / 100 / 100 for scripts/generate-package-assets.ts by covering default/injected dependency resolution, FREE/EXTRA write behavior, source-count failure, argument parsing, and the direct-run predicate while ignoring only the thin executable entrypoint guard. Staged thresholds at 88.55 / 83.14 / 91.5 / 88.46.
    • CLI snapshot branch cleanup PR #153 Coverage measured 88.61 / 83.21 / 91.58 / 88.53, reached 100 / 100 / 100 / 100 for src/cli/commands/snapshot.ts by covering invalid-plan validation exits, recipe compile failure after allowInvalid, stdout snapshot output, and plan/recipe/scenario option variants. Staged thresholds at 88.57 / 83.19 / 91.53 / 88.49.
    • CLI doctor/validate-manifest + scenario registry branch cleanup PR #154 Coverage measured 88.72 / 83.40 / 91.62 / 88.63, reached focused zero-miss coverage for src/cli/commands/doctor.ts, src/cli/commands/validate-manifest.ts, and src/scenario/registry.ts by covering coverage delegation, existing-source/missing-montage reporting, readable empty-manifest summaries, JSON output, fatal manifest validation issue exits, z-origin geometry warnings, terrainless manifest tile inference, default declaration asset/source normalization, object declaration application, custom placement kind defaults, and support-tile registry analysis while removing private unreachable layer/median guards. Staged thresholds at 88.64 / 83.28 / 91.56 / 88.54.
    • CLI guide-permutations/patrol-script branch cleanup PR #155 Coverage measured 88.83 / 83.50 / 91.70 / 88.74, reached focused zero-miss coverage for src/cli/commands/guide-permutations.ts and src/cli/commands/patrol-script.ts by covering manifest-backed missing permutation assets, readable missing-asset reporting, assignment-file array variants, missing-assignment validation, readable warning/error reporting, and fatal error/warning exits. Staged thresholds at 88.72 / 83.42 / 91.64 / 88.65.
    • Coordinates/quests branch cleanup PR #156 Coverage measured 88.89 / 83.67 / 91.70 / 88.78, reached 100 / 98.91 / 100 / 100 for src/quests/quests.ts and closed the remaining merged misses for src/coordinates/coordinates.ts by covering quest metadata/lookups, reach-tile pending progress, fallback progress preservation, source-less collision evaluation, non-quest entity rejection, canonical-key path reconstruction, spawn passability, and exported heap boundary cases while removing private unreachable coordinate/quest guards. Staged thresholds at 88.78 / 83.55 / 91.64 / 88.70.
    • CLI command-gap cleanup PR #157 Coverage measured 88.95 / 83.74 / 91.73 / 88.83, advanced src/cli/commands to 85.41 / 71.20 / 86.04 / 85.85 and guide-usages.ts to 100 / 92.30 / 100 / 100 by covering readable guide summaries, edition-scope and small-result filters, missing manifest asset exits, synthetic source-root extract/declarations success, doctor source reporting, and validation/compatibility fatal exits. Staged thresholds at 88.84 / 83.62 / 91.66 / 88.76.
    • CLI summarize-scenario cleanup PR #158 Coverage measured 88.98 / 83.88 / 91.73 / 88.86, reached 100 / 93.10 / 100 / 100 for src/cli/commands/summarize-scenario.ts by covering validation-error exits, allow-invalid readable summaries without a compiled board, warning-only failOnWarning exits, and readable title/top-asset/patrol summary fallbacks. Staged thresholds at 88.87 / 83.76 / 91.67 / 88.79.
    • Spawn-group/quest branch cleanup PR #159 Coverage measured 89.02 / 83.97 / 91.80 / 88.89, reached focused zero-miss coverage for src/gameboard/spawn-groups.ts by covering terrain/elevation/tag candidate filters, found/lower-cost/shorter/empty route selection, and removing unreachable route tie-key and warning-aggregate branches; removed the redundant quest metadata fallback after normalization and kept no-metadata quest spawn coverage. Staged thresholds at 88.90 / 83.86 / 91.74 / 88.82.
    • Command-handler branch cleanup PR #160 Coverage measured 89.02 / 84.11 / 91.80 / 88.89, reached focused zero-miss coverage for src/commands/commands.ts by covering source-less/unreachable/manual move previews, completed same-tile move execution, no-effect handler normalization, empty actor-target selection, single-handler presets, stale actor/placement removals, and successful placement removal while removing post-preview unreachable movement/handler defensive branches. Staged thresholds at 88.91 / 84.00 / 91.75 / 88.84.
    • Coverage merge location-key cleanup PR #161 Coverage measured 89.50 / 84.06 / 93.03 / 89.42, fixes cross-harness Istanbul statement/function/branch id and column drift by merging counters by source location with unique line fallback and ignoring zero-only unmatched browser entries. Staged thresholds at 89.10 / 84.00 / 92.00 / 89.00.
    • Dead built-CLI smoke cleanup PR #162 Coverage measured 91.81 / 85.47 / 94.01 / 91.81, removes stale unreferenced scripts/smoke-built-cli.ts after test:cli was deleted and rewrites current docs/commentary to the actual Vitest/coverage workflow. Staged thresholds at 91.50 / 85.30 / 93.80 / 91.50.
    • CLI entrypoint dispatcher PR #163 Coverage measured 92.55 / 85.85 / 95.60 / 92.57, reached 100 / 100 / 100 / 100 for src/cli/cli.ts through controlled side-effect imports with mocked citty, usage, and subcommand modules. Staged thresholds at 92.30 / 85.80 / 95.20 / 92.30.
    • Showcase promotion script PR #164 Coverage measured 93.07 / 85.96 / 95.88 / 93.07, reached 100 / 74 / 100 / 100 for scripts/promote-showcases.ts by extracting injected promoteShowcases()/runPromoteShowcases() helpers and covering check/promote/failure/quality paths. Staged thresholds at 92.80 / 85.85 / 95.65 / 92.80.
    • KayKit guide extractor PR #165 Coverage measured 93.57 / 86.22 / 96.32 / 93.60, reached 100 / 78.66 / 100 / 100 for scripts/extract-kaykit-guide.ts by extracting injected parser/runner/renderer helpers and covering Swift, portable, Windows lookup, missing-PDF, no-renderer, no-page, and command-failure paths. Staged thresholds at 93.30 / 86.10 / 96.00 / 93.30.
    • Spawn-groups command PR #166 Coverage measured 93.65 / 86.35 / 96.36 / 93.68 in CI (local reference-enabled proof read 94.01 / 86.68 / 96.55 / 94.03), reached 100 / 100 / 100 / 100 for src/cli/commands/spawn-groups.ts by covering missing --groups, validation-error exits, JSON output, spawn-plan error exits, and documenting the currently unreachable aggregate-warning exit. Staged thresholds at 93.50 / 86.30 / 96.30 / 93.50.
    • Blueprint command PR #167 local reference-enabled proof measured 94.33 / 87.35 / 96.74 / 94.34, advanced src/cli/commands/blueprint.ts to 98.33 / 93.47 / 90.90 / 99.14 by covering wrapped config parsing, CLI overrides, scenario/interop predicates, payload summaries, readable warnings, JSON output, warning exits, and scenario error exits; defensive output guards stay annotated because shouldInspectBlueprintScenario and shouldEmitBlueprintInterop make them unreachable through the public command flow. Staged thresholds at 93.90 / 86.90 / 96.40 / 93.90.
    • Guide-scenarios command PR #168 local reference-enabled proof measured 94.58 / 87.67 / 96.98 / 94.58, reached 100 / 93.10 / 100 / 100 for src/cli/commands/guide-scenarios.ts by covering guide filters, include-treatment payloads, missing-manifest asset reporting and exits, markdown stdout, JSON file output, invalid asset-scope errors, and the missing-treatment guard with restored fixture state. Staged thresholds at 94.20 / 87.20 / 96.60 / 94.20.
    • CLI shared-helper PR #169 local reference-enabled proof measured 95.06 / 88.12 / 97.17 / 95.08, advanced src/cli/_shared.ts to 87.86 / 83.16 / 94.12 by covering registry and piece-registry validation, output emission, GLTF metadata extraction, piece flag/source URL parsing, and readable helper reports. Staged thresholds at 94.60 / 87.70 / 96.80 / 94.60.
    • Patrol-routes command PR #170 local reference-enabled proof measured 95.15 / 88.27 / 97.21 / 95.17, advanced src/cli/commands/patrol-routes.ts to 95.83 / 90.90 / 100 / 95.74 by covering missing routes, malformed scenarios, validation exits, spawn-group exits, JSON and file output, scenario seed fallbacks, and route-error readable output. The remaining route warning/fail-on-warning arm depends on the documented contradictory route-planning warning path. Staged thresholds at 94.70 / 87.80 / 96.85 / 94.70.
    • Guide-assets command PR #171 local reference-enabled proof measured 95.25 / 88.45 / 97.36 / 95.25, reached 100 / 97.67 / 100 / 100 for src/cli/commands/guide-assets.ts by covering single-asset selected payloads, file output, readable small/overflow summaries, each empty-selection filter branch, and the no-match command error. Staged thresholds at 94.80 / 88.00 / 97.00 / 94.80.
    • Place-piece command PR #172 local reference-enabled proof measured 95.37 / 88.66 / 97.40 / 95.38, reached 100 / 97.29 / 100 / 100 for src/cli/commands/place-piece.ts by covering input validation, piece-registry selection failures, JSON/file/readable output, out-plan writes, invalid-plan exits, no-placement min-count exits, and seed/id-prefix placement output. The remaining coordinate-string readable branch is defensive because generated piece placements use coordinate objects. Staged thresholds at 94.90 / 88.10 / 97.10 / 94.90.
    • Analyze-layout command PR #173 local reference-enabled proof measured 95.48 / 88.88 / 97.44 / 95.49, reached 100 / 100 / 100 / 100 for src/cli/commands/analyze-layout.ts by covering input/rules validation, rule array and object parsing, file and CLI seed resolution, JSON/file/readable output, out-plan writes, invalid-plan exits, error exits, and fail-on-warning exits. Staged thresholds at 95.00 / 88.30 / 97.20 / 95.00.
    • Summarize-plan command PR #174 local reference-enabled proof measured 95.66 / 89.09 / 97.52 / 95.67, reached 100 / 100 / 100 / 100 for src/cli/commands/summarize-plan.ts by covering exact-input and JSON-shape validation, recipe/scenario compile exits, plan validation exits, validation warning exits, readable none/EXTRA top-asset branches, out/outPlan writes, and blueprint/config input aliases. Staged thresholds at 95.20 / 88.60 / 97.30 / 95.20.
    • Simulate-scenario command PR #175 local reference-enabled proof measured 95.82 / 89.41 / 97.59 / 95.83, reached 100 / 92.42 / 100 / 100 for src/cli/commands/simulate-scenario.ts by covering missing-input and malformed-scenario guards, scenario/script validation exits, JSON success and expectation-failure outputs, readable expectation-failure summaries, blocked-quest exits, and actor-target/mutation readable fallbacks. Staged thresholds at 95.30 / 88.90 / 97.40 / 95.30.
    • Piece command PR #176 local reference-enabled proof measured 95.85 / 89.54 / 97.59 / 95.86, reached 100 / 100 / 100 / 100 for src/cli/commands/piece.ts by covering missing-asset validation, derived asset and piece ids, default source and omitted role/report branches, explicit attribution/file output, warning exits, and fatal report error exits. Staged thresholds at 95.40 / 89.00 / 97.40 / 95.40.
    • Pieces command PR #177 local reference-enabled proof measured 95.91 / 89.68 / 97.59 / 95.92, reached 100 / 100 / 100 / 100 for src/cli/commands/pieces.ts by covering missing-input and conflicting placement-input validation, rule/source-url/placement payload variants, file output, registry analysis errors, registry warning exits, and placement-warning exits while marking the defensive placement-error guard unreachable because registry analysis blocks invalid selections before inspection. Staged thresholds at 95.45 / 89.10 / 97.40 / 95.45.
    • Bootstrap core PR #178 local reference-enabled proof measured 96.32 / 90.15 / 97.59 / 96.36, reached 100 / 100 / 100 / 100 for src/cli/commands/bootstrap/core.ts by covering default output resolution, same-size hash drift, non-empty targets without sidecars, malformed/oversized/escaping sidecars, source-format inclusion under the GLTF root, missing texture directories, deep/corrupt zip failures, successful mocked GitHub downloads, stream cleanup, and HTTP failure fallbacks; fixed extension parsing to use the file basename and marked only defensive library/filesystem race guards unreachable through the public zip path. Staged thresholds at 95.80 / 89.70 / 97.40 / 95.80.
    • Validate-simulation command PR #179 local reference-enabled proof measured 96.36 / 90.25 / 97.63 / 96.39, reached 100 / 100 / 100 / 100 for src/cli/commands/validate-simulation.ts by covering missing scenario/script guards, non-object scenario validation, JSON/readable output fallbacks with empty actor/quest lists, actor/quest JSON mapping, out-plan writes, and fatal script validation exits while simplifying redundant script-step array guards after readSimulationScript validation. Staged thresholds at 95.90 / 89.80 / 97.40 / 95.90.
    • Validate-scenario command PR #180 local reference-enabled proof measured 96.39 / 90.41 / 97.71 / 96.41, reached 100 / 100 / 100 / 100 for src/cli/commands/validate-scenario.ts by covering the missing-scenario guard, compiled-plan output, JSON/runtime actor and quest payloads, authored/empty fallback payloads when validation errors skip runtime creation, readable spawn/patrol summaries, and fatal validation exits while simplifying the unreachable runtime-plan fallback after inspection already compiles the plan. Staged thresholds at 96.00 / 89.90 / 97.40 / 96.00.
    • Pieces-from-assets command PR #181 local reference-enabled proof measured 96.57 / 90.74 / 97.75 / 96.60, reached 100 / 100 / 100 / 100 for src/cli/commands/pieces-from-assets.ts by covering missing inputs, no-model scans, override payload validation, single-file and multi-root asset inputs, absolute-path/includeReport payloads, prefix/tag file output, override-warning fail-on-warning exits, registry warning/error printing, and fatal registry-error exits while pairing scanned paths with source records and relying on the scanned-root invariant for relative asset paths. Staged thresholds at 96.10 / 90.20 / 97.40 / 96.10.
    • Guide-render-requests command PR #182 local reference-enabled proof measured 96.64 / 90.84 / 97.79 / 96.66, reached 100 / 100 / 100 / 100 for src/cli/commands/guide-render-requests.ts by covering empty selections, readable URL output, JSON grouped payloads, edition-scoped file output, missing manifest asset reporting, fatal missing-asset exits, and request overflow summaries. Staged thresholds at 96.20 / 90.30 / 97.40 / 96.20.
    • Guide-assets command PR #183 local reference-enabled proof measured 96.64 / 90.85 / 97.79 / 96.66, reached 100 / 100 / 100 / 100 for src/cli/commands/guide-assets.ts by removing the unreachable selected-asset nullish fallback after the assetIdFilter.length === 1 guard. Staged thresholds at 96.20 / 90.40 / 97.40 / 96.20.
    • Summarize-scenario command PR #184 local reference-enabled proof measured 96.64 / 90.88 / 97.79 / 96.66, reached 100 / 100 / 100 / 100 for src/cli/commands/summarize-scenario.ts by covering readable EXTRA actor asset output, including the top-asset * suffix and non-empty actor extra asset list. Staged thresholds at 96.20 / 90.50 / 97.40 / 96.20.
    • CLI command-output PR #185 local reference-enabled proof measured 96.68 / 90.98 / 97.87 / 96.69, reached 100 / 100 / 100 / 100 for src/cli/commands/place-piece.ts and advanced blueprint, patrol-routes, and simulate-scenario command-output gaps through blueprint default-shape/error/warning/scenario-validation exits, readable actor-target and mutation output, and documented defensive display branches with no current public producer. Staged thresholds at 96.30 / 90.60 / 97.50 / 96.30.
    • CLI branch-artifact PR #186 local reference-enabled proof measured 96.69 / 91.08 / 97.87 / 96.70, reached 100 / 100 / 100 / 100 for src/cli/commands/blueprint.ts, src/cli/commands/patrol-routes.ts, and src/cli/commands/simulate-scenario.ts by covering the empty patrol-route display, JSON simulation report file output, and reducing redundant CLI blueprint numeric flag branches. Staged thresholds at 96.30 / 90.70 / 97.50 / 96.30.
    • Gameboard patrol-route PR #187 local reference-enabled proof measured 96.81 / 91.19 / 97.91 / 96.81, reached 100 / 100 / 100 / 100 for src/gameboard/patrol-routes.ts by covering explicit-start/default route diagnostics, open non-loop route warnings, route-set warning aggregation, and documenting public-path-unreachable waypoint-pair invariants. Staged thresholds at 96.40 / 90.80 / 97.50 / 96.40.
    • Gameboard navigation PR #188 local reference-enabled proof measured 96.92 / 91.37 / 97.95 / 96.91, reached 100 / 100 / 100 / 100 for src/gameboard/navigation.ts by covering blocked-start/blocked-goal path branches, reachability sorting and wrapper output, movement-cost fallbacks, malformed key diagnostics, and documented heap/map invariants maintained by the exported planners. Staged thresholds at 96.50 / 91.00 / 97.60 / 96.50.
    • Patrol runtime PR #189 local reference-enabled proof measured 96.97 / 91.57 / 97.99 / 96.96, reached 100 / 100 / 100 / 100 for src/patrol/patrol.ts by covering route snapshot sorting, current-waypoint fallbacks, blocked movement fallback context, resetless blocked movement requests, completed-route wrap/end states, missing-trait diagnostics, and sparse waypoint invariant errors while removing redundant post-normalization segment-cost fallback branching. Staged thresholds at 96.60 / 91.20 / 97.70 / 96.60.
    • Scenario branch cleanup PR #190 CI-measured merged proof measured 96.65 / 91.55 / 97.91 / 96.65, reached 100 / 95.95 / 100 / 100 for src/scenario/scenario.ts by covering collision objective tile targets, deep clone coverage for scenario metadata/navigation/agent options, actor asset aggregation, and documenting only public-path-unreachable spawn-resolution and warning diagnostics. Staged thresholds at 96.50 / 91.40 / 97.80 / 96.50.
    • Movement edge cleanup local merged proof measured 97.14 / 92.00 / 98.10 / 97.14, reached 100 / 98.18 / 100 / 100 for src/movement/movement.ts by covering stale completed paths, malformed sparse path diagnostics, newly blocked stale paths, missing board/placement state diagnostics, no-agent movement-budget fallback, and fixing movement-agent writes to add the trait when absent. Staged thresholds at 96.70 / 91.60 / 97.90 / 96.70.
    • Movement final branch cleanup local merged proof measured 97.14 / 92.02 / 98.10 / 97.14, reached 100 / 100 / 100 / 100 for src/movement/movement.ts by covering the idle path-state fallback and removing the unreachable entity-side missing-placement error branch. Staged thresholds at 96.70 / 91.65 / 97.90 / 96.70.
    • Showcase promotion branch cleanup local merged proof measured 97.14 / 92.18 / 98.10 / 97.14, reached 100 / 100 / 100 / 100 for scripts/promote-showcases.ts by covering default workspace/target/dependency fallbacks, promotion-mode runner success output, and Error quality analyzer reporting. Staged thresholds at 96.70 / 91.75 / 97.90 / 96.70.
    • KayKit guide extractor branch cleanup local merged proof measured 97.14 / 92.36 / 98.10 / 97.14, reached 100 / 100 / 100 / 100 for scripts/extract-kaykit-guide.ts by covering default dependency/repo-root fallbacks, process-platform command detection, non-Error runner failures, null Swift exit status fallback, and simplifying page-number sorting to the already-filtered filename invariant. Staged thresholds at 96.70 / 91.90 / 97.90 / 96.70.
    • Packed consumer smoke branch cleanup local merged proof measured 97.17 / 92.52 / 98.10 / 97.17, reached 100 / 100 / 100 / 100 for scripts/smoke-packed-consumer.ts by covering non-Error phase failures, default context/process/filesystem fallbacks, default runner dependency wiring on safe failure paths, and the injectable direct-run predicate while ignoring only the thin executable guard. Staged thresholds at 96.75 / 92.00 / 97.90 / 96.75.
    • Scenario final branch cleanup local merged proof measured 97.17 / 92.72 / 98.10 / 97.17, reached 100 / 100 / 100 / 100 for src/scenario/scenario.ts by covering unknown-id diagnostics, omitted scenario arrays/objectives, sparse navigation clone options, unresolved-summary actor copy variants, and removing redundant claimant/spawn-index invariant fallbacks. Staged thresholds at 96.75 / 92.20 / 97.90 / 96.75.
    • Scenario catalog branch cleanup local merged proof measured 97.25 / 92.83 / 98.22 / 97.25, reached 100 / 100 / 100 / 100 for src/scenario/catalog.ts by covering texture/faction/unit guards, empty edition-scope usage filters, Markdown option branches, missing-treatment usage/role-count behavior, and preserving default asset-id sort order. Staged thresholds at 96.80 / 92.30 / 98.00 / 96.80.
    • Ingest duplicate branch cleanup local merged proof measured 97.35 / 93.08 / 98.22 / 97.36, reached 100 / 100 / 100 / 100 for src/ingest/ingest.ts by covering missing manifest roots, manifest JSON output, duplicate asset-id suffix allocation, sparse GLTF metadata, optional texture discovery, unsupported categories, symlink skipping, and simplifying private fallback branches to the generated-manifest invariants. Staged thresholds at 96.90 / 92.60 / 98.00 / 96.90.
    • script-validators.ts 100 / 100 / 100 / 100; remaining simulation-surface gaps are in assertions/patrol/report-adjacent helpers, not authored-script validators.
    • engine.ts 100 / 100 / 100 / 100 — direct mutation defaults, patrol simulation route-set branch, actor-target default spreads, and unreachable koota placement-state fallbacks closed.
    • assertions.ts 100 / 100 / 100 / 100 — expectation branches and actor-target matching are zero-miss in merged coverage.
    • report.ts 100 / 100 / 100 / 100 — copyQuestObjective tile/targetTile branches done.
    • patrol.ts 100 / 100 / 100 / 100 — route sorting, blocked fallback context, completed wrap/end transitions, and malformed entity diagnostics closed.
    • layout.ts 87.13 → ratcheting; normalizeArchetypes, resolveArchetype, selectLayout count=0.
    • quests.ts merged zero-miss after metadata normalization cleanup; historical objective rollover coverage remains in place.
    • manifest/schema.ts 100 / 100 / 100 / 100 — unit-style exclusion plus malformed-id diagnostic fallback branches closed.
    • scenario/catalog-treatments.ts 100 / 100 / 100 / 100 — source-path sort tie plus fallback neutral-structure and prop treatment branches closed.
    • scenario/catalog-guide-data.ts 100 / 100 / 100 / 100 — private guide scenario input now requires authored public APIs instead of carrying an unreachable fallback.
    • scenario/catalog.ts 100 / 100 / 100 / 100 — public taxonomy guards, usage filter edges, Markdown option branches, missing-treatment guards, and asset-id sort behavior closed.
    • actors.ts 88.93 → register + navigationProfile action wrappers.
    • pieces.ts 100 / 100 / 100 / 100 — declaration asset defaults, pooled object-archetype checks, placement count fallbacks, and compatibility override tags closed.
    • scenario/scenario.ts 100 / 100 / 100 / 100 — clone/summary option branches, collision target tile validation, unknown scenario ids, optional quest objectives, allocator claimant labels, unset spawn indexes, omitted cloned navigation fields, and unresolved-summary actor copies closed.
    • gameboard.ts 92.21 → addUnitPreset role variants.
    • bootstrap.ts 75 → verifyBootstrap unsafe-sidecar + missing-file.
    • movement.ts 100 / 100 / 100 / 100 — stale completed paths, idle fallback, sparse path diagnostics, blocked stale paths, missing board/placement state diagnostics, no-agent budget fallback, and add-if-absent agent writes covered.
    • interop/compatibility.ts 100 / 100 / 100 / 100 — tile-compatible placement, facing defaults, spawn fallback metadata, rigged default roles, animation fallback chain, and unreachable rigged-non-unit warning removed.
    • cli/usage.ts 100 / 100 / 100 / 100 — direct import covers HELP_TEXT, console output, and requested exit code.
    • cli/commands/bootstrap/upstream-layout.ts 100 / 100 / 100 / 100 — FREE-with-units rejection covered; redundant EXTRA units and nullish texture fallback branches removed.
    • cli/commands/validate-plan.ts 100 / 100 / 100 / 100 — validation-error output plus process.exit(1) branch covered.
    • cli/commands/compatibility.ts 100 / 100 / 100 / 100 — warning and fatal error process.exit(1) branches covered.
    • cli/commands/guide-apis.ts 100 / 100 / 100 / 100 — empty selection, selected payload, and readable overflow summary covered.
    • cli/commands/guide-roles.ts 100 / 100 / 100 / 100 — empty selection and selected payload covered; fixed readable output to list all current roles instead of carrying unreachable overflow.
    • cli/commands/validate-recipe.ts 100 / 100 / 100 / 100 — readable validation errors plus fatal process.exit(1) branch covered.
    • coordinates/projection.ts 100 / 100 / 100 / 100 — sloped road/crossing projection, custom placement tie sort, and unreachable defaults/helpers closed.
    • gameboard/terrain.ts 100 / 100 / 100 / 100 — default plan fallbacks, placement tie sort, authored tags, river crossing/single-edge river overlays, and sloped road overlays covered; unreachable internal branches removed.
    • gameboard/spawn-groups.ts, gameboard/patrol-routes.ts, and gameboard/navigation.ts 100 / 100 / 100 / 100.
    • ingest.ts 100 / 100 / 100 / 100 — duplicate suffix allocation, sparse GLTF metadata, texture discovery, symlink skip, missing-root errors, and manifest JSON output covered; private fallback invariants simplified.
    • Browser branch-map cleanup batch local merged proof measured 97.35 / 93.16 / 98.22 / 97.36, reached merged zero-miss coverage for src/coordinates/projection.ts, src/gameboard/terrain.ts, and src/simulation/engine.ts by exercising river-crossing projection/terrain and direct simulation mutation system branches in Chromium while simplifying actor-update mutation reads to use the updated entity. Staged thresholds at 96.90 / 92.70 / 98.00 / 96.90.
    • Gameboard/validation branch cleanup local merged proof measured 97.61 / 93.74 / 98.21 / 97.62, reached merged zero-miss coverage for src/gameboard/gameboard.ts and src/rules/validation.ts by covering builder default/variant/boundary branches, invalid authored placement/connectivity validation diagnostics, EXTRA asset references, and declaration adjacency boundaries while documenting only current public-path-impossible fallback guards. Staged thresholds at 97.10 / 93.20 / 98.00 / 97.10.
    • Seeded rules branch cleanup local merged proof measured 97.78 / 94.10 / 98.29 / 97.80, reached merged zero-miss coverage for src/rules/rules.ts by covering seeded board defaults/degenerate shapes, density override exclusivity, piece-fill registry errors/empty selections/object archetypes, and option-level layout archetype fills while documenting deterministic built-in shape/path invariants. Staged thresholds at 97.30 / 93.60 / 98.10 / 97.30.
    • Recipe branch cleanup local merged proof measured 97.84 / 94.60 / 98.40 / 97.86, reached merged zero-miss coverage for src/scenario/recipe.ts by covering remaining serializable step dispatch and clone paths, raw malformed action diagnostics, empty/no-seed/piece-only generation, local/global archetype merges, and deep criteria footprint/distance/preference cloning while fixing setTileAsset recipe tag cloning. Staged thresholds at 97.40 / 94.10 / 98.20 / 97.40.
    • Koota branch cleanup local merged proof measured 98.00 / 94.96 / 98.52 / 98.03, reached merged zero-miss coverage for src/koota/koota.ts by covering stale placement-index collision recovery, trait-corruption error paths, sparse occupancy relations, equal-order placement/occupancy sorting, default layer dispatch, computed placement offsets, and invalid tile-key inspection while simplifying query-required placement state reads. Staged thresholds at 97.50 / 94.50 / 98.30 / 97.50.
    • Blueprint branch cleanup local merged proof measured 98.19 / 95.62 / 98.52 / 98.23, reached merged zero-miss coverage for src/scenario/blueprint.ts by covering tiny-board diagnostics, authored town/harbor/road/river fallback IDs, generated defaults, semantic prop-cluster dressing, bridge de-duplication, empty-shape ridge failures, and defensive blueprint compiler invariants. Staged thresholds at 97.70 / 95.10 / 98.30 / 97.70.
    • Three branch cleanup local merged proof measured 98.39 / 95.99 / 98.75 / 98.44, reached merged zero-miss coverage for src/three/three.ts by covering asset URL defaults, animation URL overrides and clip fallbacks, transform/framing helpers, recursive user-data tagging, interaction lookup misses, stale-removal branches, no-parent sync, and sync load error collection/rethrow paths. Staged thresholds at 97.90 / 95.50 / 98.50 / 97.90.
    • Interop branch cleanup local merged proof measured 98.53 / 96.84 / 98.79 / 98.58, reached merged zero-miss coverage for src/interop/interop.ts by covering base snapshot inclusion flags, spawn candidates, legacy adjacency relation fallback, missing relation target reporting, out-of-board footprint filtering, scenario inclusion flags, unresolved actor/quest relation skips, spawn/patrol planning errors, runtime snapshot inclusion flags, and simulation report fallback variants while documenting only public-path-impossible interop serialization invariants. Staged thresholds at 98.00 / 96.30 / 98.50 / 98.00.
    • Layout branch cleanup local merged proof measured 98.79 / 97.74 / 98.87 / 98.85, reached merged zero-miss coverage for src/coordinates/layout.ts by covering layout archetype fallback registries, custom/radius/adjacent footprints, harbor facing inference, fill diagnostics, default layers, sparse serialized plans, and fill/spawn default seeds while documenting only public-path-impossible analyzer and slot-angle invariants. Staged thresholds at 98.30 / 97.20 / 98.60 / 98.30.
    • Actors branch cleanup local merged proof measured 99.15 / 98.79 / 98.99 / 99.23, reached merged zero-miss coverage for src/actors/actors.ts by covering actor kind inference, selector/string fallbacks, collision profiles, neighborhood aggregation, interaction command edges, actor-target sorting, disconnected target paths, and documenting only public-path-impossible ECS corruption/route sentinel invariants. Staged thresholds at 98.60 / 98.30 / 98.80 / 98.70.
    • CLI shared-helper cleanup local merged proof measured 99.65 / 99.57 / 99.18 / 99.75, reached 100 / 100 / 100 / 100 for src/cli/_shared.ts by covering manifest/registry validation, synthetic source manifest generation, plan reader exits, patrol route-set fallbacks, GLB metadata chunks, piece selection/source branches, and readable report edge cases while simplifying only guarded route and asset-id fallbacks. Staged thresholds at 99.30 / 99.20 / 99.00 / 99.40.
    • React cleanup local merged proof measured 100 / 100 / 100 / 100, reached merged zero-miss coverage for src/react/react.ts by covering provider factories, action-hook factories, empty-world fallbacks, coordinate-object tile hooks, queued revision disposal, and browser interop spawn-location merge counters while simplifying only unreachable/internal option guards. Remaining gaps: none in merged coverage. The explicit script.ts, script-validators.ts, bootstrap core, gameboard/gameboard.ts, rules/validation.ts, rules/rules.ts, scenario/recipe.ts, scenario/blueprint.ts, koota/koota.ts, three/three.ts, interop/interop.ts, coordinates/layout.ts, actors/actors.ts, cli/_shared.ts, and react/react.ts gaps are closed.
  • [DONE] E0h — Sweep remaining src/ files to 100% (paired with E0a per-PR). PR#10 closures advanced many of these in tandem with E0a. Status post-merge:
    • pieces/pieces.ts 100 / 100 / 100 / 100 in focused and merged unit coverage after declaration defaults, pooled-rule compatibility, placement fallback, and override-tag branch closure
    • gameboard/occupancy.ts 100 / 100 / 100 / 100 in merged coverage after explicit layout-footprint opt-out branch closure
    • quests/quests.ts merged zero-miss after metadata normalization cleanup; quest objective rollover + reward dispatch coverage remains in the existing slices
    • actors/actors.ts 100 / 100 / 100 / 100 in focused and merged coverage after actor kind inference, selector/string fallbacks, collision profiles, neighborhood aggregation, interaction command edges, actor-target sorting, disconnected target paths, and defensive ECS/route invariant cleanup.
    • scenario/scenario.ts 100 / 100 / 100 / 100 in merged coverage after unknown-id diagnostics, omitted scenario arrays/objectives, sparse navigation clone options, unresolved-summary actor copy variants, and invariant fallback cleanup
    • scenario/blueprint.ts 100 / 100 / 100 / 100 in merged coverage after tiny-board diagnostics, authored fallback ids/defaults, semantic prop-cluster dressing, bridge de-duplication, and defensive compiler invariants
    • scenario/catalog.ts 100 / 100 / 100 / 100 in merged coverage after public taxonomy guards, usage filter edges, Markdown option branches, missing-treatment guards, and asset-id sort behavior
    • ingest/ingest.ts 100 / 100 / 100 / 100 in merged coverage after duplicate suffix allocation, sparse GLTF metadata, texture discovery, symlink skip, missing-root errors, and manifest JSON output
    • manifest/schema.ts 100 / 100 / 100 / 100 in merged coverage after manifest normalization/filter combinations
    • gameboard/navigation.ts 100 / 100 / 100 / 100 in merged coverage after pathfinding and reachability edge branches
    • coordinates/layout.ts 100 / 100 / 100 / 100 in merged coverage after layout archetype fallback registries, custom/radius/adjacent footprints, harbor facing inference, fill diagnostics, default layers, sparse serialized plans, and fill/spawn default seed branch coverage.
    • three/three.ts 100 / 100 / 100 / 100 in merged coverage after URL fallback, animation fallback, transform/framing helper, user-data lookup, and sync error/stale branch coverage.
    • interop/interop.ts 100 / 100 / 100 / 100 in merged coverage after snapshot option, relation fallback, scenario/runtime/simulation projection, and defensive serialization invariant coverage.
    • cli/_shared.ts 100 / 100 / 100 / 100 in merged coverage after manifest/registry validation, synthetic source manifest generation, plan reader exits, patrol route-set fallbacks, GLB metadata chunks, piece selection/source branches, and readable report edge cases.
    • react/react.ts 100 / 100 / 100 / 100 in merged coverage after provider/action hook factories, empty-world fallbacks, coordinate-object tile helpers, queued revision disposal, and browser interop spawn-location counter closure.
    • scenario/recipe.ts merged zero-miss after serializable step dispatch and clone branch coverage, empty/no-seed/piece-only generation coverage, local/global archetype merge coverage, malformed action diagnostics, and setTileAsset tag clone hardening.
    • patrol/patrol.ts 100 / 100 / 100 / 100 in merged coverage after route snapshot sorting, blocked context fallbacks, completed-route wrap/end states, and malformed trait diagnostics.
    • src/cli/commands/{blueprint,summarize-plan,snapshot,spawn-groups,patrol-routes}.ts advanced by a direct-import blueprint-derived command batch; src/cli/_shared.ts advanced by guide-filter, authored-option, piece-source-root, and scalar-helper coverage; validate-plan, validate-recipe, validate-scenario, validate-simulation, and summarize-scenario advanced by docs-fixture happy paths; simulate-scenario and patrol-script advanced by report/output happy paths; validate-manifest, analyze-layout, and place-piece advanced by docs/blueprint fixture success paths; doctor and validate-manifest reached focused 100 / 100 / 100 / 100 through coverage delegation, existing-source/missing-montage reporting, readable empty-manifest summaries, JSON output, and fatal manifest validation issue exits; scenario/registry.ts reached focused zero-miss coverage through z-origin geometry warnings, terrainless manifest tile inference, default declaration asset/source normalization, object declaration application, custom placement kind defaults, and support-tile registry analysis; pieces-from-assets and pieces advanced by local GLTF fixture registry/rules/source URL paths; summarize-plan, patrol-routes, validate-scenario, validate-simulation, and summarize-scenario advanced through recipe/scenario/blueprint input variants and JSON/output paths; guide-assets, guide-roles, guide-scenarios, and guide-usages advanced through filtered file output, markdown output, and readable summaries; guide-apis, guide-permutations, and guide-render-requests advanced through filtered file output, grouped render requests, asset-base URLs, and readable summaries; summarize-scenario, patrol-routes, and patrol-script advanced through readable summaries, assignment-file variants, and malformed payload guards; declarations, analyze, compatibility, and piece advanced through packaged-manifest output, readable analysis, synthetic GLTF compatibility, and piece declaration output; readable command-output variants advanced summarize-plan, validate-plan, validate-recipe, validate-scenario, validate-simulation, spawn-groups, analyze-layout, and place-piece through readable report paths; blueprint, snapshot, pieces-from-assets, and pieces advanced through readable blueprint/scenario inspection, plan/recipe snapshot variants, GLTF asset scans, registry analysis, rules, source URLs, and piece-fill placement output. scripts/smoke/pack-install.ts advanced through dependency-injected packed install, CLI assertion, temp-write, and generated source coverage. The larger CLI command surface still has low-coverage command modules. Each file’s continuation work lands as one commit that adds ≤200 LOC of test code and ratchets the floor.
  • [DONE] E8 — Flip coverage thresholds to 100 / 100 / 100 / 100 in vitest.coverage.shared.ts. Final React cleanup local merged Coverage proof is 100 / 100 / 100 / 100 and the remaining react/react.ts gap is closed.

Phase E-MergedGate — wire browser coverage into the enforced gate

Section titled “Phase E-MergedGate — wire browser coverage into the enforced gate”

User decision (2026-05-28): the enforced CI gate (test:coverage:enforce) is unit-only, but it measures src/react/react.ts + src/three/three.ts which Node can never cover (292 uncov lines / 134 uncov fns dragging the gate ~1.5–4pt). Chosen fix: wire browser-free coverage into the gate (merge unit + browser-free, enforce on merged) so react/three are measured where they CAN be covered — NOT exclude them.

Closeout (2026-06-25):

  1. [DONE] Stale browser alias/import safety work from LF8 remains green; tests/unit/umbrella-browser-safe.test.ts asserts zero node:* leaks from the umbrella.
  2. [DONE] Vitest Browser hang fixed: publicDir: packageRoot was shadowing Vitest Browser’s client; browser-free now uses publicDir: false, serves bootstrapped GLTFs through /@fs/<repo>/models, and has an explicit @vitest/runner dev dependency plus browser harness smoke coverage.
  3. [DONE] Local visual gate is green: pnpm exec tsx src/cli/cli.ts bootstrap --source github --out models; pnpm test:browser:free.
  4. [DONE] Merged coverage gate is enforced: scripts/merge-coverage.ts runs nyc check-coverage when HEX_WORLDS_COVERAGE_ENFORCE=1; pnpm coverage:all:enforce passed locally at 78.19 / 72.18 / 86.11 / 77.94 and .github/workflows/ci.yml Coverage now bootstraps FREE models, installs Playwright Chromium, and enforces the merged unit+browser-free tree.

Layering decisions (2026-05-28, user-directed during link-3 investigation):

  • The 1100-line root src/index.ts hand-relisted 956 named symbols that the 18 domain barrels already export * — pure duplication, not curation (tiering is enforced at package.json#exports + @internal, not the root hand-list). Root rewritten to barrel-forwarding (export * from './<domain>'). Adding a public export to a domain now needs no root edit.
  • There is NO server/browser split and NO server.ts (rejected as a wrapper shim). The umbrella is browser-safe by correct layering: it exports library/runtime API only. bootstrap is a CLI-domain capability (reachable ONLY from src/cli/; never from runtime/react/three) — it was wrong to re-export it from the umbrella at all. Bootstrap stays reachable via the ./bootstrap subpath for programmatic CLI-equivalent callers.
  • manifest/upstream-layout.ts was mis-filed: its data + fs-probers are consumed ONLY by bootstrap (CLI-domain), nothing in manifest/runtime uses it. Move src/manifest/upstream-layout.tssrc/bootstrap/upstream-layout.ts; published subpath renamed ./manifest/upstream-layout./bootstrap/upstream-layout (pre-1.0; update docs-site 3 refs + smoke/types.ts + architecture table + biome restricted-imports + tsup entry + package.json exports). bootstrap barrel re-exports it.

Ordered sequence: The LF batch below remains the historical decomposition that unblocked browser-safe imports. Step C and Step D are complete as of 2026-06-25; the remaining coverage work is E0a/E0h/E8’s progressive 100% ratchet, not the browser/merge gate itself.

Batch — library-fit-decomposition (batch-20260528-103351)

Section titled “Batch — library-fit-decomposition (batch-20260528-103351)”

Source: docs/plans/library-fit-decomposition.prq.md (sha256: 42bbb50d5a7041055a2a67438c99192629f0f2264f89871989985fdb892d6f96) Started: 2026-05-28T10:33:51Z

task-LF1 Barrel-forwarding umbrella + internal extraction (merged LF1+LF1b)

Section titled “task-LF1 Barrel-forwarding umbrella + internal extraction (merged LF1+LF1b)”
  • task-LF1 ✅ (commit, 2026-05-28) Rewrite src/index.ts to export * from './<domain>' only (18 library barrels); drop bootstrap re-exports. Extract the 28 internal helpers the barrels over-export so they’re shareable-but-private:
    • DISCOVERY (2026-05-28): the old hand-list root was NOT pure duplication — it curated OUT 28 internal helpers the domain barrels over-export via export *. Barrel-forwarding surfaces them; they must leave the public boundary.
    • Generic cross-cutting → new src/internal/ (NOT in package.json#exports): errorMessage, isNonEmptyString, isRecord (dedupe the cli/_shared.ts copy too), includesString, isHexCoordinatesInput, tryParseHexKey, plus the type-guards/const-arrays that are pure utilities.
    • Domain-specific internals stay in their domain file but leave the public boundary (the barrel/shim re-exports only public names; siblings import directly): report.ts internals (actorRecord/…/simulationResult), script.ts SIMULATION_* arrays + isSimulation* guards + tileKeyFromTargetInput, gameboardPlanIndex@gameboard, isTextureSet/isUnitStyle@catalog, readValidationGameboardPlanFromWorld@projection, GAMEBOARD_RELEASE_GATE_SUMMARIES + GAMEBOARD_REQUIRED_BROWSER_SCREENSHOT_ARTIFACTS@coverage, KAYKIT_ATTRIBUTION@schema.
    • Mechanism: where a shim/barrel does export * and must drop internals, either move internals to src/internal/ (generic) or convert that shim to public-named re-exports (domain-specific). Update all importers + biome noRestrictedImports for ../internal. typecheck + unit green.
    • CONTRACT DECISION (2026-05-28, user: “pick the BEST for the library”): umbrella = union of legitimately-public subpath symbols; genuinely-internal symbols leave ALL public surfaces. The old hand-list was a curated-subset (umbrella ⊊ subpaths) — that was WRONG for symbols with real external consumers. Classification of the post-barrel-forwarding leaks:
      • Move to internal (no external consumer; only cross-file impl detail; auto-typedoc is noise): actorRecord/placementRecord/simulationResult/actorTargetsRecordFromReport/emptyActorTargetsRecord (report↔engine) → src/simulation/internal.ts; tryParseHexKey (coordinates-internal) → src/internal or private; gameboardPlanIndex (cross-domain layout/interop/gameboard impl) → src/internal; GAMEBOARD_RELEASE_GATE_SUMMARIES (coverage-internal) + GAMEBOARD_REQUIRED_BROWSER_SCREENSHOT_ARTIFACTS (coverage→cli impl) → src/internal or interop-internal.
      • Keep public — real external consumers, umbrella SHOULD expose (old list wrongly omitted): KAYKIT_ATTRIBUTION (scripts/audit-package.ts) ; readValidationGameboardPlanFromWorld (scripts/smoke/*). These were already public on their subpath; accept into umbrella, add to snapshot.
      • Final snapshot diff = bootstrap (13) + all genuine internals removed; + KAYKIT_ATTRIBUTION + readValidationGameboardPlanFromWorld + any other real-consumer symbols added. Delete stale auto-typedoc pages for the now-internal symbols (docs-site reference regen).
    • PROGRESS (2026-05-28): umbrella → barrel-forwarding DONE. src/internal/predicates.ts (5 generic) DONE. src/simulation/internal.ts (SIMULATION_* arrays + isSimulation* guards + tileKeyFromTargetInput) DONE — cycle broken by owning STEP_ACTIONS in internal.ts. simulation.ts shim curated (report records omitted) DONE. tsc green, 714/715 unit pass, ONLY public-api snapshot red.
    • REMAINING 6 leaks + decisions: KEEP-PUBLIC (real consumers, accept into snapshot): KAYKIT_ATTRIBUTION (scripts/audit-package), readValidationGameboardPlanFromWorld (scripts/smoke). MOVE-INTERNAL via per-domain shim/barrel curation (same pattern as simulation.ts): tryParseHexKey (coordinates.ts-internal, used by parseHexKey), gameboardPlanIndex (gameboard.ts, cross-domain → coordinates/interop import it; curate gameboard barrel + give cross-domain callers a path — likely src/internal re-home accepting type-only domain imports, OR a gameboard/internal.ts with a biome exception), GAMEBOARD_RELEASE_GATE_SUMMARIES (coverage.ts-internal), GAMEBOARD_REQUIRED_BROWSER_SCREENSHOT_ARTIFACTS (coverage.ts → cli consumes; cross-domain). Then update snapshot, delete stale typedoc pages, biome rule for any new internal import paths. typecheck + unit + coverage green → commit LF1. REORDER (2026-05-28, forward self-assessment after LF1): LF2 (config extraction) was originally first, but the work surfaced that its content — the KAYKIT_FREE_GITHUB_* constants + repo-clone patterns — is downstream of LF7’s git-clone decision (github→git changes those constants’ semantics entirely) AND lives in bootstrap files that LF4 relocates. Extracting config now would build a schema LF7 then reshapes. BEST order: LF3 → LF4 → LF7 → LF2 → LF5 → LF6 → LF8 so config captures the SETTLED constants (incl. git-clone patterns) from their final home. (Per “pick the BEST, let work surface the next step”.)

task-LF2 src/config JSON config domain (reordered: after LF7)

Section titled “task-LF2 src/config JSON config domain (reordered: after LF7)”
  • task-LF2 ✅ (commit, 2026-05-28) Created src/config/ with 3 JSON files (kaykit-source, bootstrap-paths, upstream-layouts) + typed loader (KAYKIT_SOURCE, BOOTSTRAP_PATHS, UPSTREAM_LAYOUTS, kaykitGithubArchiveUrl). Migrated all KAYKIT_BOOTSTRAP_, KAYKIT_FREE_GITHUB_, KAYKIT_FREE_USER_AGENT, KAYKIT_*_EXTENSIONS, KAYKIT_SIDECAR_SCHEMA_VERSION, KAYKIT_MEDIEVAL_FREE/EXTRA_LAYOUT to derive from config. Public names unchanged, browser-safe (pure JSON, no node), internal (not in exports). All green.
  • task-LF3 ✅ (commit, 2026-05-28) Moved src/manifest/upstream-layout.ts → src/bootstrap/upstream-layout.ts (whole file; config extraction of its data deferred to reordered LF2). manifest barrel drops it; bootstrap barrel re-exports. Subpath renamed manifest/upstream-layout → bootstrap/upstream-layout (tsup+package.json+smoke+astro typedoc). 6 layout symbols left umbrella (→ ./bootstrap). Also: react/three added to umbrella (LF1 follow-up, invariant #5, commit 3461858). All green: typecheck/715 unit/build/lint.

task-LF4 Relocate bootstrap to CLI command area

Section titled “task-LF4 Relocate bootstrap to CLI command area”
  • task-LF4 ✅ (commit, 2026-05-28) Moved src/bootstrap/* → src/cli/commands/bootstrap/ (core/target/upstream-layout/index.ts; index now hosts the run command merging the old thin wrapper). _shared imports ./commands/bootstrap/core (cycle-safe). tsup + astro typedoc inputs repointed; subpath KEYS + dist paths unchanged. e2e/integration tests repointed. No top-level src/bootstrap/. All green: typecheck/715 unit/build/lint.

task-LF5 Repoint subpaths + build + lint + docs

Section titled “task-LF5 Repoint subpaths + build + lint + docs”
  • task-LF5 ✅ (commit, 2026-05-28) Hand-written docs repointed (architecture, errors guide, kaykit-upstream-layout guide). Auto-typedoc regenerated. Empty stale reference/bootstrap/ deleted. biome rule needed no change (bootstrap moved INTO src/cli/commands; the rule’s ../bootstrap matchers no longer apply since there’s no top-level bootstrap domain). package.json exports + tsup + scripts/smoke + astro typedoc inputs already updated in LF3+LF4. All green.
  • task-LF6 ✅ (commit, 2026-05-28) Adopted citty for command routing + lazy subcommand loading; hand-curated ./usage preserved for --help (intercept BEFORE runMain since citty auto-help only lists subcommand names). All 35 subcommands unchanged (kept run(parsed, sourceRoot, edition) contract; citty wraps each with ctx.rawArgs → parseFlags). Lazy import per command preserves the cold-start budget. 31 cli tests pass; all green.

task-LF7 Unify bootstrap source on the zip flow (no git, no peer dep)

Section titled “task-LF7 Unify bootstrap source on the zip flow (no git, no peer dep)”
  • task-LF7 ✅ (commit 644862c, 2026-05-28) Unified: github source downloads the stable /archive/refs/heads/main.zip then reuses stageFromZip (same detector handles itch.io <pack>/Assets/gltf + github <repo>-main/addons/kaykit_.../Assets/gltf). Removed tar/gunzip/stream-pipeline + tar runtime dep + .gz ext. Verified structures via download. All green. ORIGINAL: REVISED (user, 2026-05-28): isomorphic-git rejected as overkill. The GitHub archive URL https://github.com/KayKit-Game-Assets/KayKit-Medieval-Hexagon-Pack-1.0/archive/refs/heads/main.zip is stable and never changes. Collapse the two source modes into ONE flow: the CLI accepts a local zip path and auto-detects free/extra by expected structural alignment (via the layout detector); if no zip is given, it fetches that stable archive .zip and feeds the SAME zip-extract flow (FREE only). Remove the tarball/gunzip/tar machinery (node:zlib, node:stream/promises, tar dep, kayKitFreeGithubTarballUrl’s codeload tar.gz URL → archive .zip URL). Keep the existing openHttpsStream redirect handling (github archive → codeload redirect) but pipe to a temp .zip file then reuse stageFromZip. Verify via tree that a fresh download of that zip extracts to the same structure as the FREE references/ tree; support both structures if they differ. Drop tar runtime dep. Coverage for the unified path. typecheck+unit+build+lint green.

task-LF8 Browser-import-safety verification

Section titled “task-LF8 Browser-import-safety verification”
  • task-LF8 ✅ (commit, 2026-05-28) Static-graph guard tests/unit/umbrella-browser-safe.test.ts walks src/index.ts transitive imports + asserts ZERO node:* leaks (72 files visited, 0 leaks). 2026-06-25 empirical verification: browser-free React/Three visual suites load under Chromium, pnpm test:browser:free passes with screenshot QA, and pnpm coverage:all:enforce measures the merged unit+browser-free tree.

Phase E9 — visual integration gate (continuation)

Section titled “Phase E9 — visual integration gate (continuation)”
  • E9 — ✅ Browser visual integration gate closed (2026-06-25). tests/browser/free-visual.test.ts, simple-rpg-visual.test.ts, and feature-gallery.spec.ts render the Three-backed catalog/gameboard/example surfaces into Chromium and assert committed PNG artifacts under tests/browser/__screenshots__/; tests/browser/react-bindings.test.ts exercises React hooks/providers/actions in Chromium; tests/browser/browser-harness-smoke.test.ts catches Vitest Browser client regressions. Local proof: pnpm exec tsx src/cli/cli.ts bootstrap --source github --out models; pnpm test:browser:free; pnpm coverage:all:enforce.
  • F-Audit-7b-equiv — ✅ Migrated all six docs/guides/*.md legacy files into docs-site/src/content/docs/guides/ with canonical-URL redirect notes pointing back. The legacy docs/guides/*.md files stay (load-bearing in src/scenario/catalog.ts at lines 1366/1515/1557/1571/1614/1653/1673) with a top-of-file canonical pointer; the docs-site versions are the human-facing canonical with Starlight frontmatter. Six files: guide-scenario-coverage, public-api, recipes-scenarios-and-simulation, release-readiness, rendering-assets-and-external-packs, runtime-integration.

Phase CR — Comprehensive Review Action Queue (2026-05-28)

Section titled “Phase CR — Comprehensive Review Action Queue (2026-05-28)”

Findings from full 5-phase review (.full-review/05-final-report.md). Ordered by priority: P0 must ship before next release; P1 before next release but can batch; P2 sprint-level; P3 backlog.

P0 — Critical (must fix before next release)

Section titled “P0 — Critical (must fix before next release)”
  • CR-P0-1 — ✅ PR #62 (2026-05-28): main branch protection enabled via gh api with required checks: lint/typecheck/build/test/Coverage/Docs Site Build/Semgrep SAST/Dependency Review.
  • CR-P0-2 — ✅ PR #62 (2026-05-28): Removed release-as: "1.0.0" from release-please-config.json.
  • CR-P0-3 — ✅ PR #62 (2026-05-28): react/three/koota/react-dom → peerDependencies (optional); @types/react → devDependencies; citty/honeycomb-grid/seedrandom/yauzl stay as runtime deps.
  • CR-P0-4 — ✅ (2026-05-28) Added src/cli/commands/bootstrap/__tests__/security.test.ts with 6 tests: (a) redirect allowlist — non-allowlisted host rejected, allowlisted host accepted (objects.githubusercontent.com → 503 proves 2nd hop ran), redirect depth >5 rejected; (b) zip-slip — raw-binary zip with ../../../ entry name rejected by extractZipTo; (c) zip-bomb — declared uncompressedSize > 64 MB rejected by pre-check, at-limit (=64 MB) passes pre-check but fails yauzl size-mismatch. Uses vi.mock('node:https') + raw zip buffer construction (yazl rejects ../ names). All 6 pass; lint/typecheck/test green.
  • CR-P0-5 — ✅ PR #62 (2026-05-28): readJson<T>readJson(): unknown; ~25 call sites updated with explicit as X casts; two unvalidated plan-return paths (layoutAnalysisPlanFromArgs, summaryPlanFromArgs) now run validateGameboardPlan; null/primitive guards added to readRegistry, readPieceRegistry, pieceOverridesFromArgs. Remaining: readValidatedJson wrapper + file-size ceiling + error-contract tests — tracked as CR-P1-partial below.

P1 — High (fix before next release, can batch)

Section titled “P1 — High (fix before next release, can batch)”
  • CR-P1-1 — ✅ (2026-05-29) Added 9 golden-path oracle tests (pathfinding-oracle.test.ts) pinning correctness + visit-count ceilings. Replaced O(N) lowestScoreKey + Set open-list in findHexPath with binary min-heap A* (lazy deletion via g-cost mismatch). Replaced O(N) lowestCostKey in reachableGameboardTiles with binary min-heap Dijkstra. Zero new deps. Biome noNonNullAssertion satisfied via explicit undefined checks. PR #65.
  • CR-P1-2 — ✅ (2026-05-29) Created src/guides/simple-rpg/ (types/exercises/smoke/index.ts). Moved types + catalog + smoke to production; CLI imports ../guides/simple-rpg + passes scenarioJson as GameboardScenario; test file re-exports production module + zero-arg wrapper. _shared.ts no longer imports from tests/. PR #66.
  • CR-P1-3 — ✅ (2026-05-28) Fixed SAFE_REF regex in config/index.ts: original /^[a-zA-Z0-9._\-/]{1,200}$/ allowed ../../etc/passwd (dots+slashes in charset); replaced with /^(?!.*\.\.)(?!\.)(?!.*\/$)[a-zA-Z0-9._\-/]{1,200}$/ rejecting .. sequences, leading dots, trailing /. Added CWE-74 guard test in smoke.test.ts; fixed security.test.ts typecheck (3× as unknown as ReturnType<typeof request> + headers cast). All 67 test files pass; tsc exit 0; lint clean.
  • CR-P1-4 — ✅ (2026-05-29) Added WeakMap<World, Map<string, Entity>> for tile-key and placement-id in koota.ts. findTileEntity + findPlacementEntity are now O(1). spawnGameboardPlan fills both indexes; spawnGameboardPlacement registers; removeGameboardPlacement deregisters; clearGameboardWorld clears. 68/68 tests pass.
  • CR-P1-5 — ✅ (2026-05-29) Added KNOWN_EXTRA_ASSET_IDS IIFE-computed Set<string> in catalog.ts. isKnownExtraAssetId is now a single Set.has() call. 68/68 tests pass.
  • CR-P1-6 — ✅ PR #62 (2026-05-28): dedicated coverage job added to ci.yml running pnpm test:coverage:enforce; added as required status check in branch protection.
  • CR-P1-7 — ✅ (2026-05-28) bootstrap-nightly.yml: SHA-pinned all 4 actions, added pull_request paths trigger, hoisted HEX_WORLDS_OUT_ROOT to job env.
  • CR-P1-8 — ✅ (2026-05-28) engine.ts:663-665: null-check .at(-1) result, throw GameboardRuntimeError with actor.actorId + actor.spawnGroupId.
  • CR-P1-9 — ✅ (2026-05-28) release.yml: guarded npm publish with if: github.event_name == 'release'.
  • CR-P1-10 — ✅ (2026-05-28) core.ts: replaced dirname(new URL(import.meta.url).pathname) with import.meta.dirname.
  • CR-P2-1_shared.ts decomposition: per-command files; extract emitOutput() helper; fix commandHandlerMutations to throw GameboardRuntimeError on never. [CQ-1, CQ-2]
  • CR-P2-2 — ✅ PR #69 (2026-05-29): findGameboardPath/reachableGameboardTiles default-arg Map allocations routed through gameboardPlanIndex WeakMap.
  • CR-P2-3 — ✅ PR #69 (2026-05-29): world.query() spreads removed (patrol.ts:227, movement.ts:421); flatMap+spread in runGameboardSystems replaced with nested for-loop push. Koota world.query() verified snapshot via .slice() — gemini live-iterator concern was a false positive.
  • CR-P2-4 — ✅ gameboard.ts no longer statically imports freeManifest; requiresExtraAsset uses catalog treatment metadata, getPlacementAsset is explicit-manifest sync, and new loadPlacementAsset lazy-loads the packaged FREE manifest via dynamic import. Added focused gameboard tests, public API snapshot update, and a dist/gameboard.js static import-graph guard proving the FREE manifest record chunk is not statically reachable. Also refreshed packed-consumer smoke peer fixture (koota, three@^0.184.0) and flat baseUrl URL assertion. Verified with pnpm verify, pnpm docs-site:build, packed-consumer smoke, and npm pack --dry-run.
  • CR-P2-5 — ✅ useGameboardDerivedRevision: split React selector invalidation into state/tile/placement/actor/movement/quest/patrol domains, coalesced trait events through one microtask revision bump, and added jsdom tests proving placement selectors ignore tile-only updates and coalesce repeated placement changes. pnpm verify green. [P-10]
  • CR-P2-6 — ✅ stageUpstreamSource: inlined github download path with try/finally for downloadRoot cleanup; stageFromZip restructured to let succeeded = false; try { ... succeeded = true; } finally { if (!succeeded) rmSync(...) }.
  • CR-P2-7 — ✅ readSidecar: added SIDECAR_MAX_BYTES = 4 MiB + SIDECAR_MAX_FILES = 100_000 constants; guards throw GameboardIoError on oversize or overcount.
  • CR-P2-8 — ✅ walkFilesInternal: added symlinkCount ref parameter; warns once on stderr when symlink encountered; passes through recursive calls.
  • CR-P2-9 — ✅ koota.ts no longer imports isKnownExtraAssetId from scenario; runtime placement spawn/update now require callers to set or preserve requiresExtra explicitly. Added Koota regression coverage for explicit EXTRA tagging. pnpm verify green. [AR-1]
  • CR-P2-10 — ✅ ci.yml: unified pnpm/action-setup and actions/setup-node SHAs across all 4 jobs to v6.0.8 / v6.4.0 (docs job was on v4.2.0/v6.3.0).
  • CR-P2-11 — ✅ release.yml: added post-publish npm audit signatures verify step; wrote ROLLBACK.md runbook covering deprecate, unpublish, patch-release, and signature failure scenarios.
  • CR-P2-12 — ✅ automerge.yml: branch protection now has strict required checks (lint, typecheck, build, test, Docs Site Build, Semgrep SAST, Dependency Review, Coverage), so Dependabot keeps gh pr merge --auto --squash behind the gate while release-please auto-approval/auto-merge is removed. Release PRs are now a maintainer checkpoint for the computed version + changelog; workflow contract + deployment docs updated. Local proof: pnpm exec vitest run tests/contract/workflows-contract.test.ts --config vitest.config.ts; pnpm typecheck; pnpm lint. [CI-6]
  • CR-P2-13 — ✅ H-DOC-1: fixed CLI reference redundant binary mention; H-DOC-2: added package rename narrative to CHANGELOG.md 1.0.0 + created docs-site/guides/migration.md; H-DOC-3: added JSON flag schema/error-contract subsection; M-DOC-1: added HEX_WORLDS_OUT_ROOT danger aside.
  • CR-P2-14 — ✅ Removed it.skip at cli.test.ts:1922 (fixture key updated to fixture-castle-kit to satisfy [A-Za-z0-9_:-]+ guard); tightened __proto__ guard message assertion in cli-security.test.ts; fixed --pieces arg to use temp file (CLI requires path, not inline JSON). Skips at lines 219 (Phase RB) and 1426 (Phase RS) remain legitimately blocked.
  • CR-P2-15 — ✅ requirePlacementState now returns Readonly<PlacementStateValue> (live ECS value, no copy) for internal reads; snapshotPlacementState does the deep-spread and is used only at the two external-result callsites (requestGameboardMovement and movementAdvanceResult).
  • CR-P2-16 — ✅ tsconfig.json: removed ignoreDeprecations: "6.0"; migrated all paths values from bare relative (src/...) to ./-prefixed relative (./src/...) and removed baseUrl: "." — TS 6 requires explicit relative paths in paths when baseUrl is absent. tsc clean, all 68 test files pass.
  • CR-P2-17 — ✅ tsup.config.ts: added treeshake: true explicit; documented bundle model (honeycomb-grid/seedrandom/citty/yauzl bundled as deps; koota/react/three external as peerDeps); added tests/unit/bundle-size.test.ts with 60KB ceiling on index.js + 100KB ceiling on cli.js (skips when dist/ absent).
  • CR-P2-18 — ✅ release.yml: pinned npm@11.11.0 (was @latest); added @cyclonedx/cyclonedx-npm@4.2.1 as pinned devDependency; switched from npx --yes @cyclonedx/cyclonedx-npm@latest to pnpm exec cyclonedx-npm; updated contract test assertion to match.
  • CR-P3-1 — ✅ Architecture decomposition: simulation/script.ts (3,163 lines → script-types/validators/index); gameboard/gameboard.ts (2,228 lines → plan/spawn-groups/terrain); systems/systems.ts (900 lines → command/tick/events); scenario/catalog.ts (2,401 lines). Progress: simulation/script.ts is now an 11-line stable public shim over script-types.ts (DTOs/schema/result records) and script-validators.ts (authored-script validators/scenario index); gameboard plan contracts, builder option contracts, memoized plan index, and plan summary helpers are split into src/gameboard/plan.ts; gameboard asset lookup/EXTRA/prop-cluster helpers are split into src/gameboard/assets.ts; derived terrain/connectivity placement construction is split into src/gameboard/terrain.ts, leaving gameboard.ts focused on builder/runtime construction behavior and built-in sample boards; board-aware spawn selection and spawn-group routing are split into src/gameboard/spawn-groups.ts; patrol waypoint and route-segment planning is split into src/gameboard/patrol-routes.ts, leaving navigation.ts focused on occupancy-backed pathfinding/reachability and public navigation re-exports; systems event contracts, event record contracts, and snapshot serializers are split into src/systems/events.ts; systems command dispatch contracts/helpers are split into src/systems/command-dispatch.ts; systems patrol/movement/quest tick orchestration is split into src/systems/tick.ts, leaving systems.ts focused on action bundles and command-plus-tick composition; scenario guide-page image/table normalization is split into src/scenario/catalog-guide-data.ts, and KayKit public treatment construction is split into src/scenario/catalog-treatments.ts, leaving catalog.ts focused on public constants, queries, inverse indexes, coverage summaries, and Markdown rendering without moving the public /catalog API surface. Local proof: pnpm typecheck; focused catalog/public API/docs contract Vitest slice. [AR-4, AR-5, AR-6]
  • CR-P3-2 — ✅ noRestrictedImports enforcement gaps: added ../interop/internal, ../internal/predicates, trait deep paths, config JSON deep paths, and .js mirrors for every extensionless restricted path; routed existing trait imports through ../traits; added a contract test for required gaps and .js mirror coverage. Local proof: pnpm exec vitest run tests/contract/biome-restricted-imports-contract.test.ts --config vitest.config.ts; focused actor/Koota/movement/patrol/quest/public-api Vitest slice; pnpm typecheck; pnpm lint; pnpm verify. [AR-10, BP-8]
  • CR-P3-3 — ✅ interop/coverage.ts cohesion: documented the release-tooling vs runtime interop split in the architecture page, mirrored the distinction in the coverage.ts module comment, and clarified both public API guide copies so ./coverage is build/review tooling rather than runtime ECS adapter glue. Kept the existing src/interop/coverage.ts location because /coverage is already a stable public surface joining interop, compatibility, manifest, scenario, and visual evidence. Local proof: pnpm exec vitest run src/interop/__tests__/coverage.test.ts tests/contract/docs-frontmatter-contract.test.ts --config vitest.config.ts; pnpm lint; pnpm typecheck; pnpm docs-site:build. [AR-7]
  • CR-P3-4 — ✅ Branded types: added public-api migration status tables to both docs-site canonical and legacy metadata guides, explicitly stating branded IDs are NOT yet enforced; added a docs contract pinning the caveat, tracked domains, tracked brands, and current implementation boundary. [AR-8, M-DOC-4]
  • CR-P3-5 — ✅ useStableOptions JSON.stringify: added a plain-empty-options fast-path before serialization; the React memoization test is now included in the main Vitest config and pins that fresh {} selector options do not call JSON.stringify. Local proof: pnpm exec vitest run src/react/__tests__/memoization.test.tsx --config vitest.config.ts. [P-11]
  • CR-P3-6 — ✅ Added .github/workflows/benchmarks.yml to run pnpm build + pnpm bench on main pushes, nightly schedule, manual dispatch, and benchmark-wiring PRs; uploads text benchmark output plus metadata artifacts; workflow contract now pins the benchmark workflow shape and SHA-pinned actions. [T-bench]
  • CR-P3-7 — ✅ Inline docs: added A* heap/heuristic commentary in findHexPath; patrol state-machine transition diagram above advancePatrolEntity; section maps for the split simulation script implementation (script-types.ts and script-validators.ts behind the stable script.ts shim); and docs/ vs docs-site/ canonical ownership guidance in CONTRIBUTING.md. [L-DOC-1, L-DOC-2, M-DOC-5, L-DOC-3]
  • CR-P3-8 — ✅ CI_GITHUB_TOKEN PAT removed from release-please auth. cd.yml now mints a repo-scoped GitHub App installation token via pinned actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 (v3.2.0), requests only the current repository, narrows App-token permissions to contents/pull-requests write, keeps the job GITHUB_TOKEN read-only, and passes steps.release-please-token.outputs.token to release-please. Deployment docs name vars.RELEASE_PLEASE_APP_CLIENT_ID + secrets.RELEASE_PLEASE_APP_PRIVATE_KEY; workflow contract rejects secrets.CI_GITHUB_TOKEN. [CI-9]
  • CR-P3-9 — ✅ GAMEBOARD_REQUIRED_BROWSER_SCREENSHOT_ARTIFACTS now re-exports through src/interop/coverage.ts and the src/interop/index.ts barrel. The CLI coverage command imports it from ../../interop instead of ../../interop/internal, coverage tests pin the barrel path, and the public API snapshot records the intentional release-tooling export. [L-1/Sec, AR-2]
  • CR-P3-10 — ✅ advancePatrolEntity split into explicit transition helpers for inactive, invalid-route, existing-movement, idle/wait/completed, and request-next-segment branches. Trait writes stay in the same behavior points, but the monolithic early-return ladder and mutable nextAgent flow are replaced with PatrolAdvanceTransition objects. Patrol edge tests, simulation patrol tests, lint, typecheck, and full verify pass locally. [CQ-7]
  • CR-P3-11 — ✅ hashFile now hashes through stream/promises.pipeline into a hashing Writable, so verification waits for stream cleanup instead of resolving on the read stream end event. Bootstrap core tests, lint, typecheck, and full verify pass locally. [CQ-9]
  • CR-P3-12 — ✅ Removed the dead src/simulation/simulation.ts double-shim and moved the public simulation barrel directly into src/simulation/index.ts. Source docs now point at src/simulation/index.ts; focused simulation/public API tests, lint, typecheck, and full verify pass locally. [AR-3]