KB-3C39
Orchestrator O2 · 01 SSOT + Repo + O1 Survey
10 min read Revision 1
dot-iu-cutterv0.6orchestrator-o2-phase-body-e2e-authoringssot-repo-surveyg0-g1-passdieu442026-05-20
Orchestrator O2 · 01 SSOT + Repo + O1 Survey
doc 1 of 7 · 2026-05-20 · O2 phase-body + in-memory E2E authoring macro
phase : G0 + G1 — SSOT read + repo precheck + O1 code survey outcome : G0 PASS · G1 PASS production_mutation : NONE
1. SSOT — GPT ruling read
reviews/dot-iu-cutter-v0.6-main-ff-after-o1-pass-gpt-ruling-2026-05-20.md
(full):
PATH_FF_O1_TO_MAIN: PASS
result: MAIN_FF_O1_TO_MAIN_PASS
agent_behavior: PASS_CORRECT
main_HEAD: 35ca9e1
feature_HEAD: 35ca9e1
production_mutation: NONE
orchestrator_execution_enabled: false
next_phase: O2_PHASE_BODY_AND_IN_MEMORY_E2E_AUTHORING
next_effort: xhigh
O2_scope:
- implement phase bodies against in-memory/discoverer/reporter seams where safe
- implement GATE_INVARIANTS predicates
- add in-memory E2E orchestration tests
- keep Mode.LIVE refused / execution_enabled false
- no production DB mutation
- no live CUT/VERIFY/enact
- no deploy/restart/push/tag
forbidden:
- production mutation
- live orchestrator execution
- enabling production execution kill-switch
- deploy/restart
- push/tag remote
- source_document/source_version mutation
- real crypto replacement
- hardcoded secrets/runtime ids
The agent accepted the ruling verbatim and entered macro O2_PHASE_BODY_AND_IN_MEMORY_E2E_AUTHORING at effort xhigh.
2. KB design + O1 authoring docs consulted
read_in_full:
- v0.6-orchestrator-o1-authoring/03-contracts-and-skeleton-summary-2026-05-20 (8.6 KB)
- v0.6-orchestrator-o1-authoring/06-final-o1-authoring-report-2026-05-20 (6.7 KB)
- v0.5-automation-orchestrator-design/02-end-to-end-state-machine-2026-05-20 (12.2 KB)
- v0.5-automation-orchestrator-design/03-phase-orchestration-and-gates-2026-05-20 (15.7 KB)
- reviews/dot-iu-cutter-v0.6-main-ff-after-o1-pass-gpt-ruling-2026-05-20 (2.2 KB)
read_for_titles_only (already cached from O1):
- v0.5-automation-orchestrator-design/{01,04,05,06,07}-…
total_kb_bytes_loaded_into_context: ~45 KB
3. Repo precheck (G0)
working_directory : /Users/nmhuyen/iu-cutter-build/repo/iu-cutter
branch_current : feature/constitution-snapshot-mark-dryrun
feature_HEAD : 35ca9e1b51f2aac1dbcb73932e855917aede91fa
main_HEAD : 35ca9e1b51f2aac1dbcb73932e855917aede91fa (== feature)
tree_status : clean (no uncommitted files)
remote : absent (no push possible — by policy)
tags : none
last_3_commits:
- 35ca9e1 feat(orchestrator/O1): authoring-only skeleton for v0.6 one-command automation orchestrator
- 0a64a61 chore(fingerprints): rename prior_md5_prosrc truncated value to display_only key
- d7ea6d1 chore(light-followups): enrich fn_iu_create fingerprint note + refine DB env-guard baseline test
runtime:
python_version : 3.11.6 (/usr/local/bin/python3)
pytest_baseline : 308/308 OK from O1 closeout
G0 PASS: HEADs match expectation, kill-switch off, no dirty tree.
4. O1 orchestrator package surface (G1)
cutter_agent/orchestrator/ — 11 modules + 11 phase files + 4 test files
authored at commit 35ca9e1. Per-file inventory:
top_level:
__init__.py : 21 LOC — milestone tag + kill-switch flag
enums.py : 170 LOC — 14 states, 13 forward edges, 11 phases,
11 internal gates, 3 sovereign gates,
phase soft-caps, batch/failure enums
errors.py : 107 LOC — 17 STOP-route exception classes
run_context.py : 168 LOC — RunContext + PhaseRecord + ApprovalRecord
+ ErrorRecord + SECRET_KEY_DENYLIST
policy.py : 92 LOC — USER_REFUSED_ARGS (20 names),
assert_no_user_artifact, discover-first,
assert_no_module_level_pins
gates.py : 151 LOC — GATE_INVARIANTS registry (36 named
invariants stubbed _todo_o2),
evaluate_internal evaluator
state_store.py : 133 LOC — JSON sidecar + fcntl.LOCK_EX|LOCK_NB
+ atomic write via tempfile+os.replace
approval.py : 136 LOC — validate_sovereign_approval
(TTL: SG_1 24h, SG_2 12h, SG_2 requires
review_decision_id)
kb_reporter.py : 101 LOC — KBReporter Protocol + DryRunReporter
(sidecar writes; raises StopKbUploadFailed)
discover.py : 92 LOC — Discoverer Protocol (7 read-only methods)
+ InMemoryDiscoverer
runner.py : 192 LOC — OrchestratorRunner.cut/resume + _drive
(refuses Mode.LIVE while killswitch off)
batch.py : 133 LOC — Queue/QueueItem + BatchRunner.plan
phases/ (each ≤30 LOC O1 skeleton):
source_pin.py : 40 LOC — read-only functional (only O1 phase body)
mark.py : 12 LOC — StopNotImplemented stub
cutplan.py : 13 LOC — StopNotImplemented stub
backup.py : 13 LOC — StopNotImplemented stub
grant_probe.py : 13 LOC — StopNotImplemented stub
cut_leg_a.py : 29 LOC — ProductionExecutionNotAuthorized guard
(refuses regardless of mode)
structural_verify.py : 13 LOC — StopNotImplemented stub
leg_b_record.py : 19 LOC — ProductionExecutionNotAuthorized guard
write_verify.py : 19 LOC — ProductionExecutionNotAuthorized guard
lifecycle_enact.py : 22 LOC — ProductionExecutionNotAuthorized guard
closeout.py : 12 LOC — StopNotImplemented stub
5. O2 gaps + design choices (informs G2 + G3)
gap_1_mutating_phase_guard_too_coarse:
what : 4 mutating phases check ``__execution_enabled__`` flag and
raise ProductionExecutionNotAuthorized REGARDLESS of mode.
why_a_gap : Mode.DRYRUN is the entire reason we need an in-memory E2E.
The kill-switch should protect Mode.LIVE only.
fix : phase bodies branch on (mode==LIVE and not __execution_enabled__);
Mode.DRYRUN runs the deterministic simulator on InMemoryDiscoverer.
gap_2_runner_resume_skips_phase_body:
what : runner.resume() sets ctx.state = SOVEREIGN_RESUME_TARGET[…]
directly. The post-sovereign phase (cut_leg_a / lifecycle_enact)
is NEVER invoked because the drive loop's exit condition
already includes the AWAITING_* pause states.
why_a_gap : without invoking the body, the run skips the actual write
and jumps to the next read-only phase. Sovereign approval
alone does not record the change_set_id, manifest_envelope_id,
etc.
fix : resume() validates approval → records on ctx → drift-revalidates
→ invokes the post-sovereign phase → advances state → re-enters drive.
gap_3_approval_consumption_not_tracked:
what : RunContext has no consumed_approval_ids list; design doc 03 §7
requires "each approval_kb_id consumed exactly once per run".
fix : add RunContext.consumed_approval_ids: list[str]; runner refuses
replay (ApprovalConsumedAlready).
gap_4_invariant_predicates_are_all_todo:
what : GATE_INVARIANTS registry holds 36 named invariants, all bound
to ``_todo_o2`` which raises NotImplementedError.
fix : replace _todo_o2 with predicates over (ctx.context_pins,
ctx.sovereign_approvals, ctx.phases, ctx attrs). Predicates
assert presence + shape of evidence the phase body was supposed
to record. Live-DB assertions stay inside phase bodies.
gap_5_discoverer_lacks_simulator_surface:
what : InMemoryDiscoverer only exposes 7 read-only lookups; phases
need mark_region / cutplan_rebuild / simulate_iu_creates /
simulate_fn_iu_enact / structural_probe / trigger checks /
verify_result counter / manifest_envelope counter.
fix : add 8 new methods + 4 dataclasses (MarkRow, CutplanRow,
IUCreateResult, EnactResult) to discover.py; keep all
Mode.DRYRUN deterministic with no IO.
gap_6_phase_bodies_silently_explode_without_seed:
what : if a discoverer seed is missing, the phase body raises a raw
KeyError; the runner's except clause only catches OrchestratorError.
fix : wrap drive loop's phase-invocation with a generic-exception
catch that converts to StopInvariantFailed. No silent reraise;
operator sees a clean stop_code and a KB stop doc.
6. G0/G1 verdict
g0_outcome : PASS (SSOT read, ruling accepted, repo HEAD verified,
killswitch off, tree clean)
g1_outcome : PASS (all 22 orchestrator/phase modules surveyed,
6 actionable gaps catalogued, no v0.5 module needs
touching)
production_mutation : NONE (read-only inspection only)
next_gate : G2 — phase body implementation