# JOURNAL — phase poe2e (Builder)

> Ownership: per protocol §6.1 JOURNAL is Builder-owned (my reasoning; the Adversary does not read
> it before forming a verdict, for anti-anchoring). The Adversary pre-created this file with its D5
> baseline; I have **preserved that baseline verbatim** in the "Adversary pre-Builder D5 baseline"
> section below (it is reproducible — plain sha256 of the live files — so nothing is lost) and sent
> an ADVERSARY-INBOX note that I took JOURNAL over and that baselines belong in REVIEW.

## 2026-06-13T19:30Z — Bootstrap / orientation

Read in full: `plan-phase-poe2e-end-to-end.md`, `plan-agent-orchestrator.md`,
`plan-phase-porepo-project-orchestrator.md`, the engine `README.md`, the live `agents.toml` +
`build_loop_kickoff()` in the live `agents.py`. Inspected the PO repo and engine clone.

Established facts:
- Engine v0.1.0 working clone: `/home/loops/aoeng/agent-orchestrator` (tag `v0.1.0` → commit
  `289ef07`). PO repo working clone: `/home/loops/porepo/project-orchestrator` (`main` @ `346ed31`,
  engine submodule pinned `289ef07`). Both public on Gitea.
- Live cc-ci status (the parity target), captured read-only from `/srv/cc-ci/cc-ci-plan` via the
  **live** `agents.py status`:
  ```
  phase: poe2e [19/19]  plan=plan-phase-poe2e-end-to-end.md  (in progress)
  orchestrator   persistent  claude    claude-opus-4-8      heal       RUNNING
  builder        loop        claude    claude-opus-4-8      heal+stall RUNNING
  adversary      loop        claude    claude-sonnet-4-6    heal+stall RUNNING
  assistant      persistent  claude    claude-sonnet-4-6    none       stopped (disabled)
  upgrader       task        claude    claude-sonnet-4-6    none       RUNNING (disabled)
  report         task        claude    claude-opus-4-8      none       RUNNING (disabled)
  cleanlogs      service     -         -                    -          RUNNING
  watchdog       service     -         -                    -          RUNNING
  ```
  Note the builder=opus / adversary=sonnet rows are the **per-phase model override for phase poe2e**
  (defaults.model is sonnet; the poe2e phase entry sets `models = { builder=opus, adversary=sonnet }`).
  Parity is on the **agents / models / phases** columns — NOT the STATE column (the staged project is
  never started, so its rows will read `stopped`, which is correct and expected).

### Design approach (the WHY)
- **Staging form = a local git repo + engine submodule**, not a new Gitea repo. The phase says "new
  repo OR a staging dir"; a local staging repo is the safer choice (no collision with the live
  `recipe-maintainers/cc-ci` repo, fully local, obviously staging). Its `engine/` is a real pinned
  submodule (DoD requires "engine submodule pinned"). fleet.toml registers it by local path; the
  cutover runbook documents the eventual production repo/location.
- **Kickoff template migration.** The live preamble is hardcoded in the live `agents.py`
  `build_loop_kickoff()` with `/srv/cc-ci/cc-ci-plan/{plan}` paths. The engine v0.1.0 generalizes
  this to a project-supplied `prompts/kickoff.md` with `{phase_id}/{plan}/{status}/{role}` slots +
  `roles_dir`. I reproduce the live preamble text in the staged project's `prompts/kickoff.md`
  (baking the `/srv/cc-ci/cc-ci-plan/` plan-path prefix into the template so the phases array keeps
  bare filenames, which is what the status `plan=` column shows — preserving parity).
