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
Back to Knowledge Hub knowledge/dev/laws/dieu44-trien-khai/v0.6-orchestrator-o2-phase-body-e2e-authoring/01-ssot-repo-and-o1-survey-2026-05-20.md