Learned Prefix Action Policy Implementation Plan
For agentic workers: REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (
- [ ]) syntax for tracking.
Goal: Add a deterministic, prefix-only learned action-value policy and its separately bound checkpoint/training path while preserving existing dynamic.v1 carrier checkpoints, fixed policies, and runner APIs.
Architecture: Runtime control data remains in mcss.dynamic.types; control_to_features is the sole ordered feature-schema encoder. LearnedActionPolicy owns a small MLP and masks infeasible actions at choose(control, feasible_actions). Policy checkpoints are independent files carrying carrier/write content hashes, feature schema, render/budget/utility bindings, teacher hashes, and training-only normalization. Offline fitting consumes the shared all-actions-per-prefix JSONL rows and validates by scene split.
Tech Stack: Python 3.11, PyTorch, dataclasses, JSONL, pytest.
Global Constraints
- Runtime policy features use only already observed image/state/camera/budget/action values; no future/query labels, paths, or teacher objects.
- Feature order and normalization are deterministic and versioned; all runtime features and scores must be finite.
- Existing
ControlInputconstruction, fixed-policy behavior, dynamic.v1 payload shape, and fixed-policy budget charge remain compatible. - Teacher rows contain all four actions in one row with
feasible_mask, nullable infeasible losses/advantages, and shared metadata bindings outside rows. - Policy checkpoints are composed with carrier/write checkpoints and reject mismatched expected bindings.
- CPU-only focused tests are required; no training run is launched here.
Task 1: Runtime prefix control and deterministic feature schema
Files:
- Modify: src/mcss/dynamic/types.py
- Modify: src/mcss/dynamic/feedback.py
- Modify: src/mcss/dynamic/policy.py
- Test: tests/dynamic/test_policy.py
Interfaces:
- ControlInput keeps existing required fields and adds optional observed-prefix fields with deterministic defaults.
- control_to_features(control: ControlInput) -> torch.Tensor returns the fixed one-dimensional schema tensor.
- LearnedActionPolicy.choose(control, feasible_actions) -> Action masks infeasible actions, validates finite values, and resolves ties in OFF,FUSE,COMPLETE,ALL order.
- [ ] Add shape/finite checks and default-compatible optional control fields.
- [ ] Implement fixed feature names/version and tensor conversion from pooled image stats, 4x4 residual summaries, coverage/valid counts, camera change, fast stats, prior action, remaining budget, and remaining steps.
- [ ] Add the MLP value model, deterministic choice, and focused leakage/finite/tie/mask tests.
Task 2: Causal runner feedback and policy-work accounting
Files:
- Modify: src/mcss/dynamic/feedback.py
- Modify: src/mcss/dynamic/runner.py
- Modify: src/mcss/dynamic/budget.py
- Test: tests/dynamic/test_runner.py
- Test: tests/dynamic/test_budget.py
Interfaces:
- preupdate_feedback continues returning old scalar keys and can add serializable current-prefix summaries.
- Runner calls policy.choose(control, feasible_actions) and records the exact serializable control_input.
- WorkBudget.policy_units(policy) charges fixed policies one unit and learned MLP inference from declared dimensions.
- [ ] Extend pre-update feedback with current image feature/residual summaries, valid/coverage counts, and camera delta without changing old scalar semantics.
- [ ] Build the full control input before cache append, pass the legacy two-argument policy signature, and log it.
- [ ] Reserve learned-policy work in mandatory future budget calculations while leaving fixed-policy charge at one.
- [ ] Test no future/query fields enter logs/features and minimum-budget feasibility remains conservative.
Task 3: Independent policy checkpoint binding
Files:
- Create: src/mcss/dynamic/policy_checkpoint.py
- Test: tests/dynamic/test_policy_checkpoint.py
Interfaces:
- save_policy_checkpoint(path, policy, *, binding, provenance) -> str saves CPU state, architecture, normalization, schema, and binding.
- load_policy_checkpoint(path, *, expected_binding=None, device='cpu') -> tuple[LearnedActionPolicy, dict] rejects mismatches before loading.
- [ ] Define the policy-only schema and canonical binding validation for model content hash, feature schema, render/budget/utility protocols, and teacher dataset/source hashes.
- [ ] Preserve exact normalization/architecture/seed metadata and strict state loading.
- [ ] Add round-trip, mismatch, nonfinite, and dynamic.v1 non-mutation tests.
Task 4: Teacher-row fitter and training script
Files:
- Create: src/mcss/training/policy_fit.py
- Create: scripts/train_action_policy.py
- Test: tests/dynamic/test_policy_fit.py
Interfaces:
- fit_action_policy(rows, *, hidden_dim, seed, validation_scene_ids, ...) trains action-value regression from the shared all-action row schema, retaining near ties and fitting normalization on training rows only.
- JSONL parser validates exact row fields and fixed action order; heldout validation is scene-based.
- CLI loads JSONL and writes the independent policy checkpoint plus provenance/binding metadata.
- [ ] Parse/validate rows with no per-action-row alternative and reject feature/schema/action mismatches.
- [ ] Fit deterministic feature normalization on training scenes only; regress all feasible action advantages/values with masked loss and report near-tie coverage.
- [ ] Add heldout-scene validation and exact seed/source metadata to the output path.
- [ ] Keep the script importable and add a CPU synthetic-row smoke test.
Verification
- [ ] Run focused policy, checkpoint, budget, runner, and fitting tests with the project Python.
- [ ] Run the complete existing dynamic test subset to verify fixed behavior and checkpoint compatibility.
- [ ] Run
ruff checkon changed Python files when available.