Files
cc-ci/machine-docs/JOURNAL-poe2e.md
2026-06-13 19:42:59 +00:00

7.7 KiB

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-*.txtbyte-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