pi-goal-list-loop-audit 0.35.13 → 0.35.64

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. package/CHANGELOG.md +977 -0
  2. package/INSTALL.md +13 -3
  3. package/LIST-PHILOSOPHY.md +90 -0
  4. package/PLAN.md +316 -0
  5. package/README.md +201 -26
  6. package/docs/DESIGN-subagent-visibility.md +76 -0
  7. package/docs/DESIGN.md +59 -8
  8. package/docs/GLLA-POSITIONING-AND-DECOMPOSITION-2026-08-08.md +6 -1
  9. package/docs/INDEX.md +4 -0
  10. package/docs/VISION-ASSIST.md +2 -2
  11. package/extensions/auditor-extensions.ts +289 -0
  12. package/extensions/context-hygiene.ts +129 -0
  13. package/extensions/faulty-objective-recovery.ts +24 -0
  14. package/extensions/glla-state-root.ts +99 -0
  15. package/extensions/goal-agents-panel.ts +211 -0
  16. package/extensions/goal-commands.ts +226 -10
  17. package/extensions/goal-continuation.ts +119 -21
  18. package/extensions/goal-heartbeat.ts +560 -35
  19. package/extensions/goal-loop-auditor-process.ts +126 -4
  20. package/extensions/goal-loop-auditor.ts +3 -5
  21. package/extensions/goal-loop-backoff.ts +79 -0
  22. package/extensions/goal-loop-core.ts +197 -15
  23. package/extensions/goal-loop-dispatch.ts +3 -2
  24. package/extensions/goal-loop-display.ts +141 -8
  25. package/extensions/goal-loop-forever.ts +52 -3
  26. package/extensions/goal-loop-shield.ts +132 -26
  27. package/extensions/goal-loop-stats.ts +3 -2
  28. package/extensions/goal-loop.ts +101 -4
  29. package/extensions/goal-recovery.ts +8 -2
  30. package/extensions/goal-settings.ts +61 -14
  31. package/extensions/goal-state.ts +20 -0
  32. package/extensions/loops/goal-activation.ts +426 -45
  33. package/extensions/loops/goal-auditor-hooks.ts +39 -3
  34. package/extensions/loops/goal-auditor-surface.ts +32 -0
  35. package/extensions/loops/goal-list-queue.ts +72 -12
  36. package/extensions/loops/goal-orchestrator.ts +33 -1
  37. package/extensions/loops/goal-runtime-globals.ts +5 -0
  38. package/extensions/loops/goal-session.ts +68 -8
  39. package/extensions/loops/goal-settings-ui.ts +116 -5
  40. package/extensions/loops/goal-tools.ts +104 -29
  41. package/extensions/loops/goal-ui.ts +106 -1
  42. package/extensions/loops/goal.ts +7 -7
  43. package/extensions/main-model-recovery.ts +10 -0
  44. package/extensions/multi-model-picker.ts +45 -7
  45. package/extensions/payload-guard.ts +172 -0
  46. package/extensions/reviewer.ts +3 -1
  47. package/extensions/settings-menu.ts +39 -4
  48. package/package.json +9 -3
  49. package/prompts/goal-loop-plan-loop.md +31 -0
  50. package/prompts/goal-loop-plan.md +51 -0
  51. package/schemas/goal.schema.json +4 -1
  52. package/scripts/auditor-extension-fixture.mjs +19 -0
  53. package/scripts/goal-auditor-launch.mjs +19 -1
  54. package/scripts/goal-auditor-worker.mjs +15 -0
  55. package/scripts/verify-auditor-extensions-offline.mjs +72 -0
package/INSTALL.md CHANGED
@@ -52,7 +52,7 @@ Then the other two modes:
52
52
 
53
53
  ## Install from source (developers)
54
54
 
55
- Prerequisites: Node 22+ and bun (the test runner — `bun test`), pi-coding-agent, TypeScript 5.9+ (for `tsc --noEmit`).
55
+ Prerequisites: Node 22.19.0+ and bun (the test runner — `bun test`), pi-coding-agent, TypeScript 5.9+ (for `tsc --noEmit`).
56
56
 
