Author SHA1 Message Date
wassname2 43fc97aebd WIP: preserve startup failure and stale-pane recovery
Saved before switching to the alternate implementation at user request. npm test run: 107 passed, 1 failed, 2 skipped. The recorded-pane test still expects one Herdr call; the new discovery path makes two. Not a functional acceptance claim.
2026-09-09 19:48:10 +08:00
wassname2 097349632c Persist goal reminders before model requests
Port b386efd8ea while preserving recovery pause/exit and sign-off safeguards. Validated with installed Pi 0.85.1, unchanged replay guard, full npm test, typecheck, lint and build.
2026-09-09 16:10:18 +08:00
wassname2 b0759fe016 Add goal recovery commands and autonomous supervision safeguards 2026-09-09 14:31:24 +08:00
wassname2 cecb1e9119 Simplify visible supervision and keep checkpoints fresh 2026-09-08 14:44:58 +08:00
wassname2 d5729ac106 Consolidate supervision and remember models per role
Bundle Intercom/VCC with the internal supervisor. Add default alignment questions and conversational plan review. Cover model recovery, cancellation and packed single-package operation.
2026-09-08 08:45:26 +08:00
wassname2 8e44738773 Use real plan supervisors and enable automation by default 2026-09-07 14:49:25 +08:00
wassname2 1c10a282ac Use goals subcommands without option prefixes 2026-09-07 09:18:56 +08:00
wassname2 3f0aadfffa Add persistent plan steward 2026-09-03 14:17:39 +08:00
254 changed files with 13587 additions and 19220 deletions
+64 -123
View File
@@ -1,140 +1,81 @@
# pi-goals contributor notes
## User intent for supervision
The following preferences are the user's words, recorded on
[`experiment/goals-owned-supervision`](https://github.com/wassname/pi-goals/blob/06794bf/AGENTS.md#user-intent-for-this-branch):
> To be clear, the hope is we can have a smart supervisor like you, with judgment and context. But it doesn't use many tokens as it checks in and sees an overview.
>
> It steers a smaller model, adding perspective and judgment.
>
> It compacts every 150k or similar to avoid cost and context rot.
>
> It has a goal / plan on a Ralph-loop-type repeat.
>
> That lets the worker be a cheaper model, and the supervisor more expensive, and still get a good outcome.
>
> Oh, and since it's two panes, the user can review both!
>
> Well, I want to see what the supervisor is thinking and saying. That's the whole point: all supervisor thinking and messages should be visible.
>
> So that should make it obvious that I need to see the messages, and the supervisor needs to use judgment. For example, it could say how we are tracking or whatever every time, and it would be useful, like in the recap.
>
> And it would only be a few output tokens.
— wassname; spelling and punctuation corrected in the source by Pi/OpenAI.
## Confirmed product preferences
- One installable pi-goals package, not separately configured supervisor packages.
- Run the full normal Pi profile and package set in two real interactive sessions, visible beside each other in Herdr. Keep extensions, skills, prompt templates, themes, configuration and authentication. Do not silently launch a reduced profile with `--no-extensions`; honor deliberate worker resource choices. Supervisor mode changes the role/model and enforces its inspection-only policy, not a separately assembled installation. Fork the main planning session, activate supervisor mode and compact the fork.
- The supervisor retains the compacted planning session. Its repeated review loop reminds it that it is the supervisor and supplies the current canonical plan. Keep those directly available rather than relying on the compaction summary alone.
- Load Intercom once per Pi process. Do not add a second copy or extra standalone supervisor package when activating supervisor mode.
- The worker carries implementation detail. The supervisor gets incremental high-level views and retains its judgments, user intent and decisions.
- Remember the last model selected separately for planning, working and supervising.
- Ask material unresolved alignment questions, not a fixed quota. Inspect technical facts yourself; do not ask for confirmation of ordinary implementation details or repeat answered questions. Batch high-impact questions with context and a recommendation. An explicit current-plan request to skip optional questions applies only to that plan; it does not grant missing permission.
- Discuss returns the review menu to normal chat, preserving the draft. Do not immediately reopen the menu while the conversation is unfinished. Ready is the human's approval to start work.
- Live supervision must not use headless Pi RPC mode or a bespoke plan-lifecycle RPC layer. Use the real sessions and Intercom messages for views, steering and plan-bound approval checkpoints.
- Keep the design simple and reliable. The user reports that it is constantly breaking; adding more orchestration or approval forms is not progress. Preserve working components and remove unnecessary layers.
- Show useful supervisor assessments, advice and perspective, not only hidden tool arguments or delivery receipts. Keep the assessment brief. The supervisor's job is judgment and helping the worker stay on course, not filling forms; transport and approval bookkeeping are supporting details.
- After the initial fork compaction, compact the supervisor again above 100k current-context tokens (not cumulative usage), respecting the model's context limit. This is the latest user clarification of the earlier approximate 150k preference. Token/cost savings and the usefulness of advice need a real task trial; passing protocol tests alone does not establish either.
- Supervise autonomously until the agreed result is achieved and inspected. Investigate claims of being blocked, waiting, unable to proceed, or done; change ineffective steering, and keep authorized independent work moving. Respect genuine dependencies, explicit human pauses, scope and permission limits. Do not make the human drive routine progress.
- Keep supervision instructions generic and outcome-focused. Approval bookkeeping supports delivery; it is not the deliverable. Inspect actual artifacts and execution evidence, not just summaries, checked boxes, or test counts. Manual completion checkboxes are claims until CompleteGoal records sign-off. Accepted inconclusive remains explicitly uncertain under fail-forward policy.
- Git status is a review guideline, not a hard acceptance gate. Unrelated dirty files and ignored output directories can be legitimate. Do not force cleanup, commits, or a dirty-state fingerprint framework.
These are user preferences, not a claim that the current implementation satisfies every point.
Validate them in real panes as well as automated tests; record remaining gaps and actual per-role usage.
## Tests
Run `npm test` before a commit. It includes unit and flow tests plus the RPC review test.
For an explicitly approved trusted-package update, a command-scoped npm release-age exception is allowed. Keep the default policy intact; do not turn a targeted update into a general package upgrade. The user approved pi-subagents 0.66.0 on 2026-09-09.
- `test/*.test.ts` unit and flow tests use a small Pi API mock. They check plan state, tool gates, and plan-file updates.
- `npm run test:rpc` runs `test/rpc-review.test.ts`. It starts the installed Pi executable in RPC mode, uses Pi's real `select` and `editor` protocol, and uses a local deterministic HTTP model. It does not need a credential or spend API credits. This is the closest automated session test.
- `npm run test:rpc` runs `test/rpc-review.test.ts`. It starts the installed Pi executable in RPC mode, uses Pi's real `select` protocol and conversational Discuss flow, and uses a local deterministic HTTP model. It does not need a credential or spend API credits. This is the closest automated session test.
- Use tmux for visual TUI debugging when the RPC test fails or a terminal-only problem is reported:
```bash
tmux new-session -s pi-goals-debug 'cd /path/to/pi-goals && pi -e ./src/index.ts'
tmux new-session -s pi-goals-debug 'cd /path/to/pi-goals && pi -e .'
```
Run `/goals <objective>` in that pane. Tmux checks the rendered menu, editor focus, widget, and keyboard handling. RPC does not render the terminal UI.
- `pi -p` has no UI, so it cannot test `Ready`, `Refine`, `Edit`, or `Cancel`.
- `pi -p` has no UI, so it cannot test `Ready`, `Discuss`, `Edit`, or `Cancel`.
## Functional acceptance: real Herdr workflow
- `npm run test:supervisor` runs the inherited `node:test` supervisor regressions. `npm test` also includes the always-enabled packed-artifact Intercom flow; Linux requires Unix-socket support.
Pi/OpenAI procedure, requested by wassname. Automated tests do not replace this check.
## Functional acceptance: real isolated Herdr workflow
1. Read `herdr --skill` and confirm `HERDR_ENV=1`. Create a separate test pane with `--no-focus` and an isolated temporary Git repo. Never operate the user's existing worker or supervisor panes. Record the code revision and any uncommitted changes being tested.
2. Start real interactive Pi with this extension and an available real model. Use `/goals` with a trivial, bounded deliverable, for example `hello.txt` containing an exact line plus a saved byte-verification log. No GPU, dependencies or unrelated work.
3. Read the rendered planning conversation. Check that ordinary implementation details do not cause needless confirmation questions. Inspect the drafted plan and select Ready through the actual UI.
4. Confirm Ready opens a visible supervisor pane and the worker starts. Read both panes. Verify the supervisor's exact advice is visible, reaches the worker, and helps it progress toward the requested artifact. A delivery receipt alone is not proof.
5. Let the pair produce the artifact, save verification evidence, and complete the real ApproveGoal -> CompleteGoal sequence. Do not perform the task for the worker. Record any manual nudge as intervention, not autonomous success.
6. Inspect the artifact itself and its saved verification output. Check the final plan state and both sessions. Success means the requested result exists and the workflow completes, not merely that tests pass or messages were exchanged.
7. Exercise reload and supervision recovery in these test panes, preserving the current plan. Check planning exit too. Record commands available in the tested revision; do not claim unimplemented commands work.
8. When a stage fails, read both panes and the exact error before diagnosing it. Fix the cause, reload only the test instance, and retry the failed stage. After a prompt change, use a fresh task to verify changed behavior. Repeated status checks are not a repair.
9. Save pane captures, session paths, artifact paths, code revision, interventions and remaining failures under `slop/reviews/`. A wait-output timeout or match is only a signal to inspect the pane, not a pass/fail verdict. Report the observed result and gaps, not a test-count substitute.
Pi/OpenAI procedure, requested by wassname; adapted from `8953dce`. Automated tests do not replace this check.
Keep this check small and goal-focused. Its purpose is to expose real startup, UI, steering and completion failures, not to create another review loop. Only close test panes that you created.
## User intent for this branch
To be clear, the hope is we can have a smart supervisor like you, with judgment and context. But it doesn't use many tokens as it checks in and sees an overview.
It steers a smaller model, adding perspective and judgment.
It compacts every 150k or similar to avoid cost and context rot.
It has a goal / plan on a Ralph-loop-type repeat.
That lets the worker be a cheaper model, and the supervisor more expensive, and still get a good outcome.
Oh, and since it's two panes, the user can review both!
Well, I want to see what the supervisor is thinking and saying. That's the whole point: all supervisor thinking and messages should be visible.
So that should make it obvious that I need to see the messages, and the supervisor needs to use judgment. For example, it could say how we are tracking or whatever every time, and it would be useful, like in the recap.
And it would only be a few output tokens.
-- wassname (spelling and punctuation corrected by Pi/OpenAI)
## User voice: redesign discussion, 2026-09-10
> This seems too complex. Models are trained to use subagents. Maybe I should make the main thread supervisor and use a worker thread. Main thread smart model, fewer tokens. Subagent dumber but more tokens.
> If we get this right it would result in simple editable prompts, clear and easier code, etc.
On the Nicobailon fleet viewer:
> Yeah, it's ugly, hard to read. Just plain text, no syntax highlighting or even formatting.
When should the supervisor review?
> Q1: 1) on stop (without process or subagent running) 2) every 60 minutes 3) on check of or change in plan.
> Note, if we want to be simple we can use pi-scheduled prompt to tell supervisor to check in?
> How will supervisor view subagent in a token-efficient way?
Who owns the plan and completion?
> Q2: hmm, I was thinking the worker does, but yeah, in this model maybe the supervisor... it's just I wanted an independent check where the supervisor is on a Ralph loop and has perspective, perhaps read-only (or partial).
On patching packages:
> Q3: yes, we can patch if needed, hopefully we don't need to.
> If we have to patch, it might be easier to patch or extend the main subagent packages, idk.
On seeing the real worker Pi pane:
> Oh, I see the subagent go, it's looking good so far.
Asked whether the worker view must allow direct interaction (typing messages, interrupting, using `/model` and `/tree`):
> Yes, I do.
On simplicity and visible status:
> Keep it simple and robust, that's why I thought pi-schedule-prompt might help, but maybe it will add complexity, idk. It's good for a user to be able to see if it's connected and so on.
On reviewing completed supervisor/worker pairs:
> And at the end I want to be able to see the tokens used in supervisor and worker. And to be able to have you find pairs, with the versions or commit used, and inspect them for how well they behaved. This will be a script in the fork.
On proceeding with the whole normal Pi worker interface:
> I do want the whole normal [Pi interface].
> Let's do that.
-- wassname (spelling and punctuation corrected by Pi/OpenAI; bracketed words supply context)
Pi/OpenAI decision record: proceed with edxeth's full interactive worker UI and validate supervision/recovery before replacing global settings. A formatted transcript-only viewer does not satisfy the request.
On supervisor plan ownership:
> Maybe the supervisor can just approve or deny worker edits to the plan? Or, okay, yeah, let's start permissive, sure.
-- wassname (spelling and punctuation corrected by Pi/OpenAI)
Pi/OpenAI decision record: start permissive. The supervisor may edit the plan and approve completion, while the worker implements and records evidence. The supervisor independently inspects results; it must not weaken the agreed goal to accept the worker's output. Keep normal tools available and express the division of work in editable prompts. The user confirmed proceeding with "so yes, do it". The workflow above describes the current implementation, not a requirement to retain its two-step approval mechanism.
## Supervisor behavior preferences
Recorded by Pi/OpenAI from wassname's instructions.
The supervisor's job is to supervise autonomously until the agreed goal is achieved and it has inspected the actual result. Elicit high-level judgment and perspective, not compliance with a detailed procedure. It should want to diagnose and fix problems through the worker, keep useful work moving, and avoid making the human drive progress.
Treat claims of being blocked, waiting, unable to proceed, or already done skeptically. Inspect the evidence, question assumptions, and look for authorized ways forward. Do not accept an excuse at face value or repeat status checks that cannot resolve it. Respect real dependencies and permission limits; skepticism does not authorize bypassing them. Seek justified confidence, not certainty at any cost.
User-authorized full-profile supervision: preserve normal Pi extensions and tools, including bash/edit/write and custom actions. Inspection-only is a role instruction, not a tool denylist or enforced sandbox. Repeat the division of work in the existing short opening: inspect and diagnose directly, delegate changes through SteerWorker, and do not take over implementation or alter shared state. Do not add per-tool reminders. Worker planning restrictions and approval checks are separate and unchanged. Validate the full profile in isolated parent-owned Herdr panes; automated tests do not prove role adherence or lifecycle recovery.
Keep the prompt generic. Do not prescribe pueue, Modal, worktrees, or a particular research setup. Explain the job and what deserves attention; let the supervisor choose useful checks. Tool requirements belong in tool descriptions. Administrative approval must not replace the requested deliverable.
Use `@monotykamary/pi-supervisor` as a behavioral reference, not an implementation to copy wholesale. Its outcome focus, autonomous continuation, and instruction not to repeat ineffective steering are useful. Judge our behavior in real sessions, not by test counts alone.
Pi/OpenAI implementation: each review repeats the short supervisor opening and current plan outcome, preferences, goals and discriminators, excluding task/evidence detail. Startup and compaction repeat the longer role prompt and full active plan before appendices/history. The long prompt asks the supervisor to read applicable AGENTS.md instructions and relevant skills rather than assuming project-specific preferences. Both forms preserve plan wording. Prompt inspiration: Anthropic's constitution (intent and autonomy) and @monotykamary/pi-supervisor (outcome focus and effective steering). Repetition supports judgment; it does not establish success.
Keep brief visible recaps that add judgment rather than repeat unchanged status. Preserve useful reasoning and evidence checks; reduce redundant context and reviews before reducing judgment. Manual checkbox changes are claims, not proof of completion. Plan edits should reach the supervisor so it can judge drift and direct corrections.
## Earlier supervision workflow discussion
I already have pi-intercom-supervisor, but thought using pi-subagents could make it simpler. The idea is that the user makes a plan as in pi-goals, but on this branch, instead of a naive stateless subagent, we 1) fork, 2) compact, and 3) make it a supervisor with a prompt as in pi-intercom-supervisor. The supervisor is cheap because it sees only high-level material, which costs fewer tokens. It has good judgement because it sees a) compacted planning context, b) the plan, and c) summarised context (for example, my modified pi-vcc). This lets it operate read-only and steer the worker without losing track. It also compacts every 100k tokens to keep it cheap and high-level.
I am now thinking the subagent implementation may be too difficult. To keep the plan and forking, this branch of pi-goals could make another Pi session, perhaps using the fork explicitly, and use pi-intercom or pi-messenger to communicate with it. The user can switch to it, or Herdr could open it automatically.
-- wassname
1. Read `herdr --skill` and confirm `HERDR_ENV=1`. Create a separate test pane with `--no-focus` and an isolated temporary Git repo. Never operate the user's existing worker or supervisor panes. Record the code revision and uncommitted changes being tested. Use a packed test package without replacing the active installation.
2. Start real interactive Pi with that package and available, different worker and supervisor models. Test the full normal profile on both sides, not two equally stripped profiles. Isolate only the candidate pi-goals package selection; do not load both old and candidate copies. Keep global settings untouched; if temporary non-secret role preferences must change, save and restore all three with guarded cleanup.
3. Use `/goals` for a trivial, bounded two-goal task: two exact-content files plus saved byte-verification output, with an ignored output directory and an unrelated dirty file to preserve. No GPU, dependencies or unrelated work. Read the planning conversation, verify that questions are material, inspect the draft, exercise ordinary-chat Discuss, and select Ready through the actual UI.
4. Confirm Ready opens a visible supervisor pane and the worker starts. Read both panes. Verify exact supervisor advice is visible, reaches the worker, and helps progress. Delivery receipts alone are not proof. Let the same pair stay active between both goals.
5. Let the worker produce artifacts and real verification output, then complete both CompleteGoal calls (retained supervisor `review_goal`, followed by the fresh evidence judge). Do not perform the worker's task. Record each manual nudge or repair as an intervention, not autonomous success. Conclusive and accepted-inconclusive results are not equivalent.
6. Inspect the actual artifacts and saved execution evidence, final plan, and both sessions. Handwritten output or a manual tick does not prove execution. Success means the requested results and both observed sign-offs, not tests passing or messages exchanged. Verify no commit/cleanup was forced for ignored outputs or unrelated dirt.
7. Exercise worker-only, supervisor-only and both-side reloads; fresh-shell resume without special launcher environment; drafting/Discuss; Ready/startup compaction; pending completion; and a stopped pairing. Preserve the plan, role, restrictions and peer identity. Interrupted decisions must fail visibly and allow retry, not approve stale work or create duplicate panes. Planning reload must not become approval or get permanently stuck. Record any recovery action needed and commands actually available.
8. If a stage fails, read both panes and the exact error before diagnosing it. Fix the cause, reload only the test instance, and retry that stage. After a prompt change use a fresh task. Repeated status checks are not a repair; wait-output timeouts/matches only signal that the pane needs inspection.
9. Save pane captures, session/artifact/log paths, revision, interventions, remaining failures, and separate role usage under `docs/slop/reviews/`. Assess usefulness and actual token/cost use, not a test-count substitute. Only close panes you created. Do not release, merge, or replace the user's installation as part of acceptance.
+251 -74
View File
@@ -1,115 +1,292 @@
# pi-goals
Plan in one Pi session, then do the work there while a stronger visible Pi session supervises it.
Make a short list of goals in one Markdown plan file. This is easy to review, and a subagent can check whether each goal is complete.
## How it works
The plan file looks like this:
1. `/goals <objective>` creates `.pi/plan/<session_id>-vN.md` and enters read-only plan mode when no plan is active. With an active plan, `/goals` opens safe actions and only `/goals plan <objective>` deliberately replaces planning.
2. Pi asks only material questions, writes the plan, and shows **Ready / Refine / Edit / Cancel**.
3. **Ready** compacts the approved worker conversation once, then opens a second Herdr pane. The new Pi session forks that compacted worker session.
4. The original session becomes the implementation worker. It keeps normal tools and resumes from the same compacted boundary.
5. The fork becomes an inspection-only supervisor by instruction, with normal Pi tools and extensions available. Worker views and supervisor instructions travel over pi-intercom's extension channel, scoped to this plan pairing.
6. Ready approves the displayed plan and waits for the supervisor's Intercom readiness message. If startup fails, the worker loudly switches to unsupervised work only after rechecking that approved content and restoring its worker model.
7. The supervisor compacts again when its context reaches 100k tokens.
8. The supervisor records a private approval only after it sees a stopped worker, no active work, a clean worktree (or an explicit inspected-state override), evidence, and saved verification output. `CompleteGoal` checks that approval against the exact plan block and Git tree before it ticks `[x]`.
```md
## <short plan title>
The two Pi sessions are visible. You can switch to the supervisor pane and talk to it directly. Supervisor instructions are shown in full, including in collapsed tool rows; ordinary messages and emitted thinking use Pi's display settings. The supervisor is prompted to give brief progress assessments and use judgment about when to intervene.
<context: one short paragraph. What the human wants and why.>
On same-process reload, monitoring is restored without removing normal or custom tools. Views include the latest human direction, source-session path, worker model, and new messages since the last acknowledged view. They report Pi idleness and tracked process/subagent activity separately. Unavailable trackers stay unknown; unregistered detached jobs are not tracked. Approval is blocked while tracked work is active or unknown. Intercom disconnects are reported; unsent current views and unacknowledged instructions are retained in Pi session history for reconnect. Incoming review/instruction payloads are saved in a bounded inbox before presentation. A receipt is sent only when Pi emits the corresponding user `message_start`: this confirms session acceptance, not model judgment or tool execution. Pending payloads survive reload, and manual-compaction success, failure or cancellation resumes delivery after Pi is idle. Unpresented incremental views are kept separately, not overwritten. The inbox limit is 64 messages; overflow is reported without acknowledging the new message. Crashes around acceptance/persistence or extensions that transform/consume input can still require inspection and explicit reconnect; end-to-end exactly-once execution is not guaranteed. Reviews stop after all goals are completed or cancelled, and both panes remain available. These mechanics are tested; useful judgment and savings from a cheaper worker still require a representative two-model run. -- Pi/OpenAI
### User-visible result
<one concrete sentence naming the final artifact or behavior the human will inspect>
### User voice
- │ "<the human's requirement, quoted in full word for word (with spelling fixes)>"
### Goals
1. [ ] goal: <one short judgeable imperative outcome>
- subtle failure mode: <a way this could look done but isn't>
- discriminator: <the concrete observation that tells real success from that failure>
- tasks:
1. [ ] <subtask>
- evidence: (empty until sign-off)
### Future work / out of scope
### Log
### Interview
### Learnings
### Papercuts - problems, gotchas, suggestions
```
![the widget: live goals from the session's plan file, with the active goal's open subtasks](media/screenshot.png)
## Related work
Like [pi-milestones](https://github.com/Neuron-Mr-White/UniPi/tree/main/packages/milestone) and
[burneikis/pi-plan](https://github.com/burneikis/pi-plan), it guides rather than guards. The
reminder cadence is copied from [tintinweb/pi-tasks](https://github.com/tintinweb/pi-tasks) and the
resync-after-compaction from [tmonk/pi-goal-x](https://github.com/tmonk/pi-goal-x).
## Install
This branch requires Pi 0.85.1 or newer (before 1.0) and Herdr 0.7.5 or newer. Pi 0.85.1 supplies the public compaction-failure event and compaction-aware idle state used for delivery recovery. It reuses installed pi-intercom or loads its pi-intercom dependency when none is registered:
```bash
pi install npm:@wassname2/pi-goals
```
The supervisor launcher uses the normal Pi profile: it inherits the agent directory/environment and discovers configured extensions, skills, prompt templates, themes and authentication. It explicitly loads this pi-goals source and forks the planning session with the supervisor role/model. Existing Intercom is reused when registered. The repeated role instruction says to inspect and diagnose directly, but delegate changes through `SteerWorker` rather than alter shared state. **This is not an enforced sandbox:** bash, edit, write and extension actions remain available; other extensions may have their own hooks or restrictions. Planning-mode restrictions and approval checks are unchanged. A complete supervisor role/binding is saved before startup compaction and restored before worker handlers can run, including fresh-shell `pi --session <saved-file>` and stopped supervisor forks. Older bootstrap markers are migrated only when their saved pairing is recoverable; incomplete identity fails visibly rather than selecting worker mode. Full-profile Herdr behavior still needs parent-owned functional acceptance.
For a local checkout:
Or for development:
```bash
git clone https://github.com/wassname/pi-goals && cd pi-goals && npm install
pi -e .
```
Run Pi from the Git repository that the plan will change. **Ready** fails if the current directory is not inside a Git repository; this prevents approval from checking the wrong repository.
## Use
## Commands
```text
/goals show safe status/actions for the current plan
/goals <objective> create a first plan when none is active
/goals plan <objective> deliberately start or replace planning
/goals model <model> select the visible supervisor model
/goals model use the remembered supervisor model
/goals work reconnect the existing approved worker pairing
/goals supervise reconnect from the saved supervisor session
/goals solo continue an already-approved plan without supervision
/goals reconnect retry the existing pairing/model without replacing its pane
/goals restart replace the tracked supervisor, including return from solo
/goals noplan exit planning, preserving the draft without approving work
/goals clear close the supervisor pane and disconnect the plan
```
/goals CSV export for the report view
```
Pi argument autocomplete shows a short description for each available verb. The worker status distinguishes **supervised worker** from **UNSUPERVISED**; the supervisor status says **supervising**, **starting/reconnecting**, or **paused**.
`/goals` enters plan mode and starts a conversation; the objective is an optional seed. From there:
`/goals` with no argument opens a status/action menu and does nothing until a deliberate action is chosen. While a draft, approved worker, or supervisor pairing exists, unknown/free-text `/goals ...` input is rejected without stopping or replacing it; use `/goals plan <objective>` to deliberately replace planning. With no active plan, `/goals <objective>` remains a convenient first-plan shortcut. `work` and `supervise` are role-aware recovery commands, not role conversion or new-pairing commands. Wrong or missing identities are rejected. `noplan` preserves the draft/history, leaves planning restrictions, and does not select Ready, start implementation or launch a supervisor. `/goals clear` closes the tracked pane and keeps the plan file. Starting another plan also keeps older versions.
1. Align. The agent inspects technical facts read-only, then asks only material unresolved
questions about outcome, scope, constraints, or success criteria. There is no fixed quota or
confirmation ritual for ordinary implementation details. It waits for required answers before
proposing the final plan. An explicit “no questions” or “skip questions” clause waives optional
questions for that plan only, not missing permissions.
“No q's” and “skip q's” are also supported. Negated instructions (“do not skip questions”) and
quoted feature references (“add a 'skip questions' button”) do not waive alignment.
2. Review. When alignment is complete, the agent requests review and the full draft is printed.
Check that User-visible result names the artifact or behavior you expect. The menu offers
**Ready / Discuss / Edit / Cancel**. Discuss returns to normal chat and asks useful alignment
questions, not a refinement-notes editor. Keep talking for as many turns as needed; the old draft
alone cannot reopen the menu. When discussion is finished, the agent calls `RequestPlanReview`,
even if the draft is unchanged. Discussion state survives reload. Edit opens the full plan directly.
Escape also returns to chat and preserves the draft; explicit Cancel discards the current draft.
3. Work. Ready is the only review action that starts work. The agent ticks subtasks, appends to
`## Log` and `## Learnings`, fills `evidence:`, and calls `CompleteGoal` when a discriminator is
satisfied. Every human reply in plan mode is saved verbatim under `## Interview`.
After eight turns without a change above `## Log`, the next natural prompt includes a saved
extension message with the working set and a short upkeep reminder.
If the worker model is unavailable or fails after Pi's automatic recovery, work stays **paused**; solo does not bypass that failure or substitute another model. Human input, read-only diagnosis, `/model`, and recovery commands remain available.
Plan reminders are saved in session history before they reach the model, not appended only to an
outgoing request. In working mode, after startup or compaction, the next natural prompt refreshes
the whole plan, including its appendix, from disk. In planning mode, it refreshes the planning-policy
snapshot and plan path instead. Automatic compaction and tool-loop continuations do not start
an extra turn for a reminder: the refresh waits until the next `before_agent_start` (normally the
next user prompt). There is no fresh plan reminder during that ongoing automatic continuation.
**Supervisor failure falls back automatically, but never silently.** On reload/disconnect or a not-ready peer, goal work pauses while the existing Intercom readiness window allows up to five minutes for recovery. A returning ready peer keeps supervised mode. A timeout, explicit supervisor startup/readiness failure, or terminal supervisor model error after Pi's own retries ends that wait and switches an approved working plan to **UNSUPERVISED**. The visible warning and saved session message state the exact reported reason (or readiness timeout, not an invented root cause), the mode transition, preserved plan/evidence, unavailable supervisor sign-off, and `/goals restart` recovery. A continuation message tells the worker to keep implementing and save verification evidence. Ordinary supervisor tool errors and recoverable manual-compaction failures are not by themselves terminal peer failures.
## Plan supervisor and auto-continue
`/goals solo` explicitly chooses the same mode for an already-approved working plan. Solo mode/reason persist across reload, resume and compaction; the tracked supervisor pane stays available for inspection but its binding is detached. A reachable supervisor receives the detachment reason, shows paused, and rejects further steering on that pairing. No late peer can silently restore supervision. `CompleteGoal` is unavailable even with a previous approval checkpoint, and manually checked goals remain unreviewed claims. Solo does not auto-complete the plan or erase evidence. Use `/goals restart` for a fresh supervisor and new approval binding; use `/goals clear` to disconnect the plan when appropriate.
Steward supervision and 60-minute auto-continue are enabled by default. A real supervisor starts at
Ready. Auto-continue is the fallback when stewardship is off; it does not run a competing timer while
supervision is enabled. Use `/goals steward off` or `/goals auto off` to opt out. Explicit preferences
survive clear and reload. Cleared legacy sessions adopt the new defaults on reload; active legacy
plans retain their settings so supervision is not attached midway through work.
An initial **Ready** selection also authorizes fallback on supervisor launch/readiness failure, but only if the exact displayed plan still matches after all waits and the worker model restores successfully. Cancellation, changed content, unapproved drafts, repository/session preflight errors, and worker-model failures never authorize fallback. Recovery does not turn a planning draft into approved work.
Install/load **only pi-goals**. Its internal modules contain the supervisor; the package bundles
`pi-intercom` 0.10.0 and `@sting8k/pi-vcc` 0.5.0 as locked runtime dependencies. An already installed
Intercom is reused; otherwise pi-goals initializes its bundled copy after installed extensions load.
There is one Intercom registration per process, not an extra supervisor companion. VCC is used as
a compiler, not loaded as another extension. Pi core stays a peer dependency. **Herdr remains the
supported terminal host**. Both panes use the same Pi agent directory and configured package set;
explicit CLI resource choices are preserved without adding `-e` companions.
Recovery commands:
Ready is the human's plan approval. Pi-goals forks the planning session, initializes the supervisor
with the original plan and supervisor policy, and waits for acknowledged pairing before starting the
worker. The initial supervisor view can steer; it is not another mandatory plan-approval gate.
The supervisor fork is compacted unless its known context is already at most 20k tokens. If native Pi
reports that no older history is eligible for compaction, startup retains the fork unchanged and continues;
other compaction failures still block initialization. Pi-goals requests compaction only for the
supervisor. Later reviews compact above 100k **current-context** tokens (not cumulative
usage), or earlier for a smaller model context limit. Each model call explicitly supplies the
supervisor role and current canonical plan while retaining the compacted planning context and judgments.
- `/goals reconnect` retries the remembered role model and existing supervisor binding. Worker readiness/reconnect waits allow five minutes, including an ordinary 60-second supervisor compaction, and never replace a slow or missing pane automatically. A peer returning within that window clears the connection pause automatically; an established active worker pairing publishes a fresh current view so supervisor-only reload can resume review even when its previous view was already accepted.
- `/goals restart` explicitly closes only the tracked supervisor pane and starts a replacement for a working plan, preserving its file/version but invalidating old approvals. During planning it clears the failed pane so Ready can launch again. If closing a healthy supervisor pane fails, the existing pairing is preserved and the close error is reported; that local error does not authorize solo fallback.
- In the supervisor pane, use `/model` then `/goals supervise` (or `/goals reconnect`) to recover an unavailable supervisor model. Startup failure is reported to the waiting worker; it need not wait for the timeout to learn the cause and enter the announced solo fallback.
The internal supervisor provides incremental VCC views and retains its decisions. While an assessment
is active, later routine updates coalesce into one pending marker instead of queuing model turns or
replacing the active view. Once settled, it requests one fresh VCC overview from the worker's latest
compaction summary and current branch. This is a bounded high-level summary, not a lossless transcript;
truncation is labeled and the overview names the read-only source session for omitted detail.
Each explicit goal checkpoint carries a fresh bounded worker snapshot, including the latest user direction;
it becomes visible only when that checkpoint is assessed. The canonical plan and checkpoint identity remain
separate from replaceable routine status.
The plan-aware policy checks every 50 model turns or 60 minutes, or when the worker settles with no tracked
background work. Absent optional trackers contribute zero tracked work. Installed process/subagent
providers that cannot answer remain unknown and do not prove the worker is finished. Unregistered
detached work is not tracked. The `SUPERVISOR.md` policy lookup is unchanged: project `.pi/SUPERVISOR.md`, then the Pi agent directory, then the built-in policy. Auto-continue is
suspended while the steward is enabled so there is only one continuation policy.
Both sessions must load the updated transport for the request/reply reconnect fix; mixed-version peers are not a supported recovery configuration. Ready announces worker readiness only after its model is restored. Plan content is rechecked across startup/model-restore waits; changed content returns to review using the existing pane instead of starting different work. Clearing or leaving planning cancels its pending Ready attempt. `CompleteGoal` checks cancellation and the original binding/version after its asynchronous status lookup and before recording completion.
At each review the supervisor is prompted to visibly give a brief progress assessment and useful
advice, not just a delivery receipt. Its advice and no-intervention assessment are also displayed
as durable messages. Supervisor mode allows native read/grep/find/ls and the narrow supervisor
tools only. Writes, bash (including `!`), process/subagent/scheduler and unknown extension tools
are blocked at execution as well as hidden, including on reload and in a stopped plan fork.
This is a model-tool policy, not an OS sandbox for arbitrary trusted extension code.
In solo, `/goals reconnect` restores only the worker model and explicitly stays unsupervised; `/goals work` explains that state. `/goals restart` waits for the replacement supervisor and announces restoration of supervised work only on success. A failed replacement stays loudly solo.
All worker/supervisor traffic uses Intercom. Local lifecycle calls are ordinary pi-goals module
calls, with no plan-lifecycle RPC dispatcher or headless live Pi process. Disconnection invalidates
pending approval and is shown explicitly; a send does not prove receipt or execution.
A new supervisor may still need up to five minutes for initial compaction. Recovery does not terminate background jobs. Planning/diagnostic command checks are guardrails, not an OS sandbox; loaded extensions and repository Git configuration must be trusted.
One `CompleteGoal` call asks this supervisor about direction and scope, then runs the normal fresh
read-only evidence judge. Use one unique exact goal subject (case and surrounding whitespace do not
matter); ambiguous or drifted wording gets an actionable retry, not a manual-tick fallback.
Manual `[x]` marks are visible completion claims, not sign-off, even before this tool is called or
after reload. A prematurely checked submitted goal is reopened before review. Only accepted sign-off
checks it again and persists a per-goal record; observed reopening invalidates that record. The widget
and supervisor distinguish conclusive acceptance from **accepted inconclusive** (judge failure or no
verdict). Inconclusive still permits fail-forward, but is not verified completion. Git status is context,
not a gate: the judge can inspect cited uncommitted and ignored files directly. No commit or clean
worktree is required unless the goal itself requires it.
Model choices are remembered per project and role in `.pi/pi-goals/models/`. Use `/model` in planning, worker, or supervisor sessions to change that role's choice. Ready restores the worker choice after the planning fork is ready. An unavailable saved model stops the transition instead of substituting another. `/goals model <model>` explicitly overrides the supervisor choice for launch. -- Pi/OpenAI
Older sessions have no trusted per-goal records. Their existing checkboxes/evidence/logs are preserved
as “legacy completion — sign-off not recorded,” not rejected or automatically reimplemented. Use normal
CompleteGoal re-review if needed; editable historical log text is not imported as trusted sign-off.
Stopped pairings remain stopped. New worker views include current completion claims and whether the
canonical plan changed; a manual tick cannot end supervision. Ordinary supervisor prose and genuine
questions no longer suppress later worker direction. Explicit human pauses remain instructions to
respect, not a reason to discard new views; idle responses do not immediately retry themselves.
The judge's checks section accepts ordinary numbered and indented Markdown lists,
but an empty section cannot borrow a list from a later heading. Approving one goal does not finish supervision. Cancelled, stale or
mismatched replies do not sign off goals. Goal/revision identity is bound in code to the checkpoint
actually presented to the supervisor, not copied into a form by the model. Supervisor model checkpoints
have no arbitrary thinking deadline: slow healthy reviews may finish. Explicit cancellation, replaced
plans, disconnects and actual settled provider failures still fail safely; startup/attachment deadlines
are separate. A genuinely settled empty response returns an incomplete assessment, not an invented
human-input dependency. Later worker progress/cadence can resume supervision without a human poke,
and failure does not immediately retry the same view. A required completion checkpoint may wait, but routine supervision does not block worker
work. `/goals steward off` ends this plan's supervision and
cancels pending goal requests; it does not close the human's terminal pane.
## Inspected dirty-worktree approval
Navigation: `/goals supervisor` focuses the supervisor, `/goals worker` returns to the worker, and
`/goals zoom` toggles supervisor zoom. These use the real Pi panes, not a Fleet inspector. If the
recorded pane is unavailable, its location/liveness is unknown. Locate the existing session first;
only after confirming it is no longer running, reopen the saved `pi --session` path shown in the
error. Pi-goals never starts a duplicate merely because a pane ID is missing.
The supervisor can call `ApproveGoal` with `force: true` and a nonempty `reason` when preserved unrelated changes would otherwise prevent sign-off. It must inspect the changes first, not commit, reset or delete someone else's work. Force bypasses **only** cleanliness, never evidence, the current stopped view, active/unknown work, or exact goal/HEAD/tree checks.
After completion, keep the plan as a record. Ordinary auto-continue stops when no open goals remain.
The supervisor's `done` ends the pairing and its watch timer; it leaves the terminal and saved session
available for inspection. `/goals clear` is the manual way to disconnect. A later `/goals plan …`
creates a new plan version and starts a new supervisor fork at Ready rather than reusing the completed
plan's pairing. You can close an old supervisor pane after supervision has ended.
The approval JSON stores the reason, NUL-delimited Git status, an index SHA-256 digest and per-dirty/untracked-file content SHA-256 digests (including modes, symlink targets and deletions). `CompleteGoal` requires the same state; even editing an already-dirty file without changing its status invalidates approval. Normal clean approvals behave as before. Git-ignored files and pi-goals' private plan/approval/model paths remain excluded. Dirty submodule/nested-repository directories or other unhashable paths fail closed; there is no recursive submodule override. Fingerprinting reads all included dirty/untracked bytes and can be expensive for large outputs; it does not lock concurrent writers.
Other commands: `/goals clear` disconnects this session, preserving its plan file;
`/goals auto [minutes|off]` controls ordinary auto-continue; `/goals judge <model-ref>` overrides the
fresh judge's model; `/goals steward status` reports supervision. Use `/goals plan <objective>` for
objectives beginning with reserved command words, such as `/goals plan judge the vendor options`.
The old `--clear`, `--auto`, and `--judge` forms remain compatibility aliases.
A gate rejection is not automatically an experiment failure or a dependency of other authorized work. The supervisor should inspect the exact error and implementation, distinguish causes with a cheap check, and steer repairs plus safe independent progress instead of repeating an unproductive status check. -- Pi/OpenAI
## Plan format
Current goals belong above `## Log`; goal-shaped historical checklists below it are ignored by the widget, approval matching and sign-off. A goal is a checkbox line whose text starts with `goal:`:
```md
1. [ ] goal: Produce the report
- subtle failure mode: the report exists but uses stale data
- discriminator: the report cites the current input and the saved check confirms it
- verify: `just verify`
- evidence: (empty until sign-off)
```
The worker saves verification output in a nonempty repository file, adds that path to evidence, and commits it. The supervisor calls `ApproveGoal` with the inspected path; the worker then calls `CompleteGoal` with the exact goal text.
If context usage is unavailable, the supervisor warns once that its custom 100k compaction trigger cannot be checked. Pi's normal post-compaction `tokens: null` sample does not produce that warning; default auto-compaction is unchanged.
## Development
For a local trial, start inside Herdr with just this checkout:
```bash
npm test
npm run typecheck
npm run lint
pi -e /path/to/pi-goals
```
`test/intercom-broker.test.ts` checks readiness and exact message delivery through an isolated real Intercom broker. `test/rpc-review.test.ts` runs the planning review flow through Pi's real RPC protocol with a local deterministic model. The Herdr launcher and visible supervisor bootstrap have focused tests; use a real Herdr session for the final two-pane check.
Then draft a plan and select Ready; no enable command is needed. Initialization failure stays in
planning and names the unavailable component; resolve it in the supervisor pane, or turn the steward
off and retry Ready. Sessions saved with the older checkpoint-only steward need a new Ready handoff;
old pi-subagents reviewer runs are not reused as supervisor sessions.
-- PI[gpt-5.6-sol]
### Migrating an already-running installation
After validating this package, remove any old standalone supervisor entry. A compatible standalone
Intercom may remain: pi-goals reuses it rather than registering a second copy. **Reload existing workers before selecting Ready again**:
an old worker still has old launch arguments in memory and can launch both old and internal copies.
Reload both sides of a retained pairing. Do not add extra `-e` supervisor/Intercom arguments.
Duplicate Intercom registries are diagnosed and plan bootstrap is refused; Pi also reports conflicting
tools from duplicate packages. Diagnose/remove the duplicate rather than starting more panes. No
settings or live panes are changed by this extension's migration.
### Remembered role models
Choose with `/model` or Pi's model-cycle shortcut in planning, the worker, or the supervisor. Each
pi-goals role remembers its own last explicit provider/model. On first use it inherits the current
model; no provider is hardcoded. Planning is restored on `/goals`, worker at Ready **after** the
planning fork is captured and before pairing activation/the work handoff, and supervisor before its initial compaction
or first turn. Reload/resume and later plans restore those choices. The supervisor does not inherit
the worker's goal tools or auto-continue policy.
Storage is under `getAgentDir()/pi-goals/` (normally `~/.pi/agent/pi-goals/`):
`planning-model.json`, `worker-model.json`, and `supervisor-model.json`. Each atomic file contains
only `{"provider":"…","id":"…"}`. Different role processes never rewrite each other's file; competing
explicit choices in the *same* role are last-write-wins. No credentials or thinking-level preferences
are stored. Automatic `setModel` and Pi's restore events do not replace role preferences.
If a remembered model is missing or unauthenticated, the role pauses with an error instead of
silently using a different provider. Configure the saved model and reload, or explicitly select a
different available model with `/model`. Pi does not emit a selection event when you choose the
already-current model; use **`/goals model current`** to explicitly save that current model for the
paused role instead. This command verifies authentication before replacing the saved choice.
A worker-model failure at Ready keeps the attached supervisor inactive and persists **worker** as
the recovery target across reload. Recovery updates the worker preference, not the planner's, and
reoffers the existing Ready menu; Ready retries the same fork without another approval stage.
There is no activation, supervisor review turn or work handoff before the worker model is usable.
`/goals clear` and `/goals steward off` still stop/cancel supervision while a model is unavailable;
old supervisor directives cannot restart the stopped work. A failed restore or recovery never
silently replaces a saved model choice.
`/goals judge <model-ref>` remains a separate override for the fresh evidence judge; it never changes
these role files.
## Prompts
Planning/judge text lives in [`src/prompts.ts`](src/prompts.ts); supervisor policy/text lives in [`src/internal/supervisor/prompts.ts`](src/internal/supervisor/prompts.ts).
## Develop
```bash
pi -e . # one package; reuses installed or bundled Intercom
npm test # unit/flow/RPC + inherited node:test supervisor regressions
npm run test:rpc # real-Pi conversational review, local offline model
npm run test:supervisor # inherited lifecycle/VCC/correlation/recovery regressions
npm run typecheck
npm run lint
npm run build
```
No supervisor checkout or opt-in environment variable is needed. `test/rpc-supervisor.test.ts`
performs `npm pack`, extracts the tarball outside the checkout, and runs real Pi sessions plus the
actual bundled Intercom broker and a fresh offline evidence judge. Only Herdr is mocked: the worker's
exec adapter imports the extracted goals entry, and the supervisor loads the untouched extracted
package manifest. The test checks bundled production resources and excludes bundled Pi core peers.
It requires Unix sockets on Linux and spends no API credits. The hook integration additionally
checks initial supervisor compaction/model order, native planning-fork capture, cancellation, two
goal reviews, and judge isolation without relying on a live terminal.
The moved VCC dependency is source-only and has upstream type incompatibilities with current Pi/Intl
unions. `tsconfig.build.json` maps just its four imported API surfaces to narrow local declarations;
the actual pinned VCC source still runs in tests and production. The Intercom extension factory
has the same narrow declaration boundary; no dependency code is rewritten. All pi-goals source is typechecked
and linted; the node:test suite is run separately, not silently collected/skipped by Vitest.
Baseline validation (2026-09-07, before the current supervision changes): **67 Vitest tests and 118 internal supervisor tests passed, with no skips**,
including the packed real-Pi/Intercom flow. Typecheck, lint, build and diff checks passed. Independent
review and targeted recheck are complete. See the [saved validation and review disposition](docs/reviews/2026-09-07_single-package-role-models.md).
The current isolated-worktree validation is recorded in [the approved supervision plan](docs/slop/plans/20260908_simple-visible-supervision.md). Packed registration/reload is also tested with Intercom loaded before or after pi-goals. The full Intercom peer flow and Herdr UAT need host Unix-socket/control access; do not treat registration alone as a successful supervision trial.
Neither automated test proves visual Herdr rendering/navigation or measured token savings. The
previous live trial contained a historical tool call without a saved result, which can still block
supervisor `done`. Use `/goals clear` to explicitly disconnect; genuine outstanding-work checks have
not been weakened. See [the prior validation record](docs/reviews/2026-09-07_supervisor-validation.md).
## License
MIT. See [third-party provenance and notices](THIRD_PARTY_NOTICES.md).
+47
View File
@@ -0,0 +1,47 @@
# Third-party provenance and notices
## Internal supervisor
`src/internal/supervisor/` and `test/internal-supervisor/` were moved from
[wassname/pi-supervise](https://github.com/wassname/pi-supervise) (formerly
pi-intercom-supervisor), commit `145c2cb081f85c08b0244c4a2c8a2d9aef8debda`.
The source package is `@wassname2/pi-supervise` 0.0.4, author wassname, declared
license MIT. The source comments and attribution are retained. Local changes
integrate package loading, role-model readiness, duplicate-registration diagnostics,
and strict build/lint compatibility. Its synthetic fork fixture is retained; it
contains no user transcript.
The supervisor's `subagents.ts` retains its attribution to
`@monotykamary/pi-supervisor` (MIT), `src/subagent-detector.ts`. Its policy precedence
also follows that project. No separate supervisor package is required at runtime.
### MIT license
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
## Bundled dependencies
- `pi-intercom` 0.10.0: existing Intercom transport and broker; MIT. Its upstream
LICENSE is included under `node_modules/pi-intercom/LICENSE` in the package.
- `@sting8k/pi-vcc` 0.5.0: existing algorithmic worker-view compiler. Its README's
License section declares MIT and is included with the bundled source.
- Intercom's runtime dependencies, including `tsx` and `esbuild`, retain their
upstream package notices in the tarball. Pi core and typebox are peers, not bundled.
No replacement IPC runtime or VCC implementation was written for this move.
@@ -0,0 +1,38 @@
# Single-package and role-model validation
2026-09-07. The parent accepted the implementation after independent review and a targeted recheck. Changes are in the local pi-goals feature worktree; this is not an npm release.
## Delivered
- One pi-goals package: internal supervisor, bundled Intercom/VCC, and one package-root supervisor launch. Herdr remains the terminal host.
- Separate remembered planning, worker and supervisor provider/model choices. Files are under `getAgentDir()/pi-goals/`; the fresh evidence-judge override stays separate.
- At least three task-specific alignment questions by default. An explicit affirmative current-plan waiver skips them; negations and quoted feature names do not.
- Ready / Discuss / Edit / Cancel. Discuss and Escape preserve the draft and return to chat. `RequestPlanReview` reopens review when discussion is finished, including an unchanged draft. Only Ready starts work.
## Observed validation
[Saved full output](evidence/2026-09-07_single-package-final-validation.log) contains:
```text
Test Files 12 passed (12)
Tests 67 passed (67)
...
tests 118
pass 118
fail 0
skipped 0
...
SINGLE_PACKAGE_FINAL_VALIDATION_PASSED
```
`npm test` includes the packed/extracted production artifact running two real Pi sessions, the actual bundled Intercom broker and an offline fresh judge. It checks distinct actual role models and does not load a companion source checkout. The real-Pi conversational test covers Discuss and same-current-model recovery. Herdr is mocked in automated tests. Typecheck, lint, build and diff checks passed. Comparing common entries in the old/new lockfiles found no changed versions of existing locked packages.
The first review found four defects: stop blocked by model unavailability; activation before worker restoration and wrong recovery role; negated waiver matching; and same-model selection not triggering recovery. All were fixed with regressions. Parent inspection also caught a recovery await before cancellation ownership was captured; two more regressions cover clear/replacement during that await. The targeted review read current source and tests and returned `No issues found.` and `Merge verdict: OK`.
## Migration and remaining limits
The parent removed the two old companion entries from the user's Pi package list after the packed path passed. Only pi-goals remains registered for this workflow. Existing workers must reload before Ready: their old launch arguments still name the standalone extensions. The failed supervisor pane was observed at a shell with no Pi process; no duplicate recovery process was started during implementation.
Live Herdr recovery/navigation, the quality of questions from the user's chosen model, and token savings still need a human trial. The old historical tool-call-without-result issue can still block whole-plan `done`; `/goals clear` explicitly disconnects supervision and preserves history. This change did not weaken outstanding-work checks or alter old session transcripts.
<!-- Parent synthesis from observed commands, source inspection and review output, by Pi. -->
@@ -0,0 +1,69 @@
# Supervisor integration options
2026-09-07. Source-based recommendation, not implemented or tested as a live two-pane session. User intent: [Plan-aware persistent supervisor](../spec/2026-09-07_plan-supervisor.md).
## Recommendation
Compose `pi-goals` with `pi-intercom-supervisor` and its existing Intercom channel. Run the supervisor as a second real Pi session in a Herdr split. Use native Pi fork/resume and Herdr launch/focus facilities; keep a small adapter in pi-goals for the plan handoff and navigation.
This reuses the supervisor's policy, incremental views, decisions, and steering. It avoids both copying that runtime into pi-goals and placing a headless subagent behind a second UI. Both sessions remain ordinary Pi sessions that the human can inspect and address.
Herdr owns the terminals. Pi owns each session's history and compaction. The supervisor package owns the supervision relationship and observation cadence. Pi-goals owns the plan and individual goal-completion requests. Intercom transports messages. Pi-subagents can continue running the worker's delegated jobs without owning the supervisor.
## Existing examples and their fit
| Pattern | Fit for this task | Boundary |
|---|---|---|
| Intercom planner/worker + existing supervisor + native Herdr split | Recommended | New fork/bootstrap, plan-signoff, and cadence hooks still needed |
| Intercom `openProjectPaneIfMissing` | Useful launch/discovery example | Starts plain Pi; no explicit fork/session argument; cwd selection is insufficient to identify this supervisor |
| Pi-subagents `project.open` | Real visible Pi session | One binding per canonical cwd; options do not select a session file or supervisor role |
| Pi-subagents retained child + Fleet/Herdr inspector | Retains child context and managed lifecycle | Inspector reads artifacts and offers control; it is not the child's interactive Pi session |
| Messenger Crew/lobby + overlay | Useful for multi-worker task orchestration | Own task state and headless `--mode json --no-session -p` workers; overlay is chat/progress, not two real Pi terminals |
Intercom's README describes its planner/worker example as “one holds the big picture, the other does the hands-on work.” Its extension-channel example is the right transport pattern for non-conversational views and correlated goal requests: channel traffic alone starts no model turn. The supervisor already uses this channel and starts its own review when a view arrives.
The supervisor's `pi-supervise:pair:v1` event accepts an explicit worker Intercom identity and goal, and resolves on worker acknowledgement. It is emitted inside the supervisor process, not across the event bus from the worker. Its companion worker-state and paired events expose the identities needed by a launcher.
## Human interaction
Default to a named worker/supervisor split so both real sessions are visible. Focus either pane to type there; zoom temporarily when more width is needed. Offer direct pi-goals actions for opening/focusing the supervisor and returning to the worker. Exact slash spelling is still a proposal.
Installed help confirms this launch shape. These commands were NOT run:
```bash
herdr pane split --current --direction right --cwd "$PROJECT" --no-focus
# Take SUPERVISOR_PANE from the returned pane.pane_id.
herdr agent start goals-supervisor --kind pi --pane "$SUPERVISOR_PANE" -- --session "$FORK_SESSION_FILE"
herdr agent focus "$SUPERVISOR_PANE"
herdr agent focus "$WORKER_PANE"
herdr pane zoom --pane "$SUPERVISOR_PANE" --toggle
```
`--session` here opens an already-created distinct fork, never the worker's live file. Pi also supports `--fork <path|id>` to create the separate session at launch, so a native CLI fork followed by supervisor-side initialization may eliminate custom fork-file construction. Herdr `agent start` waits for the expected interactive agent to be detected and ready; its pane must initially be at a shell prompt. Use a unique name per pairing and retain the returned pane ID for control.
A separate Herdr tab is an alternative for switching; the split satisfies seeing both at once. Outside Herdr, an ordinary second terminal remains usable, but automatic terminal creation is a separate portability question. Do not build an additional fallback process manager before that need is established.
## Minimal integration work still required
1. **Bootstrap:** fork at the plan handoff, establish a supervisor-only role, compact the fork, provide the worker's explicit plan path and full plan, then pair. Do not restore the fork's inherited pi-goals activation as another worker, and do not truncate the plan into the routine 15 KB view. No supervisor judgement should run before initialization finishes.
2. **One review policy:** expose the proposed 50-model-turn / 60-minute / settled-and-no-background-work triggers in the supervisor package. Replace its stock 30-minute policy rather than running a second timer beside it. Count model turns, not transcript messages. Track the worker's registered processes/subagents and react when they finish; arbitrary unregistered detached work remains a visibility limitation.
3. **Per-goal request/reply:** add correlated goal-signoff and plan-update hooks. Stock `done` ends the entire pairing. A goal decision should return to pi-goals, which owns checkbox updates and the existing fresh evidence judge. A stale or duplicate reply must not approve another goal or plan version. The current two-call CompleteGoal protocol is not a user requirement.
4. **Recovery and navigation:** retain session/plan/pane identity; reconcile live Intercom identity and pairing on restart. Focus or resume the same supervisor instead of creating another. Do not open one session file in two live Pi processes. Preserve the original supervisor's decisions and reestablish policy/plan after compaction.
Keep VCC's incremental views and the supervisor's recent-view pruning initially. Use native compaction for the fork and later supervisor history. Measure token totals, cache reads, compaction cost, and whether useful interventions occur. The supervisor README's reported cost saving is not proof of an equivalent token reduction.
## Evidence and limits
Inspected Pi 0.84.4 and Herdr `0.8.2-preview.2026-09-06-9e9bc8a14466` CLI help. Herdr is installed, but this chat is not a Herdr-managed pane. No panes, agents, packages, or settings were started/changed for the research. Only documentation changed in this branch.
Source anchors:
- [Supervisor pairing and runtime](https://github.com/wassname/pi-intercom-supervisor/blob/409233cd4fb89e9b8c4a027affdedac5c9a8fddc/src/index.ts): pairing at 749794; recent-view pruning at 535556; settled reviews at 710742. [Policy](https://github.com/wassname/pi-intercom-supervisor/blob/409233cd4fb89e9b8c4a027affdedac5c9a8fddc/src/prompts.ts) and [wire protocol](https://github.com/wassname/pi-intercom-supervisor/blob/409233cd4fb89e9b8c4a027affdedac5c9a8fddc/src/protocol.ts) show the reusable prompt and missing per-goal request.
- [Intercom 0.13.0 README](https://github.com/nicobailon/pi-intercom/blob/199279ae861bf53ce014809fb2a03337538ae13e/README.md): Planner-Worker Coordination, Extension channels. [Project launcher](https://github.com/nicobailon/pi-intercom/blob/199279ae861bf53ce014809fb2a03337538ae13e/project-agent.ts) accepts cwd/focus but not a selected session. Inspected the published npm tarball as well. The supervisor README's old `tintinweb/pi-intercom` link returned 404; current Intercom source is under `nicobailon`.
- [Pi-subagents current integration docs](https://github.com/nicobailon/pi-subagents/blob/54df154d1891db6b1a3e755539683335b9f9dbd3/docs/extension-api.md): Inspector panes, Project panes, Background-work provider API. Also inspected installed 0.60.0 source: `project-panes.ts:102107,177179,409412,546564` and `focus.ts:3255`. Registry latest was 0.66.0; no upgrade was performed. Current source still distinguishes project sessions from headless-run inspectors.
- [Messenger 0.15.2 lobby launch](https://github.com/nicobailon/pi-messenger/blob/09937ed647a1b07a3b595bf75943feacb80ff123/crew/lobby.ts): `spawnLobbyWorker` uses print/JSON/no-session mode. [Overlay actions](https://github.com/nicobailon/pi-messenger/blob/09937ed647a1b07a3b595bf75943feacb80ff123/overlay-actions.ts) send messages and manipulate Crew tasks.
- Installed Pi SDK `docs/sdk.md`, `docs/session-format.md`, and `examples/sdk/11-sessions.ts`: session persistence, native branching, compaction, and CLI resume. Installed `herdr pane split --help`, `herdr agent start --help`, `herdr agent focus --help`, and `herdr pane zoom --help`: real interactive launch and navigation.
This is a fit comparison of the requested packages and their actual examples, not a package security audit or a measured reliability ranking. End-to-end fork/compact/pair, reload, background completion, sign-off, and visible switching remain to be tested.
<!-- Research and synthesis by Pi; recommendation pending user approval. -->
@@ -0,0 +1,80 @@
# Plan supervisor: implementation and trial status
2026-09-07. Feature-branch implementation, reviewed fixes and local trial. One live supervised goal completed successfully. Full navigation/reload UAT and token-saving measurements remain open. The user authorized registering the two companion packages in Pi settings and committing/pushing both feature branches. No npm release is part of this change.
## What changed
Pi-goals now forks a real supervisor session and starts it through native Herdr commands. The existing supervisor package supplies its policy, incremental VCC worker views and retained judgement. Ready waits for initialization and acknowledged pairing, then starts work; it is not a second plan-approval gate.
Routine checks use the 50-model-turn / 60-minute / settled-with-no-tracked-work policy. One CompleteGoal call requests a correlated supervisor decision before running the separate fresh evidence judge. Direct supervisor/worker focus and zoom commands replace Fleet navigation for this workflow. Small measured forks can skip compaction; larger/unknown forks use native compaction. Missing-pane recovery is deliberately manual.
## Parent-observed automated validation
[Saved default-on validation](evidence/2026-09-07_default-on-validation.log) records `Tests 48 passed (48)` across 11 files, plus typecheck, lint, build and diff checks. Both the actual-package hook test and real-Pi/Intercom test now initialize supervision without an explicit enable command. New regressions cover default-on migration, explicit-off persistence and preserving active legacy plans.
[Earlier full saved output](evidence/2026-09-07_supervisor-validation.log) covers all seven lifecycle review fixes, before the default-on change. Relevant excerpts:
```text
GOALS: enabled suite after R6/R7
Test Files 11 passed (11)
Tests 45 passed (45)
...
Checked 16 files in 56ms. No fixes applied.
...
tests 116
pass 116
fail 0
skipped 0
...
POST-R6-R7 PARENT VALIDATION PASSED
```
The goals suite ran with `PI_GOALS_SUPERVISOR_SOURCE` pointing to the matching supervisor branch. It included the actual two-Pi RPC / Intercom-broker / fresh-offline-judge test, with Herdr mocked. The hook integration additionally exercises two goals with actual package code and a persisted native fork, but mocks transport, Herdr and the judge. Neither is visual TUI proof. Typecheck, lint, build and both diff checks also passed. The supervisor suite ran through its literal `npm test`, not only the worker's alternate runner.
Reproduce from the goals worktree:
```bash
PI_GOALS_SUPERVISOR_SOURCE=/home/ubuntu/.pi/agent/worktrees/pi-intercom-supervisor-goals-integration/src/index.ts npm test
npm run typecheck && npm run lint && npm run build && git diff --check
cd /home/ubuntu/.pi/agent/worktrees/pi-intercom-supervisor-goals-integration
npm test && git diff --check
```
## Review disposition
All seven implementation findings were accepted and fixed:
- R1: preserve unknown context usage and remove the stale pre-compaction token floor.
- R2: cancel stale Ready handoffs after awaited activation and plan replacement.
- R3: invalidate suspended view/compaction continuations after stop or shutdown.
- R4: persist acknowledged initialization separately from provisional bootstrap state.
- R5: preserve explicit-stop state across cleanup and reload.
- R6: preserve and acknowledge worker activation during same-binding bootstrap replay.
- R7: keep the plan in starting until activation succeeds; steward-off returns it to planning.
The independent final review verified the original R1R5 scenarios and found R6/R7. Its verdict was BLOCK for R6. The parent then authorized the two narrow fixes, inspected their source and regression tests, and ran the final suites above. No fourth independent review was launched: the three-round cap was reached. R6/R7 therefore have parent review and regression evidence, not a subsequent independent approval.
The orchestration script failed after the first fix worker because its progress object included an undefined optional output reference. Completed code/results were retained; only the unlaunched final reviewer was recovered. This did not constitute a code/test failure.
## Local trial
The user has registered all three local packages in Pi settings, so ordinary Pi startup now loads them. For a temporary trial elsewhere, start inside Herdr with the matching goals extension already loaded and pass the companions explicitly:
```bash
base="$HOME/.pi/agent/worktrees/pi-intercom-supervisor-goals-integration"
pi -e "$base/src/index.ts" -e "$base/node_modules/pi-intercom/index.ts"
```
Then use `/goals plan <objective>` and Ready. Steward and 60-minute fallback auto-continue now default to on; explicit off preferences persist. `/goals supervisor`, `/goals worker`, and `/goals zoom` operate on the recorded real panes. `/goals steward off` stops the relationship, not the terminal pane.
Observe both panes, switch and zoom, reload/compact the supervisor, then complete two goals. If a pane ID is lost, locate the existing supervisor before reopening its saved session; a missing pane ID is not evidence that its process exited. Unknown background providers are not evidence that all work finished. Automatic phase-model switching was not implemented.
## Live trial and remaining cleanup issue
The user completed one real Herdr-supervised file-table goal. The supervisor delivered a direction message, and CompleteGoal ultimately accepted the evidence after corrections to the saved command/transcript attribution. This establishes a live pairing, steering and goal-sign-off path; it does not establish two-goal persistence or focus/zoom/reload behavior.
After completion, the supervisor reported that its `done` call was blocked by `Cannot finish: the worker still has work running (write).` Its worker view still reported an unresolved write while the worker was settled and tracked processes/subagents were zero. The origin of this apparently stale tool state has not been diagnosed. Automatic whole-plan cleanup is therefore not verified. `/goals clear` explicitly disconnects the pairing and stops its watch timer while preserving the plan; the supervisor pane/session can remain as history. A new plan creates a new version and pairing.
The managed pi-goals checkout's pre-existing `package-lock.json` modification was left untouched. Development dependencies were installed only in the new supervisor feature checkout. The later user-approved settings change registers the existing local supervisor and Intercom copies; it does not upgrade or download packages.
<!-- Final implementation synthesis and observed validation by Pi. -->
@@ -0,0 +1,23 @@
## Review
Reviewed the worker report, follow-up-only diffs under `/tmp/pi-goals-checkpoint-fix/`, corresponding current source/tests, and the parents final latch correction. The saved `before/` files separate this work from the previously reviewed implementation; this is not a re-review of the broader uncommitted changes.
- **Correct — fresh, immutable checkpoints:** `src/internal/supervisor/index.ts:362396` captures a complete worker snapshot for each explicit review and rechecks request identity, cancellation, pairing generation, session identity and canonical-plan hash after capture. The branch is read after tracker queries in `captureWorkerView`. The snapshot replaces `worker_view` only when its checkpoint becomes active; routine updates cannot overwrite an active assessment. Covered by `test/internal-supervisor/plan.test.ts:73168`.
- **Correct — current direction and bounded transport:** `src/internal/supervisor/view.ts:267288` pins the latest non-supervisor user direction separately from older summaries, with explicit truncation. `src/internal/supervisor/protocol.ts:1939` projects checkpoint identity into replies and bounds the actual serialized request, including JSON escaping and Unicode. Its size calculation matches the installed Intercom brokers payload measurement. Success, duplicate rejection and failure responses omit the snapshot.
- **Correct — genuine settlement required:** `src/internal/supervisor/index.ts:899908,11981215` records empty final output at `agent_end` but acts only at `agent_settled`, and only for an unresolved assessment. Successful verdicts and separately queued checkpoints are excluded. The installed Pi implementation emits settlement after retry, compaction and queued-continuation processing (`node_modules/@earendil-works/pi-coding-agent/dist/core/agent-session.js:744781`). Nonempty human-question handling remains distinct.
- **Fixed by parent; verified read-only — failure incorrectly latched a human dependency:** The earlier `failAssessment` set `awaitingUser=true`, suppressing later ordinary worker views indefinitely. Current `src/internal/supervisor/index.ts:634647` clears that latch and stale routine-refresh flags, then refreshes the footer. This permits later progress/cadence without immediately retrying the same dirty view, while retaining separately queued checkpoints. The two regressions at `test/internal-supervisor/plan.test.ts:188203` fail in `wait-latch-red.log` and pass in `wait-latch-green.log`. Explicit `needs_user` and nonempty-question pause paths remain present.
**No issues found.**
**Merge verdict: OK with notes.** The scoped changes are approved. Parent-owned final aggregate validation and live-pane acceptance remain outstanding evidence, not established by this read-only review.
### Validation and residual risks
- Inspected saved worker results: **89 focused tests**, **169 supervisor tests**, **51 integration tests**, plus clean typecheck/lint. These precede the parents latch correction.
- Inspected parents post-correction regression log: **2 passed**, covering empty-final and provider-error recovery, no immediate retry loop, and subsequent ordinary progress.
- No commands, edits, Herdr operations, settings changes, staging or push were performed by this reviewer.
- Parents final `npm test`, typecheck, lint and build were starting; their results were not available for this verdict. Complete `npm test` before committing, as required by `AGENTS.md`.
- Live current-pane behavior and supervision quality/cost still require parent validation. Bounded snapshots can explicitly truncate; historical replay is not live acceptance.
@@ -0,0 +1,30 @@
# Autonomous supervision: implementation checked, live acceptance pending
Base: `cecb1e9`, branch `feature/simple-visible-supervision`. Follow-up changes are uncommitted.
Scope: [approved plan](../slop/plans/20260909_autonomous-supervision-acceptance.md).
## Implemented
- Outcome-focused supervisor instructions: investigate blockers, change ineffective steering, inspect actual results, and keep authorized work moving. VCC and existing lifecycle protections remain.
- Ordinary prose, empty responses and genuine questions do not discard later worker views or direction. Monitoring does not authorize restarting human-paused work. No immediate idle retry loop.
- Manual checkmarks are claims; CompleteGoal records conclusive or inconclusive sign-off separately. Exact goal identity, cancellation and fresh-judge behavior remain. Legacy completion is labelled without inventing approval or restarting old work.
- Dirty Git state is context, not an acceptance gate. Cited ignored output files are valid inspection targets; no forced cleanup or commit.
- Material planning questions replace the quota; Discuss remains ordinary chat. AGENTS.md includes the other branch's relevant user preferences and real-Herdr testing procedure.
## Parent validation
- [Permitted Vitest subset](evidence/2026-09-09-autonomy/parent-permitted-vitest.log): `Tests 94 passed (94)`, across 13 files. Explicitly excludes `test/rpc-supervisor.test.ts`; this is not a passing full suite.
- [Supervisor regressions](evidence/2026-09-09-autonomy/parent-supervisor.log): ` tests 176`, ` pass 176`, ` fail 0`.
- [Typecheck](evidence/2026-09-09-autonomy/parent-typecheck.log), [lint](evidence/2026-09-09-autonomy/parent-lint.log), and [build](evidence/2026-09-09-autonomy/parent-build.log) exited successfully. `git diff --check` passed on source changes.
- Review found conflicting advice to prune completed goal lines and stale fuzzy-match descriptions. Parent corrected the instructions and added regressions. [Red](evidence/2026-09-09-autonomy/housekeeping-red.log) shows the two prompt failures; [green](evidence/2026-09-09-autonomy/housekeeping-green.log) records 43 passing tests, including preserved conclusive/inconclusive records after moving detail into the appendix.
- [Read-only recheck](evidence/2026-09-09-autonomy/housekeeping-recheck.md): “Both previous findings are resolved; the narrow fixes are approved.”
## Still required
Full `npm test` did not pass: [broker diagnostics](evidence/2026-09-09-autonomy/broker-diagnostic.log) show Unix-socket `listen EPERM` in the tsx launcher. Parent Herdr control independently returned `PermissionDenied: Operation not permitted`. No TMPDIR/IPC workaround was authorized or used to bypass the restriction.
The fresh two-goal Herdr trial has not run. It must show both actual artifacts and verification output, both CompleteGoal results, useful visible supervision, same-pair continuity, explicit-pause/reload behavior, ignored output files and preserved unrelated dirty work. Record every operator intervention and separate worker/supervisor usage. Do not treat deterministic tests as evidence of live judgment or savings.
No role preferences, active installation, existing panes, or unrelated root-worktree files were changed in this follow-up. No commit, push, merge or release yet.
Recorded by Pi (OpenAI) from observed command output and the independent source review.
@@ -0,0 +1,44 @@
# Recovery commands
Implemented directly by Pi/OpenAI at the user's request, on `feature/simple-visible-supervision`, base `cecb1e9` plus the existing uncommitted autonomy changes. The active global installation was not replaced.
## Commands
- `/goals help`: available commands and limits.
- `/goals status`: phase, peer connectivity, recorded panes/session files and last runtime failure.
- `/goals stop`: stop goal continuation and supervision; retain the plan and pair.
- `/goals exit`: stop and return to ordinary chat, retaining files. Supervisor sessions remain inspection-only.
- `/goals reconnect`: send the existing pair's identity handshake. Does not fork or authorize work.
- `/goals resume`: in the worker, resume previously authorized work after peer acknowledgement. A stopped draft or changed plan returns to planning and still needs Ready. In the supervisor, directs the human to the worker for authorization.
- `/goals supervisor`, `/goals worker`, `/goals zoom`: existing pane navigation.
Stop/exit cancel startup, an outstanding Ready selection and sign-off. They persist across reload. They do not kill independently running processes. Peer notification is best-effort and explicitly unconfirmed; use the other pane's stop command if it is disconnected. A pause identity prevents an old resume request from undoing a newer stop. Permanently ended pairings are not revived by reconnect.
## Observed interactive behaviour
Used real Pi 0.85.1 in a dedicated Herdr pane, with the normal global extensions, skills, prompts and themes. Project settings replaced only the old pi-goals package selection with the candidate. No global settings or package installation changed. The pane was closed after the check.
This was an **operator-seeded unapproved draft**, not an autonomous task or a model-produced plan. There were no model responses beyond the explicitly labelled fixture marker. The purpose was to exercise the public commands and persisted state in real Pi.
Saved [verification output](evidence/2026-09-09-recovery/verification.log) reports:
> PASS: stop persisted paused draft.
> PASS: resume restored planning without Ready authorization.
> PASS: exit persisted ordinary-chat state.
> PASS: no assistant turn beyond operator fixture marker.
> PASS: draft bytes unchanged.
> PASS: actual reload rendered; stopped status retained.
> PASS: reconnect without a pair reports failure instead of launching one.
> PASS: fresh-shell --session retained exit; status reports ordinary chat.
The [reload capture](evidence/2026-09-09-recovery/reload-pane.txt) shows the actual reload notice and stopped widget. The [resume capture](evidence/2026-09-09-recovery/resume-pane.txt) says “Draft restored; no work started.” The [fresh-shell capture](evidence/2026-09-09-recovery/fresh-status-pane.txt) says “Goals: ordinary chat (goals exited).” These establish command behaviour in the interactive runtime, not supervisor judgment.
Local fixture and detailed command receipts: `/tmp/pi-goals-recovery-functional/`. Source diff: `/tmp/pi-goals-recovery-implemented.diff`.
## Automated checks
The final `npm test`, typecheck, lint, build and `git diff --check` completed successfully. Saved [npm test output](evidence/2026-09-09-recovery/npm-test.log), [typecheck](evidence/2026-09-09-recovery/typecheck.log), [lint](evidence/2026-09-09-recovery/lint.log) and [build](evidence/2026-09-09-recovery/build.log) are supporting checks, not substitutes for paired functional acceptance.
## Remaining acceptance
Real paired worker/supervisor recovery during bootstrap compaction and sign-off, and the autonomous two-goal trial, remain pending. Paired transport regressions use an in-process broker harness; they do not replace those checks. The encrypted-compaction replay mismatch is a separate unresolved issue; this change does not disable its guard or claim to fix it.
@@ -0,0 +1,27 @@
> @wassname2/pi-goals@0.2.2 test
> vitest run
RUN v4.1.9 /home/ubuntu/.pi/agent/worktrees/pi-goals-persistent-steward
Test Files 11 passed (11)
Tests 48 passed (48)
Start at 14:06:36
Duration 6.78s (transform 1.61s, setup 0ms, import 16.58s, tests 11.71s, environment 2ms)
> @wassname2/pi-goals@0.2.2 typecheck
> tsc --noEmit
> @wassname2/pi-goals@0.2.2 lint
> biome check src/ test/
Checked 16 files in 36ms. No fixes applied.
> @wassname2/pi-goals@0.2.2 build
> tsc
DEFAULT_ON_VALIDATION_PASSED
@@ -0,0 +1,157 @@
> @wassname2/pi-goals@0.2.2 test
> vitest run && npm run test:supervisor
RUN v4.1.9 /home/ubuntu/.pi/agent/worktrees/pi-goals-persistent-steward
Test Files 12 passed (12)
Tests 67 passed (67)
Start at 16:14:44
Duration 15.63s (transform 1.67s, setup 307ms, import 22.12s, tests 28.12s, environment 3ms)
> @wassname2/pi-goals@0.2.2 test:supervisor
> node --import tsx --test test/internal-supervisor/*.test.ts
✔ retries intercom registration when pi-intercom loads after pi-supervise (3.540888ms)
✔ a directive with no text is rejected, so the worker never sees undefined (0.288987ms)
✔ a directive from the paired supervisor becomes a real user message (27.396147ms)
✔ a directive to a busy worker interrupts, instead of waiting for the whole task (13.079025ms)
✔ a directive from an unpaired session is dropped (11.977008ms)
✔ a second pair takes over, and the first supervisor is told it lost the worker (21.508059ms)
✔ only the paired worker can end a run (6.314542ms)
✔ the programmatic pairing API waits for the worker acknowledgement (1.485485ms)
✔ the worker acknowledges a pair, so the supervisor knows it was heard (5.359587ms)
✔ a goal the supervisor inferred reaches the worker, which owns the view header (37.477099ms)
✔ the second view carries only what happened after the first (328.068703ms)
✔ a message addressed to a different session is ignored (11.834377ms)
✔ on settle the worker publishes a view built from the live branch (17.888259ms)
✔ the view is built from the live branch, not from every entry in the session (22.049192ms)
✔ an unpaired session publishes nothing on settle (0.498005ms)
✔ supervision never stops itself: no round limit at all (9.442441ms)
✔ goal, pairing and the steer count all survive a reload together (0.791695ms)
✔ a view that arrives while the supervisor is thinking is queued, not dropped (5.643173ms)
✔ the nudge repeats neither the instructions already sent nor the verdict rules (5.269154ms)
✔ a multi-line goal returns to supervisor context every fifth review and after compaction (31.103788ms)
✔ a one-line goal is not redundantly reinserted (26.640178ms)
✔ a check in and a worker that stopped ask for different things (12.287139ms)
✔ a loop still gets named after the supervisor compacts, from restored state (1.450856ms)
✔ a session that does not answer the roll call is not offered as a worker (501.077007ms)
✔ a child run stays out of the roll call, so it can never be picked (5.337167ms)
✔ a session already paired stays out of the roll call, and a free one answers (15.899876ms)
✔ /supervise look asks the worker for a fresh view, rather than the supervisor guessing (306.105484ms)
✔ let_it_run says the turn is over, so it is not called four times running (0.835308ms)
✔ a sign-off verdict is answered, not aborted, and a runaway is still cut (0.609635ms)
✔ every verdict result names the way to end the turn, steer included (0.449781ms)
✔ an old view is dropped from context once its verdict is in, and the verdict is kept (1.046937ms)
✔ a worker session never has its context rewritten (0.289351ms)
✔ a view that arrives mid-answer starts a fresh look (5.824464ms)
✔ a tool a worker cannot use never aborts its turn (0.339873ms)
✔ a resume onto a session that is gone drops the pairing and says so (6.297894ms)
✔ a resume onto a live worker keeps supervising, and takes the writers back off (5.29537ms)
✔ state written before recentSteers existed still loads (0.171283ms)
✔ done unpairs the worker, so it stops publishing views (320.167743ms)
✔ with no goal the supervisor cannot steer, it must ask the human (0.573651ms)
✔ set_goal binds an inferred goal, and steering then works (501.94885ms)
✔ a goal given at pair time still allows steering (0.665903ms)
✔ done is refused while the worker has an unanswered tool call (12.424782ms)
✔ done is allowed once nothing is outstanding (6.182792ms)
✔ steer refuses when the session is not supervising (0.325609ms)
✔ a reworded repeat of an earlier instruction is sent, and named back to the supervisor (0.510602ms)
✔ overlap scores rewording high and a different instruction low (0.136533ms)
✔ the view of the old worker cannot be used to judge the new one (6.045704ms)
✔ with one other session here, /supervise needs no target and the whole line is the goal (501.381162ms)
✔ naming the worker still works, and the rest of the line is the goal (0.554981ms)
✔ with two free sessions here, /supervise asks which one, and pairs with the choice (501.08053ms)
✔ a goal that is a path is read from the file, so it is not pasted every run (2.297652ms)
✔ a long goal is one short line above the picker, and reaches the worker whole (501.854523ms)
✔ a session that stayed quiet is still on the list, because 0 free is a dead end (501.687356ms)
✔ a cancelled picker pairs with nothing (500.579211ms)
✔ supervising takes the writing tools away, and stopping gives them back (501.255208ms)
✔ stopping gives back the writers without undoing another extension's tools (500.601415ms)
✔ a first word that names no session is refused, rather than folded into the goal (0.611801ms)
✔ a goal with spaces needs no target, and @name takes the rest of the line as the goal (501.893405ms)
✔ the brief starts no turn, so there is no answer before the first view (5.995751ms)
✔ /supervise goal changes the goal without breaking the pairing (0.70475ms)
✔ the footer says which side of a pairing this session is, and clears when it ends (506.432358ms)
✔ a session that is not supervising never sees the supervisor tools (5.830284ms)
✔ worker_view refuses when there is no worker, rather than implying a pairing (0.513982ms)
✔ the view names the worker's model and how full its context is (21.061667ms)
✔ supervising a second session is refused while the first is still paired (0.548942ms)
✔ the supervisor gets a look at a working worker every half hour, without being asked (926.124762ms)
✔ a human message in the worker session is not a reason to stand back (6.127037ms)
✔ letting a stopped worker run says plainly that the worker stays stopped (11.377477ms)
✔ a stopped worker is looked at again, so let_it_run cannot silence the pairing (922.993821ms)
✔ a worker that pairs at the prompt and never takes a turn is still watched (604.616558ms)
✔ a worker that reloads at the prompt starts watching itself again (604.845926ms)
✔ a timer look at a worker that has not moved is not sent, until it has been skipped three times (2425.474247ms)
✔ the worker counts reviews in a row where nothing changed (356.432776ms)
✔ an unacknowledged pair gives up, and a takeover cancels that timer (3.893969ms)
✔ duplicate standalone Intercom registries are diagnosed and cannot bootstrap a plan (1.232918ms)
✔ plan bootstrap compacts only the supervisor and pairing alone never starts a worker or a review (18.935035ms)
✔ goal decisions are correlated, preserve the pair across two goals, and cannot call overall done (5.389797ms)
✔ abort and stop cancel pending requests; late decisions cannot approve a replacement (3.265783ms)
✔ 50 actual model turns trigger one view, independent of the number of messages (3.457965ms)
✔ unknown background providers are not proof of quiescence (0.294658ms)
✔ stale plan content invalidates a pending goal review (3.01992ms)
✔ small forks skip compaction, but real compaction failure prevents pairing (2.471879ms)
✔ the hour timer and a coincident turn checkpoint produce a single view (5.559542ms)
✔ settled checks wait for tracked processes and subagents to finish (2.833087ms)
✔ bootstrap stop cannot resurrect a supervisor after compaction completes (2.15529ms)
✔ a restarted worker reconnects by exact saved session identity without a new supervisor (2.812666ms)
✔ unknown initial context must compact instead of taking the known-small shortcut (1.119486ms)
✔ null post-compaction usage cannot raise the next configured 100k checkpoint (2.180167ms)
✔ stopping a routine view during compaction invalidates its suspended continuation (1.977452ms)
✔ restart of a provisional bootstrap resumes compaction and pairing in the same saved session (2.18079ms)
✔ command preserves a stopped supervisor across reload (2.007763ms)
✔ done preserves a stopped supervisor across reload (2.456918ms)
✔ same-binding replay retains activation when the supervisor lost its acknowledgement (2.599438ms)
✔ model-unavailable stop validates binding, cancels pending reviews and ignores old directives (2.091306ms)
✔ a child process named pi is found by ps, and stops being found when it exits (367.036839ms)
✔ the check is a snapshot, so it cannot hold up the worker's settle (321.13146ms)
✔ a one-line goal stays whole while a multi-line goal has a locator (6.226689ms)
✔ a view carries only the turns the supervisor has not been sent (2.16041ms)
✔ the last two reasoning blocks stay in the narrative, and older ones drop out (1.078426ms)
✔ a compaction restarts the view, so no turn falls into the gap (0.455488ms)
✔ pi-vcc reports the files the worker wrote, and separates them from the ones it read (1.361829ms)
✔ progressKey is unchanged when a review produced no new file or commit (0.506944ms)
✔ progressKey still sees a new file past pi-vcc's ten path display cap (0.575315ms)
✔ a commit counts as progress, even when no file was written since (0.960805ms)
✔ outstandingWork finds tool calls that never got a result (1.43676ms)
✔ buildView reports a tool call with no result, so done can be refused (0.87924ms)
✔ the view says how many reviews in a row changed nothing, and says nothing at zero (0.692566ms)
✔ the view merges the worker's compaction summary with the turns after it (0.470565ms)
✔ a turn the compaction summary already covers is not sent twice (0.336722ms)
✔ pi-vcc's sections and its transcript land on the right sides of the split (2.943ms)
✔ the view does not tell the supervisor to use vcc_recall, a tool it does not have (0.291333ms)
✔ supervisor directives are not sent back as worker evidence (0.488463ms)
✔ bookkeeping tool calls are kept out of the transcript (0.390618ms)
✔ buildView reports the goal, status, and files without historical failures (0.42015ms)
✔ how long the worker has been quiet, measured from its own last entry (0.593754ms)
✔ buildView keeps the newest turns when it has to cut for the channel limit (26.316809ms)
✔ pi's own branch logic drops the abandoned fork, on a session file (1793.809954ms)
✔ a long goal cannot push the view past the broker limit (0.55492ms)
tests 118
suites 0
pass 118
fail 0
cancelled 0
skipped 0
todo 0
duration_ms 20178.623102
> @wassname2/pi-goals@0.2.2 typecheck
> tsc -p tsconfig.build.json --noEmit
> @wassname2/pi-goals@0.2.2 lint
> biome check src/ test/
Checked 32 files in 93ms. No fixes applied.
> @wassname2/pi-goals@0.2.2 build
> tsc -p tsconfig.build.json
SINGLE_PACKAGE_FINAL_VALIDATION_PASSED
@@ -0,0 +1,167 @@
GOALS: enabled suite after R6/R7
> @wassname2/pi-goals@0.2.2 test
> vitest run
RUN v4.1.9 /home/ubuntu/.pi/agent/worktrees/pi-goals-persistent-steward
Test Files 11 passed (11)
Tests 45 passed (45)
Start at 12:09:35
Duration 6.14s (transform 1.20s, setup 0ms, import 14.85s, tests 10.77s, environment 2ms)
GOALS: typecheck
> @wassname2/pi-goals@0.2.2 typecheck
> tsc --noEmit
GOALS: lint
> @wassname2/pi-goals@0.2.2 lint
> biome check src/ test/
Checked 16 files in 56ms. No fixes applied.
GOALS: build
> @wassname2/pi-goals@0.2.2 build
> tsc
SUPERVISOR: literal npm test after R6/R7
> @wassname2/pi-supervise@0.0.4 pretest
> tsx scripts/make-fixture.ts
wrote /home/ubuntu/.pi/agent/worktrees/pi-intercom-supervisor-goals-integration/test/forked-session.jsonl
entries (excluding the session header): 410
abandoned entries: 22
> @wassname2/pi-supervise@0.0.4 test
> tsx --test src/*.test.ts
✔ retries intercom registration when pi-intercom loads after pi-supervise (3.429966ms)
✔ a directive with no text is rejected, so the worker never sees undefined (0.247018ms)
✔ a directive from the paired supervisor becomes a real user message (29.622902ms)
✔ a directive to a busy worker interrupts, instead of waiting for the whole task (13.977563ms)
✔ a directive from an unpaired session is dropped (13.157035ms)
✔ a second pair takes over, and the first supervisor is told it lost the worker (27.141375ms)
✔ only the paired worker can end a run (7.283707ms)
✔ the programmatic pairing API waits for the worker acknowledgement (1.436818ms)
✔ the worker acknowledges a pair, so the supervisor knows it was heard (5.54306ms)
✔ a goal the supervisor inferred reaches the worker, which owns the view header (44.194636ms)
✔ the second view carries only what happened after the first (330.585574ms)
✔ a message addressed to a different session is ignored (10.170908ms)
✔ on settle the worker publishes a view built from the live branch (21.893806ms)
✔ the view is built from the live branch, not from every entry in the session (17.260824ms)
✔ an unpaired session publishes nothing on settle (0.379273ms)
✔ supervision never stops itself: no round limit at all (4.651789ms)
✔ goal, pairing and the steer count all survive a reload together (0.521505ms)
✔ a view that arrives while the supervisor is thinking is queued, not dropped (5.970369ms)
✔ the nudge repeats neither the instructions already sent nor the verdict rules (6.195585ms)
✔ a multi-line goal returns to supervisor context every fifth review and after compaction (32.097966ms)
✔ a one-line goal is not redundantly reinserted (26.327091ms)
✔ a check in and a worker that stopped ask for different things (10.092757ms)
✔ a loop still gets named after the supervisor compacts, from restored state (0.953582ms)
✔ a session that does not answer the roll call is not offered as a worker (502.245612ms)
✔ a child run stays out of the roll call, so it can never be picked (6.095977ms)
✔ a session already paired stays out of the roll call, and a free one answers (16.179354ms)
✔ /supervise look asks the worker for a fresh view, rather than the supervisor guessing (308.118194ms)
✔ let_it_run says the turn is over, so it is not called four times running (0.768638ms)
✔ a sign-off verdict is answered, not aborted, and a runaway is still cut (0.57058ms)
✔ every verdict result names the way to end the turn, steer included (0.39166ms)
✔ an old view is dropped from context once its verdict is in, and the verdict is kept (1.05293ms)
✔ a worker session never has its context rewritten (0.295565ms)
✔ a view that arrives mid-answer starts a fresh look (5.950038ms)
✔ a tool a worker cannot use never aborts its turn (0.408612ms)
✔ a resume onto a session that is gone drops the pairing and says so (5.502016ms)
✔ a resume onto a live worker keeps supervising, and takes the writers back off (6.297883ms)
✔ state written before recentSteers existed still loads (0.188312ms)
✔ done unpairs the worker, so it stops publishing views (321.527785ms)
✔ with no goal the supervisor cannot steer, it must ask the human (0.563499ms)
✔ set_goal binds an inferred goal, and steering then works (501.01427ms)
✔ a goal given at pair time still allows steering (0.523019ms)
✔ done is refused while the worker has an unanswered tool call (11.351204ms)
✔ done is allowed once nothing is outstanding (5.223176ms)
✔ steer refuses when the session is not supervising (0.364627ms)
✔ a reworded repeat of an earlier instruction is sent, and named back to the supervisor (0.483156ms)
✔ overlap scores rewording high and a different instruction low (0.114745ms)
✔ the view of the old worker cannot be used to judge the new one (6.06669ms)
✔ with one other session here, /supervise needs no target and the whole line is the goal (501.412838ms)
✔ naming the worker still works, and the rest of the line is the goal (0.519157ms)
✔ with two free sessions here, /supervise asks which one, and pairs with the choice (501.863353ms)
✔ a goal that is a path is read from the file, so it is not pasted every run (2.227961ms)
✔ a long goal is one short line above the picker, and reaches the worker whole (501.010774ms)
✔ a session that stayed quiet is still on the list, because 0 free is a dead end (501.565666ms)
✔ a cancelled picker pairs with nothing (501.796819ms)
✔ supervising takes the writing tools away, and stopping gives them back (501.55056ms)
✔ stopping gives back the writers without undoing another extension's tools (501.583537ms)
✔ a first word that names no session is refused, rather than folded into the goal (0.653782ms)
✔ a goal with spaces needs no target, and @name takes the rest of the line as the goal (501.035374ms)
✔ the brief starts no turn, so there is no answer before the first view (6.002338ms)
✔ /supervise goal changes the goal without breaking the pairing (0.74172ms)
✔ the footer says which side of a pairing this session is, and clears when it ends (505.756191ms)
✔ a session that is not supervising never sees the supervisor tools (5.764996ms)
✔ worker_view refuses when there is no worker, rather than implying a pairing (0.508317ms)
✔ the view names the worker's model and how full its context is (18.254298ms)
✔ supervising a second session is refused while the first is still paired (0.498834ms)
✔ the supervisor gets a look at a working worker every half hour, without being asked (920.025754ms)
✔ a human message in the worker session is not a reason to stand back (6.229147ms)
✔ letting a stopped worker run says plainly that the worker stays stopped (10.401535ms)
✔ a stopped worker is looked at again, so let_it_run cannot silence the pairing (924.087031ms)
✔ a worker that pairs at the prompt and never takes a turn is still watched (604.883737ms)
✔ a worker that reloads at the prompt starts watching itself again (604.981832ms)
✔ a timer look at a worker that has not moved is not sent, until it has been skipped three times (2426.519261ms)
✔ the worker counts reviews in a row where nothing changed (356.420327ms)
✔ an unacknowledged pair gives up, and a takeover cancels that timer (4.220555ms)
✔ plan bootstrap compacts only the supervisor and pairing alone never starts a worker or a review (23.339027ms)
✔ goal decisions are correlated, preserve the pair across two goals, and cannot call overall done (6.488073ms)
✔ abort and stop cancel pending requests; late decisions cannot approve a replacement (4.950084ms)
✔ 50 actual model turns trigger one view, independent of the number of messages (4.336451ms)
✔ unknown background providers are not proof of quiescence (0.39308ms)
✔ stale plan content invalidates a pending goal review (3.928135ms)
✔ small forks skip compaction, but real compaction failure prevents pairing (2.247287ms)
✔ the hour timer and a coincident turn checkpoint produce a single view (3.504665ms)
✔ settled checks wait for tracked processes and subagents to finish (2.813837ms)
✔ bootstrap stop cannot resurrect a supervisor after compaction completes (1.747705ms)
✔ a restarted worker reconnects by exact saved session identity without a new supervisor (2.135761ms)
✔ unknown initial context must compact instead of taking the known-small shortcut (0.924763ms)
✔ null post-compaction usage cannot raise the next configured 100k checkpoint (1.994091ms)
✔ stopping a routine view during compaction invalidates its suspended continuation (1.671618ms)
✔ restart of a provisional bootstrap resumes compaction and pairing in the same saved session (2.221047ms)
✔ command preserves a stopped supervisor across reload (1.905196ms)
✔ done preserves a stopped supervisor across reload (2.421426ms)
✔ same-binding replay retains activation when the supervisor lost its acknowledgement (2.604633ms)
✔ a child process named pi is found by ps, and stops being found when it exits (374.81872ms)
✔ the check is a snapshot, so it cannot hold up the worker's settle (319.675518ms)
✔ a one-line goal stays whole while a multi-line goal has a locator (8.167075ms)
✔ a view carries only the turns the supervisor has not been sent (2.090138ms)
✔ the last two reasoning blocks stay in the narrative, and older ones drop out (1.13405ms)
✔ a compaction restarts the view, so no turn falls into the gap (0.563394ms)
✔ pi-vcc reports the files the worker wrote, and separates them from the ones it read (1.400011ms)
✔ progressKey is unchanged when a review produced no new file or commit (0.525086ms)
✔ progressKey still sees a new file past pi-vcc's ten path display cap (0.725928ms)
✔ a commit counts as progress, even when no file was written since (0.874443ms)
✔ outstandingWork finds tool calls that never got a result (1.469005ms)
✔ buildView reports a tool call with no result, so done can be refused (0.885647ms)
✔ the view says how many reviews in a row changed nothing, and says nothing at zero (0.644311ms)
✔ the view merges the worker's compaction summary with the turns after it (0.44949ms)
✔ a turn the compaction summary already covers is not sent twice (0.364824ms)
✔ pi-vcc's sections and its transcript land on the right sides of the split (2.422505ms)
✔ the view does not tell the supervisor to use vcc_recall, a tool it does not have (0.315271ms)
✔ supervisor directives are not sent back as worker evidence (0.494375ms)
✔ bookkeeping tool calls are kept out of the transcript (0.412053ms)
✔ buildView reports the goal, status, and files without historical failures (0.403255ms)
✔ how long the worker has been quiet, measured from its own last entry (0.460999ms)
✔ buildView keeps the newest turns when it has to cut for the channel limit (33.622661ms)
✔ pi's own branch logic drops the abandoned fork, on a session file (1712.237778ms)
✔ a long goal cannot push the view past the broker limit (0.489445ms)
tests 116
suites 0
pass 116
fail 0
cancelled 0
skipped 0
todo 0
duration_ms 19908.802286
POST-R6-R7 PARENT VALIDATION PASSED
@@ -0,0 +1,26 @@
[
{
"timestamp": "2026-09-08T05:41:10.346Z",
"content": [
"Sign-off REJECTED. Missing:\nchecked-artifact list before VERDICT: accept\n\n--- judge ---\n...\nEL/converter.mjs`, lines 63-65, 74-75\n - Quote: `if (!Number.isFinite(numericValue)) { throw new Error('Value must be a finite number'); }` and `if (!Number.isFinite(result)) { throw new Error('Conversion resulted in a non-finite value'); }`\n - Confirms rejection of NaN, Infinity, and overflow-to-Infinity.\n\n6. **58 tests in converter.test.mjs using node:test**:\n - Path: `/tmp/pi-goals-herdr-uat.TGXaEL/converter.test.mjs`, lines 1-8\n - Quote: `import test from 'node:test'; import assert from 'node:assert'; import { convert } from './converter.mjs';`\n - Confirms real module import and node:test framework; grep found exactly 58 test cases.\n\n7. **Test output log saved and all 58 tests pass**:\n - Path: `/tmp/pi-goals-herdr-uat.TGXaEL/evidence/function-tests.log`, bottom\n - Quote: ` tests 58` ` pass 58` ` fail 0`\n - Confirms all 58 tests passed in a real node:test run.\n\n8. **Specific discriminator test cases all passing**:\n - Path: `/tmp/pi-goals-herdr-uat.TGXaEL/evidence/function-tests.log`\n - Quote: \n - `✔ 0 C = 32 F` (correct known conversion both directions)\n - `✔ Accept exact -273.15 C` (exact absolute-zero acceptance)\n - `✔ Reject -273.16 C (below absolute zero)` (below-limit rejection)\n - `✔ Reject trailing junk \"12junk\"` (regression test: rejects partial parseFloat)\n - `✔ Reject hexadecimal \"0x10\"` (invalid syntax rejection)\n - `✔ Reject NaN input` and `✔ Reject Infinity input` (nonfinite input rejection)\n - `✔ Reject conversion overflow to Infinity` (nonfinite result rejection)\n - `✔ All valid inputs produce finite outputs` (output finiteness assertion)\n - Confirms all subtle failure modes explicitly tested and passing.\n\n9. **Goal 2 (CLI) explicitly NOT implemented** (per pause gate):\n - Paths: find results show no cli.mjs, cli.test.mjs, cli-demo.log, or cli-tests.log in fixture root\n - Confirms the pause gate after goal 1 was respected; goal 2 awaits explicit user instruction.\n\nVERDICT: accept\nmissing:"
]
},
{
"timestamp": "2026-09-08T06:00:40.739Z",
"content": [
"Judge returned no VERDICT line. Accepted inconclusive — logged.\n\n--- judge ---\n(no output)\n\nGoal ticked [x] in .pi/plan/01a07f74-f42d-7eee-85b0-10df065920a0-v1.md."
]
},
{
"timestamp": "2026-09-08T06:09:00.490Z",
"content": [
"Supervisor: needs_work. Inspected cli.mjs, evidence/cli-tests.log and evidence/cli-demo.log. Core CLI behavior and junk regression are evidenced, but neither log includes the required nonfinite conversion-result case (a finite Number.MAX_VALUE string in C). Add a real child-process overflow rejection test and demo recording arguments, empty stdout, stderr and nonzero exit, then rerun and save actual logs. Also reconcile the stale worker view, which still says CLI work is paused, with the explicit user authorization before claiming this checkpoint complete."
]
},
{
"timestamp": "2026-09-08T06:25:30.356Z",
"content": [
"Supervisor review failed: Error: Supervisor request cancelled"
]
}
]
@@ -0,0 +1,85 @@
#!/usr/bin/env node
// Bounded trial accounting only. Reads explicitly named Pi session JSONL files, not RPC event logs.
import { readFileSync, writeFileSync } from "node:fs";
import { resolve } from "node:path";
function session(path) {
const rows = readFileSync(path, "utf8").trim().split("\n").filter(Boolean).map(line => JSON.parse(line));
if (rows[0]?.type !== "session") throw new Error(`Not a Pi session JSONL file: ${path}`);
const byId = new Map();
for (const row of rows.slice(1)) if (typeof row.id === "string") byId.set(row.id, row);
return { header: rows[0], entries: [...byId.values()] }; // Replayed/replaced records count once by entry ID.
}
function snapshot(workerFile, manifestFile) {
const path = resolve(workerFile);
const worker = session(path);
const manifest = { workerFile: path, workerSessionId: worker.header.id, startMs: Date.now(), baselineIds: worker.entries.map(entry => entry.id) };
writeFileSync(manifestFile, `${JSON.stringify(manifest, null, 2)}\n`, { flag: "wx", mode: 0o600 });
return { manifestFile: resolve(manifestFile), workerSessionId: worker.header.id, startMs: manifest.startMs, note: "Snapshot taken before Ready. Keep worker idle until Ready; do not overwrite this boundary." };
}
const fields = ["input", "output", "cacheRead", "cacheWrite", "totalTokens"];
const empty = () => ({ entries: 0, input: 0, output: 0, cacheRead: 0, cacheWrite: 0, totalTokens: 0, missingUsageEntries: [], missingFields: {}, recordedPositiveCostSubtotal: 0, zeroOrMissingCostEntries: [] });
function add(totals, entry, usage) {
totals.entries++; // Persisted accounting entries, including listed missing-usage entries; not provider calls.
if (!usage) { totals.missingUsageEntries.push(entry.id); return; }
for (const field of fields) {
if (Number.isFinite(usage[field]) && usage[field] >= 0) totals[field] += usage[field];
else totals.missingFields[field] = (totals.missingFields[field] ?? 0) + 1;
}
if (Number.isFinite(usage.cost?.total) && usage.cost.total > 0) totals.recordedPositiveCostSubtotal += usage.cost.total;
else totals.zeroOrMissingCostEntries.push(entry.id);
}
function roleUsage(path, baseline, endMs, role) {
const data = session(path);
const inherited = new Set(baseline.baselineIds);
const marker = role === "supervisor" ? data.entries.findIndex(entry => entry.type === "custom" && entry.customType === "pi-goals-supervisor" && resolve(entry.data?.binding?.workerSession ?? "/missing") === baseline.workerFile) : -1;
if (role === "supervisor" && marker < 0) throw new Error("No matching native supervisor bootstrap marker: refusing to count inherited planning usage as supervisor work");
const total = empty(); const assistant = empty(); const compaction = empty(); const nestedTools = empty();
const models = new Set(); const compactions = []; const entriesCounted = []; const missingTimestamps = [];
let selectedModel = null; let completionToolResults = 0;
data.entries.forEach((entry, index) => {
if (entry.type === "model_change") selectedModel = `${entry.provider}/${entry.modelId}`;
if (entry.type === "message" && entry.message?.role === "assistant" && entry.message.provider && entry.message.model) selectedModel = `${entry.message.provider}/${entry.message.model}`;
if (index <= marker || inherited.has(entry.id)) return;
const time = Date.parse(entry.timestamp);
if (!Number.isFinite(time)) { missingTimestamps.push(entry.id); return; }
if (time < baseline.startMs || time > endMs) return;
let category; let usage;
if (entry.type === "message" && entry.message?.role === "assistant" && entry.message.stopReason !== "pending") {
category = assistant; usage = entry.message.usage;
models.add(`${entry.message.provider ?? "unknown"}/${entry.message.model ?? "unknown"}`);
} else if (entry.type === "compaction" || entry.type === "branch_summary") {
category = compaction; usage = entry.usage;
compactions.push({ entryId: entry.id, type: entry.type, timestamp: entry.timestamp, selectedModel, modelAttribution: "selected model inferred from preceding session entries; a custom summarizer may use another model", tokensBefore: entry.tokensBefore ?? null, hasUsage: Boolean(usage) });
} else if (entry.type === "message" && entry.message?.role === "toolResult") {
if (entry.message.toolName === "CompleteGoal") completionToolResults++;
if (entry.message.usage) { category = nestedTools; usage = entry.message.usage; }
}
if (!category) return;
add(category, entry, usage); add(total, entry, usage); entriesCounted.push(entry.id);
});
return { role, sessionFile: resolve(path), sessionId: data.header.id, reportedAssistantModels: [...models], totalRecordedUsage: total, assistant, compaction, nestedTools, compactions, entriesCounted, excludedUnknownTimestampEntries: missingTimestamps, completionToolResults,
cost: total.zeroOrMissingCostEntries.length || total.missingUsageEntries.length ? "unavailable/incomplete: zero or missing pricing is not proof of zero cost" : "recorded positive costs only; not independently verified pricing",
compactionCoverage: "All post-boundary compaction/branch-summary usage is included when persisted. Missing entries are listed, not assumed free. Session records do not explicitly label initial versus later compaction; inspect the timestamp/marker sequence." };
}
const [command, first, second, out] = process.argv.slice(2);
let result;
if (command === "start" && first && second) result = snapshot(first, second);
else if (command === "finish" && first && second) {
const baseline = JSON.parse(readFileSync(first, "utf8"));
const worker = session(baseline.workerFile);
if (worker.header.id !== baseline.workerSessionId) throw new Error("Worker session identity changed since the boundary");
const endMs = Date.now();
result = { startMs: baseline.startMs, endMs,
worker: roleUsage(baseline.workerFile, baseline, endMs, "worker"), supervisor: roleUsage(resolve(second), baseline, endMs, "supervisor"),
currentContext: "These are cumulative recorded token metrics, NOT current context. The >100k compaction trigger uses ctx.getContextUsage().tokens. Native compaction tokensBefore is reported separately above.",
freshEvidenceJudge: { status: "instrumentation gap", explanation: "Current CompleteGoal runs a fresh pi -p --no-session judge and saves its text receipt, not provider Usage. Completion tool result counts do not establish judge invocation counts or tokens. Report judge tokens/cost unavailable unless separately instrumented in an authorized trial; do not hide this overhead in worker/supervisor totals." },
limitations: ["Wait for both trial sessions to settle/stop before finish so no partial JSONL/provider usage is mistaken for completed work.", "Inherited pre-fork history is excluded using both the worker baseline ID set and the supervisor bootstrap marker.", "No RPC message_update/message_end events are counted; duplicate persisted entry IDs are counted once.", "The entries counters are persisted accounting-entry counts, not provider-call counts. Native split-turn compaction may combine multiple calls in one entry, as may aggregated nested-tool usage. Entries with missing usage are counted and listed separately.", "Tool-result nested usage is separate. Do not add it again from another session without proving it is disjoint.", "Long complete VCC refreshes are ordinary supervisor calls and therefore included in supervisor usage, not assumed free."] };
} else throw new Error("Usage: node extract-trial-usage.mjs start WORKER_SESSION.jsonl BOUNDARY.json | finish BOUNDARY.json SUPERVISOR_SESSION.jsonl [USAGE_OUTPUT.json]");
const text = `${JSON.stringify(result, null, 2)}\n`;
if (command === "finish" && out) writeFileSync(out, text, { flag: "wx", mode: 0o600 });
process.stdout.write(text);
@@ -0,0 +1 @@
{"error":{"code":"agent_prompt_stalled","message":"agent prompt produced no observed working or blocked state within 5000 ms; current status is done"},"id":"cli:agent:prompt"}
@@ -0,0 +1,96 @@
{
"sourceSession": "/home/ubuntu/.pi/agent/sessions/--tmp-pi-goals-herdr-uat.TGXaEL--/2026-09-08T05-27-39-268Z_01a07f7c-7a04-7015-bfca-8af0a2fc2089.jsonl",
"compactions": [
{
"id": "4c93819c",
"timestamp": "2026-09-08T06:03:51.958Z",
"tokensBefore": 43242,
"firstKeptEntryId": "19aff06f",
"usage": {
"input": 6,
"output": 1811,
"cacheRead": 0,
"cacheWrite": 13474,
"reasoning": 12,
"totalTokens": 15291,
"cost": {
"input": 0,
"output": 0,
"cacheRead": 0,
"cacheWrite": 0,
"total": 0
}
}
}
],
"advice": [
{
"timestamp": "2026-09-08T05:35:15.748Z",
"tool": "steer",
"arguments": {
"message": "Ready is selected: implement goal one only, with converter.mjs and converter.test.mjs, then run node --test converter.test.mjs and save actual output to evidence/function-tests.log. Report the artifact paths and quote the saved test results for sign-off; do not start any CLI work before the user's explicit instruction."
}
},
{
"timestamp": "2026-09-08T05:37:00.558Z",
"tool": "review_goal",
"arguments": {
"decision": "needs_work",
"reason": "Read converter.mjs: it directly returns `(numericValue * 9 / 5) + 32` and `(numericValue - 32) * 5 / 9` without a finite-result check. Goal one requires rejecting nonfinite conversion results. Add the result guard and an explicit overflow rejection test, rerun the function suite and save its actual log. Keep CLI work paused."
}
},
{
"timestamp": "2026-09-08T05:38:59.617Z",
"tool": "review_goal",
"arguments": {
"decision": "needs_work",
"reason": "converter.mjs now guards both results, but converter.test.mjs's 'Verify conversion output validation is enforced' only checks 1e10, 0 and 32 produce finite outputs. Add assert.throws(() => convert(Number.MAX_VALUE, 'C'), /non-finite/) to exercise actual result overflow, rerun node --test converter.test.mjs and save the actual log. The current test cannot distinguish the earlier broken implementation. Keep goal two paused."
}
},
{
"timestamp": "2026-09-08T05:39:48.084Z",
"tool": "review_goal",
"arguments": {
"decision": "approve",
"reason": "Goal one remains in scope. The inspected implementation has finite-result guards, and converter.test.mjs now asserts actual overflow rejection with Number.MAX_VALUE. evidence/function-tests.log records '✔ Reject conversion overflow to Infinity', ' tests 58', ' pass 58', and ' fail 0'. Approve this checkpoint only; preserve the user-required pause before any goal-two work."
}
},
{
"timestamp": "2026-09-08T05:41:29.463Z",
"tool": "let_it_run",
"arguments": {
"reason": "The worker states: \"Per the execution gate in the plan, I am now PAUSED and waiting for your explicit instruction before implementing Goal 2 (CLI).\" This matches the required user-controlled pause."
}
},
{
"timestamp": "2026-09-08T05:58:40.850Z",
"tool": "let_it_run",
"arguments": {
"reason": "The worker states: \"Per the execution gate in the plan, I am now PAUSED and waiting for your explicit instruction before implementing Goal 2 (CLI).\" No subsequent user authorization for goal two appears in the view."
}
},
{
"timestamp": "2026-09-08T06:00:19.055Z",
"tool": "review_goal",
"arguments": {
"decision": "approve",
"reason": "Previously inspected converter.mjs finite-result guards and converter.test.mjs assertion that convert(Number.MAX_VALUE, 'C') throws /non-finite/. The latest worker view names evidence/function-tests.log and quotes ' tests 58', ' pass 58', ' fail 0', plus '✔ Reject conversion overflow to Infinity (0.299328ms)'. Direction and scope match goal one; independent artifact verification should confirm sign-off. Goal two remains paused pending explicit user instruction."
}
},
{
"timestamp": "2026-09-08T06:00:53.932Z",
"tool": "let_it_run",
"arguments": {
"reason": "The user instructed: \"Keep all CLI work paused until I explicitly authorize goal two.\" The worker reports: \"I am now paused and waiting for your explicit instruction before implementing Goal 2 (the CLI). No CLI files have been created.\""
}
},
{
"timestamp": "2026-09-08T06:09:00.488Z",
"tool": "review_goal",
"arguments": {
"decision": "needs_work",
"reason": "Inspected cli.mjs, evidence/cli-tests.log and evidence/cli-demo.log. Core CLI behavior and junk regression are evidenced, but neither log includes the required nonfinite conversion-result case (a finite Number.MAX_VALUE string in C). Add a real child-process overflow rejection test and demo recording arguments, empty stdout, stderr and nonzero exit, then rerun and save actual logs. Also reconcile the stale worker view, which still says CLI work is paused, with the explicit user authorization before claiming this checkpoint complete."
}
}
]
}
@@ -0,0 +1,175 @@
> @wassname2/pi-goals@0.2.2 test
> vitest run && npm run test:supervisor
RUN v4.1.9 /home/ubuntu/.pi/agent/worktrees/pi-goals-simple-visible-supervision
Test Files 14 passed (14)
Tests 81 passed (81)
Start at 14:01:25
Duration 24.12s (transform 2.35s, setup 503ms, import 23.03s, tests 50.95s, environment 6ms)
> @wassname2/pi-goals@0.2.2 test:supervisor
> node --import tsx --test test/internal-supervisor/*.test.ts
✔ retries intercom registration when pi-intercom loads after pi-supervise (4.227298ms)
✔ a directive with no text is rejected, so the worker never sees undefined (0.426221ms)
✔ a directive from the paired supervisor becomes a real user message (37.225884ms)
✔ a directive to a busy worker interrupts, instead of waiting for the whole task (15.784109ms)
✔ a directive from an unpaired session is dropped (12.29568ms)
✔ a second pair takes over, and the first supervisor is told it lost the worker (26.396215ms)
✔ only the paired worker can end a run (8.158348ms)
✔ the programmatic pairing API waits for the worker acknowledgement (2.239757ms)
✔ the worker acknowledges a pair, so the supervisor knows it was heard (8.486998ms)
✔ a goal the supervisor inferred reaches the worker, which owns the view header (142.929505ms)
✔ the second view carries only what happened after the first (442.433685ms)
✔ a message addressed to a different session is ignored (10.742462ms)
✔ on settle the worker publishes a view built from the live branch (56.519214ms)
✔ the view is built from the live branch, not from every entry in the session (56.418381ms)
✔ an unpaired session publishes nothing on settle (0.741332ms)
✔ supervision never stops itself: no round limit at all (5.534566ms)
✔ goal, pairing and the steer count all survive a reload together (0.550053ms)
✔ a view arriving during unrelated supervisor thinking waits for a fresh complete overview (11.333382ms)
✔ the nudge repeats neither the instructions already sent nor the verdict rules (5.152421ms)
✔ a multi-line goal returns to supervisor context every fifth review and after compaction (32.247189ms)
✔ a one-line goal is not redundantly reinserted (27.177279ms)
✔ a check in and a worker that stopped ask for different things (10.584784ms)
✔ a loop still gets named after the supervisor compacts, from restored state (1.050267ms)
✔ a session that does not answer the roll call is not offered as a worker (501.888517ms)
✔ a child run stays out of the roll call, so it can never be picked (5.986158ms)
✔ a session already paired stays out of the roll call, and a free one answers (16.582061ms)
✔ /supervise look asks the worker for a fresh view, rather than the supervisor guessing (307.790991ms)
✔ let_it_run says the turn is over, so it is not called four times running (0.647696ms)
✔ a sign-off verdict is answered, not aborted, and a runaway is still cut (0.842584ms)
✔ every verdict result names the way to end the turn, steer included (0.574206ms)
✔ an old view is dropped from context once its verdict is in, and the verdict is kept (1.074702ms)
✔ a worker session never has its context rewritten (0.294353ms)
✔ a newly presented view starts a fresh look (5.78599ms)
✔ a tool a worker cannot use never aborts its turn (0.418385ms)
✔ a resume onto a session that is gone drops the pairing and says so (5.830953ms)
✔ a resume onto a live worker keeps supervising, and takes the writers back off (6.00274ms)
✔ state written before recentSteers existed still loads (0.169851ms)
✔ done unpairs the worker, so it stops publishing views (421.186666ms)
✔ with no goal the supervisor cannot steer, it must ask the human (0.899218ms)
✔ set_goal binds an inferred goal, and steering then works (500.8593ms)
✔ a goal given at pair time still allows steering (0.585863ms)
✔ done is refused while the worker has an unanswered tool call (12.548547ms)
✔ done is allowed once nothing is outstanding (6.609937ms)
✔ steer refuses when the session is not supervising (0.480846ms)
✔ a reworded repeat of an earlier instruction is sent, and named back to the supervisor (0.801901ms)
✔ overlap scores rewording high and a different instruction low (0.177702ms)
✔ the view of the old worker cannot be used to judge the new one (6.401726ms)
✔ with one other session here, /supervise needs no target and the whole line is the goal (500.788638ms)
✔ naming the worker still works, and the rest of the line is the goal (0.601582ms)
✔ with two free sessions here, /supervise asks which one, and pairs with the choice (501.732414ms)
✔ a goal that is a path is read from the file, so it is not pasted every run (2.041028ms)
✔ a long goal is one short line above the picker, and reaches the worker whole (501.665702ms)
✔ a session that stayed quiet is still on the list, because 0 free is a dead end (500.678627ms)
✔ a cancelled picker pairs with nothing (500.632721ms)
✔ supervising takes the writing tools away, and stopping gives them back (501.535796ms)
✔ stopping gives back the writers without undoing another extension's tools (501.829786ms)
✔ a first word that names no session is refused, rather than folded into the goal (0.789825ms)
✔ a goal with spaces needs no target, and @name takes the rest of the line as the goal (501.348506ms)
✔ the brief starts no turn, so there is no answer before the first view (6.442694ms)
✔ /supervise goal changes the goal without breaking the pairing (1.012968ms)
✔ the footer says which side of a pairing this session is, and clears when it ends (506.27294ms)
✔ a session that is not supervising never sees the supervisor tools (6.599768ms)
✔ worker_view refuses when there is no worker, rather than implying a pairing (0.619204ms)
✔ the view names the worker's model and how full its context is (58.171961ms)
✔ supervising a second session is refused while the first is still paired (0.831384ms)
✔ the supervisor gets a look at a working worker every half hour, without being asked (975.124652ms)
✔ a human message in the worker session is not a reason to stand back (6.169812ms)
✔ letting a stopped worker run says plainly that the worker stays stopped (11.286563ms)
✔ a stopped worker is looked at again, so let_it_run cannot silence the pairing (926.086028ms)
✔ a worker that pairs at the prompt and never takes a turn is still watched (605.707779ms)
✔ a worker that reloads at the prompt starts watching itself again (605.044296ms)
✔ a timer look at a worker that has not moved is not sent, until it has been skipped three times (2428.612949ms)
✔ the worker counts reviews in a row where nothing changed (579.699233ms)
✔ an unacknowledged pair gives up, and a takeover cancels that timer (4.893877ms)
✔ duplicate standalone Intercom registries are diagnosed and cannot bootstrap a plan (0.862724ms)
✔ retained non-plan supervision reconnects after the worker reloads, not on unrelated peer traffic (345.917589ms)
✔ retained non-plan supervision reconnects after the supervisor reloads, not on unrelated peer traffic (628.225316ms)
✔ busy supervisor retains its active view and requests one complete overview after settling (31.243343ms)
✔ plan bootstrap compacts only the supervisor and pairing alone never starts a worker or a review (32.264425ms)
✔ goal decisions are correlated, preserve the pair across two goals, and cannot call overall done (4.70302ms)
✔ abort and stop cancel pending requests; late decisions cannot approve a replacement (3.9249ms)
✔ 50 actual model turns trigger one view, independent of the number of messages (5.510548ms)
✔ unknown background providers are not proof of quiescence (0.401943ms)
✔ stale plan content invalidates a pending goal review (6.905509ms)
✔ small forks skip compaction, but real compaction failure prevents pairing (3.703867ms)
✔ native small-history result permits startup after an attempted compaction (50000) (1.967591ms)
✔ native small-history result permits startup after an attempted compaction (null) (2.078297ms)
✔ the hour timer and a coincident turn checkpoint produce a single view (6.466486ms)
✔ settled checks wait for tracked processes and subagents to finish (2.789561ms)
✔ bootstrap stop cannot resurrect a supervisor after compaction completes (2.36892ms)
✔ a restarted worker reconnects by exact saved session identity without a new supervisor (5.448449ms)
✔ unknown initial context must compact instead of taking the known-small shortcut (1.249941ms)
✔ null post-compaction usage cannot raise the next configured 100k checkpoint (2.734318ms)
✔ stopping a routine view during compaction invalidates its suspended continuation (3.144067ms)
✔ restart of a provisional bootstrap resumes compaction and pairing in the same saved session (3.524611ms)
✔ command preserves a stopped supervisor across reload (2.800035ms)
✔ done preserves a stopped supervisor across reload (2.91728ms)
✔ same-binding replay retains activation when the supervisor lost its acknowledgement (3.51941ms)
✔ model-unavailable stop validates binding, cancels pending reviews and ignores old directives (2.44535ms)
✔ supervisor mode is a native inspection allowlist at visibility and execution, including reload and stopped forks (2.534243ms)
✔ a cancelled checkpoint's delayed verdict cannot approve the replacement checkpoint (3.005501ms)
✔ each model call reanchors the canonical plan and role without losing compacted planning context or judgments (2.28053ms)
✔ routine assessments and steering display the actual advice rather than only a receipt (2.069783ms)
✔ current context above 100k compacts; cumulative usage and exactly 100k do not (1.465216ms)
✔ absent optional trackers count as zero tracked work; installed failed or busy trackers remain non-quiet (0.298529ms)
✔ a settled worker with no optional trackers sends one review, not repeated idle wakes (2.344359ms)
✔ disconnect cancels a checkpoint and blocks steering; local stop still clears ownership (1.802362ms)
✔ registered malformed subagent tracker stays unknown even when the process tracker is absent (0.320226ms)
✔ a busy supervisor defers the 100k compaction until its own run settles (1.549437ms)
✔ a healthy goal review can take longer than ten minutes without cancellation or another pairing (1.953315ms)
✔ busy plan supervisor refreshes cumulative VCC evidence without an idle feedback loop (5.894195ms)
✔ progress during a refresh remains pending with only one look in flight (4.562161ms)
✔ complete refresh uses the current worker branch after compaction (3.866041ms)
✔ complete refresh uses the current worker branch after rewind (2.442543ms)
✔ complete refresh uses the current worker branch after reload (3.280382ms)
✔ explicit checkpoints wait separately from routine coalescing and do not replace an active assessment (3.029511ms)
✔ actual supervisor provider failure is returned explicitly without another pair or an elapsed-time cancellation (3.241667ms)
✔ a provider error followed by native retry success does not cancel the supervisor checkpoint (5.838725ms)
✔ a failed full overview waits without spinning and recovers on routine progress (7.869651ms)
✔ a failed full overview waits without spinning and recovers on explicit look (3.50097ms)
✔ overview display metadata uses native context without requiring a remote roster lookup (4.49743ms)
✔ a superseded advance re-drives the current checkpoint after deferred compaction success (4.541734ms)
✔ a superseded advance re-drives the current checkpoint after deferred compaction rejection (3.364931ms)
✔ stopping current work during an obsolete advance prevents re-drive after compaction success (2.761416ms)
✔ stopping current work during an obsolete advance prevents re-drive after compaction rejection (9.510342ms)
✔ a child process named pi is found by ps, and stops being found when it exits (400.670699ms)
✔ the check is a snapshot, so it cannot hold up the worker's settle (325.855943ms)
✔ a one-line goal stays whole while a multi-line goal has a locator (7.139299ms)
✔ a view carries only the turns the supervisor has not been sent (2.42323ms)
✔ the last two reasoning blocks stay in the narrative, and older ones drop out (1.126327ms)
✔ a compaction restarts the view, so no turn falls into the gap (0.636179ms)
✔ pi-vcc reports the files the worker wrote, and separates them from the ones it read (1.636892ms)
✔ progressKey is unchanged when a review produced no new file or commit (0.641537ms)
✔ progressKey still sees a new file past pi-vcc's ten path display cap (0.746451ms)
✔ a commit counts as progress, even when no file was written since (0.993827ms)
✔ outstandingWork finds tool calls that never got a result (1.512703ms)
✔ buildView reports a tool call with no result, so done can be refused (0.974291ms)
✔ the view says how many reviews in a row changed nothing, and says nothing at zero (2.051843ms)
✔ the view merges the worker's compaction summary with the turns after it (0.46901ms)
✔ a turn the compaction summary already covers is not sent twice (0.347676ms)
✔ pi-vcc's sections and its transcript land on the right sides of the split (2.622939ms)
✔ the view does not tell the supervisor to use vcc_recall, a tool it does not have (0.426445ms)
✔ supervisor directives are not sent back as worker evidence (0.553966ms)
✔ bookkeeping tool calls are kept out of the transcript (0.416196ms)
✔ buildView reports the goal, status, and files without historical failures (0.446159ms)
✔ how long the worker has been quiet, measured from its own last entry (0.547843ms)
✔ buildView keeps the newest turns when it has to cut for the channel limit (42.609016ms)
✔ pi's own branch logic drops the abandoned fork, on a session file (2208.621704ms)
✔ a long goal cannot push the view past the broker limit (0.558345ms)
✔ a bounded complete overview explicitly labels a truncated worker compaction summary (0.355821ms)
tests 150
suites 0
pass 150
fail 0
cancelled 0
skipped 0
todo 0
duration_ms 20896.672059
@@ -0,0 +1,3 @@
> @wassname2/pi-goals@0.2.2 build
> tsc -p tsconfig.build.json
@@ -0,0 +1,5 @@
> @wassname2/pi-goals@0.2.2 lint
> biome check src/ test/
Checked 36 files in 92ms. No fixes applied.
@@ -0,0 +1,196 @@
> @wassname2/pi-goals@0.2.2 test
> vitest run && npm run test:supervisor
RUN v4.1.9 /home/ubuntu/.pi/agent/worktrees/pi-goals-simple-visible-supervision
Test Files 14 passed (14)
Tests 81 passed (81)
Start at 14:39:34
Duration 23.08s (transform 1.86s, setup 383ms, import 20.70s, tests 48.44s, environment 3ms)
> @wassname2/pi-goals@0.2.2 test:supervisor
> node --import tsx --test test/internal-supervisor/*.test.ts
✔ retries intercom registration when pi-intercom loads after pi-supervise (3.902174ms)
✔ a directive with no text is rejected, so the worker never sees undefined (0.328116ms)
✔ a directive from the paired supervisor becomes a real user message (21.426997ms)
✔ a directive to a busy worker interrupts, instead of waiting for the whole task (14.219762ms)
✔ a directive from an unpaired session is dropped (12.533882ms)
✔ a second pair takes over, and the first supervisor is told it lost the worker (27.9299ms)
✔ only the paired worker can end a run (7.03982ms)
✔ the programmatic pairing API waits for the worker acknowledgement (1.53026ms)
✔ the worker acknowledges a pair, so the supervisor knows it was heard (5.487175ms)
✔ a goal the supervisor inferred reaches the worker, which owns the view header (137.577579ms)
✔ the second view carries only what happened after the first (435.179753ms)
✔ a message addressed to a different session is ignored (10.696368ms)
✔ on settle the worker publishes a view built from the live branch (57.306992ms)
✔ the view is built from the live branch, not from every entry in the session (56.68447ms)
✔ an unpaired session publishes nothing on settle (0.581989ms)
✔ supervision never stops itself: no round limit at all (5.758318ms)
✔ goal, pairing and the steer count all survive a reload together (0.566147ms)
✔ a view arriving during unrelated supervisor thinking waits for a fresh complete overview (11.73855ms)
✔ the nudge repeats neither the instructions already sent nor the verdict rules (6.185005ms)
✔ a multi-line goal returns to supervisor context every fifth review and after compaction (31.516221ms)
✔ a one-line goal is not redundantly reinserted (28.008114ms)
✔ a check in and a worker that stopped ask for different things (11.439857ms)
✔ a loop still gets named after the supervisor compacts, from restored state (1.117781ms)
✔ a session that does not answer the roll call is not offered as a worker (501.3539ms)
✔ a child run stays out of the roll call, so it can never be picked (5.030483ms)
✔ a session already paired stays out of the roll call, and a free one answers (15.089392ms)
✔ /supervise look asks the worker for a fresh view, rather than the supervisor guessing (307.193495ms)
✔ let_it_run says the turn is over, so it is not called four times running (0.676302ms)
✔ a sign-off verdict is answered, not aborted, and a runaway is still cut (0.656312ms)
✔ every verdict result names the way to end the turn, steer included (0.473839ms)
✔ an old view is dropped from context once its verdict is in, and the verdict is kept (1.053468ms)
✔ a worker session never has its context rewritten (0.333986ms)
✔ a newly presented view starts a fresh look (5.745135ms)
✔ a tool a worker cannot use never aborts its turn (0.405935ms)
✔ a resume onto a session that is gone drops the pairing and says so (6.018145ms)
✔ a resume onto a live worker keeps supervising, and takes the writers back off (6.026155ms)
✔ state written before recentSteers existed still loads (0.179773ms)
✔ done unpairs the worker, so it stops publishing views (430.643048ms)
✔ with no goal the supervisor cannot steer, it must ask the human (0.730352ms)
✔ set_goal binds an inferred goal, and steering then works (501.012999ms)
✔ a goal given at pair time still allows steering (0.570176ms)
✔ done is refused while the worker has an unanswered tool call (12.627739ms)
✔ done is allowed once nothing is outstanding (6.242551ms)
✔ steer refuses when the session is not supervising (0.340749ms)
✔ a reworded repeat of an earlier instruction is sent, and named back to the supervisor (0.807133ms)
✔ overlap scores rewording high and a different instruction low (0.131635ms)
✔ the view of the old worker cannot be used to judge the new one (4.978392ms)
✔ with one other session here, /supervise needs no target and the whole line is the goal (500.193542ms)
✔ naming the worker still works, and the rest of the line is the goal (0.567943ms)
✔ with two free sessions here, /supervise asks which one, and pairs with the choice (501.080782ms)
✔ a goal that is a path is read from the file, so it is not pasted every run (1.947811ms)
✔ a long goal is one short line above the picker, and reaches the worker whole (501.036423ms)
✔ a session that stayed quiet is still on the list, because 0 free is a dead end (501.634751ms)
✔ a cancelled picker pairs with nothing (500.580837ms)
✔ supervising takes the writing tools away, and stopping gives them back (501.518809ms)
✔ stopping gives back the writers without undoing another extension's tools (500.660152ms)
✔ a first word that names no session is refused, rather than folded into the goal (0.57234ms)
✔ a goal with spaces needs no target, and @name takes the rest of the line as the goal (501.882273ms)
✔ the brief starts no turn, so there is no answer before the first view (6.132116ms)
✔ /supervise goal changes the goal without breaking the pairing (0.710704ms)
✔ the footer says which side of a pairing this session is, and clears when it ends (506.538204ms)
✔ a session that is not supervising never sees the supervisor tools (4.968927ms)
✔ worker_view refuses when there is no worker, rather than implying a pairing (0.621227ms)
✔ the view names the worker's model and how full its context is (56.12934ms)
✔ supervising a second session is refused while the first is still paired (0.813791ms)
✔ the supervisor gets a look at a working worker every half hour, without being asked (972.724402ms)
✔ a human message in the worker session is not a reason to stand back (5.144485ms)
✔ letting a stopped worker run says plainly that the worker stays stopped (10.435518ms)
✔ a stopped worker is looked at again, so let_it_run cannot silence the pairing (932.562879ms)
✔ a worker that pairs at the prompt and never takes a turn is still watched (604.177279ms)
✔ a worker that reloads at the prompt starts watching itself again (603.890441ms)
✔ a timer look at a worker that has not moved is not sent, until it has been skipped three times (2426.054837ms)
✔ the worker counts reviews in a row where nothing changed (587.040645ms)
✔ an unacknowledged pair gives up, and a takeover cancels that timer (4.99076ms)
✔ duplicate standalone Intercom registries are diagnosed and cannot bootstrap a plan (0.572811ms)
✔ retained non-plan supervision reconnects after the worker reloads, not on unrelated peer traffic (343.931651ms)
✔ retained non-plan supervision reconnects after the supervisor reloads, not on unrelated peer traffic (626.873765ms)
✔ busy supervisor retains its active view and requests one complete overview after settling (32.087166ms)
✔ each checkpoint freezes fresh worker evidence and direction without replacing a busy assessment (31.899373ms)
✔ checkpoint snapshot building cannot publish after abort (2.880596ms)
✔ checkpoint snapshot building cannot publish after stop (8.956519ms)
✔ checkpoint snapshot building cannot publish after reload (2.667688ms)
✔ checkpoint snapshot building cannot publish after plan change (2.877615ms)
✔ checkpoint capture includes user direction arriving while tracked work is queried (2.511844ms)
✔ checkpoint payload fits the serialized channel limit without truncating its identity (72.81385ms)
✔ settled empty final response fails the checkpoint explicitly ([]) (9.685596ms)
✔ settled empty final response fails the checkpoint explicitly (["text"]) (2.899287ms)
✔ settled empty final response fails the checkpoint explicitly (["text"]) (2.850772ms)
✔ settled empty final response fails the checkpoint explicitly (["thinking"]) (2.388046ms)
✔ failed assessment resumes on later worker progress without a human poke (stop) (2.318919ms)
✔ failed assessment resumes on later worker progress without a human poke (error) (1.930327ms)
✔ empty low-level response may continue through compaction, ask a human, or finish with a tool verdict (2.482665ms)
✔ a successful goal tool verdict is not undone by an empty final response (2.214831ms)
✔ a duplicate checkpoint rejection never echoes its snapshot or changes the active view (2.275401ms)
✔ an empty routine assessment cannot fail a separately queued checkpoint (2.55659ms)
✔ plan bootstrap compacts only the supervisor and pairing alone never starts a worker or a review (2.075322ms)
✔ goal decisions are correlated, preserve the pair across two goals, and cannot call overall done (3.23601ms)
✔ abort and stop cancel pending requests; late decisions cannot approve a replacement (2.16195ms)
✔ 50 actual model turns trigger one view, independent of the number of messages (2.424652ms)
✔ unknown background providers are not proof of quiescence (0.207091ms)
✔ stale plan content invalidates a pending goal review (2.674516ms)
✔ small forks skip compaction, but real compaction failure prevents pairing (2.267117ms)
✔ native small-history result permits startup after an attempted compaction (50000) (1.378746ms)
✔ native small-history result permits startup after an attempted compaction (null) (1.096433ms)
✔ the hour timer and a coincident turn checkpoint produce a single view (6.533516ms)
✔ settled checks wait for tracked processes and subagents to finish (3.623399ms)
✔ bootstrap stop cannot resurrect a supervisor after compaction completes (5.414626ms)
✔ a restarted worker reconnects by exact saved session identity without a new supervisor (2.799798ms)
✔ unknown initial context must compact instead of taking the known-small shortcut (1.042567ms)
✔ null post-compaction usage cannot raise the next configured 100k checkpoint (2.177116ms)
✔ stopping a routine view during compaction invalidates its suspended continuation (1.83495ms)
✔ restart of a provisional bootstrap resumes compaction and pairing in the same saved session (2.098918ms)
✔ command preserves a stopped supervisor across reload (1.88657ms)
✔ done preserves a stopped supervisor across reload (2.164052ms)
✔ same-binding replay retains activation when the supervisor lost its acknowledgement (2.445582ms)
✔ model-unavailable stop validates binding, cancels pending reviews and ignores old directives (1.882713ms)
✔ supervisor mode is a native inspection allowlist at visibility and execution, including reload and stopped forks (2.055621ms)
✔ a cancelled checkpoint's delayed verdict cannot approve the replacement checkpoint (2.097359ms)
✔ each model call reanchors the canonical plan and role without losing compacted planning context or judgments (1.652662ms)
✔ routine assessments and steering display the actual advice rather than only a receipt (1.941714ms)
✔ current context above 100k compacts; cumulative usage and exactly 100k do not (1.494223ms)
✔ absent optional trackers count as zero tracked work; installed failed or busy trackers remain non-quiet (0.277273ms)
✔ a settled worker with no optional trackers sends one review, not repeated idle wakes (1.891433ms)
✔ disconnect cancels a checkpoint and blocks steering; local stop still clears ownership (1.836482ms)
✔ registered malformed subagent tracker stays unknown even when the process tracker is absent (0.301608ms)
✔ a busy supervisor defers the 100k compaction until its own run settles (1.994581ms)
✔ a healthy goal review can take longer than ten minutes without cancellation or another pairing (1.921063ms)
✔ busy plan supervisor refreshes cumulative VCC evidence without an idle feedback loop (2.61882ms)
✔ progress during a refresh remains pending with only one look in flight (2.679516ms)
✔ complete refresh uses the current worker branch after compaction (2.362564ms)
✔ complete refresh uses the current worker branch after rewind (1.881952ms)
✔ complete refresh uses the current worker branch after reload (1.942139ms)
✔ explicit checkpoints wait separately from routine coalescing and do not replace an active assessment (2.066604ms)
✔ actual supervisor provider failure is returned explicitly without another pair or an elapsed-time cancellation (1.521288ms)
✔ a provider error followed by native retry success does not cancel the supervisor checkpoint (1.446067ms)
✔ a failed full overview waits without spinning and recovers on routine progress (3.125641ms)
✔ a failed full overview waits without spinning and recovers on explicit look (2.105449ms)
✔ overview display metadata uses native context without requiring a remote roster lookup (1.67603ms)
✔ a superseded advance re-drives the current checkpoint after deferred compaction success (2.494889ms)
✔ a superseded advance re-drives the current checkpoint after deferred compaction rejection (2.082903ms)
✔ stopping current work during an obsolete advance prevents re-drive after compaction success (1.93112ms)
✔ stopping current work during an obsolete advance prevents re-drive after compaction rejection (1.735847ms)
✔ goal_review accepts an optional bounded snapshot but rejects malformed snapshots (1.554983ms)
✔ checkpoint snapshot bounding counts JSON escapes and does not split Unicode characters (4.67607ms)
✔ a child process named pi is found by ps, and stops being found when it exits (400.386374ms)
✔ the check is a snapshot, so it cannot hold up the worker's settle (351.256976ms)
✔ latest user direction survives bounded summaries, compaction and later supervisor echoes (107.306515ms)
✔ oversized user direction is visibly bounded with a source reference (2.769796ms)
✔ a one-line goal stays whole while a multi-line goal has a locator (1.048328ms)
✔ a view carries only the turns the supervisor has not been sent (1.039401ms)
✔ the last two reasoning blocks stay in the narrative, and older ones drop out (0.805118ms)
✔ a compaction restarts the view, so no turn falls into the gap (0.380018ms)
✔ pi-vcc reports the files the worker wrote, and separates them from the ones it read (1.083438ms)
✔ progressKey is unchanged when a review produced no new file or commit (0.507079ms)
✔ progressKey still sees a new file past pi-vcc's ten path display cap (0.530678ms)
✔ a commit counts as progress, even when no file was written since (1.701632ms)
✔ outstandingWork finds tool calls that never got a result (1.014392ms)
✔ buildView reports a tool call with no result, so done can be refused (0.70119ms)
✔ the view says how many reviews in a row changed nothing, and says nothing at zero (0.40831ms)
✔ the view merges the worker's compaction summary with the turns after it (0.34633ms)
✔ a turn the compaction summary already covers is not sent twice (0.281564ms)
✔ pi-vcc's sections and its transcript land on the right sides of the split (1.499473ms)
✔ the view does not tell the supervisor to use vcc_recall, a tool it does not have (0.20563ms)
✔ supervisor directives are not sent back as worker evidence (0.354027ms)
✔ bookkeeping tool calls are kept out of the transcript (0.318495ms)
✔ buildView reports the goal, status, and files without historical failures (0.286487ms)
✔ how long the worker has been quiet, measured from its own last entry (0.341991ms)
✔ buildView keeps the newest turns when it has to cut for the channel limit (39.367034ms)
✔ pi's own branch logic drops the abandoned fork, on a session file (2082.572485ms)
✔ a long goal cannot push the view past the broker limit (0.59147ms)
✔ a bounded complete overview explicitly labels a truncated worker compaction summary (0.371831ms)
tests 171
suites 0
pass 171
fail 0
cancelled 0
skipped 0
todo 0
duration_ms 21133.203043
@@ -0,0 +1,3 @@
> @wassname2/pi-goals@0.2.2 typecheck
> tsc -p tsconfig.build.json --noEmit
@@ -0,0 +1,3 @@
Restored prior state: /home/ubuntu/.pi/agent/pi-goals/planning-model.json
Restored prior state: /home/ubuntu/.pi/agent/pi-goals/worker-model.json
Restored prior state: /home/ubuntu/.pi/agent/pi-goals/supervisor-model.json
@@ -0,0 +1,37 @@
does not end supervision. A
later worker view will
report the worker state.
[supervisor_brief]
Progress assessment: The
worker states: "Per the
execution gate in the plan,
I am now PAUSED and waiting
for your explicit
instruction before
implementing Goal 2 (CLI)."
This matches the required
user-controlled pause.
──────────────────────────────
$ printf
EXECUTION_SHOULD_BE_BLOCKED_
42
Supervisor mode is
inspection-only. Run
commands in the worker pane.
(exit 1)
──────────────────────────────
──────────────────────────────
──────────────────────────────
/tmp/pi-goals-herdr-uat.TGX...
↑84 ↓4.0k R534k W153k CH99....
👁 watching 1
@@ -0,0 +1,35 @@
supervisor message. If the
goal remains unmet, send a
concrete continuation
instruction. A human message
does not end supervision. A
later worker view will
report the worker state.
[supervisor_brief]
Progress assessment: The
worker states: "cli-demo.log
was hand-written (heredoc)
instead of captured from
actual CLI runs" and
"Waiting for explicit
operator resumption." The
outstanding operator
instruction was "Do not call
CompleteGoal or do further
work until the test operator
explicitly resumes you after
reloading the corrected
package."
Plan supervision stopped
──────────────────────────────
──────────────────────────────
/tmp/pi-goals-herdr-uat.TGX...
↑168 ↓8.0k R1.3M W442k CH99...
@@ -0,0 +1,355 @@
{
"startMs": 1788845259248,
"endMs": 1788849703205,
"worker": {
"role": "worker",
"sessionFile": "/home/ubuntu/.pi/agent/sessions/--tmp-pi-goals-herdr-uat.TGXaEL--/2026-09-08T05-19-26-254Z_01a07f74-f42d-7eee-85b0-10df065920a0.jsonl",
"sessionId": "01a07f74-f42d-7eee-85b0-10df065920a0",
"reportedAssistantModels": [
"github-copilot/claude-haiku-4-5-20251001",
"github-copilot/claude-haiku-4.5"
],
"totalRecordedUsage": {
"entries": 68,
"input": 427,
"output": 39611,
"cacheRead": 3479071,
"cacheWrite": 730435,
"totalTokens": 4249544,
"missingUsageEntries": [],
"missingFields": {},
"recordedPositiveCostSubtotal": 1.45943285,
"zeroOrMissingCostEntries": [
"6aeb938d"
]
},
"assistant": {
"entries": 68,
"input": 427,
"output": 39611,
"cacheRead": 3479071,
"cacheWrite": 730435,
"totalTokens": 4249544,
"missingUsageEntries": [],
"missingFields": {},
"recordedPositiveCostSubtotal": 1.45943285,
"zeroOrMissingCostEntries": [
"6aeb938d"
]
},
"compaction": {
"entries": 0,
"input": 0,
"output": 0,
"cacheRead": 0,
"cacheWrite": 0,
"totalTokens": 0,
"missingUsageEntries": [],
"missingFields": {},
"recordedPositiveCostSubtotal": 0,
"zeroOrMissingCostEntries": []
},
"nestedTools": {
"entries": 0,
"input": 0,
"output": 0,
"cacheRead": 0,
"cacheWrite": 0,
"totalTokens": 0,
"missingUsageEntries": [],
"missingFields": {},
"recordedPositiveCostSubtotal": 0,
"zeroOrMissingCostEntries": []
},
"compactions": [],
"entriesCounted": [
"6a6e04a7",
"b4a2f4f2",
"febe0d96",
"bf13d8c3",
"2b51e152",
"2adb0ad3",
"2dab558e",
"3d12be91",
"f8b5837f",
"341448f4",
"c2b896e6",
"e9d164a6",
"e93ba0f2",
"c38dc00e",
"934af358",
"837660f0",
"d3a4614c",
"843d9263",
"76712952",
"71541d12",
"140245f3",
"65409dac",
"d9245939",
"b1613a95",
"df541386",
"11f0c5ee",
"50ca611e",
"1c90f42a",
"bb8b64ac",
"7df8162f",
"4f48db60",
"8dfec4a3",
"7e694984",
"b708c0a6",
"fca206ff",
"cab1d0e9",
"9369d60e",
"4853512b",
"936ea424",
"9e5711e3",
"c6db50c8",
"42667d9f",
"760e0677",
"a56881eb",
"dfe7af6f",
"e4ad17b3",
"6c771286",
"de4ee95c",
"c67a026c",
"b385af99",
"6aeb938d",
"21facf63",
"0f468d8d",
"a22beee4",
"85e01443",
"ff92478f",
"bac91d19",
"e5dee53f",
"9e5d823a",
"21c9c61e",
"1e3eca90",
"4ac37cf2",
"b4d5514f",
"29b074e3",
"5d8f3026",
"beecb616",
"01d61a64",
"a5db8329"
],
"excludedUnknownTimestampEntries": [],
"completionToolResults": 8,
"cost": "unavailable/incomplete: zero or missing pricing is not proof of zero cost",
"compactionCoverage": "All post-boundary compaction/branch-summary usage is included when persisted. Missing entries are listed, not assumed free. Session records do not explicitly label initial versus later compaction; inspect the timestamp/marker sequence."
},
"supervisor": {
"role": "supervisor",
"sessionFile": "/home/ubuntu/.pi/agent/sessions/--tmp-pi-goals-herdr-uat.TGXaEL--/2026-09-08T05-27-39-268Z_01a07f7c-7a04-7015-bfca-8af0a2fc2089.jsonl",
"sessionId": "01a07f7c-7a04-7015-bfca-8af0a2fc2089",
"reportedAssistantModels": [
"github-copilot/gpt-6-astra"
],
"totalRecordedUsage": {
"entries": 42,
"input": 129,
"output": 5035,
"cacheRead": 1097576,
"cacheWrite": 422866,
"totalTokens": 1525606,
"missingUsageEntries": [],
"missingFields": {},
"recordedPositiveCostSubtotal": 0,
"zeroOrMissingCostEntries": [
"4eef3d84",
"e5bae9bb",
"63ff341f",
"efbc771f",
"139ffb13",
"c5e54d92",
"59b3a2c8",
"99860239",
"efddcca1",
"c7b02a2d",
"e389821d",
"fd1cd048",
"cc59835c",
"1189c2d8",
"3d700727",
"60e98242",
"f0ecb5f7",
"2591e9c8",
"14a00f13",
"2961318a",
"4c93819c",
"e02b8597",
"b5f9e2f5",
"7e91736c",
"06e83709",
"b4ecb5c3",
"3409e629",
"74ec901a",
"09f9fce1",
"b6482bac",
"1638dffa",
"cdb6286f",
"5b6914e0",
"43f6c1dc",
"a4f89f95",
"b4dfad7e",
"f506115f",
"91ac16f1",
"c3e8f1de",
"311303ce",
"55083f25",
"b989cb43"
]
},
"assistant": {
"entries": 41,
"input": 123,
"output": 3224,
"cacheRead": 1097576,
"cacheWrite": 409392,
"totalTokens": 1510315,
"missingUsageEntries": [],
"missingFields": {},
"recordedPositiveCostSubtotal": 0,
"zeroOrMissingCostEntries": [
"4eef3d84",
"e5bae9bb",
"63ff341f",
"efbc771f",
"139ffb13",
"c5e54d92",
"59b3a2c8",
"99860239",
"efddcca1",
"c7b02a2d",
"e389821d",
"fd1cd048",
"cc59835c",
"1189c2d8",
"3d700727",
"60e98242",
"f0ecb5f7",
"2591e9c8",
"14a00f13",
"2961318a",
"e02b8597",
"b5f9e2f5",
"7e91736c",
"06e83709",
"b4ecb5c3",
"3409e629",
"74ec901a",
"09f9fce1",
"b6482bac",
"1638dffa",
"cdb6286f",
"5b6914e0",
"43f6c1dc",
"a4f89f95",
"b4dfad7e",
"f506115f",
"91ac16f1",
"c3e8f1de",
"311303ce",
"55083f25",
"b989cb43"
]
},
"compaction": {
"entries": 1,
"input": 6,
"output": 1811,
"cacheRead": 0,
"cacheWrite": 13474,
"totalTokens": 15291,
"missingUsageEntries": [],
"missingFields": {},
"recordedPositiveCostSubtotal": 0,
"zeroOrMissingCostEntries": [
"4c93819c"
]
},
"nestedTools": {
"entries": 0,
"input": 0,
"output": 0,
"cacheRead": 0,
"cacheWrite": 0,
"totalTokens": 0,
"missingUsageEntries": [],
"missingFields": {},
"recordedPositiveCostSubtotal": 0,
"zeroOrMissingCostEntries": []
},
"compactions": [
{
"entryId": "4c93819c",
"type": "compaction",
"timestamp": "2026-09-08T06:03:51.958Z",
"selectedModel": "github-copilot/gpt-6-astra",
"modelAttribution": "selected model inferred from preceding session entries; a custom summarizer may use another model",
"tokensBefore": 43242,
"hasUsage": true
}
],
"entriesCounted": [
"4eef3d84",
"e5bae9bb",
"63ff341f",
"efbc771f",
"139ffb13",
"c5e54d92",
"59b3a2c8",
"99860239",
"efddcca1",
"c7b02a2d",
"e389821d",
"fd1cd048",
"cc59835c",
"1189c2d8",
"3d700727",
"60e98242",
"f0ecb5f7",
"2591e9c8",
"14a00f13",
"2961318a",
"4c93819c",
"e02b8597",
"b5f9e2f5",
"7e91736c",
"06e83709",
"b4ecb5c3",
"3409e629",
"74ec901a",
"09f9fce1",
"b6482bac",
"1638dffa",
"cdb6286f",
"5b6914e0",
"43f6c1dc",
"a4f89f95",
"b4dfad7e",
"f506115f",
"91ac16f1",
"c3e8f1de",
"311303ce",
"55083f25",
"b989cb43"
],
"excludedUnknownTimestampEntries": [],
"completionToolResults": 0,
"cost": "unavailable/incomplete: zero or missing pricing is not proof of zero cost",
"compactionCoverage": "All post-boundary compaction/branch-summary usage is included when persisted. Missing entries are listed, not assumed free. Session records do not explicitly label initial versus later compaction; inspect the timestamp/marker sequence."
},
"currentContext": "These are cumulative recorded token metrics, NOT current context. The >100k compaction trigger uses ctx.getContextUsage().tokens. Native compaction tokensBefore is reported separately above.",
"freshEvidenceJudge": {
"status": "instrumentation gap",
"explanation": "Current CompleteGoal runs a fresh pi -p --no-session judge and saves its text receipt, not provider Usage. Completion tool result counts do not establish judge invocation counts or tokens. Report judge tokens/cost unavailable unless separately instrumented in an authorized trial; do not hide this overhead in worker/supervisor totals."
},
"limitations": [
"Wait for both trial sessions to settle/stop before finish so no partial JSONL/provider usage is mistaken for completed work.",
"Inherited pre-fork history is excluded using both the worker baseline ID set and the supervisor bootstrap marker.",
"No RPC message_update/message_end events are counted; duplicate persisted entry IDs are counted once.",
"The entries counters are persisted accounting-entry counts, not provider-call counts. Native split-turn compaction may combine multiple calls in one entry, as may aggregated nested-tool usage. Entries with missing usage are counted and listed separately.",
"Tool-result nested usage is separate. Do not add it again from another session without proving it is disjoint.",
"Long complete VCC refreshes are ordinary supervisor calls and therefore included in supervisor usage, not assumed free."
]
}
@@ -0,0 +1,221 @@
{
"startMs": 1788845259248,
"endMs": 1788846961538,
"worker": {
"role": "worker",
"sessionFile": "/home/ubuntu/.pi/agent/sessions/--tmp-pi-goals-herdr-uat.TGXaEL--/2026-09-08T05-19-26-254Z_01a07f74-f42d-7eee-85b0-10df065920a0.jsonl",
"sessionId": "01a07f74-f42d-7eee-85b0-10df065920a0",
"reportedAssistantModels": [
"github-copilot/claude-haiku-4-5-20251001"
],
"totalRecordedUsage": {
"entries": 31,
"input": 192,
"output": 19409,
"cacheRead": 1208000,
"cacheWrite": 141969,
"totalTokens": 1369570,
"missingUsageEntries": [],
"missingFields": {},
"recordedPositiveCostSubtotal": 0.39549825,
"zeroOrMissingCostEntries": []
},
"assistant": {
"entries": 31,
"input": 192,
"output": 19409,
"cacheRead": 1208000,
"cacheWrite": 141969,
"totalTokens": 1369570,
"missingUsageEntries": [],
"missingFields": {},
"recordedPositiveCostSubtotal": 0.39549825,
"zeroOrMissingCostEntries": []
},
"compaction": {
"entries": 0,
"input": 0,
"output": 0,
"cacheRead": 0,
"cacheWrite": 0,
"totalTokens": 0,
"missingUsageEntries": [],
"missingFields": {},
"recordedPositiveCostSubtotal": 0,
"zeroOrMissingCostEntries": []
},
"nestedTools": {
"entries": 0,
"input": 0,
"output": 0,
"cacheRead": 0,
"cacheWrite": 0,
"totalTokens": 0,
"missingUsageEntries": [],
"missingFields": {},
"recordedPositiveCostSubtotal": 0,
"zeroOrMissingCostEntries": []
},
"compactions": [],
"entriesCounted": [
"6a6e04a7",
"b4a2f4f2",
"febe0d96",
"bf13d8c3",
"2b51e152",
"2adb0ad3",
"2dab558e",
"3d12be91",
"f8b5837f",
"341448f4",
"c2b896e6",
"e9d164a6",
"e93ba0f2",
"c38dc00e",
"934af358",
"837660f0",
"d3a4614c",
"843d9263",
"76712952",
"71541d12",
"140245f3",
"65409dac",
"d9245939",
"b1613a95",
"df541386",
"11f0c5ee",
"50ca611e",
"1c90f42a",
"bb8b64ac",
"7df8162f",
"4f48db60"
],
"excludedUnknownTimestampEntries": [],
"completionToolResults": 3,
"cost": "recorded positive costs only; not independently verified pricing",
"compactionCoverage": "All post-boundary compaction/branch-summary usage is included when persisted. Missing entries are listed, not assumed free. Session records do not explicitly label initial versus later compaction; inspect the timestamp/marker sequence."
},
"supervisor": {
"role": "supervisor",
"sessionFile": "/home/ubuntu/.pi/agent/sessions/--tmp-pi-goals-herdr-uat.TGXaEL--/2026-09-08T05-27-39-268Z_01a07f7c-7a04-7015-bfca-8af0a2fc2089.jsonl",
"sessionId": "01a07f7c-7a04-7015-bfca-8af0a2fc2089",
"reportedAssistantModels": [
"github-copilot/gpt-6-astra"
],
"totalRecordedUsage": {
"entries": 15,
"input": 45,
"output": 1065,
"cacheRead": 353752,
"cacheWrite": 133546,
"totalTokens": 488408,
"missingUsageEntries": [],
"missingFields": {},
"recordedPositiveCostSubtotal": 0,
"zeroOrMissingCostEntries": [
"4eef3d84",
"e5bae9bb",
"63ff341f",
"efbc771f",
"139ffb13",
"c5e54d92",
"59b3a2c8",
"99860239",
"efddcca1",
"c7b02a2d",
"e389821d",
"fd1cd048",
"cc59835c",
"1189c2d8",
"3d700727"
]
},
"assistant": {
"entries": 15,
"input": 45,
"output": 1065,
"cacheRead": 353752,
"cacheWrite": 133546,
"totalTokens": 488408,
"missingUsageEntries": [],
"missingFields": {},
"recordedPositiveCostSubtotal": 0,
"zeroOrMissingCostEntries": [
"4eef3d84",
"e5bae9bb",
"63ff341f",
"efbc771f",
"139ffb13",
"c5e54d92",
"59b3a2c8",
"99860239",
"efddcca1",
"c7b02a2d",
"e389821d",
"fd1cd048",
"cc59835c",
"1189c2d8",
"3d700727"
]
},
"compaction": {
"entries": 0,
"input": 0,
"output": 0,
"cacheRead": 0,
"cacheWrite": 0,
"totalTokens": 0,
"missingUsageEntries": [],
"missingFields": {},
"recordedPositiveCostSubtotal": 0,
"zeroOrMissingCostEntries": []
},
"nestedTools": {
"entries": 0,
"input": 0,
"output": 0,
"cacheRead": 0,
"cacheWrite": 0,
"totalTokens": 0,
"missingUsageEntries": [],
"missingFields": {},
"recordedPositiveCostSubtotal": 0,
"zeroOrMissingCostEntries": []
},
"compactions": [],
"entriesCounted": [
"4eef3d84",
"e5bae9bb",
"63ff341f",
"efbc771f",
"139ffb13",
"c5e54d92",
"59b3a2c8",
"99860239",
"efddcca1",
"c7b02a2d",
"e389821d",
"fd1cd048",
"cc59835c",
"1189c2d8",
"3d700727"
],
"excludedUnknownTimestampEntries": [],
"completionToolResults": 0,
"cost": "unavailable/incomplete: zero or missing pricing is not proof of zero cost",
"compactionCoverage": "All post-boundary compaction/branch-summary usage is included when persisted. Missing entries are listed, not assumed free. Session records do not explicitly label initial versus later compaction; inspect the timestamp/marker sequence."
},
"currentContext": "These are cumulative recorded token metrics, NOT current context. The >100k compaction trigger uses ctx.getContextUsage().tokens. Native compaction tokensBefore is reported separately above.",
"freshEvidenceJudge": {
"status": "instrumentation gap",
"explanation": "Current CompleteGoal runs a fresh pi -p --no-session judge and saves its text receipt, not provider Usage. Completion tool result counts do not establish judge invocation counts or tokens. Report judge tokens/cost unavailable unless separately instrumented in an authorized trial; do not hide this overhead in worker/supervisor totals."
},
"limitations": [
"Wait for both trial sessions to settle/stop before finish so no partial JSONL/provider usage is mistaken for completed work.",
"Inherited pre-fork history is excluded using both the worker baseline ID set and the supervisor bootstrap marker.",
"No RPC message_update/message_end events are counted; duplicate persisted entry IDs are counted once.",
"The entries counters are persisted accounting-entry counts, not provider-call counts. Native split-turn compaction may combine multiple calls in one entry, as may aggregated nested-tool usage. Entries with missing usage are counted and listed separately.",
"Tool-result nested usage is separate. Do not add it again from another session without proving it is disjoint.",
"Long complete VCC refreshes are ordinary supervisor calls and therefore included in supervisor usage, not assumed free."
]
}
@@ -0,0 +1,10 @@
✔ failed assessment resumes on later worker progress without a human poke (stop) (22.112625ms)
✔ failed assessment resumes on later worker progress without a human poke (error) (3.617584ms)
tests 2
suites 0
pass 2
fail 0
cancelled 0
skipped 0
todo 0
duration_ms 1889.732341
@@ -0,0 +1,46 @@
✖ failed assessment resumes on later worker progress without a human poke (stop) (29.280507ms)
✖ failed assessment resumes on later worker progress without a human poke (error) (5.669199ms)
tests 2
suites 0
pass 0
fail 2
cancelled 0
skipped 0
todo 0
duration_ms 1895.833929
✖ failing tests:
test at test/internal-supervisor/plan.test.ts:1:12636
✖ failed assessment resumes on later worker progress without a human poke (stop) (29.280507ms)
AssertionError [ERR_ASSERTION]: ordinary worker progress must resume supervision without user input
1 !== 2
at TestContext.<anonymous> (/home/ubuntu/.pi/agent/worktrees/pi-goals-simple-visible-supervision/test/internal-supervisor/plan.test.ts:200:12)
at async Test.run (node:internal/test_runner/test:1208:7)
at async startSubtestAfterBootstrap (node:internal/test_runner/harness:385:3) {
generatedMessage: false,
code: 'ERR_ASSERTION',
actual: 1,
expected: 2,
operator: 'strictEqual',
diff: 'simple'
}
test at test/internal-supervisor/plan.test.ts:1:12636
✖ failed assessment resumes on later worker progress without a human poke (error) (5.669199ms)
AssertionError [ERR_ASSERTION]: ordinary worker progress must resume supervision without user input
1 !== 2
at TestContext.<anonymous> (/home/ubuntu/.pi/agent/worktrees/pi-goals-simple-visible-supervision/test/internal-supervisor/plan.test.ts:200:12)
at async Test.run (node:internal/test_runner/test:1208:7)
at async Test.processPendingSubtests (node:internal/test_runner/test:831:7) {
generatedMessage: false,
code: 'ERR_ASSERTION',
actual: 1,
expected: 2,
operator: 'strictEqual',
diff: 'simple'
}
@@ -0,0 +1,37 @@
hand-written (heredoc)
instead of captured from
actual CLI runs
2. Temporary files were
written outside the
fixture
3. Need to capture real
child-process demos from
within the fixture only
Files preserved:
- converter.mjs ✓
- converter.test.mjs ✓
- cli.mjs ✓
- cli.test.mjs ✓
- evidence/function-tests.lo
g ✓
- evidence/cli-tests.log ✓
- evidence/cli-demo.log
(needs regeneration from
real runs)
Waiting for explicit
operator resumption.
Persistent plan steward
disabled.
▸ Provide a CLI with
demonstrated valid and
invalid inputs.
──────────────────────────────
──────────────────────────────
/tmp/pi-goals-herdr-uat.TGX...
↑466 ↓43k R3.7M W749k CH99....
◷ 1/2 goals
@@ -0,0 +1,20 @@
node:net:1986
const error = new UVExceptionWithHostPort(rval, 'listen', address, port);
^
Error: listen EPERM: operation not permitted /tmp/claude/tsx-1000/28.pipe
at Server.setupListenHandle [as _listen2] (node:net:1986:21)
at listenInCluster (node:net:2065:12)
at Server.listen (node:net:2187:5)
at file:///tmp/pi-goals-broker-diagnostic-1T7ENA/package/node_modules/tsx/dist/cli.mjs:53:31472
at new Promise (<anonymous>)
at createIpcServer (file:///tmp/pi-goals-broker-diagnostic-1T7ENA/package/node_modules/tsx/dist/cli.mjs:53:31450)
at async file:///tmp/pi-goals-broker-diagnostic-1T7ENA/package/node_modules/tsx/dist/cli.mjs:55:542 {
code: 'EPERM',
errno: -1,
syscall: 'listen',
address: '/tmp/claude/tsx-1000/28.pipe',
port: -1
}
Node.js v25.8.1
@@ -0,0 +1,9 @@
RUN v4.1.9 /home/ubuntu/.pi/agent/worktrees/pi-goals-simple-visible-supervision
Test Files 3 passed (3)
Tests 43 passed (43)
Start at 09:06:46
Duration 2.31s (transform 729ms, setup 86ms, import 2.98s, tests 844ms, environment 0ms)
@@ -0,0 +1,28 @@
## Review
Read-only recheck limited to the parents fixes for the previously reported P1/P2.
- **Fixed — P1 resolved:** `src/prompts.ts:199201` now requires retaining every goal line, completion status, and evidence references above `## Log`; only verbose settled detail moves into the Appendix. This matches the unchanged identity/status filtering in `src/index.ts:220228`. The pruning instruction and Git-history assumption are gone.
- `test/prompts.test.ts:3238` guards the corrected instructions.
- `test/goals-flow.test.ts:183201` moves supporting detail below the fold, exercises the reload hook, and confirms both accept/inconclusive records, the `2/2` count, and inconclusive disclosure remain intact without emitting new work.
- **Fixed — P2 resolved:** `src/prompts.ts:291294` now directs the judge to review the unique exact subject and reject missing or ambiguous identity without substituting another goal. The overview in `src/index.ts:2130` and descriptions in `test/tick-goal.test.ts:1625` agree with that contract. `test/prompts.test.ts:4044` guards against restoring fuzzy-match wording.
- **Correct:** These are bounded prompt/documentation and regression changes. They resolve the conflicts without changing sign-off invalidation semantics, inferring historical approval, or introducing a Git gate.
**No issues found.**
### Validation
Inspected the parents saved logs:
- `housekeeping-red.log`: the two new prompt assertions failed against the former wording.
- `housekeeping-green.log`: **3 test files / 43 tests passed**.
No commands were run or files edited by this reviewer.
### Merge verdict: OK with notes
Both previous findings are resolved; the narrow fixes are approved. This supersedes the previous source-review block.
Full `npm test` and real isolated Herdr acceptance remain environment-blocked/pending. The targeted tests establish prompt and lifecycle behavior, not real-model judgment or completed two-goal acceptance. Broader parent validation was not attested by this recheck.
@@ -0,0 +1,81 @@
RUN v4.1.9 /home/ubuntu/.pi/agent/worktrees/pi-goals-simple-visible-supervision
test/prompts.test.ts (6 tests | 2 failed | 4 skipped) 23ms
× keeps signed-off goal identities during plan housekeeping 18ms
× gives the judge an exact subject rather than a fuzzy-match fallback 3ms
⎯⎯⎯⎯⎯⎯⎯ Failed Tests 2 ⎯⎯⎯⎯⎯⎯⎯
FAIL test/prompts.test.ts > planning prompt > keeps signed-off goal identities during plan housekeeping
AssertionError: expected '<system-reminder>\nYour plan (.pi/pla…' to contain 'keep every goal line and its completi…'
- Expected
+ Received
- keep every goal line and its completion status above ## Log
+ <system-reminder>
+ Your plan (.pi/plan/test.md, above the fold; the log, learnings and appendix are in the file):
+
+ plan
+
+ Keep it current as you work, with your normal edit tool:
+ - tick finished subtasks ([/] in progress), add discovered ones
+ - append ONE short line to ## Log, and a line to ## Learnings for a gotcha worth keeping
+ - when the active goal's discriminator is satisfied, fill its evidence: list (each item = a durable
+ artifact + a verbatim quote you actually observed + a short read of it), then call CompleteGoal.
+ Don't tick a goal [x] before CompleteGoal accepts; the sign-off log line is the audit trail.
+ - if the working set has grown long, prune finished goals (their evidence lives in git history and
+ ## Log) and move settled detail down to ## Appendix, which is unlimited
+ - the human's latest message outranks this plan. If it corrects the deliverable or scope, amend the
+ user-visible result, user voice, and affected goals before continuing; don't defend the old plan
+ - otherwise keep working toward the active goal; don't stop to ask unless genuinely blocked
+ </system-reminder>
test/prompts.test.ts:34:16
32| it("keeps signed-off goal identities during plan housekeeping", () =>…
33| const text = reminder("plan", ".pi/plan/test.md");
34| expect(text).toContain("keep every goal line and its completion stat…
| ^
35| expect(text).toContain("evidence references beside each goal");
36| expect(text).not.toContain("prune finished goals");
⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[1/2]⎯
FAIL test/prompts.test.ts > planning prompt > gives the judge an exact subject rather than a fuzzy-match fallback
AssertionError: expected 'The working agent claims this goal is…' to contain 'unique exact goal subject'
- Expected
+ Received
- unique exact goal subject
+ The working agent claims this goal is complete:
+
+ goal: first
+
+ Below is the full plan file (plan.md). Find that goal in it (tolerate small wording drift; if
+ you cannot find a matching goal at all, reject and say so). Read User-visible result and User voice
+ first, then its discriminator, subtle failure modes, verify command, and evidence list.
+
+ --- plan file ---
+ 1. [ ] goal: first
+ --- end plan file ---
+
+ Read the cited artifacts (you cannot execute anything), then give your VERDICT.
test/prompts.test.ts:42:16
40| it("gives the judge an exact subject rather than a fuzzy-match fallba…
41| const text = judgeUser({ goal: "first", plan: "1. [ ] goal: first", …
42| expect(text).toContain("unique exact goal subject");
| ^
43| expect(text).not.toContain("tolerate small wording drift");
44| });
⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[2/2]⎯
Test Files 1 failed | 1 passed (2)
Tests 2 failed | 1 passed | 37 skipped (40)
Start at 09:06:07
Duration 1.42s (transform 314ms, setup 63ms, import 1.30s, tests 38ms, environment 0ms)
@@ -0,0 +1,4 @@
> @wassname2/pi-goals@0.2.2 build
> tsc -p tsconfig.build.json
@@ -0,0 +1,5 @@
> @wassname2/pi-goals@0.2.2 lint
> biome check src/ test/
Checked 36 files in 91ms. No fixes applied.
@@ -0,0 +1,9 @@
RUN v4.1.9 /home/ubuntu/.pi/agent/worktrees/pi-goals-simple-visible-supervision
Test Files 13 passed (13)
Tests 94 passed (94)
Start at 09:07:25
Duration 21.60s (transform 1.68s, setup 395ms, import 20.36s, tests 34.15s, environment 2ms)
@@ -0,0 +1,188 @@
> @wassname2/pi-goals@0.2.2 test:supervisor
> node --import tsx --test test/internal-supervisor/*.test.ts
✔ retries intercom registration when pi-intercom loads after pi-supervise (3.974028ms)
✔ a directive with no text is rejected, so the worker never sees undefined (0.293578ms)
✔ a directive from the paired supervisor becomes a real user message (29.040859ms)
✔ a directive to a busy worker interrupts, instead of waiting for the whole task (11.791265ms)
✔ a directive from an unpaired session is dropped (19.421131ms)
✔ a second pair takes over, and the first supervisor is told it lost the worker (20.715922ms)
✔ only the paired worker can end a run (6.353483ms)
✔ the programmatic pairing API waits for the worker acknowledgement (1.387398ms)
✔ the worker acknowledges a pair, so the supervisor knows it was heard (5.41818ms)
✔ a goal the supervisor inferred reaches the worker, which owns the view header (132.824229ms)
✔ the second view carries only what happened after the first (435.544291ms)
✔ a message addressed to a different session is ignored (10.263168ms)
✔ on settle the worker publishes a view built from the live branch (55.816252ms)
✔ the view is built from the live branch, not from every entry in the session (55.656998ms)
✔ an unpaired session publishes nothing on settle (0.544096ms)
✔ supervision never stops itself: no round limit at all (5.166058ms)
✔ goal, pairing and the steer count all survive a reload together (0.627375ms)
✔ a view arriving during unrelated supervisor thinking waits for a fresh complete overview (12.193906ms)
✔ the nudge repeats neither the instructions already sent nor the verdict rules (6.136686ms)
✔ a multi-line goal returns to supervisor context every fifth review and after compaction (32.391613ms)
✔ a one-line goal is not redundantly reinserted (27.14758ms)
✔ a check in and a worker that stopped ask for different things (11.315795ms)
✔ a loop still gets named after the supervisor compacts, from restored state (0.916959ms)
✔ a session that does not answer the roll call is not offered as a worker (501.50719ms)
✔ a child run stays out of the roll call, so it can never be picked (4.989808ms)
✔ a session already paired stays out of the roll call, and a free one answers (15.007393ms)
✔ /supervise look asks the worker for a fresh view, rather than the supervisor guessing (306.09392ms)
✔ let_it_run says the turn is over, so it is not called four times running (0.665336ms)
✔ a sign-off verdict is answered, not aborted, and a runaway is still cut (0.661296ms)
✔ every verdict result names the way to end the turn, steer included (0.41022ms)
✔ an old view is dropped from context once its verdict is in, and the verdict is kept (1.049552ms)
✔ a worker session never has its context rewritten (0.312445ms)
✔ a newly presented view starts a fresh look (5.462915ms)
✔ a tool a worker cannot use never aborts its turn (0.423344ms)
✔ a resume onto a session that is gone drops the pairing and says so (5.570522ms)
✔ a resume onto a live worker keeps supervising, and takes the writers back off (6.022216ms)
✔ state written before recentSteers existed still loads (0.180461ms)
✔ done unpairs the worker, so it stops publishing views (428.081704ms)
✔ with no goal the supervisor cannot steer, it must ask the human (0.830044ms)
✔ set_goal binds an inferred goal, and steering then works (501.633016ms)
✔ a goal given at pair time still allows steering (0.554833ms)
✔ done is refused while the worker has an unanswered tool call (12.761991ms)
✔ done is allowed once nothing is outstanding (6.532494ms)
✔ steer refuses when the session is not supervising (0.399461ms)
✔ a reworded repeat of an earlier instruction is sent, and named back to the supervisor (0.593568ms)
✔ overlap scores rewording high and a different instruction low (0.128624ms)
✔ the view of the old worker cannot be used to judge the new one (6.184772ms)
✔ with one other session here, /supervise needs no target and the whole line is the goal (501.541112ms)
✔ naming the worker still works, and the rest of the line is the goal (0.679012ms)
✔ with two free sessions here, /supervise asks which one, and pairs with the choice (500.988416ms)
✔ a goal that is a path is read from the file, so it is not pasted every run (2.052271ms)
✔ a long goal is one short line above the picker, and reaches the worker whole (501.890317ms)
✔ a session that stayed quiet is still on the list, because 0 free is a dead end (501.763389ms)
✔ a cancelled picker pairs with nothing (501.758475ms)
✔ supervising takes the writing tools away, and stopping gives them back (500.746419ms)
✔ stopping gives back the writers without undoing another extension's tools (501.771845ms)
✔ a first word that names no session is refused, rather than folded into the goal (0.654949ms)
✔ a goal with spaces needs no target, and @name takes the rest of the line as the goal (502.193535ms)
✔ the brief starts no turn, so there is no answer before the first view (6.184913ms)
✔ /supervise goal changes the goal without breaking the pairing (0.754771ms)
✔ the footer says which side of a pairing this session is, and clears when it ends (508.144262ms)
✔ a session that is not supervising never sees the supervisor tools (5.351772ms)
✔ worker_view refuses when there is no worker, rather than implying a pairing (1.56818ms)
✔ the view names the worker's model and how full its context is (55.815989ms)
✔ supervising a second session is refused while the first is still paired (0.644348ms)
✔ the supervisor gets a look at a working worker every half hour, without being asked (973.448527ms)
✔ a human message in the worker session is not a reason to stand back (6.268048ms)
✔ letting a stopped worker run says plainly that the worker stays stopped (10.365848ms)
✔ a stopped worker is looked at again, so let_it_run cannot silence the pairing (925.887224ms)
✔ a worker that pairs at the prompt and never takes a turn is still watched (605.51902ms)
✔ a worker that reloads at the prompt starts watching itself again (604.743394ms)
✔ a timer look at a worker that has not moved is not sent, until it has been skipped three times (2429.468038ms)
✔ the worker counts reviews in a row where nothing changed (577.985914ms)
✔ an unacknowledged pair gives up, and a takeover cancels that timer (5.178547ms)
✔ duplicate standalone Intercom registries are diagnosed and cannot bootstrap a plan (0.832525ms)
✔ retained non-plan supervision reconnects after the worker reloads, not on unrelated peer traffic (344.975935ms)
✔ retained non-plan supervision reconnects after the supervisor reloads, not on unrelated peer traffic (627.895644ms)
✔ busy supervisor retains its active view and requests one complete overview after settling (31.331632ms)
✔ ordinary prose leaves future reviews live: On course; the saved check is the next useful evidence. (31.299092ms)
✔ ordinary prose leaves future reviews live: Which output format do you want? (7.054922ms)
✔ manual last-goal ticks cannot end plan supervision before CompleteGoal (3.367731ms)
✔ completion counts are plan-bound and distinguish inconclusive sign-off when ending supervision (4.579827ms)
✔ each checkpoint freezes fresh worker evidence and direction without replacing a busy assessment (9.345858ms)
✔ checkpoint snapshot building cannot publish after abort (2.874272ms)
✔ checkpoint snapshot building cannot publish after stop (21.699085ms)
✔ checkpoint snapshot building cannot publish after reload (2.94349ms)
✔ checkpoint snapshot building cannot publish after plan change (3.193298ms)
✔ checkpoint capture includes user direction arriving while tracked work is queried (2.828249ms)
✔ checkpoint payload fits the serialized channel limit without truncating its identity (77.119836ms)
✔ settled empty final response fails the checkpoint explicitly ([]) (5.826315ms)
✔ settled empty final response fails the checkpoint explicitly (["text"]) (2.399616ms)
✔ settled empty final response fails the checkpoint explicitly (["text"]) (1.983875ms)
✔ settled empty final response fails the checkpoint explicitly (["thinking"]) (1.55404ms)
✔ failed assessment resumes on later worker progress without a human poke (stop) (1.767669ms)
✔ failed assessment resumes on later worker progress without a human poke (error) (1.397948ms)
✔ empty low-level response may continue through compaction, ask a human, or finish with a tool verdict (2.553043ms)
✔ a successful goal tool verdict is not undone by an empty final response (1.959099ms)
✔ a duplicate checkpoint rejection never echoes its snapshot or changes the active view (2.140537ms)
✔ an empty routine assessment cannot fail a separately queued checkpoint (2.391144ms)
✔ plan bootstrap compacts only the supervisor and pairing alone never starts a worker or a review (1.738156ms)
✔ goal decisions are correlated, preserve the pair across two goals, and cannot call overall done (2.61962ms)
✔ abort and stop cancel pending requests; late decisions cannot approve a replacement (1.943861ms)
✔ 50 actual model turns trigger one view, independent of the number of messages (2.077155ms)
✔ unknown background providers are not proof of quiescence (0.224206ms)
✔ stale plan content invalidates a pending goal review (2.190617ms)
✔ small forks skip compaction, but real compaction failure prevents pairing (1.770236ms)
✔ native small-history result permits startup after an attempted compaction (50000) (1.149776ms)
✔ native small-history result permits startup after an attempted compaction (null) (0.989274ms)
✔ the hour timer and a coincident turn checkpoint produce a single view (4.810231ms)
✔ settled checks wait for tracked processes and subagents to finish (2.321824ms)
✔ bootstrap stop cannot resurrect a supervisor after compaction completes (1.887956ms)
✔ a restarted worker reconnects by exact saved session identity without a new supervisor (2.651845ms)
✔ unknown initial context must compact instead of taking the known-small shortcut (0.884878ms)
✔ null post-compaction usage cannot raise the next configured 100k checkpoint (1.897635ms)
✔ stopping a routine view during compaction invalidates its suspended continuation (1.841943ms)
✔ restart of a provisional bootstrap resumes compaction and pairing in the same saved session (2.414359ms)
✔ command preserves a stopped supervisor across reload (1.739858ms)
✔ done preserves a stopped supervisor across reload (2.194354ms)
✔ same-binding replay retains activation when the supervisor lost its acknowledgement (2.993195ms)
✔ model-unavailable stop validates binding, cancels pending reviews and ignores old directives (2.274799ms)
✔ supervisor mode is a native inspection allowlist at visibility and execution, including reload and stopped forks (2.183069ms)
✔ a cancelled checkpoint's delayed verdict cannot approve the replacement checkpoint (2.297678ms)
✔ each model call reanchors the canonical plan and role without losing compacted planning context or judgments (1.91378ms)
✔ routine assessments and steering display the actual advice rather than only a receipt (1.950418ms)
✔ current context above 100k compacts; cumulative usage and exactly 100k do not (1.806256ms)
✔ absent optional trackers count as zero tracked work; installed failed or busy trackers remain non-quiet (0.346121ms)
✔ a settled worker with no optional trackers sends one review, not repeated idle wakes (2.802864ms)
✔ disconnect cancels a checkpoint and blocks steering; local stop still clears ownership (2.023057ms)
✔ registered malformed subagent tracker stays unknown even when the process tracker is absent (0.352469ms)
✔ a busy supervisor defers the 100k compaction until its own run settles (1.919556ms)
✔ a healthy goal review can take longer than ten minutes without cancellation or another pairing (2.175237ms)
✔ busy plan supervisor refreshes cumulative VCC evidence without an idle feedback loop (4.336383ms)
✔ progress during a refresh remains pending with only one look in flight (8.493816ms)
✔ complete refresh uses the current worker branch after compaction (4.751519ms)
✔ complete refresh uses the current worker branch after rewind (3.59423ms)
✔ complete refresh uses the current worker branch after reload (3.022736ms)
✔ explicit checkpoints wait separately from routine coalescing and do not replace an active assessment (3.084625ms)
✔ actual supervisor provider failure is returned explicitly without another pair or an elapsed-time cancellation (1.926238ms)
✔ a provider error followed by native retry success does not cancel the supervisor checkpoint (1.872509ms)
✔ a failed full overview waits without spinning and recovers on routine progress (4.173687ms)
✔ a failed full overview waits without spinning and recovers on explicit look (2.924851ms)
✔ overview display metadata uses native context without requiring a remote roster lookup (1.976883ms)
✔ a superseded advance re-drives the current checkpoint after deferred compaction success (3.037736ms)
✔ a superseded advance re-drives the current checkpoint after deferred compaction rejection (2.425301ms)
✔ stopping current work during an obsolete advance prevents re-drive after compaction success (2.481801ms)
✔ stopping current work during an obsolete advance prevents re-drive after compaction rejection (2.130017ms)
✔ goal_review accepts an optional bounded snapshot but rejects malformed snapshots (1.89367ms)
✔ worker completion metadata is optional but cannot claim malformed counts (0.451557ms)
✔ checkpoint snapshot bounding counts JSON escapes and does not split Unicode characters (5.01807ms)
✔ a child process named pi is found by ps, and stops being found when it exits (413.232236ms)
✔ the check is a snapshot, so it cannot hold up the worker's settle (324.687926ms)
✔ latest user direction survives bounded summaries, compaction and later supervisor echoes (114.635148ms)
✔ oversized user direction is visibly bounded with a source reference (2.69704ms)
✔ a one-line goal stays whole while a multi-line goal has a locator (1.094539ms)
✔ a view carries only the turns the supervisor has not been sent (1.084425ms)
✔ the last two reasoning blocks stay in the narrative, and older ones drop out (1.002457ms)
✔ a compaction restarts the view, so no turn falls into the gap (0.457013ms)
✔ pi-vcc reports the files the worker wrote, and separates them from the ones it read (1.503099ms)
✔ progressKey is unchanged when a review produced no new file or commit (0.732168ms)
✔ progressKey still sees a new file past pi-vcc's ten path display cap (1.020185ms)
✔ a commit counts as progress, even when no file was written since (8.584645ms)
✔ outstandingWork finds tool calls that never got a result (3.568082ms)
✔ buildView reports a tool call with no result, so done can be refused (2.667216ms)
✔ the view says how many reviews in a row changed nothing, and says nothing at zero (1.134394ms)
✔ the view merges the worker's compaction summary with the turns after it (0.422717ms)
✔ a turn the compaction summary already covers is not sent twice (1.946043ms)
✔ pi-vcc's sections and its transcript land on the right sides of the split (2.32661ms)
✔ the view does not tell the supervisor to use vcc_recall, a tool it does not have (0.296905ms)
✔ supervisor directives are not sent back as worker evidence (0.792699ms)
✔ bookkeeping tool calls are kept out of the transcript (0.44677ms)
✔ buildView reports the goal, status, and files without historical failures (0.427038ms)
✔ how long the worker has been quiet, measured from its own last entry (0.436767ms)
✔ buildView keeps the newest turns when it has to cut for the channel limit (45.163847ms)
✔ pi's own branch logic drops the abandoned fork, on a session file (2196.625029ms)
✔ a long goal cannot push the view past the broker limit (0.457776ms)
✔ a bounded complete overview explicitly labels a truncated worker compaction summary (0.265551ms)
tests 176
suites 0
pass 176
fail 0
cancelled 0
skipped 0
todo 0
duration_ms 21219.975303
@@ -0,0 +1,4 @@
> @wassname2/pi-goals@0.2.2 typecheck
> tsc -p tsconfig.build.json --noEmit
@@ -0,0 +1,4 @@
> @wassname2/pi-goals@0.2.2 build
> tsc -p tsconfig.build.json
@@ -0,0 +1,34 @@
wdl, woodside, workflow-diagram-tracker, ws-roadmap-slide, wsl-proxy
[Prompts]
/council, /gather-context-and-clarify, /parallel-cleanup, /parallel-research, /parallel-review, /review-loop
[Extensions]
@aliou/pi-processes:processes, @aliou/pi-processes:processes-dock, @aliou/pi-processes:processes-logs, @ff-labs/pi-fff:src, herdr-agent-state.ts, pi-annotated-journal, pi-better-compaction, pi-sandbox, pi-schedule-prompt:src, pi-subagents,
pi-zed-shift-enter:extension.ts, pi-zentui:zentui, src, wassname/pi-copilot-web
[Themes]
adventure, adwaita-dark, arcoiris, arthur, atom, aura, black-metal-bathory, black-metal-burzum, black-metal-khold, box, brogrammer, carbonfox, catppuccin-mocha, citruszest, cursor-dark, cutie-pro, dark-modern, dark-pastel, dimmed-monokai, doom-peacock, dracula-plus,
earthsong, everforest-dark-hard, fahrenheit, flatland, flexoki-dark, front-end-delight, fun-forrest, galizur, github-dark-colorblind, github-dark-high-contrast, glacier, gruber-darker, gruvbox-dark, gruvbox-dark-hard, gruvbox-material, guezwhoz, hacktober, hardcore,
havn-skumring, ic-orange-ppl, iterm2-smoooooth, iterm2-tango-dark, japanesque, jellybeans, kanagawa-wave, kurokula, later-this-evening, lovelace, material-darker, matte-black, mellow, miasma, nvim-dark, popping-and-locking, sea-shells, sleepy-hollow, smyck, tomorrow-night,
tomorrow-night-bright, tomorrow-night-burns, twilight, vague, vesper, xcode-dark-hc
─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
Operator-created recovery command fixture. The plan is a draft, not approved. Do not implement it.
─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
Operator fixture marker, not a model response.
Warning: ⚠️ Network sandbox allows all domains because network.allowedDomains contains "*". Only use this intentionally; remove "*" to restore per-domain prompts.
Goals mode exited. Files retained; no work approved. Supervisor sessions remain inspection-only.
─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
│ gpt-6-astra Github Copilot minimal
─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
trial-nAjUyF 🔒 Sandbox: all domains, 4 write paths | [░░░░░░░░░░] 0.0%/400k (auto) | $0.000 (sub)
@@ -0,0 +1,70 @@
[Extensions] │
@aliou/pi-processes:processes, @aliou/pi-processes:processes-dock, @aliou/pi-processes:processes-logs, @ff-labs/pi-fff:src, herdr-agent-state.ts, pi-annotated-journal, pi-better-compaction, pi-sandbox, pi-schedule-prompt:src, pi-subagents, │
pi-zed-shift-enter:extension.ts, pi-zentui:zentui, src, wassname/pi-copilot-web │
[Themes] │
adventure, adwaita-dark, arcoiris, arthur, atom, aura, black-metal-bathory, black-metal-burzum, black-metal-khold, box, brogrammer, carbonfox, catppuccin-mocha, citruszest, cursor-dark, cutie-pro, dark-modern, dark-pastel, dimmed-monokai, doom-peacock, dracula-plus, │
earthsong, everforest-dark-hard, fahrenheit, flatland, flexoki-dark, front-end-delight, fun-forrest, galizur, github-dark-colorblind, github-dark-high-contrast, glacier, gruber-darker, gruvbox-dark, gruvbox-dark-hard, gruvbox-material, guezwhoz, hacktober, hardcore, │
havn-skumring, ic-orange-ppl, iterm2-smoooooth, iterm2-tango-dark, japanesque, jellybeans, kanagawa-wave, kurokula, later-this-evening, lovelace, material-darker, matte-black, mellow, miasma, nvim-dark, popping-and-locking, sea-shells, sleepy-hollow, smyck, tomorrow-night│
tomorrow-night-bright, tomorrow-night-burns, twilight, vague, vesper, xcode-dark-hc │
Warning: ⚠️ Network sandbox allows all domains because network.allowedDomains contains "*". Only use this intentionally; remove "*" to restore per-domain prompts. │
pi-better-compaction loaded • debug artifacts → /home/ubuntu/.pi/agent/artifacts/pi-better-compaction/sessions/01a084a5-a0f4-74c9-99fc-f9e5ae61adec/lifecycle/2026-09-09T05-35-21-169Z-lifecycle.json │
────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────│
Operator-created recovery command fixture. The plan is a draft, not approved. Do not implement it. │
────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────│
Operator fixture marker, not a model response. ┃
────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┃
Package Updates Available ┃
Package updates are available. Run pi update --extensions ┃
Packages: ┃
- pi-sandbox ┃
- pi-zentui ┃
- github.com/wassname/pi-annotated-journal ┃
────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┃
Goals: ordinary chat (goals exited). ┃
Pair: disconnected/unconfirmed; inactive. ↓ Jump to latest message · End │
Warning: ⚠️ Network sandbox allows all domains because network.allowedDomains contains "*". Only use this intentionally; remove "*" to restore per-domain prompts.
pi-better-compaction loaded • debug artifacts → /home/ubuntu/.pi/agent/artifacts/pi-better-compaction/sessions/01a084a5-a0f4-74c9-99fc-f9e5ae61adec/lifecycle/2026-09-09T05-35-21-169Z-lifecycle.json
─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
Operator-created recovery command fixture. The plan is a draft, not approved. Do not implement it.
─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
Operator fixture marker, not a model response.
─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
Package Updates Available
Package updates are available. Run pi update --extensions
Packages:
- pi-sandbox
- pi-zentui
- github.com/wassname/pi-annotated-journal
─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
Goals: ordinary chat (goals exited).
Pair: disconnected/unconfirmed; inactive.
Worker: not recorded · no paired session
Supervisor: not recorded · no paired session
Last failure: none recorded in this runtime
─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
│ gpt-6-astra Github Copilot minimal
─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
trial-nAjUyF 🔒 Sandbox: all domains, 4 write paths | [░░░░░░░░░░] 0.0%/400k (auto) | $0.000 (sub)
@@ -0,0 +1,5 @@
> @wassname2/pi-goals@0.2.2 lint
> biome check src/ test/
Checked 36 files in 97ms. No fixes applied.
@@ -0,0 +1,204 @@
> @wassname2/pi-goals@0.2.2 test
> vitest run && npm run test:supervisor
RUN v4.1.9 /home/ubuntu/.pi/agent/worktrees/pi-goals-simple-visible-supervision
Test Files 14 passed (14)
Tests 101 passed (101)
Start at 13:38:22
Duration 23.27s (transform 2.37s, setup 395ms, import 21.82s, tests 50.33s, environment 5ms)
> @wassname2/pi-goals@0.2.2 test:supervisor
> node --import tsx --test test/internal-supervisor/*.test.ts
✔ retries intercom registration when pi-intercom loads after pi-supervise (3.513793ms)
✔ a directive with no text is rejected, so the worker never sees undefined (0.472691ms)
✔ a directive from the paired supervisor becomes a real user message (27.644033ms)
✔ a directive to a busy worker interrupts, instead of waiting for the whole task (13.94769ms)
✔ a directive from an unpaired session is dropped (15.908473ms)
✔ a second pair takes over, and the first supervisor is told it lost the worker (21.082703ms)
✔ only the paired worker can end a run (7.780322ms)
✔ the programmatic pairing API waits for the worker acknowledgement (1.376736ms)
✔ the worker acknowledges a pair, so the supervisor knows it was heard (6.283045ms)
✔ a goal the supervisor inferred reaches the worker, which owns the view header (131.134854ms)
✔ the second view carries only what happened after the first (436.748028ms)
✔ a message addressed to a different session is ignored (10.19648ms)
✔ on settle the worker publishes a view built from the live branch (54.951438ms)
✔ the view is built from the live branch, not from every entry in the session (54.932155ms)
✔ an unpaired session publishes nothing on settle (0.5274ms)
✔ supervision never stops itself: no round limit at all (5.101803ms)
✔ goal, pairing and the steer count all survive a reload together (0.596129ms)
✔ a view arriving during unrelated supervisor thinking waits for a fresh complete overview (11.19975ms)
✔ the nudge repeats neither the instructions already sent nor the verdict rules (6.045907ms)
✔ a multi-line goal returns to supervisor context every fifth review and after compaction (32.277779ms)
✔ a one-line goal is not redundantly reinserted (26.746878ms)
✔ a check in and a worker that stopped ask for different things (10.249474ms)
✔ a loop still gets named after the supervisor compacts, from restored state (1.006545ms)
✔ a session that does not answer the roll call is not offered as a worker (502.069337ms)
✔ a child run stays out of the roll call, so it can never be picked (5.882165ms)
✔ a session already paired stays out of the roll call, and a free one answers (15.515028ms)
✔ /supervise look asks the worker for a fresh view, rather than the supervisor guessing (306.997507ms)
✔ let_it_run says the turn is over, so it is not called four times running (0.614118ms)
✔ a sign-off verdict is answered, not aborted, and a runaway is still cut (0.766328ms)
✔ every verdict result names the way to end the turn, steer included (0.601185ms)
✔ an old view is dropped from context once its verdict is in, and the verdict is kept (1.039013ms)
✔ a worker session never has its context rewritten (0.303001ms)
✔ a newly presented view starts a fresh look (5.626017ms)
✔ a tool a worker cannot use never aborts its turn (0.604727ms)
✔ a resume onto a session that is gone drops the pairing and says so (5.917942ms)
✔ a resume onto a live worker keeps supervising, and takes the writers back off (5.276493ms)
✔ state written before recentSteers existed still loads (0.221018ms)
✔ done unpairs the worker, so it stops publishing views (423.568859ms)
✔ with no goal the supervisor cannot steer, it must ask the human (0.742368ms)
✔ set_goal binds an inferred goal, and steering then works (501.288202ms)
✔ a goal given at pair time still allows steering (0.55747ms)
✔ done is refused while the worker has an unanswered tool call (12.979101ms)
✔ done is allowed once nothing is outstanding (5.279803ms)
✔ steer refuses when the session is not supervising (0.367787ms)
✔ a reworded repeat of an earlier instruction is sent, and named back to the supervisor (0.586311ms)
✔ overlap scores rewording high and a different instruction low (0.138077ms)
✔ the view of the old worker cannot be used to judge the new one (6.59538ms)
✔ with one other session here, /supervise needs no target and the whole line is the goal (501.480943ms)
✔ naming the worker still works, and the rest of the line is the goal (0.566102ms)
✔ with two free sessions here, /supervise asks which one, and pairs with the choice (500.820463ms)
✔ a goal that is a path is read from the file, so it is not pasted every run (2.17768ms)
✔ a long goal is one short line above the picker, and reaches the worker whole (501.878571ms)
✔ a session that stayed quiet is still on the list, because 0 free is a dead end (501.668999ms)
✔ a cancelled picker pairs with nothing (500.656172ms)
✔ supervising takes the writing tools away, and stopping gives them back (501.514864ms)
✔ stopping gives back the writers without undoing another extension's tools (501.710321ms)
✔ a first word that names no session is refused, rather than folded into the goal (0.552837ms)
✔ a goal with spaces needs no target, and @name takes the rest of the line as the goal (501.716252ms)
✔ the brief starts no turn, so there is no answer before the first view (6.049466ms)
✔ /supervise goal changes the goal without breaking the pairing (0.644898ms)
✔ the footer says which side of a pairing this session is, and clears when it ends (506.479387ms)
✔ a session that is not supervising never sees the supervisor tools (6.510238ms)
✔ worker_view refuses when there is no worker, rather than implying a pairing (0.773467ms)
✔ the view names the worker's model and how full its context is (55.333572ms)
✔ supervising a second session is refused while the first is still paired (0.619021ms)
✔ the supervisor gets a look at a working worker every half hour, without being asked (974.700755ms)
✔ a human message in the worker session is not a reason to stand back (6.119204ms)
✔ letting a stopped worker run says plainly that the worker stays stopped (11.325288ms)
✔ a stopped worker is looked at again, so let_it_run cannot silence the pairing (928.080952ms)
✔ a worker that pairs at the prompt and never takes a turn is still watched (605.615767ms)
✔ a worker that reloads at the prompt starts watching itself again (605.010128ms)
✔ a timer look at a worker that has not moved is not sent, until it has been skipped three times (2434.182048ms)
✔ the worker counts reviews in a row where nothing changed (580.138243ms)
✔ an unacknowledged pair gives up, and a takeover cancels that timer (5.648124ms)
✔ duplicate standalone Intercom registries are diagnosed and cannot bootstrap a plan (0.839488ms)
✔ retained non-plan supervision reconnects after the worker reloads, not on unrelated peer traffic (345.059118ms)
✔ retained non-plan supervision reconnects after the supervisor reloads, not on unrelated peer traffic (628.825545ms)
✔ busy supervisor retains its active view and requests one complete overview after settling (31.386612ms)
✔ human pause survives reload/reconnect; only explicit resume reactivates the same pair (33.112188ms)
✔ stop cancels an in-flight checkpoint even when the cancel notification cannot be sent (6.210007ms)
✔ supervisor pause cancels checkpoint and a disconnected local stop still persists (4.374153ms)
✔ ordinary prose leaves future reviews live: On course; the saved check is the next useful evidence. (8.733354ms)
✔ ordinary prose leaves future reviews live: Which output format do you want? (4.512364ms)
✔ manual last-goal ticks cannot end plan supervision before CompleteGoal (2.39126ms)
✔ completion counts are plan-bound and distinguish inconclusive sign-off when ending supervision (4.338931ms)
✔ each checkpoint freezes fresh worker evidence and direction without replacing a busy assessment (6.420082ms)
✔ checkpoint snapshot building cannot publish after abort (2.288189ms)
✔ checkpoint snapshot building cannot publish after stop (8.410958ms)
✔ checkpoint snapshot building cannot publish after reload (1.97679ms)
✔ checkpoint snapshot building cannot publish after plan change (1.998333ms)
✔ checkpoint capture includes user direction arriving while tracked work is queried (2.027935ms)
✔ checkpoint payload fits the serialized channel limit without truncating its identity (76.173014ms)
✔ settled empty final response fails the checkpoint explicitly ([]) (4.469246ms)
✔ settled empty final response fails the checkpoint explicitly (["text"]) (1.484115ms)
✔ settled empty final response fails the checkpoint explicitly (["text"]) (1.620401ms)
✔ settled empty final response fails the checkpoint explicitly (["thinking"]) (1.455427ms)
✔ failed assessment resumes on later worker progress without a human poke (stop) (2.139792ms)
✔ failed assessment resumes on later worker progress without a human poke (error) (1.490922ms)
✔ empty low-level response may continue through compaction, ask a human, or finish with a tool verdict (2.368309ms)
✔ a successful goal tool verdict is not undone by an empty final response (2.000919ms)
✔ a duplicate checkpoint rejection never echoes its snapshot or changes the active view (1.967399ms)
✔ an empty routine assessment cannot fail a separately queued checkpoint (2.00475ms)
✔ plan bootstrap compacts only the supervisor and pairing alone never starts a worker or a review (1.394665ms)
✔ goal decisions are correlated, preserve the pair across two goals, and cannot call overall done (2.282643ms)
✔ abort and stop cancel pending requests; late decisions cannot approve a replacement (1.660897ms)
✔ 50 actual model turns trigger one view, independent of the number of messages (1.928283ms)
✔ unknown background providers are not proof of quiescence (0.198076ms)
✔ stale plan content invalidates a pending goal review (2.144203ms)
✔ small forks skip compaction, but real compaction failure prevents pairing (1.584189ms)
✔ native small-history result permits startup after an attempted compaction (50000) (0.988832ms)
✔ native small-history result permits startup after an attempted compaction (null) (0.75011ms)
✔ the hour timer and a coincident turn checkpoint produce a single view (4.330684ms)
✔ settled checks wait for tracked processes and subagents to finish (2.062665ms)
✔ bootstrap stop cannot resurrect a supervisor after compaction completes (1.529383ms)
✔ a restarted worker reconnects by exact saved session identity without a new supervisor (2.505604ms)
✔ unknown initial context must compact instead of taking the known-small shortcut (1.267376ms)
✔ null post-compaction usage cannot raise the next configured 100k checkpoint (2.338111ms)
✔ stopping a routine view during compaction invalidates its suspended continuation (1.707556ms)
✔ restart of a provisional bootstrap resumes compaction and pairing in the same saved session (2.48264ms)
✔ command preserves a stopped supervisor across reload (1.840487ms)
✔ done preserves a stopped supervisor across reload (2.952022ms)
✔ same-binding replay retains activation when the supervisor lost its acknowledgement (3.738066ms)
✔ model-unavailable stop validates binding, cancels pending reviews and ignores old directives (2.963335ms)
✔ supervisor mode is a native inspection allowlist at visibility and execution, including reload and stopped forks (3.2371ms)
✔ a cancelled checkpoint's delayed verdict cannot approve the replacement checkpoint (3.477147ms)
✔ each model call reanchors the canonical plan and role without losing compacted planning context or judgments (2.473904ms)
✔ routine assessments and steering display the actual advice rather than only a receipt (2.783747ms)
✔ current context above 100k compacts; cumulative usage and exactly 100k do not (2.379765ms)
✔ absent optional trackers count as zero tracked work; installed failed or busy trackers remain non-quiet (0.421638ms)
✔ a settled worker with no optional trackers sends one review, not repeated idle wakes (3.307215ms)
✔ disconnect cancels a checkpoint and blocks steering; local stop still clears ownership (2.01323ms)
✔ registered malformed subagent tracker stays unknown even when the process tracker is absent (0.311552ms)
✔ a busy supervisor defers the 100k compaction until its own run settles (1.785982ms)
✔ a healthy goal review can take longer than ten minutes without cancellation or another pairing (2.14447ms)
✔ busy plan supervisor refreshes cumulative VCC evidence without an idle feedback loop (3.204869ms)
✔ progress during a refresh remains pending with only one look in flight (3.93267ms)
✔ complete refresh uses the current worker branch after compaction (2.418211ms)
✔ complete refresh uses the current worker branch after rewind (2.364448ms)
✔ complete refresh uses the current worker branch after reload (2.477204ms)
✔ explicit checkpoints wait separately from routine coalescing and do not replace an active assessment (2.757015ms)
✔ actual supervisor provider failure is returned explicitly without another pair or an elapsed-time cancellation (1.60961ms)
✔ a provider error followed by native retry success does not cancel the supervisor checkpoint (1.625357ms)
✔ a failed full overview waits without spinning and recovers on routine progress (3.834412ms)
✔ a failed full overview waits without spinning and recovers on explicit look (2.610627ms)
✔ overview display metadata uses native context without requiring a remote roster lookup (1.794804ms)
✔ a superseded advance re-drives the current checkpoint after deferred compaction success (2.809267ms)
✔ a superseded advance re-drives the current checkpoint after deferred compaction rejection (2.450308ms)
✔ stopping current work during an obsolete advance prevents re-drive after compaction success (2.096725ms)
✔ stopping current work during an obsolete advance prevents re-drive after compaction rejection (1.957782ms)
✔ goal_review accepts an optional bounded snapshot but rejects malformed snapshots (1.551675ms)
✔ worker completion metadata is optional but cannot claim malformed counts (0.459292ms)
✔ checkpoint snapshot bounding counts JSON escapes and does not split Unicode characters (5.01943ms)
✔ a child process named pi is found by ps, and stops being found when it exits (361.27963ms)
✔ the check is a snapshot, so it cannot hold up the worker's settle (327.919292ms)
✔ latest user direction survives bounded summaries, compaction and later supervisor echoes (82.002344ms)
✔ oversized user direction is visibly bounded with a source reference (2.652949ms)
✔ a one-line goal stays whole while a multi-line goal has a locator (1.298412ms)
✔ a view carries only the turns the supervisor has not been sent (1.16182ms)
✔ the last two reasoning blocks stay in the narrative, and older ones drop out (1.009051ms)
✔ a compaction restarts the view, so no turn falls into the gap (0.491271ms)
✔ pi-vcc reports the files the worker wrote, and separates them from the ones it read (1.551769ms)
✔ progressKey is unchanged when a review produced no new file or commit (0.723151ms)
✔ progressKey still sees a new file past pi-vcc's ten path display cap (0.853796ms)
✔ a commit counts as progress, even when no file was written since (1.124031ms)
✔ outstandingWork finds tool calls that never got a result (2.699571ms)
✔ buildView reports a tool call with no result, so done can be refused (1.30884ms)
✔ the view says how many reviews in a row changed nothing, and says nothing at zero (0.553271ms)
✔ the view merges the worker's compaction summary with the turns after it (0.439182ms)
✔ a turn the compaction summary already covers is not sent twice (0.975019ms)
✔ pi-vcc's sections and its transcript land on the right sides of the split (1.84901ms)
✔ the view does not tell the supervisor to use vcc_recall, a tool it does not have (0.311653ms)
✔ supervisor directives are not sent back as worker evidence (0.566437ms)
✔ bookkeeping tool calls are kept out of the transcript (0.395583ms)
✔ buildView reports the goal, status, and files without historical failures (0.43785ms)
✔ how long the worker has been quiet, measured from its own last entry (0.458098ms)
✔ buildView keeps the newest turns when it has to cut for the channel limit (39.471288ms)
✔ pi's own branch logic drops the abandoned fork, on a session file (1939.636064ms)
✔ a long goal cannot push the view past the broker limit (0.551003ms)
✔ a bounded complete overview explicitly labels a truncated worker compaction summary (0.286204ms)
tests 179
suites 0
pass 179
fail 0
cancelled 0
skipped 0
todo 0
duration_ms 20775.476362
@@ -0,0 +1,34 @@
[Prompts]
/council, /gather-context-and-clarify, /parallel-cleanup, /parallel-research, /parallel-review, /review-loop
[Extensions]
@aliou/pi-processes:processes, @aliou/pi-processes:processes-dock, @aliou/pi-processes:processes-logs, @ff-labs/pi-fff:src, herdr-agent-state.ts, pi-annotated-journal, pi-better-compaction, pi-sandbox, pi-schedule-prompt:src, pi-subagents,
pi-zed-shift-enter:extension.ts, pi-zentui:zentui, src, wassname/pi-copilot-web
[Themes]
adventure, adwaita-dark, arcoiris, arthur, atom, aura, black-metal-bathory, black-metal-burzum, black-metal-khold, box, brogrammer, carbonfox, catppuccin-mocha, citruszest, cursor-dark, cutie-pro, dark-modern, dark-pastel, dimmed-monokai, doom-peacock, dracula-plus,
earthsong, everforest-dark-hard, fahrenheit, flatland, flexoki-dark, front-end-delight, fun-forrest, galizur, github-dark-colorblind, github-dark-high-contrast, glacier, gruber-darker, gruvbox-dark, gruvbox-dark-hard, gruvbox-material, guezwhoz, hacktober, hardcore,
havn-skumring, ic-orange-ppl, iterm2-smoooooth, iterm2-tango-dark, japanesque, jellybeans, kanagawa-wave, kurokula, later-this-evening, lovelace, material-darker, matte-black, mellow, miasma, nvim-dark, popping-and-locking, sea-shells, sleepy-hollow, smyck, tomorrow-night,
tomorrow-night-bright, tomorrow-night-burns, twilight, vague, vesper, xcode-dark-hc
─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
Operator-created recovery command fixture. The plan is a draft, not approved. Do not implement it.
─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
Operator fixture marker, not a model response.
Warning: ⚠️ Network sandbox allows all domains because network.allowedDomains contains "*". Only use this intentionally; remove "*" to restore per-domain prompts.
Goals mode exited. Files retained; no work approved. Supervisor sessions remain inspection-only.
Warning: Recovery failed; no new work authorized: Error: No recoverable pair. Reconnect never creates a supervisor; inspect the recorded pane or select Ready for a new pairing.
─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
│ gpt-6-astra Github Copilot minimal
─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
trial-nAjUyF 🔒 Sandbox: all domains, 4 write paths | [░░░░░░░░░░] 0.0%/400k (auto) | $0.000 (sub)
@@ -0,0 +1,34 @@
[Prompts]
/council, /gather-context-and-clarify, /parallel-cleanup, /parallel-research, /parallel-review, /review-loop
[Extensions]
@aliou/pi-processes:processes, @aliou/pi-processes:processes-dock, @aliou/pi-processes:processes-logs, @ff-labs/pi-fff:src, herdr-agent-state.ts, pi-annotated-journal, pi-better-compaction, pi-sandbox, pi-schedule-prompt:src, pi-subagents,
pi-zed-shift-enter:extension.ts, pi-zentui:zentui, src, wassname/pi-copilot-web
[Themes]
adventure, adwaita-dark, arcoiris, arthur, atom, aura, black-metal-bathory, black-metal-burzum, black-metal-khold, box, brogrammer, carbonfox, catppuccin-mocha, citruszest, cursor-dark, cutie-pro, dark-modern, dark-pastel, dimmed-monokai, doom-peacock, dracula-plus,
earthsong, everforest-dark-hard, fahrenheit, flatland, flexoki-dark, front-end-delight, fun-forrest, galizur, github-dark-colorblind, github-dark-high-contrast, glacier, gruber-darker, gruvbox-dark, gruvbox-dark-hard, gruvbox-material, guezwhoz, hacktober, hardcore,
havn-skumring, ic-orange-ppl, iterm2-smoooooth, iterm2-tango-dark, japanesque, jellybeans, kanagawa-wave, kurokula, later-this-evening, lovelace, material-darker, matte-black, mellow, miasma, nvim-dark, popping-and-locking, sea-shells, sleepy-hollow, smyck, tomorrow-night,
tomorrow-night-bright, tomorrow-night-burns, twilight, vague, vesper, xcode-dark-hc
─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
Operator-created recovery command fixture. The plan is a draft, not approved. Do not implement it.
─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
Operator fixture marker, not a model response.
Warning: ⚠️ Network sandbox allows all domains because network.allowedDomains contains "*". Only use this intentionally; remove "*" to restore per-domain prompts.
Reloaded keybindings, extensions, skills, prompts, themes, and context files
Goals stopped by user. Plan and evidence retained.
─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
│ gpt-6-astra Github Copilot minimal
─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
trial-nAjUyF goals stopped · /goals resume | 🔒 Sandbox: all domains, 4 write paths | [░░░░░░░░░░] 0.0%/400k (auto) | $0.000 (sub)
@@ -0,0 +1,34 @@
[Prompts]
/council, /gather-context-and-clarify, /parallel-cleanup, /parallel-research, /parallel-review, /review-loop
[Extensions]
@aliou/pi-processes:processes, @aliou/pi-processes:processes-dock, @aliou/pi-processes:processes-logs, @ff-labs/pi-fff:src, herdr-agent-state.ts, pi-annotated-journal, pi-better-compaction, pi-sandbox, pi-schedule-prompt:src, pi-subagents,
pi-zed-shift-enter:extension.ts, pi-zentui:zentui, src, wassname/pi-copilot-web
[Themes]
adventure, adwaita-dark, arcoiris, arthur, atom, aura, black-metal-bathory, black-metal-burzum, black-metal-khold, box, brogrammer, carbonfox, catppuccin-mocha, citruszest, cursor-dark, cutie-pro, dark-modern, dark-pastel, dimmed-monokai, doom-peacock, dracula-plus,
earthsong, everforest-dark-hard, fahrenheit, flatland, flexoki-dark, front-end-delight, fun-forrest, galizur, github-dark-colorblind, github-dark-high-contrast, glacier, gruber-darker, gruvbox-dark, gruvbox-dark-hard, gruvbox-material, guezwhoz, hacktober, hardcore,
havn-skumring, ic-orange-ppl, iterm2-smoooooth, iterm2-tango-dark, japanesque, jellybeans, kanagawa-wave, kurokula, later-this-evening, lovelace, material-darker, matte-black, mellow, miasma, nvim-dark, popping-and-locking, sea-shells, sleepy-hollow, smyck, tomorrow-night,
tomorrow-night-bright, tomorrow-night-burns, twilight, vague, vesper, xcode-dark-hc
─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
Operator-created recovery command fixture. The plan is a draft, not approved. Do not implement it.
─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
Operator fixture marker, not a model response.
Warning: ⚠️ Network sandbox allows all domains because network.allowedDomains contains "*". Only use this intentionally; remove "*" to restore per-domain prompts.
Draft restored; no work started. Review the plan and request Ready before working.
pi-goals: drafting goals
─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
│ gpt-6-astra Github Copilot minimal
─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
trial-nAjUyF planning | 🔒 Sandbox: all domains, 4 write paths | [░░░░░░░░░░] 0.0%/400k (auto) | $0.000 (sub)
@@ -0,0 +1,75 @@
integrated-solutions-architecture, ipynb, jira-search, just, m365-search, marimo, markdown-tables, md-share, mermaid-js, ml-debug, ml-human-in-loop, moa, moa-brainstorm, moa-science, ocr, on-the-record, oracle, pi-intercom, pi-processes, pi-subagents, plan-format, ┃
platform-alignment, project-brief, pseudopy, react-component-design, react-unit-testing, recommending-pi-extensions, review, roadmap, scout-provision, skill-authoring, skill-bootstrapper, skill-importer, snowflake-query, task-tracker, tufte-viz, uv, vargdown, varglite, ┃
wdl, woodside, workflow-diagram-tracker, ws-roadmap-slide, wsl-proxy ┃
[Prompts] ┃
integrated-solutions-architecture, ipynb, jira-search, just, m365-search, marimo, markdown-tables, md-share, mermaid-js, ml-debug, ml-human-in-loop, moa, moa-brainstorm, moa-science, ocr, on-the-record, oracle, pi-intercom, pi-processes, pi-subagents, plan-format, │
platform-alignment, project-brief, pseudopy, react-component-design, react-unit-testing, recommending-pi-extensions, review, roadmap, scout-provision, skill-authoring, skill-bootstrapper, skill-importer, snowflake-query, task-tracker, tufte-viz, uv, vargdown, varglite, │
wdl, woodside, workflow-diagram-tracker, ws-roadmap-slide, wsl-proxy │
[Prompts] │
/council, /gather-context-and-clarify, /parallel-cleanup, /parallel-research, /parallel-review, /review-loop │
[Extensions] │
@aliou/pi-processes:processes, @aliou/pi-processes:processes-dock, @aliou/pi-processes:processes-logs, @ff-labs/pi-fff:src, herdr-agent-state.ts, pi-annotated-journal, pi-better-compaction, pi-sandbox, pi-schedule-prompt:src, pi-subagents, │
pi-zed-shift-enter:extension.ts, pi-zentui:zentui, src, wassname/pi-copilot-web │
[Themes] │
adventure, adwaita-dark, arcoiris, arthur, atom, aura, black-metal-bathory, black-metal-burzum, black-metal-khold, box, brogrammer, carbonfox, catppuccin-mocha, citruszest, cursor-dark, cutie-pro, dark-modern, dark-pastel, dimmed-monokai, doom-peacock, dracula-plus, │
earthsong, everforest-dark-hard, fahrenheit, flatland, flexoki-dark, front-end-delight, fun-forrest, galizur, github-dark-colorblind, github-dark-high-contrast, glacier, gruber-darker, gruvbox-dark, gruvbox-dark-hard, gruvbox-material, guezwhoz, hacktober, hardcore, │
havn-skumring, ic-orange-ppl, iterm2-smoooooth, iterm2-tango-dark, japanesque, jellybeans, kanagawa-wave, kurokula, later-this-evening, lovelace, material-darker, matte-black, mellow, miasma, nvim-dark, popping-and-locking, sea-shells, sleepy-hollow, smyck, tomorrow-night│
tomorrow-night-bright, tomorrow-night-burns, twilight, vague, vesper, xcode-dark-hc │
Warning: ⚠️ Network sandbox allows all domains because network.allowedDomains contains "*". Only use this intentionally; remove "*" to restore per-domain prompts. │
pi-better-compaction loaded • debug artifacts → /home/ubuntu/.pi/agent/artifacts/pi-better-compaction/sessions/01a084a5-a0f4-74c9-99fc-f9e5ae61adec/lifecycle/2026-09-09T05-32-14-754Z-lifecycle.json │
────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────│
Operator-created recovery command fixture. The plan is a draft, not approved. Do not implement it. ┃
────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┃
Operator fixture marker, not a model response. ┃
────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┃
Package Updates Available ┃
Package updates are available. Run pi update --extensions ┃
Packages: ┃
- pi-sandbox ┃
- pi-zentui ┃
- github.com/wassname/pi-annotated-journal ↓ Jump to latest message · End │
tomorrow-night-bright, tomorrow-night-burns, twilight, vague, vesper, xcode-dark-hc
Warning: ⚠️ Network sandbox allows all domains because network.allowedDomains contains "*". Only use this intentionally; remove "*" to restore per-domain prompts.
pi-better-compaction loaded • debug artifacts → /home/ubuntu/.pi/agent/artifacts/pi-better-compaction/sessions/01a084a5-a0f4-74c9-99fc-f9e5ae61adec/lifecycle/2026-09-09T05-32-14-754Z-lifecycle.json
─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
Operator-created recovery command fixture. The plan is a draft, not approved. Do not implement it.
─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
Operator fixture marker, not a model response.
─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
Package Updates Available
Package updates are available. Run pi update --extensions
Packages:
- pi-sandbox
- pi-zentui
- github.com/wassname/pi-annotated-journal
─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
Goals stopped. Use /goals resume in the worker when ready. Detached processes are not killed.
Goals stopped by user. Plan and evidence retained.
─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
│ gpt-6-astra Github Copilot minimal
─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
trial-nAjUyF goals stopped · /goals resume | 🔒 Sandbox: all domains, 4 write paths | [░░░░░░░░░░] 0.0%/400k (auto) | $0.000 (sub)
@@ -0,0 +1,4 @@
> @wassname2/pi-goals@0.2.2 typecheck
> tsc -p tsconfig.build.json --noEmit
@@ -0,0 +1,8 @@
PASS: stop persisted paused draft.
PASS: resume restored planning without Ready authorization.
PASS: exit persisted ordinary-chat state.
PASS: no assistant turn beyond operator fixture marker.
PASS: draft bytes unchanged.
PASS: actual reload rendered; stopped status retained.
PASS: reconnect without a pair reports failure instead of launching one.
PASS: fresh-shell --session retained exit; status reports ordinary chat.
@@ -0,0 +1,44 @@
# Plan-aware supervisor integration
Approved direction: compose the existing supervisor with native Pi/Herdr sessions. See [intent](../../spec/2026-09-07_plan-supervisor.md) and [final validation](../../reviews/2026-09-07_supervisor-validation.md).
- [ ] goal: Ready creates a real, plan-aware supervisor that the user can open beside the worker
- [x] Replace the checkpoint reviewer with native fork/bootstrap, acknowledged pairing and a Herdr launch/focus adapter.
- [x] Compact only the supervisor; supply the explicit worker plan and isolate the supervisor role.
- [x] Observe live supervisor steering and accepted sign-off for one goal.
- [ ] Verify navigation, reload, two-goal persistence and automatic whole-plan cleanup in Herdr.
- failure modes: dashboard mistaken for a session; inherited worker automation; duplicate startup.
- deliverable: branch implementation and trial route; live visual acceptance remains open.
- evidence: [final log](../../reviews/evidence/2026-09-07_supervisor-validation.log) shows 45 enabled goals tests passing, including two real Pi processes and actual Intercom; Herdr is mocked.
- [x] goal: One supervisor checks progress at the agreed cadence without following every worker turn
- [x] Use one 50-model-turn / 60-minute / settled-and-no-tracked-work policy, VCC views, retained verdicts and supervisor-only compaction.
- failure modes: duplicate timers; message count substituted for model turns; unknown work treated as finished.
- deliverable: supervisor branch with deterministic cadence, background-state and compaction coverage.
- evidence: [final log](../../reviews/evidence/2026-09-07_supervisor-validation.log) includes passing 50-turn, hour/turn coincidence, unknown-provider, background-completion and nullable-compaction regressions. Token savings are not yet measured.
- [x] goal: Goal sign-off asks that supervisor and still checks evidence independently
- [x] Correlate goal requests and replies; preserve pairing between goals; keep the worker and fresh judge as the completion path.
- [x] Cover stale replies, cancellation, interrupted bootstrap, lost acknowledgement and explicit stop/reload.
- failure modes: one goal ends all supervision; an old response approves another goal; disabled-only tests.
- deliverable: single-call sign-off with actual-package and real-Pi integration tests.
- evidence: [final log](../../reviews/evidence/2026-09-07_supervisor-validation.log) records 45 goals and 116 supervisor tests passing without skips; [report](../../reviews/2026-09-07_supervisor-validation.md) distinguishes the real and mocked boundaries.
- [x] goal: The two branches are reviewable and ready for a user trial
- [x] Complete the single-writer implementation, independent review, accepted R1R7 fixes and final parent diff/test checks.
- failure modes: mocks hide the package boundary; undisclosed updates; unrelated settings/lockfiles change.
- deliverable: [review disposition, saved validation and trial commands](../../reviews/2026-09-07_supervisor-validation.md).
- evidence: final log ends `POST-R6-R7 PARENT VALIDATION PASSED`; typecheck/lint/build and both diff checks passed. R6/R7 were parent-reviewed after the independent three-round cap, not independently re-reviewed.
## UAT / Verification
- Success: Ready initializes and pairs; goal review reaches the correct supervisor and fresh judge. Automated enabled-path evidence is saved above.
- Likely failure: unavailable Intercom/Herdr/API produces an actionable error, with no false approval; covered in tests.
- Sneaky failure: pending work, stale replies or restarted identities cause a false finish; targeted lifecycle regressions pass.
- Still required: see/focus/zoom both real Herdr sessions, reload/compact the supervisor and finish two goals. Measure supervisor token use and usefulness on real work.
## Constraints and state
- Goals: `/home/ubuntu/.pi/agent/worktrees/pi-goals-persistent-steward`, branch `feature/persistent-steward`.
- Supervisor: `/home/ubuntu/.pi/agent/worktrees/pi-intercom-supervisor-goals-integration`, branch `feature/pi-goals-integration`.
- State: automated default-on validation passes 48 goals tests; one live supervised goal accepted. Full Herdr UAT remains open, including an apparently stale unresolved-write cleanup blocker. User authorized companion-package settings and feature-branch commit/push; no npm release.
- Manual lost-pane recovery remains explicit. The managed pi-goals lockfile, APC files and personal journals were not edited. No council or automatic phase-model switching.
<!-- Plan and final evidence read by Pi. -->
@@ -0,0 +1,138 @@
# One package, remembered role models, and conversational plan alignment
The user wants supervision inside pi-goals, with a separate remembered model choice for planning,
working and supervising. This replaces the three-extension installation described in the earlier
integration plan. Two follow-up requests require default alignment questions and a clear return to
normal chat from review; the parent supplied these approved additions during implementation.
## User-visible result
Install only pi-goals, discuss a plan and select Ready to open its real supervisor. Each role restores
its last explicitly selected provider/model. Planning asks at least three task-specific alignment
questions by default. Discuss returns the review menu to ordinary conversation without an editor or
an immediately recurring menu; Ready remains the sole handoff to work.
## User voice
- > did you do the part where the last model choice in plan ,vs worker vs supervisor mode is sticky?
- > ok implement. and just put it into pi-goals I guess... seems messy to have a sep package. one clean package
- > note I tried it in another window and it didn't grill me even one quesiton that is bad should be default to at least ask 3 questions to see how far apart in understanding user and agent are
- > and then I wans't sure what to press, edit? no. refine? that's a special prompt. how to go back to chat about plan and ask it to grill. should not have ot
## Goals
1. [x] goal: Install one package for planning and supervision
- scope: Move supervisor code and regression coverage into pi-goals. Bundle the existing Intercom transport through supported Pi packaging; no separate companion registration or source checkout required. Keep Herdr as the terminal host.
- failure modes: A source-checkout test hides missing packed dependencies; duplicate extension registration; lifecycle regressions during the move.
- discriminator: A packed pi-goals artifact alone supplies both real Pi sessions and completes the offline supervised-goal test. Full inherited supervisor regressions run from this repository.
- evidence: `src/internal/supervisor/` imports the implementation from `145c2cb081f85c08b0244c4a2c8a2d9aef8debda`; `THIRD_PARTY_NOTICES.md` and source attribution retain provenance/MIT notices. `package.json` bundles locked Intercom 0.10.0 and VCC 0.5.0; its manifest loads Intercom through `node_modules/`, while VCC remains a compiler rather than a loaded extension. Launch passes only the pi-goals package root. Duplicate registry diagnostics reject ambiguous plan bootstrap. `test/rpc-supervisor.test.ts` packs/extracts outside companion checkouts, runs actual Pi/Intercom and an offline fresh judge, and asserts production resources and no bundled Pi core peers. Only the worker's Herdr exec is adapted; the supervisor loads the untouched extracted manifest. Parent full validation passed 59 Vitest tests and 117 internal tests (116 inherited plus duplicate-registry coverage), zero skipped.
2. [x] goal: Restore the last model selected for each role
- scope: Remember provider/model separately for planning, worker and supervisor in user-scoped pi-goals preferences. First use inherits the current model. Preserve the separate evidence-judge override.
- failure modes: Automatic switching overwrites another role's preference; reload/fork assigns the wrong role; one process overwrites another role's choice; an unavailable model silently changes the saved preference.
- discriminator: Tests select distinct models in each role, enter/re-enter roles, reload and start another plan. Each role restores its own selection; missing models are reported without overwriting preferences.
- evidence: `src/role-models.ts` uses public `model_select` (`set`/`cycle`; ignores `restore` and guarded automatic `setModel` events). Separate atomic `planning-model.json`, `worker-model.json`, and `supervisor-model.json` files under `getAgentDir()/pi-goals` contain only provider/id. Failed authentication or lookup visibly pauses the role, preserving its saved choice. `test/role-models.test.ts` covers deterministic cycling, fresh processes and unavailable/unauthenticated models. `test/goals-flow.test.ts` covers Ready, cancellation during setModel, failed Ready, next plans, fresh-instance resume/reload and inherited supervisor isolation. `test/supervisor-integration.test.ts` proves planning model capture before worker restore, supervisor model before initial compaction, activation cancellation and judge override isolation. The packed RPC flow also verifies actual planning selection and distinct worker/supervisor/judge model IDs.
3. [x] goal: Ask useful alignment questions before the final plan
- scope: Default to at least three distinct task-specific questions in one chat round, about expected result, scope/constraints and success/failure criteria. Resolve technical facts read-only. Wait for answers and use them. Only an explicit current-objective no/skip-questions instruction waives the default.
- failure modes: Generic ritual questions; questions skipped merely because the agent thinks it understands; an old waiver leaking into a new plan.
- discriminator: Prompt and flow regressions require the default, persist the current-plan waiver across resync, reset it on a new plan, and keep the final-review menu closed until review is requested.
- evidence: `src/prompts.ts` defines the default and current-plan policy; `src/index.ts` persists `questionsWaived` per plan. Prompt and flow tests cover default/waiver/next-plan behavior. The deterministic real-Pi `test/rpc-review.test.ts` asks questions before the first review, accepts chat answers, and reaches Ready. This validates protocol/control flow, not semantic question quality from every live model; no semantic question-count framework was added.
4. [x] goal: Return to ordinary plan chat from review
- scope: Ready / Discuss / Edit / Cancel. Discuss preserves the draft and planning role, asks useful questions in chat, and supports multiple answer turns without another modal. Escape also preserves the draft and returns to chat. Edit remains direct editing; explicit Cancel discards the draft.
- failure modes: Refine-notes editor persists under a renamed button; unchanged drafts immediately reopen the menu; discussion is lost on reload; another approval gate starts work.
- discriminator: Discuss -> multiple chat turns without a menu -> completed discussion -> review again (including unchanged draft) -> exactly one Ready handoff. Reload retains discussion state.
- evidence: Planning-only `RequestPlanReview` is the unambiguous signal to offer review; it does not approve work. New plans and Discuss set persisted `reviewRequested: false`. `test/goals-flow.test.ts` proves unchanged-draft re-review and reload. `test/rpc-review.test.ts` uses real Pi select/chat events and asserts no Discuss editor or premature menu. Ready still exclusively starts work.
## Log
Final parent acceptance: [saved validation and review disposition](../../reviews/2026-09-07_single-package-role-models.md). All four review findings and the recovery-cancellation correction passed the targeted recheck (`No issues found.`, `Merge verdict: OK`). Final tests: 67 Vitest and 118 internal tests, no skips. The package-list migration is complete; existing workers need reload before another Ready attempt.
## Verification
Initial (pre-review-fix) parent unsandboxed checkpoint validation, read back from
`/tmp/pi-goals-single-package-parent-validation.log`:
```text
npm test
Test Files 12 passed (12)
Tests 59 passed (59)
internal node:test: tests 117, pass 117, fail 0, skipped 0
npm run typecheck: passed
npm run lint: Checked 32 files. No fixes applied.
npm run build: passed
git diff --check: passed
SINGLE_PACKAGE_PARENT_VALIDATION_PASSED
```
The full test includes production `npm pack` and the real broker/offline supervised flow, without an
optional integration flag or companion checkout. Worker-local validation independently passes 58
non-broker Vitest tests and all 117 internal regressions, plus typecheck/lint/build. Worker full
`npm test` fails only at Intercom startup: a minimal Unix `net.listen()` also returns `EPERM` in this
sandbox. The parent ran the unchanged enabled test outside that restriction and passed it. Do not
confuse the worker environment limitation with a skipped test or a product pass claim.
`tsconfig.build.json` maps only the four used source-only VCC API surfaces to narrow declarations,
because VCC 0.5.0 has upstream Pi-message/Intl type incompatibilities. Pi-goals source remains fully
typechecked/linted; tests execute the actual pinned VCC implementation. The inherited `node:test`
suite has its own package script and is not silently collected or skipped by Vitest.
Final production tarball, file listing, tracked-plus-new-source diff, source copies, status and
validation logs are saved under `/tmp/pi-goals-single-package-review/` for read-only review. No files
are staged. Fresh review and the targeted recheck are complete; parent acceptance is recorded above.
## Accepted review findings and narrow fixes
Parent accepted all four findings in `single-package-review-recovery.md`; the source was frozen
again for unsandboxed validation after this targeted pass:
1. **Stop while a model is unavailable:** the validated `stop` control-plane operation bypasses
model readiness, while binding/channel checks and peer notification remain. AbortSignal review
cancellation also works during the pause. Directives are ignored for paused/inactive or stopped
workers. New actual-module clear/off tests and the internal wrong-binding/abort/stop regression
prove that the old pair cannot revive work.
2. **Restore before activation and recover the right role:** Ready captures/attaches the planning
fork, persists a pending worker recovery target, restores the worker model, then activates and
hands off. Missing lookup/authentication returns to the review UI without activation or a
supervisor review turn. The persisted recovery target remains worker across reload; an explicit
selection writes worker-model.json, not planning-model.json. Both failure paths have supervised
integration regressions; successful recovery reuses the existing fork and hands off once.
3. **Affirmative waivers only:** a small clause recognizer accepts explicit affirmative current-plan
instructions including `no q's` and `skip q's`, but not `do not skip questions`, quoted feature
names, or embedded quoted clauses. No general NLP parser or semantic question-count gate was added.
4. **Already-current model recovery:** `/goals model current` explicitly authenticates and saves the
current model for the paused role. It does not depend on model_select, which Pi suppresses for
an unchanged model. It is never automatic and does nothing if no role is paused. Unit tests
cover failed authentication without preference replacement; real-Pi RPC proves that same-model
selection alone cannot recover, then the explicit command safely recovers and Ready starts once.
The parent identified one cancellation gap in the initial repair: the recovery restore await was
outside Ready's controller/version ownership. It is now inside the captured lifetime/controller and
plan version/hash checks, before any launch call. Deferred recovery -> clear and -> replacement
regressions prove zero additional startup/activation/handoff and preserve the new/null state.
Worker validation on the final fix source: 66 non-broker Vitest tests and 118 internal supervisor tests pass;
`npm run typecheck`, lint (32 files), build and diff checks pass. Worker full `npm test` still fails
only at actual Intercom startup under the same sandbox Unix-socket EPERM limitation. The enabled
packed test has not been skipped or replaced. Parent unsandboxed validation of the four-fix checkpoint passed 65/65 Vitest and 118/118 internal
tests, zero skipped, plus typecheck/lint/build/diff checks; see
`/tmp/pi-goals-single-package-fixed-validation.log`, ending `SINGLE_PACKAGE_FIX_VALIDATION_PASSED`.
That full run predates the final recovery-await cancellation correction and two extra local tests.
Final parent unsandboxed validation of that correction has now passed **67/67 Vitest tests in 12
files and 118/118 internal tests, zero skipped**, plus typecheck, lint (32 files), build and diffcheck.
The read-back log is `/tmp/pi-goals-single-package-final-validation.log`, ending
`SINGLE_PACKAGE_FINAL_VALIDATION_PASSED`. Parent's targeted review subsequently returned `No issues found.` and `Merge verdict: OK`; all named fixes and their immediate regressions were checked.
Fresh complete snapshots are at `/tmp/pi-goals-single-package-fix-review/`, including a fix-only
delta against the previous review snapshot as well as the full tracked-plus-new-source diff. The
normal three-role/Discuss/RequestPlanReview flow is unchanged, and no extra normal-path approval
gate, IPC/package redesign, global setting edit, or legacy orphaned-write fix was made.
## Boundaries and remaining limits
- Sole writer in the goals worktree on `feature/persistent-steward`, based on `8e44738`; the supervisor source checkout was read-only. No commit/push/publish or global settings/auth edits.
- Only pi-goals is loaded after migration. Parent reports that the old standalone supervisor/Intercom global registrations have now been removed; existing workers remain instructed to wait for validated reload/retry guidance before Ready. Old worker code can otherwise launch old `-e` companion arguments. No panes were controlled here.
- Herdr remains the supported host. Automated tests mock its exec adapter; live navigation/rendering/recovery and measured token savings are not established by this change.
- Native fork/compaction, SUPERVISOR.md precedence, incremental VCC memory, correlated review/cancellation/recovery and default-on policy remain. The fresh evidence judge stays separate.
- The previous live trial's apparently stale unresolved-write `done` failure remains pre-existing and undiagnosed, as recorded in `docs/reviews/2026-09-07_supervisor-validation.md`. Outstanding-work safeguards were not weakened and cleanup is not claimed fixed.
- Role files avoid cross-role lost updates; concurrent explicit choices within the same role are intentionally last-write-wins. No thinking-level preferences or credentials are stored.
<!-- Implementation and parent-observed validation by Pi. -->
@@ -0,0 +1,239 @@
# Simple, visible supervision
Approved for implementation by the user, superseding the earlier draft and its open questions. Work is based on tested checkpoint `d5729ac`, in the isolated `feature/simple-visible-supervision` worktree. User intent is recorded in [AGENTS.md](../../../AGENTS.md). Approval is not a claim that live acceptance has passed.
## User-visible result
One pi-goals package runs the same Pi profile/package set in a worker pane and a real visible supervisor pane. The supervisor retains planning context, repeatedly sees its role and the canonical plan, and gives brief useful assessments and advice. Reliability and fewer layers take priority over new orchestration.
## User voice
- > yeah use intercom not RPC
- > in the other one we 1) fork the main proc 2) compact. then the supervisor has a) a repeated loop stating it is the supervisor and the plan, and it also has the compacted session. we compact at >100k to keep it cheap
- > we should just be able to run the same pi profile but activate supervisor mode
- > yes but also it needs to be simple it's constantly breaking and the supervisor needs to actually offer advice and perspective not just fill forms
- All worker-Pi / supervisor-Pi communication must use pi-intercom. Direct controller calls are only ordinary module composition inside one process.
## Approved goals and current evidence
1. [/] goal: Start and recover supervision using one Pi profile
- scope: Ready forks the planning session, activates supervisor mode in a real Herdr pane, and compacts the fork. Reuse the same agent directory and resource choices. One Intercom registration per process, including profiles with Intercom already installed. Remove the generic plan-lifecycle RPC dispatcher; lifecycle stays directly in pi-goals.
- implemented: Removed `plan-api.ts`, `pi-supervise:plan:v1`, its request envelope and generic dispatcher. pi-goals owns a typed local controller; peer messages remain on Intercom. Herdr launch passes the current Pi agent directory, preserves explicit resource choices, and adds no companion extension. Recovery reuses the recorded session/pane rather than spawning a duplicate because a location is unavailable.
- evidence: `test/supervisor-integration.test.ts` checks native session-fork capture, Ready/model ordering, cancellation and two goals with the fresh judge. Real installed-Pi packed-artifact tests in `test/intercom-registration.test.ts` passed bundled-only, Intercom-before-goals and Intercom-after-goals, including native reload: one channel registration, one Intercom tool, unchanged tool sets.
- live evidence: The user disabled the host sandbox. The complete packed peer flow now passes. Ready created one real supervisor fork; reloading that same pane recovered the initial native-compaction no-op failure without another fork. Both panes subsequently reloaded and retained their relationship. Detailed observations and limitations are in the live-UAT log below.
2. [/] goal: Give visible, context-aware advice in the retained supervisor loop
- scope: Repeatedly supply the supervisor role and current canonical plan, preserve compacted planning context and incremental VCC views/judgments, compact again above 100k current-context tokens subject to the model limit. Show the actual assessment/advice. Keep the fresh evidence judge; plan-bound asynchronous checkpoint identity/freshness is code-owned, not a model-filled form.
- implemented: Each model call receives the role/current plan alongside retained context. Routine prompts request useful visible assessment/perspective; steering and no-intervention assessments display their actual content as durable messages. `review_goal` takes only decision/reason; its verdict must match the checkpoint actually presented to that model call. Transport messages carry plan binding; disconnection invalidates pending checkpoints and is shown rather than treated as approval/delivery.
- evidence: Supervisor regressions verify retained compaction context/judgments, canonical-plan refresh, visible actual advice, delayed verdict rejection after checkpoint replacement, changed-plan rejection, two-goal persistence, and >100k current context versus cumulative usage/exactly 100k, including compaction deferred until a busy supervisor settles. Existing small-fork behavior is retained: known context at most 20k skips unnecessary initial compaction; unknown usage does not skip it.
- cadence: One worker-owned cadence: 50 completed model turns OR 60 minutes OR genuinely settled with no tracked work. After explicit supervisor approval of a discovered baseline gap, absent optional tracking tools count as zero tracked work; installed trackers with failed/malformed status remain unknown. Tests cover absent, busy, malformed/mixed providers and coalesced settled reviews. Detached/unregistered work is still explicitly untracked.
- live evidence: The supervisor caught missing finite-result protection, an ineffective overflow test, and missing CLI overflow evidence. The worker corrected the function/tests but later acknowledged hand-written demo output. The stale checkpoint view, empty-response stall and false human-wait latch are fixed and reviewed with regressions; the final fixes have not been retried in the live pair. Final role usage is recorded below. This debugging trial has no worker-alone control and does not establish savings.
3. [/] goal: Keep supervisor mode inspection-only, including recovery
- scope: Block direct writes/bash and indirect process/subagent/scheduler/unknown mutation routes at both visibility and execution. Allow native inspection and narrowly owned supervisor steering/state only. Restore restrictions before model work and retain them in stopped plan forks.
- implemented: Replaced writer-name denylist with native read/grep/find/ls plus application-owned supervisor tools. Enforce `tool_call` and `user_bash` gates; restored supervisor state and bootstrap markers reapply restrictions on reload. No arbitrary filesystem-note writer was added.
- evidence: Tests cover hidden tools, re-enabled forbidden tools still blocked at execution, process/subagent/scheduler/Intercom/unknown routes, native read permitted, user bash rejected, and reload/stopped-fork restrictions. Registered tool provenance prevents a custom tool merely named `read` being treated as native inspection.
- live evidence: The supervisor's native `!printf EXECUTION_SHOULD_BE_BLOCKED_42` probe was rejected after reload: “Supervisor mode is inspection-only. Run commands in the worker pane.” A stopped-fork live check remains pending. This is a model-tool restriction, not an OS sandbox for malicious trusted extension code or a human deliberately invoking another extension's slash commands.
4. [ ] goal: Validate the installed artifact and real visible Herdr workflow honestly
- scope: Full tests, typecheck, lint, build, packed artifact checks and bounded real Herdr UAT: fork/compaction, visible assessment/steering, reload/recovery, two goals, stop, no duplicate tools. Use only dedicated test fixtures/panes; no active-profile replacement. RPC is a deterministic test harness only.
- evidence: Full `npm test` ran: 71 Vitest tests passed, one packed Intercom peer-flow test failed at broker connection. Separate `npm run test:supervisor` passed 128 tests. `npm run test:rpc`, typecheck, lint, build, diff checks passed. The explicit diagnostic run excluding the environment-blocked peer-flow file passed 71 tests; this does not make full `npm test` green. Packed content checks passed with Intercom/VCC present, removed `plan-api.ts` absent, core peers excluded, and one manifest extension entry. Real installed-Pi registration/reload tests passed without requiring a model call.
- blocker: `HERDR_ENV=1`, but `herdr workspace list` returned OS `PermissionDenied: Operation not permitted`. A fresh `/tmp` Unix-socket listen probe returned `listen EPERM`. Parent confirmed the same host-control restriction. Herdr control stopped before creating panes/workspaces; no auth/host workaround was attempted.
- current status: The host blocker above is historical and resolved for the parent. Final full validation passed 81 Vitest and 171 supervisor tests, plus typecheck/lint/build; targeted independent review approved the final fixes. The bounded Herdr trial is stopped and all three temporary role preferences restored. Goal one was accepted under the existing inconclusive-judge policy, not conclusively verified; goal two remains unsigned. The user requested commit/push of the latest changes with these live-UAT gaps retained.
## Preserved policies
- The fresh read-only evidence judge remains mandatory in the existing CompleteGoal path; existing inconclusive-judge semantics are unchanged.
- Sticky planning/worker/supervisor models and explicit auth recovery; three-question planning; ordinary-chat Discuss; Ready as sole human start approval; no-dash commands; SUPERVISOR.md precedence; plan/history retention.
- One goal's approval does not end supervision. Existing overall `done` / explicit stop behavior remains; stop leaves the pane and history available. A disconnected stop reports local success and unconfirmed peer delivery instead of claiming the remote session stopped.
- No new mailbox, orchestration framework, dependency upgrade, release or active-profile replacement. The user subsequently authorized commit/push after live testing. Only the three non-secret role preferences may be temporarily changed for the trial, with guarded restoration; no unrelated global settings edits.
## Log
### 2026-09-08 — Implementation and permitted validation
Exact worktree: `/home/ubuntu/.pi/agent/worktrees/pi-goals-simple-visible-supervision`.
Exact logs and packed artifact: `/tmp/pi-goals-simple-visible-evidence/`. Durable handoff copies are under the implementation output's sibling `validation/` directory. Primary logs:
- `final-command-status.log`
- `final-npm-test.log` — full suite, **not passed**
- `final-npm-run-test-supervisor.log` — 128 passed
- `final-npm-run-test-rpc.log` — deterministic conversational review passed
- `final-permitted-vitest.log` — 71 passed, explicit diagnostic exclusion only
- `final-npm-run-typecheck.log`, `final-npm-run-lint.log`, `final-npm-run-build.log`
- `registration-reload.log` — real installed-Pi packed registration and reload in three load orders
- `npm-pack.json`, `packed-artifact-check.log`
- `herdr-access.log`, `unix-socket-probe.log` — exact environment blockers
Read the installed Pi extension, session, session-format, compaction, package, TUI, environment and CLI-usage documentation, plus the relevant event-bus/compaction examples, public session-manager declarations and Intercom extension-channel contract. The implementation uses public extension/session APIs, not private runtime state.
The original plan's sign-off question is resolved: preserve the fresh judge. No authenticated model pair or spending was selected here because host UAT was blocked before that stage. Actual costs and token benefit remain unavailable, not zero or inferred from protocol tests.
### 2026-09-08 — Accepted review fixes and slow-supervisor robustness follow-up
The parent accepted two concrete review findings: retained non-plan peer reload recovery and missing
Pi `-ne` / `-ns` / `-np` aliases. Both now have saved red/green regressions. Recovery requires validated,
addressed traffic from the currently paired peer; arbitrary joins, wrong recipients and unrelated plan
bindings do not restore connectivity. Short/long resource options now produce equivalent production
launch arguments.
The user then explicitly required slow-supervisor fixes, not characterization-only gaps. The approved
minimal direction uses one active assessment, a pending dirty marker and one existing Intercom look/view
refresh in flight, without cursor acknowledgements or a new queue runtime. Busy-time incremental updates
do not replace the active view or enqueue model turns. After settling, the worker rebuilds a bounded VCC
overview from its latest compaction summary and current branch. Progress arriving during that refresh
remains pending. Explicit checkpoints and the canonical plan are separate from replaceable routine
status. Overview truncation is visible and includes a read-only source-session reference.
The arbitrary ten-minute supervisor model-review deadline has been removed. Finite transport startup
and attachment waits remain separate. Healthy long reviews can succeed; explicit cancellation, changed
plans, disconnects and genuine settled provider failures still fail safely without a replacement pair
or fork. A native automatic retry is not mistaken for a final provider failure. Routine review is paused
when waiting for a user decision, and stale active views cannot end supervision while newer work awaits
an overview.
Latest validation: `npm test` ran with **73 passed, one environment-blocked Intercom peer-flow failure**;
`npm run test:supervisor` passed **141 tests**. Typecheck, lint, build and deterministic RPC review passed.
The explicit permitted Vitest subset passed 73 tests. An earlier full run also hit the unchanged role-model
subprocess test's five-second timeout; its log is retained, and both the subsequent full run and isolated
role-model test passed without relaxing that timeout.
Exact follow-up logs, red/green evidence, final packed artifact and the lightweight usage extractor are
under the implementation output's `validation/review-fixes/` directory (latest suite logs in `final/`).
The extractor is `extract-trial-usage.mjs`: capture the worker boundary before Ready, then read both real
trial session files after settling. It separates input/output/cache-read/cache-write, excludes inherited
planning history and duplicate entries, includes recorded compaction usage and labels missing compaction
or fresh-judge usage as instrumentation gaps. Its validation used synthetic fixtures only; these are not
live token measurements. Current-context compaction thresholds are separate from cumulative recorded token totals.
Herdr control and Unix sockets still return PermissionDenied/EPERM. No actual Herdr trial, live per-role
usage, cost or savings evidence is claimed; authorized host UAT and reviewer recheck remain required.
### 2026-09-08 — Accepted liveness review corrections
The next read-only review identified two concrete refresh/compaction liveness races and a usage-report
label error. Scope stayed limited to those accepted findings. A worker now retains a full-overview
request and its evidence cursor until publication succeeds; failure does not recursively retry from
`finally`. Routine progress/cadence or explicit `/supervise look` can retry. View model/context display
uses native local context rather than a mandatory remote roster lookup. Existing addressed-peer,
plan-binding and stopped checks remain, with generation checks on suspended publication.
An obsolete advance awaiting compaction now releases its single-advance guard and re-drives only
actual current-generation pending work. Deferred old compaction success or rejection cannot strand
a new checkpoint after valid reconnect, fail that new checkpoint as obsolete, or restart stopped work.
No model timeout, queue runtime or additional pair/fork was added.
Saved red/green checks cover publication failure with routine and explicit recovery, nonfatal roster
unavailability, and deferred compaction success/rejection. Two further stop regressions cover both
completion orderings. Latest supervisor suite: **148/148 passed**. Full `npm test`: **73 passed,
one failed** at packed Intercom broker startup; the complete peer flow remains unpassed. Typecheck,
lint, build, deterministic RPC review, the explicit 73-test permitted subset, packed content checks and
all three real-Pi registration/reload load orders passed. Herdr still returns PermissionDenied, and a
fresh Unix socket probe returns EPERM. No live pane or authenticated usage proof is claimed.
The artifact-only usage extractor now labels counters `entries`, not provider calls: one persisted
compaction or nested-tool entry can aggregate multiple calls. Token components, missing usage/pricing
and judge instrumentation caveats remain separate. Its corrected assertions passed synthetic fixtures
only. Exact new logs, pre-edit snapshots, packed artifact and follow-up-only diff are in the
implementation output's `validation/review-fixes/liveness/` directory. Earlier logs remain historical;
independent reviewer recheck and authorized host acceptance are still pending.
### 2026-09-08 — Actual Herdr trial, in progress
The user disabled the sandbox and requested live testing before the authorized commit/push. Parent
host access and the full packed Intercom flow now work. The revived child retained its old sandbox;
no bypass was attempted. The parent operates the trial directly.
Fixture: `/tmp/pi-goals-herdr-uat.TGXaEL`. Worker `goals-uat-worker` (`w1:pE`) and Ready-created
supervisor `supervisor-9a775b1a` (`w1:pF`) use the extracted package and the normal agent directory,
with bundled-only extension loading. This is not a live test of every globally installed extension
combination. Planning/supervisor use `github-copilot/gpt-6-astra`; the worker requests
`github-copilot/claude-haiku-4.5` and reports `claude-haiku-4-5-20251001` in usage records.
Observed so far:
- Three alignment questions, ordinary-chat Discuss, final Ready, and the native fork were exercised.
- Initial compaction returned `Nothing to compact (session too small)` despite measured context above
20k. The exact initial no-op now retains the fork; genuine errors still fail. Reloading the same
supervisor completed startup. Later both panes reloaded without another fork.
- Supervisor advice caused finite-result protection and an effective overflow regression to be added.
It respected the required pause before the CLI goal. Native user bash was blocked after reload.
- Premature worker checkboxes and valid numbered judge checks exposed two completion defects. The
submitted goal is now reopened before review, and the checks parser accepts numbered/indented lists
only inside its checks section. These fixes passed independent review and red/green regressions.
- The [pre-checkpoint-fix full test log](../../reviews/evidence/2026-09-08-visible-supervision/pre-checkpoint-fix-tests.log)
records `Tests 81 passed (81)` and ` pass 150`; typecheck, lint and build also passed.
- Goal one's latest [actual receipt](../../reviews/evidence/2026-09-08-visible-supervision/completion-receipts-observed.json)
says `Judge returned no VERDICT line. Accepted inconclusive — logged.` It is not conclusive verification.
- Manual supervisor compaction persisted a [native record](../../reviews/evidence/2026-09-08-visible-supervision/observed-supervisor-actions.json)
with `tokensBefore: 43242` and 15,291 recorded tokens. The [Herdr observer](../../reviews/evidence/2026-09-08-visible-supervision/manual-compaction-result.json)
nevertheless returned `agent_prompt_stalled`. The native record, not that observer status, proves
compaction occurred. Its summary covers the older prefix; recent work remains in the retained suffix.
The automatic >100k threshold has unit coverage, not a real threshold-crossing trial.
- After explicit operator authorization, the worker built the CLI. The supervisor caught a missing
CLI overflow test/demo, which the worker added. However, its cached view still showed the old pause.
A subsequent empty final response left the completion request waiting. The operator cancelled the
request and paused the worker. A focused writer/reviewer round is correcting checkpoint freshness
and genuinely settled empty-response handling; no thinking deadline or new queue is being added.
[Interim usage](../../reviews/evidence/2026-09-08-visible-supervision/trial-usage-interim.json), captured before
manual compaction and the CLI work, records worker 1,369,570 tokens (19,409 output; 31 entries) and
supervisor 488,408 tokens (1,065 output; 15 entries). Inherited planning is excluded. Cache components
are separate in the artifact. Entries are not provider calls. Judge usage is unrecorded; supervisor
zero/missing pricing does not mean free use. This includes debugging, retries and reloads, has no
worker-alone control, and supports no savings claim. Final usage, stop checks, guarded role-preference
restoration, final validation and publication remain pending.
Recorded by Pi (OpenAI) from the observed trial artifacts; the section above records the trial before its publication checkpoint.
### 2026-09-08 — Publication checkpoint requested by the user
The user requested “commit and push latest”, then clarified “supervisor is waiting? it's job is not wait”.
The final correction removes the failure-to-human-wait latch: empty/incomplete assessments and provider
failures do not block later ordinary worker progress/cadence. Stale refresh flags are cleared to avoid
an immediate same-input retry loop. Explicit human dependencies remain separate. The two regression
cases failed [red](../../reviews/evidence/2026-09-08-visible-supervision/wait-latch-red.log) with
`ordinary worker progress must resume supervision without user input`, then passed
[green](../../reviews/evidence/2026-09-08-visible-supervision/wait-latch-green.log).
Fresh snapshots now travel on the existing Intercom checkpoint message, with the latest user direction
retained within the bounded overview. The snapshot is promoted only when its checkpoint becomes active;
replies carry identity/verdict, not a copy of the snapshot. Cancellation, changed plans, generation/session
identity and serialized 16 KiB limits are checked. The historical replay is not a live acceptance test.
The [independent targeted review](../../reviews/2026-09-08_checkpoint-review.md) reports “No issues found.”
Final parent-run evidence (committed log copies normalize trailing whitespace only; originals remain in the fixture):
- [npm test](../../reviews/evidence/2026-09-08-visible-supervision/publish-npm-test.log):
`Tests 81 passed (81)`, ` tests 171`, ` pass 171`, ` fail 0`.
- [Typecheck](../../reviews/evidence/2026-09-08-visible-supervision/publish-typecheck.log),
[lint](../../reviews/evidence/2026-09-08-visible-supervision/publish-lint.log) and
[build](../../reviews/evidence/2026-09-08-visible-supervision/publish-build.log) all exited successfully;
`git diff --check` passed.
- The [worker](../../reviews/evidence/2026-09-08-visible-supervision/worker-stopped.txt) shows
`Persistent plan steward disabled.` and 1/2 goals. The
[supervisor](../../reviews/evidence/2026-09-08-visible-supervision/supervisor-stopped.txt) shows
`Plan supervision stopped`. Auto-continue was disabled too. Panes/history are retained.
- [Guarded restoration](../../reviews/evidence/2026-09-08-visible-supervision/role-preferences-restored.log)
reports `Restored prior state` for all three role preference files. No active-installation replacement.
The worker's final acknowledgement says the CLI demo log was hand-written rather than captured from
actual runs, and reports temporary files outside the fixture. Those are trial failures, not accepted
evidence. Goal two remains unsigned; its demonstrations still need actual execution. The latest
checkpoint/latch fixes have not been reloaded and retried in the live pair. The stopped-fork execution
gate and automatic >100k threshold retain unit coverage, not a new live test here.
[Final recorded role usage](../../reviews/evidence/2026-09-08-visible-supervision/trial-usage-final.json),
after explicit stop, excludes inherited planning:
- Worker: 4,249,544 tokens across 68 entries: input 427, output 39,611, cache read 3,479,071,
cache write 730,435.
- Supervisor: 1,525,606 tokens across 42 entries: input 129, output 5,035, cache read 1,097,576,
cache write 422,866. This includes the one 15,291-token native compaction record.
The [extractor](../../reviews/evidence/2026-09-08-visible-supervision/extract-trial-usage.mjs) separates
assistant, compaction and nested usage; entries are not calls. Original session files remain local,
not committed. Fresh-judge usage and parent/development-agent overhead are not included. Supervisor
pricing is unrecorded/zero, and the worker's positive cost subtotal is incomplete. There is no reliable
total cost or savings claim. This is a debugging trial with retries/reloads and an unfinished second goal,
not a clean efficiency benchmark.
Recorded by Pi (OpenAI); publication does not signify complete live acceptance.
@@ -0,0 +1,33 @@
# Autonomous supervision and two-goal acceptance
User requested the other branch's better instructions, manual-checkmark handling, and a completed real trial. Keep the current reliability base and VCC. Do not import Git cleanliness, commit, or ignored-output approval gates.
- [ ] goal: Keep useful supervision running without invented human waits
- Adopt the latest `565b272` prompt structure: stage-specific check-ins, outcome-first tool guidance, a clear distinction between recap and sent instruction, applicable AGENTS/skills, and short review context versus full orientation. Keep current-plan freshness and checkpoint evidence.
- Preserve the earlier adopted behavior: investigate blockers, change ineffective steering, keep authorized independent work moving, inspect the result, and give brief visible judgments.
- Take the new VCC adapter safeguards: separate budgets for extracted context/recent actions, partial-call handling, and explicit omitted-result/reference notices. Keep the current recovery and coalescing implementation.
- Remove the assumption that ordinary prose without a verdict tool means a human decision is needed. New worker direction must reach the supervisor even after a real question.
- failure modes: normal prose silently stops reviews; alternatively, failure causes an immediate retry loop or the supervisor ignores an explicit user pause.
- deliverable: focused regressions for ordinary prose, empty/error responses, subsequent worker updates, genuine user pauses and no idle loop.
- [ ] goal: Treat manual completion marks as claims while retaining artifact-based review
- Keep unsigned manual `[x]` claims visible and supervised, including reload. CompleteGoal remains the sign-off path; preserve independent judge policy and current plan identity/cancellation protections.
- Git status is review context, not an acceptance gate. Ignored output files may be evidence. Do not force commits or cleanup.
- failure modes: a manual tick ends supervision; dirty/ignored artifacts are rejected merely due to Git status; legitimate signed-off goals reopen on reload.
- deliverable: widget/lifecycle/sign-off regressions, including dirty worktree and ignored-output cases.
- [ ] goal: Finish a real two-goal workflow with the chosen implementation
- Carry relevant user preferences and the other branch's actual-Herdr testing procedure into AGENTS.md. Ask material questions, not a quota; retain ordinary-chat Discuss.
- Run the functional trial with full normal Pi profiles, isolating only candidate pi-goals selection, and different worker/supervisor models. Inspect both panes and actual artifacts; do not substitute bundled-only loading or test counts for acceptance.
- Exercise worker/supervisor/both reloads, fresh-shell resume, drafting/Discuss, Ready/startup, pending completion and stopped sessions. Preserve plan/role/peer; interrupted decisions need a visible retry path, not stale acceptance, duplicate panes or a permanent wait.
- Diagnose failures from exact logs, fix them and retry; after prompt changes use a fresh task. Do not do the worker's artifact work for it.
- failure modes: only unit tests pass; one goal is left unsigned; fabricated logs pass as execution; operator repairs are described as autonomous success.
- deliverable: saved logs and pane evidence of both CompleteGoal results, actual output verification, interventions, remaining limitations, and separate role usage.
## UAT / Verification
- Success: both artifacts match the task, real verification output exists, both sign-offs are observed, and the same pair remains active between goals.
- Likely failure: startup/reload/approval stalls. Read both panes and the error, repair the cause, then repeat that stage.
- Sneaky failure: manual checkmarks or handwritten output appear complete. Inspect the underlying artifact and actual execution record, not just the widget or worker summary.
- Include an ignored output directory and preserved unrelated dirty file; neither should force a commit or block valid completion.
- Keep original sessions/settings untouched. Temporary changes to the three non-secret role preferences require guarded restoration. No release, merge, or active-installation replacement.
Recorded by Pi (OpenAI). [Earlier implementation validation](../../reviews/2026-09-09_autonomy-validation.md) remains a source check, not functional acceptance. The user has since disabled the sandbox and authorized the latest prompt/VCC adoption. pi-subagents was upgraded from 0.62.0 to 0.66.0 with a command-only release-age exception; other direct package versions and the default policy were unchanged. After reload, prioritize the real two-goal trial. Review suggestions for the other branch are posted in [issue #6](https://github.com/wassname/pi-goals/issues/6).
@@ -0,0 +1,39 @@
# Persistent plan steward
Historical snapshot of the replaced checkpoint-review implementation. The user's clarified objective and proposed real-session supervisor workflow are captured in [Plan-aware persistent supervisor (2026-09-07)](2026-09-07_plan-supervisor.md); the current branch implements that newer composition, with validation limitations recorded in its plan.
## Purpose
Add judgement across a plan without weakening the fresh evidence check. The steward checks intent,
trajectory, goal ordering, and scope. `CompleteGoal`'s fresh judge continues to check artifacts.
## Lifecycle
1. The human opts in with `/goals steward on`.
2. Ready forks one non-writing `oracle` through the public `pi-subagents` RPC. Work does not start
until it returns `approve`.
3. The child process exits. Pi-subagents retains its session and run identity; no model or process
remains active between checkpoints.
4. The first `CompleteGoal` call resumes the same child with bounded approved/current contract views
and the proposed goal. Checkbox state is normalized and evidence detail is omitted because the fresh
judge owns it. The steward checks contract fidelity and whether sign-off is timely.
5. `approve` creates a one-use approval bound to the goal and current working-set hash. The next
`CompleteGoal` call consumes it and runs the existing fresh evidence judge.
6. `revise_plan`, `needs_user`, an invalid response, or a failed child never signs off the goal.
## Authority
The steward's contract forbids edits, goal completion, detailed evidence assessment, and answers to
unresolved human choices. The builtin Oracle retains inspection-only bash; pi-goals rejects a review
when pi-subagents reports a file-mutation effect, but this is not an OS sandbox. Structured decisions
are `approve`, `revise_plan`, and `needs_user`. An `approve` carrying drift or unresolved decisions is
downgraded. A separate fresh judge remains the only evidence sign-off path.
## Integration
Pi-goals uses the process-local `subagents:rpc:v1` event API. Initial execution is async `spawn` with
`context: fork`; later checks use `resume`. The current run id and approved working set persist in the
existing `pi-goals-state` session entry. `pi-intercom` is not involved.
The feature is opt-in and has no hard package dependency. If pi-subagents is absent, RPC startup
fails visibly and the plan remains in planning mode until the user retries or turns the steward off.
+73
View File
@@ -0,0 +1,73 @@
# Plan-aware persistent supervisor
Status: user-confirmed intent and package composition, approved 2026-09-07. The composition is implemented in the two feature worktrees. [Final validation and trial instructions](../reviews/2026-09-07_supervisor-validation.md) record passing enabled suites and real Pi/Intercom integration. Live Herdr UAT and token-saving measurements remain open in [the branch plan](../slop/plans/20260907_plan-supervisor-integration.md).
This updates the direction of [the persistent-steward branch](2026-09-03_persistent-plan-steward.md). That earlier document is a historical snapshot of the replaced checkpoint reviewer.
## User's goal
> the idea is that the supervisor agent can use less tokens, and keep track of the overall goals, keeping the work on trck, and using it's judgment and context to steer or sign off.
The worker carries detailed investigation and implementation context. The supervisor retains the overall goals, user intent, decisions, and enough progress information to judge the direction of the work. It spends its tokens on supervision rather than following every working turn.
The intended result is lower supervisory token use while keeping work on track. A succession of approval gates is not the objective. The supervisor should remember earlier reasoning and its own interventions, recognize ineffective approaches, and steer or sign off using that context.
## Proposed workflow
The user proposed:
> make a plan
> fork this agent and compact
> so supervisor has: compacted state, plan, and supervisor prompt
1. Draft the plan with the user.
2. At the planning-to-working handoff, create a separate supervisor session from the planning session's fork. Compact it unless measured context is already at most 20k tokens; unknown size does not justify skipping. The original session remains the worker.
3. Give the supervisor the compacted planning context, actual plan, and supervisor policy from `pi-intercom-supervisor` (including the existing `SUPERVISOR.md` customization route).
4. Send incremental worker updates. Retain supervisor context between checks; inactivity need not consume model tokens.
5. Let the user open either real Pi session or see both together without manually starting and pairing the second session.
The plan and supervisor policy remain available directly after compaction. Summarization should not become the only surviving copy of the user's goals.
## Two check interfaces
Routine supervision and per-goal sign-off ask different questions.
Routine checks are proposed after 50 completed worker model turns, after 60 minutes, or when the worker settles with no outstanding processes or subagents. These are candidate defaults, not measured optimal settings. Overlapping triggers should produce one check. A busy worker making progress may need no instruction; a stopped worker with unfinished work may need a continuation or a human decision.
A goal-completion attempt is a separate explicit request identifying the goal and its evidence. Approving one goal must not end supervision of the remaining plan. The existing fresh evidence judge remains in the branch; removing it has not been approved.
Use registered background-work state where available. The existing supervisor's child-process snapshot is not a complete test for outstanding work. The idle supervisor itself must not prevent the worker from ever being considered settled.
## Context and token use
- Consider native compaction for the initial supervisor fork and later supervisor-history compaction.
- Compare native summary generation with the existing VCC compiler for incremental worker views. Reporting should not require compacting the worker each time.
- Preserve user decisions and supervisory conclusions; avoid repeatedly sending the whole worker transcript.
- Reuse the existing supervisor's retention approach where useful: recent views remain detailed, older views give way to the supervisor's verdicts.
- The user suggested supervisor compaction around 100k tokens to reduce context rot and cost. Interpret this as current context size, subject to the model's limit, rather than cumulative billed tokens. Exact policy remains to be tested.
- Planning/working model persistence was considered earlier; its settings and switching behaviour are not settled.
## Preferences
Use the simplest robust composition of existing packages and supported APIs. Candidates include `pi-intercom-supervisor`, `pi-intercom`, `pi-subagents`, `pi-messenger`, and Herdr. Mentioning a package does not approve adding it as a dependency or merging its whole codebase.
Reuse the supervisor prompt and working supervision behaviour where possible. Avoid an additional orchestration framework, council, or growing collection of mechanical review gates. Routine implementation judgement belongs to the supervisor; material choices requiring the user's knowledge or preferences still come back to the user.
Keep `/goals` subcommands without required `--` prefixes. The feature should be testable in an ordinary Pi session through this branch.
Make worker/supervisor navigation direct. The user finds Fleet hard to parse. A named supervisor pane, easy switching, and a side-by-side view are preferable to requiring navigation through a fleet dashboard. A headless-run inspector is not the same thing as the real supervisor session.
## Approved implementation qualifications
Compose the existing supervisor through narrow APIs, using native Pi sessions and Herdr panes.
Human Ready is the approval: wait for successful bootstrap and pairing, then start work once. The
initial supervisor view may steer but is not a second mandatory plan-approval gate.
A demonstrably small fork (at most 20k tokens) skips the initial compaction call and reports that fact.
Unknown size does not justify skipping; other compaction failures remain visible.
If a recorded pane is missing, locate the supervisor before reopening its saved session. Missing pane
identity is not proof of process exit. Automatic recreation or an additional confirmation UI is
deferred for the branch trial, as approved by the parent during implementation.
<!-- Written by Pi from the user's conversation; integration proposals are not implementation receipts. -->
-116
View File
@@ -1,116 +0,0 @@
# Visible supervisor handover
## Objective
Replace pi-goals' nested pi-subagents worker with two visible Pi sessions:
1. The main session plans with the user, then becomes the implementation worker.
2. On Ready, pi-goals explicitly forks the planning session into a Herdr pane.
3. Only the fork is compacted. It becomes the stronger read-only supervisor.
4. pi-supervise and pi-intercom connect the supervisor to the worker.
5. The worker starts only after the real pi-supervise `pair`/`paired` acknowledgment.
6. The supervisor retains the plan, compact planning context, and concise worker views. It can steer the worker and approve a completed goal.
7. The supervisor compacts near 100k tokens.
Keep this minimal. Reuse pi-supervise's intercom protocol instead of building a second orchestration layer.
## User preferences
- The primary session must do the implementation. Other agents may test or review it, but must not own core development.
- Avoid relaying implementation decisions through multiple agents.
- Herdr should open the supervisor automatically and let the user switch to it.
- Persist configurable models for three stages:
- planning: strongest model, for example Fable 5.1 or Astra;
- supervision: for example Sol or Opus;
- implementation: for example Terra, Sonnet, Kimi K3, DeepSeek Pro, or GLM 5.3.
- Validate model IDs through Pi. Do not hard-code a model list.
- Switch the main session to the planning model when planning starts and to the worker model only after pairing succeeds. Launch the fork with the supervisor model.
## Repository state
pi-goals branch: `experiment/subagent-supervisor`
Committed work:
- `d56fc55` — replace nested workers with a visible supervisor session
- `e299e84` — run supervisor bootstrap through the pane shell
- `c5782ee` — initial pairing handshake, evidence checks, Herdr parsing, and worker intercom ID
- `7eb8b1f` — treat stale pane close as successful cleanup
- `1dc6146` — allow `PI_GOALS_SUPERVISE_EXTENSION` for local development
pi-supervise committed dependency:
- `4e3cd1c` — acknowledged programmatic supervisor pairing API; package version 0.0.4
Uncommitted pi-goals files:
- `src/intercom.ts`
- `src/supervise.ts`
- `test/intercom.test.ts` (new)
Uncommitted pi-supervise file:
- `src/index.ts`
Inspect these diffs before editing. They are a partial design-B refactor and have not passed the real workflow.
## Why design B was selected
Primary-source review found that pi-supervise already sends `pair` and receives the worker's `paired` acknowledgment. The custom `pi-goals/visible-supervisor/v1` intercom namespace duplicated that acknowledgment and introduced another registration and connection race.
Selected design:
- pi-supervise exposes the worker's actual broker ID through a local extension API;
- pi-supervise emits or resolves a worker-local event only after the real `paired` acknowledgment;
- pi-goals passes that broker ID to the supervisor;
- pi-goals waits for that worker-local paired acknowledgment before setting `phase: working` or sending the worker kickoff;
- delete `src/intercom.ts` and custom supervisor-ready messages if the partial diff has not already completed that deletion;
- support either extension load order by using pi-intercom/pi-supervise registry-ready events idempotently.
Do not use pi-intercom `project-agent.ts` as another lifecycle. It opens a generic Pi pane and polls broker presence but does not supply the required fork, extensions, model, or pairing semantics.
## Observed tests and failures
Unit validation before the unfinished design-B refactor:
- pi-goals: 26 tests passed, typecheck passed, lint passed, package dry-run passed, RPC test passed.
- pi-supervise: 97 tests passed and package dry-run passed.
Real Herdr observations:
1. The initial smoke loaded pi-supervise directly from source and did not exercise pi-goals' actual Ready command.
2. A later actual `/goals` → Ready run failed before pane creation because pi-goals emitted `intercom:extension-register` before pi-intercom installed its listener.
3. A local uncommitted registry-ready re-registration fix moved the real path farther: Ready created supervisor pane `w8:p1F` through `supervisorCommand`.
4. That run then timed out waiting for the duplicate custom `supervisor-ready` message. This led to design B.
5. The supervisor exited before its transcript was preserved. Do not infer that pi-supervise pairing succeeded.
The real end-to-end workflow has not passed.
## Next work
1. Read the uncommitted diffs in both repositories and finish or simplify design B.
2. Add focused tests:
- pi-supervise local API works whether pi-goals loads before or after pi-supervise;
- no `phase: working` or kickoff before actual `paired`;
- duplicate `paired` is idempotent.
3. Run the actual pi-goals path, not a substitute command:
- start worker with pi-goals and pi-intercom;
- enter `/goals`, draft a plan, and select Ready;
- use `PI_GOALS_SUPERVISE_EXTENSION=/home/code/.pi/agent/git/github.com/wassname/pi-supervise/src/index.ts` until 0.0.4 is published;
- positively observe fork-only compaction, actual pairing acknowledgment, then worker kickoff;
- preserve supervisor stdout/stderr and session JSONL before cleanup on every failure;
- observe supervisor monitoring or steering;
- complete real evidence at a clean commit, approve it, call CompleteGoal, and close the pane.
4. Commit the lifecycle separately once the real path passes.
5. Add the three persisted model settings in a separate commit.
6. Run tests, typecheck, lint, package dry-runs, real RPC tests, and a fresh read-only review.
## Known packaging constraint
`src/herdr.ts` defaults to `npm:@wassname2/pi-supervise@0.0.4`. Version 0.0.4 is not publicly published. Do not publish without explicit editorial approval. Local testing must use `PI_GOALS_SUPERVISE_EXTENSION`.
## Important lifecycle bug discovered in this session
`/goals clear` cleared extension state but left the current model request under the previously injected coordinator system instruction. `/reload` did not remove it. A fresh ordinary Pi session is required for direct implementation. The redesign should avoid leaving a session unable to resume ordinary work after clear.
-- PI[gpt-5.6-sol]
+512 -588
View File
File diff suppressed because it is too large Load Diff
+27 -20
View File
@@ -1,7 +1,7 @@
{
"name": "@wassname2/pi-goals",
"version": "0.2.2",
"description": "Plan in one Pi session, then work under a visible forked supervisor.",
"description": "One plan file per session: set goals in plan mode, work them, sign off only when a read-only judge checks the evidence.",
"author": "wassname",
"license": "MIT",
"type": "module",
@@ -18,48 +18,55 @@
"proof",
"uat",
"evidence",
"supervisor",
"herdr"
"judge"
],
"peerDependencies": {
"@earendil-works/pi-coding-agent": ">=0.85.1 <1.0.0",
"@earendil-works/pi-tui": "*",
"@earendil-works/pi-coding-agent": "*",
"typebox": "*"
},
"files": [
"src",
"README.md"
"README.md",
"THIRD_PARTY_NOTICES.md"
],
"publishConfig": {
"access": "public"
},
"scripts": {
"build": "tsc",
"build": "tsc -p tsconfig.build.json",
"prepublishOnly": "npm run lint && npm run typecheck && npm run test",
"test": "vitest run",
"test": "vitest run && npm run test:supervisor",
"test:rpc": "vitest run test/rpc-review.test.ts",
"test:watch": "vitest",
"typecheck": "tsc --noEmit",
"typecheck": "tsc -p tsconfig.build.json --noEmit",
"lint": "biome check src/ test/",
"lint:fix": "biome check --fix src/ test/"
},
"dependencies": {
"@sting8k/pi-vcc": "0.5.0",
"pi-intercom": "^0.13.0"
"lint:fix": "biome check --fix src/ test/",
"test:supervisor": "node --import tsx --test test/internal-supervisor/*.test.ts"
},
"devDependencies": {
"@biomejs/biome": "^2.4.8",
"@earendil-works/pi-coding-agent": "0.85.1",
"@earendil-works/pi-tui": "^0.85.1",
"@earendil-works/pi-coding-agent": "^0.84.1",
"@types/node": "^20.0.0",
"typebox": "^1.3.7",
"typescript": "^5.0.0",
"vitest": "^4.0.18"
"@biomejs/biome": "^2.4.8",
"vitest": "^4.0.18",
"tsx": "^4.20.0"
},
"pi": {
"extensions": [
"./src/index.ts"
],
"image": "https://cdn.jsdelivr.net/gh/wassname/pi-goals@main/media/screenshot.png"
}
"image": "https://cdn.jsdelivr.net/gh/wassname/pi-goals@main/media/screenshot.png",
"skills": [
"./node_modules/pi-intercom/skills"
]
},
"dependencies": {
"@sting8k/pi-vcc": "0.5.0",
"pi-intercom": "0.10.0"
},
"bundledDependencies": [
"pi-intercom",
"@sting8k/pi-vcc"
]
}
@@ -1,31 +0,0 @@
# Goal steward validation
## Observations
- Unit, flow, type, and lint checks passed. [`20260905_validation.log`](20260905_validation.log) says:
> Test Files 8 passed (8)
> Tests 36 passed (36)
> Checked 12 files in 14ms. No fixes applied.
- A real Pi 0.85.0 process loaded pi-subagents 0.65.1, pi-goals, and a runtime `goal-steward` agent. It spawned one review and resumed that run for sign-off. [`20260905_steward-probe.json`](20260905_steward-probe.json) records two distinct run IDs:
> "runId": "4e9dc0c0-385b-4eb9-a060-ced7dc7cb6cc"
> "runId": "f6115c82-31de-499f-ab78-145dde0c51c0"
- The second review recalled a token that appeared only in the first review request. This is direct evidence that resume retained the steward conversation:
> "Persistence lineage token: amber-731."
- The sign-off review read `report.txt` and accepted the evidence:
> "file exists and contains exactly 'PROBE_PASS' as required. Failure mode (empty report) is ruled out."
## Test environment finding
The repository's older local Pi 0.84.1 install could not launch a pi-subagents background child because it did not include `@earendil-works/chord` and `@earendil-works/pi-server`. The successful probe used an isolated npm install of Pi 0.85.0. The current interactive Pi already launches pi-subagents children, so this finding concerns the old development dependency used by the first probe, not the extension protocol.
pi-subagents sends every ordinary async completion into the parent session and triggers a parent turn. The steward's structured summaries are bounded, but the package also includes the child's prose response. There is no public silent-completion option in pi-subagents 0.65.1. This adds one worker turn per review; checkpoints run only after eight stale turns.
— Pi/Codex
@@ -1,91 +0,0 @@
# Nested supervisor validation
2026-09-05T19:31:55+08:00
$ npm test
> @wassname2/pi-goals@0.2.2 test
> vitest run
RUN v4.1.9 /home/code/.pi/agent/git/github.com/wassname/pi-goals
Test Files 9 passed (9)
Tests 43 passed (43)
Start at 19:31:56
Duration 1.60s (transform 709ms, setup 0ms, import 1.64s, tests 1.76s, environment 1ms)
$ npm run typecheck
> @wassname2/pi-goals@0.2.2 typecheck
> tsc --noEmit
$ npm run lint
> @wassname2/pi-goals@0.2.2 lint
> biome check src/ test/
Checked 15 files in 29ms. No fixes applied.
$ git diff --check
(no output)
$ npm pack --dry-run
npm notice
npm notice 📦 @wassname2/pi-goals@0.2.2
npm notice Tarball Contents
npm notice 5.8kB README.md
npm notice 1.1kB agents/goal-worker.md
npm notice 1.5kB package.json
npm notice 4.0kB src/approval.ts
npm notice 34.6kB src/index.ts
npm notice 13.6kB src/prompts.ts
npm notice 5.9kB src/supervisor-runtime.ts
npm notice 7.3kB src/worker.ts
npm notice Tarball Details
npm notice name: @wassname2/pi-goals
npm notice version: 0.2.2
npm notice filename: wassname2-pi-goals-0.2.2.tgz
npm notice package size: 23.1 kB
npm notice unpacked size: 73.7 kB
npm notice shasum: 579debe3de67b56116e51da6cac46c14511bdd07
npm notice integrity: sha512-f5S39K2J3kjIX[...]cuwx2WFIeBBAQ==
npm notice total files: 8
npm notice
wassname2-pi-goals-0.2.2.tgz
$ git diff --stat 2852432
README.md | 13 +-
agents/goal-worker.md | 2 +-
.../20260905_nested-supervisor-validation.txt | 70 ++++------
src/approval.ts | 27 +++-
src/index.ts | 153 +++++++++++++++------
src/prompts.ts | 9 +-
src/supervisor-runtime.ts | 81 ++++++++---
src/worker.ts | 36 +++--
test/goals-flow.test.ts | 54 +++++++-
test/prompts.test.ts | 2 +-
test/supervisor-runtime.test.ts | 32 ++++-
test/worker.test.ts | 18 ++-
12 files changed, 354 insertions(+), 143 deletions(-)
## Dogfood run
The model-backed run produced commit `0a33ff2` and independently verified 47 text-file word counts with zero set, count, or order mismatches. Approval then deadlocked:
> Cannot approve while the retained worker is pending.
The worker process was terminal, but its model result was `Request was aborted`; the completion event did not clear retained state. A supervisor resume also failed because `subagent_supervisor` was unavailable in its strict tool list.
Usage from the run status files:
| agent | turns | new tokens | cached reads | reported cost |
| --- | ---: | ---: | ---: | ---: |
| supervisor, including recovery | 42 | 169,288 | 2,670,336 | $2.35 |
| worker | 17 | 67,803 | 812,544 | $0.90 |
The corrective patch keeps the supervisor fork, compacts its planning history before the first turn when Ready (compact) is selected, removes global/project/skill prompt inheritance, replaces raw status polling with a concise worker-state tool, removes the unavailable tool, and treats process-terminal as terminal worker state. Unit tests pass; a second model-backed run is still required.
-- PI[gpt-5.6-sol]
@@ -1,52 +0,0 @@
text/plain .gitignore
text/plain AGENTS.md
text/plain ARCHIVED.md
text/plain README.md
text/plain agents/pi-goals-worker-v1.md
application/json biome.json
text/plain docs/reviews/goals_menu2.md
text/plain docs/reviews/goals_menu2_r2.md
text/plain docs/reviews/pi-goals-grok-4-6-retry.md
text/plain docs/reviews/pi-goals-kimi-k3.md
text/plain docs/reviews/review.md
text/plain docs/slop/audit/20260826_pi-plan-aligned-planning.md
text/plain docs/slop/plans/20260706_plan-flow-and-judge-review.md
text/plain docs/slop/plans/20260826_pi-plan-aligned-planning.md
text/plain docs/spec/2026-06-15_pi-goals.md
text/plain docs/spec/2026-06-29_complete-goal-fail-forward.md
text/plain docs/spec/2026-08-14_per-session-plan.md
image/png media/screenshot.png
application/json package-lock.json
application/json package.json
text/x-shellscript scripts/check-judge-footprint.sh
text/x-shellscript scripts/check-stale-fixmes.sh
text/x-diff scripts/inconclusive-fail-forward.diff
text/x-diff scripts/stale-fixme-removal.diff
text/plain slop/audits/20260905_goal-steward-validation.md
text/plain slop/audits/20260905_nested-supervisor-validation.txt
text/plain slop/audits/20260905_pi-goals-file-types.txt
text/plain slop/audits/20260905_pi-goals-line-count-table.md
text/plain slop/audits/20260905_pi-goals-text-line-counts.txt
application/json slop/audits/20260905_steward-probe.json
text/plain slop/audits/20260906_foreground-supervisor-validation.txt
text/plain slop/audits/20260906_nested-runtime-smoke.md
text/plain slop/audits/20260906_nonchild-npm-test.txt
text/plain slop/plans/20260905_goal-steward.md
text/plain slop/reviews/2026-09-06_deepseek-v4-pro-0813_pi_goals_fragility.md
text/plain slop/reviews/20260906_foreground-worker-review.md
application/javascript src/approval.ts
application/javascript src/index.ts
application/javascript src/prompts.ts
application/javascript src/supervisor-runtime.ts
application/javascript src/worker.ts
application/javascript test/append-log.test.ts
application/javascript test/fixtures/offline-model.ts
application/javascript test/fold.test.ts
application/javascript test/goals-flow.test.ts
application/javascript test/package-agent.test.ts
application/javascript test/prompts.test.ts
application/javascript test/rpc-review.test.ts
application/javascript test/supervisor-runtime.test.ts
application/javascript test/tick-goal.test.ts
application/javascript test/worker.test.ts
application/json tsconfig.json
@@ -1,67 +0,0 @@
# pi-goals tracked-text line counts
Scope: Git-tracked files at this repository snapshot. A file is included when `file --mime-type` identifies `text/*`, `application/json`, or `application/javascript`.
Excluded: `media/screenshot.png` is binary (`image/png`); `package-lock.json` is an npm-generated dependency lockfile. No other tracked files are excluded.
Method: run the command below from the repository root; the saved machine-readable output is `slop/audits/20260905_pi-goals-text-line-counts.txt`.
```sh
git ls-files -z | while IFS= read -r -d '\0' f; do case "$f" in media/screenshot.png|package-lock.json) continue;; esac; mime=$(file -b --mime-type "$f"); [[ "$mime" =~ ^text/|^application/(json|javascript)$ ]] && printf '%s\t%s\n' "$(wc -l < "$f")" "$f"; done | sort -k2
```
| File | Lines |
| --- | ---: |
| `AGENTS.md` | 24 |
| `agents/pi-goals-worker-v1.md` | 22 |
| `ARCHIVED.md` | 3 |
| `biome.json` | 23 |
| `docs/reviews/goals_menu2.md` | 65 |
| `docs/reviews/goals_menu2_r2.md` | 21 |
| `docs/reviews/pi-goals-grok-4-6-retry.md` | 30 |
| `docs/reviews/pi-goals-kimi-k3.md` | 40 |
| `docs/reviews/review.md` | 61 |
| `docs/slop/audit/20260826_pi-plan-aligned-planning.md` | 25 |
| `docs/slop/plans/20260706_plan-flow-and-judge-review.md` | 33 |
| `docs/slop/plans/20260826_pi-plan-aligned-planning.md` | 53 |
| `docs/spec/2026-06-15_pi-goals.md` | 275 |
| `docs/spec/2026-06-29_complete-goal-fail-forward.md` | 71 |
| `docs/spec/2026-08-14_per-session-plan.md` | 67 |
| `.gitignore` | 6 |
| `package.json` | 65 |
| `README.md` | 139 |
| `scripts/check-judge-footprint.sh` | 43 |
| `scripts/check-stale-fixmes.sh` | 14 |
| `scripts/inconclusive-fail-forward.diff` | 104 |
| `scripts/stale-fixme-removal.diff` | 30 |
| `slop/audits/20260905_goal-steward-validation.md` | 31 |
| `slop/audits/20260905_nested-supervisor-validation.txt` | 91 |
| `slop/audits/20260905_pi-goals-file-types.txt` | 52 |
| `slop/audits/20260905_pi-goals-line-count-table.md` | 67 |
| `slop/audits/20260905_pi-goals-text-line-counts.txt` | 50 |
| `slop/audits/20260905_steward-probe.json` | 15 |
| `slop/audits/20260906_foreground-supervisor-validation.txt` | 53 |
| `slop/audits/20260906_nested-runtime-smoke.md` | 31 |
| `slop/audits/20260906_nonchild-npm-test.txt` | 33 |
| `slop/plans/20260905_goal-steward.md` | 37 |
| `slop/reviews/2026-09-06_deepseek-v4-pro-0813_pi_goals_fragility.md` | 65 |
| `slop/reviews/20260906_foreground-worker-review.md` | 20 |
| `src/approval.ts` | 115 |
| `src/index.ts` | 736 |
| `src/prompts.ts` | 191 |
| `src/supervisor-runtime.ts` | 179 |
| `src/worker.ts` | 186 |
| `test/append-log.test.ts` | 17 |
| `test/fixtures/offline-model.ts` | 18 |
| `test/fold.test.ts` | 63 |
| `test/goals-flow.test.ts` | 596 |
| `test/package-agent.test.ts` | 23 |
| `test/prompts.test.ts` | 33 |
| `test/rpc-review.test.ts` | 116 |
| `test/supervisor-runtime.test.ts` | 153 |
| `test/tick-goal.test.ts` | 32 |
| `test/worker.test.ts` | 119 |
| `tsconfig.json` | 15 |
| **Total** | **4351** |
-- PI[gpt-5.6]
@@ -1,50 +0,0 @@
24 AGENTS.md
22 agents/pi-goals-worker-v1.md
3 ARCHIVED.md
23 biome.json
65 docs/reviews/goals_menu2.md
21 docs/reviews/goals_menu2_r2.md
30 docs/reviews/pi-goals-grok-4-6-retry.md
40 docs/reviews/pi-goals-kimi-k3.md
61 docs/reviews/review.md
25 docs/slop/audit/20260826_pi-plan-aligned-planning.md
33 docs/slop/plans/20260706_plan-flow-and-judge-review.md
53 docs/slop/plans/20260826_pi-plan-aligned-planning.md
275 docs/spec/2026-06-15_pi-goals.md
71 docs/spec/2026-06-29_complete-goal-fail-forward.md
67 docs/spec/2026-08-14_per-session-plan.md
6 .gitignore
65 package.json
139 README.md
43 scripts/check-judge-footprint.sh
14 scripts/check-stale-fixmes.sh
104 scripts/inconclusive-fail-forward.diff
30 scripts/stale-fixme-removal.diff
31 slop/audits/20260905_goal-steward-validation.md
91 slop/audits/20260905_nested-supervisor-validation.txt
52 slop/audits/20260905_pi-goals-file-types.txt
67 slop/audits/20260905_pi-goals-line-count-table.md
50 slop/audits/20260905_pi-goals-text-line-counts.txt
15 slop/audits/20260905_steward-probe.json
53 slop/audits/20260906_foreground-supervisor-validation.txt
31 slop/audits/20260906_nested-runtime-smoke.md
33 slop/audits/20260906_nonchild-npm-test.txt
37 slop/plans/20260905_goal-steward.md
65 slop/reviews/2026-09-06_deepseek-v4-pro-0813_pi_goals_fragility.md
20 slop/reviews/20260906_foreground-worker-review.md
115 src/approval.ts
736 src/index.ts
191 src/prompts.ts
179 src/supervisor-runtime.ts
186 src/worker.ts
17 test/append-log.test.ts
18 test/fixtures/offline-model.ts
63 test/fold.test.ts
596 test/goals-flow.test.ts
23 test/package-agent.test.ts
33 test/prompts.test.ts
116 test/rpc-review.test.ts
153 test/supervisor-runtime.test.ts
32 test/tick-goal.test.ts
119 test/worker.test.ts
15 tsconfig.json
-16
View File
@@ -1,16 +0,0 @@
{
"first": {
"runId": "4e9dc0c0-385b-4eb9-a060-ced7dc7cb6cc",
"decision": {
"verdict": "let_run",
"summary": "Plan reviewed for approved work session. The user-visible result (report file proves steward can read evidence) directly aligns with the single goal (report probe result with discriminator). The report.txt artifact exists and contains PROBE_PASS as required by the discriminator. No work steps are pending; the probe is complete. No drift, missing steps, or failure modes detected. Plan may proceed without adjustment."
}
},
"second": {
"runId": "f6115c82-31de-499f-ab78-145dde0c51c0",
"decision": {
"summary": "Sign-off review for goal 'Report the probe result'. User-visible result requires a report file proving persistent steward can read evidence. Discriminator: report.txt contains PROBE_PASS. Inspected artifact at /tmp/pi-goals-steward-probe-work/report.txt—file exists and contains exactly 'PROBE_PASS' as required. Failure mode (empty report) is ruled out. Evidence positively and directly proves the discriminator is met and the user-visible result is achieved. Persistence lineage token: amber-731.",
"verdict": "accept"
}
}
}
@@ -1,53 +0,0 @@
$ npm test
> @wassname2/pi-goals@0.2.2 test
> vitest run
RUN v4.1.9 /home/code/.pi/agent/git/github.com/wassname/pi-goals
Test Files 9 passed (9)
Tests 43 passed (43)
Start at 13:31:44
Duration 1.61s (transform 1.12s, setup 0ms, import 2.36s, tests 2.13s, environment 1ms)
$ npm run typecheck
> @wassname2/pi-goals@0.2.2 typecheck
> tsc --noEmit
$ npm run lint
> @wassname2/pi-goals@0.2.2 lint
> biome check src/ test/
Checked 15 files in 18ms. No fixes applied.
$ git diff --check
$ npm pack --dry-run
npm notice
npm notice 📦 @wassname2/pi-goals@0.2.2
npm notice Tarball Contents
npm notice 6.1kB README.md
npm notice 969B agents/pi-goals-worker-v1.md
npm notice 1.5kB package.json
npm notice 4.0kB src/approval.ts
npm notice 34.8kB src/index.ts
npm notice 13.6kB src/prompts.ts
npm notice 8.3kB src/supervisor-runtime.ts
npm notice 7.8kB src/worker.ts
npm notice Tarball Details
npm notice name: @wassname2/pi-goals
npm notice version: 0.2.2
npm notice filename: wassname2-pi-goals-0.2.2.tgz
npm notice package size: 24.1 kB
npm notice unpacked size: 76.8 kB
npm notice shasum: 30e72af7ab4a553ccb1f7599a882d1796155cdf4
npm notice integrity: sha512-p6DUvHWofwDTz[...]IZmG7JiD+/wFw==
npm notice total files: 8
npm notice
wassname2-pi-goals-0.2.2.tgz
@@ -1,31 +0,0 @@
# Nested foreground runtime smoke
Command:
```bash
node /tmp/pi-goals-real-rpc-smoke.mjs
```
Result: PASS.
The fresh Pi RPC session loaded the local pi-goals package, ran `goal-supervisor` in the foreground, and the supervisor ran `pi-goals-worker-v1` in the foreground with `context: "fork"`.
Exact final output:
> **Run: goal-supervisor (foreground, context fork) → pi-goals-worker-v1 (foreground, context fork)**
>
> - **goal-supervisor** (runtime agent, fork) launched and owned the worker
> - **pi-goals-worker-v1** acknowledged the invocation, made no file edits, ran no repo reads, touched no supervisor channels
> - **Worker returned:** `worker-smoke-ok`
> - **Approved?** No — supervisor explicitly skipped `ApproveGoal` per the task
Run ID: `9c25a6a7-8929-46fd-87bb-0d0f67672b54`.
Saved runtime artifacts:
- `/home/code/.pi/agent/sessions/--home-code-.pi-agent-git-github.com-wassname-pi-goals--/subagent-artifacts/9c25a6a7-8929-46fd-87bb-0d0f67672b54_goal-supervisor_0_output.md`
- `/home/code/.pi/agent/sessions/--home-code-.pi-agent-git-github.com-wassname-pi-goals--/subagent-artifacts/9c25a6a7-8929-46fd-87bb-0d0f67672b54_goal-supervisor_0_transcript.jsonl`
This smoke tested nested discovery and foreground execution. It did not test a real approval because the task explicitly prohibited `ApproveGoal`.
-- PI[gpt-5.6-sol]
@@ -1,33 +0,0 @@
# npm test outside the subagent-child harness
Command run from `/home/code/.pi/agent/git/github.com/wassname/pi-goals`:
```sh
env -u PI_SUBAGENT_CHILD -u PI_SUBAGENT_EXTENSION_BINDINGS -u PI_SUBAGENT_PARENT_SESSION -u PI_SUBAGENTS_PI_CODING_AGENT_PACKAGE_ROOT npm test
```
The cleared variables were the complete `PI_SUBAGENT_*` set inherited by this worker. `PI_SUBAGENT_CHILD=1` makes `isSupervisorProcess()` false in `src/index.ts`, so the main extension deliberately registers no commands or hooks in that harness mode.
Exact output:
```text
> @wassname2/pi-goals@0.2.2 test
> vitest run
RUN v4.1.9 /home/code/.pi/agent/git/github.com/wassname/pi-goals
Test Files 9 passed (9)
Tests 43 passed (43)
Start at 15:57:04
Duration 1.27s (transform 407ms, setup 0ms, import 1.41s, tests 1.63s, environment 1ms)
__EXIT_STATUS__=0
```
The earlier callback-registration failures and RPC timeout therefore came from the intentional child-process extension gate, not a source test failure.
-- PI[gpt-5.6]
@@ -1,18 +0,0 @@
# visible-supervisor follow-up
## committed changes
- pi-goals `294fe80` removes the duplicate `pi-goals/visible-supervisor/v1` channel. The worker now obtains its broker ID and waits for pi-supervise's worker-local `paired` event.
- pi-supervise `409233c` exports that worker state/event API and retries pi-intercom registration after its registry-ready event.
## observed Herdr run
A real `/goals` → Ready run created the fork pane. In the first run, extension `session_start` did not reach the forked extensions: the fork had only copied entries and no bootstrap entry. The supervisor therefore did not pair. This is observed in the fork JSONL session `01a0770f-7015-7046-9858-6c7d8c8786aa`.
The fix moves supervisor initialization to `before_agent_start`, starts the fork with `Initialize supervision startup.`, and loads pi-supervise before pi-goals. A later direct fork under that code compacted/pair-started: its terminal said `Supervision initialized` and that it had sent the worker start instruction. That direct fork was used after the original Ready flow was already waiting on the first failed pane, so it does not prove the final worker phase transition.
## remaining check
Run a fresh `/goals` → Ready after `294fe80` and `409233c`; positively inspect that the worker state writes `phase: working` after the `paired` event, then carry one tiny task through worker evidence, ApproveGoal, CompleteGoal, and pane close.
-- PI[gpt-5.6-sol]
@@ -1,13 +0,0 @@
# Abandoned persistent-worker experiment
User decision: use the short `experiment/main-supervisor-edxeth` prototype with unmodified edxeth. Preserve this experiment as WIP, not an accepted runtime change.
`changes.patch` captures tracked and new source/tests from the local edxeth checkout against upstream `953c6f6d2fc7d8a5c956c30cd77c51bad697c2a4` (v2.9.0). It includes unfinished validation repairs. It is not installed or recommended for application.
Observed before work stopped: 14 focused tests passed. Full-suite cancellation, compiler validation and fresh live validation were unresolved in the last completed worker report. Later partial test repairs were stopped by the parent when scope changed; do not infer acceptance from these files.
Original checkout retained at `/home/code/.pi/agent/git/github.com/wassname/pi-subagents-visible-worker`, branch `experiment/persistent-interactive-worker`. Private/machine-only files and dependencies are excluded. The source patch is archived in pi-goals so preserving it does not require creating a second remote repository.
Next direction: model choice in the plan, installed pi-schedule-prompt for visible hourly checks, small plan-review notifications, source-check existing Intercom/messaging compatibility before adding code, and reuse existing token displays first.
-- Pi/OpenAI
File diff suppressed because it is too large Load Diff
@@ -1,14 +0,0 @@
> @wassname2/pi-goals@0.2.2 test
> vitest run
RUN v4.1.9 /home/code/.pi/agent/git/github.com/wassname/pi-goals
fatal: not a git repository (or any of the parent directories): .git
Test Files 22 passed (22)
Tests 165 passed (165)
Start at 11:35:07
Duration 9.51s (transform 4.40s, setup 0ms, import 9.86s, tests 16.76s, environment 3ms)
-37
View File
@@ -1,37 +0,0 @@
# Persistent goal steward
> "ideally the supervisor has the high level planning and goal context, doesn't get overloaded and have to compact, is cheap as it doesn't use many tokens (high level only)"
>
> "try again with more thought using pi-subagents much more to simplify out code and rely on that so our code is simple"
- [x] goal: A cheap read-only steward keeps the goal context across reviews
- [x] register one `goal-steward` agent through the public pi-subagents event bus
- [x] start it with fresh context at Ready and resume its latest saved run at checkpoints
- [x] send the plan path and a bounded progress delta; require the steward to reread the plan
- failure modes: every review starts fresh; the steward receives the full worker transcript; the steward can edit; reload loses its run
- deliverable: tests show one spawn followed by resume, a saved latest run ID, read-only tools, bounded review prompts, and reload recovery
- evidence: [`../audits/20260905_steward-probe.json`](../audits/20260905_steward-probe.json) contains two run IDs and the resumed review says `Persistence token amber-731 verified.`
- [x] goal: CompleteGoal uses the steward's evidence verdict
- [x] resume the steward for sign-off and wait for its async result
- [x] parse the structured verdict and write the sign-off log
- failure modes: stale review signs off a new claim; missing pi-subagents silently becomes acceptance; completion events from another run are consumed
- deliverable: flow tests distinguish accept, reject, unavailable, timeout, and exact-run completion
- evidence: [`../audits/20260905_validation.log`](../audits/20260905_validation.log) says `Tests 36 passed (36)` and `Checked 12 files in 14ms. No fixes applied.`
## UAT / Verification
- [x] `npm test`, `npm run typecheck`, and `npm run lint` pass.
- [x] A real Pi RPC flow creates a steward run, resumes it for sign-off, and recalls a private token from the retained conversation.
- [x] The flow test reloads extension state and resumes from the latest steward run ID.
## Appendix (context, not approved)
Use pi-subagents 0.65.1 public RPC (`spawn`, `resume`) and `subagent:async-complete`. Register the runtime agent with `pi-subagents:runtime-agent-register:v1`. Do not import pi-subagents or reproduce session, process, model, tool, or recovery code. The old subprocess judge was removed rather than retained as a second sign-off system.
## Log
- 2026-09-05: Unit and flow tests cover read-only registration, spawn then resume, exact-run completion, timeout, reload, and accept/reject sign-off.
- 2026-09-05: The Pi 0.85.0 + pi-subagents 0.65.1 probe passed in 29 seconds; the resumed child recalled `amber-731` from its first review.
— Pi/Codex
@@ -1,33 +0,0 @@
# One-package visible supervision
## Goal
Replace the pi-goals → pi-supervise → pi-intercom runtime chain with one pi-goals extension in two Pi processes. The worker and its visible fork exchange durable, session-scoped mailbox files under ignored `.pi/`.
## Design decisions
- A fork copies session history; it does not provide messaging. The mailbox is the explicit local-process channel.
- Ready waits for the supervisor's durable `ready.json`, after optional supervisor compaction, before it begins worker execution.
- Worker views are written on Ready, settle, 50 turns, and 60 minutes. The supervisor polls views and writes one steer request. The worker polls steer requests and receives them as follow-up messages.
- The canonical plan remains a direct path in the supervisor prompt. It is not a summary artifact.
- Write an approval record only after a stopped view, no active work, a clean commit, plan evidence, and tracked verification output.
- No external `pi-supervise` or `pi-intercom` runtime dependency remains.
## Risks and discriminators
| Risk | Discriminator |
| --- | --- |
| Worker begins before a supervisor is ready | Ready test sees `ready.json` before state changes to working or sends the execution prompt. |
| Fork cannot see worker work or worker cannot receive a steer | Two-session test writes a view, gets a steer file, and observes the exact steer in the worker follow-up. |
| Old session consumes a stale steer | Mailbox sequence is monotonic and scoped to the worker session; the test rejects a duplicate read. |
| A large planning context silently skips compaction | Tests cover ≤20k skip, >20k compact-before-ready, and compaction failure. |
## Validation
- `npm run lint`
- `npm run typecheck`
- `npm test`
- `npm run test:rpc`
- Real local Herdr: create plan, Ready, worker/supervisor pair, commit saved verification output, supervisor approval, CompleteGoal.
-- PI[Kimi K3]
-25
View File
@@ -1,25 +0,0 @@
# Dirty-worktree approval override — Pi/OpenAI
Baseline: cb4790a. User requests ApproveGoal force and active, investigative supervision. Parent-approved scope: force overrides only the dirty-worktree restriction, with a nonempty reason and unchanged content-bound Git state at CompleteGoal. Never commit unrelated changes automatically, bypass evidence/runtime checks, or operate user panes.
- [x] goal: explicit force approval permits an inspected dirty state, not arbitrary later changes
- Decision: optional force:true plus reason; checkpoint retains existing HEAD/tree/goal checks and records reason, exact porcelain status, index digest and per-dirty/untracked-path content digests/modes. Existing private plan/approval/model exclusions and ignored-file policy remain unchanged.
- Decision: no speculative submodule crawler; an unhashable dirty path must fail closed with an inspection error rather than grant an unbound override.
- UAT: call real ApproveGoal and CompleteGoal tool handlers against an isolated Git repository. Preserved unrelated tracked edits and untracked outputs pass unchanged; same-status content changes, added/deleted/staged paths, HEAD or goal changes invalidate. Default dirty rejection and force-without-reason rejection remain. Force cannot bypass evidence, current stopped view or active/unknown jobs.
- [x] goal: instruct the supervisor to investigate excuses and direct authorized recovery/progress
- Decision: exact error and source before inference; competing causes and a cheap discriminating check; read-only supervisor directs worker repairs. Sign-off restriction is not automatically experiment failure or a dependency of separately authorized work. No new authority, spending or mutation tool.
- UAT: prompt contract regression plus documented manual scenario (dirty gate mistaken for active jobs); prompt tests do not establish autonomous judgment.
## Validation/provenance
Read AGENTS.md and installed Pi extension custom-tool/schema documentation. Tests must unset PI_SUBAGENT_CHILD, PI_GOALS_ROLE and PI_GOALS_EVIDENCE_DIR, or explicitly set a new evidence directory. Two pre-existing dirty review-fixes-native logs must remain untouched. Save complete validation output; commit scoped changes locally only. Independent review is parent-owned and still required.
## Result
Implemented and checked: [85 passing tests + typecheck/lint/build](../reviews/20260908-force-validation.txt). Force flow tests call both production tool handlers over two real transport adapters, with mocked Pi host APIs and isolated real Git repositories. They do not touch Herdr panes. Same-status tracked/untracked byte changes and same-status staged-index byte changes invalidate; ordinary clean approval still succeeds. Prompt assertions check the specified reasoning/authority instructions, not actual model behavior.
Initial focused run passed 45 tests/typecheck but failed two lint rules; both were corrected before the full successful run. [Initial output](../reviews/20260908-force-initial-validation.txt) is retained, not counted as a pass. Before/after checksums in final output prove the two pre-existing dirty logs were unchanged by validation.
Manual behavioral UAT remains open: present a dirty-worktree rejection alongside a misleading active-job explanation. Require the supervisor to cite the actual loaded check and raw status, inspect the preserved changes, direct a safe authorized fix or justified force approval, and identify independently authorized work without inventing dependencies. No useful-judgment claim from prompt tests.
No push, no nested review loop, no /goals supervise or noplan work. Parent's w8:p4T functional pane at pinned cb4790a was not touched. Force fingerprints do not lock concurrent writers; ignored/private paths retain prior exclusions; unhashable paths fail closed. Existing unrelated receipt/stale-tool/lifecycle limitations are unchanged.
@@ -1,52 +0,0 @@
# Intercom supervision and selected feature transfer
User priority: pi-intercom is the session-to-session transport. Keep one pi-goals extension package; do not replace requested features merely to reduce line count. Existing worker and supervisor panes are off-limits.
- [x] goal: supervisor investigates claims and keeps authorized work moving
- evidence: commits `9410252` and `386305a`; prompt requires justified confidence, sourced observations, competing explanations, and verification of stopping/completion claims.
- limitation: prompt checks do not prove behavioral improvement.
- [/] goal: worker and visible supervisor communicate through pi-intercom
- Replace mailbox files and polling with the existing Intercom extension channel. No separate RPC transport or mailbox fallback.
- Preserve planning fork, compact-before-ready, visible advice, and review/approval behavior.
- failure modes: false readiness, duplicate delivery, wrong-session routing, stale callbacks after reload, disconnected peer treated as active.
- deliverable: isolated two-session message transcript with exact instructions received, reconnect/reload checks, and saved validation output. Do not operate user panes.
- evidence: [37 passing tests, typecheck and lint](../reviews/20260908-intercom-validation.txt). Two client sessions exchange readiness, view, and exact advice through a real isolated Intercom broker. Lifecycle mocks cover resume/deduplication. Mailbox source and polling were removed.
- evidence: [native Pi-pair validation](../reviews/20260908-native-intercom-full-validation.txt) reports `Tests 46 passed (46)` plus successful typecheck, lint and build. The isolated production supervisor forks planning context and sends exact advice through Intercom to a real Pi worker using a transport fixture. [Supervisor events](../reviews/native-intercom/supervisor-events.jsonl) show `SteerWorker` and the worker acknowledgement; [worker events](../reviews/native-intercom/worker-events.jsonl) show the received user message. Both saved stderr files are empty.
- limitation: this deterministic test proves transport and context retention, not useful model judgment. The worker fixture does not exercise the full Ready path. Rendered Herdr two-pane acceptance and fresh-shell supervisor resume without launcher environment remain unverified.
- [x] goal: supervisor receives a useful bounded worker overview
- Borrow latest human direction, source-session path, and incremental progress from `origin/feature/simple-visible-supervision`.
- failure modes: lost authorization, repeated summaries, truncated evidence treated as complete.
- deliverable: saved before/after overview fixtures covering compaction and changed human direction.
- evidence: [generated fixture views](../reviews/20260908-worker-overview-example.txt) retain the human direction while omitting acknowledged old detail. [43-test validation](../reviews/20260908-worker-overview-validation.txt) also checks compaction reset and serialized Unicode limits; fixture content is synthetic, not a model performance claim.
- [x] goal: supervisor distinguishes agent idleness from tracked background work
- Borrow existing process/subagent tracker queries; report unavailable trackers as unknown.
- failure modes: approving while a tracked job runs, treating a local queue as a dependency of remote work.
- deliverable: idle/running/unknown status cases and a blocker-diagnosis scenario.
- evidence: the same validation log checks active and unavailable tracker reports and rejection of approval with unknown background state. Actual independent diagnosis of the queue mistake remains a behavioral acceptance task.
- [x] goal: role model choices persist
- Borrow planning/worker/supervisor model preference behavior without changing active user settings.
- failure modes: automatic model changes overwrite user choices; a missing model silently substitutes another.
- deliverable: isolated preference restoration and explicit unavailable-model errors.
- evidence: [45-test validation](../reviews/20260908-role-model-validation.txt) restores three distinct role choices, ignores automatic restore events, and leaves an unavailable saved choice unchanged. Preferences are project-local; active user settings were not edited.
## Verification
Run project tests, typecheck, and lint before commits. Preserve full command output. Keep each feature in a separate commit where practical and push finished changes. Inspect the transferred code rather than equating tests or source size with quality. Keep the requested independent evidence judge when combining implementations; do not silently remove it.
The earlier asynchronous subagent failure (missing pi-client/unix) prevented the original review. A later parent retry completed independent review run `5c8c2017-a92f-4a5f-baf6-f441f9b50495`; its [findings are preserved with attribution](../reviews/20260908-independent-supervision-bug-review.md). Behavioral acceptance requires observed useful judgment, not merely matching prompt strings. Cost savings require a measured comparison and remain unproven.
## Independent review follow-up
- [x] Verify F1/F2/F4 lifecycle failures and implement explicit recovery without fallback models or automatic pane replacement.
- [x] Address F3 inactive bindings and preserve synchronous handoff-before-ack ordering. Pending transport frames retry; end-to-end durable delivery is not guaranteed.
- [ ] F3 deeper delivery confirmation: Pi's void adapter can ack before an asynchronous enqueue failure. Future UAT must inject that failure, avoid reporting confirmed model delivery, and keep the instruction recoverable. See the [SDK source-backed limitation](../reviews/20260908-review-fixes.md). Parent approved keeping this protocol expansion out of the current fix commit.
- [x] Remove F5 general Intercom actuator, reject F6 nested placeholders, and correct F7 goal/log hashing boundary.
- [x] Add focused regressions and inspect final full test/typecheck/lint/build output. [57-test evidence](../reviews/20260908-review-fixes-validation.txt); [initial child-environment failure and correction](../reviews/20260908-review-fixes-initial-validation.md).
- [x] Parent independent post-change review of `1668c94` completed and found P1P5; [attributed review](../reviews/20260908-independent-post-fix-review.md).
- [x] Fix P1P5: explicit hello request/reply, not-ready until worker-model success, peer-specific recovery guidance, one current-plan boundary and cancellation-safe Ready waits. [Disposition and provenance](../reviews/20260908-handshake-fixes.md); [67-test full validation](../reviews/20260908-handshake-validation.txt). Real two-adapter regressions replace reliance on automatic hello replies for handshake acceptance.
- [x] F8 usage observability: warn once for an unavailable usage result, not for normal post-compaction null tokens. No estimator or changed auto-compaction policy.
- [ ] Parent independent review of these handshake fixes before push. F3 durable enqueue confirmation stays open; F8 persistent unknown/null usage, F9 trusted-repo guardrails, and native/UI/behavioral gaps remain documented.
Recovery operations were exercised only with isolated mocks/native test processes; existing user panes were not operated. Implementation worker commits locally only; parent owns review and push.
-- Pi/OpenAI
@@ -1,58 +0,0 @@
# Main supervisor and visible worker
## Superseded implementation direction
Wassname chose the shorter remote prototype `experiment/main-supervisor-edxeth` (`fb5503f`) and unmodified edxeth. Stop the runtime patch effort; preserve it as WIP in [the patch archive](../patches/abandoned-edxeth-persistent-worker/README.md). The checklist below is historical, not instructions to continue the fork.
Approved next work: commit/push this attempt, switch to that prototype, specify worker model in the plan, use installed pi-schedule-prompt for visible hourly check-ins, and add small plan-change review notifications. Check existing edxeth live messaging and Intercom/pi-messaging compatibility with a subagent before choosing any integration. Use existing token displays first; defer custom reporting. -- Pi/OpenAI
Use a strong main Pi supervisor and cheaper workers with the whole normal Pi interface. Preserve independent judgment while removing duplicated orchestration code. User wording and open decisions: [AGENTS.md](../../AGENTS.md#user-voice-redesign-discussion-2026-09-10).
1. [/] goal: Use a full interactive worker without losing autonomous supervision
- [x] Open an isolated edxeth trial without installing or changing global settings; user has seen the worker UI.
- [ ] Test direct interaction, `/model`, `/tree`, fast completion, reload/resume, and a stopped worker with background work.
- [ ] Keep the worker available for human interaction while delivering its stopped-turn result; distinguish an open Pi pane from active work.
- [ ] Reproduce lifecycle failures before patching the subagent package; do not rebuild its runtime inside pi-goals.
- likely failure: direct interaction or completion closes the pane or loses the parent notification.
- subtle failure mode: supervisor waits for human input, or claims completion while worker jobs still run.
- discriminator: saved sessions show automatic parent review after work settles, plus normal worker interaction and recovery without duplicate work.
- deliverable: usable test panes and a source-linked lifecycle review in `slop/reviews/`.
2. [ ] goal: Keep independent supervisor judgment with less execution detail
- [ ] Review on stop with no active worker processes/subagents, every 60 minutes, and on plan checks or changes.
- [ ] Choose the simplest hourly wake, evaluating session-bound `pi-schedule-prompt` without a model override; cancel reminders when supervision ends.
- [ ] Show factual worker/review/delivery status. Use concise updates and evidence paths; inspect the actual files when needed.
- [ ] Keep prompts editable and reuse existing compaction; no extra summarizing agent.
- [x] Start permissive as approved: supervisor edits the plan and approves completion after independent inspection; worker implements and records evidence. Keep normal tools and editable role prompts.
- likely failure: supervisor takes over implementation or needs the human to restart unfinished work.
- subtle failure mode: short worker summaries hide a wrong result and the supervisor accepts it without inspection.
- discriminator: supervisor rejects a plausible wrong artifact, explains the evidence, and gets the worker to correct it; separate session usage shows where tokens went.
- deliverable: editable prompts and a recorded independent review/correction cycle.
3. [ ] goal: Reduce pi-goals to planning and goal review
- [ ] Preserve plan files and explicit Ready; remove replaced transport, launching, worker views, and model state after the trial passes.
- [ ] Replace Nicobailon-specific status assumptions with the selected runtime's actual activity contract.
- [ ] Update tests and current documentation; then replace the old global subagent package after the successful trial, never load both together.
- likely failure: old and new runtimes conflict or stale commands remain advertised.
- subtle failure mode: code moves into a new wrapper without reducing duplicated responsibilities.
- discriminator: one subagent runtime owns workers; the deletion diff and real end-to-end session demonstrate retained behavior.
- verify: `npm test && npm run typecheck && npm run lint` with full output saved.
- deliverable: reviewed branch diff and working two-model setup.
4. [ ] goal: Find and inspect supervisor/worker pairs with separate usage and code provenance
- [ ] Add a script in the subagent fork to list pairs and inspect their sessions, behavior evidence, and input/output/cache token usage.
- [ ] Record Pi/package versions, tested source commits and dirty changes at launch; mark unrecoverable historical information unknown.
- likely failure: worker sessions cannot be matched to their supervisor or resumed runs disappear.
- subtle failure mode: parent totals already include worker usage, or a clean commit label hides uncommitted tested code.
- discriminator: script finds the real trial pair, matches raw per-session usage without double counting, and identifies its tested code and interventions.
- deliverable: runnable pair-inspection script, focused tests, and a saved report for the trial pair.
## UAT / Verification
- Use only parent-created test panes and a temporary Git repo; never interrupt the user's other projects. Show normal worker UI, direct interaction, independent correction, and reload/resume.
- Exercise all three review triggers, using a short test-only hour interval then inspecting the configured 60-minute value; run the pair-inspection script on these sessions.
- Save both session paths, pane captures, actual artifact and verification output, versions, token usage, and every manual intervention. A UI preview or receipt is not autonomous success.
- Diagnose exact failures from both sessions, patch the responsible component, and repeat the failed scenario. Keep unresolved behavior explicit.
## Appendix (context, not approved)
Branch: `experiment/main-supervisor-visible-worker`, based on `2a7c490`. Existing unrelated dirty files are preserved. [Initial trial and interview](../reviews/20260910_edxeth_ui_trial/notes.md). Wassname approved proceeding with "sounds good"; isolated lifecycle validation is first. Wassname then approved permissive supervisor plan/completion ownership and implementation with "so yes, do it". Lifecycle reports: [observed test](../reviews/20260910_edxeth_ui_trial/interactive-lifecycle.md), [runtime and pair-script contract](../reviews/20260910_edxeth_ui_trial/minimal-runtime-contract.md).
-- Pi/OpenAI
@@ -1,40 +0,0 @@
# Visible Pi worker extensions
Question: can a strong main Pi session supervise a cheaper, visible worker Pi session, with prompts that can be edited as files?
## Observations
### edxeth/pi-subagents — <https://github.com/edxeth/pi-subagents>
- The README states: "Interactive children open in Herdr, cmux, tmux, zellij, or WezTerm; background children run headlessly."
- Its `Orchestrator` mode removes the parent's file and shell tools. `src/runtime/orchestrator-prompt.ts` says: "You are an orchestrator ... You do not inspect files, run commands, edit code, or perform implementation work yourself."
- Agent definitions are Markdown files in `.pi/agents/` or the global Pi agent directory. Their frontmatter contains `model`, `mode`, `tools`, and `session-mode`. Thus a project can keep its worker prompt and cheap-worker model in one editable file.
- The package requires Pi `>=0.85.0`; the observed local Pi version is `0.85.1`. Interactive Herdr placement is source-tested (`scripts/test-live-herdr-*.mjs`).
- GitHub API observation: 120 stars; 5 non-bot contributors; created 2026-04-16; latest code commit 2026-09-07; 2 open / 23 closed issues.
- Risk: this package uses the npm name `pi-subagents`, which is also the name of the installed Nicobailon extension. The two export overlapping tools. They should not be loaded together.
### giuseppecrj/pi-herdr-agents — <https://github.com/giuseppecrj/pi-herdr-agents>
- The README states: "Each child runs as a real Pi process in its own Herdr surface" and documents non-blocking result delivery, live child state, and model-bearing role files.
- This is a smaller, Herdr-only alternative. It supplies visible worker panes, but static source inspection did not find the strict delegation-only parent role that `edxeth/pi-subagents` provides.
- GitHub API observation: 18 stars; 2 non-bot contributors; created 2026-08-05; latest code commit 2026-09-09; 5 open / 40 closed issues. Its declared peers are unconstrained, although development dependencies target Pi 0.84, so Pi 0.85.1 compatibility is not directly declared.
### tintinweb/pi-subagents — <https://github.com/tintinweb/pi-subagents>
- The README documents a FleetView and a "live, auto-updating conversation" overlay with steering. This is close if one TUI view is sufficient, but it is not a separately switchable worker Pi pane.
- It supports Pi `>=0.84.0`. GitHub API observation: 1,111 stars; 27 non-bot contributors; latest code commit 2026-09-03; 54 open / 46 closed issues.
### Installed nicobailon/pi-subagents — <https://github.com/nicobailon/pi-subagents>
- The README documents `/subagents-fleet`: "browse children, read transcripts, steer a running child, or stop a run." This corrects the narrower claim that it cannot expose worker activity, but it remains an inspector/overlay rather than an independent Pi terminal surface.
- GitHub API observation: 3,518 stars; latest code commit 2026-09-09. It is already installed locally.
## Inference
`edxeth/pi-subagents` is the closest existing implementation (very probable, about 90%): it directly combines a strict main-session coordinator with an interactive real Pi worker in a Herdr pane, per-role models, and Markdown agent prompts. It is a better simplification target than adding another supervisor process to `pi-goals`.
Important gap: its parent orchestrator prompt is bundled in TypeScript, though Pi's `APPEND_SYSTEM.md` can extend it. The role prompt of the worker is directly editable as `.pi/agents/worker.md`. It does not promise a bespoke compaction policy such as "every 150k"; child sessions use Pi's native compaction plus its own context-warning policy.
Static source and metadata inspection only; no candidate was installed or executed.
-- PI[openai-codex]
@@ -1,65 +0,0 @@
---
requested_model: deepseek/deepseek-v4-pro-0813
mode: code review
input: src/worker.ts, src/supervisor-runtime.ts
trace: omitted from git (11 MB raw provider transcript)
generated: 2026-09-06T04:44:52.809370+00:00
---
# MoA fragility review
Decision: reject the current fix and replace duplicate async lifecycle state with one synchronous worker tool.
Strongest objection: if a truly synchronous worker RPC is unavailable, this simplification blocks the intended parallel supervision model.
Next check: read the goal-worker tool implementation and the three failing test transcripts before deleting code.
Smallest recommended architecture:
The supervisor extension must not store worker lifecycle state. Lifecycle is owned by the subagent runtime. Move ownership into one tool boundary.
1. Delete NESTED_STATE persistence, event listeners, pending reconciliation, CheckWorkerState, and the replacement guard from supervisor-runtime.ts.
2. Add a single supervisor tool:
- RunGoalWorker: starts and awaits a goal-worker synchronously, using the aggregate output as a tool result.
- Keep one in-memory boolean `workerRunning`, guarded at tool execute start, not relying on event ordering.
3. If that synchronous tool cannot be supported:
- StartGoalWorker returns a run ID as ordinary tool output.
- WaitGoalWorker(runId) blocks on terminal status check.
- ApproveGoal always calls bg_wait on the ID from StartGoalWorker or WaitGoalWorker; otherwise approval fails.
Because existing failure 2 came from the runtime blocking on a mismatched ID, the important property is:
- an ID not produced by StartGoalWorker/WaitGoalWorker may not be used for bg_wait;
- a failed wait must clear any in-process guard immediately;
- an await cover failure must be treated as a terminal error, not as `pending`.
Exact deletions/changes:
In `src/supervisor-runtime.ts`:
- Remove `NESTED_STATE`, `NestedState`, `nested`, `persist`, `targetRun`, `completeNested`, all `subagent:async-*`, process-terminal listeners, and `retainedRunState` reconciliation.
- Remove `pi.events.on("tool_call")` blocks. Replace with allow/deny only: deny edit/write, allow read-only bash, allow RunGoalWorker, allow bg_wait, allow ApproveGoal, deny subagent action tools.
- Replace CheckWorkerState with nothing. State inspection is only through normal async progress updates.
- ApproveGoal asserts no active await cover currently exists from RunGoalWorker or WaitGoalWorker, processWorkState is idle, worktree is clean, and evidence inspection claims are backed by the actual tool result from RunGoalWorker.
In `src/worker.ts`:
- Drop `retainedRunState` and any pending-closure logic.
- Keep `asyncSnapshot` only for processWorkState, if needed.
Why this removes fragility:
- Duplicate state is gone.
- Lifecycle is only stored in the runtimes tool execution stack.
- Revival cannot resurrect a wrong worker ID unless a new tool starts it.
- Race between event handler and spawn disappears because Start or Wait returns a result synchronously to the model.
Why this may be worse:
- Synchronous wait loses the supervisor's ability to issue corrections inline during progress.
- Parallel instrumented runs cannot be sustained within one tool without exposing `bg_wait` to the model.
- If the model calls WaitGoalWorker with an incorrect ID, it will now fail directly, but the failure must not be caught and retried with a cached ID.
Acceptance test to catch all observed failures:
- Send the supervisor script: `StartGoalWorker``WaitGoalWorker(id)``RunGoalWorker(correction)``ApproveGoal`, where a midway kill drops the terminal event and forces session revival, and then assert the code path stores no `NESTED_STATE`, does not even mention it in the extension memory, and either the worker returns a tool result or the revived session remains in the same `WaitGoalWorker` tool with no retry on an ID not yielded by that tool.
## Completion
- outcome: `completed_after_follow_up`
- trace: omitted from git (11 MB raw provider transcript); this file preserves the complete review answer
@@ -1,58 +0,0 @@
---
requested_model: z-ai/glm-5.3-flash
max_tokens: 4000
final_tokens: 20000
reasoning_effort: low
input_bytes: 5103
trace: /home/code/.pi/agent/git/github.com/wassname/pi-goals/slop/reviews/2026-09-10_glm-5.3-flash_moa_brainstorm_glm_pi_goals_simplicity.trace.jsonl
generated: 2026-09-10T00:43:46.736035+00:00
---
# bounded completion
## First call reasoning
Brainstorm: architectural reductions, discriminating checks, no winner. Be concise but cover compaction, supervisor visibility, recovery, retained context; include implementation error, objective mismatch, unintended learning dynamic with falsifiable predictions.
## First call answer
# `pi-goals` simplification brainstorm — independent, no winner
## Reconstruction (observed vs. inferred)
**Observed:** two visible sessions; explicit plan state machine; recent fixes are mostly *edge-case patches* (retry bounds, retained steer, benign-error whitelists, threshold skips); compaction logic is duplicated in worker and supervisor with three separate guard conditions; recovery currently requires session reload.
**Inferred:** the system's complexity is concentrated exactly where the Pi core API is ambiguous (token estimates, compaction errors, disconnection states). The fixes treat symptoms of one root ambiguity: *the code reasons about context size it cannot actually observe, and about liveness it cannot actually verify.*
---
## Candidate reductions
### R1 — Delete pre-emptive compaction entirely; compact reactively on provider failure only
**Mechanism (implementation error candidate):** token counts are estimates; a wrong threshold either wastes a compaction (losing supervisor-facing detail) or misses, and the benign-error whitelist (`Already compacted` / `Nothing to compact`) converts a *miswired call* into silence. Falsifiable prediction: if the 100k estimate is ever wrong by >15%, the supervisor inherits a truncated plan that still passes sign-off because the compaction summary restates the plan header.
**Cheapest check:** in one isolated UAT, log the *actual* session entry count before/after each `ctx.compact` call vs. the estimated token figure. If estimated-100k sessions compact "nothing" while estimated-95k sessions compact real content, the threshold is measuring noise.
**What this removes:** three guard branches, two error whitelists, `compactApprovedWorker` as a concept.
### R2 — Single source of truth: the plan document *is* the recovery state
**Mechanism (objective mismatch candidate):** the supervisor's implicit objective ("retain judgment") is implemented as "retain transcript," so it must survive disconnects via handshakes and retries. If the objective were "retain the signed-off plan + latest steer," the transcript becomes disposable. Falsifiable prediction: after any crash/restart of *either* session, a plan-doc-only recovery reproduces the same next decision as full-transcript recovery in ≥90% of UAT replays; where it differs, the difference is always in unverifiable narrative, not judgment.
**Cheapest check:** run one UAT, kill the supervisor mid-review, restart it with only the plan file + last steer. Compare its next action to a recorded full-context control run.
**What this removes:** pi-intercom handshake/recovery retry logic, bounded hello retry, "retained newest disconnected steer" as special state — it's just the plan file's last field.
### R3 — Ended worker session = loud terminal state, not a recovery path
**Mechanism (unintended learning/behavioral dynamic candidate):** the supervisor's repeated long status narration during failed delivery looks like an agent *learning* that narration substitutes for action (it receives its own narration back as evidence of work). The current fix (keep latest instruction) addresses the queue, not the loop. Falsifiable prediction: supervisors that fail delivery once generate longer subsequent status messages than controls that never failed — narration length grows with failed attempts.
**Cheapest check:** diff supervisor message lengths before vs. after one injected failed send in an isolated Herdr run. If length grows monotonically, R3's deletion of retry-narration (replace with a single "delivery failed, worker ended" terminal banner) is warranted.
**What this removes:** overnight-instruction queueing; reload/restart becomes the *only* documented path, made loud rather than silent.
### R4 — Unify "solo" and "supervised" into: plan is approved or it isn't
Falsifiable prediction: `CompleteGoal` blocked in solo is equivalent to "no recorded sign-off exists" — i.e., the `solo|supervised` mode flag never changes a decision that the sign-off ledger doesn't already determine. **Check:** grep the codebase for decisions keyed on mode that don't transitively depend on a sign-off or supervisor-liveness fact; if none, delete the mode enum. **Removes:** `supervised | solo` state, loud-solo-fallback special case (falls out of "no sign-off + no supervisor heartbeat = blocked, loudly").
---
## Cross-cutting discriminating check (one run covers R1R4)
One isolated Herdr UAT with instrumentation logging: (a) token estimate vs. actual entries at each compact, (b) supervisor output length per turn, (c) every state-machine transition with its cause. The three predictions above are all falsifiable from this single trace plus the kill-and-restart experiment.
**Explicitly not done:** no compaction extension assumptions, no queue, no winner. R1R4 are independent deletions; each stands or falls on its own check.
## Completion
- outcome: `complete`
- trace: `/home/code/.pi/agent/git/github.com/wassname/pi-goals/slop/reviews/2026-09-10_glm-5.3-flash_moa_brainstorm_glm_pi_goals_simplicity.trace.jsonl`
File diff suppressed because one or more lines are too long
@@ -1,150 +0,0 @@
---
requested_model: moonshotai/kimi-k3
max_tokens: 4000
final_tokens: 20000
reasoning_effort: low
input_bytes: 5103
trace: /home/code/.pi/agent/git/github.com/wassname/pi-goals/slop/reviews/2026-09-10_kimi-k3_moa_brainstorm_kimi_pi_goals_simplicity.trace.jsonl
generated: 2026-09-10T00:43:46.736079+00:00
---
# bounded completion
## First call reasoning
Let me analyze this carefully. This is a bounded decision request asking for an independent scientific brainstorm about how `pi-goals` (a Pi extension providing a worker/supervisor architecture) can become simpler and more robust while preserving user preferences.
The task: propose distinct mechanisms including an implementation error, an objective/gradient mismatch, and an unintended learning dynamic. For each: falsifiable prediction and cheapest discriminating check. State observed vs inferred. Do not choose a winner.
Wait — "objective or gradient mismatch" and "unintended learning dynamic" — these are ML-flavored framings, but this is a software architecture question. The system prompt says "Reconstruct the situation from the supplied evidence. Propose distinct mechanisms, including an implementation error, an objective or gradient mismatch, and an unintended learning dynamic when relevant." Hmm — this seems like a template applied across domains. For a software system, "gradient mismatch" translates to incentive/objective mismatch — the policy objective vs. actual behavior; "learning dynamic" translates to feedback loops / state evolution dynamics where repeated behavior drifts (e.g., status narration spiraling). I should map these onto the software domain sensibly: implementation error (bug), objective mismatch (policy encodes the wrong objective), unintended dynamics (feedback loop in the session state machine, e.g., repeated status narration, compaction thrash).
Let me reconstruct:
**System**: `pi-goals` extension. One worker Pi session, one visible supervisor Pi session (fork) in a Herdr pane. Supervisor retains judgment cheaply (less context, compaction at startup), worker keeps full context.
**Preferences** (AGENTS.md): supervisor visible thinking/messages; autonomous supervision; inspect evidence; steer through worker not take over; normal tools preserved; short judgmental recaps not repeated status.
**Current state machine**: plan state `planning | working`, `supervised | solo`, approval binding, plan version, sign-offs, model role manager, intercom handshake/recovery.
**Recent fixes**: safe bare `/goals`; explicit plan replacement; bounded hello retry (1+2); retained newest disconnected steer; paired signed-off plans; loud solo fallback only after approved plan + supervisor failure; CompleteGoal blocked in solo.
**Compaction**: worker <100k known → skip; ≥100k → compact before forking supervisor; supervisor skips second compaction if inherited ends with compaction entry or <100k; unknown usage → attempt compaction, treat "Already compacted"/"Nothing to compact" as benign. Supervisor also compacts own settled turns at 100k.
**Observed issues**:
1. UAT: "Nothing to compact (session too small)" printed despite continuation — a visible error that confused; fixed with threshold skip. Suggests error classification is fragile (string matching on error messages) and that the code was attempting compaction unnecessarily on small sessions.
2. Supervisor tried to send overnight instruction after worker disconnected; repeated long status narration; couldn't deliver. New code keeps latest instruction and replays on reconnect; ended worker needs reload/restart.
3. Rate limits can look stuck; compaction can time out. Timeout ≠ permanent failure. Policy: preserve plan, loud eventual solo fallback; don't infer approval from draft/cancellation/plan change/model error.
**Constraints**: keep two visible sessions; separate read-only-by-role supervisor; explicit approval + evidence sign-off; prefer deletion and single source of truth; no silent model substitution; don't pretend delivery/recovery; no particular queue/compaction extension; testable in small isolated Herdr; identify what can be removed.
**Deliverables**:
- Architectural reductions
- Distinct mechanisms: implementation error, objective mismatch, unintended dynamic
- For each: falsifiable prediction + cheapest discriminating check
- Observed vs inferred
- No winner
- Decision stated, strongest objection, next check (per system prompt — but the system prompt also says "Do not choose a winner" via the question. The system prompt says "state the decision, strongest objection, and next check." Hmm — tension. The question says "Do not choose a winner." The system prompt says state the decision. I can reconcile: the decision requested is *how to approach simplification* — i.e., propose reductions and discriminating checks; the "decision" I can state is a bounded recommendation of which reductions are candidates, while explicitly not choosing among the causal mechanisms. Or interpret "the decision" as the answer to the question: the set of proposed reductions. I'll state the decision as: adopt deletion-first reductions gated on discriminating checks, and enumerate candidate mechanisms without ranking them as causes. Actually, better: state a bounded decision like "the safest reduction set is X, but which failure mechanism dominates is undecided — here's the check." That satisfies both.
Let me now think substantively about the architecture.
### Architectural reduction candidates
1. **Single source of truth for compaction decisions.** Currently compaction logic is spread: `compactApprovedWorker` in index.ts, supervisor startup skip logic in supervisor-session.ts, threshold constant 100k duplicated implicitly, error classification by string matching. Reduction: one module/function `shouldCompact(usage)` returning `skip | compact | attempt-benign`, used by both worker pre-fork and supervisor startup. Even better: **delete the unknown-usage compaction attempt entirely** — if usage is unknown, don't compact; compaction is only needed to fit the supervisor fork cheaply, and if usage is unknown, attempting and swallowing string-matched errors is fragile. Cheapest check: remove unknown-usage attempt, run UAT with unknown usage, confirm no error and supervisor still functions. But risk: unknown usage could be huge → supervisor fork inherits huge context → expensive. Alternative: when unknown, treat as ≥100k and compact but rely on Pi API error types rather than message strings... but the code "only uses the Pi API" — if Pi API doesn't expose typed errors, string matching is all there is. Prediction: if error classification is string-based, any Pi version changing message text breaks benign classification → visible failures. Check: unit-test classifier against both message variants; grep Pi's error strings.
2. **Compaction ownership: supervisor's own settled-turn compaction at 100k** duplicates worker logic. Reduction: the supervisor could reuse the same threshold function. Or delete supervisor-side compaction entirely and let Pi's native compaction handle it? Constraint says code depends only on Pi API and ordinary compaction events — supervisor compaction at settled turns 100k is custom. Is it needed? The supervisor is supposed to be cheap and retain judgment. Maybe keep but unify.
3. **State machine reduction**: `planning | working` × `supervised | solo` + approval binding + plan version + sign-offs + role manager + handshake/recovery. This is a lot of orthogonal state. Reduction: collapse to a single immutable plan record: `{ objective, version, approval?: {evidence, signoff, supervisorId}, status: draft|approved|complete }` and derive mode: `mode = approved ? (supervisorAlive ? supervised-working : loud-solo) : planning`. I.e., **derive, don't store** — solo/supervised as derived from liveness + approval, not stored flags that can desync. Falsifiable: desync bugs (stored solo flag persisting after supervisor reconnect) disappear if derived. Check: after supervisor reconnect, does code path that reads mode recompute it? Test: kill supervisor, reconnect, verify mode flips without manual reset.
4. **Recovery reduction**: retained newest disconnected steer + replay after reconnect + ended session requires reload. Instead of a retained-steer buffer, make steering idempotent: the steer is just the latest supervisor message; on reconnect, worker re-reads the plan record which contains pending supervisor directive. One source of truth: the plan record, not a separate buffer. Check: disconnect mid-steer, reconnect, verify exactly-once delivery and no duplication with the buffer removed.
5. **Handshake reduction**: bounded hello retry (1+2). Could be deleted in favor of deriving readiness from the fork event/stream — if Pi emits a settled/first-token event, wait for that rather than hello handshake. Check: remove hello, rely on session-ready event; UAT Ready→visible supervisor timing. But "do not request files or defer" — fine, this is a proposal.
### Mechanisms (three required genres)
**A. Implementation error (bug class)**: Error-classification by string matching (`Already compacted` / `Nothing to compact`) — observed fact 7 shows the error surfaced visibly *despite continuation* before the threshold skip, meaning the "benign" acceptance either wasn't hit on that path or the error was logged by Pi core itself (visible print) rather than thrown to the extension. Note the nuance: the error was *visibly printed by Pi* — "Pi visibly printed Error: Compaction failed" — so the extension may have accepted it as benign, but Pi's own logging surfaced it to the user. That's an observed/inferred split: observed = error text appeared; inferred = it came from Pi core logging, not extension. The threshold skip masks rather than fixes the classification fragility. Falsifiable prediction: on a Pi version that rewords these errors (e.g., "nothing to compact" lowercase, or localized), the benign path fails and compaction errors propagate or retry storms occur. Cheapest check: grep Pi's installed source for the exact strings; run a tiny session under the threshold boundary and an unknown-usage session; assert the extension's classifier matches Pi's actual error text. Also: supervisor startup skip checks "inherited context ends in a compaction entry" — an ordering assumption; if any entry appends after compaction (e.g., a system note), the skip fails and a second compaction runs. Prediction: append a post-compaction entry → supervisor double-compacts. Check: fork with inherited compaction + one trailing entry; count compact calls.
**B. Objective/gradient mismatch (policy encodes wrong objective)**: The supervisor's behavioral objective as prompted — "supervise autonomously, inspect evidence, steer" — combined with delivery-obligation (retained steer, replay) can produce **delivery-attempt narration**: fact 8 shows repeated long status narration when it could not deliver. The policy treats "supervisor must act/steer" as the objective, but the user preference is "short judgmental recaps rather than repeated unchanged status." So the mismatch: the system optimizes for *attempted steering / visible activity* rather than *information gain per token*. The threshold skip is another example: the objective "avoid compaction errors" was met by skipping compaction, but the actual objective should be "don't surface noise; compact only when needed for cost" — the fix optimized error suppression not correctness (it masks classification fragility). Also "loud solo fallback" vs "must not infer approval": timeout ≠ failure, yet a timeout-triggered solo fallback *is* an inference from ambiguous evidence — the policy must choose a decision threshold; current policy (preserve plan, loud fallback) is fine but the *trigger* conditions (what counts as supervisor failure vs slow) are a mismatch risk: treating rate-limit-stuck as failure flips to solo, which then blocks CompleteGoal — a supervisor that's merely slow degrades the whole workflow. Falsifiable prediction: inject a slow-but-alive supervisor (rate-limit delay); system flips to solo and CompleteGoal becomes blocked even though supervisor later approves — or, if fallback is only manual, no flip occurs; check which. Cheapest check: UAT with a delayed supervisor response (sleep injection), observe mode transitions and whether approval after timeout is accepted or rejected.
**C. Unintended learning/feedback dynamic (state evolution loop)**: No gradient learning here, but dynamic analogs: (1) **Narration spiral**: supervisor can't deliver → generates status → status consumes context → supervisor compacts at 100k → compaction may time out (fact 9) → more failure → more narration. A positive feedback loop where failure increases the supervisor's own context pressure, increasing future failure probability. (2) **Compaction thrash**: supervisor compacts own settled turns at 100k; each compaction summary plus recap grows toward threshold again; with "recaps that repeat plan outcome" the context re-approaches 100k cyclically, and each compaction risks timeout; unknown-usage attempts add benign-error noise. (3) **Retained-steer replay**: on reconnect, replay of newest steer + supervisor seeing replayed steer may re-generate another steer, which gets retained, replayed... a steer regeneration loop if delivery state isn't recorded. Falsifiable prediction: with a worker that disconnects for N minutes and supervisor that narrates on each failed delivery, supervisor token usage grows superlinearly and compaction events cluster; after fix (deliver-or-defer single attempt, quiet), narration count per disconnect window = ≤1. Cheapest check: scripted disconnect scenario, count supervisor messages and compaction events with timestamps; check for replayed-steer duplication in worker log (same steer id twice).
### Observed vs inferred
Observed: facts 110, excerpts. Inferred: error came from Pi core logging; narration spiral causal loop; desync risk of stored mode flags; the threshold skip masking classifier fragility; supervisor-side settled-turn compaction being redundant.
### Strongest objection
To the deletion-first reduction: deleting stored mode flags and handshake/retained-steer machinery removes explicit recovery guarantees — derived state can't distinguish "supervisor never started" from "supervisor died," and deleting the bounded hello could regress the Ready→visible-supervisor UAT. Also unknown-usage compaction deletion risks an expensive giant fork. And constraint: "do not pretend recovery succeeded" — deletion must not weaken the loud fallback.
### Next check
The single cheapest discriminating experiment: an isolated Herdr UAT matrix of 4 cells: {known <100k, known ≥100k, unknown usage} × {normal, supervisor-delayed} — count compaction calls, visible errors, mode transitions, approval acceptance. Or simpler: the disconnect/narration count test. Pick one: I'd say the smallest is the compaction-call counting test across the three usage states since it needs no fault injection, just instrumentation (log every ctx.compact call + every visible error). That discriminates mechanism A. For B/C need delay/disconnect injection. Recommend ordering: instrument first (cheap, read-only), then fault injection.
Also: propose concrete deletions list:
- Delete: unknown-usage compaction attempt (or reduce to "log and proceed").
- Delete: duplicated threshold logic → one function.
- Delete: stored `supervised | solo` flag → derive from supervisor liveness + approval presence.
- Delete: separate retained-steer buffer → fold pending directive into plan record (single source of truth).
- Possibly delete: supervisor startup inherited-compaction ordering check → replace with explicit marker/metadata passed at fork time (the worker knows it just compacted; pass a boolean rather than inspecting entry ordering). That's a nice reduction: replace inference-from-transcript with explicit handoff state. Prediction: fork marker removes ordering fragility; check: append trailing entry, confirm no double compaction.
- Handshake: keep bounded hello but derive readiness from intercom ack event rather than retry count? Or keep — it's already bounded. The retry (1+2) could be deleted in favor of: supervisor announces readiness as its first visible message (which is required anyway by visibility preference) — the hello is then observable, not a separate protocol. Merge handshake into the mandatory visible opening.
Also the "model role manager" — unclear what it does; flag as candidate for deletion if it duplicates Pi's own model selection; constraint says don't silently substitute models.
Format: This needs headers, structured. Length: substantial but bounded. Use sections: Reconstruction; Observed vs inferred; Candidate reductions (deletion-first); Mechanisms A/B/C each with prediction + cheapest check; Strongest objection; Next check. Maybe a small table for mechanisms. Keep it tight. No choosing a winner — present mechanisms as competing, note what evidence would discriminate.
The system prompt asks to "state the decision" — I'll state: the decision supported by evidence alone is to adopt the deletion-first reduction set (they're low-regret regardless of which mechanism dominates), while the causal attribution among A/B/C remains open pending checks. That's the bounded decision. Strongest objection to that. Next check.
Let me draft.
Word budget: this is complex; ~9001300 words. Use headers and compact bullets. A table for mechanisms could work well.
## First call answer
# Reconstruction (observed vs. inferred)
**Observed:** A two-session worker/supervisor extension with explicit plan state, approval binding, handshake/recovery, and threshold-based compaction at 100k. Three field anomalies: (1) a visible `Nothing to compact` error from Pi on a small session, suppressed by a threshold skip; (2) an undeliverable overnight steer producing repeated long status narration; (3) rate limits and compaction timeouts that are indistinguishable from stuckness.
**Inferred (not observed):** that the visible compaction error originated in Pi core logging rather than extension failure; that stored mode flags can desync from liveness; that narration forms a feedback loop with compaction pressure; that the threshold skip masks a fragile error classifier rather than fixing one.
# Candidate architectural reductions (deletion-first)
1. **One compaction oracle.** Collapse the threshold constant, the worker pre-fork path, the supervisor startup skip, and the unknown-usage attempt into a single `shouldCompact(usage): skip | compact` used by both sessions. Delete the unknown-usage compaction attempt: it exists only to be swallowed, and its error classification is string matching. If usage is unknown, log loudly and proceed; a too-large fork is a cost problem, not a correctness problem.
2. **Replace inference-from-transcript with explicit handoff.** The supervisor startup skip inspects whether inherited context *ends in* a compaction entry — an ordering assumption. The worker knows whether it just compacted; pass a boolean at fork time. Delete the transcript-tail inspection.
3. **Derive mode, don't store it.** `supervised | solo` and `planning | working` are stored flags that can desync from supervisor liveness and approval state. Derive: `mode = approved(plan) ? (supervisorAlive ? supervised : loud-solo) : planning`. One immutable plan record `{objective, version, approval{evidence, signoff}, status}` is the single source of truth.
4. **Fold the retained-steer buffer into the plan record.** A separate newest-steer buffer is a second source of truth for "what the supervisor wants." Store the pending directive (with a delivery marker) on the plan record; replay is then re-reading state, not a queue.
5. **Merge the handshake into the mandatory visible opening.** The supervisor must visibly announce itself anyway (user preference). Its first visible message *is* the readiness signal; the separate hello + two retries can be deleted or reduced to "wait for first settled turn."
6. **Interrogate the model role manager.** If it duplicates Pi's own model selection, delete it; the constraint against silent model substitution argues for less machinery here, not more.
# Competing mechanisms
| # | Mechanism | Class | Falsifiable prediction | Cheapest
## Final answer call answer
# Reconstruction (observed vs. inferred)
**Observed:** A two-session worker/supervisor extension with explicit plan state, approval binding, handshake/recovery, and 100k-threshold compaction. Three field anomalies: (1) a visible `Nothing to compact` error on a small session, suppressed by a threshold skip; (2) an undeliverable overnight steer producing repeated long status narration; (3) rate limits and compaction timeouts indistinguishable from stuckness.
**Inferred (not observed):** that the compaction error logging originates in Pi core, not extension failure; that stored mode flags can desync from actual liveness; that narration forms a feedback loop with compaction pressure; that the threshold skip masks a fragile error classifier rather than fixing one.
# Candidate architectural reductions (deletion-first)
1. **One compaction oracle.** Collapse the 100k constant, worker pre-fork path, supervisor startup skip, and unknown-usage attempt into a single `shouldCompact(usage): skip | compact` used by both sessions. Delete the unknown-usage compaction attempt — it exists only to be swallowed via string-matching on `Already compacted` / `Nothing to compact`. If usage is unknown, log loudly and proceed; an oversized fork is a cost problem, not a correctness problem.
2. **Replace inference-from-transcript with explicit handoff.** The supervisor startup skip inspects whether inherited context *ends in* a compaction entry — an ordering assumption. The worker knows whether it just compacted; pass a boolean at fork time. Delete the transcript-tail inspection.
3. **Derive mode, don't store it.** `supervised | solo` and `planning | working` are stored flags that can desync from supervisor liveness and approval state. Derive: `mode = approved(plan) ? (supervisorAlive ? supervised : loud-solo) : planning`. One immutable plan record `{objective, version, approval{evidence, signoff}, status}` is the single source of truth.
4. **Fold the retained-steer buffer into the plan record.** A separate newest-steer buffer is a second source of truth for "what the supervisor wants." Store the pending directive (with a delivery marker) on the plan record; replay is then re-reading state, not a queue.
5. **Merge the handshake into the mandatory visible opening.** The supervisor must visibly announce itself anyway (user preference). Its first visible message *is* the readiness signal; the separate hello + two retries can be deleted or reduced to "wait for first settled turn."
6. **Interrogate the model role manager.** If it duplicates Pi's own model selection, delete it; the constraint against silent model substitution argues for less machinery here, not more.
# Competing mechanisms
| # | Mechanism | Class | Falsifiable prediction | Cheapest discriminating check |
|---|---|---|---|---|
| 1 | **String-matched error classification is fragile.** The code swallows `Nothing to compact` / `Already compacted` by matching error text. Pi core may change message wording; the extension then treats benign cases as failures. | Implementation error | Search Pi core source for those exact strings; if they appear in a `throw` path with different surrounding text, or in a localization/template layer, classification breaks. | `grep` Pi core for the two strings; check if they're template literals or constants. If the strings are constructed dynamically, the classifier is brittle. |
| 2 | **Threshold skip masks the real compaction signal.** The 100k threshold suppresses compaction attempts on small sessions, but the real failure mode is "Pi core logs an error for a benign no-op." The threshold skip silences the symptom without fixing the classifier. | Objective mismatch (proxy metric) | If the threshold were removed and the classifier made robust, small sessions would attempt compaction, receive `Nothing to compact`, and continue silently. If they instead *fail loudly*, the threshold was load-bearing. | In an isolated Herdr session with < 100k tokens, remove the threshold skip and call `ctx.compact`. Observe whether Pi logs the error or fails the call. |
| 3 | **Mode flags desync from liveness.** `supervised | solo` is stored state; if the supervisor process dies or disconnects without updating the flag, the worker may believe it's supervised when it isn't (or vice versa). | Implementation error (state synchronization) | If the stored mode and actual supervisor process liveness can diverge, there exists a sequence where the worker blocks `CompleteGoal` (thinking it's solo) while the supervisor is alive, or allows it (thinking it's supervised) while the supervisor is dead. | In a test, kill the supervisor process without clean shutdown; check whether the worker's stored mode updates. If it doesn't, the flag is stale. |
| 4 | **Supervisor narration creates a context-pressure feedback loop.** Repeated long status messages (field report #8) consume supervisor context, pushing it toward the 100k compaction threshold, which triggers compaction, which loses nuance, which may cause more verbose re-explanation. | Unintended learning dynamic (emergent from interaction) | If narration length correlates with time-since-last-compaction, and compaction frequency correlates with narration verbosity, the loop is active. | Log supervisor token usage and narration length over a long session. If they trend upward together and reset after compaction, the loop is confirmed. |
| 5 | **Overnight steer failure reveals missing delivery acknowledgment.** The supervisor generated repeated narration because it received no signal that the worker was disconnected. The fix (retain newest steer) is correct but incomplete: the supervisor still doesn't know *whether* delivery succeeded after replay. | Implementation error (missing ack) | If the worker reconnects and the supervisor replays the steer, but the worker has already completed the goal or moved on, the replayed steer is now stale and potentially harmful. | In a test, disconnect the worker, let the supervisor queue a steer, reconnect the worker *after* it would have completed the goal solo, and observe whether the replayed steer causes confusion or incorrect behavior. |
| 6 | **Compaction timeout conflated with permanent failure.** Field report #9 notes rate limits and compaction timeouts "can appear stuck." If the supervisor compaction times out and the worker interprets this as supervisor failure, it may incorrectly trigger solo fallback. | Objective mismatch (timeout as proxy for failure) | If a supervisor compaction timeout is followed by eventual success (the compaction completes after the timeout), but the worker has already fallen back to solo, the timeout was misclassified.
## Completion
- outcome: `completed_after_follow_up`
- trace: `/home/code/.pi/agent/git/github.com/wassname/pi-goals/slop/reviews/2026-09-10_kimi-k3_moa_brainstorm_kimi_pi_goals_simplicity.trace.jsonl`
File diff suppressed because one or more lines are too long
@@ -1,20 +0,0 @@
## Review
No issues found.
- Correct: The packaged worker is discoverable in pi-subagents 0.65.1 child-safe fanout. `package.json` exposes `pi.subagents.agents`, which the installed discovery code consumes (`pi-subagents/src/agents/agents.ts:510-538,597-657`), while the child fanout executor uses normal `discoverAgents` (`pi-subagents/src/extension/fanout-child.ts:145-190`).
- Correct: The supervisor gate requires the exact packaged agent, nonempty task, `async:false`, `context:"fork"`, and the configured model with no extra fields (`src/supervisor-runtime.ts:83-108`). The installed executor honors explicit foreground mode (`pi-subagents/src/runs/foreground/subagent-executor.ts:6511-6515,6917-6920`).
- Correct: Foreground completion is tied to the real `tool_result`. `activeWorkerCalls` is removed only when that result arrives, successful completion is recorded, and approval requires a later turn (`src/supervisor-runtime.ts:75-115,132-138`). Same-message worker launch plus approval is independently rejected by inspecting the assistant message.
- Correct: Stale local launch reservations self-heal: errors clear on `tool_result`, and `turn_start` clears any reservation for which no result hook arrived (`src/supervisor-runtime.ts:75-115`). The tests cover duplicate launch, failed-result recovery, and next-turn recovery (`test/supervisor-runtime.test.ts:57-76`).
- Correct: `CompleteGoal` remains blocked while the retained supervisor is pending, while any subagent/process work is active or unknown, or until a matching approval checkpoint exists (`src/index.ts`, `CompleteGoal`). Foreground nested work therefore cannot race sign-off because its containing supervisor run remains pending.
- Correct: `supervisor-runtime.ts` does not perform runtime-agent registration. The main extension exits in child processes through `isSupervisorProcess`, while installed pi-subagents itself is inert when `PI_SUBAGENT_CHILD=1` (`src/index.ts`, `isSupervisorProcess`; installed `pi-subagents/index.ts:3-8`).
- Correct: The former nested async worker ID/pending lifecycle is absent. The remaining `workerRunId`/`workerPending` state belongs only to the retained supervisor lifecycle, matching the documented topology.
Residual risks:
- `test/package-agent.test.ts` verifies packaging statically rather than launching the packaged worker through the real child-safe fanout runtime. The installed 0.65.1 source supports the configuration, but retaining an RPC integration check is advisable.
- The focused approval tests mock Pis `tool_call`/`tool_result` ordering. A real RPC test remains the strongest guard against upstream lifecycle-event changes.
- Tests were inspected but not executed in this review environment; the supervisor should run `npm test`, `npm run typecheck`, and `npm run lint`.
- Merge verdict: **OK with residual test-environment risks.**
-- PI[reviewer/gpt-5.6-sol]
@@ -1,105 +0,0 @@
> @wassname2/pi-goals@0.2.2 test
> vitest run --run test/force-approval-flow.test.ts test/approval.test.ts test/supervisor-session.test.ts test/goals-flow.test.ts --reporter=verbose
RUN v4.1.9 /home/code/.pi/agent/git/github.com/wassname/pi-goals
✓ test/approval.test.ts > hashes only the current goal, excluding the log, interview, and their historical goal text 6ms
stdout | test/force-approval-flow.test.ts > force ApproveGoal -> CompleteGoal accepts only the reviewed dirty state without committing or modifying it
Force UAT: paired real handlers accepted unchanged tracked + untracked dirty content; Git HEAD and user files stayed unchanged.
✓ test/force-approval-flow.test.ts > force ApproveGoal -> CompleteGoal accepts only the reviewed dirty state without committing or modifying it 108ms
✓ test/goals-flow.test.ts > /goals flow > reports actual idle state, invalidates stopped views on start, and stops completed plans 41ms
✓ test/goals-flow.test.ts > /goals flow > preserves drafts, records the interview, and keeps planning read-only 20ms
✓ test/goals-flow.test.ts > /goals flow > forks a visible supervisor on Ready and keeps the main session as worker 35ms
✓ test/force-approval-flow.test.ts > invalidates forced approval after changed tracked content 99ms
✓ test/goals-flow.test.ts > /goals flow > starts work only after the supervisor launcher resolves 24ms
✓ test/goals-flow.test.ts > /goals flow > delivers an Intercom instruction to the worker 25ms
✓ test/goals-flow.test.ts > /goals flow > closes the supervisor on clear but keeps the plan file 23ms
✓ test/goals-flow.test.ts > /goals flow > accepts only an approval for the exact clean commit and goal block 64ms
✓ test/goals-flow.test.ts > process role > keeps subagent children and visible supervisors out of the worker extension 0ms
✓ test/goals-flow.test.ts > restores working linkage even when its remembered model is unavailable, and supports explicit recovery 24ms
✓ test/goals-flow.test.ts > restores planning linkage even when its remembered model is unavailable, and supports explicit recovery 23ms
✓ test/goals-flow.test.ts > shows a missing resumed supervisor, pauses writes, and automatically unpauses when that peer returns 25ms
✓ test/force-approval-flow.test.ts > invalidates forced approval after changed untracked content 82ms
✓ test/force-approval-flow.test.ts > invalidates forced approval after changed new untracked 83ms
✓ test/goals-flow.test.ts > times out stale Ready retries in five seconds, without replacing the pane automatically 35ms
✓ test/goals-flow.test.ts > explicitly restarts only the tracked pane, keeps the plan, and invalidates old approval binding 24ms
✓ test/goals-flow.test.ts > does not persist startup results or launch work after session shutdown 21ms
✓ test/goals-flow.test.ts > keeps a failed Ready model not-ready and recovers the same real supervisor binding 26ms
✓ test/goals-flow.test.ts > points a present-but-paused peer recovery at the supervisor pane 17ms
✓ test/goals-flow.test.ts > clear during the initial Ready wait cancels immediately and cannot resurrect the plan 21ms
✓ test/goals-flow.test.ts > clear before the launcher resolves rejects late pane callbacks without restoring the binding 21ms
✓ test/force-approval-flow.test.ts > invalidates forced approval after changed deleted untracked 62ms
✓ test/force-approval-flow.test.ts > invalidates forced approval after changed index only 65ms
✓ test/force-approval-flow.test.ts > invalidates forced approval after changed rename 74ms
✓ test/force-approval-flow.test.ts > invalidates forced approval after changed HEAD 80ms
✓ test/force-approval-flow.test.ts > invalidates forced approval after changed goal 79ms
✓ test/force-approval-flow.test.ts > force does not bypass the evidence gate 44ms
✓ test/supervisor-session.test.ts > visible supervisor session > restores monitoring and read-only tools without replaying persisted views 10ms
✓ test/supervisor-session.test.ts > visible supervisor session > renders all advice in real Pi tool rows, including collapsed and restored rows 43ms
✓ test/supervisor-session.test.ts > visible supervisor session > asks for judgment and useful recaps without inventing instructions 1ms
✓ test/supervisor-session.test.ts > visible supervisor session > writes readiness only after removing writing tools 7ms
✓ test/supervisor-session.test.ts > visible supervisor session > compacts a large planning fork before writing readiness 2ms
✓ test/supervisor-session.test.ts > visible supervisor session > does not become ready when initial compaction fails 2ms
✓ test/supervisor-session.test.ts > visible supervisor session > writes a durable worker instruction 2ms
✓ test/force-approval-flow.test.ts > force does not bypass the verification gate 47ms
✓ test/force-approval-flow.test.ts > force does not bypass the stopped view gate 29ms
✓ test/force-approval-flow.test.ts > force does not bypass the tool call gate 21ms
✓ test/force-approval-flow.test.ts > force does not bypass the unknown tracker gate 27ms
✓ test/force-approval-flow.test.ts > force does not bypass the active tracker gate 28ms
✓ test/supervisor-session.test.ts > visible supervisor session > records approval only from a stopped view with evidence and no active work 98ms
✓ test/supervisor-session.test.ts > blocks the general intercom actuator even if enabled after startup 2ms
✓ test/supervisor-session.test.ts > keeps a supervisor unready after model restoration failure, then recovers explicitly without substituting a model 2ms
✓ test/supervisor-session.test.ts > warns once on unavailable usage but stays quiet for Pi's post-compaction null token sample 3ms
Test Files 4 passed (4)
Tests 45 passed (45)
Start at 06:14:52
Duration 1.54s (transform 492ms, setup 0ms, import 2.27s, tests 1.58s, environment 0ms)
> @wassname2/pi-goals@0.2.2 typecheck
> tsc --noEmit
> @wassname2/pi-goals@0.2.2 lint
> biome check src/ test/
src/approval.ts:42:7 lint/suspicious/noImplicitAnyLet ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
× This variable implicitly has the any type.
40 │ const files = paths.map((path): WorktreeSnapshot["files"][number] => {
41 │ const fullPath = join(repoRoot, path);
> 42 │ let stat;
│ ^^^^
43 │ try { stat = lstatSync(fullPath); }
44 │ catch (error) {
i Variable declarations without type annotation and initialization implicitly have the any type. Declare a type or initialize the variable with some value.
src/approval.ts:56:12 lint/suspicious/noAssignInExpressions ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
× The assignment should not be in an expression.
54 │ const buffer = Buffer.alloc(256 * 1024);
55 │ let bytes: number;
> 56 │ while ((bytes = readSync(fd, buffer, 0, buffer.length, null)) > 0) hash.update(buffer.subarray(0, bytes));
│ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
57 │ } finally { closeSync(fd); }
58 │ return { path, kind: "file", mode, contentHash: hash.digest("hex") };
i The use of assignments in expressions is confusing.
Expressions are often considered as side-effect free.
Checked 33 files in 39ms. No fixes applied.
Found 2 errors.
check ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
× Some errors were emitted while running checks.
-132
View File
@@ -1,132 +0,0 @@
Before validation: pre-existing dirty evidence checksums
a8f1facd16fd6ff2938195a7adbdc3b4b1e1dea61533e90a39e5eb18d201e190 slop/reviews/review-fixes-native/supervisor-events.jsonl
de5bb7171e71508c40e19f3929303a63f1fa0f2ea7789a2bcc8728ea038310d2 slop/reviews/review-fixes-native/worker-events.jsonl
Command: env -u PI_SUBAGENT_CHILD -u PI_GOALS_ROLE -u PI_GOALS_EVIDENCE_DIR npm test -- --reporter=verbose
> @wassname2/pi-goals@0.2.2 test
> vitest run --reporter=verbose
RUN v4.1.9 /home/code/.pi/agent/git/github.com/wassname/pi-goals
✓ test/package-agent.test.ts > package manifest > includes the extension without registering a packaged subagent 3ms
✓ test/prompts.test.ts > planning prompt > requires fact finding or a focused question before a goal 2ms
✓ test/prompts.test.ts > planning prompt > restores the same rule after compaction 1ms
✓ test/prompts.test.ts > planning prompt > anchors work and sign-off to the user-visible result 0ms
✓ test/worker-view.test.ts > keeps human direction and source location while sending only new messages 3ms
✓ test/worker-view.test.ts > restarts after compaction and does not report historical tool calls as active 1ms
✓ test/worker-view.test.ts > bounds serialized Unicode and quoted logs while marking omissions 3ms
stdout | test/role-models.test.ts > remembers each role without automatic switching overwriting another role
Role preferences restored: planning=planner, worker=small-worker, supervisor=astra; restore events did not overwrite the choice.
✓ test/role-models.test.ts > remembers each role without automatic switching overwriting another role 9ms
✓ test/role-models.test.ts > fails on an unavailable remembered model without replacing the choice 4ms
✓ test/intercom.test.ts > pi-intercom transport > receives exact advice once, acknowledges it and rejects unrelated peers 15ms
✓ test/intercom.test.ts > pi-intercom transport > restores an unacknowledged steer on reconnect and stops replay after acknowledgment 5ms
✓ test/intercom.test.ts > pi-intercom transport > advances the incremental overview only after acknowledgment 1ms
✓ test/intercom.test.ts > pi-intercom transport > cancels a readiness wait on shutdown 2ms
✓ test/intercom.test.ts > does not acknowledge a synchronous handoff failure, and retries the instruction 1ms
✓ test/intercom.test.ts > detaches a completed binding and ignores its late advice without replay errors or false acceptance 1ms
✓ test/background.test.ts > reports tracked running work, rather than equating idle agent with finished jobs 110ms
✓ test/background.test.ts > distinguishes missing providers from an unavailable installed tracker 4ms
✓ test/intercom-handshake.test.ts > re-handshakes unchanged peers in either direction without hello ping-pong or lost advice 11ms
✓ test/intercom-handshake.test.ts > replays pending advice and views across either role's own readiness transition 1ms
✓ test/intercom-handshake.test.ts > cancels pending waits immediately on detach or reconfiguration 2ms
✓ test/herdr.test.ts > supervisor pane command > forks the planning session with pi-goals owning its Intercom dependency 8ms
✓ test/herdr.test.ts > supervisor pane command > accepts Herdr's text version output and stale pane cleanup 55ms
✓ test/approval.test.ts > fingerprints literal unusual paths, binary bytes, symlink targets, modes and deletions 177ms
✓ test/approval.test.ts > hashes only the current goal, excluding the log, interview, and their historical goal text 1ms
✓ test/fold.test.ts > foldPlan (current goals are above ## Log; durable memory is below it) > keeps the title, user voice and goals 1ms
✓ test/fold.test.ts > foldPlan (current goals are above ## Log; durable memory is below it) > drops the log, the learnings and the unlimited appendix 0ms
✓ test/fold.test.ts > foldPlan (current goals are above ## Log; durable memory is below it) > returns the whole plan when there is no ## Log yet (a fresh draft) 0ms
✓ test/fold.test.ts > openSubtasks (the widget shows the next action, so the plan IS the task list) > lists the active goal's open and in-progress subtasks, stopping at the next goal 1ms
✓ test/fold.test.ts > openSubtasks (the widget shows the next action, so the plan IS the task list) > does not leak subtasks from the goal below 1ms
✓ test/fold.test.ts > does not show historical Log subtasks under the last active goal 0ms
✓ test/append-log.test.ts > appendLog (the extension's only plan-file write) > creates ## Log at EOF when absent 2ms
✓ test/append-log.test.ts > appendLog (the extension's only plan-file write) > appends after the last existing log line, before any following header 1ms
✓ test/tick-goal.test.ts > tickGoal (sign-off ticks the goal; agent only ticks on wording drift) > ticks the exact-matching goal line, case-insensitive, leaving subtasks alone 2ms
✓ test/tick-goal.test.ts > tickGoal (sign-off ticks the goal; agent only ticks on wording drift) > returns null on wording drift (fuzzy matching is the judge's job, not TypeScript's) 0ms
✓ test/tick-goal.test.ts > tickGoal (sign-off ticks the goal; agent only ticks on wording drift) > returns null when the subject matches more than one goal line 0ms
✓ test/tick-goal.test.ts > tickGoal (sign-off ticks the goal; agent only ticks on wording drift) > ignores a historical duplicate below the Log and leaves it unchanged 0ms
✓ test/goals-flow.test.ts > /goals flow > reports actual idle state, invalidates stopped views on start, and stops completed plans 51ms
✓ test/goals-flow.test.ts > /goals flow > preserves drafts, records the interview, and keeps planning read-only 25ms
stdout | test/intercom-broker.test.ts > exchanges readiness, views and exact advice over a real isolated pi-intercom broker
Intercom broker: readiness confirmed; exact worker view and supervisor advice received.
stdout | test/force-approval-flow.test.ts > force ApproveGoal -> CompleteGoal accepts only the reviewed dirty state without committing or modifying it
Force UAT: paired real handlers accepted unchanged tracked + untracked dirty content; Git HEAD and user files stayed unchanged.
✓ test/force-approval-flow.test.ts > force ApproveGoal -> CompleteGoal accepts only the reviewed dirty state without committing or modifying it 124ms
✓ test/intercom-broker.test.ts > exchanges readiness, views and exact advice over a real isolated pi-intercom broker 425ms
✓ test/goals-flow.test.ts > /goals flow > forks a visible supervisor on Ready and keeps the main session as worker 27ms
✓ test/goals-flow.test.ts > /goals flow > starts work only after the supervisor launcher resolves 28ms
✓ test/goals-flow.test.ts > /goals flow > delivers an Intercom instruction to the worker 20ms
✓ test/goals-flow.test.ts > /goals flow > closes the supervisor on clear but keeps the plan file 22ms
✓ test/force-approval-flow.test.ts > keeps ordinary clean approval unchanged and rechecks runtime state at forced completion 104ms
✓ test/goals-flow.test.ts > /goals flow > accepts only an approval for the exact clean commit and goal block 74ms
✓ test/goals-flow.test.ts > process role > keeps subagent children and visible supervisors out of the worker extension 0ms
✓ test/goals-flow.test.ts > restores working linkage even when its remembered model is unavailable, and supports explicit recovery 27ms
✓ test/goals-flow.test.ts > restores planning linkage even when its remembered model is unavailable, and supports explicit recovery 26ms
✓ test/goals-flow.test.ts > shows a missing resumed supervisor, pauses writes, and automatically unpauses when that peer returns 25ms
✓ test/force-approval-flow.test.ts > invalidates forced approval after changed tracked content 78ms
✓ test/goals-flow.test.ts > times out stale Ready retries in five seconds, without replacing the pane automatically 32ms
✓ test/goals-flow.test.ts > explicitly restarts only the tracked pane, keeps the plan, and invalidates old approval binding 31ms
✓ test/goals-flow.test.ts > does not persist startup results or launch work after session shutdown 27ms
✓ test/goals-flow.test.ts > keeps a failed Ready model not-ready and recovers the same real supervisor binding 32ms
✓ test/force-approval-flow.test.ts > invalidates forced approval after changed untracked content 76ms
✓ test/force-approval-flow.test.ts > invalidates forced approval after changed new untracked 70ms
✓ test/goals-flow.test.ts > points a present-but-paused peer recovery at the supervisor pane 21ms
✓ test/goals-flow.test.ts > clear during the initial Ready wait cancels immediately and cannot resurrect the plan 27ms
✓ test/goals-flow.test.ts > clear before the launcher resolves rejects late pane callbacks without restoring the binding 19ms
✓ test/force-approval-flow.test.ts > invalidates forced approval after changed deleted untracked 61ms
✓ test/force-approval-flow.test.ts > invalidates forced approval after changed index only 63ms
✓ test/force-approval-flow.test.ts > invalidates forced approval after changed index contents 122ms
✓ test/force-approval-flow.test.ts > invalidates forced approval after changed rename 73ms
✓ test/force-approval-flow.test.ts > invalidates forced approval after changed HEAD 67ms
✓ test/supervisor-session.test.ts > visible supervisor session > restores monitoring and read-only tools without replaying persisted views 9ms
✓ test/supervisor-session.test.ts > visible supervisor session > renders all advice in real Pi tool rows, including collapsed and restored rows 26ms
✓ test/supervisor-session.test.ts > visible supervisor session > asks for judgment and useful recaps without inventing instructions 1ms
✓ test/supervisor-session.test.ts > visible supervisor session > writes readiness only after removing writing tools 2ms
✓ test/supervisor-session.test.ts > visible supervisor session > compacts a large planning fork before writing readiness 1ms
✓ test/supervisor-session.test.ts > visible supervisor session > does not become ready when initial compaction fails 2ms
✓ test/supervisor-session.test.ts > visible supervisor session > writes a durable worker instruction 1ms
✓ test/supervisor-session.test.ts > visible supervisor session > records approval only from a stopped view with evidence and no active work 77ms
✓ test/supervisor-session.test.ts > blocks the general intercom actuator even if enabled after startup 2ms
✓ test/supervisor-session.test.ts > keeps a supervisor unready after model restoration failure, then recovers explicitly without substituting a model 2ms
✓ test/supervisor-session.test.ts > warns once on unavailable usage but stays quiet for Pi's post-compaction null token sample 3ms
✓ test/force-approval-flow.test.ts > invalidates forced approval after changed goal 86ms
✓ test/force-approval-flow.test.ts > force does not bypass the evidence gate 51ms
✓ test/force-approval-flow.test.ts > force does not bypass the verification gate 42ms
✓ test/force-approval-flow.test.ts > force does not bypass the stopped view gate 24ms
✓ test/force-approval-flow.test.ts > force does not bypass the tool call gate 25ms
✓ test/force-approval-flow.test.ts > force does not bypass the unknown tracker gate 25ms
✓ test/force-approval-flow.test.ts > force does not bypass the active tracker gate 27ms
✓ test/rpc-review.test.ts > RPC review flow > opens Refine's editor before it starts the revision turn 1856ms
stdout | test/native-intercom.test.ts > runs a forked Pi supervisor and receives its exact instruction in another Pi session
Native Pi pair: fork retained planning context; SteerWorker delivered exactly: Read the real outputs before declaring completion.
✓ test/native-intercom.test.ts > runs a forked Pi supervisor and receives its exact instruction in another Pi session 2941ms
Test Files 18 passed (18)
Tests 85 passed (85)
Start at 06:18:03
Duration 3.48s (transform 3.77s, setup 0ms, import 7.89s, tests 7.45s, environment 2ms)
> @wassname2/pi-goals@0.2.2 typecheck
> tsc --noEmit
> @wassname2/pi-goals@0.2.2 lint
> biome check src/ test/
Checked 33 files in 68ms. No fixes applied.
> @wassname2/pi-goals@0.2.2 build
> tsc
After validation: pre-existing dirty evidence checksums
a8f1facd16fd6ff2938195a7adbdc3b4b1e1dea61533e90a39e5eb18d201e190 slop/reviews/review-fixes-native/supervisor-events.jsonl
de5bb7171e71508c40e19f3929303a63f1fa0f2ea7789a2bcc8728ea038310d2 slop/reviews/review-fixes-native/worker-events.jsonl
@@ -1,122 +0,0 @@
> @wassname2/pi-goals@0.2.2 test
> vitest run --reporter=verbose
RUN v4.1.9 /home/code/.pi/agent/git/github.com/wassname/pi-goals
✓ test/package-agent.test.ts > package manifest > includes the extension without registering a packaged subagent 3ms
stdout | test/role-models.test.ts > remembers each role without automatic switching overwriting another role
Role preferences restored: planning=planner, worker=small-worker, supervisor=astra; restore events did not overwrite the choice.
✓ test/intercom.test.ts > pi-intercom transport > receives exact advice once, acknowledges it and rejects unrelated peers 4ms
✓ test/intercom.test.ts > pi-intercom transport > restores an unacknowledged steer on reconnect and stops replay after acknowledgment 2ms
✓ test/intercom.test.ts > pi-intercom transport > advances the incremental overview only after acknowledgment 1ms
✓ test/intercom.test.ts > pi-intercom transport > cancels a readiness wait on shutdown 1ms
✓ test/intercom.test.ts > does not acknowledge a synchronous handoff failure, and retries the instruction 1ms
✓ test/intercom.test.ts > detaches a completed binding and ignores its late advice without replay errors or false acceptance 1ms
✓ test/role-models.test.ts > remembers each role without automatic switching overwriting another role 32ms
✓ test/role-models.test.ts > fails on an unavailable remembered model without replacing the choice 5ms
✓ test/intercom-handshake.test.ts > re-handshakes unchanged peers in either direction without hello ping-pong or lost advice 9ms
✓ test/intercom-handshake.test.ts > replays pending advice and views across either role's own readiness transition 2ms
✓ test/intercom-handshake.test.ts > cancels pending waits immediately on detach or reconfiguration 2ms
✓ test/worker-view.test.ts > keeps human direction and source location while sending only new messages 3ms
✓ test/worker-view.test.ts > restarts after compaction and does not report historical tool calls as active 1ms
✓ test/worker-view.test.ts > bounds serialized Unicode and quoted logs while marking omissions 3ms
✓ test/approval.test.ts > hashes only the current goal, excluding the log, interview, and their historical goal text 8ms
✓ test/prompts.test.ts > planning prompt > requires fact finding or a focused question before a goal 2ms
✓ test/prompts.test.ts > planning prompt > restores the same rule after compaction 2ms
✓ test/prompts.test.ts > planning prompt > anchors work and sign-off to the user-visible result 0ms
✓ test/herdr.test.ts > supervisor pane command > forks the planning session with pi-goals owning its Intercom dependency 3ms
✓ test/herdr.test.ts > supervisor pane command > accepts Herdr's text version output and stale pane cleanup 51ms
✓ test/background.test.ts > reports tracked running work, rather than equating idle agent with finished jobs 52ms
✓ test/background.test.ts > distinguishes missing providers from an unavailable installed tracker 5ms
✓ test/fold.test.ts > foldPlan (current goals are above ## Log; durable memory is below it) > keeps the title, user voice and goals 2ms
✓ test/fold.test.ts > foldPlan (current goals are above ## Log; durable memory is below it) > drops the log, the learnings and the unlimited appendix 1ms
✓ test/fold.test.ts > foldPlan (current goals are above ## Log; durable memory is below it) > returns the whole plan when there is no ## Log yet (a fresh draft) 0ms
✓ test/fold.test.ts > openSubtasks (the widget shows the next action, so the plan IS the task list) > lists the active goal's open and in-progress subtasks, stopping at the next goal 1ms
✓ test/fold.test.ts > openSubtasks (the widget shows the next action, so the plan IS the task list) > does not leak subtasks from the goal below 1ms
✓ test/fold.test.ts > does not show historical Log subtasks under the last active goal 0ms
✓ test/append-log.test.ts > appendLog (the extension's only plan-file write) > creates ## Log at EOF when absent 2ms
✓ test/append-log.test.ts > appendLog (the extension's only plan-file write) > appends after the last existing log line, before any following header 0ms
stdout | test/intercom-broker.test.ts > exchanges readiness, views and exact advice over a real isolated pi-intercom broker
Intercom broker: readiness confirmed; exact worker view and supervisor advice received.
✓ test/tick-goal.test.ts > tickGoal (sign-off ticks the goal; agent only ticks on wording drift) > ticks the exact-matching goal line, case-insensitive, leaving subtasks alone 2ms
✓ test/tick-goal.test.ts > tickGoal (sign-off ticks the goal; agent only ticks on wording drift) > returns null on wording drift (fuzzy matching is the judge's job, not TypeScript's) 0ms
× test/tick-goal.test.ts > tickGoal (sign-off ticks the goal; agent only ticks on wording drift) > returns null when the subject matches more than one goal line 5ms
→ expected '# Plan\n\n## Goals\n\n1. [/] goal: Im…' to be null
✓ test/intercom-broker.test.ts > exchanges readiness, views and exact advice over a real isolated pi-intercom broker 254ms
✓ test/goals-flow.test.ts > /goals flow > reports actual idle state, invalidates stopped views on start, and stops completed plans 59ms
✓ test/goals-flow.test.ts > /goals flow > preserves drafts, records the interview, and keeps planning read-only 33ms
✓ test/goals-flow.test.ts > /goals flow > forks a visible supervisor on Ready and keeps the main session as worker 27ms
✓ test/goals-flow.test.ts > /goals flow > starts work only after the supervisor launcher resolves 38ms
✓ test/goals-flow.test.ts > /goals flow > delivers an Intercom instruction to the worker 41ms
✓ test/goals-flow.test.ts > /goals flow > closes the supervisor on clear but keeps the plan file 27ms
✓ test/goals-flow.test.ts > /goals flow > accepts only an approval for the exact clean commit and goal block 61ms
✓ test/goals-flow.test.ts > process role > keeps subagent children and visible supervisors out of the worker extension 0ms
✓ test/goals-flow.test.ts > restores working linkage even when its remembered model is unavailable, and supports explicit recovery 21ms
✓ test/goals-flow.test.ts > restores planning linkage even when its remembered model is unavailable, and supports explicit recovery 23ms
✓ test/goals-flow.test.ts > shows a missing resumed supervisor, pauses writes, and automatically unpauses when that peer returns 26ms
✓ test/goals-flow.test.ts > times out stale Ready retries in five seconds, without replacing the pane automatically 29ms
✓ test/goals-flow.test.ts > explicitly restarts only the tracked pane, keeps the plan, and invalidates old approval binding 24ms
✓ test/goals-flow.test.ts > does not persist startup results or launch work after session shutdown 23ms
✓ test/goals-flow.test.ts > keeps a failed Ready model not-ready and recovers the same real supervisor binding 31ms
✓ test/goals-flow.test.ts > points a present-but-paused peer recovery at the supervisor pane 21ms
✓ test/goals-flow.test.ts > clear during the initial Ready wait cancels immediately and cannot resurrect the plan 25ms
✓ test/goals-flow.test.ts > clear before the launcher resolves rejects late pane callbacks without restoring the binding 21ms
✓ test/supervisor-session.test.ts > visible supervisor session > restores monitoring and read-only tools without replaying persisted views 8ms
✓ test/supervisor-session.test.ts > visible supervisor session > renders all advice in real Pi tool rows, including collapsed and restored rows 21ms
✓ test/supervisor-session.test.ts > visible supervisor session > asks for judgment and useful recaps without inventing instructions 1ms
✓ test/supervisor-session.test.ts > visible supervisor session > writes readiness only after removing writing tools 2ms
✓ test/supervisor-session.test.ts > visible supervisor session > compacts a large planning fork before writing readiness 1ms
✓ test/supervisor-session.test.ts > visible supervisor session > does not become ready when initial compaction fails 2ms
✓ test/supervisor-session.test.ts > visible supervisor session > writes a durable worker instruction 1ms
✓ test/supervisor-session.test.ts > visible supervisor session > records approval only from a stopped view with evidence and no active work 96ms
✓ test/supervisor-session.test.ts > blocks the general intercom actuator even if enabled after startup 3ms
✓ test/supervisor-session.test.ts > keeps a supervisor unready after model restoration failure, then recovers explicitly without substituting a model 2ms
✓ test/supervisor-session.test.ts > warns once on unavailable usage but stays quiet for Pi's post-compaction null token sample 3ms
✓ test/rpc-review.test.ts > RPC review flow > opens Refine's editor before it starts the revision turn 1541ms
stdout | test/native-intercom.test.ts > runs a forked Pi supervisor and receives its exact instruction in another Pi session
Native Pi pair: fork retained planning context; SteerWorker delivered exactly: Read the real outputs before declaring completion.
✓ test/native-intercom.test.ts > runs a forked Pi supervisor and receives its exact instruction in another Pi session 2503ms
⎯⎯⎯⎯⎯⎯⎯ Failed Tests 1 ⎯⎯⎯⎯⎯⎯⎯
FAIL test/tick-goal.test.ts > tickGoal (sign-off ticks the goal; agent only ticks on wording drift) > returns null when the subject matches more than one goal line
AssertionError: expected '# Plan\n\n## Goals\n\n1. [/] goal: Im…' to be null
- Expected:
null
+ Received:
"# Plan
## Goals
1. [/] goal: Implement the cache layer
- tasks:
1. [x] wire client
2. [x] goal: Ship the docs
## Log
3. [ ] goal: Ship the docs
"
test/tick-goal.test.ts:30:42
28| it("returns null when the subject matches more than one goal line", (…
29| const dup = `${plan}3. [ ] goal: Ship the docs\n`;
30| expect(tickGoal(dup, "Ship the docs")).toBeNull();
| ^
31| });
32| });
⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[1/1]⎯
Test Files 1 failed | 16 passed (17)
Tests 1 failed | 65 passed (66)
Start at 19:22:13
Duration 2.84s (transform 2.51s, setup 0ms, import 5.72s, tests 5.21s, environment 2ms)
-42
View File
@@ -1,42 +0,0 @@
# Post-review P1P5 fixes — Pi/OpenAI implementation worker
Baseline: `1668c94`. Independent review: [attributed, preserved source](20260908-independent-post-fix-review.md), reviewer run `bdb93a2e-52f4-4a6d-bac2-7c9eb48118b5`.
Read AGENTS.md and installed Pi extension docs for lifecycle teardown, commands, model selection and compaction before editing. No user pane/session was operated; tests use isolated mocks/brokers/native Pi processes. No nested delegation or push.
## Dispositions
- **P1:** Replaced change-gated hello replies with an explicit request/reply bit. Every request receives one reply even when the peer state is unchanged; a reply never elicits another hello. Each successful exchange retries only still-pending instructions/current view, including after either side's own readiness transition. Repeated wire frames are allowed and deduplicated at the receiving adapter; this is not a new durable-delivery claim. `test/intercom-handshake.test.ts` wires **two real GoalIntercom adapters**, not an auto-ready peer. It checks repeated worker and supervisor reconfiguration, concurrent reset (four hello frames), single-sided reset (two frames), exact advice handoff, own-ready pause/resume, pending advice/view replay, and reconnect deduplication. Both peers must load the updated transport; mixed-version reconnect is not claimed supported.
- **P2:** The worker configures not-ready during startup/recovery. Startup can await peer readiness without claiming implementation readiness. It announces ready only after worker model restoration and the phase transition to working. Model failures remain not-ready. The Ready/retry flow test uses the same two real adapters and proves unavailable worker model → not-ready → `/model` + reconnect → Ready → working on the **same** binding/pane, followed by successful advice after healthy reconnect. Planning reconnect alone does not authorize implementation.
- **P3:** A known peer with incomplete readiness is distinguished from an absent peer. Guidance points to the supervisor pane's compaction/model diagnostics and `/model` + `/goals reconnect`, rather than treating every pause as disconnection. Regression checks widget and prompt guidance.
- **P4:** `src/plan.ts` now owns the single goal-line and Log-fold definitions. Widget scanning, subtasks, goal ticking and approval use the same current-plan boundary. Tick still rejects duplicate active-region matches; historical Log copies remain byte-for-byte unchanged. The existing approval/sign-off flow now includes duplicate/historical goal lines in the Log, succeeds and ends the active plan instead of reopening historical goals.
- **P5:** Detach/reconfigure immediately reject old readiness waiters. A small Ready-attempt identity plus plan-version guard invalidates asynchronous startup results on clear/recovery/replacement; stale menu/editor responses are also ignored. Regressions clear while the five-minute initial wait is pending (no clock advance needed to settle), then advance five minutes and verify no resurrection; a second test clears before the launcher callback resolves and verifies no late binding/pane persistence or work launch. No automatic late-pane kill was added.
- **F8 observability:** One warning per runtime if the entire usage result is unavailable at a settled check. No warning for Pi's ordinary post-compaction `tokens: null` sample. No speculative token estimator, new compaction policy, or change to Pi auto-compaction. Persistent null usage still cannot trigger the custom 100k check.
## Verification and changed old assertions
[Full successful commands/output](20260908-handshake-validation.txt): **67 tests passed in 17 files**, followed by successful typecheck, lint, build and `git diff --check`. The exact main-session test command unsets `PI_SUBAGENT_CHILD` and `PI_GOALS_ROLE` and sets a **fresh explicit** `PI_GOALS_EVIDENCE_DIR` to `slop/reviews/handshake-native`.
Two intermediate failures are preserved, not counted as passes:
1. [Handshake-focused run](20260908-handshake-initial-validation.txt): 26 passed/1 failed. The old assertion demanded exactly one outbound wire retry after configure+markReady. These now generate separate request/reply exchanges, which can retry the same still-unacked id more than once before its ack. Updated assertion requires at least one retry, every retry's exact id/text, and no further retries after ack. Two-real-adapter tests independently require exactly one user handoff/view callback after duplicate wire delivery.
2. [First full boundary run](20260908-handshake-boundary-initial-validation.txt): 65 passed/1 failed. Its old duplicate-goal fixture appended the duplicate **below `## Log`**, precisely the P4 behavior being corrected. The duplicate-rejection test now inserts the duplicate above the fold and still requires null; an added test requires historical copies below the fold to be ignored and unchanged.
An intermediate typecheck passed; lint initially flagged import order and a nested assignment. Those were corrected; the full final lint passed with no fixes applied.
[Native log inspection](20260908-handshake-log-inspection.txt) reads the final worker/supervisor event files, verifies zero error records and empty stderr, and matches the outgoing instruction, worker incoming instruction and adapter ack id `22068654-6e7c-4328-890f-9382b25c8ea7`. The worker user message is exactly `[supervisor] Read the real outputs before declaring completion.` This deterministic native test proves context retention/routing/tool exposure, not autonomous judgment or durable enqueue guarantees.
## Evidence provenance caveat
At the first inspection, these two tracked files were **already dirty**:
- `slop/reviews/review-fixes-native/supervisor-events.jsonl`
- `slop/reviews/review-fixes-native/worker-events.jsonl`
The inherited `PI_GOALS_EVIDENCE_DIR` pointed there. The first full test run accidentally refreshed them again. Their pre-task uncommitted bytes were not captured, so it is not established that all differences from HEAD were produced by this worker. They are left **unstaged and uncommitted**, not restored over unknown prior edits. The refreshed copies were separately preserved under this worker's output directory, `scratch-refreshed-prior-evidence/`. Final evidence uses only the fresh `handshake-native/` directory and is not mixed with these prior paths.
## Still open / acceptance limits
**F3 async enqueue confirmation remains open.** Pi's void `sendUserMessage` wrapper can return before a later async enqueue rejection. An adapter ack is not durable enqueue, model receipt, or execution confirmation. No correlated-receipt protocol was added; the future forced-async-rejection UAT remains required. A synchronous handoff failure still remains unacked for retry.
Parent/reviewer owns independent post-change review and push. Rendered Herdr acceptance, the complete two-native-session ApproveGoal → CompleteGoal chain, fresh-shell role recovery without launcher environment, useful independent judgment and cost savings remain unproven. Planning/pause shell gates remain trusted-repo guardrails, not a security sandbox. If a pane split finishes after cancellation, it can remain untracked for human inspection; this change prevents stale state resurrection rather than operating a late pane automatically.
@@ -1,77 +0,0 @@
> @wassname2/pi-goals@0.2.2 test
> vitest run --run test/intercom-handshake.test.ts test/intercom.test.ts test/goals-flow.test.ts --reporter=verbose
RUN v4.1.9 /home/code/.pi/agent/git/github.com/wassname/pi-goals
✓ test/intercom-handshake.test.ts > re-handshakes unchanged peers in either direction without hello ping-pong or lost advice 7ms
✓ test/intercom-handshake.test.ts > replays pending advice and views across either role's own readiness transition 1ms
✓ test/intercom-handshake.test.ts > cancels pending waits immediately on detach or reconfiguration 1ms
✓ test/intercom.test.ts > pi-intercom transport > receives exact advice once, acknowledges it and rejects unrelated peers 4ms
× test/intercom.test.ts > pi-intercom transport > restores an unacknowledged steer on reconnect and stops replay after acknowledgment 7ms
→ expected [ { binding: 'binding', …(4) }, …(1) ] to match object [ { …(2) } ]
✓ test/intercom.test.ts > pi-intercom transport > advances the incremental overview only after acknowledgment 1ms
✓ test/intercom.test.ts > pi-intercom transport > cancels a readiness wait on shutdown 1ms
✓ test/intercom.test.ts > does not acknowledge a synchronous handoff failure, and retries the instruction 1ms
✓ test/intercom.test.ts > detaches a completed binding and ignores its late advice without replay errors or false acceptance 3ms
✓ test/goals-flow.test.ts > /goals flow > reports actual idle state, invalidates stopped views on start, and stops completed plans 34ms
✓ test/goals-flow.test.ts > /goals flow > preserves drafts, records the interview, and keeps planning read-only 18ms
✓ test/goals-flow.test.ts > /goals flow > forks a visible supervisor on Ready and keeps the main session as worker 24ms
✓ test/goals-flow.test.ts > /goals flow > starts work only after the supervisor launcher resolves 22ms
✓ test/goals-flow.test.ts > /goals flow > delivers an Intercom instruction to the worker 18ms
✓ test/goals-flow.test.ts > /goals flow > closes the supervisor on clear but keeps the plan file 23ms
✓ test/goals-flow.test.ts > /goals flow > accepts only an approval for the exact clean commit and goal block 47ms
✓ test/goals-flow.test.ts > process role > keeps subagent children and visible supervisors out of the worker extension 0ms
✓ test/goals-flow.test.ts > restores working linkage even when its remembered model is unavailable, and supports explicit recovery 18ms
✓ test/goals-flow.test.ts > restores planning linkage even when its remembered model is unavailable, and supports explicit recovery 16ms
✓ test/goals-flow.test.ts > shows a missing resumed supervisor, pauses writes, and automatically unpauses when that peer returns 17ms
✓ test/goals-flow.test.ts > times out stale Ready retries in five seconds, without replacing the pane automatically 26ms
✓ test/goals-flow.test.ts > explicitly restarts only the tracked pane, keeps the plan, and invalidates old approval binding 23ms
✓ test/goals-flow.test.ts > does not persist startup results or launch work after session shutdown 23ms
✓ test/goals-flow.test.ts > keeps a failed Ready model not-ready and recovers the same real supervisor binding 23ms
✓ test/goals-flow.test.ts > points a present-but-paused peer recovery at the supervisor pane 18ms
✓ test/goals-flow.test.ts > clear during the initial Ready wait cancels immediately and cannot resurrect the plan 21ms
✓ test/goals-flow.test.ts > clear before the launcher resolves rejects late pane callbacks without restoring the binding 35ms
⎯⎯⎯⎯⎯⎯⎯ Failed Tests 1 ⎯⎯⎯⎯⎯⎯⎯
FAIL test/intercom.test.ts > pi-intercom transport > restores an unacknowledged steer on reconnect and stops replay after acknowledgment
AssertionError: expected [ { binding: 'binding', …(4) }, …(1) ] to match object [ { …(2) } ]
- Expected
+ Received
[
{
+ "binding": "binding",
+ "id": "7f4566ea-f2ef-4a14-ad75-e138fc3a26a0",
+ "kind": "steer",
+ "role": "supervisor",
+ "text": "Read the full output.",
+ },
+ {
+ "binding": "binding",
"id": "7f4566ea-f2ef-4a14-ad75-e138fc3a26a0",
+ "kind": "steer",
+ "role": "supervisor",
"text": "Read the full output.",
},
]
test/intercom.test.ts:45:76
43| resumed.link.markReady();
44| await resumed.link.waitReady();
45| expect(resumed.fixture.sent.filter(message => message.kind === "stee…
| ^
46| resumed.fixture.receive({ binding: "binding", role: "worker", kind: …
47| resumed.fixture.connect(false);
⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[1/1]⎯
Test Files 1 failed | 2 passed (3)
Tests 1 failed | 26 passed (27)
Start at 19:20:05
Duration 861ms (transform 365ms, setup 0ms, import 583ms, tests 437ms, environment 0ms)
@@ -1,8 +0,0 @@
slop/reviews/handshake-native/worker-events.jsonl: 22 events; 0 error records; stderr 0 bytes
worker: ack received cf656aef-1404-4d5c-9a11-4fbd4ed5b5dc
worker: ack received cf656aef-1404-4d5c-9a11-4fbd4ed5b5dc
worker: in steer 22068654-6e7c-4328-890f-9382b25c8ea7
worker: [{"type":"text","text":"[supervisor] Read the real outputs before declaring completion."}]
slop/reviews/handshake-native/supervisor-events.jsonl: 21 events; 0 error records; stderr 0 bytes
supervisor: out steer 22068654-6e7c-4328-890f-9382b25c8ea7
supervisor: ack received 22068654-6e7c-4328-890f-9382b25c8ea7
@@ -1,107 +0,0 @@
+ env -u PI_SUBAGENT_CHILD -u PI_GOALS_ROLE PI_GOALS_EVIDENCE_DIR=/home/code/.pi/agent/git/github.com/wassname/pi-goals/slop/reviews/handshake-native npm test -- --reporter=verbose
> @wassname2/pi-goals@0.2.2 test
> vitest run --reporter=verbose
RUN v4.1.9 /home/code/.pi/agent/git/github.com/wassname/pi-goals
✓ test/background.test.ts > reports tracked running work, rather than equating idle agent with finished jobs 5ms
✓ test/background.test.ts > distinguishes missing providers from an unavailable installed tracker 47ms
✓ test/package-agent.test.ts > package manifest > includes the extension without registering a packaged subagent 3ms
✓ test/herdr.test.ts > supervisor pane command > forks the planning session with pi-goals owning its Intercom dependency 3ms
✓ test/herdr.test.ts > supervisor pane command > accepts Herdr's text version output and stale pane cleanup 26ms
✓ test/prompts.test.ts > planning prompt > requires fact finding or a focused question before a goal 2ms
✓ test/prompts.test.ts > planning prompt > restores the same rule after compaction 0ms
✓ test/prompts.test.ts > planning prompt > anchors work and sign-off to the user-visible result 0ms
✓ test/worker-view.test.ts > keeps human direction and source location while sending only new messages 3ms
✓ test/worker-view.test.ts > restarts after compaction and does not report historical tool calls as active 1ms
✓ test/worker-view.test.ts > bounds serialized Unicode and quoted logs while marking omissions 2ms
stdout | test/role-models.test.ts > remembers each role without automatic switching overwriting another role
Role preferences restored: planning=planner, worker=small-worker, supervisor=astra; restore events did not overwrite the choice.
✓ test/role-models.test.ts > remembers each role without automatic switching overwriting another role 14ms
✓ test/role-models.test.ts > fails on an unavailable remembered model without replacing the choice 5ms
✓ test/approval.test.ts > hashes only the current goal, excluding the log, interview, and their historical goal text 5ms
✓ test/intercom-handshake.test.ts > re-handshakes unchanged peers in either direction without hello ping-pong or lost advice 9ms
✓ test/intercom-handshake.test.ts > replays pending advice and views across either role's own readiness transition 1ms
✓ test/intercom-handshake.test.ts > cancels pending waits immediately on detach or reconfiguration 2ms
✓ test/intercom.test.ts > pi-intercom transport > receives exact advice once, acknowledges it and rejects unrelated peers 7ms
✓ test/intercom.test.ts > pi-intercom transport > restores an unacknowledged steer on reconnect and stops replay after acknowledgment 4ms
✓ test/intercom.test.ts > pi-intercom transport > advances the incremental overview only after acknowledgment 1ms
✓ test/intercom.test.ts > pi-intercom transport > cancels a readiness wait on shutdown 1ms
✓ test/intercom.test.ts > does not acknowledge a synchronous handoff failure, and retries the instruction 2ms
✓ test/intercom.test.ts > detaches a completed binding and ignores its late advice without replay errors or false acceptance 1ms
✓ test/tick-goal.test.ts > tickGoal (sign-off ticks the goal; agent only ticks on wording drift) > ticks the exact-matching goal line, case-insensitive, leaving subtasks alone 2ms
✓ test/tick-goal.test.ts > tickGoal (sign-off ticks the goal; agent only ticks on wording drift) > returns null on wording drift (fuzzy matching is the judge's job, not TypeScript's) 0ms
✓ test/tick-goal.test.ts > tickGoal (sign-off ticks the goal; agent only ticks on wording drift) > returns null when the subject matches more than one goal line 0ms
✓ test/tick-goal.test.ts > tickGoal (sign-off ticks the goal; agent only ticks on wording drift) > ignores a historical duplicate below the Log and leaves it unchanged 0ms
✓ test/append-log.test.ts > appendLog (the extension's only plan-file write) > creates ## Log at EOF when absent 4ms
✓ test/append-log.test.ts > appendLog (the extension's only plan-file write) > appends after the last existing log line, before any following header 1ms
✓ test/fold.test.ts > foldPlan (current goals are above ## Log; durable memory is below it) > keeps the title, user voice and goals 2ms
✓ test/fold.test.ts > foldPlan (current goals are above ## Log; durable memory is below it) > drops the log, the learnings and the unlimited appendix 1ms
✓ test/fold.test.ts > foldPlan (current goals are above ## Log; durable memory is below it) > returns the whole plan when there is no ## Log yet (a fresh draft) 0ms
✓ test/fold.test.ts > openSubtasks (the widget shows the next action, so the plan IS the task list) > lists the active goal's open and in-progress subtasks, stopping at the next goal 1ms
✓ test/fold.test.ts > openSubtasks (the widget shows the next action, so the plan IS the task list) > does not leak subtasks from the goal below 1ms
✓ test/fold.test.ts > does not show historical Log subtasks under the last active goal 0ms
stdout | test/intercom-broker.test.ts > exchanges readiness, views and exact advice over a real isolated pi-intercom broker
Intercom broker: readiness confirmed; exact worker view and supervisor advice received.
✓ test/goals-flow.test.ts > /goals flow > reports actual idle state, invalidates stopped views on start, and stops completed plans 47ms
✓ test/goals-flow.test.ts > /goals flow > preserves drafts, records the interview, and keeps planning read-only 24ms
✓ test/intercom-broker.test.ts > exchanges readiness, views and exact advice over a real isolated pi-intercom broker 236ms
✓ test/goals-flow.test.ts > /goals flow > forks a visible supervisor on Ready and keeps the main session as worker 32ms
✓ test/goals-flow.test.ts > /goals flow > starts work only after the supervisor launcher resolves 29ms
✓ test/goals-flow.test.ts > /goals flow > delivers an Intercom instruction to the worker 26ms
✓ test/goals-flow.test.ts > /goals flow > closes the supervisor on clear but keeps the plan file 20ms
✓ test/goals-flow.test.ts > /goals flow > accepts only an approval for the exact clean commit and goal block 62ms
✓ test/goals-flow.test.ts > process role > keeps subagent children and visible supervisors out of the worker extension 0ms
✓ test/goals-flow.test.ts > restores working linkage even when its remembered model is unavailable, and supports explicit recovery 33ms
✓ test/goals-flow.test.ts > restores planning linkage even when its remembered model is unavailable, and supports explicit recovery 24ms
✓ test/goals-flow.test.ts > shows a missing resumed supervisor, pauses writes, and automatically unpauses when that peer returns 24ms
✓ test/goals-flow.test.ts > times out stale Ready retries in five seconds, without replacing the pane automatically 25ms
✓ test/goals-flow.test.ts > explicitly restarts only the tracked pane, keeps the plan, and invalidates old approval binding 42ms
✓ test/goals-flow.test.ts > does not persist startup results or launch work after session shutdown 36ms
✓ test/goals-flow.test.ts > keeps a failed Ready model not-ready and recovers the same real supervisor binding 31ms
✓ test/goals-flow.test.ts > points a present-but-paused peer recovery at the supervisor pane 17ms
✓ test/goals-flow.test.ts > clear during the initial Ready wait cancels immediately and cannot resurrect the plan 25ms
✓ test/goals-flow.test.ts > clear before the launcher resolves rejects late pane callbacks without restoring the binding 19ms
✓ test/supervisor-session.test.ts > visible supervisor session > restores monitoring and read-only tools without replaying persisted views 7ms
✓ test/supervisor-session.test.ts > visible supervisor session > renders all advice in real Pi tool rows, including collapsed and restored rows 22ms
✓ test/supervisor-session.test.ts > visible supervisor session > asks for judgment and useful recaps without inventing instructions 1ms
✓ test/supervisor-session.test.ts > visible supervisor session > writes readiness only after removing writing tools 2ms
✓ test/supervisor-session.test.ts > visible supervisor session > compacts a large planning fork before writing readiness 1ms
✓ test/supervisor-session.test.ts > visible supervisor session > does not become ready when initial compaction fails 2ms
✓ test/supervisor-session.test.ts > visible supervisor session > writes a durable worker instruction 1ms
✓ test/rpc-review.test.ts > RPC review flow > opens Refine's editor before it starts the revision turn 1350ms
✓ test/supervisor-session.test.ts > visible supervisor session > records approval only from a stopped view with evidence and no active work 87ms
✓ test/supervisor-session.test.ts > blocks the general intercom actuator even if enabled after startup 2ms
✓ test/supervisor-session.test.ts > keeps a supervisor unready after model restoration failure, then recovers explicitly without substituting a model 2ms
✓ test/supervisor-session.test.ts > warns once on unavailable usage but stays quiet for Pi's post-compaction null token sample 2ms
stdout | test/native-intercom.test.ts > runs a forked Pi supervisor and receives its exact instruction in another Pi session
Native Pi pair: fork retained planning context; SteerWorker delivered exactly: Read the real outputs before declaring completion.
✓ test/native-intercom.test.ts > runs a forked Pi supervisor and receives its exact instruction in another Pi session 2530ms
Test Files 17 passed (17)
Tests 67 passed (67)
Start at 19:24:07
Duration 2.84s (transform 2.36s, setup 0ms, import 6.39s, tests 4.95s, environment 3ms)
+ npm run typecheck
> @wassname2/pi-goals@0.2.2 typecheck
> tsc --noEmit
+ npm run lint
> @wassname2/pi-goals@0.2.2 lint
> biome check src/ test/
Checked 32 files in 91ms. No fixes applied.
+ npm run build
> @wassname2/pi-goals@0.2.2 build
> tsc
+ git diff --check
@@ -1,100 +0,0 @@
# Post-fix independent bug review — pi-goals supervision recovery
Scope: changes `2824396..1668c94` (fix commit `325b939` + evidence commit `1668c94`).
Inputs: AGENTS.md, `slop/reviews/20260908-review-fixes.md` (dispositions), `slop/reviews/20260908-independent-supervision-bug-review.md` (original F1F9), full current sources of `src/{index,intercom,supervisor-session,approval,role-models,herdr}.ts`, changed tests, native evidence logs.
Read-only: no repo edits, no live panes, no messaging. Repro artifacts lived in /tmp only.
Labels: **[TESTED]** = executed/compiled and observed. **[CODE]** = unambiguous from source. **[INFERENCE]** = depends on runtime behavior I could not observe here. Test passage is treated as evidence of the asserted path only, not as design proof.
Baseline check: `env -u PI_SUBAGENT_CHILD -u PI_GOALS_ROLE npx vitest run` → 57/57 pass in 16 files, matching the worker's validation claim. **[TESTED]**
---
## Fix verification F1F7
**F1 (unavailable remembered model aborts restore) — verified fixed. [CODE + repo tests]**
`session_start` now sets `modelError` first, configures the binding and timers independent of model selection, and only then attempts `restoreModel` in try/catch (`src/index.ts:557-580`). On failure: no `setModel`, no ready hello (`configure(..., false)` at :562, `markReady` gated on `!modelError` at :572-573), paused widget (`pauseReason`/`updateWidget` :149-153, 271-276), write/sign-off gating (:453-456, 592-597), human input and read-only diagnosis retained. `/model` saves over the failed role choice because `RoleModels.enter` sets `this.role` before throwing (`src/role-models.ts:29-30`), so `/goals reconnect` then picks up the user's replacement — a deliberate, workable recovery chain. No fallback model is substituted anywhere.
**F2 (resumed worker silently unsupervised) — verified fixed, with a residual in P3 below. [CODE + repo tests]**
`connected` now requires own-ready + binding + channel + peerReady (`src/intercom.ts:87`); `onConnectionChange` refreshes the widget immediately (:139, :145, :164); a resumed working worker hellos not-ready until its model restores, then `waitReady(5000)` and warns on failure (`src/index.ts:572-577`). Returning peers clear the pause automatically via the hello/`changed` path. Explicit `/goals restart` preserves plan/version and replaces only the tracked pane with a fresh approval binding (test asserts old checkpoint removed, plan unchanged, exactly one close).
**F3 (inactive-plan steer throws/replays) — lifecycle part fixed; delivery gap honestly open. [CODE + repo tests]**
`detach()` (`src/intercom.ts:72-81`) clears the binding on completion/clear/restart; late steers for a dead binding are dropped at the binding check (:151) without invoking `onSteer` or acking — covered by the new intercom tests. Ack ordering is still handoff-before-ack (:186-193), so a synchronous `sendUserMessage` throw leaves the steer unrecorded/unacked and it retries (test proves retry succeeds). The documented residual is real and correctly **not** claimed fixed: Pi 0.84.1's `sendUserMessage` is a void wrapper over an async enqueue, so an ack can precede an asynchronous enqueue failure, after which the instruction is gone from the supervisor's pending set and never reaches the model — silently. This is a genuine gap a future correlated-receipt protocol should close; the recorded UAT requirement (force an async enqueue rejection) is the right acceptance test. Acceptable as an explicitly-open item, not as a resolved one.
**F4 (stale pane → repeated 5-minute Ready waits) — verified fixed for the timeout itself. [CODE + repo tests]**
Existing-pane reconnect waits are 5s (`src/index.ts:186`, `:323`); first launch keeps the 300s compaction allowance (:213); failed `pane run` retains and reports the pane ID (:204-208); no automatic pane kill. **However, see P1: in one important sub-scenario the 5s retry fails deterministically even when the supervisor is healthy, so the fix's "retry" guidance does not actually recover there.**
**F5 (supervisor gets general `intercom` tool) — verified fixed. [CODE + native test]**
`intercom` is in `BLOCKED_TOOLS` (`src/supervisor-session.ts:13`), filtered from active tools at start and bootstrap (:108-110, :146), and blocked at tool-call time even if re-enabled (:170-173). The native pair test asserts the real supervisor model request's tool list excludes `intercom` and `bash`. Note the tool gate uses `terminate: true`, so a blocked call ends the whole supervisor turn — a deliberate-looking but behaviorally stronger choice than the planning gate's plain block.
**F6 (nested placeholder evidence) — verified fixed as far as claimed. [CODE + repo tests]**
Both the inline and child-bullet paths reject exactly `(empty until sign-off)` case-insensitively (`src/supervisor-session.ts:46,52`); the string matches the template in `src/prompts.ts:97`. Residual (documented as a presence floor): the child scan still accepts *any* deeper-indented nonblank bullet as evidence, and quoted variants like `"(empty until sign-off)"` pass. That is a semantic-judging limit, accurately disclaimed; supervisor judgment remains the real gate. Acceptable.
**F7 (last-goal hash includes Log/Interview) — verified fixed. [CODE + TESTED via unit tests]**
`goalBlock` now truncates the plan at `## Log` before scanning and ends the block at the next goal line or any `#`/`##` heading, with `trimEnd` (`src/approval.ts:43-58`). `approval.test.ts` covers duplicate goal text in the log, Interview section, next-goal boundary, and real block edits invalidating the hash; the flow test proves a manual log line between ApproveGoal and CompleteGoal no longer invalidates. Fail-closed on upgrade (old hashes need re-approval) is the right direction. One residual asymmetry (P4 below).
---
## New findings
### P1 — Reconnect/Ready-retry can wedge in a half-open state: peer hello is only re-sent on *perceived* state change (Medium) [TESTED]
`GoalIntercom.configure()` resets `peer`/`peerReady` (`src/intercom.ts:45-46`) and sends a hello, but the peer replies to a hello only when *its own* view changed (`src/intercom.ts:154-164`: `changed = !this.peer || this.peerReady !== message.ready; if (changed) this.hello()`). There is no periodic hello. If the peer's stored state already matches the incoming hello (same session id, same ready flag), it stays silent — so the side that reconfigured never learns the peer and `connected` stays false forever (until some unrelated broker `session_joined` at :148 happens to trigger a hello).
Reproduced in isolation (compiled real `src/intercom.ts` from HEAD, two links cross-wired as broker peers, script in /tmp, no repo changes):
```
after initial link: worker.connected = true supervisor.connected = true
after worker reconfigure: worker.connected = false supervisor.connected = true
waitReady REJECTED after 201 ms: Supervisor did not become ready through pi-intercom; inspect its pane.
supervisor steer() succeeded (reports sent)
worker delivered steer: null
```
Consequences, all reachable through new/changed code paths:
1. **`/goals reconnect` on a healthy link breaks it.** `src/index.ts:322-323` reconfigures the same binding; if nothing about readiness actually changed, every retry times out after 5s with "Goal recovery failed", and the only in-app escape is `/goals restart` — which closes the *healthy* pane and invalidates the approval binding (`beginReview` deletes checkpoints).
2. **The F1-on-Ready retry fails deterministically.** First Ready: `startSupervisor` completes the hello exchange (worker announced `ready=true` at `beginReview`/`configure`), then `restoreModel("worker")` throws → back to planning. After the user fixes the model, the next Ready takes the existing-pane path (`src/index.ts:184-186`): `configure` resets the worker's peer, hellos `ready=true`, the supervisor sees no change, stays silent, and `waitReady(5000)` times out — even though the supervisor is up and healthy. Every Ready/reconnect retry repeats this. This undercuts the F1/F4 recovery story on exactly the path those fixes target.
3. **Silent steer loss during the window.** While half-open, the supervisor's `connected` is true, so `SteerWorker` "succeeds", but the worker drops the message at `src/intercom.ts:166` (`event.fromSessionId !== this.peer`) with no notification; the steer sits in pending awaiting a changed hello that may never come. The SteerWorker result text ("Receipt and execution are not confirmed") softens but does not surface this.
Why the tests miss it: the fixture auto-replies to **every** hello with `ready: true` (`test/intercom-fixture.ts:21`), which is precisely the behavior the real peer logic does not have. The new peer-return and reconnect tests therefore cannot observe the change-gated reply.
Suggested direction (not implemented): reply to a hello whenever the sender may have lost state — e.g. have `configure` retain `peer`/`peerReady` when the binding is unchanged (re-handshake is only needed after a real transport/binding change), or include a monotonic hello generation and reply to any newer/unknown generation. An unconditional reply to every hello also works without ping-pong, because the *response* hello is still change-gated on the receiver's side.
### P2 — Failed Ready leaves the worker announcing `ready=true` while paused (Low) [CODE]
In the Ready flow, `beginReview``configure(approvalId, "worker", ctx)` defaults to `ready=true` (`src/intercom.ts:43`, `src/index.ts:171`). If `restoreModel("worker")` then throws (`src/index.ts:525` → catch at :537-544), the code rolls back `phase` to planning but never rolls back intercom readiness or detaches. The worker thereafter hellos `ready=true` on any broker event while `modelError` is set; the supervisor sees a ready, connected worker, `SteerWorker` sends successfully, and the worker's `onSteer` throws (`src/index.ts:113-116`) — unacked, error notification per replay. Self-consistent recovery exists (next Ready after `/model` works, modulo P1), so impact is confusing error noise and a misleading readiness signal, not loss. A `markNotReady`/detach in that catch would align the announced state with the pause.
### P3 — Worker pause message misattributes a *supervisor-side* pause (Low) [CODE]
`pauseReason()` (`src/index.ts:149-154`) collapses "peer absent" and "peer present but not ready" into one message: "Supervisor disconnected. Run /goals reconnect, or /goals restart…". When the supervisor pane is alive but paused on its own model restoration (`src/supervisor-session.ts:150-158` sets supervisor `modelError`, readiness stays false), the worker-side `/goals reconnect` will hello, get a `ready=false` reply, and time out after 5s — the advised action cannot work; the actual fix is `/model` + `/goals reconnect` in the supervisor pane. The supervisor pane does display its own error notification, and the design keeps both panes visible, so the user has the information — but the worker-side guidance points the wrong way. `peer` set + `peerReady` false is distinguishable from no peer; the message could be too.
### P4 — `goalBlock` and `tickGoal` now scan different regions (Low) [CODE]
Post-F7, `goalBlock` only sees the pre-`## Log` region (`src/approval.ts:44`), while `tickGoal` and `scanGoals` still scan the whole file (`src/index.ts:670-677`, :53-60). A goal-shaped line quoted inside the Log (e.g. a pasted checklist) yields: `goalBlock` finds a unique match → approval proceeds and hashes, but `CompleteGoal``tickGoal` finds two hits → returns null → sign-off blocked after a successful approval. Fail-closed, requires unusual plan content, and the same class of confusion pre-dates the fix (both sides failed before); noting it because the fix changed the boundary of only one of the two scanners.
### P5 — Ready catch can resurrect a cleared plan phase after a concurrent `/goals clear` (Low) [CODE/INFERENCE]
The Ready path awaits up to 300s inside `startSupervisor` (`src/index.ts:213`), and neither `detach()` nor `configure()` wakes `waitReady` waiters (only hellos/shutdown do; `detach`'s clearing of `binding` means its own not-ready hello is ignored by waiters, and the peer's reply is dropped by the now-empty binding check). If the user runs `/goals clear` during that wait, the plan state is cleared; when the wait later times out, the catch at `src/index.ts:537-544` unconditionally sets `phase: "planning"` and persists — yielding `phase: "planning"` with `planVersion: null`, a "drafting goals" widget over no plan, and "No active plan to disconnect" from `/goals clear`. Recoverable via a fresh `/goals <objective>`, and the interleaving requires issuing a command while the Ready select-loop is mid-wait, hence Low. I did not execute this interleaving; it follows from the unconditional catch and the waiter semantics. Guarding the catch on "state still belongs to this Ready attempt" (e.g. approvalId/planVersion unchanged) would close it.
---
## Assessment of documented residuals (not accepted on documentation alone)
- **F3 durable-delivery gap**: genuine and correctly scoped as open. Concretely, after an acked-but-async-failed enqueue, the supervisor waits indefinitely for a response to an instruction the worker model never saw, with no signal on either side; the recorded future UAT (inject an async enqueue rejection, assert no confirmed-delivery claim and recoverability) is the right bar. Fine to defer; not fine to call resolved — and it isn't.
- **F8 (unknown usage disables 100k compaction)**: the `?? 0` fallback (`src/supervisor-session.ts:187`) silently disables the custom compaction wherever `getContextUsage()` is unavailable, contradicting the AGENTS.md cost design with no user-visible signal. Mitigating factor I verified: the supervisor system prompt (with `planPath`) is re-appended every `before_agent_start` (:175), and approvals/checkpoints live on disk, so a fallback default-compaction does not lose the plan pointer or approval state — the consequence is cost/context-rot drift, not correctness. Still, a one-time "usage unknown; custom compaction inactive" notification would close the observability gap cheaply. Acceptable as a documented limitation; the silence is the weakest part.
- **F9 (planning/pause bash gate holes)**: accurately disclaimed as guardrail-not-sandbox. The paused-diagnostic gate (`src/index.ts:453-456`) intentionally inherits the same heuristic, including the `git diff --ext-diff` external-command hole that requires a pre-existing hostile `.git/config`. Given the threat model (trusted repo, trusted extensions), the README statement is sufficient; a hardened policy remains correctly out of scope.
- **Test-quality caveat**: beyond the fixture issue in P1, the native pair test drives only `SteerWorker`; the two-real-session `ApproveGoal → CompleteGoal` chain is still unexecuted end to end, so the F7 hash boundary and the view-freshness gate are verified only per-side (unit/flow tests) plus one real supervisor tool-list inspection. The disposition states this; I confirm it remains true at 1668c94.
## What is solid
- Shutdown/late-startup guards (`src/index.ts:180, 199-203, 210`) and the supervisor's `bootstrapping` `finally` fix are correct; the test proves no late persistence after shutdown.
- Queued pending steers when *own* readiness changes are handled correctly on both roles: republish is gated on `peerReady && this.ready` (`src/intercom.ts:158-162`), pause suppresses republication, and recovery replays exactly the unacked set from session entries. The only hole in this chain is P1's missing trigger.
- Approval binding safety (per-approvalId, head/tree/clean-worktree/goal-block-hash equality, restart invalidating old approvals) is preserved and extended by the restart flow.
- Human recovery availability while paused is real on both roles: input, read-only tools, `/model`, `/goals reconnect|restart|clear` all remain reachable; sign-off and writes fail closed.
## Summary
F1F7 are fixed as claimed, with tests and native evidence matching the dispositions. The significant new finding is **P1**: the change-gated hello reply combined with `configure()`'s peer reset makes `/goals reconnect` and Ready-retry wedge half-open precisely when readiness did not change — including the F1-on-Ready retry scenario the fixes were built for — and steers are silently dropped in that window while `steer()` reports success. P2P5 are low-severity consistency/guard gaps. Documented residuals F3/F8/F9 are honest; F3's delivery gap and F8's silent compaction-disable remain open items, not fixes.
Attribution: independent reviewer, run bdb93a2e-52f4-4a6d-bac2-7c9eb48118b5; preserved verbatim by Pi/OpenAI implementation worker.
@@ -1,151 +0,0 @@
# pi-goals supervision bug review — HEAD 2824396
> Attribution: independent delegated reviewer, run `5c8c2017-a92f-4a5f-baf6-f441f9b50495`, artifact `supervision-bug-review.md`. Findings below are preserved from that reviewer, not authored by the implementation worker. Implementation dispositions are in `20260908-review-fixes.md`.
Scope: AGENTS.md, src/{index,intercom,supervisor-session,background,role-models,approval,worker-view,herdr,prompts}.ts and tests.
Priorities: lifecycle/reload, delivery/reconnect, approval safety, autonomy failures.
Method: static review plus targeted checks against the installed `@earendil-works/pi-coding-agent` 0.84.1 and `pi-intercom` 0.13.0 sources, and one live reproduction (F1). Nothing in the repo was modified; repro scripts lived in /tmp.
Labels: **[TESTED]** = demonstrated by execution or verified against dependency source. **[CODE]** = read directly from pi-goals source; control flow unambiguous. **[INFERENCE]** = depends on behavior I could not observe.
---
## F1 — Working-phase session restore aborts halfway when the remembered role model is unavailable (Medium) [TESTED]
`src/index.ts:486-495` (`session_start`):
```ts
if (state.phase) await models.enter(...); // line 488 — can throw
planningContextPending = state.phase === "planning";
resyncReason = state.phase === "working" ? "New session." : null;
if (state.phase === "working") {
intercom.configure(state.approvalId!, "worker", ctx); // line 492 — skipped on throw
startWorkerTimers(ctx); // line 493 — skipped
}
updateWidget(ctx); // line 495 — skipped
```
`RoleModels.enter` (`src/role-models.ts:30-40`) throws `worker model is unavailable...` when the saved `.pi/pi-goals/models/worker.json` names a model that `ctx.modelRegistry.find` can no longer resolve (provider removed, auth expired). That is a realistic state: the feature exists precisely to remember models across sessions, and model availability changes over time.
Reproduction (executed): mock Pi host, persisted state `{phase: "working", approvalId: "appr-1", planVersion: 1}`, saved worker model `gone/expired`, `modelRegistry.find → undefined`. Result:
```
session_start handler threw: worker model is unavailable. Select an available model with /model, then retry. Saved choice was not replaced.
intercom.configure called during working-phase restore: false
```
Consequences after the throw:
- Intercom binding is never restored: no hello, `peerReady` stays false, every subsequent `publishWorkerView` silently records views with an empty binding and never publishes them.
- The hourly view timer never starts.
- Widget is not updated.
- On a planning-phase resume, `planningContextPending` is never set, so the planning snapshot is never re-injected.
- Pi catches per-handler errors (`ExtensionRunner.emit`, runner.js:587-601) and routes them to `emitError`, so the user sees at most an extension-error diagnostic. The error text says "then retry", but no code path retries the restore — `session_start` does not re-run when the user picks a new model.
This overlaps F2: the session resumes looking normal while supervision is dead.
## F2 — No supervisor liveness check on worker resume; dead supervisor pane is invisible (Medium) [CODE]
`src/index.ts:486-495`: on resume with `phase === "working"`, the worker calls `intercom.configure` (which sends one hello) and starts timers. There is no `waitReady`, no Herdr pane probe, and no timeout. If the supervisor pane died while the worker session was closed:
- `GoalIntercom.view()` (`src/intercom.ts:82-88`) records the view and skips publishing because `connected` is false — silently. No notify anywhere on this path.
- `updateWidget` still renders "· supervised" (`src/index.ts:249`).
- The worker system prompt tells the model to "Stop when a goal appears complete so the supervisor can inspect a settled worker view" — it will stop and wait for an approval that can never arrive. `CompleteGoal` then fails with "no matching supervisor approval checkpoint" with no hint that the supervisor is gone.
- The only reconnect wait (`waitReady`) lives in `startSupervisor`, which is unreachable from the working phase: the Ready menu only renders when `state.phase === "planning"` (`src/index.ts:417`). The only recovery is `/goals clear` (drops plan linkage) or `/goals <new objective>` (new plan version, old plan orphaned). There is no "restart supervisor" path that preserves the current plan.
[INFERENCE] Whether the broker notices the dead pane while the worker is offline is irrelevant here — the worker has no handler for "peer never came back after resume" in either case.
## F3 — `onSteer` rejection throws before ack: unacked steer replays forever, error notification each reconnect (Medium-low) [CODE]
`src/index.ts:113-116`:
```ts
intercom.onSteer = (instruction) => {
if (state.phase !== "working") throw new Error("Worker plan is not active; instruction rejected.");
pi.sendUserMessage(`[supervisor] ${instruction}`, { deliverAs: "steer" });
};
```
`src/intercom.ts:167-174` (worker steer branch):
```ts
this.onSteer(message.text!); // throws → everything below skipped
this.received.add(message.id);
this.record("in", message);
this.publish({ ... kind: "received" ... });
```
Because `onSteer` runs before dedupe/record/ack, a steer that arrives when the plan is not active (plan just completed — `publishWorkerView` sets `phase: null` at index.ts:213; or `/goals clear`; or a supervisor that ignores "stop issuing instructions") is:
1. never acked — the supervisor keeps it in `pending` and republishes it on every `changed` hello (`src/intercom.ts:143-149`), so each supervisor reconnect re-fires the throw;
2. never recorded — so the dedupe set can't suppress it;
3. surfaced only as `Goal Intercom error: ... instruction rejected.` notifications in the worker pane; the supervisor's `SteerWorker` result says only "Receipt and execution are not confirmed", so the supervisor model cannot distinguish "rejected" from "lost" and may re-send, producing one error notification per attempt.
Related at-least-once window: a crash between `pi.sendUserMessage` (persisted) and `record("in", ...)` causes the same `[supervisor] ...` instruction to be delivered twice after resume. Narrow, but the fix is the same: record/ack before invoking `onSteer`, and add a rejection result back to the supervisor instead of throwing.
## F4 — Stale `supervisorPaneId` makes every Ready retry block for 5 minutes (Medium-low) [CODE]
`src/index.ts:163-166`:
```ts
if (state.supervisorPaneId && state.approvalId) {
intercom.configure(state.approvalId, "worker", ctx);
await intercom.waitReady(); // default 300_000 ms, intercom.ts:73
return;
}
```
This reconnect path is taken after a partial `startSupervisor` failure — e.g. `herdr pane split` succeeded (pane id persisted via the `onOpened` callback at index.ts:174-176) but `herdr pane run` failed (`src/herdr.ts:76-84`), or `models.enter("worker")` threw after the supervisor started. The pane is dead or the supervisor process exited, but the retry never asks Herdr whether the pane exists; it blocks the `agent_settled` handler (and therefore the planning menu) until the 5-minute `waitReady` timeout. Every subsequent Ready repeats the 5-minute hang. `/goals clear` recovers (`closeSupervisorPane` tolerates `NOT_FOUND`/`PANE_GONE`, herdr.ts:60-66), but the timeout error message ("inspect its pane") does not say so.
Also note the same 5-minute blocking wait applies to the supervisor's first-time initial compaction (`supervisor-session.ts:133-160`); a slow compaction of a large fork produces the same opaque worker-side failure, though that path self-heals on retry.
## F5 — The "read-only" supervisor gets pi-intercom's full `intercom` tool (Low-medium, approval/authority surface) [TESTED against pi-intercom source]
The supervisor runs with `--no-extensions -e src/index.ts` (`src/herdr.ts:48-58`), so pi-intercom is never an installed extension in the supervisor session, so `GoalIntercom.loadIntercom` (`src/intercom.ts:189-200`) always dynamically imports it. `intercom(api)` executes pi-intercom's full default export, which registers:
- the `intercom` tool: "Send a message to another pi session running on this machine" (pi-intercom/index.ts:2088),
- `/intercom`, `/intercom-id`, `/alias` commands (pi-intercom/index.ts:2802-2812).
The supervisor's read-only enforcement filters only `WRITER_TOOLS` (`src/supervisor-session.ts:13`, applied at session_start line ~124 and in bootstrap), so `intercom` remains an active tool for the supervisor model. Effect: the supervisor — prompted as read-only with `SteerWorker`/`ApproveGoal` as its only actuators — can message arbitrary Pi sessions on the machine, including the user's other sessions, outside the auditable SteerWorker channel whose renders the tests assert are visible. Severity depends on how much you trust the supervisor model; the capability contradicts the stated design ("all supervisor thinking and messages should be visible", AGENTS.md).
Mitigation would be filtering `intercom` (and any other messaging tools) out of the supervisor's active set, or passing a `registerTool` denylist through the `loadIntercom` proxy (it currently only wraps `on`).
## F6 — `hasEvidenceEntry` accepts placeholder or unrelated nested bullets as evidence (Low) [CODE]
`src/supervisor-session.ts:41-60`. The inline placeholder `(empty until sign-off)` is rejected, but when the inline value is empty the child scan returns true for *any* deeper-indented bullet with nonblank text — including `- (empty until sign-off)` written as a child bullet, or any stray nested line. So this block passes the gate:
```
1. [ ] goal: x
- evidence:
- (empty until sign-off)
```
The supervisor model is instructed to actually read the evidence, so this is a heuristic floor rather than the real defense; still, the placeholder check should apply to child bullets too.
## F7 — Approval goal block for the last goal runs to EOF; tail edits spuriously invalidate approvals (Low) [CODE]
`goalBlock` (`src/approval.ts:36-53`) slices from the goal line to the next goal line *or EOF*. For the last goal, the block includes `## Log`, `## Interview`, and the Appendix. `hashGoalBlock` therefore changes if the worker appends a manual `## Log` line (which the prompts encourage — `stamp()` exists for that) between `ApproveGoal` and `CompleteGoal`, producing "no matching supervisor approval checkpoint" and forcing a fresh review. Fail-closed, so not a safety bug; it is an availability/UX trap in the normal approve → log → sign-off rhythm. Consider ending the block at the fold (`## Log`) like `foldPlan` does.
## F8 — Supervisor 100k compaction silently disabled when `getContextUsage` is unavailable (Low) [INFERENCE]
`src/supervisor-session.ts:141-143`: `if (compacting || (ctx.getContextUsage()?.tokens ?? 0) < COMPACT_AT_TOKENS) return;`. If `getContextUsage()` returns undefined (RPC/print modes or any runtime where it isn't wired), tokens coerce to 0 and the supervisor never self-compacts, contradicting the AGENTS.md cost design ("compacts every 100k"). Pi's own auto-compaction will eventually fire without the custom instructions that protect the plan pointer and approval state. I could not confirm whether `getContextUsage` is ever undefined in the Herdr-pane interactive mode; in the test mock it is explicitly set.
## F9 — Plan-mode bash gate: residual holes are narrow but worth noting (Low) [CODE/INFERENCE]
`isPlanningReadOnlyCommand` (`src/index.ts:566-574`) is otherwise tight (blocks pipes/redirects/backticks/`$`, splits on `&&`/`;`, whitelists verbs, special-cases `--output`, `find -delete/-exec...`, mutating `git branch`). Residual issues:
- The whitelist allows `git log/show/diff` with *arbitrary* flags. `git diff --ext-diff` / `git log --ext-diff` execute the command configured in `diff.external`/`GIT_EXTERNAL_DIFF`. Env-prefix assignments are blocked (the part must start with a whitelisted verb), so this requires a pre-existing malicious `.git/config` in the target repo. [INFERENCE] that any real repo would have this.
- Plan mode blocks only `edit`/`write` by name (`PLAN_MODE_BLOCKED_TOOLS`, index.ts:34). Any other extension's mutating tool (e.g. a `process`/background-task launcher, `apply_patch`-style tools — the supervisor's own `WRITER_TOOLS` list at supervisor-session.ts:13 acknowledges several) is not blocked in plan mode. In the worker session all user extensions are loaded, so this depends on the user's setup. [INFERENCE]
## Non-findings (checked, working as intended)
- **Shutdown latch**: `GoalIntercom.stopped = true` on `session_shutdown` looked dangerous for in-process `/resume`, but Pi tears down and re-creates the ExtensionRunner (and therefore all extension instances) on resume/new/fork/reload (agent-session-runtime.js:102-112, agent-session.js:2053-2073). [TESTED against pi source]
- **Handler ordering**: Pi runs handlers sequentially in registration order and awaits them (runner.js:579-604), so `GoalIntercom`'s constructor-registered `session_start` (channel load) completes before index.ts's `configure` → hello. Per-handler errors are swallowed into `emitError` (this is why F1 is silent). [TESTED against pi source]
- **ApproveGoal freshness gates**: the `view === newest.text` equality check is sound — `sendUserMessage` stores the text verbatim (agent-session.js:1106-1133), `latestView` is set before `onView` fires, and any newer queued view makes the comparison fail closed. Worker "stopped"/`backgroundQuiet` are extension-computed (`ctx.isIdle()`, `backgroundState`), not model-controlled, so the worker model cannot spoof a stopped/quiet view. `backgroundState` fails closed ("unknown" → not quiet) when an installed tracker doesn't answer, and distinguishes missing providers (background.ts, covered by test/background.test.ts).
- **Approval checkpoint binding**: head/tree/clean-worktree/goal-block-hash equality plus per-`approvalId` binding and `beginReview`'s deletion of prior approvals make approval replay across plans or commits infeasible; `.pi/plan`, approvals, and model prefs are correctly excluded from the dirtiness check relative to repo root (`approval.ts:20-34`).
- **Steer/view redelivery after restart**: pending steers and `received` dedupe survive restart via session-entry replay (`intercom.ts:54-68`) and are covered by test/intercom.test.ts; ack cursors are monotonic.
- **Two-peer guard**: the "Two peers claim this supervision binding" throw fires before any state mutation and repeats harmlessly; it can wedge only if the broker failed to emit `session_left` for the previous peer, which the broker does send on disconnect/reregister (broker.ts:327,540).
## Test-coverage gaps relevant to the above
- No test exercises F1 (resume with unavailable remembered model).
- No test exercises a resumed worker whose supervisor never answers (F2) — the intercom fixture auto-replies to hellos, so `connected` is always true in tests.
- The native end-to-end test (test/native-intercom.test.ts) drives `SteerWorker` only; the `ApproveGoal` → approval file → `CompleteGoal` chain has never run through two real Pi sessions, so F7-class friction and the `view === newest.text` gate are unverified end to end.
@@ -1,62 +0,0 @@
> @wassname2/pi-goals@0.2.2 test
> vitest run --reporter=verbose
RUN v4.1.9 /home/code/.pi/agent/git/github.com/wassname/pi-goals
✓ test/package-agent.test.ts > package manifest > includes the extension without registering a packaged subagent 6ms
✓ test/herdr.test.ts > supervisor pane command > forks the planning session with pi-goals owning its Intercom dependency 3ms
✓ test/herdr.test.ts > supervisor pane command > accepts Herdr's text version output and stale pane cleanup 40ms
✓ test/prompts.test.ts > planning prompt > requires fact finding or a focused question before a goal 2ms
✓ test/prompts.test.ts > planning prompt > restores the same rule after compaction 0ms
✓ test/prompts.test.ts > planning prompt > anchors work and sign-off to the user-visible result 0ms
✓ test/intercom.test.ts > pi-intercom transport > receives exact advice once, acknowledges it and rejects unrelated peers 14ms
✓ test/intercom.test.ts > pi-intercom transport > restores an unacknowledged steer on reconnect and stops replay after acknowledgment 7ms
✓ test/intercom.test.ts > pi-intercom transport > cancels a readiness wait on shutdown 4ms
✓ test/fold.test.ts > foldPlan (current goals are above ## Log; durable memory is below it) > keeps the title, user voice and goals 2ms
✓ test/fold.test.ts > foldPlan (current goals are above ## Log; durable memory is below it) > drops the log, the learnings and the unlimited appendix 1ms
✓ test/fold.test.ts > foldPlan (current goals are above ## Log; durable memory is below it) > returns the whole plan when there is no ## Log yet (a fresh draft) 0ms
✓ test/fold.test.ts > openSubtasks (the widget shows the next action, so the plan IS the task list) > lists the active goal's open and in-progress subtasks, stopping at the next goal 1ms
✓ test/fold.test.ts > openSubtasks (the widget shows the next action, so the plan IS the task list) > does not leak subtasks from the goal below 1ms
✓ test/tick-goal.test.ts > tickGoal (sign-off ticks the goal; agent only ticks on wording drift) > ticks the exact-matching goal line, case-insensitive, leaving subtasks alone 2ms
✓ test/tick-goal.test.ts > tickGoal (sign-off ticks the goal; agent only ticks on wording drift) > returns null on wording drift (fuzzy matching is the judge's job, not TypeScript's) 0ms
✓ test/tick-goal.test.ts > tickGoal (sign-off ticks the goal; agent only ticks on wording drift) > returns null when the subject matches more than one goal line 0ms
stdout | test/intercom-broker.test.ts > exchanges readiness, views and exact advice over a real isolated pi-intercom broker
Intercom broker: readiness confirmed; exact worker view and supervisor advice received.
✓ test/append-log.test.ts > appendLog (the extension's only plan-file write) > creates ## Log at EOF when absent 2ms
✓ test/append-log.test.ts > appendLog (the extension's only plan-file write) > appends after the last existing log line, before any following header 1ms
✓ test/intercom-broker.test.ts > exchanges readiness, views and exact advice over a real isolated pi-intercom broker 221ms
✓ test/goals-flow.test.ts > /goals flow > reports actual idle state, invalidates stopped views on start, and stops completed plans 38ms
✓ test/goals-flow.test.ts > /goals flow > preserves drafts, records the interview, and keeps planning read-only 21ms
✓ test/goals-flow.test.ts > /goals flow > forks a visible supervisor on Ready and keeps the main session as worker 24ms
✓ test/goals-flow.test.ts > /goals flow > starts work only after the supervisor launcher resolves 20ms
✓ test/goals-flow.test.ts > /goals flow > delivers an Intercom instruction to the worker 20ms
✓ test/goals-flow.test.ts > /goals flow > closes the supervisor on clear but keeps the plan file 24ms
✓ test/goals-flow.test.ts > /goals flow > accepts only an approval for the exact clean commit and goal block 49ms
✓ test/goals-flow.test.ts > process role > keeps subagent children and visible supervisors out of the worker extension 0ms
✓ test/supervisor-session.test.ts > visible supervisor session > restores monitoring and read-only tools without replaying persisted views 6ms
✓ test/supervisor-session.test.ts > visible supervisor session > renders all advice in real Pi tool rows, including collapsed and restored rows 25ms
✓ test/supervisor-session.test.ts > visible supervisor session > asks for judgment and useful recaps without inventing instructions 1ms
✓ test/supervisor-session.test.ts > visible supervisor session > writes readiness only after removing writing tools 2ms
✓ test/supervisor-session.test.ts > visible supervisor session > compacts a large planning fork before writing readiness 1ms
✓ test/supervisor-session.test.ts > visible supervisor session > does not become ready when initial compaction fails 1ms
✓ test/supervisor-session.test.ts > visible supervisor session > writes a durable worker instruction 1ms
✓ test/supervisor-session.test.ts > visible supervisor session > records approval only from a stopped view with evidence and no active work 58ms
✓ test/rpc-review.test.ts > RPC review flow > opens Refine's editor before it starts the revision turn 1384ms
Test Files 11 passed (11)
Tests 37 passed (37)
Start at 16:31:10
Duration 1.67s (transform 1.31s, setup 0ms, import 3.59s, tests 2.00s, environment 1ms)
> @wassname2/pi-goals@0.2.2 typecheck
> tsc --noEmit
> @wassname2/pi-goals@0.2.2 lint
> biome check src/ test/
Checked 21 files in 67ms. No fixes applied.
@@ -1,81 +0,0 @@
> @wassname2/pi-goals@0.2.2 test
> vitest run --reporter=verbose
RUN v4.1.9 /home/code/.pi/agent/git/github.com/wassname/pi-goals
✓ test/package-agent.test.ts > package manifest > includes the extension without registering a packaged subagent 2ms
✓ test/prompts.test.ts > planning prompt > requires fact finding or a focused question before a goal 2ms
✓ test/prompts.test.ts > planning prompt > restores the same rule after compaction 1ms
✓ test/prompts.test.ts > planning prompt > anchors work and sign-off to the user-visible result 0ms
✓ test/background.test.ts > reports tracked running work, rather than equating idle agent with finished jobs 3ms
✓ test/background.test.ts > distinguishes missing providers from an unavailable installed tracker 4ms
stdout | test/role-models.test.ts > remembers each role without automatic switching overwriting another role
Role preferences restored: planning=planner, worker=small-worker, supervisor=astra; restore events did not overwrite the choice.
✓ test/role-models.test.ts > remembers each role without automatic switching overwriting another role 7ms
✓ test/role-models.test.ts > fails on an unavailable remembered model without replacing the choice 4ms
✓ test/worker-view.test.ts > keeps human direction and source location while sending only new messages 5ms
✓ test/worker-view.test.ts > restarts after compaction and does not report historical tool calls as active 1ms
✓ test/worker-view.test.ts > bounds serialized Unicode and quoted logs while marking omissions 3ms
✓ test/herdr.test.ts > supervisor pane command > forks the planning session with pi-goals owning its Intercom dependency 3ms
✓ test/herdr.test.ts > supervisor pane command > accepts Herdr's text version output and stale pane cleanup 30ms
✓ test/intercom.test.ts > pi-intercom transport > receives exact advice once, acknowledges it and rejects unrelated peers 6ms
✓ test/intercom.test.ts > pi-intercom transport > restores an unacknowledged steer on reconnect and stops replay after acknowledgment 6ms
✓ test/intercom.test.ts > pi-intercom transport > advances the incremental overview only after acknowledgment 1ms
✓ test/intercom.test.ts > pi-intercom transport > cancels a readiness wait on shutdown 1ms
✓ test/fold.test.ts > foldPlan (current goals are above ## Log; durable memory is below it) > keeps the title, user voice and goals 2ms
✓ test/fold.test.ts > foldPlan (current goals are above ## Log; durable memory is below it) > drops the log, the learnings and the unlimited appendix 1ms
✓ test/fold.test.ts > foldPlan (current goals are above ## Log; durable memory is below it) > returns the whole plan when there is no ## Log yet (a fresh draft) 0ms
✓ test/fold.test.ts > openSubtasks (the widget shows the next action, so the plan IS the task list) > lists the active goal's open and in-progress subtasks, stopping at the next goal 1ms
✓ test/fold.test.ts > openSubtasks (the widget shows the next action, so the plan IS the task list) > does not leak subtasks from the goal below 1ms
✓ test/append-log.test.ts > appendLog (the extension's only plan-file write) > creates ## Log at EOF when absent 2ms
✓ test/append-log.test.ts > appendLog (the extension's only plan-file write) > appends after the last existing log line, before any following header 0ms
stdout | test/intercom-broker.test.ts > exchanges readiness, views and exact advice over a real isolated pi-intercom broker
Intercom broker: readiness confirmed; exact worker view and supervisor advice received.
✓ test/intercom-broker.test.ts > exchanges readiness, views and exact advice over a real isolated pi-intercom broker 206ms
✓ test/goals-flow.test.ts > /goals flow > reports actual idle state, invalidates stopped views on start, and stops completed plans 34ms
✓ test/goals-flow.test.ts > /goals flow > preserves drafts, records the interview, and keeps planning read-only 21ms
✓ test/goals-flow.test.ts > /goals flow > forks a visible supervisor on Ready and keeps the main session as worker 25ms
✓ test/tick-goal.test.ts > tickGoal (sign-off ticks the goal; agent only ticks on wording drift) > ticks the exact-matching goal line, case-insensitive, leaving subtasks alone 2ms
✓ test/tick-goal.test.ts > tickGoal (sign-off ticks the goal; agent only ticks on wording drift) > returns null on wording drift (fuzzy matching is the judge's job, not TypeScript's) 0ms
✓ test/tick-goal.test.ts > tickGoal (sign-off ticks the goal; agent only ticks on wording drift) > returns null when the subject matches more than one goal line 0ms
✓ test/goals-flow.test.ts > /goals flow > starts work only after the supervisor launcher resolves 23ms
✓ test/goals-flow.test.ts > /goals flow > delivers an Intercom instruction to the worker 23ms
✓ test/goals-flow.test.ts > /goals flow > closes the supervisor on clear but keeps the plan file 27ms
✓ test/goals-flow.test.ts > /goals flow > accepts only an approval for the exact clean commit and goal block 163ms
✓ test/goals-flow.test.ts > process role > keeps subagent children and visible supervisors out of the worker extension 0ms
✓ test/supervisor-session.test.ts > visible supervisor session > restores monitoring and read-only tools without replaying persisted views 8ms
✓ test/supervisor-session.test.ts > visible supervisor session > renders all advice in real Pi tool rows, including collapsed and restored rows 27ms
✓ test/supervisor-session.test.ts > visible supervisor session > asks for judgment and useful recaps without inventing instructions 1ms
✓ test/supervisor-session.test.ts > visible supervisor session > writes readiness only after removing writing tools 3ms
✓ test/supervisor-session.test.ts > visible supervisor session > compacts a large planning fork before writing readiness 2ms
✓ test/supervisor-session.test.ts > visible supervisor session > does not become ready when initial compaction fails 2ms
✓ test/supervisor-session.test.ts > visible supervisor session > writes a durable worker instruction 2ms
✓ test/supervisor-session.test.ts > visible supervisor session > records approval only from a stopped view with evidence and no active work 59ms
✓ test/rpc-review.test.ts > RPC review flow > opens Refine's editor before it starts the revision turn 1226ms
stdout | test/native-intercom.test.ts > runs a forked Pi supervisor and receives its exact instruction in another Pi session
Native Pi pair: fork retained planning context; SteerWorker delivered exactly: Read the real outputs before declaring completion.
✓ test/native-intercom.test.ts > runs a forked Pi supervisor and receives its exact instruction in another Pi session 2314ms
Test Files 15 passed (15)
Tests 46 passed (46)
Start at 16:58:17
Duration 2.73s (transform 2.47s, setup 0ms, import 5.82s, tests 4.28s, environment 2ms)
> @wassname2/pi-goals@0.2.2 typecheck
> tsc --noEmit
> @wassname2/pi-goals@0.2.2 lint
> biome check src/ test/
Checked 28 files in 21ms. No fixes applied.
> @wassname2/pi-goals@0.2.2 build
> tsc
@@ -1,17 +0,0 @@
> @wassname2/pi-goals@0.2.2 test
> vitest run --run test/native-intercom.test.ts --reporter=verbose
RUN v4.1.9 /home/code/.pi/agent/git/github.com/wassname/pi-goals
stdout | test/native-intercom.test.ts > runs a forked Pi supervisor and receives its exact instruction in another Pi session
Native Pi pair: fork retained planning context; SteerWorker delivered exactly: Read the real outputs before declaring completion.
✓ test/native-intercom.test.ts > runs a forked Pi supervisor and receives its exact instruction in another Pi session 2264ms
Test Files 1 passed (1)
Tests 1 passed (1)
Start at 16:52:40
Duration 2.43s (transform 26ms, setup 0ms, import 56ms, tests 2.27s, environment 0ms)
@@ -1,24 +0,0 @@
# Initial delegated-worker test failure — Pi/OpenAI
The first implementation check ran `npm run typecheck && npm test` inside the delegated worker's inherited environment (`PI_SUBAGENT_CHILD=1`). Typecheck passed. At that point the suite reported:
```
Test Files 2 failed | 13 passed (15)
Tests 8 failed | 38 passed (46)
```
Representative actual output from that run (18:39:14):
```
FAIL test/goals-flow.test.ts > /goals flow > preserves drafts, records the interview, and keeps planning read-only
TypeError: Cannot read properties of undefined (reading 'handler')
at flow.commands.get("goals").handler("first objective", flow.ctx)
FAIL test/rpc-review.test.ts > RPC review flow > opens Refine's editor before it starts the revision turn
Error: Test timed out in 15000ms.
```
Diagnosis: the production `isMainSession()` deliberately excludes subagent children. Consequently the mock host never registered `/goals`, and the real RPC test process inherited the child flag and did not register it either. This was not treated as a passing test and no product guard was removed to conceal it.
Exact corrected test command: `env -u PI_SUBAGENT_CHILD -u PI_GOALS_ROLE npm test`.
That rerun passed all 46 then-existing tests. Subsequent added regressions also passed. The final complete command and unabridged final output are saved in `20260908-review-fixes-validation.txt`; it uses the same two-variable isolation. All role-specific tests still explicitly configure their intended role. No live user session's environment or settings were changed.
@@ -1,4 +0,0 @@
worker: 21 events parsed; 0 errors; stderr empty
Worker user-message event contains exact instructed text.
supervisor: 21 events parsed; 0 errors; stderr empty
Supervisor outbound/ack ID matched: 780f7dac-e4e5-4351-b890-0684a42de681. This is adapter handling, not durable queue confirmation.
@@ -1,93 +0,0 @@
COMMAND: env -u PI_SUBAGENT_CHILD -u PI_GOALS_ROLE PI_GOALS_EVIDENCE_DIR="$PWD/slop/reviews/review-fixes-native" npm test -- --reporter=verbose && npm run typecheck && npm run lint && npm run build && git diff --check
> @wassname2/pi-goals@0.2.2 test
> vitest run --reporter=verbose
RUN v4.1.9 /home/code/.pi/agent/git/github.com/wassname/pi-goals
✓ test/package-agent.test.ts > package manifest > includes the extension without registering a packaged subagent 2ms
✓ test/approval.test.ts > hashes only the current goal, excluding the log, interview, and their historical goal text 3ms
✓ test/prompts.test.ts > planning prompt > requires fact finding or a focused question before a goal 3ms
✓ test/prompts.test.ts > planning prompt > restores the same rule after compaction 0ms
✓ test/prompts.test.ts > planning prompt > anchors work and sign-off to the user-visible result 1ms
stdout | test/role-models.test.ts > remembers each role without automatic switching overwriting another role
Role preferences restored: planning=planner, worker=small-worker, supervisor=astra; restore events did not overwrite the choice.
✓ test/background.test.ts > reports tracked running work, rather than equating idle agent with finished jobs 3ms
✓ test/background.test.ts > distinguishes missing providers from an unavailable installed tracker 6ms
✓ test/role-models.test.ts > remembers each role without automatic switching overwriting another role 7ms
✓ test/role-models.test.ts > fails on an unavailable remembered model without replacing the choice 4ms
✓ test/worker-view.test.ts > keeps human direction and source location while sending only new messages 3ms
✓ test/worker-view.test.ts > restarts after compaction and does not report historical tool calls as active 1ms
✓ test/worker-view.test.ts > bounds serialized Unicode and quoted logs while marking omissions 3ms
✓ test/herdr.test.ts > supervisor pane command > forks the planning session with pi-goals owning its Intercom dependency 3ms
✓ test/herdr.test.ts > supervisor pane command > accepts Herdr's text version output and stale pane cleanup 25ms
✓ test/intercom.test.ts > pi-intercom transport > receives exact advice once, acknowledges it and rejects unrelated peers 5ms
✓ test/intercom.test.ts > pi-intercom transport > restores an unacknowledged steer on reconnect and stops replay after acknowledgment 3ms
✓ test/intercom.test.ts > pi-intercom transport > advances the incremental overview only after acknowledgment 1ms
✓ test/intercom.test.ts > pi-intercom transport > cancels a readiness wait on shutdown 1ms
✓ test/intercom.test.ts > does not acknowledge a synchronous handoff failure, and retries the instruction 1ms
✓ test/intercom.test.ts > detaches a completed binding and ignores its late advice without replay errors or false acceptance 1ms
✓ test/append-log.test.ts > appendLog (the extension's only plan-file write) > creates ## Log at EOF when absent 2ms
✓ test/append-log.test.ts > appendLog (the extension's only plan-file write) > appends after the last existing log line, before any following header 0ms
✓ test/tick-goal.test.ts > tickGoal (sign-off ticks the goal; agent only ticks on wording drift) > ticks the exact-matching goal line, case-insensitive, leaving subtasks alone 2ms
✓ test/tick-goal.test.ts > tickGoal (sign-off ticks the goal; agent only ticks on wording drift) > returns null on wording drift (fuzzy matching is the judge's job, not TypeScript's) 0ms
✓ test/tick-goal.test.ts > tickGoal (sign-off ticks the goal; agent only ticks on wording drift) > returns null when the subject matches more than one goal line 0ms
✓ test/fold.test.ts > foldPlan (current goals are above ## Log; durable memory is below it) > keeps the title, user voice and goals 2ms
✓ test/fold.test.ts > foldPlan (current goals are above ## Log; durable memory is below it) > drops the log, the learnings and the unlimited appendix 1ms
✓ test/fold.test.ts > foldPlan (current goals are above ## Log; durable memory is below it) > returns the whole plan when there is no ## Log yet (a fresh draft) 0ms
✓ test/fold.test.ts > openSubtasks (the widget shows the next action, so the plan IS the task list) > lists the active goal's open and in-progress subtasks, stopping at the next goal 1ms
✓ test/fold.test.ts > openSubtasks (the widget shows the next action, so the plan IS the task list) > does not leak subtasks from the goal below 1ms
stdout | test/intercom-broker.test.ts > exchanges readiness, views and exact advice over a real isolated pi-intercom broker
Intercom broker: readiness confirmed; exact worker view and supervisor advice received.
✓ test/intercom-broker.test.ts > exchanges readiness, views and exact advice over a real isolated pi-intercom broker 226ms
✓ test/goals-flow.test.ts > /goals flow > reports actual idle state, invalidates stopped views on start, and stops completed plans 45ms
✓ test/goals-flow.test.ts > /goals flow > preserves drafts, records the interview, and keeps planning read-only 21ms
✓ test/goals-flow.test.ts > /goals flow > forks a visible supervisor on Ready and keeps the main session as worker 26ms
✓ test/goals-flow.test.ts > /goals flow > starts work only after the supervisor launcher resolves 19ms
✓ test/goals-flow.test.ts > /goals flow > delivers an Intercom instruction to the worker 22ms
✓ test/goals-flow.test.ts > /goals flow > closes the supervisor on clear but keeps the plan file 23ms
✓ test/goals-flow.test.ts > /goals flow > accepts only an approval for the exact clean commit and goal block 42ms
✓ test/goals-flow.test.ts > process role > keeps subagent children and visible supervisors out of the worker extension 0ms
✓ test/goals-flow.test.ts > restores working linkage even when its remembered model is unavailable, and supports explicit recovery 19ms
✓ test/goals-flow.test.ts > restores planning linkage even when its remembered model is unavailable, and supports explicit recovery 18ms
✓ test/goals-flow.test.ts > shows a missing resumed supervisor, pauses writes, and automatically unpauses when that peer returns 19ms
✓ test/goals-flow.test.ts > times out stale Ready retries in five seconds, without replacing the pane automatically 27ms
✓ test/goals-flow.test.ts > explicitly restarts only the tracked pane, keeps the plan, and invalidates old approval binding 22ms
✓ test/goals-flow.test.ts > does not persist startup results or launch work after session shutdown 19ms
✓ test/supervisor-session.test.ts > visible supervisor session > restores monitoring and read-only tools without replaying persisted views 8ms
✓ test/supervisor-session.test.ts > visible supervisor session > renders all advice in real Pi tool rows, including collapsed and restored rows 28ms
✓ test/supervisor-session.test.ts > visible supervisor session > asks for judgment and useful recaps without inventing instructions 2ms
✓ test/supervisor-session.test.ts > visible supervisor session > writes readiness only after removing writing tools 19ms
✓ test/supervisor-session.test.ts > visible supervisor session > compacts a large planning fork before writing readiness 2ms
✓ test/supervisor-session.test.ts > visible supervisor session > does not become ready when initial compaction fails 2ms
✓ test/supervisor-session.test.ts > visible supervisor session > writes a durable worker instruction 2ms
✓ test/supervisor-session.test.ts > visible supervisor session > records approval only from a stopped view with evidence and no active work 89ms
✓ test/supervisor-session.test.ts > blocks the general intercom actuator even if enabled after startup 2ms
✓ test/supervisor-session.test.ts > keeps a supervisor unready after model restoration failure, then recovers explicitly without substituting a model 2ms
✓ test/rpc-review.test.ts > RPC review flow > opens Refine's editor before it starts the revision turn 1303ms
stdout | test/native-intercom.test.ts > runs a forked Pi supervisor and receives its exact instruction in another Pi session
Native Pi pair: fork retained planning context; SteerWorker delivered exactly: Read the real outputs before declaring completion.
✓ test/native-intercom.test.ts > runs a forked Pi supervisor and receives its exact instruction in another Pi session 2338ms
Test Files 16 passed (16)
Tests 57 passed (57)
Start at 18:57:11
Duration 2.57s (transform 1.87s, setup 0ms, import 4.26s, tests 4.46s, environment 2ms)
> @wassname2/pi-goals@0.2.2 typecheck
> tsc --noEmit
> @wassname2/pi-goals@0.2.2 lint
> biome check src/ test/
Checked 29 files in 28ms. No fixes applied.
> @wassname2/pi-goals@0.2.2 build
> tsc
-38
View File
@@ -1,38 +0,0 @@
# Independent review fixes — Pi/OpenAI implementation worker
Baseline: `2824396a711ed56bd462742ab22620df44e5624f`.
Original independent review: [preserved review and attribution](20260908-independent-supervision-bug-review.md), run `5c8c2017-a92f-4a5f-baf6-f441f9b50495`.
The parent approved explicit `/goals reconnect` and `/goals restart`, with human input and read-only diagnosis available while paused. No existing user pane/session was inspected, operated, restarted, or closed. All Herdr recovery operations in this work used mocks. No additional reviewer or subagent was launched by this worker.
Read AGENTS.md and installed Pi extension documentation covering session replacement/shutdown, sequential events, model selection, input, command context, tool gates, compaction and context usage before editing extension lifecycle code. The native tests use repository-local Pi **0.84.1**; the parent host's 0.85.1 version is not the test executable's version.
## Finding dispositions
| Finding | Disposition and concrete proof |
| --- | --- |
| F1: unavailable remembered model aborts restore | Confirmed and fixed. Planning injection and worker binding/timers initialize independently of model selection. A failure leaves an explicit paused widget and gates implementation/sign-off, not a partially initialized normal worker. No fallback model is selected. The worker does not announce readiness until model restoration succeeds. `/model` followed by `/goals reconnect` retries the same plan. Added flow reproductions for both working/planning restoration and supervisor model recovery. Tests assert no `setModel` on unavailable lookup, no ready hello, preserved preferences/binding/version, retained human input, allowed diagnostic reads, blocked writes/sign-off and successful explicit recovery. |
| F2: resumed worker silently has no supervisor | Confirmed and fixed. Connection changes update the widget immediately; absence on restore warns after five seconds. Writes/sign-off are gated while disconnected; human prompts, diagnostic reads and recovery commands remain available. Returning peers clear the connection pause automatically. Explicit restart preserves the working plan and replaces only its tracked pane with a new approval binding. Tests exercise a never-answering peer, later hello, exact owned-pane close, unchanged plan/version, removed old checkpoint, and no automatic pane replacement. |
| F3: inactive-plan steer throws/replays | Confirmed; lifecycle cause addressed without premature acceptance. Completed, cancelled or cleared plans detach their binding and announce not-ready; stale advice is ignored without invoking delivery or acknowledging it. Tests cover completion/clear not accepting advice or restarting, transport detach, and a *synchronous handoff* failure remaining unrecorded/unacked until retry succeeds. **Delivery gap remains:** Pi 0.84.1 `dist/core/agent-session.js:18551862` implements ExtensionAPI.sendUserMessage as a void wrapper calling async `this.sendUserMessage(...).catch(emitError)`; `:11061133` awaits `prompt` internally. The adapter therefore cannot observe durable enqueue success. An async enqueue error may occur after the ack and suppress replay even though the model never received the instruction. A crash between handoff and recording can instead duplicate it. Pending transport messages retain at-least-once retry semantics, but end-to-end durable/at-least-once/exactly-once model delivery is NOT guaranteed. Recording/acking before even the synchronous handoff would worsen loss and was deliberately NOT implemented. Parent explicitly accepted documenting this deeper limitation rather than expanding the protocol in this commit. README and the code comment distinguish adapter handling from persistence/model receipt/execution. |
| F4: stale pane causes repeated five-minute Ready waits | Confirmed and fixed. Existing-pane Ready/reconnect waits are five seconds, with explicit reconnect/restart guidance. First-time launch retains the five-minute compaction allowance. Failed `pane run` retains the pane ID for inspection and reports it. No automatic probe-driven kill/replacement of a possibly healthy slow supervisor. Planning restart clears its failed tracked pane for the next Ready; working restart forks a replacement immediately. Test simulates split success/run failure and two Ready attempts, and proves one launch, zero automatic closes, and a five-second retry. Startup results arriving after shutdown are not persisted and do not launch worker work. |
| F5: general intercom tool available to supervisor | Confirmed and fixed. `intercom` is removed alongside writing tools before readiness and blocked at tool-call time even if later re-enabled. `SteerWorker` remains available. Both mocked gate tests and the real native pair test assert this; the latter inspects the actual supervisor model request's tool list. |
| F6: nested placeholder evidence accepted | Confirmed and fixed. The same exact `(empty until sign-off)` rejection applies to inline and child bullets. Tests exercise both through `ApproveGoal`, assert no approval file, then confirm actual nonblank evidence still passes. This is a presence floor, not a semantic evidence judge; unrelated nonblank prose still requires supervisor judgment. |
| F7: last goal hash includes Log/Interview | Confirmed and fixed. The canonical block ignores the Log and stops at the next goal or top-level section. Trailing section-separator whitespace is excluded. Unit tests cover log history containing duplicate goal text, interview, next goal, and actual goal edits still invalidating the hash. The flow test appends a manual Log entry between approval and CompleteGoal and still succeeds. Previously recorded hashes may require a fresh approval after upgrade (fail closed). |
| F8: unknown usage disables 100k compaction | Assessed; no speculative estimator added. Installed `agent-session.js:getContextUsage()` returns undefined without a usable model/window and explicitly returns `tokens: null` after compaction until a later assistant usage sample exists. Native RPC tests have valid usage; RPC mode itself is not evidence of permanent unavailability. Existing unknown handling avoids immediate repeat compaction. Persistent unavailable usage still prevents the custom 100k trigger; this remains a documented limitation, not claimed fixed. |
| F9: planning read-only guard residuals | Confirmed as a guardrail limitation, not fixed by broad tool/shell policy changes in this task. Planning still explicitly gates edit/write and selected bash commands, not every installed extension actuator. Git read commands can invoke configured external diff/textconv programs. Paused diagnostic bash uses this same heuristic, so trusted repository configuration and extensions are required; it is NOT a security sandbox. README now states this. A hardened shell policy or comprehensive planning tool allowlist needs separately scoped review; no claim of airtight isolation is made. |
## Validation and inspected evidence
- [Full final command/output](20260908-review-fixes-validation.txt): **57 tests passed in 16 files**, typecheck, lint, build and `git diff --check` passed.
- Exact test environment isolation: `env -u PI_SUBAGENT_CHILD -u PI_GOALS_ROLE PI_GOALS_EVIDENCE_DIR="$PWD/slop/reviews/review-fixes-native" npm test -- --reporter=verbose`. This runs main-session tests as a main session, while explicit role tests still select their role.
- [Initial child-environment failure](20260908-review-fixes-initial-validation.md): recorded the original failure (8 failed/38 passed), cause and exact corrected command. It was not omitted or counted as a pass.
- Inspected [worker native events](review-fixes-native/worker-events.jsonl) and [supervisor native events](review-fixes-native/supervisor-events.jsonl): the worker received `[supervisor] Read the real outputs before declaring completion.`; supervisor out and ack records share the same instruction ID in the saved run. Both stderr files are empty; neither event log contains an error/failed-response/error-notification record.
- Tests preserve human recovery/input while paused, peer-return unpause, and clear/complete not receiving stale advice or reopening supervision. Shutdown guards prevent late startup results from writing the disposed runtime.
## Remaining acceptance limits
**Priority residual: F3 durable delivery confirmation is still open.** Required UAT for a future correlated-receipt design: force an asynchronous Pi enqueue rejection after the adapter returns; the supervisor must not report confirmed model delivery and the instruction must remain recoverable. The current receipt does not make that promise.
These fixes still need the parent's independent post-change review. The native pair uses a deterministic local model and a transport-only worker fixture; it proves routing/context retention and supervisor tool exposure, not good judgment, cost savings, rendered Herdr behavior, or the full two-native-session ApproveGoal → CompleteGoal chain. Full fresh-shell supervisor role restoration without launcher environment remains unverified. An already-created pane can remain for inspection if shutdown interrupts startup; the fix avoids stale context use rather than silently operating such a pane. Background work is not killed by recovery, and unregistered detached work remains outside tracker coverage.
No changes were pushed by this implementation worker.
@@ -1,73 +0,0 @@
> @wassname2/pi-goals@0.2.2 test
> vitest run --reporter=verbose
RUN v4.1.9 /home/code/.pi/agent/git/github.com/wassname/pi-goals
✓ test/package-agent.test.ts > package manifest > includes the extension without registering a packaged subagent 3ms
stdout | test/role-models.test.ts > remembers each role without automatic switching overwriting another role
Role preferences restored: planning=planner, worker=small-worker, supervisor=astra; restore events did not overwrite the choice.
✓ test/background.test.ts > reports tracked running work, rather than equating idle agent with finished jobs 2ms
✓ test/background.test.ts > distinguishes missing providers from an unavailable installed tracker 6ms
✓ test/role-models.test.ts > remembers each role without automatic switching overwriting another role 7ms
✓ test/role-models.test.ts > fails on an unavailable remembered model without replacing the choice 6ms
✓ test/prompts.test.ts > planning prompt > requires fact finding or a focused question before a goal 2ms
✓ test/prompts.test.ts > planning prompt > restores the same rule after compaction 0ms
✓ test/prompts.test.ts > planning prompt > anchors work and sign-off to the user-visible result 0ms
✓ test/intercom.test.ts > pi-intercom transport > receives exact advice once, acknowledges it and rejects unrelated peers 5ms
✓ test/intercom.test.ts > pi-intercom transport > restores an unacknowledged steer on reconnect and stops replay after acknowledgment 3ms
✓ test/intercom.test.ts > pi-intercom transport > advances the incremental overview only after acknowledgment 1ms
✓ test/intercom.test.ts > pi-intercom transport > cancels a readiness wait on shutdown 1ms
✓ test/herdr.test.ts > supervisor pane command > forks the planning session with pi-goals owning its Intercom dependency 2ms
✓ test/herdr.test.ts > supervisor pane command > accepts Herdr's text version output and stale pane cleanup 30ms
✓ test/worker-view.test.ts > keeps human direction and source location while sending only new messages 2ms
✓ test/worker-view.test.ts > restarts after compaction and does not report historical tool calls as active 0ms
✓ test/worker-view.test.ts > bounds serialized Unicode and quoted logs while marking omissions 2ms
✓ test/fold.test.ts > foldPlan (current goals are above ## Log; durable memory is below it) > keeps the title, user voice and goals 2ms
✓ test/fold.test.ts > foldPlan (current goals are above ## Log; durable memory is below it) > drops the log, the learnings and the unlimited appendix 0ms
✓ test/fold.test.ts > foldPlan (current goals are above ## Log; durable memory is below it) > returns the whole plan when there is no ## Log yet (a fresh draft) 0ms
✓ test/fold.test.ts > openSubtasks (the widget shows the next action, so the plan IS the task list) > lists the active goal's open and in-progress subtasks, stopping at the next goal 1ms
✓ test/fold.test.ts > openSubtasks (the widget shows the next action, so the plan IS the task list) > does not leak subtasks from the goal below 1ms
stdout | test/intercom-broker.test.ts > exchanges readiness, views and exact advice over a real isolated pi-intercom broker
Intercom broker: readiness confirmed; exact worker view and supervisor advice received.
✓ test/append-log.test.ts > appendLog (the extension's only plan-file write) > creates ## Log at EOF when absent 1ms
✓ test/append-log.test.ts > appendLog (the extension's only plan-file write) > appends after the last existing log line, before any following header 0ms
✓ test/tick-goal.test.ts > tickGoal (sign-off ticks the goal; agent only ticks on wording drift) > ticks the exact-matching goal line, case-insensitive, leaving subtasks alone 2ms
✓ test/tick-goal.test.ts > tickGoal (sign-off ticks the goal; agent only ticks on wording drift) > returns null on wording drift (fuzzy matching is the judge's job, not TypeScript's) 0ms
✓ test/tick-goal.test.ts > tickGoal (sign-off ticks the goal; agent only ticks on wording drift) > returns null when the subject matches more than one goal line 0ms
✓ test/intercom-broker.test.ts > exchanges readiness, views and exact advice over a real isolated pi-intercom broker 222ms
✓ test/goals-flow.test.ts > /goals flow > reports actual idle state, invalidates stopped views on start, and stops completed plans 36ms
✓ test/goals-flow.test.ts > /goals flow > preserves drafts, records the interview, and keeps planning read-only 24ms
✓ test/goals-flow.test.ts > /goals flow > forks a visible supervisor on Ready and keeps the main session as worker 26ms
✓ test/goals-flow.test.ts > /goals flow > starts work only after the supervisor launcher resolves 21ms
✓ test/goals-flow.test.ts > /goals flow > delivers an Intercom instruction to the worker 21ms
✓ test/goals-flow.test.ts > /goals flow > closes the supervisor on clear but keeps the plan file 19ms
✓ test/goals-flow.test.ts > /goals flow > accepts only an approval for the exact clean commit and goal block 47ms
✓ test/goals-flow.test.ts > process role > keeps subagent children and visible supervisors out of the worker extension 0ms
✓ test/supervisor-session.test.ts > visible supervisor session > restores monitoring and read-only tools without replaying persisted views 7ms
✓ test/supervisor-session.test.ts > visible supervisor session > renders all advice in real Pi tool rows, including collapsed and restored rows 22ms
✓ test/supervisor-session.test.ts > visible supervisor session > asks for judgment and useful recaps without inventing instructions 1ms
✓ test/supervisor-session.test.ts > visible supervisor session > writes readiness only after removing writing tools 2ms
✓ test/supervisor-session.test.ts > visible supervisor session > compacts a large planning fork before writing readiness 2ms
✓ test/supervisor-session.test.ts > visible supervisor session > does not become ready when initial compaction fails 3ms
✓ test/supervisor-session.test.ts > visible supervisor session > writes a durable worker instruction 5ms
✓ test/supervisor-session.test.ts > visible supervisor session > records approval only from a stopped view with evidence and no active work 49ms
✓ test/rpc-review.test.ts > RPC review flow > opens Refine's editor before it starts the revision turn 1427ms
Test Files 14 passed (14)
Tests 45 passed (45)
Start at 16:49:24
Duration 1.79s (transform 1.51s, setup 0ms, import 4.33s, tests 2.03s, environment 1ms)
> @wassname2/pi-goals@0.2.2 typecheck
> tsc --noEmit
> @wassname2/pi-goals@0.2.2 lint
> biome check src/ test/
Checked 26 files in 62ms. No fixes applied.

Some files were not shown because too many files have changed in this diff Show More