Skip to content

Commit 1faf53a

Browse files
SamPlvsSam TukraclaudeSam Tukra
authored
feat(control-plane): v2 Phase 2 — plan ledger with oracle-owned pass flags (WS-B) (#108)
* feat(control-plane): v2 Phase 2 — plan ledger with oracle-owned pass flags (WS-B) Implements plans/zo-v2-rearchitecture.md Phase 2 (oracle checks 8-10): - src/zo/ledger.py: plan-ledger.json in the project memory root — one entry per (phase, subtask) with synthesized acceptance criteria (artifact existence; oracle threshold for phase_4), passes/attempts/ last_failure, and a phase_status map. Merge-preserving regeneration; every write atomic (temp + os.replace). - Oracle-owned flips: mark_phase_passed called ONLY from the automated gate's verified path and nonce-verified human PROCEED; ITERATE and loop-CONTINUE reset with reason; mark_subtask_complete counts attempts but cannot set passes; plan-ledger.json added to _SEALED_DEFAULTS so builder Write/Edit is denied by the WS-A4 hook (check 9). - Story sizing lint: optional '## Stories' section (StorySpec parser); validate_plan rejects stories without a machine-verifiable criterion (threshold / artifact path / `command`) — surfaces via preflight and zo validate; legacy plans without Stories untouched (check 10). - zo status renders the control plane from the ledger (per-phase status, pass counts, attempts, last failure); STATE.md stays the human projection and legacy fallback (check 8). - Phase-1 hardenings (recon findings): contracts.set_active_phase now atomic; zo build exports ZO_MEMORY_ROOT/ZO_DELIVERY_ROOT/ ZO_CONTRACTS_PATH so per-project sealing works in delivery sessions. Deferred to Phase 3 (documented in DECISION_LOG): evaluate_loop_state ledger input; session-restore cutover (protects the PR-036 fix). Tests: 908 -> 929 passed / 7 skipped. ruff src/ clean. validate-docs green. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * docs(memory): session-040 handoff notes for Phase 3 pickup Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Sam Tukra <sam101fe4x@Sams-MBP.Home> Co-authored-by: Claude Fable 5 <noreply@anthropic.com> Co-authored-by: Sam Tukra <sam101fe4x@Sams-MacBook-Pro.local>
1 parent 0a73f08 commit 1faf53a

16 files changed

Lines changed: 911 additions & 13 deletions

File tree

docs/COMMANDS.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,14 @@ zo gates set MODE --project NAME
158158

159159
`MODE` is one of: `supervised` (human approves every gate), `auto` (orchestrator approves unless ambiguous), `full-auto` (all gates auto-approved).
160160

161+
### zo status (control plane)
162+
163+
When a project has a `plan-ledger.json` (v2 WS-B — generated automatically at
164+
plan decompose), `zo status` renders progress from it first: per-phase status,
165+
oracle-owned pass counts, attempts, and last failure. The ledger is the
166+
machine-readable truth; STATE.md remains the human-readable projection and
167+
the fallback for legacy projects.
168+
161169
### zo gates approve / reject
162170

163171
Record a nonce-verified human decision on the pending blocking gate (v2

memory/zo-platform/DECISION_LOG.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1265,3 +1265,15 @@ The `--no-headlines` flag is preserved (not removed) for backwards compatibility
12651265
**Honest caveats:** PostToolUseFailure did not fire for nonzero-exit Bash commands in this session — its semantics appear limited to tool-infrastructure errors, so the failure feed will capture fewer events than designed; if nonzero-exit capture matters, add PostToolUse-with-error-inspection in WS-D. PreCompact/SessionEnd not yet observed live (no compaction occurred; SessionEnd fires at session close) — same wiring pattern as the three proven events. A full `zo build` demo run remains desirable on a machine with the claude CLI (this Desktop-managed Mac has none — see PR-046).
12661266

12671267
**Outcome:** 904 → 908 tests (3 trace + 1 live-payload drift-guard), ruff clean. Fail-open verified end to end in production conditions. Evidence committed to PR #107.
1268+
1269+
## Decision: 2026-08-12T17:00:00Z
1270+
**Type:** FEATURE + ARCHITECTURE
1271+
**Title:** v2 Phase 2 (WS-B control plane) — plan ledger with oracle-owned pass flags, story sizing lint, ledger-first status
1272+
1273+
**Decision:** Implemented WS-B per plans/zo-v2-rearchitecture.md Phase 2. (1) `src/zo/ledger.py`: `plan-ledger.json` in the project memory root — one entry per (phase, subtask) with synthesized acceptance criteria (artifact existence for all phases; oracle threshold for phase_4), verification descriptor, `passes`, attempts, last_failure, plus a phase_status map. Regeneration is merge-preserving (progress survives re-decompose); every write atomic. (2) Oracle-owned flips: `mark_phase_passed` is called ONLY from the two verified-completion paths (automated gate after artifact/experiment checks, nonce-verified human PROCEED); ITERATE/loop-CONTINUE reset entries with the reason; `mark_subtask_complete` counts attempts but cannot set passes; the ledger file joined `_SEALED_DEFAULTS`, so builder Write/Edit is denied by the existing WS-A4 hook. (3) Sizing lint: optional `## Stories` plan section (StorySpec parser) + `validate_plan` rule — every declared story needs ≥1 machine-verifiable criterion (threshold/path/`command`); surfaces through preflight and `zo validate` for free; legacy plans without Stories are untouched. (4) `zo status` renders a control-plane table from the ledger (per-phase status, pass counts, attempts, last failure) with STATE.md as fallback/projection.
1274+
1275+
**Also fixed (recon findings on Phase 1):** `contracts.set_active_phase` was non-atomic (torn read = enforcement silently off) — now temp+rename; the wrapper never exported hook env for delivery sessions — `zo build` now passes ZO_MEMORY_ROOT/ZO_DELIVERY_ROOT/ZO_CONTRACTS_PATH via extra_env, closing the per-project sealing gap.
1276+
1277+
**Scope deferrals (deliberate, to Phase 3):** `evaluate_loop_state` keeps its ExperimentRegistry input (already oracle-derived; signature change touches ~20 test call sites and belongs to the fresh-context loop rework); session-state restore still reads STATE.md (cutover rides the fresh-context substrate to avoid regressing the PR-036 GATED-precedence resume fix).
1278+
1279+
**Outcome:** 908 → 929 passed / 7 skipped (+21: 13 ledger, 5 stories/lint, 2 nonce-flip, 1 status), ruff clean, validate-docs green. Oracle checks 8-10 have passing seeded tests: status renders from the ledger; builder ledger-write denied while the oracle flip lands; vague story rejected. Cascade: specs/plan.md (§10 Stories + lint), specs/workflow.md (state-tracking line), docs/COMMANDS.md (status control plane). Branch `claude/v2-phase2-control-plane`.

memory/zo-platform/STATE.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ status: complete
88

99
## Current Position
1010

11-
**Session 040 (current) — pick up here.** Research + decision session: deep-dive review of three agent-orchestration repos (oh-my-claudecode, ruflo, ralph — cloned to `~/Documents/code/`) to inform the ZO v2 rearchitecture. 9-agent workflow (7 source-reading lenses + ZO baseline + adversarial synthesis, ~1.06M tokens) catalogued **63 features**, distilled to **12 ranked adoptions** + 6 rearchitecture themes + 11 anti-patterns; all findings persisted to `memory/zo-platform/research/2026-08-12-repo-reviews/` (per-repo markdown + `raw-findings.json`). **Sam decided: adopt all 12.** Work organized into **five layer-based workstreams** (A enforcement plane, B control plane, C execution substrate, D self-learning/platform oracle, E operator experience) — NOT source-repo categories, because features from different repos interlock into single mechanisms. Shipped this session: `plans/zo-v2-rearchitecture.md` (full plan: 6 gated phases, 20-check oracle, anti-scope; + `.gitignore` exception), `docs/reference/v2-rearchitecture.mdx` (all 12 features w/ provenance + repo links; added to mint.json Reference nav), `docs/roadmap.mdx` v2 section (4 pillars + repo credits), website §11 "What's next" (new section w/ 3 repo credit cards; quick start renumbered §12; drawer nav updated). **Verification caveat: no Node.js on this machine** — Astro build NOT run; website change verified via HTML-parser balance check + static-server DOM inspection (section text, all 4 links, drawer entry, renumbering all confirmed rendered). CI/deploy build must confirm. **Same session, part 2 — v2 Phase 1 (WS-A enforcement plane) SHIPPED** on branch `claude/v2-phase1-enforcement` (stacked on the plan branch, PR #106): (A1) `src/zo/contracts.py` — contracts.json emitted at decompose into memory_root (gate_mode precedent), `contract_produced` upgraded from prose placeholders to concrete paths (ownership ∩ required_artifacts, ownership-dir fallback), SubagentStop hook validates deliverables (missing/undersized/pattern/empty-dir) and blocks with a violation list; (A2) drift-guard Stop hook — completion-claim regex over the last assistant transcript message + added TODO/FIXME/NotImplementedError lines in `git diff HEAD` → block (env kill-switch `ZO_DRIFT_GUARD=0`); (A3) PreCompact (STATE flush + checkpoint decision), SessionEnd (summary backfill), PostToolUseFailure (`logs/comms/failures-{date}.jsonl` feed) — specs/memory.md recovery section updated to match (replaces the never-built periodic postToolUse checkpoint design); (A4) sealed-paths PreToolUse guard — memory-root control files (gate_mode/gate_nonce/gate_decision/contracts.json/sealed_paths) + user `sealed_paths` prefixes denied, off-limits write-scope enforced per contracts.json when agent identity present in hook input (plan check 6 AMENDED: no disallowedTools frontmatter exists for subagents and verifiers need scoped writes — path-scoped enforcement instead, fail-open without identity); (A5) nonce gates — minted at GATED (`secrets.token_hex(8)` → `gate_nonce` file), surfaced in `prepare_gate_review`, `apply_human_decision` raises PermissionError without it (single-use, cleared on terminal decisions), new `zo gates approve/reject --nonce` CLI writes DECISION_LOG + comms + `gate_decision` file consumed on next decompose, `/approve`+`/reject` slash commands rewritten to route through the CLI (forgeable hand-edit path CLOSED). All via one shim (`.claude/hooks/zo-hookkit.sh` → `python3 -m zo.hookkit`, venv-preferring, fail-open) + 6 new settings.json wirings. **First-ever hook-script tests** (subprocess + stdin JSON pattern). **854 → 904 passed / 7 skipped, ruff `src/` clean, validate-docs green.** 4 pre-existing integration tests updated to pass the nonce (designed behaviour change). Plan oracle checks 1-5 + 7 have passing seeded-failure tests; check 6 as amended. **Part 3 — live pre-PR verification (Sam-directed):** added always-on hook-trace observability (`logs/hook-trace-{date}.jsonl`, `ZO_HOOK_TRACE=0` off-switch) and verified in the live session itself: sealed-paths DENIED a real Write to gate_mode; drift-guard fired correctly-silent on a real Stop; subagent-stop fired with `agent_type`+`agent_id` in the live payload — **agent-identity open question RESOLVED** (per-agent enforcement keys correctly). Drift-guard now prefers the live payload's `last_assistant_message` (transcript parse = fallback). Caveats logged: PostToolUseFailure doesn't fire on nonzero-exit Bash (infrastructure errors only); PreCompact/SessionEnd not yet observed live; full `zo build` demo needs a machine with the claude CLI (this Mac has none — PR-046). **908 passed / 7 skipped, ruff clean.** **Next:** Phase 1 gate review → then WS-B control plane (plan-ledger.json) per `plans/zo-v2-rearchitecture.md`; prior Batch D/E + Tier-1 items queue behind v2.
11+
**Session 040 (current) — pick up here.** Research + decision session: deep-dive review of three agent-orchestration repos (oh-my-claudecode, ruflo, ralph — cloned to `~/Documents/code/`) to inform the ZO v2 rearchitecture. 9-agent workflow (7 source-reading lenses + ZO baseline + adversarial synthesis, ~1.06M tokens) catalogued **63 features**, distilled to **12 ranked adoptions** + 6 rearchitecture themes + 11 anti-patterns; all findings persisted to `memory/zo-platform/research/2026-08-12-repo-reviews/` (per-repo markdown + `raw-findings.json`). **Sam decided: adopt all 12.** Work organized into **five layer-based workstreams** (A enforcement plane, B control plane, C execution substrate, D self-learning/platform oracle, E operator experience) — NOT source-repo categories, because features from different repos interlock into single mechanisms. Shipped this session: `plans/zo-v2-rearchitecture.md` (full plan: 6 gated phases, 20-check oracle, anti-scope; + `.gitignore` exception), `docs/reference/v2-rearchitecture.mdx` (all 12 features w/ provenance + repo links; added to mint.json Reference nav), `docs/roadmap.mdx` v2 section (4 pillars + repo credits), website §11 "What's next" (new section w/ 3 repo credit cards; quick start renumbered §12; drawer nav updated). **Verification caveat: no Node.js on this machine** — Astro build NOT run; website change verified via HTML-parser balance check + static-server DOM inspection (section text, all 4 links, drawer entry, renumbering all confirmed rendered). CI/deploy build must confirm. **Same session, part 2 — v2 Phase 1 (WS-A enforcement plane) SHIPPED** on branch `claude/v2-phase1-enforcement` (stacked on the plan branch, PR #106): (A1) `src/zo/contracts.py` — contracts.json emitted at decompose into memory_root (gate_mode precedent), `contract_produced` upgraded from prose placeholders to concrete paths (ownership ∩ required_artifacts, ownership-dir fallback), SubagentStop hook validates deliverables (missing/undersized/pattern/empty-dir) and blocks with a violation list; (A2) drift-guard Stop hook — completion-claim regex over the last assistant transcript message + added TODO/FIXME/NotImplementedError lines in `git diff HEAD` → block (env kill-switch `ZO_DRIFT_GUARD=0`); (A3) PreCompact (STATE flush + checkpoint decision), SessionEnd (summary backfill), PostToolUseFailure (`logs/comms/failures-{date}.jsonl` feed) — specs/memory.md recovery section updated to match (replaces the never-built periodic postToolUse checkpoint design); (A4) sealed-paths PreToolUse guard — memory-root control files (gate_mode/gate_nonce/gate_decision/contracts.json/sealed_paths) + user `sealed_paths` prefixes denied, off-limits write-scope enforced per contracts.json when agent identity present in hook input (plan check 6 AMENDED: no disallowedTools frontmatter exists for subagents and verifiers need scoped writes — path-scoped enforcement instead, fail-open without identity); (A5) nonce gates — minted at GATED (`secrets.token_hex(8)` → `gate_nonce` file), surfaced in `prepare_gate_review`, `apply_human_decision` raises PermissionError without it (single-use, cleared on terminal decisions), new `zo gates approve/reject --nonce` CLI writes DECISION_LOG + comms + `gate_decision` file consumed on next decompose, `/approve`+`/reject` slash commands rewritten to route through the CLI (forgeable hand-edit path CLOSED). All via one shim (`.claude/hooks/zo-hookkit.sh` → `python3 -m zo.hookkit`, venv-preferring, fail-open) + 6 new settings.json wirings. **First-ever hook-script tests** (subprocess + stdin JSON pattern). **854 → 904 passed / 7 skipped, ruff `src/` clean, validate-docs green.** 4 pre-existing integration tests updated to pass the nonce (designed behaviour change). Plan oracle checks 1-5 + 7 have passing seeded-failure tests; check 6 as amended. **Part 3 — live pre-PR verification (Sam-directed):** added always-on hook-trace observability (`logs/hook-trace-{date}.jsonl`, `ZO_HOOK_TRACE=0` off-switch) and verified in the live session itself: sealed-paths DENIED a real Write to gate_mode; drift-guard fired correctly-silent on a real Stop; subagent-stop fired with `agent_type`+`agent_id` in the live payload — **agent-identity open question RESOLVED** (per-agent enforcement keys correctly). Drift-guard now prefers the live payload's `last_assistant_message` (transcript parse = fallback). Caveats logged: PostToolUseFailure doesn't fire on nonzero-exit Bash (infrastructure errors only); PreCompact/SessionEnd not yet observed live; full `zo build` demo needs a machine with the claude CLI (this Mac has none — PR-046). **908 passed / 7 skipped, ruff clean.** **Part 4 — Phases merged + Phase 2 (WS-B control plane) SHIPPED:** #106 + #107 merged to main (stack conflict resolved by merging main into the branch, branch side kept — main had nothing unique). Then WS-B on `claude/v2-phase2-control-plane`: `src/zo/ledger.py` (plan-ledger.json: per-subtask entries w/ synthesized criteria, merge-preserving regeneration, atomic writes, phase_status map); oracle-owned flips wired at the two verified-completion sites (automated gate + nonce-verified human PROCEED), resets on ITERATE/loop-CONTINUE, attempts on mark_subtask_complete, ledger sealed via `_SEALED_DEFAULTS`; `## Stories` plan section + sizing lint in validate_plan (fires only when stories declared — legacy plans untouched); `zo status` renders the control-plane table from the ledger (STATE.md = fallback/projection). Phase-1 hardenings from recon: `contracts.set_active_phase` now atomic; `zo build` exports ZO_MEMORY_ROOT/ZO_DELIVERY_ROOT/ZO_CONTRACTS_PATH so per-project sealing works in delivery sessions. Deferred to Phase 3 (documented): evaluate_loop_state ledger input, session-restore cutover (PR-036 precedence). **929 passed / 7 skipped, ruff clean, validate-docs green. Oracle checks 8-10 seeded tests pass.** **Next:** Phase 2 PR review/merge → Phase 3 (WS-C: watchdog, then fresh-context loop — demo validation needs the Linux box w/ claude CLI, PR-046).
1212

1313
**Session 039 (prior).** Test-only change making the CLI command-set test plugin-tolerant: `tests/unit/test_cli.py::TestCliGroup::test_cli_group_has_all_commands` asserted strict equality on `cli.commands`, which contradicts the extension points ZO itself shipped in PR #99 — any downstream build installing a `zo.commands` entry-point plugin (the documented mechanism in `zo.extensions.load_cli_plugins`) adds commands and turned the core suite red in that environment, despite zero core changes. Changed `assert expected == actual` → `assert expected <= actual` with an explanatory comment. Trade-off accepted: equality also caught *core* commands added without updating the test; subset still catches removals, and additions have always required updating this test's `expected` set anyway. Surfaced by the first real downstream plugin registering a new command group. No code, version, agents, or docs touched — single-assertion diff (+ memory). **854 passed / 7 skipped on Python 3.11 AND 3.12, ruff `src/` clean, validate-docs 0 failures.** **Next:** unchanged — Batch **D** / **E**, standing Tier-1 (caveman, onboarding).
1414

memory/zo-platform/sessions/session-040-2026-08-12.md

Lines changed: 32 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -75,10 +75,35 @@ Sam said go — WS-A shipped on `claude/v2-phase1-enforcement` (stacked):
7575
- 854 → 904 tests passed / 7 skipped; ruff clean; validate-docs green;
7676
first-ever hook-script tests (subprocess + stdin JSON)
7777

78-
## Next session
79-
80-
Phase 1 gate review with Sam, then WS-B control plane (plan-ledger.json,
81-
oracle-owned pass flags, sizing lint) per plans/zo-v2-rearchitecture.md
82-
Phase 2. Watchdog (WS-C) after that. Note for Phase 6 e2e: confirm Claude
83-
Code's SubagentStop/PreToolUse hook payloads carry agent identity in live
84-
team sessions (enforcement is fail-open without it).
78+
## Live verification + merges + Phase 2 (same session, parts 3-4)
79+
80+
- Live pre-PR verification (Sam-directed): hook-trace observability
81+
added; sealed-paths DENIED a real Write, drift-guard fired silent on a
82+
real Stop, subagent-stop payload carries agent_type+agent_id (identity
83+
question RESOLVED). PR-046: this Mac has no claude CLI/uv/npm.
84+
- #106 (plan+docs+website) MERGED. #107 (Phase 1) MERGED after resolving
85+
a stack conflict (merged main in, kept branch side).
86+
- Phase 2 / WS-B SHIPPED as PR #108 (targets main, full CI GREEN):
87+
src/zo/ledger.py, oracle-owned flips at the two verified-completion
88+
sites, ledger sealed, `## Stories` + sizing lint, ledger-first
89+
`zo status`; Phase-1 hardenings (atomic set_active_phase, hook env
90+
exported by zo build). 929 passed / 7 skipped.
91+
92+
## Next session — pick up here
93+
94+
1. Confirm #108 merged (Phase 2 gate). If not, merge it (CI is green).
95+
2. Start Phase 3 = WS-C on a fresh branch off main:
96+
`claude/v2-phase3-substrate`. Watchdog FIRST (heartbeat JSON per
97+
agent, external checker in LifecycleWrapper poll loop, never-block
98+
taxonomy: context-limit/rate-limit/auth/user-abort, bounded nudges,
99+
rate-limit wait-and-resume, PID+start-time identity) — oracle checks
100+
11-12, buildable/testable on this Mac. THEN the fresh-context loop
101+
for ML Phase 4 (experiment_loop.py spawns fresh builder per iteration
102+
from ledger+lineage+priors digest) — its go/no-go check 13 needs the
103+
Linux box with the claude CLI (PR-046).
104+
3. Deferred-into-Phase-3 items: evaluate_loop_state ledger input;
105+
session-restore cutover from STATE.md to ledger (keep PR-036 GATED
106+
precedence). PostToolUseFailure only catches infra errors → WS-D.
107+
4. Playbook that worked: recon swarm (4-7 read-only mappers w/ exact
108+
file:line integration points) → build → seeded-failure test per
109+
mechanism + wiring test → memory protocol → commit → PR.

specs/plan.md

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -251,6 +251,33 @@ These sections are included based on project needs.
251251

252252
Milestones are informational. Agents do not skip work to meet deadlines. If a milestone is missed, the orchestrator logs the delay and notifies the human.
253253

254+
### 10. Stories (optional, v2 WS-B)
255+
256+
An optional `## Stories` section declares explicit user stories with per-story
257+
acceptance criteria. Each `### <title>` sub-heading is one story; bullets under
258+
an `**Acceptance criteria:**` label become its criteria:
259+
260+
```markdown
261+
## Stories
262+
263+
### Load and validate the dataset
264+
265+
**Acceptance criteria:**
266+
- `pytest tests/test_ingest.py` passes with exit code 0
267+
- data/processed/clean.csv exists
268+
```
269+
270+
**Sizing lint (ralph's "Number One Rule"):** when stories are declared, every
271+
story must carry at least one *machine-verifiable* acceptance criterion — a
272+
threshold comparison (`RMSE <= 0.05`), an artifact path, or a backticked
273+
runnable command. `validate_plan` rejects vague criteria ("works well") as an
274+
error, which also fails `zo preflight` and `zo validate`. Plans without a
275+
Stories section are unaffected. Story sizing guidance: each story should be
276+
completable in a single agent context window.
277+
278+
Parsed stories feed `plan-ledger.json` (the machine-readable progress ledger
279+
whose `passes` flags only the oracle-verified gate paths may flip).
280+
254281
### 10. Delivery Specification
255282

256283
```markdown

0 commit comments

Comments
 (0)