pi-goal-list-loop-audit 0.25.4 โ†’ 0.25.5

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.
@@ -1090,6 +1090,10 @@ export interface AuditLogEntry {
1090
1090
  report: string;
1091
1091
  impossibleReason?: string;
1092
1092
  error?: string;
1093
+ /** v0.25.4 post-audit: how long the audit took, and whether the infra
1094
+ * retry fired. */
1095
+ durationMs?: number;
1096
+ retriedOnce?: boolean;
1093
1097
  }
1094
1098
 
1095
1099
  export function auditLogPath(cwd: string): string {
@@ -1145,3 +1149,55 @@ export function formatAuditLog(entries: AuditLogEntry[]): string {
1145
1149
  })
1146
1150
  .join("\n");
1147
1151
  }
1152
+
1153
+ // =================================================================
1154
+ // v0.25.4 (post-audit fix): infra-failure retry-once-with-backoff
1155
+ // =================================================================
1156
+
1157
+ /** Which auditor infra errors are worth an automatic retry? User aborts
1158
+ * and missing-model config are NOT โ€” retrying can't help them. */
1159
+ export function isRetriableInfraError(error?: string): boolean {
1160
+ if (!error) return false;
1161
+ if (/aborted/i.test(error)) return false;
1162
+ if (/no model/i.test(error)) return false;
1163
+ return true;
1164
+ }
1165
+
1166
+ export interface InfraRetryOutcome<T> {
1167
+ result: T;
1168
+ retriedOnce: boolean;
1169
+ }
1170
+
1171
+ /** Run the auditor; on a retriable infra failure, wait `backoffMs` and
1172
+ * retry EXACTLY once before reporting "auditor infrastructure error
1173
+ * (retried once)". The failed pair is never a verdict on the work. */
1174
+ export async function runWithInfraRetry<T extends { error?: string; approved: boolean; disapproved: boolean }>(
1175
+ run: () => Promise<T>,
1176
+ opts: { backoffMs?: number; sleep?: (ms: number) => Promise<void>; onRetry?: (error: string) => void } = {},
1177
+ ): Promise<InfraRetryOutcome<T>> {
1178
+ const sleep = opts.sleep ?? ((ms: number) => new Promise<void>((r) => setTimeout(r, ms)));
1179
+ const first = await run();
1180
+ if (first.approved || first.disapproved || !isRetriableInfraError(first.error)) {
1181
+ return { result: first, retriedOnce: false };
1182
+ }
1183
+ opts.onRetry?.(first.error!);
1184
+ await sleep(opts.backoffMs ?? 5000);
1185
+ const second = await run();
1186
+ return { result: second, retriedOnce: true };
1187
+ }
1188
+
1189
+ /** /glla audits default view: the ACTIVE goal's own audit history (the
1190
+ * surface the goal spec asked for), one line per verdict. */
1191
+ export function formatGoalAuditHistory(goal: { id: string; auditHistory?: Array<any> }): string {
1192
+ const history = goal.auditHistory ?? [];
1193
+ if (history.length === 0) return "(no audits on this goal yet)";
1194
+ return history
1195
+ .map((v) => {
1196
+ const glyph = v.approved ? (v.regressionShieldPassed === false ? "๐Ÿ›ก" : "โœ”") : v.impossible ? "โ›”" : v.disapproved ? "โœ–" : "โš ";
1197
+ const day = String(v.at ?? "").slice(5, 16).replace("T", " ");
1198
+ const elapsed = v.durationMs ? ` ยท ${Math.round(v.durationMs / 60000)}m` : "";
1199
+ const firstLine = (String(v.report ?? "").split("\n").find((l: string) => l.trim()) ?? "").trim().slice(0, 80);
1200
+ return `${glyph} ${day} ${v.model ?? "?"}${elapsed} โ€” ${firstLine}`;
1201
+ })
1202
+ .join("\n");
1203
+ }
@@ -42,6 +42,8 @@ import {
42
42
  appendAuditLog,
43
43
  computeListDepth,
44
44
  formatAuditLog,
45
+ formatGoalAuditHistory,
46
+ runWithInfraRetry,
45
47
  readAuditLog,
46
48
  stripThinkBlocks,
47
49
  type AuditLogEntry,
@@ -1703,24 +1705,38 @@ function registerAgentTools(pi: any, ctx: ExtensionContext): void {
1703
1705
  // Esc during the audit aborts this tool's signal โ†’ threaded into the
1704
1706
  // auditor session, which aborts cleanly and returns "Auditor aborted."
1705
1707
  latestAuditProgress = { label: "starting", lastEventAt: Date.now() };
1706
- const result = await runGoalCompletionAuditor({
1707
- ctx,
1708
- goal: state.goal,
1709
- completionSummary: p.completionSummary,
1710
- verificationSummary: p.verificationSummary,
1711
- model: auditorModel,
1712
- thinkingLevel: settings.auditorThinkingLevel ?? getSessionThinkingLevel(),
1713
- signal: signal ?? undefined,
1714
- onProgress: (progress) => {
1715
- latestAuditProgress = {
1716
- currentTool: progress.currentTool,
1717
- label: progress.label,
1718
- elapsedMs: progress.elapsedMs,
1719
- lastEventAt: Date.now(),
1720
- };
1708
+ const runAudit = () =>
1709
+ runGoalCompletionAuditor({
1710
+ ctx,
1711
+ goal: state.goal!,
1712
+ completionSummary: p.completionSummary,
1713
+ verificationSummary: p.verificationSummary,
1714
+ model: auditorModel,
1715
+ thinkingLevel: settings.auditorThinkingLevel ?? getSessionThinkingLevel(),
1716
+ signal: signal ?? undefined,
1717
+ onProgress: (progress) => {
1718
+ latestAuditProgress = {
1719
+ currentTool: progress.currentTool,
1720
+ label: progress.label,
1721
+ elapsedMs: progress.elapsedMs,
1722
+ lastEventAt: Date.now(),
1723
+ };
1724
+ refreshUI(ctx);
1725
+ },
1726
+ });
1727
+ // v0.25.4 (post-audit fix): a retriable infra failure (stream error,
1728
+ // auth blip โ€” NOT user abort, NOT missing model) gets ONE automatic
1729
+ // retry with backoff before we report "auditor infrastructure error
1730
+ // (retried once)". Neither attempt is a verdict on the work.
1731
+ const auditStartMs = Date.now();
1732
+ const { result, retriedOnce } = await runWithInfraRetry(runAudit, {
1733
+ onRetry: (err) => {
1734
+ latestAuditProgress = { label: `infra error (${err.slice(0, 40)}) โ€” retrying once`, lastEventAt: Date.now() };
1721
1735
  refreshUI(ctx);
1736
+ appendLedger(ctx.cwd, "audit_infra_retry", { goalId: state.goal?.id, error: err.slice(0, 200) });
1722
1737
  },
1723
1738
  });
1739
+ const auditDurationMs = Date.now() - auditStartMs;
1724
1740
  latestAuditProgress = null;
1725
1741
  // Audit history: record REAL verdicts only โ€” a non-empty report is the
1726
1742
  // evidence the auditor actually inspected something. Empty-report runs
@@ -1746,7 +1762,8 @@ function registerAgentTools(pi: any, ctx: ExtensionContext): void {
1746
1762
  error: result.error,
1747
1763
  regressionShieldPassed: result.regressionShieldPassed,
1748
1764
  regressionShieldMissing: result.regressionShieldMissing,
1749
- });
1765
+ durationMs: auditDurationMs,
1766
+ } as any);
1750
1767
  // Cap history โ€” 39 infra errors taught us unbounded growth is real.
1751
1768
  if (history.length > 20) history.splice(0, history.length - 20);
1752
1769
  // v0.25.4: durable append-only audit log โ€” survives state-snapshot
@@ -1771,7 +1788,9 @@ function registerAgentTools(pi: any, ctx: ExtensionContext): void {
1771
1788
  report: cleanOutput,
1772
1789
  impossibleReason: result.impossibleReason,
1773
1790
  error: result.error,
1774
- });
1791
+ durationMs: auditDurationMs,
1792
+ retriedOnce,
1793
+ } as AuditLogEntry);
1775
1794
  }
