pi-goal-list-loop-audit 0.28.7 → 0.28.9
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/extensions/goal-loop-forever.ts +24 -5
- package/extensions/loops/goal.ts +10 -2
- package/extensions/reviewer.ts +27 -15
- package/package.json +1 -1
|
@@ -43,6 +43,11 @@ export interface LoopState {
|
|
|
43
43
|
maxIterations: number;
|
|
44
44
|
plateauWindow: number;
|
|
45
45
|
stallCount: number;
|
|
46
|
+
/** v0.28.8 (E5): consecutive iterations where the measure printed NO
|
|
47
|
+
* number. Tracked separately from stallCount — plateau judges movement
|
|
48
|
+
* (a real number that didn't improve); a broken measure says nothing
|
|
49
|
+
* about movement and must stop the loop with its own loud reason. */
|
|
50
|
+
consecutiveNullMeasures?: number;
|
|
46
51
|
bestValue: number | null;
|
|
47
52
|
lastValue: number | null;
|
|
48
53
|
active: boolean;
|
|
@@ -172,14 +177,20 @@ export type LoopTickOutcome =
|
|
|
172
177
|
*/
|
|
173
178
|
export function applyMeasurement(loop: LoopState, value: number | null, at: string): LoopTickOutcome {
|
|
174
179
|
loop.iteration++;
|
|
180
|
+
// improved is judged BEFORE bestValue moves (post-mutation it would read false).
|
|
175
181
|
const improved = value !== null && loop.direction !== undefined && isImprovement(loop.direction, value, loop.bestValue);
|
|
176
182
|
if (value === null) {
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
loop.
|
|
180
|
-
loop.stallCount = 0;
|
|
183
|
+
// E5: a null measure is NOT a stall — it carries no information about
|
|
184
|
+
// improvement. Plateau stays reserved for real non-improving numbers.
|
|
185
|
+
loop.consecutiveNullMeasures = (loop.consecutiveNullMeasures ?? 0) + 1;
|
|
181
186
|
} else {
|
|
182
|
-
loop.
|
|
187
|
+
loop.consecutiveNullMeasures = 0;
|
|
188
|
+
if (improved) {
|
|
189
|
+
loop.bestValue = value;
|
|
190
|
+
loop.stallCount = 0;
|
|
191
|
+
} else {
|
|
192
|
+
loop.stallCount++;
|
|
193
|
+
}
|
|
183
194
|
}
|
|
184
195
|
loop.lastValue = value;
|
|
185
196
|
loop.history.push({ iteration: loop.iteration, value, improved, at });
|
|
@@ -198,6 +209,14 @@ export function applyMeasurement(loop: LoopState, value: number | null, at: stri
|
|
|
198
209
|
loop.stopReason = `token budget exhausted (${(loop.tokensUsed ?? 0).toLocaleString()} >= ${loop.tokenBudget.toLocaleString()}); best: ${loop.bestValue ?? "n/a"}`;
|
|
199
210
|
return { kind: "stop", reason: loop.stopReason };
|
|
200
211
|
}
|
|
212
|
+
// E5: a broken measure command gets its OWN loud stop — never the
|
|
213
|
+
// misleading "plateau — no improvement" (there was nothing to improve
|
|
214
|
+
// against; the metric itself is dead).
|
|
215
|
+
if ((loop.consecutiveNullMeasures ?? 0) >= loop.plateauWindow) {
|
|
216
|
+
loop.active = false;
|
|
217
|
+
loop.stopReason = `measure command broken — ${loop.consecutiveNullMeasures} consecutive iterations printed no number (cmd: \`${loop.measureCmd ?? "?"}\`). Fix the measure command, or /loop stop.`;
|
|
218
|
+
return { kind: "stop", reason: loop.stopReason };
|
|
219
|
+
}
|
|
201
220
|
if (loop.stallCount >= loop.plateauWindow) {
|
|
202
221
|
loop.active = false;
|
|
203
222
|
loop.stopReason = `plateau — no improvement in ${loop.plateauWindow} consecutive iterations (best: ${loop.bestValue ?? "n/a"})`;
|
package/extensions/loops/goal.ts
CHANGED
|
@@ -879,8 +879,16 @@ function fireReviewer(
|
|
|
879
879
|
`[REVIEWER FOLLOW-UP — ${reason}. Propose this as a /goal via propose_goal_draft (the user Confirms or rejects): ${objective}]`,
|
|
880
880
|
{ deliverAs: ctx.isIdle() ? "followUp" : "steer" },
|
|
881
881
|
);
|
|
882
|
-
|
|
883
|
-
|
|
882
|
+
return true;
|
|
883
|
+
} catch (err) {
|
|
884
|
+
// v0.28.8 (E4): the phantom-reviewer hole — a swallowed throw used
|
|
885
|
+
// to still count as "proposed" in the report + notify. Now the
|
|
886
|
+
// failure is LOUD and the proposal goes uncounted.
|
|
887
|
+
ctx.ui.notify(
|
|
888
|
+
`Reviewer /goal proposal NOT delivered: ${err instanceof Error ? err.message : String(err)} — the follow-up never reached the session. Restart pi if the session was just replaced.`,
|
|
889
|
+
"warning",
|
|
890
|
+
);
|
|
891
|
+
return false;
|
|
884
892
|
}
|
|
885
893
|
},
|
|
886
894
|
notify: (message, level) => ctx.ui.notify(message, level),
|
package/extensions/reviewer.ts
CHANGED
|
@@ -197,7 +197,11 @@ export interface ReviewerDeps {
|
|
|
197
197
|
/** Source texts for finding extraction (archive md, audit reports). */
|
|
198
198
|
sources: Array<{ name: string; text: string }>;
|
|
199
199
|
enqueueListItems: (objectives: string[]) => void;
|
|
200
|
-
|
|
200
|
+
/** Deliver a /goal proposal message to the session. Returns true when the
|
|
201
|
+
* message was actually sent; false when the send failed (the v0.28.8 E4
|
|
202
|
+
* contract — a failed send must NOT count as `proposed`, else the user is
|
|
203
|
+
* told about phantom proposals that never arrived). */
|
|
204
|
+
proposeGoal: (objective: string, reason: string) => boolean;
|
|
201
205
|
notify: (message: string, level: "info" | "warning") => void;
|
|
202
206
|
ledger: (type: string, value: Record<string, unknown>) => void;
|
|
203
207
|
}
|
|
@@ -274,23 +278,29 @@ export function runReviewer(
|
|
|
274
278
|
// v0.27.5 aggressive: also propose the FIRST architectural finding
|
|
275
279
|
// as a relaunch so the queue gets burned through even when the
|
|
276
280
|
// unattended rig can't Confirm.
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
+
if (
|
|
282
|
+
deps.proposeGoal(
|
|
283
|
+
architectural[0]!.text,
|
|
284
|
+
`aggressive postaudit: relaunching as /goal without Confirm (${architectural.length} architectural findings total)`,
|
|
285
|
+
)
|
|
286
|
+
) {
|
|
287
|
+
proposed += 1;
|
|
288
|
+
}
|
|
281
289
|
enqueued += architectural.length;
|
|
282
|
-
proposed += 1;
|
|
283
290
|
cascadeStep = "aggressive-relaunch";
|
|
284
291
|
} else if (auto) {
|
|
285
292
|
deps.enqueueListItems(architectural.map((f) => f.text));
|
|
286
293
|
enqueued += architectural.length;
|
|
287
294
|
cascadeStep = convertStep;
|
|
288
295
|
} else {
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
296
|
+
if (
|
|
297
|
+
deps.proposeGoal(
|
|
298
|
+
architectural.map((f) => f.text).join("; "),
|
|
299
|
+
`reviewer found ${architectural.length} architectural-class finding(s) — needs your Confirm`,
|
|
300
|
+
)
|
|
301
|
+
) {
|
|
302
|
+
proposed += architectural.length;
|
|
303
|
+
}
|
|
294
304
|
cascadeStep = "propose-goal";
|
|
295
305
|
}
|
|
296
306
|
}
|
|
@@ -301,16 +311,18 @@ export function runReviewer(
|
|
|
301
311
|
if (findings.length === 0 && config.cascade.includes("fire-audit-on-clean")) {
|
|
302
312
|
const auditObjective = `Post-completion regression scan after ${source.goalId} (${config.auditScope})`;
|
|
303
313
|
if (aggressive) {
|
|
304
|
-
deps.proposeGoal(auditObjective, "aggressive postaudit: clean completion — relaunching the regression scan as /goal")
|
|
305
|
-
|
|
314
|
+
if (deps.proposeGoal(auditObjective, "aggressive postaudit: clean completion — relaunching the regression scan as /goal")) {
|
|
315
|
+
proposed++;
|
|
316
|
+
}
|
|
306
317
|
cascadeStep = "aggressive-relaunch";
|
|
307
318
|
} else if (auto) {
|
|
308
319
|
deps.enqueueListItems([auditObjective]);
|
|
309
320
|
enqueued++;
|
|
310
321
|
cascadeStep = "fire-audit-on-clean";
|
|
311
322
|
} else {
|
|
312
|
-
deps.proposeGoal(auditObjective, "reviewer: completion looks clean — firing the audit step")
|
|
313
|
-
|
|
323
|
+
if (deps.proposeGoal(auditObjective, "reviewer: completion looks clean — firing the audit step")) {
|
|
324
|
+
proposed++;
|
|
325
|
+
}
|
|
314
326
|
cascadeStep = "fire-audit-on-clean";
|
|
315
327
|
}
|
|
316
328
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-goal-list-loop-audit",
|
|
3
|
-
"version": "0.28.
|
|
3
|
+
"version": "0.28.9",
|
|
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",
|