Implementation Plan: holodeck test optimize — Post-MVP → Spec v1¶
Spec (authoritative): 2026-05-16-optimizer-for-holodeck-test-design.md (rev. 2026-05-29)
Predecessor plans: plan.md (MVP, shipped), plan-text-proposer.md (iterative textual, shipped),
plan-optimize-otel.md (observability, shipped)
Status: Draft for review (2026-06-07) — no code written yet.
Companion: this file embeds its own task list (same convention as plan-optimize-otel.md).
Overview¶
The MVP (plan.md T1–T9), iterative textual refinement (plan-text-proposer.md), and
observability (plan-optimize-otel.md) all shipped in commit #335. What remains is the
work that turns the compounding-coordinate-descent MVP into the authoritative spec v1:
the statistical-rigor core the MVP explicitly deferred (plan.md:3-10, confirmed with the
user 2026-05-31), the full audit/artifact set, resume/checkpointing (plan.md Phase 7,
already specced as T10–T12), the remaining CLI diagnostics, and proposer-fidelity fixes.
The current acceptance rule is a flat min_delta (loop.py:178) against a single test set
scored once — the very "magic threshold below the noise floor" the 2026-05-29 rewrite was
written to eliminate. The spine of this plan is replacing that with train/holdout +
repeats + variance-aware acceptance, then making every trial durable and auditable.
Few-shot demonstration optimization (the design's headlined #1 v2 item) is out of scope here — it needs its own schema/backend/selector design pass (see "Out of scope").
Architecture Decisions¶
- Statistical rigor lands as one coherent slice, not piecemeal.
repeats, train/holdout split, and the variance-aware bar are mutually dependent (the bar needs the spread fromrepeatsmeasured ontrain, gated byholdout). They ship together in Phase A behind a single checkpoint, so the loop is never in a half-honest state. - The audit log is the checkpoint. Resume replays
trials.jsonl; no separate pickle (plan.md:99-102). This forces richer per-trial records (Phase B) to land before resume (Phase C) — Phase B is a hard dependency of Phase C. TestExecutorstays unchanged. Train/holdout isagent.model_copy(update={"test_cases": subset})per call (spec §"What's new vs reused"); the scorer gains amean_losswrapper forrepeats. No runner edits.- Backward-compatible config. Every new
OptimizerConfigfield has a spec default so existingagent.yamlfiles keep parsing; the behavioural switch frommin_deltato the σ-bar is the only intentional break, gated by validation that warns whenrepeats == 1. - Deterministic run-id enables resume. Switch from
timestamp + random hex(optimize.py:251-255) tosha256(baseline_yaml + optimizer_config + seed)[:8](spec §"On-disk layout") so--resumeis unambiguous. - Secrets never leak into artifacts. Existing
overlay_axeson the unsubstituted template (optimize.py:286-297) is preserved for every candidate written; span/CSV/JSONL rules fromplan-optimize-otel.mddecision 5 carry over.
Verified integration points¶
- Config:
OptimizerConfig(src/holodeck/optimizer/config.py) — add fields + amodel_validatorfor the new cross-field constraints. - Scorer:
score()(src/holodeck/optimizer/scorer.py:16-42) — wrap inmean_lossand accept acasessubset; today it runsagent.test_casesonce. - Loop:
OptimizerLoop._run_phaseaccept gate (loop.py:178),run()baseline (loop.py:74-79),_record(loop.py:225-229); proposertellalready carriesreport. - Loss:
scalarize/_metric_averages(src/holodeck/optimizer/loss.py:26-102) — flat averaging today; needs per-case-then-across + penalties +max_errored_fraction. - Models:
TrialRecord/OptimizationResult(src/holodeck/optimizer/models.py). - Output:
write_outputs(src/holodeck/optimizer/output.py:98-115) — 3 artifacts today. - Numeric proposer: fresh study per phase already (
numeric.py:39-43) but nomultivariate/n_startup_trials/n_ei_candidates, no per-phase seed offset. - Textual proposer:
_critique/_apply_edit(textual.py:241-302) emit a baregradientstring +new_text; noconfidenceshort-circuit; subagents loaded from package dir (textual.py:42-58), not auto-installed/user-editable. - CLI:
optimizecommand (src/holodeck/cli/commands/optimize.py) — add flags + 3 diagnostic modes. - Resume task detail: already specced in
plan.md:94-121andtasks.md:176-237(T10–T12). - Optuna: currently a base dependency (
pyproject.toml:57); spec wants it under an[optimizer]extra.
Task List¶
Phase A — Statistical rigor (MVP → honest acceptance)¶
- A1 — Config surface for rigor + budgets.
Add to
OptimizerConfig:train_cases_file,holdout_cases_file,holdout_eval_policy(on_train_improve|every_trial|skip, defaulton_train_improve),min_holdout_cases(default 5),repeats(default 3),accept_sigma(default 1.0),max_errored_fraction(default 0.25),penalties(cost_per_usd,latency_per_sec, both default 0.0), globalbudget(max_minutes,max_usd, both optional), andnumeric_convergence_eps(default 1e-3). Keepmin_deltafor therepeats == 1/skip path. Acceptance: - All fields parse with spec defaults; an existing MVP
agent.yaml(no new keys) still loads. -
model_validatorrejectsmin_holdout_cases < 1,repeats < 1,accept_sigma < 0. -
holdout_eval_policyoutside the enum →ValidationError. Verification:pytest tests/unit/optimizer/test_config.py -n auto;make type-check. Dependencies: None. Files:src/holodeck/optimizer/config.py,tests/unit/optimizer/test_config.py. Scope: S. -
A2 — Startup validation pass (collect-all-errors). Implement the spec §"Validation at startup" 11-step pass as a pure function returning a list of errors (raise a single
OptimizerErroraggregating them). Covers: optimizer block present; train/holdout load + parse + disjoint bytest_name+ share metric set + holdout ≥min_holdout_cases; loss weights reference configured metrics;repeats/accept_sigmabounds with therepeats == 1warning; per-phasemax_trials ≥ 1+ numeric-below-warmup warning; each numeric axis applies to the baseline as a sanity check; each textual axis path resolves andmax_chars ≥ current length. Acceptance: - Multiple simultaneous misconfigurations are reported together, not one-at-a-time.
- Overlapping train/holdout names → error naming the offenders.
-
Holdout below floor → error (not warning);
repeats == 1→ warning, not error. Verification:pytest tests/unit/optimizer/test_validation.py -n auto. Dependencies: A1. Files:src/holodeck/optimizer/validation.py(new),tests/unit/optimizer/test_validation.py. Scope: M. -
A3 — Train/holdout loading + subset injection. Load both case files into
list[TestCaseModel]; threadtrain/holdoutsubsets into the scorer viaagent.model_copy(update={"test_cases": subset}). When onlytest_cases_fileis present and no split is configured, error per spec (point atholdout_eval_policy: skip). Acceptance: - Scorer runs against the train subset by default; holdout subset available on demand.
-
holdout_eval_policy: skipruns train-only and is flagged for the report. Verification:pytest tests/unit/optimizer/test_scorer.py -n auto. Dependencies: A1. Files:src/holodeck/optimizer/scorer.py,src/holodeck/cli/commands/optimize.py,tests/unit/optimizer/test_scorer.py. Scope: M. -
A4 —
mean_loss: repeats aggregation (mean + std). Addmean_loss(cand, cases, repeats) -> TrialLoss{mean, std, n, runs}runningrepeatsindependent sweeps (force_ingest=Falsethroughout). Carry the spread for the accept bar. Acceptance: -
repeats=3runs the executor 3× and returnspstdevof the per-run losses. -
repeats=1returnsstd=0(degenerate, documented). Verification:pytest tests/unit/optimizer/test_scorer.py -n auto(stub executor). Dependencies: A3. Files:src/holodeck/optimizer/scorer.py,src/holodeck/optimizer/models.py(addTrialLoss),tests/unit/optimizer/test_scorer.py. Scope: S–M. -
A5 — Loss: per-turn/per-case averaging,
max_errored_fraction, penalties. Inloss.py: average per-turn metrics within a case then across cases (not flat across allmetric_results); mark a metric's trial loss unreliable when its errored fraction exceedsmax_errored_fraction(block accept-on-that-basis, logged); add the optional cost/latency penalties (trial_usdsummed from per-resulttoken_usage× repeats, mean latency fromexecution_time_ms). Acceptance: - A multi-turn case does not dominate a single-turn case in the aggregate.
- >25% errored runs for a weighted metric marks the trial unreliable.
-
Penalties off by default; when set, add to the scalar loss per the spec formula. Verification:
pytest tests/unit/optimizer/test_loss.py -n auto. Dependencies: A1. Files:src/holodeck/optimizer/loss.py,tests/unit/optimizer/test_loss.py. Scope: M. -
A6 — Variance-aware acceptance + holdout gating in the loop. Replace
min_deltaaccept (loop.py:178) with: always run TRAIN ×repeats; decide holdout perholdout_eval_policy;pooled_std = sqrt(train.std² + best_train.std²),noise_bar = accept_sigma·pooled_std; accept iff(best_train.mean − train.mean) ≥ noise_barAND holdout did not regress beyond its own σ. Update bests (mean+std) only on accept; advance baseline (compounding preserved). Fall back tomin_deltawhenrepeats == 1and policyskip(no measurable spread). Acceptance: - A sub-noise "improvement" is rejected with the spec rationale string.
- A holdout regression beyond its σ blocks an otherwise-accepted train win.
-
Baseline still advances on accept; wins still compound across phases. Verification:
pytest tests/unit/optimizer/test_loop.py -n auto. Dependencies: A4, A5. Files:src/holodeck/optimizer/loop.py,tests/unit/optimizer/test_loop.py. Scope: M. -
A7 — Global budgets + numeric convergence stop. Track cumulative wall-clock and USD; stop the run when
max_minutes/max_usdtrips (in-flight trial finishes first). Addnumeric_convergence_epsas a per-phase numeric stop (TPE expected-improvement below ε). Skipmax_usdwith a startup warning when a model lacks pricing. Acceptance: -
max_usd/max_minutesend the run between trials; recorded asexit_reason. - Numeric phase stops early when EI < ε; logged distinctly from patience/max_trials.
Verification:
pytest tests/unit/optimizer/test_loop.py tests/unit/optimizer/test_numeric.py -n auto. Dependencies: A6. Files:src/holodeck/optimizer/loop.py,src/holodeck/optimizer/proposers/numeric.py, tests. Scope: M.
🛑 Checkpoint A — honest acceptance¶
- Train drives proposals; holdout gates accepts; accept bar is measured, not magic.
- A known-noisy stub agent yields zero false accepts at
accept_sigma=1.0. -
make test-unit && make type-checkclean; existing MVP configs still run.
Phase B — Audit & artifacts (spec-complete outputs)¶
- B1 — Richer
TrialRecord+OptimizationResult. ExtendTrialRecordto the spec shape:timestamp,cycle,phase,axis_target,baseline_before_path,proposal_source(numeric: params/study_id/marginals; textual: critic+applier blocks),train/holdoutblocks (loss,loss_std,loss_runs,report_summary,errored_runs_excluded,duration_sec,trial_usd),decisionrationale (noise_bar, improvement_clears_noise, holdout_within_noise, reason),study_state. Acceptance: - A trial round-trips to/from the spec JSON example without loss.
-
Existing readers of the minimal record are updated; serialization is
extra="forbid"-clean. Verification:pytest tests/unit/optimizer/test_models.py -n auto. Dependencies: A6 (decision fields exist to record). Files:src/holodeck/optimizer/models.py,tests/unit/optimizer/test_models.py. Scope: M. -
B2 —
run.jsonheader + deterministic run-id. Switch run-id toYYYY-MM-DDTHH-MM-SS_<sha256(baseline+config+seed)[:8]>; write immutablerun.json(spec §"run.json") on trial 0. NoteDate.now()-equivalents are fine in CLI (timestamp fromdatetime.now), but the hash drives resume identity. Acceptance: - Same
(baseline, config, seed)→ identical hash suffix; any change → different. -
run.jsonround-trips and carries the config fingerprint + subagent paths. Verification:pytest tests/unit/optimizer/test_output.py -n auto. Dependencies: A1. Files:src/holodeck/optimizer/output.py,src/holodeck/cli/commands/optimize.py, tests. Scope: S–M. -
B3 — Per-trial atomic persistence (
trials.jsonl). Append one row after each completed trial (and the baseline) via atomic write + fsync, instead of one bulk write at the end (output.py:112). Partial/in-flight trials write nothing. Acceptance: - After N trials,
trials.jsonlhas N (+1 baseline) parseable rows. -
A simulated kill mid-trial leaves the file ending on a complete row. Verification:
pytest tests/unit/optimizer/test_output.py -n auto. Dependencies: B1, B2. Files:src/holodeck/optimizer/output.py,src/holodeck/optimizer/loop.py, tests. Scope: M. (This isplan.md/tasks.mdT10 — realize it here.) -
B4 —
trajectory.csv+ versioned candidates/instructions + symlinks. Writetrajectory.csv(spec columns: trial_id…accepted,trial_usd,duration_sec); writecandidates/iter-NN.yamlandinstructions/system-prompt.iter-NN.mdon each accept; maintainbest.yaml/best-instructions.mdas atomically-replaced symlinks (write tmp +os.replace). Add--keep-best-onlypruning at exit. Acceptance: - CSV row count = trials; empty
holdout_meanwhen holdout not run. -
iter-NNnumbering matchestrial_id; symlinks point at the current leader. -
Candidates carry
${VAR}placeholders (via existingoverlay_axes), no resolved secrets. Verification:pytest tests/unit/optimizer/test_output.py -n auto. Dependencies: B3. Files:src/holodeck/optimizer/output.py, tests. Scope: M. -
B5 —
report.mdenrichment. Extend the report (output.py:49-95) with: result summary (incl.repeats/exit reason), ASCII sparkline of train/holdout with phase boundaries, per-phase + per-axis attribution table, per-metric baseline→best, full baseline→best diff (yaml + instructions), key accepted rationales, "How to adopt"cp/sedcommands, methodology notes (split sizes,accept_sigma, holdout policy, distributional-overfit + config-level-reproducibility warnings). Acceptance: - Report renders for a multi-cycle run with both phases and ≥1 accept.
- Sparkline marks phase boundaries; attribution sums match accepted Δloss.
Verification:
pytest tests/unit/optimizer/test_report.py -n auto. Dependencies: B1, B4. Files:src/holodeck/optimizer/report.py(new) +output.py,tests/unit/optimizer/test_report.py. Scope: M.
🛑 Checkpoint B — durable & auditable¶
- A run produces the full 6-artifact set + symlinks;
trials.jsonlsurvives a mid-run kill. -
make test-unit && make lint && make type-checkclean.
Phase C — Resume & resilience (plan.md Phase 7)¶
- C1 —
--resumereplay inOptimizerLoop. Loadtrials.jsonl+run.json; re-derive bests by replaying accepted rows in order; rebuild each numeric phase's study from that phase's rows viastudy.add_trial(params, value); carry bests (mean+std) forward; replay last 3 rejected textual gradients into the Critic memory; continue fromlen(trials)+1. Studies reconstructed per phase, never merged. Acceptance: - Replaying a captured
trials.jsonlreproduces the samebest/best_lossdecisions. - A resumed numeric phase's study contains all prior in-phase trials (TPE not reset).
-
No duplicate trial ids; cycle numbering continues correctly. Verification:
pytest tests/unit/optimizer/test_resume.py -n auto. Dependencies: B3 (per-trial persistence is the checkpoint). Files:src/holodeck/optimizer/loop.py,src/holodeck/optimizer/resume.py(new), tests. Scope: M–L. (This is T11.) -
C2 — CLI
--resume+ drift guard + signal handling. Add--resume RUN_ID(auto-detect latest incomplete run when omitted); refuse onbaseline_sha256mismatch unless--force; trap Ctrl-C/SIGTERM → let the in-flight trial finish, writereport.md, exit code 2 with intact state. Acceptance: -
--resume <id>continues a stopped run to completion. - Mismatched config → non-zero exit with a clear message;
--forceoverrides. - Ctrl-C → exit 2; a subsequent
--resumesucceeds. Verification:pytest tests/unit/cli/test_optimize*.py -n auto; manual SIGINT smoke. Dependencies: C1. Files:src/holodeck/cli/commands/optimize.py, tests. Scope: M. (This is T12.)
🛑 Checkpoint C — interruption resilience¶
- Kill a real run mid-trial (SIGINT);
--resumecontinues from the last completed trial with bests + each phase's TPE study intact, reaching the same accept/reject decisions (not bit-exact).
Phase D — CLI diagnostics & proposer fidelity¶
- D1 — New CLI flags + diagnostic modes.
Add
--repeats,--accept-sigma,--max-minutes,--max-usdoverrides and the three diagnostic modes:--dry-run(validate + print resolved axes/budget/loss, exit 0),--print-baseline(trial 0 only + per-metric breakdown, exit 0),--report-only(regeneratereport.mdfrom existing JSONL, no trials). Preserve CLI→YAML→default precedence. Acceptance: -
--helplists every spec flag;--dry-runspends nothing and exits 0. -
--report-onlyrebuilds the report from a captured run dir. Verification:pytest tests/unit/cli/test_optimize*.py -n auto. Dependencies: A1 (config), B5 (report regen). Files:src/holodeck/cli/commands/optimize.py, tests. Scope: M. -
D2 — Critic/Applier structured schema + confidence short-circuit. Replace the bare
gradientstring with the spec schema (Critic:failing_pattern,root_cause_hypothesis,suggested_change_direction,confidence,citations,avoid; Applier:edit_type,rationale,new_text,diff_summary). Short-circuit before the Applier + sweep whenconfidence < min_confidence(default 0.4) — recorded as a cheap skip. Persist both blocks intoproposal_source(B1). Acceptance: - Low-confidence gradient skips the trial without running the Applier or a sweep.
-
citations/edit_type/diff_summaryland in the trial audit row. Verification:pytest tests/unit/optimizer/test_textual.py -n auto. Dependencies: B1. Files:src/holodeck/optimizer/proposers/textual.py,src/holodeck/optimizer/agents/{critic,applier}.yaml, tests. Scope: M. -
D3 — Auto-install user-editable subagents. On first run, copy
critic.yaml/applier.yamlfrom package data to.holodeck/optimizer/agents/{critic,applier}.yamlif missing; load from there so users can edit without losing changes (never overwrite). Record the resolved paths inrun.json. Acceptance: -
Fresh project auto-installs both; an edited local copy is preserved across runs. Verification:
pytest tests/unit/optimizer/test_textual.py -n auto. Dependencies: D2. Files:src/holodeck/optimizer/proposers/textual.py, tests. Scope: S. -
D4 — TPE fidelity +
[optimizer]extra. ConfigureTPESampler(seed=seed+phase_index, n_startup_trials=10, n_ei_candidates=24, multivariate=True); offset the seed per numeric phase; add the warmup-below-max_trialswarning; exposeaxis_marginals/numeric_study_id/paramsfor the audit row; moveoptunato a[optimizer]extra inpyproject.toml(out of base install) with an import guard. Acceptance: - Repeated numeric phases draw different warmup sequences yet stay reproducible.
-
optunanot pulled by base install; clear error if the extra is missing. Verification:pytest tests/unit/optimizer/test_numeric.py -n auto; clean-env install check. Dependencies: A7, B1. Files:src/holodeck/optimizer/proposers/numeric.py,pyproject.toml, tests. Scope: S–M.
🛑 Checkpoint D — spec-complete CLI & proposers¶
- All spec CLI flags + diagnostics present; structured subagents with confidence skip; TPE
configured per spec;
make ciclean.
Phase E — Docs, schema, hygiene¶
- E1 — Schema + docs for the new config.
Extend
schemas/agent.schema.jsonfor the newevaluations.optimizerfields; updatedocs/guides/evaluations.md+AGENTS.mdwith the train/holdout, repeats, acceptance, budget, and resume sections; runpython scripts/generate_agent_schema.py --check. Acceptance: -
Schema validates the spec's full reference
optimizer:block; drift guard green. Verification:make ci. Dependencies: A1. Files:schemas/agent.schema.json,docs/guides/evaluations.md,AGENTS.md,docs/product-specs/033-holodeck-test-optimizer/optimizer.md. Scope: S–M. -
E2 — Refresh stale predecessor docs. Mark
plan-text-proposer.mdas shipped (it still says "no code written yet") and tick its task checkboxes intasks-text-proposer.md; tick the shipped MVP boxes intasks.mdT1–T9; move resume out ofplan.mdPhase 7 with a pointer to this file (single source of truth). Acceptance: -
No predecessor plan claims unshipped status for shipped code. Verification: doc review. Dependencies: None (can run anytime). Files:
docs/product-specs/033-holodeck-test-optimizer/{plan,tasks,plan-text-proposer,tasks-text-proposer}.md. Scope: XS. -
E3 — End-to-end integration test. Full coordinate-descent loop against a tiny in-process agent + small train/holdout split,
repeats=2, mocked Optuna sampler + Critic/Applier; assert a numeric+textual win compounds into one candidate and the σ-bar rejects a sub-noise trial. Acceptance: - E2E green;
best_loss ≤ baseline_loss; both phases contribute to the final candidate. Verification:pytest tests/integration/optimizer/test_end_to_end.py -n auto. Dependencies: A6, B4, C1. Files:tests/integration/optimizer/test_end_to_end.py. Scope: M.
🛑 Checkpoint: Complete¶
- All acceptance criteria met;
make ciclean; full spec v1 contract satisfied. - Manual run on
sample/financial-assistant/claudewrites the 6-artifact set, honest accept decisions, and a resumable run. Human review before merge.
Dependency Graph¶
A1 (config) ──┬── A2 (validation)
├── A3 (train/holdout) ── A4 (mean_loss/repeats) ──┐
├── A5 (loss: penalties/errors/per-turn) ──────────┤
└──────────────────────────────────────────────── A6 (variance accept)
└── A7 (budgets/convergence)
A6 ── B1 (rich TrialRecord) ── B3 (atomic jsonl) ── B4 (csv/candidates/symlinks) ── B5 (report)
A1 ── B2 (run.json/run-id) ───┘ │
B3 ── C1 (resume replay) ── C2 (cli resume/signals) │
B1 ── D2 (subagent schema) ── D3 (auto-install) │
A7,B1 ── D4 (TPE fidelity/extra) A1,B5 ── D1 (cli flags/diagnostics)
A1 ── E1 (schema/docs) (E2 anytime) A6,B4,C1 ── E3 (e2e)
Bottom-up order: A → B → C / D in parallel → E. Phase B must precede Phase C (the audit log is the resume checkpoint). D1–D4 are independent of C and can run in parallel once their own deps land.
Parallelization Opportunities¶
- Parallel-safe: A5 alongside A2/A3 (independent of each other, both need only A1); D2/D3 alongside C1/C2 (textual vs resume are independent); E2 anytime.
- Sequential (shared state): A4→A6→A7 (the accept-gate chain); B1→B3→B4→B5 (artifact pipeline); B3→C1→C2 (resume chain).
- Contract-first: B1's
TrialRecordshape gates B3/B5/C1/D2 — land it before fanning out.
Risks and Mitigations¶
| Risk | Impact | Mitigation |
|---|---|---|
repeats×cycles×phases triples cost vs MVP |
High | max_usd/max_minutes budgets (A7); cost shown ×repeats in progress; repeats lowerable for deterministic agents; confidence short-circuit (D2) skips sweeps. |
Switching min_delta→σ-bar silently changes existing runs' outcomes |
Med | Validation warns on repeats==1; keep min_delta fallback for the deterministic/skip path; E3 asserts the new gate; document in E1. |
Rich TrialRecord churns many downstream readers |
Med | Land B1 first as a contract; extra="forbid" catches drift; update output/report/resume together. |
| Resume study rebuild diverges from a live run | High | Per-phase add_trial from that phase's rows only; C-checkpoint asserts decision-level (not bit-exact) equivalence. |
| Optuna moved to extra breaks base imports | Med | Import guard with a clear "install holodeck[optimizer]" error; clean-env install check in D4. |
| Train/holdout from same distribution hides distributional overfit | Med (honest limitation) | Documented in B5 report + E1 docs; not solvable in v1. |
Out of Scope (explicit — not in this plan)¶
These remain deferred per the authoritative spec (§"Out of scope for v1"):
- Few-shot demonstration optimization — the design's headlined #1 v2 item; needs a
first-class
demonstrationsschema slot, backend prompt injection, and a new selector proposer (its own design pass). Not decomposed here. - Ingestion-time axes (
chunking_strategy,max_chunk_tokens,contextual_embeddings,embedding_model) — a separateholodeck test ingest-sweep. - Parallel trials; K-fold CV; population/evolutionary search; full paired-bootstrap significance testing; co-optimization of multiple textual axes per trial; auto-discovery of axes; cross-run TPE warm-start; live dashboard rendering of optimizer runs.
Open Questions¶
min_deltaretirement: keep it permanently as therepeats==1 && skipfallback, or remove once the σ-bar is proven? (Plan keeps it; flag for reviewer.)- Run-id timestamp vs pure hash: spec uses
timestamp_<hash>; the timestamp is cosmetic and the hash drives resume — confirm the timestamp stays for human readability. --report-onlyvs--report-only --keep-best-onlyinteraction: confirm report-only never prunes.