pi-goal-list-loop-audit 0.35.12 → 0.35.13
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 +9 -0
- package/README.md +1 -1
- package/docs/INDEX.md +1 -1
- package/extensions/goal-heartbeat.ts +6 -13
- package/extensions/loops/goal-session.ts +14 -10
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,14 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.35.13 — stale-API recovery loop fix (2026-08-20)
|
|
4
|
+
|
|
5
|
+
### Stale-handle recovery correctness
|
|
6
|
+
Heartbeat recovery now validates the captured `ExtensionAPI` separately
|
|
7
|
+
from `ExtensionContext`. A context that still answers `isIdle()` cannot
|
|
8
|
+
revive an API that Pi has invalidated, so glla keeps the durable interruption
|
|
9
|
+
parked instead of repeatedly announcing recovery and retrying the same dead
|
|
10
|
+
continuation handle.
|
|
11
|
+
|
|
3
12
|
## 0.35.12 — npm 12 pack-report compatibility (2026-08-20)
|
|
4
13
|
|
|
5
14
|
### Keyed npm 12 dry-run reports
|
package/README.md
CHANGED
|
@@ -10,7 +10,7 @@ This is a detached process, not a nested session in the main pi process. `comple
|
|
|
10
10
|
|
|
11
11
|
On Windows, npm installs the `pi.cmd` shim rather than a directly executable `pi` binary. The auditor launches it through an explicitly quoted `cmd.exe` boundary; POSIX keeps direct shell-less execution. Protocol snapshots also tolerate transient Windows file-locks without deleting the last valid snapshot first.
|
|
12
12
|
|
|
13
|
-
**Current package version:** `v0.35.
|
|
13
|
+
**Current package version:** `v0.35.13` — use `/glla version` to see the installed version and the command for comparing it with the registry latest. This checkout may contain unreleased changes; the npm registry is authoritative for published versions.
|
|
14
14
|
|
|
15
15
|
## Why this exists
|
|
16
16
|
|
package/docs/INDEX.md
CHANGED
|
@@ -17,7 +17,7 @@ For shipped docs, the relevant entry points are:
|
|
|
17
17
|
task milestone gating; v0.35.8 added main-model preferred-primary
|
|
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
|
-
shapes; v0.35.12 supports npm 12's keyed pack reports.
|
|
20
|
+
shapes; v0.35.12 supports npm 12's keyed pack reports; v0.35.13 fixes stale-API recovery loops.
|
|
21
21
|
- `../README.md` — what the plugin is, install, quickstart, and the
|
|
22
22
|
architectural guarantee (drafting + confirm + detached auditor).
|
|
23
23
|
- `../INSTALL.md` — manual install / symlink setup; the recommended
|
|
@@ -484,19 +484,12 @@ function heartbeatTick(): void {
|
|
|
484
484
|
if (tryAbsorbHostSuccessor(knownCtx, "heartbeat-self-heal")) return;
|
|
485
485
|
rememberCtx(knownCtx);
|
|
486
486
|
// Reuse the same-session recovery gate as ordinary commands. It clears
|
|
487
|
-
// the durable interrupted marker and
|
|
488
|
-
//
|
|
489
|
-
//
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
flags.extensionApiStale
|
|
493
|
-
flags.zombieStoodDown = false;
|
|
494
|
-
flags.sessionHandoffPending = false;
|
|
495
|
-
try {
|
|
496
|
-
knownCtx.ui.notify("glla: pi recovered after a stale-handle terminal — self-healing in-memory state (no /reload needed).", "info");
|
|
497
|
-
} catch {
|
|
498
|
-
/* the ledger is the durable record; notify is best-effort */
|
|
499
|
-
}
|
|
487
|
+
// the durable interrupted marker and rebinds the owner only after BOTH
|
|
488
|
+
// the context and the captured ExtensionAPI are healthy. If that gate
|
|
489
|
+
// refuses the contact, stay parked: clearing these flags here used to
|
|
490
|
+
// announce a false recovery and immediately retry against the same stale
|
|
491
|
+
// API every heartbeat tick.
|
|
492
|
+
if (flags.staleTerminalDone || flags.extensionApiStale) return;
|
|
500
493
|
}
|
|
501
494
|
const ctx = freshCtx();
|
|
502
495
|
if (!ctx) return;
|
|
@@ -1072,7 +1072,11 @@ function isCtxAlive(ctx: ExtensionContext | null | undefined): boolean {
|
|
|
1072
1072
|
* (field: hegemon 2026-08-06 — one probe failure parked a live session for
|
|
1073
1073
|
* 5 hours). */
|
|
1074
1074
|
function probeExtensionApiStaleRaw(): boolean {
|
|
1075
|
-
|
|
1075
|
+
// The ExtensionAPI and ExtensionContext can disagree briefly: a live
|
|
1076
|
+
// context does NOT prove that the captured `pi` can still send. In
|
|
1077
|
+
// particular, a stale send can latch the API while ctx.isIdle() continues
|
|
1078
|
+
// to succeed. Always probe the API itself here or the heartbeat will
|
|
1079
|
+
// repeatedly "recover" and immediately fail the next continuation send.
|
|
1076
1080
|
if (!extensionApi) return false;
|
|
1077
1081
|
try {
|
|
1078
1082
|
extensionApi.getSessionName();
|
|
@@ -1083,13 +1087,10 @@ function probeExtensionApiStaleRaw(): boolean {
|
|
|
1083
1087
|
}
|
|
1084
1088
|
|
|
1085
1089
|
function probeExtensionApiStale(): boolean {
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
}
|
|
1091
|
-
return true;
|
|
1092
|
-
}
|
|
1090
|
+
// A stale ExtensionAPI is terminal for this factory instance. A healthy
|
|
1091
|
+
// context probe must not clear this latch: the next send would still use
|
|
1092
|
+
// the same captured API and throw again.
|
|
1093
|
+
if (extensionApiStale) return true;
|
|
1093
1094
|
if (probeExtensionApiStaleRaw()) extensionApiStale = true;
|
|
1094
1095
|
return extensionApiStale;
|
|
1095
1096
|
}
|
|
@@ -1483,8 +1484,11 @@ function selfHealStaleSameSession(ctx: ExtensionContext): boolean {
|
|
|
1483
1484
|
if (owner && owner.pid === process.pid && typeof owner.instanceId === "string" && owner.instanceId !== instanceId) {
|
|
1484
1485
|
return false; // a successor module instance owns this cwd — never re-claim
|
|
1485
1486
|
}
|
|
1486
|
-
//
|
|
1487
|
-
|
|
1487
|
+
// Both handles must actually be healthy NOW. A live ExtensionContext does
|
|
1488
|
+
// not prove that the captured ExtensionAPI can send; Pi can leave ctx
|
|
1489
|
+
// probes answering while the API has already latched stale. Reclaim only
|
|
1490
|
+
// when the exact API used by continuation sends also passes its probe.
|
|
1491
|
+
if (!isCtxAlive(ctx) || !extensionApi || probeExtensionApiStaleRaw()) return false;
|
|
1488
1492
|
const was = extensionApiStale ? "extension_api_stale" : sessionHandoffPending ? "session_handoff_pending" : "stale_terminal_done";
|
|
1489
1493
|
extensionApiStale = false;
|
|
1490
1494
|
sessionHandoffPending = false;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-goal-list-loop-audit",
|
|
3
|
-
"version": "0.35.
|
|
3
|
+
"version": "0.35.13",
|
|
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",
|