pi-goal-list-loop-audit 0.31.4 → 0.31.6

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.
@@ -25,6 +25,12 @@ export interface Settings {
25
25
  * the verifier should differ from the executor. Unset = same model stands
26
26
  * (with a loud one-line nudge). */
27
27
  auditorModelFallback?: string;
28
+ /** v0.31.6: when the pinned auditor IS the session model, walk the
29
+ * fallback pin (verifier ≠ executor). Default ON (undefined); false =
30
+ * same-model audits stand — the isolated session + evidence contract is
31
+ * the first-order defense either way; diversity is the second-order one
32
+ * the user may deliberately trade away. */
33
+ auditorSameSessionSwap?: boolean;
28
34
  auditorThinkingLevel?: "off" | "minimal" | "low" | "medium" | "high" | "xhigh";
29
35
  /** Shell command run on goal complete / goal pause / loop stop; message passed as $1. */
30
36
  notifyCmd?: string;
@@ -1365,7 +1365,7 @@ async function retryStoredCompletionAudit(ctx: ExtensionContext, origin: "quota-
1365
1365
  ? "Manual /goal verify — running the isolated auditor now (no agent turn needed)."
1366
1366
  : "Auditor quota window elapsed — retrying the audit with your stored completion claim (no agent turn needed).", "info");
1367
1367
  const settings = loadSettings(liveCtx.cwd);
1368
- const { model: auditorModel, error: modelError, via } = resolveAuditorModel(liveCtx, settings.auditorModel, settings.auditorModelFallback);
1368
+ const { model: auditorModel, error: modelError, via } = resolveAuditorModel(liveCtx, settings.auditorModel, settings.auditorModelFallback, settings.auditorSameSessionSwap !== false);
1369
1369
  if (modelError) liveCtx.ui.notify(`Auditor model issue: ${modelError}`, "warning");
1370
1370
  latestAuditProgress = { label: "quota-retry", lastEventAt: Date.now() };
1371
1371
  completionAuditInFlight = true;
@@ -3173,7 +3173,7 @@ function registerAgentTools(pi: any, ctx: ExtensionContext): void {
3173
3173
  }
3174
3174
  updateGoal({ status: "auditing", pendingTasks: undefined }, ctx);
3175
3175
  const settings = loadSettings(ctx.cwd);
3176
- const { model: auditorModel, error: modelError, via } = resolveAuditorModel(ctx, settings.auditorModel, settings.auditorModelFallback);
3176
+ const { model: auditorModel, error: modelError, via } = resolveAuditorModel(ctx, settings.auditorModel, settings.auditorModelFallback, settings.auditorSameSessionSwap !== false);
3177
3177
  if (modelError) {
3178
3178
  ctx.ui.notify(`Auditor model issue: ${modelError}`, "warning");
3179
3179
  }
@@ -4229,7 +4229,7 @@ function registerAgentTools(pi: any, ctx: ExtensionContext): void {
4229
4229
  * bought; it lasted one version). Every hop is LOUD (ledger + notify): the
4230
4230
  * v0.9.12 no-SILENT-substitution law.
4231
4231
  */
4232
- function resolveAuditorModel(ctx: ExtensionContext, ref?: string, fallbackRef?: string): { model: any; error?: string; via?: string } {
4232
+ function resolveAuditorModel(ctx: ExtensionContext, ref?: string, fallbackRef?: string, sameSessionSwap = true): { model: any; error?: string; via?: string } {
4233
4233
  const sessionModel = ctx.model as any;
4234
4234
  const tryRef = (trimmed: string): { model?: any; reason?: string } => {
4235
4235
  const slash = trimmed.indexOf("/");
@@ -4257,14 +4257,14 @@ function resolveAuditorModel(ctx: ExtensionContext, ref?: string, fallbackRef?:
4257
4257
  ctx.ui.notify(`Auditor model "${pin}" is unavailable (${r.reason}) — ${i + 1 < pins.length ? "trying the fallback pin" : "falling back to the session model"}. Fix via /glla → Auditor model.`, "warning");
4258
4258
  continue;
4259
4259
  }
4260
- if (isSession(r.model) && i + 1 < pins.length) {
4260
+ if (sameSessionSwap && isSession(r.model) && i + 1 < pins.length) {
4261
4261
  // The pin IS the session model — the verifier would be the executor's
4262
4262
  // own model; auto-swap down the chain (the user's move).
4263
4263
  appendLedger(ctx.cwd, "auditor_model_same_as_session", { model: `${r.model.provider}/${r.model.id}`, fallback: pins[i + 1] });
4264
4264
  ctx.ui.notify(`Session model IS the pinned auditor (${r.model.provider}/${r.model.id}) — auditor auto-swapped to ${pins[i + 1]} so the verifier differs.`, "info");
4265
4265
  continue;
4266
4266
  }
4267
- if (isSession(r.model) && !fallbackRef?.trim()) {
4267
+ if (sameSessionSwap && isSession(r.model) && !fallbackRef?.trim()) {
4268
4268
  // Last resort reached and it IS the session model, with no fallback
4269
4269
  // ever pinned — the model stands (the session IS the last resort);
4270
4270
  // one loud nudge so the user can wire the swap.
@@ -4455,6 +4455,14 @@ export async function handleSettingChoice(id: string, ctx: ExtensionContext): Pr
4455
4455
  if (pick.kind === "session") ctx.ui.notify("Auditor fallback cleared — a session on the pinned auditor model keeps that model.", "info");
4456
4456
  return;
4457
4457
  }
4458
+ case "auditorSameSessionSwap": {
4459
+ const v = await ctx.ui.select("Same-model swap — when the pinned auditor IS the session model, walk the fallback pin", [
4460
+ "on — the verifier differs from the executor (default; a same-family model shares the executor's blind spots)",
4461
+ "off — same-model audits stand (you accept the executor's model as its own verifier; isolation + evidence contract still apply)",
4462
+ ]);
4463
+ if (v) saveSettings("global", ctx.cwd, { auditorSameSessionSwap: v.startsWith("off") ? false : undefined });
4464
+ return;
4465
+ }
4458
4466
  case "auditCap": {
4459
4467
  const v = await ctx.ui.input("Consecutive auditor disapprovals before the goal pauses", "non-negative integer; 0 = unlimited, empty = default 5");
4460
4468
  if (v !== undefined) {
@@ -173,9 +173,17 @@ export function buildSettingsRows(
173
173
  id: "auditorModelFallback",
174
174
  section: "auditor",
175
175
  label: "Auditor fallback model",
176
- valueText: show("auditorModelFallback", "none"),
176
+ valueText: show("auditorModelFallback", "session model (last resort)"),
177
177
  sourceText: src("auditorModelFallback"),
178
- description: "auto-swap target when the session model IS the auditor model the verifier should differ from the executor",
178
+ description: "walked when the primary is unavailable OR IS the session model (the verifier should differ) unset = the session model is the last resort",
179
+ },
180
+ {
181
+ id: "auditorSameSessionSwap",
182
+ section: "auditor",
183
+ label: "Same-model swap",
184
+ valueText: show("auditorSameSessionSwap", "on"),
185
+ sourceText: src("auditorSameSessionSwap"),
186
+ description: "when the pinned auditor IS the session model, walk the fallback pin (verifier ≠ executor) — off = same-model audits stand",
179
187
  },
180
188
  {
181
189
  id: "auditCap",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-goal-list-loop-audit",
3
- "version": "0.31.4",
3
+ "version": "0.31.6",
4
4
  "description": "Goal. Loop. Audit. Done. \u2014 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 \u2014 only the read tools needed to verify your goal.",
5
5
  "license": "MIT",
6
6
  "author": "dracon",