pi-goal-list-loop-audit 0.38.36 → 0.38.38
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.
- package/CHANGELOG.md +25 -0
- package/docs/INDEX.md +1 -1
- package/extensions/completion-summary.ts +15 -3
- package/extensions/goal-loop-core.ts +6 -0
- package/extensions/goal-loop-display.ts +8 -6
- package/extensions/loops/goal-auditor-hooks.ts +2 -0
- package/extensions/loops/goal-tools.ts +19 -1
- package/package.json +1 -1
- package/prompts/goal-loop-continuation.md +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,30 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.38.38 — elapsed-time duplication cut + PR #47 closed (2026-09-09)
|
|
4
|
+
|
|
5
|
+
### Fixed
|
|
6
|
+
|
|
7
|
+
- **Elapsed time in two places (field 20260909_002132):** the `setStatus` one-liner no longer carries `total …` on the idle/busy/working branches — other sessions' tab strips showed `glla: [WORKING] total …` under a card already reading it. The card head keeps the timer unconditionally; state + task/queue counts stay on the status line. (`Chrome Bridge`/`(indefinite)` framing is pi core, not GLLA — only our timer text was cut.)
|
|
8
|
+
- **PR #47 triage:** KV-cache checkpoint complaint verified real on main but the strip shape is unsafe as-is (post-compaction blindness, no compensating pointer) — replied per-piece, gave the contributor a merge-based re-sync command, closed without merging per the #45/#46 precedent (live `active.jsonl`, 39-behind divergence, bundled features). Per-task audits stay held pending cost review.
|
|
9
|
+
|
|
10
|
+
### Verification
|
|
11
|
+
|
|
12
|
+
- New pins: status-without-timer + card-keeps-timer; full `release:check` 0 failures; `tsc --noEmit` clean.
|
|
13
|
+
- Evidence: `audit/ELAPSED-DUPLICATION-PR47-2026-09-09.md`. No open PRs.
|
|
14
|
+
|
|
15
|
+
## 0.38.37 — bullets + deliberate non-do (2026-09-09)
|
|
16
|
+
|
|
17
|
+
### Fixed
|
|
18
|
+
|
|
19
|
+
- **Auditor disapproval of v0.38.36 answered:** the posted summary now carries one `•` bullet per informing detail on both posted surfaces (chat + transcript); new optional `complete_goal` `leftOut` parameter renders as the closing `• Left out:` bullet on all three approval sites (fresh, detached-retry, Esc-anyway). Absent stays absent — never invented, filler drops. Recap/archive format unchanged.
|
|
20
|
+
- **Stale pins updated deliberately:** approval-chat `deepEqual` expectations now bullet-prefixed.
|
|
21
|
+
|
|
22
|
+
### Verification
|
|
23
|
+
|
|
24
|
+
- New pins: bullet count/evidence + present/absent/filler non-do (render unit), end-to-end `leftOut` claim → posted bullet (MockPi).
|
|
25
|
+
- Full `release:check`: 2040 pass / 2 skip / 0 fail across 204 files (`/var/tmp/glla-bullets-release-check2.log`, tarball `pi-goal-list-loop-audit-0.38.37.tgz`); `tsc --noEmit` clean.
|
|
26
|
+
- Evidence: `audit/HUMAN-VOICE-SUMMARY-2026-09-08.md`.
|
|
27
|
+
|
|
3
28
|
## 0.38.36 — human-voice terminal summaries (2026-09-08)
|
|
4
29
|
|
|
5
30
|
### Fixed
|
package/docs/INDEX.md
CHANGED
|
@@ -18,7 +18,7 @@ For shipped docs, the relevant entry points are:
|
|
|
18
18
|
failback; v0.35.9 hardened cross-version npm tarball checks; v0.35.10
|
|
19
19
|
handles multi-entry npm dry-run reports; v0.35.11 accepts both npm report
|
|
20
20
|
shapes; v0.35.12 supports npm 12's keyed pack reports; v0.35.13 fixes stale-API recovery loops.
|
|
21
|
-
v0.35.14–v0.38.
|
|
21
|
+
v0.35.14–v0.38.38 continue through the supervisor freeze (`/glla pause`),
|
|
22
22
|
load hold, auditor picker parity, Windows launch fix, zombie-watchdog
|
|
23
23
|
subagent carve-out, due-wait backstop, the `/glla agents` visibility panel,
|
|
24
24
|
durable state-root selection, blank-until-resume auditor context, frozen
|
|
@@ -200,7 +200,9 @@ export function buildApprovalChatLines(notice: {
|
|
|
200
200
|
}): string[] {
|
|
201
201
|
return [
|
|
202
202
|
`✓ done — ${notice.outcome}`,
|
|
203
|
-
|
|
203
|
+
// v0.38.37 (audit 2026-09-08): one verifiable-result bullet per
|
|
204
|
+
// informing detail — the Codex closing shape.
|
|
205
|
+
...withoutStaleNext(notice.details).map((detail) => `• ${detail}`),
|
|
204
206
|
notice.approval,
|
|
205
207
|
...(notice.counts ? [notice.counts] : []),
|
|
206
208
|
notice.record,
|
|
@@ -240,6 +242,8 @@ export interface TerminalApprovalRenderInput {
|
|
|
240
242
|
countsLine?: string;
|
|
241
243
|
/** Override for the audit half of the counts line. */
|
|
242
244
|
auditNote?: string;
|
|
245
|
+
/** v0.38.37: what the agent deliberately left out (complete_goal leftOut). */
|
|
246
|
+
leftOut?: string;
|
|
243
247
|
}
|
|
244
248
|
|
|
245
249
|
export interface TerminalApprovalRender {
|
|
@@ -271,7 +275,15 @@ export function buildTerminalApprovalRender(input: TerminalApprovalRenderInput):
|
|
|
271
275
|
};
|
|
272
276
|
const candidate = input.completionSummary ?? input.goal.completionSummary;
|
|
273
277
|
const recap = compactTerminalCompletionSummary(facts, candidate);
|
|
274
|
-
const
|
|
278
|
+
const baseBrief = terminalHumanBrief(facts, candidate);
|
|
279
|
+
// v0.38.37 (audit 2026-09-08): the deliberate non-do comes from the
|
|
280
|
+
// agent's complete_goal leftOut claim — never invented. Filler ("none")
|
|
281
|
+
// drops via the same briefValueContent filter; absent stays absent.
|
|
282
|
+
const leftOut = input.leftOut?.trim();
|
|
283
|
+
const leftOutContent = leftOut ? briefValueContent(leftOut) : null;
|
|
284
|
+
const brief = leftOutContent
|
|
285
|
+
? { ...baseBrief, details: [...baseBrief.details, `Left out: ${clipSummaryValue(leftOutContent, 120)}`] }
|
|
286
|
+
: baseBrief;
|
|
275
287
|
const countsLine = input.countsLine ?? buildAuditCountsLine(input.goal, input.auditNote);
|
|
276
288
|
return {
|
|
277
289
|
chatLines: [
|
|
@@ -285,7 +297,7 @@ export function buildTerminalApprovalRender(input: TerminalApprovalRenderInput):
|
|
|
285
297
|
...(input.extras ?? []),
|
|
286
298
|
],
|
|
287
299
|
recap,
|
|
288
|
-
transcriptLines: [...withoutStaleNext(brief.details), input.approval],
|
|
300
|
+
transcriptLines: [...withoutStaleNext(brief.details).map((detail) => `• ${detail}`), input.approval],
|
|
289
301
|
countsLine,
|
|
290
302
|
outcome: brief.outcome,
|
|
291
303
|
approval: input.approval,
|
|
@@ -280,6 +280,12 @@ export interface PendingCompletion {
|
|
|
280
280
|
recoveryEpisodeKey?: string;
|
|
281
281
|
/** Durable per-episode notice fence; display projections must consult it. */
|
|
282
282
|
recoveryNoticeKeys?: string[];
|
|
283
|
+
/**
|
|
284
|
+
* v0.38.37: what the agent deliberately left out of this turn's work
|
|
285
|
+
* (complete_goal leftOut). Renders as the closing non-do bullet in the
|
|
286
|
+
* terminal user summary; absent means nothing was deliberately left out.
|
|
287
|
+
*/
|
|
288
|
+
leftOut?: string;
|
|
283
289
|
/**
|
|
284
290
|
* Durable one-shot recovery fence. A parked claim may receive one
|
|
285
291
|
* automatic retry after a validated healthy lifecycle/recovery event;
|
|
@@ -1323,8 +1323,11 @@ function buildStatusTextBase(state: State, audit?: AuditDisplayProgress | null,
|
|
|
1323
1323
|
// state + counts only. Freshness tails (`last host activity`,
|
|
1324
1324
|
// `last stream`) duplicated the card-head `stream {age}` readout —
|
|
1325
1325
|
// one surface owns liveness so the two can never disagree.
|
|
1326
|
+
// v0.38.38 (field 20260909_002132): the elapsed `total …` duplicated
|
|
1327
|
+
// the card head too (other sessions' tab strips showed
|
|
1328
|
+
// `glla: [WORKING] total …` under a card already reading it) — the
|
|
1329
|
+
// card owns the timer now; the status line keeps state + counts.
|
|
1326
1330
|
const idleDetails = [
|
|
1327
|
-
goalTotalText(g, now),
|
|
1328
1331
|
(state.list?.length ?? 0) > 0 ? `${state.list!.length} queued` : "",
|
|
1329
1332
|
].filter(Boolean);
|
|
1330
1333
|
return `glla: ${activityStateBadge("IDLE", theme, "warning")}${idleDetails.length > 0 ? ` ${idleDetails.join(" · ")}` : ""}${heldSuffix}`;
|
|
@@ -1335,7 +1338,6 @@ function buildStatusTextBase(state: State, audit?: AuditDisplayProgress | null,
|
|
|
1335
1338
|
// like progress. Queued work is neither idle nor currently executing.
|
|
1336
1339
|
if (activity === "busy") {
|
|
1337
1340
|
const busyDetails = [
|
|
1338
|
-
goalTotalText(g, now),
|
|
1339
1341
|
g.taskList ? `${countDone(g)}/${countTotal(g)} tasks` : "",
|
|
1340
1342
|
(state.list?.length ?? 0) > 0 ? `${state.list!.length} queued` : "",
|
|
1341
1343
|
].filter(Boolean);
|
|
@@ -1370,11 +1372,11 @@ function buildStatusTextBase(state: State, audit?: AuditDisplayProgress | null,
|
|
|
1370
1372
|
const recovery = state.mainModelRecovery;
|
|
1371
1373
|
const blockedByRecovery = queued && recovery && recovery.retryAt;
|
|
1372
1374
|
const recoverySuffix = blockedByRecovery ? ` · parked on provider recovery` : "";
|
|
1373
|
-
// Keep the screenshot-proven order: state,
|
|
1374
|
-
//
|
|
1375
|
-
//
|
|
1375
|
+
// Keep the screenshot-proven order: state, then queue/task context.
|
|
1376
|
+
// It scans like a compact instrument readout and remains useful when
|
|
1377
|
+
// the above-editor card is hidden or scrolled away. Elapsed `total …`
|
|
1378
|
+
// lives on the card head only (v0.38.38, field 20260909_002132).
|
|
1376
1379
|
const details = [
|
|
1377
|
-
goalTotalText(g, now),
|
|
1378
1380
|
g.taskList ? `${countDone(g)}/${countTotal(g)} tasks` : "",
|
|
1379
1381
|
// v0.34.124: the QUEUED "why" — an accepted dispatch that pi has not
|
|
1380
1382
|
// started. (The last-activity age that used to ride here moved to the
|
|
@@ -1439,6 +1439,8 @@ async function retryStoredCompletionAudit(origin: CompletionAuditOrigin = "provi
|
|
|
1439
1439
|
completionSummary: state.goal.completionSummary,
|
|
1440
1440
|
approval: `— auditor ${result.model} approved${approvalVia}.`,
|
|
1441
1441
|
record: approvalRecord,
|
|
1442
|
+
// v0.38.37: the deliberate non-do the agent claimed, if any.
|
|
1443
|
+
...(claim.leftOut ? { leftOut: claim.leftOut } : {}),
|
|
1442
1444
|
extras: inspectionSessionPath
|
|
1443
1445
|
? [`Auditor session kept for review: pi --session ${inspectionSessionPath} (or pi --fork ${inspectionSessionPath}).`]
|
|
1444
1446
|
: [],
|
|
@@ -519,6 +519,13 @@ function registerAgentTools(pi: any): void {
|
|
|
519
519
|
"and cross-checks the verification claim against real artifacts (see audit/COMPLETION-SUMMARY-POLICY-2026-08-19.md).",
|
|
520
520
|
})),
|
|
521
521
|
newObjective: Type.Optional(Type.String({ description: "v0.25.0 (contract item 15): when the work has legitimately shifted, pass the new objective here — it atomically replaces the goal objective AND the audit proceeds against the NEW objective in this same call. Do not use to dodge a legitimate disapproval; the auditor sees the change." })),
|
|
522
|
+
leftOut: Type.Optional(Type.String({
|
|
523
|
+
maxLength: 500,
|
|
524
|
+
description:
|
|
525
|
+
"v0.38.37: what this turn deliberately left out (scope cut, deferred item + why, in plain words). " +
|
|
526
|
+
"Renders as the closing `• Left out:` bullet in the user-facing terminal summary. " +
|
|
527
|
+
"Omit when nothing was deliberately left out — absent stays absent, never invented.",
|
|
528
|
+
})),
|
|
522
529
|
}),
|
|
523
530
|
async execute(_id, params, signal, _onUpdate, execCtx) {
|
|
524
531
|
const foreign0 = foreignToolGuard(execCtx);
|
|
@@ -542,7 +549,7 @@ function registerAgentTools(pi: any): void {
|
|
|
542
549
|
}
|
|
543
550
|
return { content: [{ type: "text", text: `No active goal — it is ${state.goal.status}.` }], details: {} };
|
|
544
551
|
}
|
|
545
|
-
const p = params as { completionSummary?: string; verificationSummary?: string; newObjective?: string };
|
|
552
|
+
const p = params as { completionSummary?: string; verificationSummary?: string; newObjective?: string; leftOut?: string };
|
|
546
553
|
if (state.goal.repairTarget) {
|
|
547
554
|
return {
|
|
548
555
|
content: [{ type: "text", text: `This repair card cannot be completed yet. Redraft the original target as a confirmed task list with propose_task_list (include objective: ${state.goal.repairTarget.objective.slice(0, 180)}), then continue the real work.` }],
|
|
@@ -742,6 +749,9 @@ function registerAgentTools(pi: any): void {
|
|
|
742
749
|
const completionClaim = beginCompletionAudit(ctx, {
|
|
743
750
|
completionSummary: finalSummary,
|
|
744
751
|
verificationSummary: p.verificationSummary,
|
|
752
|
+
// v0.38.37: the deliberate non-do rides the pending claim into
|
|
753
|
+
// the terminal render — the only source the summary may cite.
|
|
754
|
+
...(p.leftOut?.trim() ? { leftOut: p.leftOut.trim().slice(0, 500) } : {}),
|
|
745
755
|
at: nowIso(),
|
|
746
756
|
}, "complete-goal");
|
|
747
757
|
if (!completionClaim) {
|
|
@@ -1194,6 +1204,9 @@ function registerAgentTools(pi: any): void {
|
|
|
1194
1204
|
// Escape hatch: the user aborted the audit (Esc). Offer the explicit
|
|
1195
1205
|
// choice — complete WITHOUT audit, or keep working. (pi-goal-x parity.)
|
|
1196
1206
|
if (result.error === "Auditor aborted.") {
|
|
1207
|
+
// v0.38.37: capture the agent-claimed non-do before the claim is
|
|
1208
|
+
// cleared below — the Esc-complete path renders the same voice.
|
|
1209
|
+
const escLeftOut = state.goal.pendingCompletion?.leftOut;
|
|
1197
1210
|
updateGoal({ status: "active", auditHistory: history, pendingCompletion: undefined, pauseReason: "audit aborted by user (Esc)" }, ctx);
|
|
1198
1211
|
const abortConfirmCtx = freshCtxForGeneration(auditGeneration);
|
|
1199
1212
|
if (!abortConfirmCtx) return staleToolResult();
|
|
@@ -1232,6 +1245,9 @@ function registerAgentTools(pi: any): void {
|
|
|
1232
1245
|
approval: `— completed without audit (your choice).`,
|
|
1233
1246
|
record: `— record: ${escArchivePath}`,
|
|
1234
1247
|
auditNote: "completed without audit (your choice)",
|
|
1248
|
+
// v0.38.37: the claim was cleared pre-confirm; the non-do was
|
|
1249
|
+
// captured from it above.
|
|
1250
|
+
...(escLeftOut ? { leftOut: escLeftOut } : {}),
|
|
1235
1251
|
});
|
|
1236
1252
|
if (!archiveCurrentGoal(ctx, "complete", terminalReason)) {
|
|
1237
1253
|
return {
|
|
@@ -1286,6 +1302,8 @@ function registerAgentTools(pi: any): void {
|
|
|
1286
1302
|
completionSummary: state.goal.completionSummary,
|
|
1287
1303
|
approval: `— auditor ${result.model} approved.`,
|
|
1288
1304
|
record: manualArchiveRecord,
|
|
1305
|
+
// v0.38.37: the deliberate non-do rides the durable claim.
|
|
1306
|
+
...(durableCompletionClaim.leftOut ? { leftOut: durableCompletionClaim.leftOut } : {}),
|
|
1289
1307
|
extras: inspectionSessionPath
|
|
1290
1308
|
? [`Auditor session kept for review: pi --session ${inspectionSessionPath} (or pi --fork ${inspectionSessionPath}).`]
|
|
1291
1309
|
: [],
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-goal-list-loop-audit",
|
|
3
|
-
"version": "0.38.
|
|
3
|
+
"version": "0.38.38",
|
|
4
4
|
"description": "Mission control for autonomous pi: interview-drafted goals, an audited task queue, and forever-loops (metric, spec, project-audit) that run for hours. A detached extension-less auditor process re-verifies every completion with raw evidence without holding the main pi turn; confirmed drafts, decision pauses and consent gates keep you in charge.",
|
|
5
5
|
"license": "AGPL-3.0-only",
|
|
6
6
|
"author": "dracon",
|
|
@@ -197,4 +197,4 @@ The orchestrator's backstop is the stall watchdog: three consecutive turns with
|
|
|
197
197
|
|
|
198
198
|
`complete_goal` submits a nonterminal claim, not a completion verdict. While the detached audit is pending, do not say the goal is done/complete/approved or present a final success summary. Do not wait or poll. If a response is needed, give one brief pending-status sentence. GLLA posts the concrete outcome-first summary into chat after verified approval and durable archive, without needing another user prompt. Do not duplicate that summary. A rejected claim remains unfinished and repair work continues.
|
|
199
199
|
|
|
200
|
-
The agent-written completionSummary is user-facing evidence, not a step log: open with the outcome in plain words, then one verifiable result per label with its proof inline (test counts, file paths, commit refs) — never raw run stats. Cut values at clause boundaries, never mid-word;
|
|
200
|
+
The agent-written completionSummary is user-facing evidence, not a step log: open with the outcome in plain words, then one verifiable result per label with its proof inline (test counts, file paths, commit refs) — never raw run stats. Cut values at clause boundaries, never mid-word; pass what was deliberately left out as the complete_goal leftOut parameter — it renders as the closing bullet, and is omitted when absent.
|