559dbebd86
Spec §4.1 + §4.2 — Phase 2 Task 14:
- tools/router-prehook.mjs:
- removed: ENFORCEMENT_TYPES + isEnforcementRequired (gate now uses
NON_BLOCKING_TASK_TYPES on state.classification.task_type — Task 13).
- buildStateFromClassification:
+ task_id: randomUUID() per turn (or caller-supplied taskId).
+ task_cost: {} placeholder (caller fills classifier_input/output_tokens
when available; LLM helper does not yet thread tokens through — task
17/20 will add).
+ inheritance: { inherited_from_task_id, inheritance_age_minutes } —
written only on continuation (source: 'prefilter_inherited'); copied
into the episode by observer-stop-hook in Task 16 (closes B5).
- dropped enforcementRequired field — Tool gate decides solely on
task_type + no_skill_found + skillInvokedThisTurn.
- main(): read prevState (~/.claude/runtime/router-state-<session>.json)
BEFORE overwrite; pass to classify({ prevState }); lift inheritance
from classification result into the new state when prefilter inherited.
- tools/router-prehook.test.mjs: rewritten — 9 tests covering v4 shape,
task_id randomness + override, inheritance present/absent, cost passthrough,
ENFORCEMENT_TYPES + isEnforcementRequired no longer exported, UTF-8 smoke.
Tests: 9/9 prehook PASS. Consumer regressions: router-tool-gate (25) +
router-classifier (44) = 69 PASS — no regressions.