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/CHANGELOG.md CHANGED
@@ -1,5 +1,982 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.35.64 — bounded recovery for frozen subagents (2026-08-25)
4
+
5
+ ### Fix
6
+ A tracked top-level subagent that produces no tool-use or output-token
7
+ progress now receives the existing short warning first, then one
8
+ generation-fenced child-specific abort request after the configurable
9
+ `subagentHangEscalationMinutes` threshold (default 30; 0 keeps
10
+ warning/telemetry-only behavior). Nested, unreachable, or ownership-
11
+ ambiguous children remain warning-only. A stale child no longer shields an
12
+ unrelated parent zombie watchdog, and `/glla agents` shows ABORTING,
13
+ unavailable, or failed action state while preserving partial output.
14
+
15
+ ### Tests
16
+ `tests/subagent-hang-detection.test.ts` covers one-shot escalation,
17
+ progress-before-action cancellation, manager-unavailable and nested-child
18
+ safety, and `tests/agents-panel.test.ts` pins the action surface. Settings
19
+ menu/editor and INSTALL documentation expose the new threshold.
20
+
21
+ ### Follow-up hardening
22
+ Frozen-child escalation now uses pi-subagents' existing root-session
23
+ `subagents:rpc:stop` bridge, with readiness, ownership, generation, and
24
+ timeout-race fencing. The real AgentManager/RPC path is covered by a
25
+ deterministic pending-provider integration test without modifying the
26
+ upstream package.
27
+
28
+ Malformed saved goal/list objectives now produce a bounded repair/replan
29
+ card instead of a self-blocking first turn. One durable bootstrap turn
30
+ carries the complete preserved target and `propose_task_list` confirmation;
31
+ automatic repeats are fenced, while explicit `/list resume` re-arms one
32
+ retry. The card keeps its concrete recovery action and queue position
33
+ visible.
34
+
35
+ ### Tests
36
+ Focused repair/replan, display, stale-probe, and RPC regressions are
37
+ included in the release contract. The complete gate remains the source of
38
+ truth for the published artifact.
39
+
40
+ ## 0.35.63 — auditor context held until resume (2026-08-25)
41
+
42
+ ### Fix
43
+ Cold session restores now keep unfinished goal/list objectives and their
44
+ status visible without automatically injecting the previous auditor report
45
+ or dispatching a new continuation. Explicit `/goal resume`, list/glla/loop
46
+ continuation commands, validated lifecycle continuity, and global
47
+ `autoResume: true` release the auditor-context gate. The prior Pi transcript
48
+ and durable audit history remain untouched.
49
+
50
+ ### Tests
51
+ `tests/auditor-blank-until-resume.test.ts` proves objective visibility,
52
+ pre-consent report/TODO suppression, explicit resume release, auto-resume
53
+ release, and rejected stale-resume suppression. Version metadata is
54
+ synchronized to 0.35.63.
55
+
56
+ ### Follow-up hardening
57
+ `/goal resume` now releases the auditor surface only after its existing
58
+ stale/foreign admission probe. Active-idle resumes receive the same probe;
59
+ stale paused resumes preserve the existing active/interrupted recovery
60
+ marker without exposing old auditor context. Main-model recovery resumes
61
+ now use the same stale/foreign admission probe and release the surface on
62
+ manual-hold, retry, and primary-probe recovery paths; a recovery regression
63
+ test pins the consent behavior.
64
+
65
+ ## 0.35.62 — subagent host-state boundary (2026-08-25)
66
+
67
+ ### Fix
68
+ Headless child sessions are now rejected before state-root registration,
69
+ restore, owner claims, and tool repair. The same fail-closed boundary covers
70
+ persistent children, foreign slash commands, and missing tool invocation
71
+ contexts. File-backed host successors remain eligible for legitimate reload
72
+ and silent-rebind recovery. Main-host subagent telemetry continues through
73
+ the event bus and `/glla agents` path.
74
+
75
+ ### Tests
76
+ `tests/subagent-host-boundary.test.ts` proves first-claim prevention,
77
+ foreign slash-command refusal, persistent-worker refusal, legitimate host
78
+ successor admission, and durable Explore telemetry. Version metadata is
79
+ synchronized to 0.35.62.
80
+
81
+ ## 0.35.61 — list queue visibility across host replacement (2026-08-25)
82
+
83
+ ### Fix
84
+ Waiting-only list state now has an actionable status/widget projection even
85
+ when no list item is active. Silent host-successor and same-session stale
86
+ recovery boundaries also re-read the selected durable root and hydrate queue
87
+ sidecars before repainting. A recovered queue now stays visible and can be
88
+ started with `/list next` without requiring a full reload.
89
+
90
+ ### Tests
91
+ `tests/list-invisible-restart.test.ts` covers waiting-only visibility and
92
+ activation plus sidecar-only silent-successor rehydration. Version metadata
93
+ is synchronized to 0.35.61.
94
+
95
+ ## 0.35.60 — pre-turn glla tool visibility (2026-08-25)
96
+
97
+ ### Fix
98
+ GLLA agent tools are now registered and reactivated immediately before
99
+ agent turns, with `agent_start`/`turn_start` compatibility fallbacks. This
100
+ closes the interval where an external tool allowlist or modlist could remove
101
+ `pause_goal` after session restore and Pi would answer a valid model call
102
+ with `Tool pause_goal not found`, leaving a parked objective looking stuck
103
+ until reload.
104
+
105
+ ### Tests
106
+ `tests/gettick-tool-visibility.test.ts` simulates a post-restore active-tool
107
+ replacement and verifies the pre-turn boundary restores `pause_goal` and
108
+ keeps it callable. Version metadata is synchronized to 0.35.60.
109
+
110
+ ## 0.35.59 — safe cancel/wipe across unresolved session roots (2026-08-25)
111
+
112
+ ### Fix
113
+ `/glla cancel`, `/glla wipe`, `/list cancel`, `/list clear`, and the shared
114
+ goal archive path now fail closed while opt-in `sessionDir` resolution is
115
+ pending. They leave the in-memory objective/list untouched and do not
116
+ recreate or mutate an ambiguous cwd state tree; after host lifecycle
117
+ admission registers the session root, cancel and wipe archive/clear under
118
+ the selected session root as before.
119
+
120
+ ### Tests
121
+ `tests/objective-loss-lifecycle.test.ts` covers both deferred destructive
122
+ commands and successful `/glla cancel` + `/glla wipe` cleanup under a
123
+ registered session root. Version metadata is synchronized to 0.35.59.
124
+
125
+ ## 0.35.58 — objective-loss lifecycle repair (2026-08-24)
126
+
127
+ ### Fix
128
+ Wired the opt-in `sessionDir` root into the admitted production lifecycle.
129
+ `session_start` and silent host-successor admission now register Pi's
130
+ canonical `SessionManager.getSessionDir()` before owner, invalidation, or
131
+ restore writes; in-memory worker sessions remain pending instead of creating
132
+ an ambiguous cwd tree. The configured session directory wins over an
133
+ imported session-file parent, while `PI_SESSION_FILE` remains the explicit
134
+ child-process fallback.
135
+
136
+ ### Evidence
137
+ Added `tests/objective-loss-lifecycle.test.ts`: a real registered
138
+ `session_start` handler proves production root registration, and separate
139
+ fresh Bun writer/reader processes recover an objective across a cwd switch.
140
+ The report intentionally does not claim to simulate a crash mid-write or a
141
+ specific version migration. Full evidence:
142
+ audit/OBJECTIVE-LOSS-VALIDATION-2026-08-24.md.
143
+
144
+ ### Tests
145
+ Focused lifecycle/state-root tests and clean tsc pass; the full release gate
146
+ is run for this version before closure.
147
+
148
+ ## 0.35.57 — objective-loss validation (2026-08-24)
149
+
150
+ ### Evidence
151
+ Validated the Now report that objectives disappeared after a Wez crash or
152
+ version/cwd switch. The historical workingDir default intentionally makes a
153
+ cwd switch select a different on-disk root, while explicit sessionDir keeps
154
+ the objective visible across cwd changes. Pending session-root resolution
155
+ does not migrate or delete the old cwd tree. The bounded result was
156
+ evidence-based closure pending production lifecycle wiring; crash-only loss
157
+ was not reproduced. The subsequent gettick, list-reload, and
158
+ subagent-visibility reports remain separate items.
159
+ Full evidence: audit/OBJECTIVE-LOSS-VALIDATION-2026-08-24.md.
160
+ ## 0.35.56 — state-root consumer/lifecycle hardening (2026-08-24)
161
+
162
+ ### Fix
163
+ Hardened every remaining state-root consumer and lifecycle boundary missed
164
+ by the core/settings slice. Raw `<cwd>/.pi-glla` joins in auditor jobs,
165
+ dispatch, goal-loop ledger reads, reviewer, stats rollup/discovery, and
166
+ session owner/handoff/pending-list paths now route through `piGlaDir` and
167
+ respect the selected root. Pending `sessionDir` resolution (no session dir
168
+ yet) is a strict deferral: dispatch, reviewer, session owner, handoff, and
169
+ pending-list writes return a deferred/false result without creating a
170
+ fallback `<cwd>/.pi-glla` tree, and legacy `.pi-gla` trees are still never
171
+ migrated. Audit-loop open-count helpers now resolve via the selected root
172
+ as well. Host/subagent ownership stays per-process via `PI_SESSION_FILE`
173
+ fallback and the explicit `setRuntimeSessionDir` hook — no global overwrite.
174
+
175
+ ### Tests
176
+ New `tests/state-root-consumers.test.ts` pins resolved-root routing for
177
+ dispatch/stats/audit helpers, pending deferral for dispatch/reviewer, the
178
+ `PI_SESSION_FILE` fallback, and source-level absence of raw hardcodings plus
179
+ pending guards. Existing `tests/state-root.test.ts` continues to cover core
180
+ core/settings behavior. Red/green: breaking the `piGlaDir` routing makes the
181
+ consumer pins fail; restoring passes 9/9 focused plus 56 prior. tsc and full
182
+ release gate green for this tree.
183
+ ## 0.35.55 — opt-in session-root state core/settings slice (2026-08-24)
184
+
185
+ ### Fix
186
+ Ported the valid state-root portion of PR #21 onto current main without
187
+ merging the stale PR verbatim. New dependency-free
188
+ extensions/glla-state-root.ts owns the typed global root selector and
189
+ session-directory resolution so goal-loop-core can select a root without a
190
+ settings import cycle. The historical <cwd>/.pi-glla workingDir remains
191
+ the default; sessionDir is explicit opt-in and resolves to the top-level Pi
192
+ session directory (or PI_SESSION_FILE's parent for worker processes).
193
+ Session-root mode is global-only because project settings.json lives inside
194
+ the selected root. Pending sessionDir resolution is a write boundary:
195
+ core directory/ledger/queue/sentinel/audit-log writes defer rather than
196
+ recreate an ambiguous cwd tree, and old .pi-gla/.pi-glla trees are never
197
+ migrated or deleted by the new mode. The settings menu exposes the two
198
+ choices and project attempts to override stateRoot are stripped.
199
+
200
+ ### Tests
201
+ tests/state-root.test.ts covers default cwd persistence, opt-in session-root
202
+ persistence, pending-write/no-migration behavior, PI_SESSION_FILE fallback,
203
+ and global-only settings round-trip. settings-editors and
204
+ settings-menu-complete pin the UI/provenance surface; the long-term
205
+ preferences boundary now checks the dependency-free global path owner.
206
+ Red/green proved the session-root branch is required (2 of 5 focused tests
207
+ fail when neutered; restored 5/5). tsc and focused tests pass before the
208
+ full release gate.
209
+ ## 0.35.54 — RESUMABLE_STOP honors the v0.35.31 "metric never moved" stop (2026-08-24)
210
+
211
+ ### Fix
212
+ Collect-pass HIGH finding: the v0.35.31 "metric never moved" stop reason
213
+ promises "/loop resume retries or /loop stop" in its own message, but the
214
+ RESUMABLE_STOP predicate in /loop resume never matched that prefix - the
215
+ promised command answered "No held loop to resume", and with
216
+ propose_loop_refine gated on an ACTIVE loop, the only recovery was
217
+ /loop stop + a fresh start discarding iteration history. Same class as
218
+ the v0.35.25 issue-#14 zombie prefix bug (fixed there for zero-stream,
219
+ missed for this brand-new prefix). The prefix is now resumable: resuming
220
+ re-arms the error/stuck/stall counters while preserving iteration, best,
221
+ and history; if the metric is still dead it re-stops loudly after its
222
+ window, and a measure-changing propose_loop_refine (usable again once
223
+ resumed) re-scopes the measure era so the never-moved grace re-arms.
224
+
225
+ ### Tests
226
+ tests/metric-never-moved-resumable.test.ts: behavioral - a loop parked by
227
+ the exact production reason string resumes via /loop resume with
228
+ iteration/best/history preserved and all three streak counters re-armed;
229
+ negative pin - a bounded stop ("max iterations reached") stays
230
+ non-resumable. Red-proven by removing the predicate clause (behavioral
231
+ fails, negative pin stays green).
232
+ ## 0.35.53 — false repair card after abort+reload: parser marker fix + contract-derived objective heal (2026-08-24)
233
+
234
+ ### Fix
235
+ note.md Now: "objective needs repair issue, but before reload it looked
236
+ fine". Field forensics (neonbreak, item 20260823082852-in3rc7): the list
237
+ draft batch wrote an item with objective "" and the ENTIRE intent inside
238
+ the verification contract - extractVerificationContract's line marker
239
+ regex `verify\b[^:]*:` misread the imperative sentence "Verify the
240
+ shipped PREMIUM-UIUX pass (...): confirm ..." as a contract marker
241
+ ("verify" is both a marker word and an ordinary imperative verb), leaving
242
+ the objective empty. The activation gate then correctly flagged "empty"
243
+ and jammed a repair card ahead of the item - 42
244
+ faulty_objective_list_activation_blocked events over 22 hours, an endless
245
+ repair-card loop that wedged the session. Two-layer durable fix:
246
+ (1) WRITER - the line marker for the ambiguous verbs now requires the
247
+ colon immediately ("Verify:" / "Verify when:" / "Verification:");
248
+ "done"/"done when"/"verified when" keep a bounded 60-char decorated-marker
249
+ gap so prose tails cannot masquerade as markers either. The field text
250
+ now parses with the real objective and only the grep tail as contract.
251
+ (2) READER - legacy items already persisted with an empty objective plus
252
+ a clean, actionable contract derive their objective deterministically
253
+ from the contract's leading imperative sentence at activation
254
+ (list_objective_derived_from_contract) instead of demanding a repair
255
+ card. Empty objective + absent or suspicious contract still takes the
256
+ true broken-objective repair path, unchanged.
257
+
258
+ ### Tests
259
+ tests/false-repair-card.test.ts: the exact field text parses with its
260
+ intent in the objective; short-marker and decorated-marker forms still
261
+ parse; derivation unit rules (first sentence, suspicious/non-imperative
262
+ contracts rejected); behavioral - a legacy stuck item activates with the
263
+ derived objective (no repair demand, contract preserved), a truly broken
264
+ item still triggers the repair card, and a fresh /list add of the field
265
+ text activates directly end-to-end. Red-proven by neutering both layers
266
+ (4 of 6 fail; the true-broken-path tests stay green).
267
+ ## 0.35.52 — context hygiene: era-scope failed error-only turns out of the effective context (2026-08-24)
268
+
269
+ ### Fix
270
+ note.md Now: "failed requests add to the context, while clearly adding
271
+ nothing of value". When retries are exhausted, the failed assistant turn
272
+ (stopReason "error", errorMessage set, content empty/partial) STAYS in
273
+ agent state and the session - pi strips it from live state only for
274
+ mid-flight retries. Every later LLM call receives it and compaction
275
+ summarizes it; nothing downstream filters these. Field evidence (polis,
276
+ 2026-08-23): a run of 503/network_error/retry-cancelled turns drove the
277
+ estimated context to 122.7% of the 200k window, and auto-compaction then
278
+ aborted on its own bloated summarization input. New
279
+ extensions/context-hygiene.ts: a durable bounded rule drops error-only
280
+ assistant turns (stopReason "error", NO tool-call blocks) from the
281
+ effective context EXCEPT the most recent one, which stays so the model
282
+ sees why the previous attempt failed on the retry send. Applied at two
283
+ points: the `context` event projection (per-send, transcript untouched -
284
+ alongside the v0.35.51 payload guard) and `session_before_compact`
285
+ (prunes the shared preparation object the compaction runner summarizes,
286
+ shrinking the summarizer request and keeping failures out of the summary).
287
+ Tool-call-carrying error turns own paired toolResults and stay intact;
288
+ "aborted" turns are user-intent boundaries and are never touched. Drops
289
+ are ledgered (context_hygiene_dropped / context_hygiene_compaction_input).
290
+
291
+ ### Tests
292
+ tests/context-hygiene.test.ts: predicate (tool-carrying/aborted/healthy
293
+ never droppable); bounded drop rule (newest kept, older dropped, identity
294
+ preserved at/under the window, configurable window); seeded bloat (60
295
+ failures collapse, normal turns survive verbatim); in-place compaction
296
+ preparation pruning; behavioral wiring through MockPi for both hooks with
297
+ ledger assertions and clean-history no-op. Red-proven by neutering both
298
+ production call sites.
299
+ ## 0.35.51 — payload guard: bound inline image bytes on every outgoing LLM call (2026-08-24)
300
+
301
+ ### Fix
302
+ note.md Now: "req body too large due to images in context". Generated
303
+ images accumulate in conversation history as inline base64 blocks until
304
+ the provider rejects the request with 413 ("Downloaded image content
305
+ cannot exceed 30MB" / "Request Entity Too Large") - and every
306
+ main-model-recovery probe re-sent the same bloated history, so recovery
307
+ could never classify or heal the failure; the session was wedged until a
308
+ manual restart WITHOUT history. Two-layer durable fix: (1) a new
309
+ extensions/payload-guard.ts projects the outgoing message list at the pi
310
+ `context` event (fired before EVERY LLM call), bounding cumulative
311
+ inline-image bytes to 16MB - evicting the OLDEST images first, always
312
+ keeping the newest two, replacing each evicted block with a short text
313
+ placeholder. Disk history is untouched (per-send projection), and the
314
+ chokepoint protects ordinary turns AND recovery probes alike. Evictions
315
+ are ledgered as payload_guard_eviction. (2) classifyMainModelFailure now
316
+ maps 413/payload-size texts to "transient" - retryable in place, because
317
+ the payload guard (not a fallback-model switch) heals the size; the old
318
+ "unknown" classification burned the whole chain on useless rotations.
319
+
320
+ ### Tests
321
+ tests/payload-guard.test.ts: under-budget pass-through (same identity);
322
+ oldest-first eviction with newest-two floor; floor holds when the budget
323
+ cannot be met; idempotent projection, non-image content untouched;
324
+ behavioral wiring (context handler projects + ledgeres; under-budget
325
+ passes unprojected); 413 texts classify transient (not unknown, not
326
+ context-overflow). Red-proven by neutering both production sites.
327
+ ## 0.35.50 — same-process session successors auto-resume the main thread (2026-08-23)
328
+
329
+ ### Fix
330
+ note.md Now #2: session-start auto-resume asymmetry. The v0.35.23 loop
331
+ branch treats a SAME-PROCESS session successor (shutdown recorded in the
332
+ owner sidecar with a non-quit reason, previous pid === current pid) as
333
+ mid-flight continuity and resumes held loops - but a plain ACTIVE goal
334
+ held ("restored on session load - held for explicit resume") and a parked
335
+ completion-audit claim stayed parked in that exact corner: from the
336
+ user's seat, the list kept going after the session replacement while the
337
+ goal sat "awaiting first turn". The goal restore gate and the auditor
338
+ claim's canRecoverNow now accept the same consent, refined per the
339
+ v0.34.49 one-shot identity law: a PRESENT handoff marker is authoritative
340
+ even when mismatched (rejection holds); only an ABSENT marker with a
341
+ same-pid non-quit shutdown is continuity - the same distinction
342
+ listOperationLifecycleResume already draws. Different-pid crash
343
+ successors and cold loads still hold for an explicit decision;
344
+ Auto-resume stays the only load-time automation for them.
345
+
346
+ ### Tests
347
+ tests/same-process-successor-resume.test.ts: same-process successor
348
+ resumes a held ACTIVE goal (continuation dispatched, no stale interrupt
349
+ marker); same-process successor auto-retries a parked completion claim
350
+ (audit_recovery_auto_retry_claimed fence in the ledger); different-pid
351
+ crash successor still HOLDS (cold-load law). Red-proven by neutering
352
+ both consent sites; the v0.34.49 mismatched-marker identity test stays
353
+ green against the refined consent.
354
+ ## 0.35.49 — parent-side silence watchdogs close the auditor-AWOL gap (2026-08-23)
355
+
356
+ ### Fix
357
+ Field evidence across five projects (football-forever, doomtap,
358
+ junk-runner, email-api-compare, vps-compare): a detached auditor worker
359
+ whose provider hangs emits ONE boot RPC event (or none) and then total
360
+ silence. The v0.34.57 no-progress watchdog only arms while heartbeats
361
+ stay FRESH, so a stale heartbeat disarmed it, the worker's own stall
362
+ brake was the only other bound, and every doomed attempt burned its full
363
+ 30m wall while the goal sat "auditing" and the queue looked dead. The
364
+ poll loop now owns two complementary silence axes with the same
365
+ running-tool exemption: heartbeat-stale (had an event, went silent for
366
+ the window) and first-event-timeout (never emitted anything within
367
+ firstEventTimeoutMs, a new runtime knob defaulting to the same window).
368
+ Both demote the HUD to quiet, emit auditor_stalled, terminate the
369
+ worker, and return retryable "timeout" infra - which the existing
370
+ fallback ladder re-drives with its eager 5s first retry instead of the
371
+ wall.
372
+
373
+ ### Tests
374
+ tests/auditor-stall-watchdog.test.ts: three workers (silent since boot,
375
+ one-boot-heartbeat-then-silence, tool-open-silent) prove both axes fail
376
+ fast BEFORE the wall, classify as retryable infra, SIGTERM the worker,
377
+ and remove the job scratch; the third pins the running-tool exemption.
378
+ Red-proven against pre-change code: both stall runs burned the full
379
+ wall and never stalled. tests/auditor-process.test.ts heartbeat test
380
+ disarms the new axis (firstEventTimeoutMs) to isolate its own.
381
+ ## 0.35.48 — overdue-wait backstop respects the dispatch-surface gates (2026-08-23)
382
+
383
+ ### Fix
384
+ Audit-pass finding: overdueWaitBackstop mutated durable state (parked to
385
+ active, pauseResumeAt cleared) without checking the
386
+ extensionApiStale/sessionHandoffPending/stale-terminal or
387
+ mainModelRecoveryActive gates - during a latched-stale heartbeat a
388
+ durably parked wait could become an ACTIVE goal with no dispatch until a
389
+ fresh session_start, breaking the paused-is-safe invariant. The backstop
390
+ now refuses mid-handoff and stale-latched windows, and under an active
391
+ main-model recovery releases ONLY recovery-routed waits (the probe route
392
+ re-parks with a fresh resumeAt on failure) - unrelated agent-authored
393
+ waits stay parked until recovery resolves. The gates sit BEFORE the
394
+ lastOverdueWaitKey one-shot latch so skipped windows stay retriable.
395
+
396
+ ## 0.35.47 — completions/handler parity for /list and /loop verbs (2026-08-23)
397
+
398
+ ### Fix
399
+ Audit-pass finding: verbs handled by the dispatchers but absent from the
400
+ subcommand completions - /list add|import|rm (and pause, caught while
401
+ pinning), and /loop resume|refine|polish. All seven now appear in their
402
+ getArgumentCompletions tables with accurate descriptions. A generic
403
+ parity pin in tests/command-registration-collisions.test.ts scans every
404
+ `sub === "x"` dispatch literal inside cmdList/cmdLoop and fails when a
405
+ handled verb has no completion entry - future verbs cannot ship
406
+ half-registered.
407
+
408
+ ## 0.35.46 — /glla agents --tail sanitization + bounded scan reads (2026-08-23)
409
+
410
+ ### Fix
411
+ Audit-pass finding, two parts: (1) child-transcript tail lines were
412
+ rendered through ctx.ui.notify WITHOUT ANSI/control-character
413
+ sanitization - unlike every other external-text projection - so a
414
+ hostile child transcript could emit terminal escape sequences;
415
+ formatTranscriptEntry now runs all output paths (both [raw] fallbacks
416
+ and the [role] text path) through sanitizeDisplayText. (2) The candidate
417
+ scan synchronously read up to 25 FULL transcript files on the main
418
+ thread; the reader contract now takes an optional maxBytes and the
419
+ production command passes a real partial tail read (256 KiB window,
420
+ TRANSCRIPT_SCAN_MAX_BYTES), so the scan touches at most the last 256 KiB
421
+ of each candidate. The single matched file still gets a full read so the
422
+ "last N of M" detail stays honest.
423
+
424
+ ## 0.35.45 — plan-mode seeded hint separator (2026-08-23)
425
+
426
+ ### Fix
427
+ Audit-pass finding: planNote ended "...than a regular draft." and was
428
+ concatenated directly with the label hint, producing
429
+ "...regular draft.Goal drafting - deep planning: ..." in the notified
430
+ seeded hint. The join is now explicit (planNote ? `${planNote} ` : "").
431
+ Behavioral test drives the real /goal plan command with a seed and
432
+ asserts the notified hint reads "regular draft. Goal drafting - deep
433
+ planning:"; proven red with the glued concatenation restored.
434
+
435
+ ## 0.35.44 — draftingDepth dead state removed; orphaned-gate windows closed (2026-08-23)
436
+
437
+ ### Fix
438
+ Audit-pass finding, three parts: (1) the draftingDepth runtime global was
439
+ write-only dead state - set in startDrafting, reset in clearDraftingState,
440
+ zero readers (template selection uses the depth parameter) - removed
441
+ outright; "no target => normal depth" now holds by construction, so no
442
+ consumer can observe stale depth across proposal-completion paths.
443
+ (2) The two bare `draftingTarget = null` completion paths that skipped the
444
+ drafter-model restore (batch-activation conflict refusal, zombie-twin
445
+ rejection) now restore like every other exit. (3) beginDrafterModel moved
446
+ inside a try that clears the drafting gate on throw - a throw used to
447
+ leave the orphaned gate startDrafting's own header warns about.
448
+
449
+ ## 0.35.43 — refine re-baselines specChecked with the spec write (2026-08-23)
450
+
451
+ ### Fix
452
+ Audit-pass finding: refine's orchestrator-side spec write updated
453
+ specHash but not loop.specChecked, so the next tick saw checked >
454
+ specChecked against the OLD file's count and ledged spec_item_progress
455
+ attributed to the agent's iteration - unearned progress feeding the
456
+ multi-signal stuck gate (the user confirmed the respec; the agent may
457
+ have done nothing). The refine handler now re-baselines specChecked
458
+ together with specHash after writing the new spec.
459
+
460
+ ## 0.35.42 — measure-era scoping for loop movement accounting (2026-08-23)
461
+
462
+ ### Fix
463
+ Audit-pass finding: applyRefinement re-baselines best/last/stall on a
464
+ measure-changing refine but keeps history, so OLD-era improved entries
465
+ made both movement checks permanently true for the NEW metric era - the
466
+ v0.35.31 flat-reading grace could never apply after a measure-changing
467
+ refine, and a dead new metric could never earn its never-moved stop.
468
+ applyMeasurement now scopes metricHasMoved and metricNeverMoved to the
469
+ current measure era (history after the last measure-changing
470
+ refinement's iteration; the boundary was already recorded on every
471
+ LoopRefinement). Two twin tests proven red without the scoping, green
472
+ with it.
473
+
474
+ ## 0.35.41 — the last two loop-stop routes announce queue resumption (2026-08-23)
475
+
476
+ ### Fix
477
+ Audit-pass finding: v0.35.22's "ends by ANY route ... ANNOUNCE loudly"
478
+ contract was only wired into some stop routes. The stuck-ladder stop and
479
+ the provider-error/abort-cap stop notified the loop line but never
480
+ announced that waiting list items can start again - a dead silent entry.
481
+ Both routes now call announceQueuedListAfterLoopEnd (exported from
482
+ goal-loop.ts for the goal-activation site). Two twin behavioral tests
483
+ drive each production route against a seeded waiting queue; both proven
484
+ red with their call neutered, green restored.
485
+
486
+ ## 0.35.40 — regression pins for the audit-kind measurement exemption (2026-08-23)
487
+
488
+ ### Tests
489
+ Audit-pass finding: commit 28131527's audit-kind exemption in
490
+ applyMeasurement shipped with zero regression pin. Two twin-loop tests in
491
+ tests/loop-forever.test.ts now pin it: (1) identical flat-metric shapes
492
+ diverge by kind - the audit loop counts every flat toward plateau from
493
+ iteration 1 while the non-audit loop's pre-movement flats stay free;
494
+ (2) a dead metric gets the dedicated "metric never moved" stop on plain
495
+ loops but never on audit loops, whose final verdict stays plateau.
496
+ Red/green proven: deleting both halves of guard one fails both twins;
497
+ the never-moved kind-guard proved unreachable-by-construction for audits
498
+ (plateau always returns first) and is pinned in source instead.
499
+
500
+ ## 0.35.39 — README Files map is actually complete (2026-08-23)
501
+
502
+ ### Docs
503
+ Audit-pass finding: the Files map showed 4 of 7 prompts (missing both
504
+ plan-draft prompts shipped in v0.35.33 and goal-loop-forever-metricless)
505
+ and ~19 of 44 extensions files while reading as complete. The map now
506
+ enumerates every file - 34 extensions/ + 10 loops/ + 7 prompts/ + all
507
+ scripts/ - grouped by concern, with one-line descriptions verified
508
+ against each module's exports.
509
+
510
+ # 0.35.38 — README verb-semantics documentation (2026-08-23)
511
+
512
+ ### Docs
513
+ User-requested audit finding: what /goal|/list|/loop audit MEAN vs start
514
+ vs the plan verbs lived only in code comments. New "What the verbs mean"
515
+ table right after the quick-start block (audit is deliberately three
516
+ machines: one-shot fix-in-pass goal, collect-then-drain list item,
517
+ forever cadence loop; plan = extended draft on all surfaces; verify
518
+ audits the CURRENT goal, not the project), the drafting-rules paragraph
519
+ now names plan as the fourth depth, and "Which loop?" cross-links it.
520
+ Includes the DECIDED semantics: /list plan takes prose only — a file
521
+ path stays bulk import; files mentioned inside /list plan are research
522
+ input, never auto-imported.
523
+
524
+ ## 0.35.37 — recovery welcome-back notice now fires exactly once (2026-08-23)
525
+
526
+ ### Fix
527
+ Audit-pass finding: autoResumedAt/autoResumedEvent were set by three
528
+ auto-recovery sites (heartbeat overdue-wait backstop, main-model provider
529
+ recovery, auditor provider retry) but the ONLY clearing site was MANUAL
530
+ resume — so the continuation prompt injected the "WELCOME BACK, YOU WERE
531
+ RECOVERED" directive into EVERY dispatch of a goal that kept running days
532
+ after one recovery. The accepted-dispatch site in sendContinuation now
533
+ marks the notice delivered: the stamp clears and a
534
+ recovery_notice_delivered ledger entry records it, so the directive is
535
+ injected exactly once per auto-resume. Manual /goal resume keeps its own
536
+ clearing (user-driven, no notice needed).
537
+
538
+ ## 0.35.36 — complete_goal newObjective no longer launders agent text into userSeeds (2026-08-23)
539
+
540
+ ### Fix
541
+ Audit-pass finding: the newObjective branch appended the AGENT-authored
542
+ objective to objectiveProvenance.userSeeds; since createdVia stays "user"
543
+ from creation, the v0.35.31 seed trust then treated that agent-written
544
+ text as explicit user prose and dispatched it verbatim past the
545
+ suspicious-objective fence. userSeeds is now strictly human-confirmed
546
+ text (creation arg, /goal tweak Confirm dialog, repair-redraft task-list
547
+ confirm); a newObjective pivot is recorded via its goal_tweaked ledger
548
+ entry and reviewed by the isolated auditor against the NEW contract in
549
+ the same call. Regression test proves red-on-laundering /
550
+ green-on-fix; behavioral consequence observed: heuristic-tripping pivots
551
+ on user goals now flow through the normal fence (auto-restore from the
552
+ durable original) instead of being waved through.
553
+
554
+ ## 0.35.35 — user-seed trust works with contract clauses and role markers (2026-08-23)
555
+
556
+ ### Fix
557
+ Audit-pass finding: v0.35.31's seed trust compared the CLEANED
558
+ goal.objective against RAW stored seeds by exact equality — but createGoal
559
+ strips "Done when:" clauses and Agent:/Role: declarations out of the
560
+ objective while keeping the raw arg as the seed, so any seeded goal WITH a
561
+ clause/role silently no-op'd the trust and still parked behind the
562
+ suspicious-objective heuristic. New pure helper objectiveIsUserSeeded()
563
+ normalizes BOTH sides through the same extraction pipeline the creation
564
+ path applies; createdVia still gates WHO is trusted (agent-authored seeds
565
+ gain nothing). Regression tests: clause+role user seeds dispatch verbatim;
566
+ reviewer-created goals with matching-cleaned seeds never get the trust.
567
+
568
+ ### Mechanical pre-audit: maxBuffer ceiling killed verbose green suites (2026-08-23)
569
+
570
+ #### Fix
571
+ runMechanicalPreAuditChecks passed no maxBuffer to execFileSync, so
572
+ Node's default 1 MB cap applied: any contract gate whose output exceeds
573
+ 1 MB gets its child SIGTERMed by Node and the call throws ENOBUFS —
574
+ which the banner logic (signal==="SIGTERM") then misreported as "killed
575
+ after 600s". Field incident (2026-08-23, five consecutive auditor
576
+ rounds on hellhunter's `bun test src/lib/game`): the gate emits ~1.17 MB
577
+ of ALL-PASSING output and was unpassable by construction — every attempt
578
+ died at ~1 MB (~15s in) while the identical tree passed green from an
579
+ interactive shell 19/19 times, including piped-output and single-core
580
+ pinned runs. Now passes maxBuffer: 64 MB, and ENOBUFS deaths no longer
581
+ print the misleading 600s timeout banner.
582
+
583
+ ## 0.35.34 — lastOutcome actually durable (2026-08-23)
584
+
585
+ ### Fix
586
+ Audit-pass finding: v0.35.30's "durable" last-outcome record was never
587
+ serialized — persistStateLine omitted the field and readState never
588
+ restored it, so any restart/reload blanked the widget retention line
589
+ within its 24h window (the exact failure v0.35.30 fixed). Now always
590
+ written (null when absent — readState spreads successive state events, so
591
+ an omitted key would resurrect stale values and /glla wipe could never
592
+ clear the record) and restored through a strict shape sanitizer (corrupt
593
+ lines degrade to absent, never throw). Round-trip + corruption regression
594
+ tests added.
595
+
596
+ ## 0.35.33 — plan mode: the extended draft (2026-08-22)
597
+
598
+ ### Add
599
+ /goal plan | /list plan | /loop plan — the EXTENDED DRAFT for
600
+ greenfield/megaplan work where the standard 5–7-question interview is too
601
+ shallow (user design 2026-08-22). Research BEFORE questions (Explore
602
+ subagents, file reads), multi-round interviewing (architecture → scope →
603
+ failure conditions → verification), and a structured expanded objective:
604
+ current-state analysis, decisions with rationale, milestone breakdown,
605
+ per-milestone verification contract. Deliberately NOT a separate artifact —
606
+ the objective itself is the single truth (the respec lesson: a second
607
+ document always goes stale). Trust machinery unchanged: propose_*_draft +
608
+ the Confirm card still gate activation; regular drafts stay the fast path.
609
+ New prompts prompts/goal-loop-plan.md + goal-loop-plan-loop.md; depth flag
610
+ on the drafting session (runtime-global, reset by clearDraftingState);
611
+ completions on all three commands; /list plan gated as a mutating verb on
612
+ stale handles. respec stays untouched (kept by user decision).
613
+
614
+ ## 0.35.32 — hermetic settings round-trip test (2026-08-22)
615
+
616
+ ### Fix
617
+ tests/auditor-extensions.test.ts depended on the developer machine having
618
+ ~/.pi/agent extensions to discover: on a bare CI home the discovered list
619
+ was empty, the handler fell back to the input prompt, and the TUI-picker
620
+ branch under test never ran (publish workflow failure). The test now seeds
621
+ a project-scope `.pi/extensions/hermetic-ext.js` so discovery is non-empty
622
+ on every machine; verified green under both an empty HOME and a populated one.
623
+
624
+ ## 0.35.31 — user-seed trust for /goal start; loop plateau no longer false-stops on a never-moved baseline (2026-08-22)
625
+
626
+ ### Fix 1: explicit /goal start paused by the suspicious-objective heuristic
627
+ Field: Screenshot_20260822_193744 — `/goal start "…because we are logged in"`
628
+ was parked as "Suspicious objective detected (dangling-fragment)" with a
629
+ repair task queued instead of dispatching. The fragment heuristics exist
630
+ for AGENT-authored report garbage; an explicit `/goal start` whose
631
+ objective is verbatim a user seed now dispatches and ledgers
632
+ `faulty_objective_user_seed_trusted` (/goal tweak remains available).
633
+ ### Fix 2: loop plateau vs a degenerate zero baseline
634
+ Field: doomtap loop stopped "plateau — best: 0" while iterations visibly
635
+ fixed real findings: a min-direction metric reading 0 before work starts
636
+ pins best at 0, so every later productive reading scores flat and burns
637
+ plateau slots. Flat readings now count toward plateau only once the metric
638
+ has demonstrably moved (an improvement on record, or best ≠ first measured
639
+ reading of the run); a metric that NEVER moves gets its own loud bounded
640
+ stop ("metric never moved …") after 2× window, not a fake plateau.
641
+
642
+ ## 0.35.30 — durable last-outcome retention: the final verdict stays visible (2026-08-22)
643
+
644
+ ### Gap
645
+ Field report with screenshots (email-api-compare, 2026-08-22): "goal gets
646
+ closed before final audit, so auditor never approves." Forensics showed the
647
+ lifecycle was CORRECT — every archived goal had an approving verdict — but
648
+ closeArchivedSlot nulled the widget slot the moment the goal archived, so
649
+ after the agent's turn ended the surface went completely blank and the only
650
+ trace of the approval was one transient toast. Returning later, "Auditor
651
+ verdict pending" was the last visible text: indistinguishable from closed-
652
+ without-audit.
653
+ ### Ship
654
+ - State.lastOutcome {at, ok, title, recap}: written by closeArchivedSlot on
655
+ every terminal slot close (approved AND aborted), overwritten per outcome.
656
+ - Widget: while no goal/list/loop occupies the slot, one dim retention line
657
+ renders for 24h — "✓ done · auditor … approved · <recap>" or "▪ ended ·
658
+ <reason>" — then goes silent. A live goal always outranks it.
659
+ - /glla wipe clears the record (clean slate means clean).
660
+ - Tests: tests/last-outcome-retention.test.ts (5) — render shapes, expiry +
661
+ garbage-timestamp safety, live-goal precedence, source pins for both
662
+ write and wipe-clear sites.
663
+
664
+ ## 0.35.29 — /glla agents: tracked-subagent panel, transcript tail, widget segment (2026-08-22, GitHub issue #15)
665
+
666
+ ### Gap
667
+ During long fan-outs the only child visibility was the widget's 3-slot
668
+ recent-action ring. A child that "almost completed its final report, went
669
+ back to check some more, then crashed" was invisible: no live status, no
670
+ counters, and no post-mortem trail anyone could find (issue #15).
671
+ Scope agreed with the user: panel + transcript tail + widget line; a live
672
+ activity stream was explicitly rejected as too noisy.
673
+ ### Ship
674
+ - getSubagentAgentsSnapshot() (goal-heartbeat.ts): read-only view of the
675
+ tracked-subagent probes with hung classification mirroring the watchdog
676
+ scan WITHOUT its counter mutation; record-frozen vs event-only evidence
677
+ named; degrades gracefully when the pi-subagents manager registry is
678
+ absent (as on currently installed versions).
679
+ - /glla agents: ranked table (hung > running > ended), per-child
680
+ tools/output/silent clocks, liveness hint on hung rows, 20-row cap with
681
+ an explicit trim notice. Read-only, stale-safe.
682
+ - /glla agents --tail <id> [--lines N]: locates the child's session file
683
+ in the cwd-munged session store by needle + newest mtime and prints the
684
+ last N entries tolerantly ([role] text, raw fallback). LOUD when nothing
685
+ matches — searched dir, transcript count, needles. Never resumes or
686
+ attaches to a child session.
687
+ - Widget segment: "● N agents · <busiest> silent Xm ⚠" appended to every
688
+ card shape via buildWidgetLines; hidden at zero tracked children.
689
+ - New pure module extensions/goal-agents-panel.ts; snapshot reaches
690
+ goal-commands via CommandDeps injection (no heartbeat import cycle).
691
+
692
+ ## 0.35.28 — due-wait backstop: lapsed wait pauses actually resume; "you were recovered" notice (2026-08-22, GitHub issue #16)
693
+
694
+ ### Root cause (field: goal paused 30min past its scheduled auto-resume while the agent narrated "the system should have auto-resumed by now")
695
+ Auto-resume for pauseKind "wait" relied SOLELY on in-memory timers. An
696
+ exhaustive map of every wait-pause site found: agent-authored waits
697
+ (pause_goal kind="wait") armed NO timer at all while their own copy
698
+ promised automatic continuation; error-brake cooldown waits were not
699
+ re-armed on session_start; single-slot provider-retry timers could be
700
+ silently clobbered by a later schedule; and no code path anywhere compared
701
+ wall time against pauseResumeAt outside display rendering.
702
+ ### Fix
703
+ The heartbeat owns the durable invariant now: every tick, a wait whose
704
+ pauseResumeAt lapsed >90s is re-fired — main-model recovery waits route to
705
+ a provider probe, everything else clears the park and dispatches one fresh
706
+ continuation. supervisorPaused() still freezes it under /glla pause and
707
+ the load hold, one attempt per (goalId:resumeAt) key prevents storms (the
708
+ route re-parks with a fresh resumeAt on failure), and every fire is
709
+ ledgered wait_pause_overdue_resume. A stale hold persisted by a previous
710
+ process is released when a consenting reload arrives. Issue part 2:
711
+ resumed goals carry an autoResumed stamp rendered as a RECOVERY NOTICE in
712
+ the continuation prompt — "welcome back, YOU were recovered" — so agents
713
+ stop waiting for an external recovery signal that already happened.
714
+
715
+ ## 0.35.27 — Windows auditor launch: quote only when needed, gate always first (2026-08-22, PR #17)
716
+
717
+ ### Field report (PR #17, reproduced on Windows 11 + pnpm global shim)
718
+ The detached auditor died ~0.5s after launch and retried forever: quoting
719
+ EVERY argument wraps a bare executable name in quotes, which changes how
720
+ cmd.exe resolves it and how npm/pnpm .CMD shims compute their own
721
+ directory -> MODULE_NOT_FOUND -> "pi exited without an agent_settled RPC
722
+ event" in a 60s retry loop of flashing terminal windows.
723
+ ### Fix
724
+ buildAuditorPiSpawnSpec now runs the WINDOWS_UNSAFE_ARG rejection on EVERY
725
+ argument BEFORE the quoting decision, then quotes only when tokenization
726
+ requires it (whitespace / cmd metacharacters / empty). Clean bare tokens
727
+ reach cmd.exe untouched (shims resolve; full RPC sessions work); the
728
+ upstream PR's variant was not mergeable as-is because its needs-quoting
729
+ regex also gated the unsafe-arg check, letting %/CR/LF through bare.
730
+ Regression tests pin all three classes through the spec builder.
731
+
732
+ ## 0.35.26 — zombie watchdog recognizes pi-subagents tool names (2026-08-22, GitHub issue #13)
733
+
734
+ ### Gap
735
+ The v0.35.4 subagent-wait carve-out matched only the legacy built-in names
736
+ (Agent / get_subagent_result / steer_subagent). The pi-subagents extension
737
+ registers its foreground dispatch tool as "subagent" and a blocking wait as
738
+ "subagent_wait", so a parent legitimately BUSY on a healthy foreground child
739
+ tripped the bounded abort: field report shows a child writing Postgres
740
+ records productively for 30 minutes while the parent was stream-silent on
741
+ `subagent` — zombie_run_suspected at 20m, loop_stopped + zombie_run_aborted
742
+ at 30m, productive work killed mid-write.
743
+ ### Fix
744
+ One shared SUBAGENT_WAIT_TOOL_NAMES set + isSubagentWaitCall predicate in
745
+ goal-heartbeat.ts, consumed by BOTH sites (zombie stand-down and wedge-alert
746
+ hint) so the lists cannot drift apart again. New names: "subagent",
747
+ "subagent_wait". Behavioral tests drive the real heartbeat tick with a real
748
+ tool_call event: stand-down while in flight, clean abort once it settles,
749
+ no blanket amnesty.
750
+
751
+ ## 0.35.25 — /loop resume honors the zero-stream abort park (2026-08-22, GitHub issue #14)
752
+
753
+ ### Gap
754
+ abortZombieRun parks a loop with stopReason "stopped: automatic zero-stream
755
+ abort — ... (iteration N preserved; /loop resume to retry)" and its message
756
+ promises /loop resume — but the RESUMABLE_STOP predicate in the resume
757
+ handler never matched that prefix. The explicit resume answered "No held
758
+ loop to resume"; iteration count, best value, and preserved history were
759
+ unreachable without re-drafting from scratch (field report: a metricless
760
+ 24h loop parked at iteration 210 with 200 history entries).
761
+ ### Fix
762
+ RESUMABLE_STOP gains the "stopped: automatic zero-stream abort" prefix.
763
+ The explicit resume now re-arms the loop exactly as promised: fresh stall
764
+ window, re-armed counters, load hold released, one new dispatch — with
765
+ iteration/best/history intact. Control test pins that non-resumable stops
766
+ (e.g. bounds) stay stopped.
767
+
768
+ ## 0.35.24 — auditor model picker at full selector parity: forbidden-models filtering (2026-08-22, note.md Next #1)
769
+
770
+ ### Gap
771
+ The /glla -> Auditor model row already hosted the /model-style fuzzy
772
+ picker and persisted to the exact key resolveAuditorModel reads — but
773
+ unlike every main-agent flow it did NOT apply forbidden-models policy:
774
+ blocked models appeared in the list and the typed escape hatch accepted
775
+ them, yielding pins the resolver silently skips at audit time.
776
+ ### Fix
777
+ promptModelRef gains an excludeRefs opt threading into buildModelPickItems
778
+ (list-level filter) AND validating typed entries against isForbiddenModel
779
+ (a policy match is refused with a warning naming the ref — never saved).
780
+ Both auditor slots use it: Auditor model and Auditor fallback agent.
781
+ A pin saved by the picker is one the resolver honors; runtime skips
782
+ (auditor_model_fallback reason:"forbidden") remain as belt-and-suspenders.
783
+
784
+ ## 0.35.23 — load without autostart: cold sessions hold automation for an explicit decision (2026-08-22, note.md Next #2)
785
+
786
+ ### Root cause
787
+ shouldAutoResumeOnSessionStart already demanded explicit `autoResume ===
788
+ true` (v0.28.21 tri-state, undefined default = HOLD) — but its only
789
+ consumer fed it the AGGRESSIVE-MODE COERCED value (unset -> true because
790
+ aggressiveMode defaults on), so stock installs auto-resumed everything on
791
+ every session load despite the documented default. Three further paths
792
+ bypassed the consent entirely.
793
+ ### Fixes
794
+ - Load consent now reads the RAW global autoResume setting; aggressive
795
+ mode keeps owning its caps only. Default (unset/false) = restore and
796
+ DISPLAY state, hold automation.
797
+ - New durable loadHoldAt state engages through the SAME freeze gates as
798
+ /glla pause (continuation dispatch, loop ticks, heartbeat refires,
799
+ recovery timers); released by any explicit work command (/goal resume,
800
+ /list resume, /list next, /loop resume|start, new goal creation),
801
+ each release ledgered load_hold_released. Heartbeat host-loss
802
+ supervision stays armed under the hold — a held plane is never an
803
+ unprobed idle plane.
804
+ - Closed consent bypasses: different-pid crash successors no longer
805
+ auto-resume held loops or replay journals as automation (same-process
806
+ /reload successors keep continuity); parked completion-audit claims no
807
+ longer auto-retry on a bare cold start (the main-model-recovery one-
808
+ shot retry keeps its pinned consent).
809
+
810
+ ## 0.35.22 — a queued item blocked by a live loop is loud and self-heals at loop end (2026-08-22)
811
+
812
+ ### suspicious-unstartable-repair-card fix (note.md Next #3)
813
+ Field (screenshots 20260821_114109/114210/134442/134645): /goal start of a
814
+ lowercase-fragment objective paused the goal and queued a repair task; the
815
+ card said "/list next starts the preserved repair/replan task" — but with
816
+ the Chrome-Bridge loop owning the surface, activateNextListItem's
817
+ one-active-thing guard refused activation LEDGER-ONLY: unstartable AND
818
+ invisibly blocked. Two fixes:
819
+ - the refusal now notifies with the queued objective and the way out
820
+ ("/loop stop … then /list next"), and the ledger names what stayed queued;
821
+ - when a loop ends by ANY route (/loop stop, /loop finish, plateau/bounds
822
+ stop), resumeQueuedListAfterLoopEnd retries list activation when no goal
823
+ owns the surface — the blocked entry starts instead of staying dead.
824
+ Also: tests/list-invisible-restart.test.ts no longer depends on co-resident
825
+ module state (unique owner session + explicit reset), fixing the cross-file
826
+ ordering failure surfaced by audit round eight.
827
+
828
+ ## 0.35.21 — list queue stays visible across lifecycle boundaries (2026-08-22)
829
+
830
+ ### list-invisible-until-restart fix (note.md Next #4)
831
+ Field: a stopped/interrupted /list exec left the queue surface blank —
832
+ active item only, no "N waiting · up next" line — until a session
833
+ restart. Root cause: the sidebar renders state.list from MEMORY while the
834
+ durable queue is the UNION of the state ledger and the per-item
835
+ .queue.json sidecars (v0.34.60 disk-first writes); a plugin re-init /
836
+ stale-handle window reset RAM to defaults and only some later path
837
+ re-ran the disk merge. session_start's restore now converges memory to
838
+ that union immediately (hydrateListQueueFromDisk after readState), so
839
+ the next lifecycle boundary heals the surface without a restart; the
840
+ hydration notifies with a truthful count ("restored N queued list
841
+ item(s)"). Regression tests: sidecar-only item is hydrated AND rendered;
842
+ convergence is idempotent (no duplicate for items in both stores).
843
+
844
+ ## 0.35.20 — one bounded automatic retry for transient mechanical-check deaths (2026-08-21)
845
+
846
+ ### Gate resilience
847
+ Field (sixth audit round): the pre-audit gate died MID-RUN under machine
848
+ load ~30 — output ends inside a passing file, no runner summary, exit 1 —
849
+ while the identical tree passed green twice in isolation. Resource
850
+ contention, not a red suite. Mechanical check commands now get exactly ONE
851
+ bounded automatic retry on failure: a deterministic red command stays red
852
+ on both attempts (final output names the retry and preserves the second
853
+ attempt's diagnostics); a first-attempt transient death followed by a
854
+ passing retry passes with an honest `recoveredRetryNote` in the result.
855
+ Mirrors the v0.35.17 zero-stream auto-retry philosophy at the gate level.
856
+
857
+ ## 0.35.19 — load-resilient budgets for the aggressive-recovery test (2026-08-21)
858
+
859
+ ### Flake hardening
860
+ At machine load ~50 (16 cores), the aggressive no-verdict recovery test's
861
+ wall-clock wait budgets (2x 25s inside a 60s per-test ceiling) expired
862
+ before two real subprocess-based auditor retry cycles completed — while
863
+ the canonical full-suite run stayed green in the same conditions. Raised:
864
+ per-test 60s→120s, retry waits 25s→45s, state-transition waits 8s→20s.
865
+ Budgets only; semantics untouched (same precedent as v0.35.15's 30s→60s).
866
+
867
+ ## 0.35.18 — mechanical checks resolve raw runners to their canonical scripts (2026-08-21)
868
+
869
+ ### Spurious fast-fail fix (fourth audit round)
870
+ A verification contract that names a RAW RUNNER in prose ("passes under
871
+ `bun test`") made the deterministic pre-audit execute `bun test` bare,
872
+ ignoring the project's own required configuration encoded in package.json
873
+ scripts (--parallel=1 --max-concurrency=1 --timeout; this suite shares
874
+ module state process-wide by design and serializes deliberately). The bare
875
+ invocation failed 6 tests + 5 nested-test errors while the canonical gate
876
+ was green twice — a spurious fast-fail of finished work. Mechanical check
877
+ commands that are exactly a raw runner invocation (bun test / vitest /
878
+ jest, no extra args) now resolve to the package script that wraps them;
879
+ narrower runs and non-runner programs pass through untouched. Pure resolver
880
+ (`resolveCanonicalRunnerCommand`) lives in goal-loop-backoff.ts with unit
881
+ tests; bunfig cannot express the required flags (verified empirically:
882
+ `[test] timeout` is not honored on bun 1.3.14).
883
+
884
+ ## 0.35.17 — zero-stream abort gains ONE bounded automatic retry; tag backfill (2026-08-21)
885
+
886
+ ### Post-accept hang self-heal (note.md Next §1)
887
+ Turns dispatched by accepting a Confirm dialog hung with zero provider
888
+ stream activity often enough that users repeatedly returned to parked
889
+ "action needed" sessions (field screenshot 20260821_152311). The watchdog's
890
+ bounded abort was correct; what was missing is self-heal. The FIRST silence
891
+ of a zero-stream streak now arms exactly ONE automatic retry ~90s after the
892
+ park — the parked goal/list item/loop auto-resumes through the durable
893
+ continuation machinery and one fresh dispatch goes out. A SECOND consecutive
894
+ silence refuses further retries (`zombie_auto_retry_refused_streak`) and
895
+ parks permanently for manual resume; real stream activity between aborts
896
+ resets the streak so an independent later hang earns its own single retry.
897
+ `/glla pause` freezes the retry like every other automatic side-effect;
898
+ the timer only clears a pause carrying exactly the watchdog's own reason
899
+ (a newer manual/recovery pause supersedes it); the heartbeat's one-shot
900
+ abort latch is released on retry dispatch so a fully-silent retry can still
901
+ be re-aborted. Pure streak decision lives in goal-loop-backoff.ts
902
+ (`zombieRetryDecision`) with unit tests; behavioral coverage drives the
903
+ full hang→abort/park→auto-resume→re-dispatch arc plus the double-hang and
904
+ pause-during-waystation paths (tests/post-accept-hang-retry.test.ts).
905
+
906
+ ### Version tags backfilled
907
+ All 41 released versions missing their `v<version>` git tag (v0.34.20 …
908
+ v0.35.16) were tagged at the historical commit whose package.json carried
909
+ that exact version and pushed to all remotes. Additive-only — no history
910
+ rewrite.
911
+
912
+ ### README currency pass
913
+ Documents the v0.35.15 per-phase glyphs/activity meter/silent-stretch
914
+ footer, `/glla pause`, and the v0.35.17 zero-stream auto-retry.
915
+
916
+ ## 0.35.16 — mechanical pre-audit gate no longer kills legitimate long checks (2026-08-21)
917
+
918
+ ### Deterministic pre-audit timeout fix
919
+ `runMechanicalPreAuditChecks` executed every contract command under a
920
+ hard 60-second `execFileSync` ceiling — but this repo's own contract
921
+ command (`npm run release:check`) legitimately needs ~3 minutes. Every
922
+ deterministic pre-audit therefore fast-failed with a truncated
923
+ head-of-output report showing only startup logs (two field rounds:
924
+ 2026-08-21 14:17 and 16:01), burning two auditor cycles on a gate that
925
+ could never pass inside its own bound. The default bound is now 10 minutes
926
+ — still a hang guard, no longer an honest-slow-work guard. Failed output
927
+ keeps the TAIL (where failures live) instead of the head, truncation is
928
+ labeled, and a timeout kill is bannered as such instead of masquerading as
929
+ an exit-code-1 test failure.
930
+
931
+ ## 0.35.15 — glla status-surface UX: visual footer, /glla pause, proactive quiet notify (2026-08-21)
932
+
933
+ ### Visual status footer
934
+ The auditing footer now leads each auditor phase with a distinct glyph
935
+ (queued ⋯ · running ▶ · quiet ◌ · blocked ⛔ · awaiting-verdict ✓) and a
936
+ compact draining activity meter (▰▱) that empties as worker silence grows
937
+ toward the quiet threshold. A glance answers "is the audit alive?" without
938
+ reading the sentence.
939
+
940
+ ### /glla pause | resume — broad supervisor freeze
941
+ `/glla pause` freezes ALL automatic machinery — heartbeat re-arms, stale
942
+ probes, zombie cleanup, main-model recovery probes, automatic completion-
943
+ audit recovery, continuation dispatch, loop ticks, and the proactive quiet
944
+ notification — while leaving the active goal/list item/loop and any
945
+ detached worker untouched. The flag persists via `supervisorPausedAt`, so a
946
+ session restart cannot silently re-arm machinery the user explicitly
947
+ stopped. `/glla resume` clears it first, then resumes whatever else is
948
+ resumable, and never follows with a misleading "Nothing to resume". Manual
949
+ user commands always still work.
950
+
951
+ ### Proactive auditor quiet reporting
952
+ Entering the quiet phase (~3 min of zero worker activity) now fires exactly
953
+ ONE warning notify instead of only recoloring the status chip — the field
954
+ complaint was an 8-minute silent stretch the user only discovered after the
955
+ fact. Once activity resumes, the footer shows "silent Xm then resumed" for
956
+ 10 minutes so a missed silence stays visible.
957
+
958
+ ### Persistence fix (latent bug)
959
+ `persistStateLine` never serialized `lastCompactionAt` despite v0.34.97's
960
+ comment claiming it did — the ⏳ compacting… chip silently lost its reload
961
+ survival. Both epoch fields now ride the state line with explicit nulls so
962
+ ledger merges clear them correctly.
963
+
964
+ ## 0.35.14 — full extension audit hardening (2026-08-21)
965
+
966
+ ### Verification and lifecycle integrity
967
+ Mechanical contract checks now run through a shell-free literal-argument
968
+ boundary, auditor verdicts require one final terminal marker, and regression
969
+ shield references must appear inside `<evidence>`. Invalid persisted IDs are
970
+ rejected at state hydration and filesystem boundaries. Child extension
971
+ factories no longer claim the host API or start timers before an admitted
972
+ `session_start`; completion approval cannot report success when terminal
973
+ archiving fails, and branch-mode loop resumes refuse the wrong branch.
974
+
975
+ ### Release contract
976
+ Published documentation includes the linked planning files, the workflow
977
+ runs the release contract on pushes and pull requests, and release tooling
978
+ uses pinned Node/npm versions.
979
+
3
980
  ## 0.35.13 — stale-API recovery loop fix (2026-08-20)
4
981
 
5
982
  ### Stale-handle recovery correctness