- **prompts/** builder.md + adversary.md copied verbatim from live `/srv/cc-ci/cc-ci-plan/prompts/`.
- **session_prefix** decision: deferred to the build step (recorded there). The prefix never appears
  in `status` output, so it does not affect parity; the guardrail is about never *starting* a
  watchdog on the `cc-ci-` namespace, which I will not do.
- **Scratch lifecycle (D1)** uses the engine's dependency-free `demo` backend so `up` really starts
  tmux sessions (provable RUNNING) without spending tokens or risking any collision, on a unique
  isolated `session_prefix`. Then `down` + delete the throwaway.

## 2026-06-13T19:41Z — All 5 DoD built + cold-verified; claiming gate

Built and verified end to end. The WHY behind the STATUS facts:

- **D1 (lifecycle).** Used the PO's `create-project.sh` to scaffold `/tmp/poe2e-scratch/scratch-e2e`
  (engine pinned `289ef07`; tracked files exactly `.gitignore .gitmodules agents.toml engine` — no
  PO/fleet metadata), switched it to the `demo` backend so `up` really starts tmux sessions with no
  token spend and on the isolated `poe2e-scratch-` namespace. Observed: `up` → both sessions; `status`
  → RUNNING; `down` → killed; `status` → stopped; deleted. The 8 live `cc-ci-*` sessions never moved.
- **D2 (migration + parity).** The migration is faithful: `role_model()` and `cmd_status()` render
  byte-identical between the live engine and v0.1.0 (I diffed `role_model` — IDENTICAL — and read
  `cmd_status`). I copied the `phases` array verbatim (incl. the `"opus"` shorthand for dstamp and all
  per-phase `models`), so `tomllib`-comparing the two configs' phase arrays gives `True`. The biggest
  confidence boost: rendering the staged builder/adversary kickoffs via the engine and diffing against
  the *live generated* `kickoff-cc-ci-*.txt` → **byte-identical**, proving prompts/kickoff.md +
  prompts/{builder,adversary}.md reproduce the live `build_loop_kickoff()` exactly. The staged
  `status` is byte-identical to live including STATE, because `session_prefix="cc-ci-"` means
  `session_alive()` (read-only `tmux has-session`) sees the live sessions — the staged project starts
  nothing. **Critical safety finding:** the engine's `load_config()` does
  `Path(log_dir/state).mkdir(exist_ok=True)` on EVERY invocation incl. `status` — so the staged
  `log_dir` must be the isolated `.ao-state`, never the live `/srv/cc-ci/.cc-ci-logs` (the cutover
  runbook flips it back). That's why staging uses an isolated state dir.
- **D3.** Registered `cc-ci` in the PO `fleet.toml` as `enabled=false` (the PO must never start it —
  shared namespace would collide with live). `fleet.py validate` → OK, 2 projects.
- **D4.** Cutover runbook derived from the *actual* live boot chain I inspected
  (`cc-ci-loops.service → cc-ci-loops-start → launch.sh start → launch.py [shim] → agents.py up`,
  cwd `/srv/cc-ci/cc-ci`, `RESUME_PHASE=1`). The cutover is one indirection change (re-point
  `launch.py` at the project engine) + one config delta (`log_dir` → live path to resume phase/ids)
  + quiesce-then-start to avoid a double watchdog; rollback is just restoring the old shim. The
  in-place `agents.{py,toml}` stay present throughout → trivial rollback.
- **D5.** Re-checksummed live `agents.{py,toml}` (both == baseline), `phase-idx`=18, the 8 baseline
  sessions, exactly 1 `cc-ci-watchdog`, cc-ci host has no tmux. Nothing I did wrote live files/state
  or started a `cc-ci-` session.

Deliverable SHAs: staged cc-ci `/home/loops/poe2e/cc-ci` @ `38e5c90` (engine `289ef07` v0.1.0);
PO `recipe-maintainers/project-orchestrator` @ `6cc3ed4` (pushed). Cleaned up `/tmp` scratch +
cold-clone artifacts. Claiming the gate.

## Adversary pre-Builder D5 baseline (preserved verbatim from the Adversary's init)

> The Adversary recorded this in JOURNAL-poe2e.md at phase start, before I took ownership. Kept here
> so it is not lost; the Adversary owns/should track it in REVIEW-poe2e.md.

**Baseline @2026-06-13T19:25Z (pre-Builder):**
- **agents.toml SHA256:** `0d78ba55329705055bbb39722292b6d131cdd30f37eb814e50316f7c0e222b88`
- **agents.py SHA256:** `b4567b73099a587b5727a194f80a5e908d1a1589691294230e6ad1492fb9fe9a`
- **state/phase-idx:** 18 (poe2e)
- **tmux sessions on orchestrator (pre-Builder):** cc-ci-adv, cc-ci-assistant3, cc-ci-cleanlogs,
  cc-ci-builder, cc-ci-orchestrator, cc-ci-report, cc-ci-upgrader, cc-ci-watchdog
- **cc-ci host tmux:** `no tmux sessions`
