| name | phase6-refinement |
| description | Run Phase 6 (REFINEMENT) of the A2MC calibration workflow as the offline agent — the human-in-the-loop analog of the orchestrator's `_run_refinement()` / `reasoning.interpret_results()` + `extract_lesson()`. Evaluate the experiment results vs baseline + expected outcomes, extract lessons (discoveries / failed approaches), update Adaptive Memory, and decide convergence — converged, rethink (6→3), or redesign (6→0). Use when the user says "evaluate the results", "did the experiment work", "extract the lessons", "run Phase 6", "should we converge or iterate", "what did we learn", after Phase 5 testing. |
| modes | {"requires_fates":false,"nutrient_pathway":"any","scope":["calibration"],"summary":"Offline analog of Phase 6 (evaluate, learn, converge/iterate). Applies in every calibration mode."} |
Phase 6: Refinement (offline agent)
The offline analog of _run_refinement(). Online, reasoning.interpret_results() +
extract_lesson() evaluate and learn automatically; offline, YOU do both — judge the experiment
honestly against expectation, name the mechanism you learned, and decide where the loop goes next.
Floor, not ceiling. The online agent classifies confirmed/partial/rejected and picks the next
phase. As the offline agent you can do the deeper work the loop can't: a full equifinality /
cross-regime analysis (scientific-analysis), a manuscript figure, reconciling this result with
prior rounds (compare-calibration-rounds), or deciding a finding is worth curating into the KB.
Evaluate at least as rigorously as the online agent, then reason past it.
Critical mode difference — the memory write gate. The online agent runs Memory in propose
mode (stages to auto_discovered_pending.json, cannot write curated knowledge). You, the offline
agent, are the disposer — you write curated knowledge directly (interactive mode) and you promote
the online agent's staged proposals. "Online proposes, offline disposes." This is the thing Phase 6
does differently offline.
Inputs (from Phase 5): experiment results (per-target metrics, extraction status) + the Phase 4
expected outcomes. Deliverable: honest per-hypothesis verdict, lessons written to Memory, a
convergence decision.
Step 1 — evaluate the results (reads existing experiment results — no new simulations)
phases/phase6_refinement/evaluate_results.py compares each experiment to expected outcomes and to
the Phase 2 baseline → outcome class (SUCCESS / PARTIAL / MARGINAL / FAILED), best experiment,
targets met.
Footgun — data-reliability gate. A silent extraction failure (no error, empty metrics) reads
as 0/6 targets and looks like a real FAILED result. Confirm extraction_status == "extracted" AND
non-empty metrics AND no error before trusting any outcome — otherwise you contaminate the KB
with a phantom failure.
Step 2 — interpret + extract lessons (you are the reasoning)
Mirror interpret_results (targets improved/degraded, hypothesis_status honestly — partial is
PARTIAL, not SUCCESS; cross-PFT impact) and extract_lesson (is it a discovery? a failed
approach? a named pattern — Allocation Paradox, Perfect Storm, Mortality Trap?). Verify any
mechanism against RAG before asserting it.
Step 3 — update Adaptive Memory (offline = curated, direct)
- Vetted new discovery / failed approach you originated → write it via
inject-knowledge
(interactive mode writes the curated JSON directly through memory/manager.py).
- The online agent's staged proposals (
auto_discovered_pending.json) → review + promote/discard
via curate-knowledge (tools/review_pending_knowledge.py). This is the Tier-3 write gate.
Step 4 — decide where the loop goes (GATE on the middle-loop counter)
The online orchestrator enforces this fork in code (orchestrator.py state machine: experiment_count
vs max_experiments), so it physically cannot skip a cycle. Offline you must enforce the SAME gate by
hand — the offline agent matches or exceeds the online loop discipline, it never rushes past it. Read
experiment_count / skip_testing_count from workflow_state_offline_r{RR}.json before deciding.
Structural objective gate (docs/34) — fill it, don't skip it. Before recording a decision, populate the
phase6_decision block and run the validator; a failing check blocks the escalation (it cannot be the
path of least resistance):
from tools.workflow_state_offline import WorkflowStateOffline
st = WorkflowStateOffline.load(calibration_round=RR)
st.set_phase6_decision(decision="rethink_6to3",
objective="6 targets", best_so_far="3/6", binding_target="<the specific failing target>",
next_targeted_experiment="<named, in-range, target-aimed experiment aimed at binding_target> | NONE",
exhaustion_justification="<why no in-range experiment remains> | ''", max_experiments=10)
violations = st.validate_phase6_decision()
stop_model_dev / redesign_6to0 are rejected while experiment_count < max_experiments and a named
next_targeted_experiment remains (that is a rethink_6to3); stop_model_dev also requires
next_targeted_experiment == NONE + a non-empty exhaustion_justification. On rethink_6to3, advance the
counter via st.set_position(experiment_count=experiment_count+1) and st.save().
- All targets met → converged (Phase 7); write the final config + round summary.
- NOT met,
experiment_count < --max-experiments (default 10) → 6→3 rethink is the DEFAULT. Do NOT
escalate while the cycle budget remains. Before choosing anything other than rethink, confirm there is no
named, in-range, target-aimed parameter experiment left to run ([[feedback_performance_experiment_is_the_objective]]);
if one remains — including a lead flagged in a prior log — that is the next rethink cycle, run it.
On routing 6→3: increment experiment_count in the state file.
- NOT met,
experiment_count = --max-experiments (middle loop exhausted) → 6→0 redesign: back to
phase0-design with widened bounds; increment calibration_round. Redesign earlier is justified ONLY if
every remaining candidate is a Morris-bound edge parameter (a redesign signal, not a Phase-4 knob) AND
no in-range experiment remains — the exception, not the default.
"Stop → improve the model" is NOT a loop branch. Modifying model source is outside the A2MC
calibration loop; it is justified only after the loop is provably exhausted (rethink cycles to the cap,
then redesign) OR a structural impossibility is proven by exhausting the targeted experiments, not
asserted from one result. Jumping there with experiment_count cycles still on the clock is the rush this
gate prevents.
Step 5 — log, report, hand off
Log via calibration-log (phase log → PhaseLogger.log_refinement). Standardized reporting:
summarize-calibration-round (this round) / compare-calibration-rounds (vs prior). Then route per
Step 4. Evidence gate (docs/33): the refinement log must cite the evaluation artifact produced this
session (the biomass/target extraction + figure in phase_results/{stem}/); run
python tools/check_offline_log_evidence.py <log.md> (exit 0) before curating any lesson.
Related skills / next phase
- Curate staged proposals →
curate-knowledge. Inject a vetted finding → inject-knowledge.
- Deeper investigation / figure →
scientific-analysis. Round reports →
summarize-calibration-round, compare-calibration-rounds.
- Next: converged (Phase 7), or loop to
phase3-diagnosis (rethink) / phase0-design (redesign).
Changelog
- 2026-07-06: Wired the middle-loop gate into Step 4. The decision fork now gates on
experiment_count
vs --max-experiments (rethink 6→3 is the DEFAULT while cycles remain; redesign 6→0 only at the cap), adds
the "no in-range target-aimed experiment left" precondition before any escalation, the counter-increment
step, and an explicit "'stop → improve the model' is NOT a loop branch" guard. Mirrors the online
orchestrator's coded state machine so the offline agent can't rush past the loop. Ported from demo 2d3f4b0
(v3.12), scrubbed of the Kougarok worked example. See feedback_performance_experiment_is_the_objective.
- 2026-07-02: Created — offline Phase 6 routine mirroring
interpret_results() + extract_lesson(); encodes the offline "disposer" write gate (direct curated writes + promote staged proposals), delegates memory to curate-/inject-knowledge, reporting to summarize-/compare-calibration-round.