instar 1.3.128 → 1.3.130
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/.claude/skills/autonomous/hooks/autonomous-stop-hook.sh +36 -0
- package/dist/commands/server.d.ts.map +1 -1
- package/dist/commands/server.js +12 -4
- package/dist/commands/server.js.map +1 -1
- package/dist/config/ConfigDefaults.d.ts.map +1 -1
- package/dist/config/ConfigDefaults.js +4 -0
- package/dist/config/ConfigDefaults.js.map +1 -1
- package/dist/core/PostUpdateMigrator.d.ts.map +1 -1
- package/dist/core/PostUpdateMigrator.js +29 -5
- package/dist/core/PostUpdateMigrator.js.map +1 -1
- package/dist/core/installCodexHooks.d.ts +7 -0
- package/dist/core/installCodexHooks.d.ts.map +1 -1
- package/dist/core/installCodexHooks.js +30 -2
- package/dist/core/installCodexHooks.js.map +1 -1
- package/dist/core/types.d.ts +19 -0
- package/dist/core/types.d.ts.map +1 -1
- package/dist/core/types.js.map +1 -1
- package/dist/monitoring/SessionReaper.d.ts +39 -0
- package/dist/monitoring/SessionReaper.d.ts.map +1 -1
- package/dist/monitoring/SessionReaper.js +104 -0
- package/dist/monitoring/SessionReaper.js.map +1 -1
- package/dist/scaffold/templates.d.ts.map +1 -1
- package/dist/scaffold/templates.js +7 -5
- package/dist/scaffold/templates.js.map +1 -1
- package/dist/server/routes.d.ts.map +1 -1
- package/dist/server/routes.js +12 -0
- package/dist/server/routes.js.map +1 -1
- package/package.json +1 -1
- package/src/data/builtin-manifest.json +62 -62
- package/src/scaffold/templates.ts +7 -5
- package/upgrades/1.3.129.md +55 -0
- package/upgrades/1.3.130.md +74 -0
- package/upgrades/side-effects/codex-autonomous-loop-driver.md +91 -0
- package/upgrades/side-effects/sessionreaper-cpu-aware-and-decision-audit.md +122 -0
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
# Upgrade Guide — vNEXT
|
|
2
|
+
|
|
3
|
+
<!-- bump: patch -->
|
|
4
|
+
|
|
5
|
+
## What Changed
|
|
6
|
+
|
|
7
|
+
**The SessionReaper now reaps under CPU pressure, not only memory — and keeps a
|
|
8
|
+
silent, reviewable record of every decision it makes.**
|
|
9
|
+
|
|
10
|
+
The idle-session reaper used to compute its pressure tier purely from free
|
|
11
|
+
memory. But on a busy multi-agent box the real squeeze is almost always CPU, not
|
|
12
|
+
RAM (free memory can look fine while the load average is well past the core
|
|
13
|
+
count). So an idle session could sit holding CPU baseline indefinitely and the
|
|
14
|
+
reaper, watching only memory, would never wake up.
|
|
15
|
+
|
|
16
|
+
Pressure is now the WORST of two signals: memory (free %) and CPU (1-minute load
|
|
17
|
+
average ÷ core count). A CPU-bound box raises the tier even when memory is fine,
|
|
18
|
+
so genuinely-idle sessions become eligible under load — while the reaper's
|
|
19
|
+
positive-idle proof, hysteresis, confirmation window, rate limits, and grace
|
|
20
|
+
period are all unchanged, so it still never reaps a working session. The two CPU
|
|
21
|
+
thresholds are configurable; sensible defaults ship (moderate at 1.0 load per
|
|
22
|
+
core, critical at 1.5), and a transient build spike won't trigger a reaping spree
|
|
23
|
+
because the existing 3-observation confirmation smooths it.
|
|
24
|
+
|
|
25
|
+
Second, the reaper now writes a dedicated decision audit trail. Previously its
|
|
26
|
+
structured events were mixed into the shared sentinel log and only covered the
|
|
27
|
+
reap path — there was no record of the routine keep decisions, so "what is the
|
|
28
|
+
reaper considering, and why?" had no grounded answer. It now logs every keep/kill
|
|
29
|
+
decision change (on transition, not every tick, so a multi-day kept session logs
|
|
30
|
+
once) plus the reap-path events, each stamped with the pressure tier that drove
|
|
31
|
+
it, to a dedicated file readable through a new read-only endpoint.
|
|
32
|
+
|
|
33
|
+
## What to Tell Your User
|
|
34
|
+
|
|
35
|
+
Nothing to configure. Your idle-session cleanup is now aware of CPU load, not
|
|
36
|
+
just memory — so on a busy machine it can finally relieve pressure that free
|
|
37
|
+
memory alone would have hidden. It is still just as careful: it never touches a
|
|
38
|
+
session that might be working. You can also now ask me what the cleanup is
|
|
39
|
+
considering and why it kept or shut down any session — there is a quiet,
|
|
40
|
+
inspectable decision log behind it. None of this sends you notifications; it is
|
|
41
|
+
all there for when you want to look.
|
|
42
|
+
|
|
43
|
+
## Summary of New Capabilities
|
|
44
|
+
|
|
45
|
+
- Reaper pressure is CPU-aware: tier is the worst of memory (free %) and CPU
|
|
46
|
+
(1-min load ÷ cores), via the new pure `computePressure()` classifier.
|
|
47
|
+
- Two new tunable thresholds: `cpuModerateLoadPerCore` (default 1.0) and
|
|
48
|
+
`cpuCriticalLoadPerCore` (default 1.5) under `monitoring.sessionReaper`.
|
|
49
|
+
Existing agents receive them automatically via the canonical config defaults.
|
|
50
|
+
- `GET /sessions/reaper`'s `pressure.inputs` now exposes `freePct`,
|
|
51
|
+
`loadPerCore`, and the `memTier`/`cpuTier` breakdown.
|
|
52
|
+
- New read-only endpoint `GET /sessions/reaper/audit?limit=N` returns the tail
|
|
53
|
+
of the dedicated decision trail at `logs/reaper-audit.jsonl`.
|
|
54
|
+
- A `decision` audit row is written on first sight and on every (verdict,
|
|
55
|
+
keptBy) change — transition-only, so no per-tick log spam. Silent: no Telegram,
|
|
56
|
+
no attention items.
|
|
57
|
+
|
|
58
|
+
## Evidence
|
|
59
|
+
|
|
60
|
+
- `tests/unit/session-reaper-pressure-audit.test.ts` — new: `computePressure`
|
|
61
|
+
(memory-only when cores unknown, CPU-raises-tier, worst-of combos, custom
|
|
62
|
+
thresholds, non-finite load ignored); the `reaperAuditSink`/`readReaperAudit`
|
|
63
|
+
round-trip (bounded tail, `[]` when absent); and the transition-only decision
|
|
64
|
+
audit (logs on first sight + on change, not when unchanged).
|
|
65
|
+
- `tests/integration/session-reaper-routes.test.ts` — new: `GET
|
|
66
|
+
/sessions/reaper/audit` returns 200 with the tail, honors `?limit`, and `[]`
|
|
67
|
+
when no trail exists.
|
|
68
|
+
- `tests/e2e/session-reaper-lifecycle.test.ts` — new Phase-1 "feature alive"
|
|
69
|
+
test: the audit route returns 200 (not 503) through the real AgentServer
|
|
70
|
+
plumbing and reads a written row back.
|
|
71
|
+
- `tests/unit/feature-delivery-completeness.test.ts` + `capabilities-discoverability.test.ts`
|
|
72
|
+
green: migrator parity (new `migrateClaudeMd` section), config parity, and
|
|
73
|
+
route classification all satisfied.
|
|
74
|
+
- Full `npm run lint` + the reaper test tiers pass.
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
# Side-Effects Review — Codex autonomous-loop driver
|
|
2
|
+
|
|
3
|
+
**Version / slug:** `codex-autonomous-loop-driver`
|
|
4
|
+
**Date:** `2026-05-30`
|
|
5
|
+
**Author:** `echo`
|
|
6
|
+
**Second-pass reviewer:** see below (required — lifecycle machinery)
|
|
7
|
+
|
|
8
|
+
## Summary of the change
|
|
9
|
+
|
|
10
|
+
Adds a codex registration of the shared autonomous-stop-hook so a `codex exec` session
|
|
11
|
+
sustains a multi-turn autonomous run (the codex analog of Claude's Stop-hook loop). A
|
|
12
|
+
SEPARATE codex Stop group (`autonomous-stop-hook.sh --codex`) is added in
|
|
13
|
+
`installCodexHooks`; the hook self-gates on `autonomousSessions.codexLoopDriver.enabled`
|
|
14
|
+
(default false → DARK). Claude's path is byte-for-byte unchanged.
|
|
15
|
+
|
|
16
|
+
## Decision-point inventory
|
|
17
|
+
|
|
18
|
+
1. `IS_CODEX` gate in the hook (— is this a codex-registered invocation?).
|
|
19
|
+
2. `codexLoopDriver.enabled` flag check (— should the codex loop actually run?).
|
|
20
|
+
3. `groupIsInstarOwned` (— is this Stop group instar-owned, to replace not duplicate?).
|
|
21
|
+
|
|
22
|
+
## 1. Over-block
|
|
23
|
+
Could it block a stop that SHOULD proceed? Only when the flag is ON, an autonomous job is
|
|
24
|
+
active for this session, AND tasks remain — which is exactly the intended block (continue
|
|
25
|
+
the run). With the flag OFF (default) it never blocks. The existing ownership/duration/
|
|
26
|
+
emergency/completion terminal checks (unchanged) still release the session.
|
|
27
|
+
|
|
28
|
+
## 2. Under-block
|
|
29
|
+
Could it fail to block when it SHOULD continue? When the flag is OFF, yes — by design
|
|
30
|
+
(dark). When ON, the only residual is the open binary question of whether codex runs the
|
|
31
|
+
second Stop group (Phase-5 / live verification gates this before enabling; fallback =
|
|
32
|
+
move into group 0). No silent data loss either way — at worst the codex run stops early,
|
|
33
|
+
same as today.
|
|
34
|
+
|
|
35
|
+
## 3. Level-of-abstraction fit
|
|
36
|
+
The driver lives where Claude's does (the autonomous skill hook) and is registered where
|
|
37
|
+
codex's other standing hooks are (`installCodexHooks`). The flag sits with the other
|
|
38
|
+
autonomous-mode settings (`autonomousSessions`). No new subsystem.
|
|
39
|
+
|
|
40
|
+
## 4. Signal vs authority compliance
|
|
41
|
+
**Required reference:** [docs/signal-vs-authority.md](../../docs/signal-vs-authority.md)
|
|
42
|
+
The hook is an AUTHORITY surface by nature (a Stop hook returns block/approve — same as
|
|
43
|
+
Claude's existing loop hook and codex's existing stop-gate-router). It does not newly
|
|
44
|
+
elevate authority: it reuses the established Stop-hook contract. The dark flag means the
|
|
45
|
+
authority is dormant until explicitly enabled. No monitoring/signal component is converted
|
|
46
|
+
into a blocker.
|
|
47
|
+
|
|
48
|
+
## 5. Interactions
|
|
49
|
+
- **Review trio (stop-gate-router / response-review / claim-intercept / scope-coherence):**
|
|
50
|
+
the driver is the LAST hook in the SAME Stop group (slot stop:0:N). Within-group block
|
|
51
|
+
precedence vs the router is verified live before enabling; worst case the session still
|
|
52
|
+
continues via the router (never strands).
|
|
53
|
+
- **Claude autonomous mode:** independent registration (settings.json vs .codex/hooks.json);
|
|
54
|
+
`IS_CODEX=0` for Claude → unchanged.
|
|
55
|
+
- **armCodexHooks:** the new hook changes the hooks.json hash → re-arm on update (handled
|
|
56
|
+
by the existing migration). Because it rides group 0 (a group codex already trusts/arms),
|
|
57
|
+
it adds NO new arm slot — avoiding the recurring-arm-spawn side-effect a separate group
|
|
58
|
+
(stop:1:0) would have caused (caught by the second-pass review, then designed out).
|
|
59
|
+
|
|
60
|
+
## 6. External surfaces
|
|
61
|
+
None new. No HTTP route, no Telegram message, no external API. The hook talks only to the
|
|
62
|
+
local server's existing `/autonomous/evaluate-completion` (unchanged) when a completion
|
|
63
|
+
condition is set.
|
|
64
|
+
|
|
65
|
+
## 7. Rollback cost
|
|
66
|
+
Lowest tier. Set `autonomousSessions.codexLoopDriver.enabled: false` → the standing hook
|
|
67
|
+
exits immediately (instant, no redeploy, no session kill). Full PR revert is clean
|
|
68
|
+
(additive change; removing the Stop group + the `IS_CODEX` block restores prior behavior).
|
|
69
|
+
|
|
70
|
+
## Conclusion
|
|
71
|
+
Safe to ship DARK. The only non-trivial residual (does codex run a second Stop group) is
|
|
72
|
+
gated behind the default-off flag and resolved by live verification before enabling — per
|
|
73
|
+
Justin's "careful + clear plan to regress" condition.
|
|
74
|
+
|
|
75
|
+
## Second-pass review (if required)
|
|
76
|
+
|
|
77
|
+
**Reviewer:** independent second-pass agent (lifecycle machinery — required)
|
|
78
|
+
**Status:** DONE 2026-05-30 — **CONCUR on shipping DARK.** Verified PASS on: Claude path
|
|
79
|
+
unchanged, dark gate cannot leak (all config-read failure paths → disabled), `$0` anchor,
|
|
80
|
+
groupIsInstarOwned idempotency, migration parity (both halves land). The reviewer caught a
|
|
81
|
+
fleet-wide arm side-effect from the original separate-group design (a `stop:1:0` slot codex
|
|
82
|
+
may never trust → recurring codex-TUI arm spawns on every update, even dark). **Resolved**
|
|
83
|
+
by moving the driver into the existing Stop group (slot stop:0:N) — no new arm slot. The
|
|
84
|
+
remaining open item (within-group block precedence + that the loop actually re-prompts a
|
|
85
|
+
real codex run) is gated to live verification BEFORE the flag is enabled, per the spec's
|
|
86
|
+
Phase 5 — it is not a merge/dark-ship blocker.
|
|
87
|
+
|
|
88
|
+
## Evidence pointers
|
|
89
|
+
- Unit: `tests/unit/installCodexHooks.test.ts` (separate Stop group, idempotent, user-group preserved).
|
|
90
|
+
- Unit: `tests/unit/autonomous-stop-hook-codex-gate.test.ts` (dark default / disabled / enabled / Claude-unaffected — both sides of the gate).
|
|
91
|
+
- Spec: `docs/specs/codex-autonomous-loop-driver.md` (+ `.eli16.md`).
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
# Side-Effects Review — SessionReaper CPU-aware pressure + decision audit
|
|
2
|
+
|
|
3
|
+
**Version / slug:** `sessionreaper-cpu-aware-and-decision-audit`
|
|
4
|
+
**Date:** `2026-05-30`
|
|
5
|
+
**Author:** `echo`
|
|
6
|
+
**Second-pass reviewer:** `not required`
|
|
7
|
+
|
|
8
|
+
## Summary of the change
|
|
9
|
+
|
|
10
|
+
The idle-session reaper's pressure tier was computed from free memory only. This
|
|
11
|
+
change makes it the WORST of memory (free %) and CPU (1-min load ÷ cores) via a
|
|
12
|
+
new pure `computePressure()` classifier, with two tunable thresholds
|
|
13
|
+
(`cpuModerateLoadPerCore` 1.0 / `cpuCriticalLoadPerCore` 1.5) auto-migrated to
|
|
14
|
+
existing agents. It also adds a silent decision audit: every keep/kill decision
|
|
15
|
+
*change* + the reap-path events land in `logs/reaper-audit.jsonl`, served
|
|
16
|
+
read-only at `GET /sessions/reaper/audit`.
|
|
17
|
+
|
|
18
|
+
## Decision-point inventory
|
|
19
|
+
|
|
20
|
+
- **Pressure tier computation** (existing decision, widened): now also keys on CPU
|
|
21
|
+
load. Gates *when* the reaper may consider acting.
|
|
22
|
+
- **Decision audit emission** (new, zero-authority signal): writes an observability
|
|
23
|
+
row on `(verdict, keptBy)` transitions. No control-flow effect.
|
|
24
|
+
|
|
25
|
+
## 1. Over-block
|
|
26
|
+
|
|
27
|
+
**What legitimate inputs does this change reject that it shouldn't?**
|
|
28
|
+
|
|
29
|
+
CPU-awareness can raise the tier from `normal` to `moderate`/`critical` during a
|
|
30
|
+
load spike, making genuinely-idle sessions eligible sooner. It cannot cause a
|
|
31
|
+
*working* session to be reaped: the kill path still requires the full positive-idle
|
|
32
|
+
proof, transcript-stasis, render-stasis, 3-observation hysteresis over the
|
|
33
|
+
confirmation window, the two-phase reap, and the per-tick/per-hour budget — all
|
|
34
|
+
unchanged. A transient build spike is smoothed by the multi-observation
|
|
35
|
+
requirement. Default thresholds (1.0/1.5 load-per-core) are deliberately at/above
|
|
36
|
+
full subscription so "moderate" means genuinely oversubscribed.
|
|
37
|
+
|
|
38
|
+
## 2. Under-block
|
|
39
|
+
|
|
40
|
+
**What failure modes does this still miss?**
|
|
41
|
+
|
|
42
|
+
`os.loadavg()` is a trailing 1-minute average, so a very brief CPU famine may not
|
|
43
|
+
register, and a famine caused by non-session processes still only lets the reaper
|
|
44
|
+
trim *idle* sessions (it cannot reduce the load of the busy processes themselves).
|
|
45
|
+
This is acceptable — the reaper is one lever among several (load-shed, hosting
|
|
46
|
+
migration, tool/agent sleep); it is not meant to be a complete CPU governor.
|
|
47
|
+
|
|
48
|
+
## 3. Level-of-abstraction fit
|
|
49
|
+
|
|
50
|
+
**Is this at the right layer?**
|
|
51
|
+
|
|
52
|
+
Yes. Pressure sensing belongs in the reaper's injected `pressure()` provider; the
|
|
53
|
+
pure classifier lives next to the reaper and is unit-tested without `os`. The audit
|
|
54
|
+
is a sink/reader pair beside the existing `fileAuditSink`, mirroring the
|
|
55
|
+
`/sessions/reap-log` read-surface pattern. No business logic leaks into routes.
|
|
56
|
+
|
|
57
|
+
## 4. Signal vs authority compliance
|
|
58
|
+
|
|
59
|
+
**Required reference:** [docs/signal-vs-authority.md](../../docs/signal-vs-authority.md)
|
|
60
|
+
|
|
61
|
+
**Does this change hold blocking authority with brittle logic?**
|
|
62
|
+
|
|
63
|
+
No new blocking authority. The reaper remains the authority it already was; this
|
|
64
|
+
change does not add a brittle check that gates behavior — it widens an existing,
|
|
65
|
+
heavily-confirmed kill path's *eligibility window*, and every safety gate still has
|
|
66
|
+
to clear independently. The decision audit is a pure signal producer (write-only
|
|
67
|
+
observability) with zero authority. `computePressure` is total: unknown/non-finite
|
|
68
|
+
CPU input degrades to the prior memory-only behavior rather than failing.
|
|
69
|
+
|
|
70
|
+
## 5. Interactions
|
|
71
|
+
|
|
72
|
+
**Does this interact with existing checks, recovery paths, or infrastructure?**
|
|
73
|
+
|
|
74
|
+
- Reads the same `monitoring.sessionReaper` config block; two additive fields.
|
|
75
|
+
- `reapNotify`, the reap-log (`/sessions/reap-log`), and the silently-stopped
|
|
76
|
+
sentinels are untouched; the new audit writes a SEPARATE file
|
|
77
|
+
(`reaper-audit.jsonl`), so nothing reading `sentinel-events.jsonl` is affected.
|
|
78
|
+
(Reaper events previously co-mingled there now route to the dedicated file —
|
|
79
|
+
reviewed: no consumer filters `sentinel-events.jsonl` for `kind:'session-reaper'`.)
|
|
80
|
+
- Migration: canonical config defaults (`applyDefaults` deep-merge) + a
|
|
81
|
+
content-sniffed `migrateClaudeMd` section; both idempotent.
|
|
82
|
+
|
|
83
|
+
## 6. External surfaces
|
|
84
|
+
|
|
85
|
+
**Does this change anything visible outside the immediate code path?**
|
|
86
|
+
|
|
87
|
+
One new read-only HTTP route (`GET /sessions/reaper/audit`, Bearer-auth, classified
|
|
88
|
+
in the capabilities-discoverability lint). `GET /sessions/reaper`'s `pressure.inputs`
|
|
89
|
+
gains `loadPerCore`/`memTier`/`cpuTier` fields (additive). One new on-disk file
|
|
90
|
+
(`logs/reaper-audit.jsonl`). No Telegram, no attention items, no notifications.
|
|
91
|
+
|
|
92
|
+
## 7. Rollback cost
|
|
93
|
+
|
|
94
|
+
**If this turns out wrong in production, what's the back-out?**
|
|
95
|
+
|
|
96
|
+
Cheap and layered. (a) Operationally, set the CPU thresholds absurdly high to
|
|
97
|
+
neutralize CPU-awareness with no deploy; the audit is write-only and harmless to
|
|
98
|
+
ignore. (b) A full revert of the PR restores the prior behavior exactly (the change
|
|
99
|
+
is additive). No data migration, no schema change, no irreversible state.
|
|
100
|
+
|
|
101
|
+
## Conclusion
|
|
102
|
+
|
|
103
|
+
Low-risk, additive, reversible. The safety-critical "never reap a working session"
|
|
104
|
+
contract is untouched; the change only widens *when* the existing gated path may
|
|
105
|
+
act and adds zero-authority observability. Ships behind the reaper's existing
|
|
106
|
+
OFF + dry-run default.
|
|
107
|
+
|
|
108
|
+
## Second-pass review (if required)
|
|
109
|
+
|
|
110
|
+
Not required — additive change, no new blocking authority, safety classifier
|
|
111
|
+
untouched.
|
|
112
|
+
|
|
113
|
+
## Evidence pointers
|
|
114
|
+
|
|
115
|
+
- `tests/unit/session-reaper-pressure-audit.test.ts` — `computePressure` matrix,
|
|
116
|
+
transition-only decision audit, sink/reader round-trip.
|
|
117
|
+
- `tests/integration/session-reaper-routes.test.ts` — `GET /sessions/reaper/audit`.
|
|
118
|
+
- `tests/e2e/session-reaper-lifecycle.test.ts` — Phase-1 feature-alive for the
|
|
119
|
+
audit route through the real AgentServer.
|
|
120
|
+
- `tests/unit/feature-delivery-completeness.test.ts` + capabilities-discoverability
|
|
121
|
+
lint — migration + route-classification parity.
|
|
122
|
+
- `upgrades/NEXT.md` — upgrade guide.
|