Skip to content

feat(v0.10.0): F5 worktree isolation + B1a/B1b persistent runs + G1/3/4/6/7 + NEU-B + NEU-C + 4 FIXES#2

Closed
ShinonKagura wants to merge 5 commits into
Tiziano-AI:mainfrom
ShinonKagura:feat/v0.10.0-f5-b1a-b1b-neuc-and-fixes
Closed

feat(v0.10.0): F5 worktree isolation + B1a/B1b persistent runs + G1/3/4/6/7 + NEU-B + NEU-C + 4 FIXES#2
ShinonKagura wants to merge 5 commits into
Tiziano-AI:mainfrom
ShinonKagura:feat/v0.10.0-f5-b1a-b1b-neuc-and-fixes

Conversation

@ShinonKagura

Copy link
Copy Markdown

⚠️ Important: version-skew warning

This PR was authored against installed npm pi-multiagent@0.9.1. Upstream main has since released 0.9.2 → 0.9.5 with architectural changes (notably 0.9.2 'Removed non-enforced shell and mutation paperwork' and 0.9.3 'Removed the separate local-source trust authority'). A rebase against current main is almost certainly required before merge. Mark / @Tiziano-AI: please confirm rebase strategy.

Summary

Single extended Pi delivery session 2026-05-26. ALL changes verified via 116 inline bun smoke scenarios (116/116 PASS); upstream pnpm run gate not yet executed (operator-owned in this fork — see Verification below).

What this adds

Features

  • PRE — preflight/schema drift fix (preflight-shape.ts)
  • F5 — per-step git worktree isolation (mutation-worktree.ts NEW)
  • NEU-A B1a — persistent run-state foundation (persistent-run-state.ts NEW)
  • NEU-A B1blist + reattach tool actions
  • G1 — artifact mirroring into persistent run dir
  • G3 — periodic 6h retention sweep timer
  • G4pi.events lifecycle event emission
  • G6/G7 — declarative worktreeSetup (propagateNodeModules + symlinkPaths)
  • NEU-B — per-step output-truncation knobs
  • NEU-C — schedule/cron triggers (scheduled-runs.ts NEW)

Adversarial-review fixes

  • FIX-1 HIGH — persistence-unavailable + worktree = fail closed at construction (was: guaranteed F5 leak on crash)
  • FIX-2 MEDteardownWorktreeForStep optional artifactStore (replaces as never cast)
  • FIX-3 MEDmutateWorktrees reentrancy invariant docstring
  • FIX-4 LOWpruneOrphanWorktreeBranches helper for partial-teardown recovery

Tests

10 new test files under tests/ covering all new behavior and all 4 adversarial fixes:

  • preflight-schema-drift.test.ts — PRE invariant
  • worktree-planning.test.ts — F5 schema + planning rejections
  • worktree-lifecycle.test.ts — F5 real-git fixture
  • persistent-run-state.test.ts — B1a storage layer
  • worktree-isolation-persistence-interlock.test.ts — FIX-1 HIGH regression
  • teardown-without-store.test.ts — FIX-2 regression
  • orphan-branch-prune.test.ts — FIX-4 regression
  • list-and-reattach.test.ts — B1b actions
  • step-output-limit.test.ts — NEU-B
  • worktree-setup.test.ts — G6/G7

Adversarial review

Independent analysis-deepseek reviewer surfaced 4 findings (1 HIGH, 2 MED, 1 LOW); all fixed and verified in-session. See CHANGELOG Unreleased block.

Docs

  • docs/migration-guide.md — for consumers moving to v0.10.0
  • docs/operator-runbook.md — day-to-day operations for B1a-era worktree isolation + persistence
  • README.md — new 'Architectural non-goals' section
  • SKILL.md — sections for worktree isolation, B1b list/reattach, NEU-B knobs, G4 events, G6/G7 worktreeSetup, NEU-C schedule, architectural non-goals

Verification done in delivery session

116 distinct smoke-test scenarios via bun against the patched in-place package. Categories:

Category Count
PRE drift fix 1
F5 schema + planning 4
F5 real-git lifecycle 8
FIX-2 (no-store teardown) 3
FIX-4 (orphan branch prune) 4
G6/G7 worktreeSetup 6
B1a storage layer 19
B1a integration (F5+B1a) 8
F5 regression after B1a 19
B1b end-to-end 13
FIX-1 + G4 lifecycle event 4
NEU-B output budget 9
NEU-C schedule 30
Final consolidated regression 33

All node:test files in this PR encode the same scenarios for pnpm run gate.

Verification still needed

  • pnpm install && pnpm run gate from upstream root (operator-owned in this fork; requires resolving the version-skew first).
  • Real-Pi manual smoke. Recipe is real-pi-smoke.sh in the original delivery session at /mnt/DEV/stellar/lux/docs/90-workspace/handoffs/pi-multiagent-2026-05-26/.