1776
1795
 
1777
1796
  // Escape hatch: the user aborted the audit (Esc). Offer the explicit
@@ -1897,14 +1916,14 @@ function registerAgentTools(pi: any, ctx: ExtensionContext): void {
1897
1916
  updateGoal({
1898
1917
  status: "active",
1899
1918
  auditHistory: history,
1900
- pauseReason: `auditor infrastructure: ${result.error}`,
1919
+ pauseReason: `auditor infrastructure${retriedOnce ? " (retried once)" : ""}: ${result.error}`,
1901
1920
  pauseSuggestedAction: "Fix the auditor model (/glla model=provider/id) and call complete_goal again โ€” your work was NOT judged",
1902
1921
  }, ctx);
1903
1922
  scheduleContinuation(ctx, true);
1904
1923
  return {
1905
1924
  content: [{
1906
1925
  type: "text",
1907
- text: `The auditor could not run (infrastructure, NOT a verdict): ${result.error}\nYour completion claim was not evaluated. Fix the auditor model with /glla model=provider/id and call complete_goal again โ€” do not change your deliverable for this.`,
1926
+ text: `The auditor could not run (infrastructure, NOT a verdict${retriedOnce ? "; retried once with backoff, both attempts failed" : ""}): ${result.error}\nYour completion claim was not evaluated. Fix the auditor model with /glla model=provider/id and call complete_goal again โ€” do not change your deliverable for this.`,
1908
1927
  }],
1909
1928
  details: {},
1910
1929
  };
@@ -2785,12 +2804,28 @@ function cmdStats(args: string, ctx: ExtensionContext): void {
2785
2804
  */
2786
2805
  function cmdAudits(args: string, ctx: ExtensionContext): void {
2787
2806
  const full = /\bfull\b/.test(args);
2807
+ const all = /\b(?:all|global|log)\b/.test(args);
2788
2808
  const nMatch = args.match(/\b(\d+)\b/);
2789
2809
  if (full) {
2810
+ // Latest report โ€” active goal's history first, then the log.
2811
+ const fromGoal = state.goal?.auditHistory?.at(-1);
2812
+ if (fromGoal?.report) {
2813
+ ctx.ui.notify(`Latest audit on this goal โ€” ${fromGoal.model} (${fromGoal.at})\n${fromGoal.report}`, "info");
2814
+ return;
2815
+ }
2790
2816
  const latest = readAuditLog(ctx.cwd).at(-1);
2791
2817
  ctx.ui.notify(latest ? `Latest audit โ€” ${latest.verdict} (${latest.model}, ${latest.at})\n${latest.report}` : "No audits logged yet.", "info");
2792
2818
  return;
2793
2819
  }
2820
+ // Default: the ACTIVE goal's own audit history (with per-audit elapsed);
2821
+ // "all"/"global"/"log" browses the durable cross-goal log.
2822
+ if (!all && state.goal?.auditHistory && state.goal.auditHistory.length > 0) {
2823
+ ctx.ui.notify(
2824
+ `glla audits โ€” this goal's history (${state.goal.auditHistory.length} verdict(s); /glla audits all for the project log)\n${formatGoalAuditHistory(state.goal)}`,
2825
+ "info",
2826
+ );
2827
+ return;
2828
+ }
2794
2829
  const n = nMatch ? Number(nMatch[1]) : 10;
2795
2830
  const entries = readAuditLog(ctx.cwd, n);
2796
2831
  ctx.ui.notify(`glla audits โ€” last ${entries.length} verdict(s) in ${ctx.cwd}\n${formatAuditLog(entries)}`, "info");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-goal-list-loop-audit",
3
- "version": "0.25.4",
3
+ "version": "0.25.5",
4
4
  "description": "Goal. Loop. Audit. Done. โ€” a pi-coding-agent extension that supervises long-running work, with isolated auditor on each completion. Beat bamboozling by design: the auditor runs in a fresh session with no extensions, no skills, no editor โ€” only the read tools needed to verify your goal.",
5
5
  "license": "MIT",
6
6
  "author": "dracon",