pi-goal-list-loop-audit 0.35.32 → 0.35.65

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 (40) hide show
  1. package/CHANGELOG.md +632 -0
  2. package/INSTALL.md +177 -321
  3. package/README.md +390 -694
  4. package/docs/INDEX.md +4 -2
  5. package/extensions/context-hygiene.ts +129 -0
  6. package/extensions/faulty-objective-recovery.ts +24 -0
  7. package/extensions/glla-state-root.ts +99 -0
  8. package/extensions/goal-agents-panel.ts +116 -23
  9. package/extensions/goal-commands.ts +108 -6
  10. package/extensions/goal-continuation.ts +77 -22
  11. package/extensions/goal-heartbeat.ts +448 -42
  12. package/extensions/goal-loop-auditor-process.ts +100 -4
  13. package/extensions/goal-loop-core.ts +100 -11
  14. package/extensions/goal-loop-dispatch.ts +3 -2
  15. package/extensions/goal-loop-display.ts +86 -55
  16. package/extensions/goal-loop-forever.ts +17 -6
  17. package/extensions/goal-loop-shield.ts +20 -3
  18. package/extensions/goal-loop-stats.ts +3 -2
  19. package/extensions/goal-loop.ts +36 -4
  20. package/extensions/goal-settings.ts +38 -14
  21. package/extensions/goal-state.ts +9 -0
  22. package/extensions/loops/goal-activation.ts +201 -21
  23. package/extensions/loops/goal-auditor-surface.ts +32 -0
  24. package/extensions/loops/goal-list-queue.ts +55 -11
  25. package/extensions/loops/goal-orchestrator.ts +5 -0
  26. package/extensions/loops/goal-runtime-globals.ts +5 -0
  27. package/extensions/loops/goal-session.ts +68 -8
  28. package/extensions/loops/goal-settings-ui.ts +21 -1
  29. package/extensions/loops/goal-tools.ts +22 -1
  30. package/extensions/loops/goal-ui.ts +9 -6
  31. package/extensions/main-model-recovery.ts +10 -0
  32. package/extensions/payload-guard.ts +172 -0
  33. package/extensions/reviewer.ts +3 -1
  34. package/extensions/settings-menu.ts +30 -5
  35. package/package.json +3 -2
  36. package/prompts/goal-loop-plan-loop.md +31 -0
  37. package/prompts/goal-loop-plan.md +51 -0
  38. package/schemas/goal.schema.json +2 -1
  39. package/scripts/auditor-extension-fixture.mjs +19 -0
  40. package/scripts/verify-auditor-extensions-offline.mjs +51 -38
