pi-goal-list-loop-audit 0.38.91 → 0.38.92
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
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.38.92 — Deterministic 400s hold; dethroned sessions named (2026-09-22)
|
|
4
|
+
|
|
5
|
+
- Main-model recovery no longer blind-retries deterministic provider refusals (HTTP 400 — e.g. 12 images against a 4-image model cap, which burned 7.5h of "retrying automatically"). Identical retries cannot succeed, so it holds for manual resume with fix directions (switch model or trim the request) in every mode; model switches retire the old episode's diagnostic so failover still probes (audit/DETERMINISTIC-400-AND-DETHRONED-2026-09-22.md).
|
|
6
|
+
- A session that loses the state-root race is now told exactly that ("owned by another session … not a subagent refusal") instead of being misdiagnosed as a subagent session.
|
|
7
|
+
|
|
3
8
|
## 0.38.91 — Tool descriptions enumerate plan/audit/verify/add (2026-09-21)
|
|
4
9
|
|
|
5
10
|
- `/goal plan`, `/goal audit`, `/goal verify`, `/list plan`, and `/list add` existed but were undiscoverable from the tool descriptions. Both descriptions now enumerate them with one-line roles; a pin keeps the enumerations (audit/POST-090-IMPROVEMENT-SWEEP-2026-09-21.md).
|
package/docs/INDEX.md
CHANGED
|
@@ -16,7 +16,7 @@ Policy contracts and recent changes live in the `audit/` directory of the
|
|
|
16
16
|
failback; v0.35.9 hardened cross-version npm tarball checks; v0.35.10
|
|
17
17
|
handles multi-entry npm dry-run reports; v0.35.11 accepts both npm report
|
|
18
18
|
shapes; v0.35.12 supports npm 12's keyed pack reports; v0.35.13 fixes stale-API recovery loops.
|
|
19
|
-
v0.35.14–v0.38.
|
|
19
|
+
v0.35.14–v0.38.92 continue through the supervisor freeze (`/glla pause`),
|
|
20
20
|
load hold, auditor picker parity, Windows launch fix, zombie-watchdog
|
|
21
21
|
subagent carve-out, due-wait backstop, the `/glla agents` visibility panel,
|
|
22
22
|
durable state-root selection, blank-until-resume auditor context, frozen
|
|
@@ -31,6 +31,7 @@ import {
|
|
|
31
31
|
mainModelFailureDelayMs,
|
|
32
32
|
mainModelPrimaryProbeDelayMs,
|
|
33
33
|
mainModelRetryDelayMs,
|
|
34
|
+
isDeterministicProviderError,
|
|
34
35
|
isQuotaHorizonExempt,
|
|
35
36
|
quotaResetSleepMs,
|
|
36
37
|
isCompactionInFlightSince,
|
|
@@ -800,6 +801,15 @@ export function setMainModelRecoveryPause(ctx: ExtensionContext, recovery: MainM
|
|
|
800
801
|
};
|
|
801
802
|
const now = Date.now();
|
|
802
803
|
const deadlineMs = normalized.autoRetryUntil ? Date.parse(normalized.autoRetryUntil) : Number.NaN;
|
|
804
|
+
// v0.38.92: deterministic 400s never schedule — an identical retry cannot
|
|
805
|
+
// succeed, so the ladder would burn (forever under aggressiveMode) while
|
|
806
|
+
// promising "retrying automatically". Hold for manual resume with the fix
|
|
807
|
+
// directions; the user's resume re-probes a CHANGED request. Checked
|
|
808
|
+
// before the horizon/quota logic so it wins in every mode.
|
|
809
|
+
if (isDeterministicProviderError(normalized.providerErrorDiagnostic ?? normalized.reason)) {
|
|
810
|
+
holdMainModelRecovery(ctx, normalized, "the provider refused the request itself (deterministic client error — e.g. too many images for this model). Switch model or trim the request, then resume");
|
|
811
|
+
return false;
|
|
812
|
+
}
|
|
803
813
|
const requestedDelayMs = Math.max(1_000, delayMs);
|
|
804
814
|
// v0.38.69 (Antigravity port): quota waits never park at the horizon —
|
|
805
815
|
// a rate-limit/plan-quota wall is transient, so the hold below is
|
|
@@ -1627,7 +1637,11 @@ export async function recoverMainModelFromSendStorm(ctx: ExtensionContext, kind:
|
|
|
1627
1637
|
if (!current) return;
|
|
1628
1638
|
const recovery = state.mainModelRecovery;
|
|
1629
1639
|
if (!recovery) return;
|
|
1630
|
-
|
|
1640
|
+
// v0.38.92: the switch retires the old episode's diagnostic — it
|
|
1641
|
+
// describes the previous model's failure, and a stale deterministic
|
|
1642
|
+
// marker must not hold the fresh model's probe. Reason restarts from
|
|
1643
|
+
// the storm failure that triggered the switch.
|
|
1644
|
+
if (setMainModelRecoveryPause(ctx, { ...recovery, kind: kind === "loop" ? "loop" : "goal", active: current, resumeCurrent: true, reason: mainModelRecoveryReason(failure), providerErrorDiagnostic: undefined }, 1_000)) {
|
|
1631
1645
|
flags.mainModelAbortForRecovery = true;
|
|
1632
1646
|
try { ctx.abort(); } catch { /* best effort; recovery guard prevents re-send storms */ }
|
|
1633
1647
|
scheduleMainModelRecoveryTimer(ctx, 1_000);
|
|
@@ -1884,8 +1884,15 @@ function isHostLifecycleSessionStart(event: unknown): boolean {
|
|
|
1884
1884
|
|
|
1885
1885
|
const FOREIGN_SESSION_TOOL_MESSAGE =
|
|
1886
1886
|
"This tool changes goal/loop/list state, which only the MAIN session owns — you are running in a subagent session. Report back to the main agent; it owns the goal and can call this tool.";
|
|
1887
|
-
|
|
1888
|
-
|
|
1887
|
+
/** Refusal when the caller lost the workingDir state-root race (field
|
|
1888
|
+
* 2026-09-21: a dethroned MAIN session got the bare subagent message,
|
|
1889
|
+
* which misdiagnoses — it is not a worker, it lost the root to another
|
|
1890
|
+
* live session). Keeps the v0.35.72 pinned contract (MAIN-owner clause,
|
|
1891
|
+
* "state-root read-only", sessionDir cure) but replaces the false
|
|
1892
|
+
* "subagent session" diagnosis with the dethroned one. Replaces
|
|
1893
|
+
* FOREIGN_SESSION_TOOL_MESSAGE_WITH_STATE_ROOT_HINT. */
|
|
1894
|
+
const DETHRONED_SESSION_TOOL_MESSAGE =
|
|
1895
|
+
"This tool changes goal/loop/list state, which only the MAIN session owns — but this is not a subagent refusal: another live session holds this folder's state root, so this session is state-root read-only. Close the other session, start a fresh session here to take the root back (/glla owner inspects the holder), or switch to sessionDir via /glla settings → State root.";
|
|
1889
1896
|
|
|
1890
1897
|
/** Refusal message when a state-mutating tool is called from a subagent session, else null. */
|
|
1891
1898
|
function foreignToolGuard(execCtx: unknown): string | null {
|
|
@@ -1901,9 +1908,10 @@ function foreignToolGuard(execCtx: unknown): string | null {
|
|
|
1901
1908
|
if (tryAbsorbHostSuccessor(c, "tool-call")) return null;
|
|
1902
1909
|
if (isForeignCtx(c)) {
|
|
1903
1910
|
// v0.35.72: when the cwd is also denied by the workingDir state-root
|
|
1904
|
-
// owner, the two warnings co-occur.
|
|
1905
|
-
// subagent
|
|
1906
|
-
|
|
1911
|
+
// owner, the two warnings co-occur. v0.38.92: name the dethroned
|
|
1912
|
+
// diagnosis, not the subagent one — the caller is usually a former
|
|
1913
|
+
// main session that lost the root race (field 2026-09-21).
|
|
1914
|
+
if (c && processOwnerDeniedCwd === c.cwd) return DETHRONED_SESSION_TOOL_MESSAGE;
|
|
1907
1915
|
return FOREIGN_SESSION_TOOL_MESSAGE;
|
|
1908
1916
|
}
|
|
1909
1917
|
// Post-park the owner is nulled; the dead-owner record means only the
|
|
@@ -323,6 +323,21 @@ export function isQuotaHorizonExempt(raw: string | undefined): boolean {
|
|
|
323
323
|
return signal === "rate-limit" || signal === "plan-quota";
|
|
324
324
|
}
|
|
325
325
|
|
|
326
|
+
// v0.38.92 (field 2026-09-21: 12 images vs a 4-image model cap retried 7.5h):
|
|
327
|
+
// a deterministic HTTP 400 client error can never succeed on an identical
|
|
328
|
+
// retry — only a changed request (fewer images, different model, fixed
|
|
329
|
+
// params) can. Retrying it on the ladder burns the horizon (or loops
|
|
330
|
+
// forever under aggressiveMode) while telling the user "retrying
|
|
331
|
+
// automatically". Match the error-type markers, never a bare "400" (token
|
|
332
|
+
// counts and limits quote 400s constantly). Callers hold for manual resume
|
|
333
|
+
// with the fix directions instead of scheduling.
|
|
334
|
+
const DETERMINISTIC_CLIENT_ERROR = /badrequesterror|invalid_request_error|"code"\s*:\s*"400"/i;
|
|
335
|
+
|
|
336
|
+
export function isDeterministicProviderError(raw: string | undefined): boolean {
|
|
337
|
+
if (typeof raw !== "string" || !raw.trim()) return false;
|
|
338
|
+
return DETERMINISTIC_CLIENT_ERROR.test(raw);
|
|
339
|
+
}
|
|
340
|
+
|
|
326
341
|
/** v0.38.69 (Antigravity port): sleep-until-reset for quota-class failures
|
|
327
342
|
* with an explicit upstream reset hint. Returns undefined (keep the blind
|
|
328
343
|
* ladder) unless ALL hold: a rate-limit/plan-quota signal, an upstream
|
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.92",
|
|
4
4
|
"description": "Mission control for long running pi work: interview drafted goals, an audited task queue, and metric or audit loops that run for hours. Every completion is rechecked by a detached auditor with raw evidence, while Confirm drafts, decision pauses, and consent gates keep you in charge.",
|
|
5
5
|
"license": "AGPL-3.0-only",
|
|
6
6
|
"author": "dracon",
|