57
57
  ```bash
58
58
  git clone https://github.com/DraconDev/pi-goal-list-loop-audit.git # or use the local dir
@@ -111,8 +111,8 @@ a file or committed — narration alone is the narrate-but-don't-ship loop)
111
111
  Why it changed: the v0.24.0 single-signal detector (same tool + same
112
112
  result hash 3×) killed two real user loops that were shipping work with
113
113
  stable verification output — stable verification is the GOAL state of a
114
- metricless loop, not the stuck state. Design doc:
115
- `audit/STUCK-DETECTION-REWORK-2026-07-24.md`. `/loop start toolsamerepeat=0`
114
+ metricless loop, not the stuck state. See `docs/DESIGN.md` for the shipped
115
+ design overview. `/loop start toolsamerepeat=0`
116
116
  disables the legacy check entirely; `/loop finish [reason]` ends a loop
117
117
  cleanly with stopReason `completed: <reason>` (distinct from
118
118
  stuck/plateau/stopped-by-user).
@@ -143,6 +143,16 @@ NOT pause: the auditor's objections become a TODO list (`pendingTasks`)
143
143
  rendered into every continuation, and the goal stays ACTIVE. Every
144
144
  auto-event announces itself with a one-line notify.
145
145
 
146
+ ## Subagent stall action (v0.35.64)
147
+
148
+ The subagent watchdog warns after short no-progress windows. A top-level
149
+ tracked child that remains frozen for the longer
150
+ `subagentHangEscalationMinutes` threshold (default `30`) receives one
151
+ child-specific abort request; the parent goal is not aborted. Set the value to
152
+ `0` under `/glla` for warning/telemetry only. Unreachable, nested, or
153
+ ownership-ambiguous children remain warning-only, and partial output stays
154
+ available for inspection.
155
+
146
156
  ## Subagent model inheritance (v0.24.6)
147
157
 
148
158
  If you use `@tintinweb/pi-subagents`: its default `Explore` agent pins
@@ -0,0 +1,90 @@
1
+ # List philosophy — the three-mode hierarchy
2
+
3
+ pi-goal-list-loop-audit ships three loops. They are NOT redundant — each
4
+ has a **distinct source of long-running-ness**:
5
+
6
+ | Mode | Item size | Long-running by | Typical lifetime |
7
+ |---|---|---|---|
8
+ | `/goal` | ONE big multi-hour task | **Scope** | Hours |
9
+ | `/list` | N items × short (minutes each) | **Queue depth** | Hours → days → weeks |
10
+ | `/loop` | 1 metric × infinite polish | **Bounds** | Until plateau/stop/finish |
11
+
12
+ ## `/goal` — one big long task
13
+
14
+ `/goal` is the multi-hour mode. Its long-running property is **scope**:
15
+ one task that spans multiple agent runs, requires deep research, or would
16
+ take hours end-to-end. It ends only when the isolated auditor approves
17
+ the verification contract. If your work fits in a single agent run — a
18
+ focused change, one audit, a small refactor — it belongs in `/list`.
19
+
20
+ ## `/list` — hundreds of short items
21
+
22
+ `/list` items are **short tasks, not multi-hour objectives**. Each item
23
+ should fit comfortably in a single agent run: minutes of work, a single
24
+ focused change. The list's long-running property is **queue depth** — the
25
+ queue can hold hundreds of items, activated one at a time, pushed over
26
+ days or weeks. An item longer than ~30 minutes probably wants breaking
27
+ up; much longer and it wants `/goal`.
28
+
29
+ `/list depth` shows the long-running state: queue depth, oldest item age,
30
+ and average item duration from your archived list items.
31
+
32
+ ## `/loop` — metric-driven infinite polish
33
+
34
+ `/loop` improves ONE metric forever. Its long-running property is
35
+ **bounds**: it ends on plateau, on bounds (max iterations / time /
36
+ tokens), on `/loop stop`, or on `/loop finish` (graceful stop after the
37
+ current iteration).
38
+
39
+ ## The wrapper-goal anti-pattern (why this doc exists)
40
+
41
+ Real incidents, 2026-07-24, two projects on the same day:
42
+
43
+ > "Close every weak point in `docs/per-screen-weak-points.md` (76 items,
44
+ > one commit each)" and "land all 40 findings as a tasklist, ordered by
45
+ > ROI" — each folded into **ONE** list item with an **aggregate**
46
+ > verification contract ("≥ 76 commits with `CLOSED:`", "≥ 32 fix(Wn)
47
+ > commits").
48
+
49
+ The work got done; the auto-committer squashed intermediate commits; the
50
+ literal commit count failed; the isolated auditor **correctly
51
+ disapproved** finished work. The failure was at step 1 — task
52
+ designation — not at the audit.
53
+
54
+ The fix: **N independent short items → N `/list` items**, each closing
55
+ exactly ONE finding with its own per-item contract ("close IMP-AUD3-68:
56
+ `Map.svelte:1528` missing `role`"). Per-item contracts are impossible to
57
+ squash. Any aggregate re-audit becomes the FINAL `/goal`, not the first.
58
+
59
+ Since v0.25.3 the drafting flow detects this shape ("N items" + "each" +
60
+ "one commit") and steers you to `items[]` — see the cross-recommend
61
+ block in `prompts/goal-loop-draft.md`.
62
+
63
+ Since v0.26.0 the **Reviewer** is the post-completion glue layer across
64
+ all three modes' terminal states: it converts completion findings into
65
+ `/list` items (bug/refactor, no Confirm), proposes architectural work as
66
+ `/goal` (Confirm), fires a regression-scan audit on clean completions,
67
+ and notifies + idles otherwise. See `INSTALL.md` "Reviewer".
68
+
69
+ ## Audit Cadence: Why Every `/list` Task is Audited
70
+
71
+ Auditing occurs at the completion boundary of **every single `/list` task** (via the detached isolated auditor) before the next item in the queue can activate.
72
+
73
+ While auditing every item requires rigorous verification, it prevents **queue drift**:
74
+ - In a 50-item list, an unverified error in item #2 would otherwise silently corrupt the codebase, causing items #3 through #50 to fail or build on broken invariants.
75
+ - Per-task auditing ensures each item represents a rock-solid, verified invariant before the next task begins.
76
+
77
+ ## Single-Trunk Execution Law & Parallelization
78
+
79
+ ### Why "Main-Only" Outperforms Branch Swarms in Autonomous Loops
80
+ Speculative feature branching across autonomous subagents creates **stale context bubbles** and **merge collision debt**:
81
+ 1. Agent A on branch-1 and Agent B on branch-2 both read from snapshot $T_0$.
82
+ 2. Once Agent A lands a commit, Agent B is working on an obsolete codebase without knowing it.
83
+ 3. Merging parallel LLM branches frequently causes semantic regressions and broken invariants.
84
+
85
+ ### The Single-Trunk Operating Rule:
86
+ * **Serial Queue on `main`**: All queue items drain sequentially on the single primary working tree. Item $N+1$ always executes with 100% truthful, up-to-date context left by item $N$.
87
+ * **Transactional Green-or-Revert**: Every task either lands green (verified by tests and the detached auditor) and commits, or cleanly rolls back on `main` before the next backlog item is touched.
88
+ * **Safe Subagent Parallelism**: Subagents are used for **read-only research fan-out** (e.g. concurrent `Explore` queries across subsystems in a single turn) or standalone verification, rather than speculative mutating branches.
89
+
90
+ See `INSTALL.md` for the command surface.
package/PLAN.md ADDED
@@ -0,0 +1,316 @@
1
+ # PLAN — pi-goal-list-loop-audit
2
+
3
+ Living plan for the project. Update this file as decisions land or milestones close.
4
+ New here? Start with README.md and INSTALL.md — this file is the historical
5
+ plan, not the onboarding path.
6
+ Last updated: v0.29.6 (header refresh). The milestones
7
+ below cover the v0.1.0–v0.7.0 scaffold era; later decisions live in CHANGELOG.md
8
+ (current through v0.29.6) and the current-state addendum in docs/DESIGN.md.
9
+
10
+ ---
11
+
12
+ ## 0. Product definition (frozen)
13
+
14
+ - **What it is**: a pi-coding-agent extension that supervises long-running work to *verified* completion.
15
+ - **Core mechanism**: a shared goal state machine + an `agent_end`-driven continuation loop + an **isolated auditor** (fresh pi session, no extensions, no skills, power-mode audit tools: read/grep/find/ls/bash) that must approve before a goal is marked complete.
16
+ - **Three loops on one machine**:
17
+ - **goal** — one ordered goal, audited (`/goal`)
18
+ - **list** — a queue of goals, each audited in turn (`/list`)
19
+ - **loop** — a forever-polish loop around a measurable target (`/loop`)
20
+ - **Naming is frozen**: commands are `/goal*`, `/list*`, `/loop*`. No `pi-gla-` prefix, no `oracle/sisyphus/squad/forge` metaphors anywhere (code, files, docs, keywords).
21
+
22
+ ### Non-goals (v0.x)
23
+
24
+ - No interop with `pi-goal-x` state (`.pi/goals/`). Clean break, `.pi-gla/` only.
25
+ - No web dashboard, no remote control, no multi-machine coordination.
26
+ - No planner/decomposer that invents the goal for the user (drafting *clarifies*; it does not originate).
27
+
28
+ ---
29
+
30
+ ## 1. Milestones & acceptance criteria
31
+
32
+ ### M0 — v0.1.0-alpha.1 scaffold ✅ (done)
33
+
34
+ - [x] Package layout, LICENSE, README, CHANGELOG, DESIGN, tsconfig
35
+ - [x] `extensions/loops/goal.ts` — commands + agent tools + agent_end loop
36
+ - [x] `extensions/goal-loop-core.ts` — types, JSONL ledger, markdown renderer
37
+ - [x] `extensions/goal-loop-auditor.ts` — isolated auditor session
38
+ - [x] `extensions/goal-loop-backoff.ts` — 5-min hard cap
39
+ - [x] `prompts/goal-loop-continuation.md`, `schemas/goal.schema.json`
40
+ - [x] 24 unit tests green (`npm test`)
41
+ - **Exit evidence**: `npm test` → 24/24 pass (verified 2026-07-20).
42
+
43
+ ### M1 — v0.1.0 (first real release)
44
+
45
+ Scope: make the goal loop actually work end-to-end in a live pi session. No new features.
46
+
47
+ - [ ] **Type-check clean**: `npm run check` (tsc --noEmit) → 0 errors.
48
+ - Known risk: `ExtensionContext`, `defineTool` import path, `pi.registerCommand` arg shapes were written against memory of pi-goal-x, not verified against the installed pi 0.74 API.
49
+ - [x] **Live smoke test** ✅ 2026-07-20 — full loop verified end-to-end in tmux: `/goal` → agent works → `complete_goal` → isolated auditor (opencode/deepseek-v4-flash-free, extension-less) approves → archived with clean 1-entry history + real auditor report.
50
+ - [x] **Fix whatever the smoke test breaks** ✅ — 6 real fixes: (1) API imports from public entrypoint + pi-ai/pi-agent-core types; (2) `sendMessage` on `pi` API not `ctx`; (3) stale-ctx crash → `lastCtx`/`rememberCtx` pattern; (4) `details:{}` in tool results, async handlers, `tool_call` event name; (5) auditor model default → `ctx.model` + string-ref resolver; (6) audit-history pollution — record only non-empty reports, cap at 20, include `error` field.
51
+ - [x] **Escape hatch verified** ✅ (with caveat) — Esc during audit aborts the pi turn; the auditor session may complete detached. Loop recovers cleanly via `agent_end` (verified live: 3 empty audits then approval). pi-goal-x's fancy Escape dialog is v0.2.0 scope. Abort signal is threaded into the auditor for when pi wires tool-level abort properly.
52
+ - [x] **Backoff cap verified** ✅ (incidentally, live) — openrouter 403 storm triggered exactly "Goal paused: 5 consecutive errors" auto-pause.
53
+ - [ ] Update CHANGELOG, tag `v0.1.0`, `npm publish`.
54
+
55
+ **Live smoke script** (target: < 5 min):
56
+ ```
57
+ pi -e /home/dracon/Dev/pi-goal-list-loop-audit
58
+ > /goal "Create file hello.txt containing the word world. Done when: grep -q world hello.txt"
59
+ # expect: agent writes file, calls complete_goal, auditor approves, goal archived
60
+ > /goal status # expect: complete, audit history shows 1 approved
61
+ cat .pi-gla/active.jsonl | tail -3
62
+ ls .pi-gla/archive/ # expect: one .md file
63
+ ```
64
+
65
+ ### M2 — v0.2.0 (list + drafting + regression_shield) ✅ (2026-07-20)
66
+
67
+ - [x] **Loop 2: `/list`** — `add|show|next|remove <n>|clear`; each item is a full goal; completing/aborting one auto-activates the next; session restart resumes a non-empty queue. Live-verified: two items auto-advanced through audit to archive.
68
+ - [x] **Drafting**: `/goal` no-args → agent grills one question at a time → `propose_goal_draft` → real Confirm dialog. Live-verified end-to-end (drafted goal completed with shield).
69
+ - [x] **regression_shield**: auditor must quote raw output per contract item in an `<evidence>` block; orchestrator converts evidence-free `<approved/>` into disapproval. Pure logic in `goal-loop-shield.ts`; 14 unit tests + live verification (verbatim `<evidence>` in history).
70
+ - [x] **Escape dialog**: abort → complete-without-audit / continue choice.
71
+ - [x] **Provider warning**: one-time `session_start` notice when the session provider isn't a confirmed built-in and no auditorModel is set. Live-verified on kilocode.
72
+ - [x] **Inline contract extraction**: one-liner `Done when:` now extracts (was silently skipped before — the shield never engaged on one-liners).
73
+ - [x] **Live integration harness**: `scripts/smoke.sh [goal|list|draft]` — goal scenario 5/5 assertions green.
74
+ - [x] CHANGELOG, version 0.2.0, publish.
75
+ - [ ] `max_subtasks_per_task` cap → moved to M3 (no task-list creation tool exists yet; capping nothing is premature).
76
+
77
+ ### M3 — v0.3.0 (loop) ✅ (2026-07-20) — design
78
+
79
+ **Loop 3 is metric-driven, not vibes-driven.** This is the anti-doorknob design:
80
+ pi-loop-mode's failure mode was endless "improvement" churn (the DOORKNOB problem).
81
+ Our loop only believes a number.
82
+
83
+ **Model**:
84
+ - User supplies: `target` (what to improve), `measure` (shell command that prints
85
+ a number), `direction` (min|max). Optional: `window` (plateau window, default 5),
86
+ `max` (iteration cap, default 50).
87
+ - On `/loop start`: orchestrator runs `measure` → baseline.
88
+ - On every `agent_end` while active: orchestrator runs `measure` → compare to best:
89
+ - improved (min: value < best; max: value > best) → new best, stall=0
90
+ - not improved / measure failed → stall++
91
+ - The **orchestrator** runs the measure (via `pi.exec`), never the agent —
92
+ the agent cannot fake the number.
93
+ - Stop conditions: `stall >= window` (plateau), `iteration >= max`, or `/loop stop`.
94
+ - No git-based auto-revert in v0.3.0 (too dangerous with uncommitted user work);
95
+ on regression the agent is instructed to undo its own last change, and the next
96
+ measure verifies.
97
+ - **No auditor in loop 3**: the metric IS the verdict. Documented.
98
+ - Mutual exclusion: a `/loop` cannot start while a goal/list is active and vice versa.
99
+
100
+ **Command shape**: `/loop start "<target>" measure="<cmd>" direction=min [window=5] [max=50]`
101
+ `/loop` (status) · `/loop stop`
102
+
103
+ **Collision note**: `/loop` collides with pi-loop-mode — the M1 collision detector
104
+ handles UX; smoke tests run under a bare `PI_CODING_AGENT_DIR` to isolate.
105
+
106
+ **Also in M3**:
107
+ - `propose_task_list` tool + `max_subtasks_per_task: 5` cap (M2 carry-over — makes
108
+ the existing complete_task/update_task_status tools actually usable).
109
+ - `notify=<cmd>` setting: shell out on goal complete / goal pause / loop stop
110
+ (message passed as `$1`; config-gated, no deps).
111
+ - Unit tests (metric parse, plateau logic, task cap) + `/loop` smoke scenario.
112
+
113
+ **M3 verification evidence** (all live, 2026-07-20):
114
+ - `/loop` smoke: metric 5→0 over 5 improving iterations (stall reset each time),
115
+ 3 stall iterations at 0, plateau stop at window=3, `loop_stopped` + per-iteration
116
+ `loop_measured` in ledger, notify fired on stop. `scripts/smoke.sh loop` 5/5.
117
+ - Regression check: `goal` 5/5, `list` 4/4, `draft` 3/3 — all scenarios hermetic
118
+ (bare agent dir + readiness wait) after two collision/REPL-race flakes.
119
+ - 73 unit tests green; `tsc --noEmit` clean.
120
+ - Found + fixed during M3: `/gla` whitespace split mangled quoted
121
+ notify commands; smoke `wait_for "plateau"` matched agent prose instead of
122
+ the orchestrator's stop text (assertions raced the loop).
123
+
124
+ ### M7 — v0.7.0 (global config tier) ✅ (2026-07-21)
125
+
126
+ User directive: settings are not per-goal/loop/list — there should be ONE
127
+ global config you set once and rarely open. Shipped: project > global >
128
+ defaults resolution, `/gla` writes global by default (`project`
129
+ prefix for local overrides), provenance display, 4 mergeSettings unit tests,
130
+ live-verified both tiers + no-leak smoke. Docs updated.
131
+
132
+ ### M6 — v0.6.0 (draft everything) ✅ (2026-07-20)
133
+
134
+ User directive: for a long-running thing, a draft up front is better. Drafting
135
+ exists only for `/goal`; `/list add` takes raw strings, and `/loop start`
136
+ demands a correct target+measure+direction in one blind shot — the most
137
+ expensive place to be wrong (up to 50 iterations before plateau stops a bad
138
+ metric). Draft all three loops; for `/loop`, validate the metric BEFORE
139
+ confirming.
140
+
141
+ 1. **Unified drafting modes**: drafting target becomes `"goal" | "list" |
142
+ "loop"`. `/goal` (existing), `/list add` with no args (draft → confirmed
143
+ contract goes into the QUEUE instead of activating), `/loop` with no args
144
+ (draft → confirmed loop config starts the loop).
145
+ 2. **`/loop` drafting with measure test-run** (centerpiece): the agent grills
146
+ about target + what number represents progress, then calls
147
+ `propose_loop_draft(target, measureCmd, direction, window?, max?)`. The
148
+ **orchestrator runs the measure command once** and shows target + measure +
149
+ real output + parsed number + direction in the Confirm dialog:
150
+ "`grep -c TODO src.txt` → `42` (min). Start?" A broken measure (no number)
151
+ is shown as such and the agent is told to fix the proposal. User validates
152
+ the metric before a single iteration burns tokens.
153
+ 3. **`/goals` archive browser**: list archived goals (id, status, stop reason,
154
+ objective head) from `.pi-gla/archive/`. Long-running tool needs history.
155
+ 4. Gates: unit tests (draft-mode routing, loop-draft measure parsing), smoke
156
+ scenarios for loop-drafting and list-drafting, publish v0.6.0.
157
+
158
+ **M6 evidence** (2026-07-20):
159
+ - Loop drafting live: agent located num.txt itself, proposed `cat num.txt`;
160
+ Confirm dialog showed the real test-run ("Parsed number: 10, lower is
161
+ better"); confirmed loop ran improving iterations immediately.
162
+ - List drafting live: confirmed contract → list_added → auto-activate →
163
+ audited → archived.
164
+ - `/goals` parsing verified against real archive entries.
165
+ - 89 unit tests, tsc clean.
166
+
167
+ **Still deferred**: live footer/TUI widget (now the ONLY remaining scoreboard
168
+ gap vs pi-loop-mode/pi-goal-x).
169
+
170
+ ### M5 — v0.5.0 (self-sufficiency) ✅ (2026-07-20)
171
+
172
+ User directive: a goal loop that dies silently after compaction and needs an
173
+ EXTERNAL plugin (`@badliveware/pi-compaction-continue`) to restart it is a hole
174
+ in OUR plugin. Liveness is the loop's own job. Bake it in; cut the watchdog.
175
+
176
+ 1. **Heartbeat self-watchdog** (replaces pi-compaction-continue for our loops):
177
+ a 15s interval checks: active goal-or-loop AND session idle AND no pending
178
+ continuation/loop timer AND no activity for 60s → re-fire the continuation.
179
+ One check covers every stall cause (compaction-eaten turn, dropped message,
180
+ stale ctx). Stall accounting: a heartbeat-nudged turn with ZERO tool calls
181
+ counts as a nudge; 3 consecutive → pause (mirrors the watchdog's 3-nudge cap,
182
+ but scoped to real goal progress). Pure decision function unit-tested.
183
+ Scope note: this covers stalls while a goal/loop is active. Non-goal sessions
184
+ are the user's own business — they are at the keyboard.
185
+ 2. **`/goal tweak "<text>"`** — edit the active goal's objective in place
186
+ (Confirm dialog shows old vs new; contract re-extracted from the new text).
187
+ Closes the last pi-goal-x feature gap we use.
188
+ 3. **Structured drafting forms**: drafting prompt prefers `ask_user_question`
189
+ (rpiv-ask-user-question) when the tool is available in the session — closes
190
+ the structured-forms gap vs pi-goal-x without a hard dependency.
191
+ 4. **Rig cuts** (after publish): `pi-codex-goal`, `pi-loop-mode`,
192
+ `@badliveware/pi-compaction-continue`. AGENTS.md stack table rewritten:
193
+ goal plane = pi-goal-list-loop-audit.
194
+
195
+ **M5 evidence** (2026-07-20):
196
+ - Heartbeat: 8 unit tests for the stall predicate + nudge accounting; `goal`
197
+ smoke 5/5 with the heartbeat interval live through the full cycle.
198
+ - `/goal tweak`: implemented with Confirm dialog + contract re-extraction.
199
+ - Drafting prompt prefers `ask_user_question` when available.
200
+ - 89 unit tests, tsc clean.
201
+
202
+ **Deferred**: live footer/TUI widget (pi-loop-mode's dashboard is the one thing
203
+ we genuinely lose by cutting it; v0.6.0 candidate if missed).
204
+
205
+ ### M4 — v0.4.0 (completion release) ✅ (2026-07-20)
206
+
207
+ Everything left, in one release. Completes the 6-flaw list and makes the docs honest.
208
+
209
+ 1. **Auditor compaction (flaw #3 — the LAST open flaw)**. Enable pi's built-in
210
+ compaction in the auditor session (currently `compaction: { enabled: false }`).
211
+ Safety argument: regression_shield is orchestrator-side — a compaction-degraded
212
+ auditor produces weaker evidence → disapproval, never false approval. The risky
213
+ direction (silent false approval) is structurally impossible.
214
+ 2. **Schema + examples + docs sync**. `schemas/goal.schema.json` still says "oracle"
215
+ and "v0.1.0 loop 1 only"; `examples/example-objective.md` used `/pi-gla-set`;
216
+ `tests/README.md` has stale counts; `docs/DESIGN.md` needs the v0.2/v0.3 addendum.
217
+ 3. **tokensUsed wiring + limit enforcement**. `AgentEndEvent.messages` carries
218
+ `usage.totalTokens` per assistant message — accumulate per goal. `tokensLimit`
219
+ becomes a real cost guard: crossing it pauses the goal with a clear reason
220
+ (configurable via `/glla tokenlimit=`).
221
+ 4. **Resumption notice** on `session_start`: if a goal is active or a loop is
222
+ running, say so. (The "plugin vanished" self-check from D4 is impossible from
223
+ inside the plugin — absent code cannot run. Recorded as rejected.)
224
+ 5. **Loop 3 git-branch mode** (`branch=1` flag): at `/loop start`, create scratch
225
+ branch `pi-glla-loop/<id>`; commit after each improving iteration; on regression
226
+ `git reset --hard` to the last improving commit ON THE SCRATCH BRANCH ONLY.
227
+ The user's branch and uncommitted work are never touched. Requires: git repo,
228
+ and we refuse `branch=1` with a dirty tree (refuse to mix user work into the
229
+ scratch branch).
230
+ 6. **Draft reject path** in the smoke harness (Confirm → No → agent refines).
231
+
232
+ After M4 the 6-flaw list is closed and the roadmap table is all-shipped.
233
+
234
+ **M4 verification evidence** (all live, 2026-07-20):
235
+ - Auditor compaction enabled; `goal` smoke 5/5 green after the change.
236
+ - Token guard: 3 unit tests for dedup accumulation; limit-pause path wired in
237
+ agent_end with settings-configurable budget.
238
+ - branch=1 live: 5 improvement commits on scratch branch, 0 for stalls, main
239
+ untouched, returned to main on plateau with merge instructions.
240
+ - `draft-reject` smoke 6/6: Confirm → reject → refine → Confirm → approval.
241
+ - Resumption notice on session_start for active goal/loop.
242
+ - 81 unit tests, tsc clean, all 5 smoke scenarios green.
243
+ - **6/6 pi-goal-x flaws now closed.** The D4 "plugin vanished" self-check is
244
+ recorded as REJECTED (absent code cannot run); replaced by the resumption
245
+ notice.
246
+
247
+ **Deferred to v0.4.0 (with justification)**: (superseded — this release)
248
+
249
+ ---
250
+
251
+ ## 2. Open decisions (must resolve before M1 publish)
252
+
253
+ ### D1 — Command collision strategy ✅ RESOLVED
254
+
255
+ **Verified in installed pi source** (`dist/core/extensions/runner.js:resolveRegisteredCommands`):
256
+ - Duplicate command names **never throw** and **never clobber** — both survive.
257
+ - First registrant keeps the bare name (`/goal`); later ones get `/goal:2`, `/goal:3`, …
258
+ - So the failure mode is degraded UX (our command reachable as `/goal:2`), never breakage.
259
+
260
+ **Decision: option 1 — plain names + detect-and-warn.** Implemented in `extensions/loops/goal.ts:warnOnCommandCollision`: at `session_start` we count registered command names via `pi.getCommands()`, and if any of ours (`goal`, `list`, `loop`, `goal-*`) appears more than once we notify the user with the degraded invocation name. Collision check is fail-silent (non-fatal by design).
261
+
262
+ ### D2 — Auditor model default ✅ RESOLVED (with a hard discovered constraint)
263
+
264
+ **Discovered during M1 smoke (2026-07-20): the auditor session has no extensions, so it can only use BUILT-IN providers.** On this rig the main session ran kilocode (`tencent/hy3:free`) — an extension-registered provider — and every auditor spawn failed with `No API key found for kilocode`. Verified bare-session matrix: `opencode/deepseek-v4-flash-free` works extension-less; kilocode/zenmux/kimi-coding do not.
265
+
266
+ **Decision**: default = session model (works when the session model is built-in); `/gla model=provider/id` overrides for rigs running extension-provided session models. The `/gla` save message now warns about the built-in-provider constraint. `resolveAuditorModel` documents it in code. v0.2.0 should add a startup check: if session model's provider is extension-registered and no auditorModel is set, warn once.
267
+
268
+ ### D3 — State dir name ✅ RESOLVED
269
+
270
+ **Keep `.pi-gla/`.** Internal-only path; renaming costs a migration for zero user-visible gain. If we ever regret it, the rename is a one-line constant (`piGlaDir` in `goal-loop-core.ts`) plus a migrate-on-read.
271
+
272
+ ### D4 — Persistence across pi updates ✅ RESOLVED
273
+
274
+ Known rig behavior (from earlier audits): `pi update` overwrites `~/.pi/agent/npm/node_modules/`, which can wipe npm-installed plugins. **Decision: document both install paths in INSTALL.md** — `pi install npm:pi-goal-list-loop-audit` (convenient, re-install after `pi update`) and project-local `.pi/extensions/` (permanent, survives updates). The `-e <path>` dev flow is unaffected. v0.2.0 should add a `session_start` self-check that notifies if the plugin vanished from the loaded set while `.pi-gla/active.jsonl` shows an active goal.
275
+
276
+ ---
277
+
278
+ ## 3. Verification gates (apply to every milestone)
279
+
280
+ A milestone is not done until:
281
+
282
+ 1. `npm test` green (unit).
283
+ 2. `npm run check` clean (types).
284
+ 3. Live smoke passes (M1+).
285
+ 4. CHANGELOG entry written.
286
+ 5. No `oracle|sisyphus|squad|forge|pi-gla-` string outside `.pi-gla/` dir name (run the grep).
287
+
288
+ ```bash
289
+ grep -rn "oracle\|sisyphus\|squad\|forge" \
290
+ tests/ extensions/ prompts/ docs/ examples/ README.md INSTALL.md CHANGELOG.md package.json \
291
+ | grep -v node_modules
292
+ # expect: no output
293
+ ```
294
+
295
+ ---
296
+
297
+ ## 4. Risks
298
+
299
+ | Risk | Likelihood | Mitigation |
300
+ |---|---|---|
301
+ | pi extension API drift (0.74 → next) | medium | pin peerDeps `*`; smoke test after every pi update |
302
+ | Command collision (D1) | high | resolve D1 before publish |
303
+ | Auditor cost (every complete_goal = extra session) | medium | D2 settings; document cost expectation in README |
304
+ | User installs alongside pi-goal-x and gets two loops fighting | medium | README "conflicts" section; loud notify if `.pi/goals/` detected |
305
+ | v0.1.0's auditor is rubber-stampable (`bash true`) until v0.2.0 regression_shield | known/accepted | documented in DESIGN + README; ship v0.2.0 fast |
306
+
307
+ ---
308
+
309
+ ## 5. Publish checklist (M1)
310
+
311
+ - [ ] D1–D4 resolved and recorded in this file
312
+ - [ ] `npm test` + `npm run check` + live smoke all green
313
+ - [ ] Version bump `0.1.0-alpha.1` → `0.1.0`
314
+ - [ ] git init + initial commit + GitHub repo `dracon/pi-goal-list-loop-audit`
315
+ - [ ] `npm publish --access public`
316
+ - [ ] Verify: `pi install npm:pi-goal-list-loop-audit` on a clean rig