package/CHANGELOG.md CHANGED
@@ -1,5 +1,637 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.35.65 — status surfaces and worker liveness (2026-08-26)
4
+
5
+ ### Added
6
+ The persistent footer now stays compact and global, while the detailed
7
+ widget and `/glla agents` share one evidence-backed worker projection. Active
8
+ non-auditor workers expose sanitized identity/purpose, queued/running/hung/
9
+ ended status, coarse phase, elapsed time, silence age, and ownership-aware
10
+ lifecycle evidence. Narrow widgets retain essential liveness fields and
11
+ point explicitly to `/glla agents` when rows overflow.
12
+
13
+ ### Changed
14
+ Detached completion-auditor evidence remains a separate verification HUD;
15
+ it is not mixed into the worker roster or duplicated in the global footer.
16
+ Existing command names, lifecycle, persistence, recovery, and auditor
17
+ semantics are unchanged.
18
+
19
+ ### Tests
20
+ Focused status and worker-lifecycle coverage, fresh active/queue/recovery/
21
+ auditor fixtures, the full release gate, TypeScript checking, offline auditor
22
+ validation, and npm packaging were completed for this release.
23
+
24
+ ## 0.35.64 — bounded recovery for frozen subagents (2026-08-25)
25
+
26
+ ### Fix
27
+ A tracked top-level subagent that produces no tool-use or output-token
28
+ progress now receives the existing short warning first, then one
29
+ generation-fenced child-specific abort request after the configurable
30
+ `subagentHangEscalationMinutes` threshold (default 30; 0 keeps
31
+ warning/telemetry-only behavior). Nested, unreachable, or ownership-
32
+ ambiguous children remain warning-only. A stale child no longer shields an
33
+ unrelated parent zombie watchdog, and `/glla agents` shows ABORTING,
34
+ unavailable, or failed action state while preserving partial output.
35
+
36
+ ### Tests
37
+ `tests/subagent-hang-detection.test.ts` covers one-shot escalation,
38
+ progress-before-action cancellation, manager-unavailable and nested-child
39
+ safety, and `tests/agents-panel.test.ts` pins the action surface. Settings
40
+ menu/editor and INSTALL documentation expose the new threshold.
41
+
42
+ ### Follow-up hardening
43
+ Frozen-child escalation now uses pi-subagents' existing root-session
44
+ `subagents:rpc:stop` bridge, with readiness, ownership, generation, and
45
+ timeout-race fencing. The real AgentManager/RPC path is covered by a
46
+ deterministic pending-provider integration test without modifying the
47
+ upstream package.
48
+
49
+ Malformed saved goal/list objectives now produce a bounded repair/replan
50
+ card instead of a self-blocking first turn. One durable bootstrap turn
51
+ carries the complete preserved target and `propose_task_list` confirmation;
52
+ automatic repeats are fenced, while explicit `/list resume` re-arms one
53
+ retry. The card keeps its concrete recovery action and queue position
54
+ visible.
55
+
56
+ ### Tests
57
+ Focused repair/replan, display, stale-probe, and RPC regressions are
58
+ included in the release contract. The complete gate remains the source of
59
+ truth for the published artifact.
60
+
61
+ ## 0.35.63 — auditor context held until resume (2026-08-25)
62
+
63
+ ### Fix
64
+ Cold session restores now keep unfinished goal/list objectives and their
65
+ status visible without automatically injecting the previous auditor report
66
+ or dispatching a new continuation. Explicit `/goal resume`, list/glla/loop
67
+ continuation commands, validated lifecycle continuity, and global
68
+ `autoResume: true` release the auditor-context gate. The prior Pi transcript
69
+ and durable audit history remain untouched.
70
+
71
+ ### Tests
72
+ `tests/auditor-blank-until-resume.test.ts` proves objective visibility,
73
+ pre-consent report/TODO suppression, explicit resume release, auto-resume
74
+ release, and rejected stale-resume suppression. Version metadata is
75
+ synchronized to 0.35.63.
76
+
77
+ ### Follow-up hardening
78
+ `/goal resume` now releases the auditor surface only after its existing
79
+ stale/foreign admission probe. Active-idle resumes receive the same probe;
80
+ stale paused resumes preserve the existing active/interrupted recovery
81
+ marker without exposing old auditor context. Main-model recovery resumes
82
+ now use the same stale/foreign admission probe and release the surface on
83
+ manual-hold, retry, and primary-probe recovery paths; a recovery regression
84
+ test pins the consent behavior.
85
+
86
+ ## 0.35.62 — subagent host-state boundary (2026-08-25)
87
+
88
+ ### Fix
89
+ Headless child sessions are now rejected before state-root registration,
90
+ restore, owner claims, and tool repair. The same fail-closed boundary covers
91
+ persistent children, foreign slash commands, and missing tool invocation
92
+ contexts. File-backed host successors remain eligible for legitimate reload
93
+ and silent-rebind recovery. Main-host subagent telemetry continues through
94
+ the event bus and `/glla agents` path.
95
+
96
+ ### Tests
97
+ `tests/subagent-host-boundary.test.ts` proves first-claim prevention,
98
+ foreign slash-command refusal, persistent-worker refusal, legitimate host
99
+ successor admission, and durable Explore telemetry. Version metadata is
100
+ synchronized to 0.35.62.
101
+
102
+ ## 0.35.61 — list queue visibility across host replacement (2026-08-25)
103
+
104
+ ### Fix
105
+ Waiting-only list state now has an actionable status/widget projection even
106
+ when no list item is active. Silent host-successor and same-session stale
107
+ recovery boundaries also re-read the selected durable root and hydrate queue
108
+ sidecars before repainting. A recovered queue now stays visible and can be
109
+ started with `/list next` without requiring a full reload.
110
+
111
+ ### Tests
112
+ `tests/list-invisible-restart.test.ts` covers waiting-only visibility and
113
+ activation plus sidecar-only silent-successor rehydration. Version metadata
114
+ is synchronized to 0.35.61.
115
+
116
+ ## 0.35.60 — pre-turn glla tool visibility (2026-08-25)
117
+
118
+ ### Fix
119
+ GLLA agent tools are now registered and reactivated immediately before
120
+ agent turns, with `agent_start`/`turn_start` compatibility fallbacks. This
121
+ closes the interval where an external tool allowlist or modlist could remove
122
+ `pause_goal` after session restore and Pi would answer a valid model call
123
+ with `Tool pause_goal not found`, leaving a parked objective looking stuck
124
+ until reload.
125
+
126
+ ### Tests
127
+ `tests/gettick-tool-visibility.test.ts` simulates a post-restore active-tool
128
+ replacement and verifies the pre-turn boundary restores `pause_goal` and
129
+ keeps it callable. Version metadata is synchronized to 0.35.60.
130
+
131
+ ## 0.35.59 — safe cancel/wipe across unresolved session roots (2026-08-25)
132
+
133
+ ### Fix
134
+ `/glla cancel`, `/glla wipe`, `/list cancel`, `/list clear`, and the shared
135
+ goal archive path now fail closed while opt-in `sessionDir` resolution is
136
+ pending. They leave the in-memory objective/list untouched and do not
137
+ recreate or mutate an ambiguous cwd state tree; after host lifecycle
138
+ admission registers the session root, cancel and wipe archive/clear under
139
+ the selected session root as before.
140
+
141
+ ### Tests
142
+ `tests/objective-loss-lifecycle.test.ts` covers both deferred destructive
143
+ commands and successful `/glla cancel` + `/glla wipe` cleanup under a
144
+ registered session root. Version metadata is synchronized to 0.35.59.
145
+
146
+ ## 0.35.58 — objective-loss lifecycle repair (2026-08-24)
147
+
148
+ ### Fix
149
+ Wired the opt-in `sessionDir` root into the admitted production lifecycle.
150
+ `session_start` and silent host-successor admission now register Pi's
151
+ canonical `SessionManager.getSessionDir()` before owner, invalidation, or
152
+ restore writes; in-memory worker sessions remain pending instead of creating
153
+ an ambiguous cwd tree. The configured session directory wins over an
154
+ imported session-file parent, while `PI_SESSION_FILE` remains the explicit
155
+ child-process fallback.
156
+
157
+ ### Evidence
158
+ Added `tests/objective-loss-lifecycle.test.ts`: a real registered
159
+ `session_start` handler proves production root registration, and separate
160
+ fresh Bun writer/reader processes recover an objective across a cwd switch.
161
+ The report intentionally does not claim to simulate a crash mid-write or a
162
+ specific version migration. Full evidence:
163
+ audit/OBJECTIVE-LOSS-VALIDATION-2026-08-24.md.
164
+
165
+ ### Tests
166
+ Focused lifecycle/state-root tests and clean tsc pass; the full release gate
167
+ is run for this version before closure.
168
+
169
+ ## 0.35.57 — objective-loss validation (2026-08-24)
170
+
171
+ ### Evidence
172
+ Validated the Now report that objectives disappeared after a Wez crash or
173
+ version/cwd switch. The historical workingDir default intentionally makes a
174
+ cwd switch select a different on-disk root, while explicit sessionDir keeps
175
+ the objective visible across cwd changes. Pending session-root resolution
176
+ does not migrate or delete the old cwd tree. The bounded result was
177
+ evidence-based closure pending production lifecycle wiring; crash-only loss
178
+ was not reproduced. The subsequent gettick, list-reload, and
179
+ subagent-visibility reports remain separate items.
180
+ Full evidence: audit/OBJECTIVE-LOSS-VALIDATION-2026-08-24.md.
181
+ ## 0.35.56 — state-root consumer/lifecycle hardening (2026-08-24)
182
+
183
+ ### Fix
184
+ Hardened every remaining state-root consumer and lifecycle boundary missed
185
+ by the core/settings slice. Raw `<cwd>/.pi-glla` joins in auditor jobs,
186
+ dispatch, goal-loop ledger reads, reviewer, stats rollup/discovery, and
187
+ session owner/handoff/pending-list paths now route through `piGlaDir` and
188
+ respect the selected root. Pending `sessionDir` resolution (no session dir
189
+ yet) is a strict deferral: dispatch, reviewer, session owner, handoff, and
190
+ pending-list writes return a deferred/false result without creating a
191
+ fallback `<cwd>/.pi-glla` tree, and legacy `.pi-gla` trees are still never
192
+ migrated. Audit-loop open-count helpers now resolve via the selected root
193
+ as well. Host/subagent ownership stays per-process via `PI_SESSION_FILE`
194
+ fallback and the explicit `setRuntimeSessionDir` hook — no global overwrite.
195
+
196
+ ### Tests
197
+ New `tests/state-root-consumers.test.ts` pins resolved-root routing for
198
+ dispatch/stats/audit helpers, pending deferral for dispatch/reviewer, the
199
+ `PI_SESSION_FILE` fallback, and source-level absence of raw hardcodings plus
200
+ pending guards. Existing `tests/state-root.test.ts` continues to cover core
201
+ core/settings behavior. Red/green: breaking the `piGlaDir` routing makes the
202
+ consumer pins fail; restoring passes 9/9 focused plus 56 prior. tsc and full
203
+ release gate green for this tree.
204
+ ## 0.35.55 — opt-in session-root state core/settings slice (2026-08-24)
205
+
206
+ ### Fix
207
+ Ported the valid state-root portion of PR #21 onto current main without
208
+ merging the stale PR verbatim. New dependency-free
209
+ extensions/glla-state-root.ts owns the typed global root selector and
210
+ session-directory resolution so goal-loop-core can select a root without a
211
+ settings import cycle. The historical <cwd>/.pi-glla workingDir remains
212
+ the default; sessionDir is explicit opt-in and resolves to the top-level Pi
213
+ session directory (or PI_SESSION_FILE's parent for worker processes).
214
+ Session-root mode is global-only because project settings.json lives inside
215
+ the selected root. Pending sessionDir resolution is a write boundary:
216
+ core directory/ledger/queue/sentinel/audit-log writes defer rather than
217
+ recreate an ambiguous cwd tree, and old .pi-gla/.pi-glla trees are never
218
+ migrated or deleted by the new mode. The settings menu exposes the two
219
+ choices and project attempts to override stateRoot are stripped.
220
+
221
+ ### Tests
222
+ tests/state-root.test.ts covers default cwd persistence, opt-in session-root
223
+ persistence, pending-write/no-migration behavior, PI_SESSION_FILE fallback,
224
+ and global-only settings round-trip. settings-editors and
225
+ settings-menu-complete pin the UI/provenance surface; the long-term
226
+ preferences boundary now checks the dependency-free global path owner.
227
+ Red/green proved the session-root branch is required (2 of 5 focused tests
228
+ fail when neutered; restored 5/5). tsc and focused tests pass before the
229
+ full release gate.
230
+ ## 0.35.54 — RESUMABLE_STOP honors the v0.35.31 "metric never moved" stop (2026-08-24)
231
+
232
+ ### Fix
233
+ Collect-pass HIGH finding: the v0.35.31 "metric never moved" stop reason
234
+ promises "/loop resume retries or /loop stop" in its own message, but the
235
+ RESUMABLE_STOP predicate in /loop resume never matched that prefix - the
236
+ promised command answered "No held loop to resume", and with
237
+ propose_loop_refine gated on an ACTIVE loop, the only recovery was
238
+ /loop stop + a fresh start discarding iteration history. Same class as
239
+ the v0.35.25 issue-#14 zombie prefix bug (fixed there for zero-stream,
240
+ missed for this brand-new prefix). The prefix is now resumable: resuming
241
+ re-arms the error/stuck/stall counters while preserving iteration, best,
242
+ and history; if the metric is still dead it re-stops loudly after its
243
+ window, and a measure-changing propose_loop_refine (usable again once
244
+ resumed) re-scopes the measure era so the never-moved grace re-arms.
245
+
246
+ ### Tests
247
+ tests/metric-never-moved-resumable.test.ts: behavioral - a loop parked by
248
+ the exact production reason string resumes via /loop resume with
249
+ iteration/best/history preserved and all three streak counters re-armed;
250
+ negative pin - a bounded stop ("max iterations reached") stays
251
+ non-resumable. Red-proven by removing the predicate clause (behavioral
252
+ fails, negative pin stays green).
253
+ ## 0.35.53 — false repair card after abort+reload: parser marker fix + contract-derived objective heal (2026-08-24)
254
+
255
+ ### Fix
256
+ note.md Now: "objective needs repair issue, but before reload it looked
257
+ fine". Field forensics (neonbreak, item 20260823082852-in3rc7): the list
258
+ draft batch wrote an item with objective "" and the ENTIRE intent inside
259
+ the verification contract - extractVerificationContract's line marker
260
+ regex `verify\b[^:]*:` misread the imperative sentence "Verify the
261
+ shipped PREMIUM-UIUX pass (...): confirm ..." as a contract marker
262
+ ("verify" is both a marker word and an ordinary imperative verb), leaving
263
+ the objective empty. The activation gate then correctly flagged "empty"
264
+ and jammed a repair card ahead of the item - 42
265
+ faulty_objective_list_activation_blocked events over 22 hours, an endless
266
+ repair-card loop that wedged the session. Two-layer durable fix:
267
+ (1) WRITER - the line marker for the ambiguous verbs now requires the
268
+ colon immediately ("Verify:" / "Verify when:" / "Verification:");
269
+ "done"/"done when"/"verified when" keep a bounded 60-char decorated-marker
270
+ gap so prose tails cannot masquerade as markers either. The field text
271
+ now parses with the real objective and only the grep tail as contract.
272
+ (2) READER - legacy items already persisted with an empty objective plus
273
+ a clean, actionable contract derive their objective deterministically
274
+ from the contract's leading imperative sentence at activation
275
+ (list_objective_derived_from_contract) instead of demanding a repair
276
+ card. Empty objective + absent or suspicious contract still takes the
277
+ true broken-objective repair path, unchanged.
278
+
279
+ ### Tests
280
+ tests/false-repair-card.test.ts: the exact field text parses with its
281
+ intent in the objective; short-marker and decorated-marker forms still
282
+ parse; derivation unit rules (first sentence, suspicious/non-imperative
283
+ contracts rejected); behavioral - a legacy stuck item activates with the
284
+ derived objective (no repair demand, contract preserved), a truly broken
285
+ item still triggers the repair card, and a fresh /list add of the field
286
+ text activates directly end-to-end. Red-proven by neutering both layers
287
+ (4 of 6 fail; the true-broken-path tests stay green).
288
+ ## 0.35.52 — context hygiene: era-scope failed error-only turns out of the effective context (2026-08-24)
289
+
290
+ ### Fix
291
+ note.md Now: "failed requests add to the context, while clearly adding
292
+ nothing of value". When retries are exhausted, the failed assistant turn
293
+ (stopReason "error", errorMessage set, content empty/partial) STAYS in
294
+ agent state and the session - pi strips it from live state only for
295
+ mid-flight retries. Every later LLM call receives it and compaction
296
+ summarizes it; nothing downstream filters these. Field evidence (polis,
297
+ 2026-08-23): a run of 503/network_error/retry-cancelled turns drove the
298
+ estimated context to 122.7% of the 200k window, and auto-compaction then
299
+ aborted on its own bloated summarization input. New
300
+ extensions/context-hygiene.ts: a durable bounded rule drops error-only
301
+ assistant turns (stopReason "error", NO tool-call blocks) from the
302
+ effective context EXCEPT the most recent one, which stays so the model
303
+ sees why the previous attempt failed on the retry send. Applied at two
304
+ points: the `context` event projection (per-send, transcript untouched -
305
+ alongside the v0.35.51 payload guard) and `session_before_compact`
306
+ (prunes the shared preparation object the compaction runner summarizes,
307
+ shrinking the summarizer request and keeping failures out of the summary).
308
+ Tool-call-carrying error turns own paired toolResults and stay intact;
309
+ "aborted" turns are user-intent boundaries and are never touched. Drops
310
+ are ledgered (context_hygiene_dropped / context_hygiene_compaction_input).
311
+
312
+ ### Tests
313
+ tests/context-hygiene.test.ts: predicate (tool-carrying/aborted/healthy
314
+ never droppable); bounded drop rule (newest kept, older dropped, identity
315
+ preserved at/under the window, configurable window); seeded bloat (60
316
+ failures collapse, normal turns survive verbatim); in-place compaction
317
+ preparation pruning; behavioral wiring through MockPi for both hooks with
318
+ ledger assertions and clean-history no-op. Red-proven by neutering both
319
+ production call sites.
320
+ ## 0.35.51 — payload guard: bound inline image bytes on every outgoing LLM call (2026-08-24)
321
+
322
+ ### Fix
323
+ note.md Now: "req body too large due to images in context". Generated
324
+ images accumulate in conversation history as inline base64 blocks until
325
+ the provider rejects the request with 413 ("Downloaded image content
326
+ cannot exceed 30MB" / "Request Entity Too Large") - and every
327
+ main-model-recovery probe re-sent the same bloated history, so recovery
328
+ could never classify or heal the failure; the session was wedged until a
329
+ manual restart WITHOUT history. Two-layer durable fix: (1) a new
330
+ extensions/payload-guard.ts projects the outgoing message list at the pi
331
+ `context` event (fired before EVERY LLM call), bounding cumulative
332
+ inline-image bytes to 16MB - evicting the OLDEST images first, always
333
+ keeping the newest two, replacing each evicted block with a short text
334
+ placeholder. Disk history is untouched (per-send projection), and the
335
+ chokepoint protects ordinary turns AND recovery probes alike. Evictions
336
+ are ledgered as payload_guard_eviction. (2) classifyMainModelFailure now
337
+ maps 413/payload-size texts to "transient" - retryable in place, because
338
+ the payload guard (not a fallback-model switch) heals the size; the old
339
+ "unknown" classification burned the whole chain on useless rotations.
340
+
341
+ ### Tests
342
+ tests/payload-guard.test.ts: under-budget pass-through (same identity);
343
+ oldest-first eviction with newest-two floor; floor holds when the budget
344
+ cannot be met; idempotent projection, non-image content untouched;
345
+ behavioral wiring (context handler projects + ledgeres; under-budget
346
+ passes unprojected); 413 texts classify transient (not unknown, not
347
+ context-overflow). Red-proven by neutering both production sites.
348
+ ## 0.35.50 — same-process session successors auto-resume the main thread (2026-08-23)
349
+
350
+ ### Fix
351
+ note.md Now #2: session-start auto-resume asymmetry. The v0.35.23 loop
352
+ branch treats a SAME-PROCESS session successor (shutdown recorded in the
353
+ owner sidecar with a non-quit reason, previous pid === current pid) as
354
+ mid-flight continuity and resumes held loops - but a plain ACTIVE goal
355
+ held ("restored on session load - held for explicit resume") and a parked
356
+ completion-audit claim stayed parked in that exact corner: from the
357
+ user's seat, the list kept going after the session replacement while the
358
+ goal sat "awaiting first turn". The goal restore gate and the auditor
359
+ claim's canRecoverNow now accept the same consent, refined per the
360
+ v0.34.49 one-shot identity law: a PRESENT handoff marker is authoritative
361
+ even when mismatched (rejection holds); only an ABSENT marker with a
362
+ same-pid non-quit shutdown is continuity - the same distinction
363
+ listOperationLifecycleResume already draws. Different-pid crash
364
+ successors and cold loads still hold for an explicit decision;
365
+ Auto-resume stays the only load-time automation for them.
366
+
367
+ ### Tests
368
+ tests/same-process-successor-resume.test.ts: same-process successor
369
+ resumes a held ACTIVE goal (continuation dispatched, no stale interrupt
370
+ marker); same-process successor auto-retries a parked completion claim
371
+ (audit_recovery_auto_retry_claimed fence in the ledger); different-pid
372
+ crash successor still HOLDS (cold-load law). Red-proven by neutering
373
+ both consent sites; the v0.34.49 mismatched-marker identity test stays
374
+ green against the refined consent.
375
+ ## 0.35.49 — parent-side silence watchdogs close the auditor-AWOL gap (2026-08-23)
376
+
377
+ ### Fix
378
+ Field evidence across five projects (football-forever, doomtap,
379
+ junk-runner, email-api-compare, vps-compare): a detached auditor worker
380
+ whose provider hangs emits ONE boot RPC event (or none) and then total
381
+ silence. The v0.34.57 no-progress watchdog only arms while heartbeats
382
+ stay FRESH, so a stale heartbeat disarmed it, the worker's own stall
383
+ brake was the only other bound, and every doomed attempt burned its full
384
+ 30m wall while the goal sat "auditing" and the queue looked dead. The
385
+ poll loop now owns two complementary silence axes with the same
386
+ running-tool exemption: heartbeat-stale (had an event, went silent for
387
+ the window) and first-event-timeout (never emitted anything within
388
+ firstEventTimeoutMs, a new runtime knob defaulting to the same window).
389
+ Both demote the HUD to quiet, emit auditor_stalled, terminate the
390
+ worker, and return retryable "timeout" infra - which the existing
391
+ fallback ladder re-drives with its eager 5s first retry instead of the
392
+ wall.
393
+
394
+ ### Tests
395
+ tests/auditor-stall-watchdog.test.ts: three workers (silent since boot,
396
+ one-boot-heartbeat-then-silence, tool-open-silent) prove both axes fail
397
+ fast BEFORE the wall, classify as retryable infra, SIGTERM the worker,
398
+ and remove the job scratch; the third pins the running-tool exemption.
399
+ Red-proven against pre-change code: both stall runs burned the full
400
+ wall and never stalled. tests/auditor-process.test.ts heartbeat test
401
+ disarms the new axis (firstEventTimeoutMs) to isolate its own.
402
+ ## 0.35.48 — overdue-wait backstop respects the dispatch-surface gates (2026-08-23)
403
+
404
+ ### Fix
405
+ Audit-pass finding: overdueWaitBackstop mutated durable state (parked to
406
+ active, pauseResumeAt cleared) without checking the
407
+ extensionApiStale/sessionHandoffPending/stale-terminal or
408
+ mainModelRecoveryActive gates - during a latched-stale heartbeat a
409
+ durably parked wait could become an ACTIVE goal with no dispatch until a
410
+ fresh session_start, breaking the paused-is-safe invariant. The backstop
411
+ now refuses mid-handoff and stale-latched windows, and under an active
412
+ main-model recovery releases ONLY recovery-routed waits (the probe route
413
+ re-parks with a fresh resumeAt on failure) - unrelated agent-authored
414
+ waits stay parked until recovery resolves. The gates sit BEFORE the
415
+ lastOverdueWaitKey one-shot latch so skipped windows stay retriable.
416
+
417
+ ## 0.35.47 — completions/handler parity for /list and /loop verbs (2026-08-23)
418
+
419
+ ### Fix
420
+ Audit-pass finding: verbs handled by the dispatchers but absent from the
421
+ subcommand completions - /list add|import|rm (and pause, caught while
422
+ pinning), and /loop resume|refine|polish. All seven now appear in their
423
+ getArgumentCompletions tables with accurate descriptions. A generic
424
+ parity pin in tests/command-registration-collisions.test.ts scans every
425
+ `sub === "x"` dispatch literal inside cmdList/cmdLoop and fails when a
426
+ handled verb has no completion entry - future verbs cannot ship
427
+ half-registered.
428
+
429
+ ## 0.35.46 — /glla agents --tail sanitization + bounded scan reads (2026-08-23)
430
+
431
+ ### Fix
432
+ Audit-pass finding, two parts: (1) child-transcript tail lines were
433
+ rendered through ctx.ui.notify WITHOUT ANSI/control-character
434
+ sanitization - unlike every other external-text projection - so a
435
+ hostile child transcript could emit terminal escape sequences;
436
+ formatTranscriptEntry now runs all output paths (both [raw] fallbacks
437
+ and the [role] text path) through sanitizeDisplayText. (2) The candidate
438
+ scan synchronously read up to 25 FULL transcript files on the main
439
+ thread; the reader contract now takes an optional maxBytes and the
440
+ production command passes a real partial tail read (256 KiB window,
441
+ TRANSCRIPT_SCAN_MAX_BYTES), so the scan touches at most the last 256 KiB
442
+ of each candidate. The single matched file still gets a full read so the
443
+ "last N of M" detail stays honest.
444
+
445
+ ## 0.35.45 — plan-mode seeded hint separator (2026-08-23)
446
+
447
+ ### Fix
448
+ Audit-pass finding: planNote ended "...than a regular draft." and was
449
+ concatenated directly with the label hint, producing
450
+ "...regular draft.Goal drafting - deep planning: ..." in the notified
451
+ seeded hint. The join is now explicit (planNote ? `${planNote} ` : "").
452
+ Behavioral test drives the real /goal plan command with a seed and
453
+ asserts the notified hint reads "regular draft. Goal drafting - deep
454
+ planning:"; proven red with the glued concatenation restored.
455
+
456
+ ## 0.35.44 — draftingDepth dead state removed; orphaned-gate windows closed (2026-08-23)
457
+
458
+ ### Fix
459
+ Audit-pass finding, three parts: (1) the draftingDepth runtime global was
460
+ write-only dead state - set in startDrafting, reset in clearDraftingState,
461
+ zero readers (template selection uses the depth parameter) - removed
462
+ outright; "no target => normal depth" now holds by construction, so no
463
+ consumer can observe stale depth across proposal-completion paths.
464
+ (2) The two bare `draftingTarget = null` completion paths that skipped the
465
+ drafter-model restore (batch-activation conflict refusal, zombie-twin
466
+ rejection) now restore like every other exit. (3) beginDrafterModel moved
467
+ inside a try that clears the drafting gate on throw - a throw used to
468
+ leave the orphaned gate startDrafting's own header warns about.
469
+
470
+ ## 0.35.43 — refine re-baselines specChecked with the spec write (2026-08-23)
471
+
472
+ ### Fix
473
+ Audit-pass finding: refine's orchestrator-side spec write updated
474
+ specHash but not loop.specChecked, so the next tick saw checked >
475
+ specChecked against the OLD file's count and ledged spec_item_progress
476
+ attributed to the agent's iteration - unearned progress feeding the
477
+ multi-signal stuck gate (the user confirmed the respec; the agent may
478
+ have done nothing). The refine handler now re-baselines specChecked
479
+ together with specHash after writing the new spec.
480
+
481
+ ## 0.35.42 — measure-era scoping for loop movement accounting (2026-08-23)
482
+
483
+ ### Fix
484
+ Audit-pass finding: applyRefinement re-baselines best/last/stall on a
485
+ measure-changing refine but keeps history, so OLD-era improved entries
486
+ made both movement checks permanently true for the NEW metric era - the
487
+ v0.35.31 flat-reading grace could never apply after a measure-changing
488
+ refine, and a dead new metric could never earn its never-moved stop.
489
+ applyMeasurement now scopes metricHasMoved and metricNeverMoved to the
490
+ current measure era (history after the last measure-changing
491
+ refinement's iteration; the boundary was already recorded on every
492
+ LoopRefinement). Two twin tests proven red without the scoping, green
493
+ with it.
494
+
495
+ ## 0.35.41 — the last two loop-stop routes announce queue resumption (2026-08-23)
496
+
497
+ ### Fix
498
+ Audit-pass finding: v0.35.22's "ends by ANY route ... ANNOUNCE loudly"
499
+ contract was only wired into some stop routes. The stuck-ladder stop and
500
+ the provider-error/abort-cap stop notified the loop line but never
501
+ announced that waiting list items can start again - a dead silent entry.
502
+ Both routes now call announceQueuedListAfterLoopEnd (exported from
503
+ goal-loop.ts for the goal-activation site). Two twin behavioral tests
504
+ drive each production route against a seeded waiting queue; both proven
505
+ red with their call neutered, green restored.
506
+
507
+ ## 0.35.40 — regression pins for the audit-kind measurement exemption (2026-08-23)
508
+
509
+ ### Tests
510
+ Audit-pass finding: commit 28131527's audit-kind exemption in
511
+ applyMeasurement shipped with zero regression pin. Two twin-loop tests in
512
+ tests/loop-forever.test.ts now pin it: (1) identical flat-metric shapes
513
+ diverge by kind - the audit loop counts every flat toward plateau from
514
+ iteration 1 while the non-audit loop's pre-movement flats stay free;
515
+ (2) a dead metric gets the dedicated "metric never moved" stop on plain
516
+ loops but never on audit loops, whose final verdict stays plateau.
517
+ Red/green proven: deleting both halves of guard one fails both twins;
518
+ the never-moved kind-guard proved unreachable-by-construction for audits
519
+ (plateau always returns first) and is pinned in source instead.
520
+
521
+ ## 0.35.39 — README Files map is actually complete (2026-08-23)
522
+
523
+ ### Docs
524
+ Audit-pass finding: the Files map showed 4 of 7 prompts (missing both
525
+ plan-draft prompts shipped in v0.35.33 and goal-loop-forever-metricless)
526
+ and ~19 of 44 extensions files while reading as complete. The map now
527
+ enumerates every file - 34 extensions/ + 10 loops/ + 7 prompts/ + all
528
+ scripts/ - grouped by concern, with one-line descriptions verified
529
+ against each module's exports.
530
+
531
+ # 0.35.38 — README verb-semantics documentation (2026-08-23)
532
+
533
+ ### Docs
534
+ User-requested audit finding: what /goal|/list|/loop audit MEAN vs start
535
+ vs the plan verbs lived only in code comments. New "What the verbs mean"
536
+ table right after the quick-start block (audit is deliberately three
537
+ machines: one-shot fix-in-pass goal, collect-then-drain list item,
538
+ forever cadence loop; plan = extended draft on all surfaces; verify
539
+ audits the CURRENT goal, not the project), the drafting-rules paragraph
540
+ now names plan as the fourth depth, and "Which loop?" cross-links it.
541
+ Includes the DECIDED semantics: /list plan takes prose only — a file
542
+ path stays bulk import; files mentioned inside /list plan are research
543
+ input, never auto-imported.
544
+
545
+ ## 0.35.37 — recovery welcome-back notice now fires exactly once (2026-08-23)
546
+
547
+ ### Fix
548
+ Audit-pass finding: autoResumedAt/autoResumedEvent were set by three
549
+ auto-recovery sites (heartbeat overdue-wait backstop, main-model provider
550
+ recovery, auditor provider retry) but the ONLY clearing site was MANUAL
551
+ resume — so the continuation prompt injected the "WELCOME BACK, YOU WERE
552
+ RECOVERED" directive into EVERY dispatch of a goal that kept running days
553
+ after one recovery. The accepted-dispatch site in sendContinuation now
554
+ marks the notice delivered: the stamp clears and a
555
+ recovery_notice_delivered ledger entry records it, so the directive is
556
+ injected exactly once per auto-resume. Manual /goal resume keeps its own
557
+ clearing (user-driven, no notice needed).
558
+
559
+ ## 0.35.36 — complete_goal newObjective no longer launders agent text into userSeeds (2026-08-23)
560
+
561
+ ### Fix
562
+ Audit-pass finding: the newObjective branch appended the AGENT-authored
563
+ objective to objectiveProvenance.userSeeds; since createdVia stays "user"
564
+ from creation, the v0.35.31 seed trust then treated that agent-written
565
+ text as explicit user prose and dispatched it verbatim past the
566
+ suspicious-objective fence. userSeeds is now strictly human-confirmed
567
+ text (creation arg, /goal tweak Confirm dialog, repair-redraft task-list
568
+ confirm); a newObjective pivot is recorded via its goal_tweaked ledger
569
+ entry and reviewed by the isolated auditor against the NEW contract in
570
+ the same call. Regression test proves red-on-laundering /
571
+ green-on-fix; behavioral consequence observed: heuristic-tripping pivots
572
+ on user goals now flow through the normal fence (auto-restore from the
573
+ durable original) instead of being waved through.
574
+
575
+ ## 0.35.35 — user-seed trust works with contract clauses and role markers (2026-08-23)
576
+
577
+ ### Fix
578
+ Audit-pass finding: v0.35.31's seed trust compared the CLEANED
579
+ goal.objective against RAW stored seeds by exact equality — but createGoal
580
+ strips "Done when:" clauses and Agent:/Role: declarations out of the
581
+ objective while keeping the raw arg as the seed, so any seeded goal WITH a
582
+ clause/role silently no-op'd the trust and still parked behind the
583
+ suspicious-objective heuristic. New pure helper objectiveIsUserSeeded()
584
+ normalizes BOTH sides through the same extraction pipeline the creation
585
+ path applies; createdVia still gates WHO is trusted (agent-authored seeds
586
+ gain nothing). Regression tests: clause+role user seeds dispatch verbatim;
587
+ reviewer-created goals with matching-cleaned seeds never get the trust.
588
+
589
+ ### Mechanical pre-audit: maxBuffer ceiling killed verbose green suites (2026-08-23)
590
+
591
+ #### Fix
592
+ runMechanicalPreAuditChecks passed no maxBuffer to execFileSync, so
593
+ Node's default 1 MB cap applied: any contract gate whose output exceeds
594
+ 1 MB gets its child SIGTERMed by Node and the call throws ENOBUFS —
595
+ which the banner logic (signal==="SIGTERM") then misreported as "killed
596
+ after 600s". Field incident (2026-08-23, five consecutive auditor
597
+ rounds on hellhunter's `bun test src/lib/game`): the gate emits ~1.17 MB
598
+ of ALL-PASSING output and was unpassable by construction — every attempt
599
+ died at ~1 MB (~15s in) while the identical tree passed green from an
600
+ interactive shell 19/19 times, including piped-output and single-core
601
+ pinned runs. Now passes maxBuffer: 64 MB, and ENOBUFS deaths no longer
602
+ print the misleading 600s timeout banner.
603
+
604
+ ## 0.35.34 — lastOutcome actually durable (2026-08-23)
605
+
606
+ ### Fix
607
+ Audit-pass finding: v0.35.30's "durable" last-outcome record was never
608
+ serialized — persistStateLine omitted the field and readState never
609
+ restored it, so any restart/reload blanked the widget retention line
610
+ within its 24h window (the exact failure v0.35.30 fixed). Now always
611
+ written (null when absent — readState spreads successive state events, so
612
+ an omitted key would resurrect stale values and /glla wipe could never
613
+ clear the record) and restored through a strict shape sanitizer (corrupt
614
+ lines degrade to absent, never throw). Round-trip + corruption regression
615
+ tests added.
616
+
617
+ ## 0.35.33 — plan mode: the extended draft (2026-08-22)
618
+
619
+ ### Add
620
+ /goal plan | /list plan | /loop plan — the EXTENDED DRAFT for
621
+ greenfield/megaplan work where the standard 5–7-question interview is too
622
+ shallow (user design 2026-08-22). Research BEFORE questions (Explore
623
+ subagents, file reads), multi-round interviewing (architecture → scope →
624
+ failure conditions → verification), and a structured expanded objective:
625
+ current-state analysis, decisions with rationale, milestone breakdown,
626
+ per-milestone verification contract. Deliberately NOT a separate artifact —
627
+ the objective itself is the single truth (the respec lesson: a second
628
+ document always goes stale). Trust machinery unchanged: propose_*_draft +
629
+ the Confirm card still gate activation; regular drafts stay the fast path.
630
+ New prompts prompts/goal-loop-plan.md + goal-loop-plan-loop.md; depth flag
631
+ on the drafting session (runtime-global, reset by clearDraftingState);
632
+ completions on all three commands; /list plan gated as a mutating verb on
633
+ stale handles. respec stays untouched (kept by user decision).
634
+
3
635
  ## 0.35.32 — hermetic settings round-trip test (2026-08-22)
4
636
 
5
637
  ### Fix