Architectural non-goals (DO NOT IMPLEMENT)

These are deliberately not in scope and should stay closed:

  • Child→parent intercom (conflicts with unattended-child trust model)
  • Recursive agent_team calls (already denied at 3 layers)
  • Cross-host registry
  • Child resurrection / live-control reattach (B1b reattach is read-only)
  • Free-form chain/parallel DSL (static DAG by design)

Provenance

Authored by Mark Higginson via a delivery session run by Claude Opus 4.7 with peer review by ChatGPT gpt-5.5 and adversarial review by analysis-deepseek. Single session, single repo, single Unreleased CHANGELOG block.

Mark Higginson (via Pi delivery session) added 5 commits May 26, 2026 19:14
…/4/6/7 + NEU-B + NEU-C + 4 FIXES

Single extended Pi delivery session 2026-05-26. ALL changes verified via 116
inline bun smoke scenarios (116/116 PASS); upstream pnpm run gate not yet
executed (operator-owned in this fork).

## ⚠️ Version-skew warning

Branched from version 0.9.1 (the installed npm package at the time of the
delivery session). Upstream main has since released 0.9.2 → 0.9.5 with
architectural changes (notably 0.9.2 'Removed non-enforced shell and mutation
paperwork' and 0.9.3 'Removed the separate local-source trust authority').
This PR likely needs a rebase before merge. See docs/migration-guide.md and
the receipts referenced in CHANGELOG for the canonical pre-rebase state.

## What this adds

- PRE — preflight/schema drift fix (preflight-shape.ts)
- F5 — per-step git worktree isolation (mutation-worktree.ts NEW)
- NEU-A B1a — persistent run-state foundation (persistent-run-state.ts NEW)
- NEU-A B1b — list + reattach tool actions
- G1 — artifact mirroring into persistent run dir
- G3 — periodic 6h retention sweep timer
- G4 — pi.events lifecycle event emission
- G6/G7 — declarative worktreeSetup (propagateNodeModules + symlinkPaths)
- NEU-B — per-step output-truncation knobs
- NEU-C — schedule/cron triggers (scheduled-runs.ts NEW)
- FIX-1 HIGH — persistence-unavailable + worktree = fail closed at construction
- FIX-2 MED — teardownWorktreeForStep optional artifactStore
- FIX-3 MED — mutateWorktrees reentrancy invariant docstring
- FIX-4 LOW — pruneOrphanWorktreeBranches helper

## Tests

10 new tests under tests/ covering all new behavior and all 4 adversarial fixes.

## Adversarial review

analysis-deepseek surfaced 4 findings (1 HIGH, 2 MED, 1 LOW); all fixed and
verified in-session.

## Docs

- docs/migration-guide.md — for consumers
- docs/operator-runbook.md — day-to-day operations
- README.md — Architectural non-goals section
- SKILL.md — Worktree isolation, B1b list/reattach, NEU-B knobs, G4 events,
  G6/G7 worktreeSetup, NEU-C schedule, Architectural non-goals
…tart-scheduled/formatCancel-schedule

Bug found in real-Pi smoke test (Pi 0.75.5):

`agent_team list` returned "agent-team-error - agent_team failed" because
formatDetailsForModel had no branch for 'list' or 'reattach' actions and fell
through to formatError. Same gap for the NEU-C scheduled-start and
schedule-cancel rendering paths.

Fix:
- Add formatListAction() renderer for B1b list (runs + scheduled).
- Add formatReattachAction() renderer for B1b reattach snapshot.
- Branch formatStart() on details.scheduleRegistration for NEU-C scheduled start.
- New formatCancel() wraps formatRunAction() and routes details.scheduleCancel.
- Extend shouldRenderGenericError() to NOT generic-error list/reattach/scheduled
  paths even when ok=false (they have their own structured output).

Verified via bun smoke against real runAgentTeam dispatcher (5/5 PASS).

This is the kind of bug only a real-Pi smoke would surface — the bun-isolated
smokes verified the dispatcher logic but not the model-facing rendering path.
…xit (FIX-6)

Found in real-Pi smoke test (Pi 0.75.5):

The RPC child controller spawns step children with detached:true (non-Win)
and piped stdio. Without child.unref(), libuv tracks the ChildProcess
handle as a live reference even after the child has exited cleanly and
all stdio has closed. The parent Pi process therefore cannot exit after
`pi -p ...` returns its terminal response.

Symptom: `pi -p` hangs at the shell prompt after the model's terminal
JSON. Mark had to open a new terminal after every smoke run.

Fix: call this.child.unref?.() immediately after spawn. Exit/close/stderr
listeners still fire after unref(); completion handling is unchanged.

unref() is the standard Node.js pattern for detached:true + piped stdio
when the parent uses Promise-based completion tracking instead of
event-loop liveness as the wait mechanism.
…error (FIX-7)

Real-Pi smoke runs 1-5 all hit worktree-tree-dirty during the mutate step
even though post-run inspection found the fixture clean (.pi/ gitignored).
Without the actual dirty entries in the error message, operators cannot
distinguish:
  (a) a real .gitignore gap (a Pi child wrote unexpected state)
  (b) a transient file that's gone by post-run inspection time
  (c) a different invocation cwd than expected

Fix: append `git status --porcelain` output to the error message,
truncated to 10 lines with overflow indicator.

Next smoke run will show exactly what made the tree dirty at mutate's
start time, breaking the diagnostic dead-end.

@tiziano-contorno tiziano-contorno left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maintainer note: this review text was drafted with assistance from the local Pi assistant and approved by Tiziano before posting.

Thanks for the work here. There are useful ideas in this branch, but I don’t want to merge it as-is.

The main issue is that this appears to have been built against an older main/package state, and it now diverges significantly from current main.

Current blockers:

  • The branch does not typecheck against current main.

    • missing ./src/library-policy.ts
    • missing exported formatAgentTeamLiveStatus
    • MutationWorktreeState is declared locally but not exported
    • stale projectAgents, allowProjectCode, and extensionToolPolicy type mismatches
  • It reintroduces surfaces that current main removed, including allowProjectCode, projectAgents, and mutationScope.

  • It removes current role enforcement for:

    • package:validator requiring effective bash
    • package:worker requiring effective edit or write
  • It bumps package.json to 0.10.0 and rewrites changelog release sections. Please leave versioning and dated release sections to maintainer release prep; contributor changes should stay under ## Unreleased.

  • The PR bundles too many large changes together: persistence, list/reattach, worktree isolation, scheduling, symlink setup, output limits, docs, and tests.

A few implementation concerns also need to be addressed before those larger features are reviewable:

  • worktree teardown appears to capture committed changes only, so normal uncommitted edit/write changes can be lost
  • persistent state is keyed by process-local run IDs like r1, which can collide after reload
  • worktree-isolated steps appear to ignore step.cwd
  • scheduling is exposed in runtime/schema but still documented as deferred/non-goal
  • new action/docs/schema surfaces for list/reattach are not consistent yet
  • some documented example files are referenced but not present

Suggested next step: please rebuild from current origin/main and split this into smaller PRs.

Good first candidates for focused PRs:

  1. the child-process exit/unref fix, with focused proof
  2. the dirty-worktree diagnostic improvement
  3. the preflight/schema drift fix, if it still applies cleanly
  4. output-limit knobs as a separate small feature

For larger features like scheduling, persistent reattach, or worktree isolation, please open a separate proposal issue first so we can agree on the shape before implementation.

Before re-requesting review, please include fresh output from:

pnpm run typecheck
pnpm test
pnpm run gate
git diff --check

Thanks again — I’d rather preserve the useful parts by reviewing them in smaller, current-main PRs than try to merge this large stale branch.

@ShinonKagura

Copy link
Copy Markdown
Author

Thanks again for the detailed review — your concerns were taken seriously and I've split this work as you requested.

Focused PRs against current main

Three small, focused PRs, each rebuilt against current main (v0.9.5), each with single commits, no version bumps, full required-check evidence in the body:

All three pass npx tsc --noEmit, node --test tests/*.test.ts, check-source-size, check-public-docs, and git diff --check cleanly against this branch. Changelog entries are under ## Unreleased only.

Proposal issues for the larger features

For the bigger features you said should go through proposal-first, I've opened issues with concrete shape sketches, trade-offs, and open questions:

Each proposal-issue calls out the specific maintainer decisions I'd like before writing code, so the next round of PRs only happens after we agree on shape.

What got dropped (intentionally)

  • allowProjectCode, projectAgents, mutationScope — none of the three new PRs reintroduce surfaces you removed in v0.9.2 / v0.9.3
  • package:validator / package:worker fail-closed role enforcement — left untouched in the three new PRs; not silently removed
  • All version-bump + dated-release-section rewrites — left to you for release prep

Side-finding (independent of this PR)

While running the gate on clean origin/main, tests/smoke-fake-pi.ts fails with an assertion mismatch (expected pattern includes # agent_team terminal notice, actual output contains untrusted status evidence; run_status/step_result for artifacts). Looks like a stale expectation against a recent rendering refactor. Mentioning here in case you weren't aware; happy to file separately or send a small follow-up PR if you'd like.


Closing this PR. Happy to keep iterating in #3 / #4 / #5 and in the proposal threads #6 / #7 / #8.

Thanks for the maintainer discipline — the review made everything much cleaner.

@ShinonKagura

Copy link
Copy Markdown
Author

Follow-up on the split request here: I left this larger PR closed and updated the two focused follow-up PRs against current upstream/main @ 4d9734b.

Both focused branches avoid version bumps/release-section rewrites and keep contributor changelog notes under ## Unreleased.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants