instar 1.3.372 → 1.3.374

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.
@@ -0,0 +1,30 @@
1
+ # Side Effects — stop-hook-idle-backoff
2
+
3
+ ## Files touched
4
+
5
+ - `.claude/skills/autonomous/hooks/autonomous-stop-hook.sh` — new IDLE_BACKOFF block between the session-id reconcile and the iteration increment: measures the agent's active gap since the last re-injection via a per-topic sidecar (`<topic>.local.backoff.json`), counts consecutive quick stops, and sleeps tiered (3+ → 30s, 6+ → 120s, 10+ → 300s) before emitting the block decision. Poll-sleeps in 5s chunks with early-break on new inbound message / emergency-stop flag / state-file removal; re-checks terminal conditions after the sleep (emergency → notify + clear + exit; state gone → exit). Sleep self-clamps to a third of the hook's own registered Stop timeout read from `.claude/settings.json` (unreadable or codex-mode → conservative 20s). Env seams: `INSTAR_HOOK_BACKOFF_DISABLE`, `_QUICK_SECS`, `_T1/_T2/_T3`, `_POLL_SECS`, `_MAX_SLEEP`.
6
+ - `src/core/PostUpdateMigrator.ts` — stop-hook migration marker bumped `RESTART_NOTE_SILENT` → `IDLE_BACKOFF` so existing agents receive the paced hook (customized hooks still untouched).
7
+ - `tests/unit/autonomous-stop-hook-idle-backoff.test.ts` — new (13 tests; executes the real hook).
8
+ - 7 existing hook-exec test harnesses (`autonomous-completion-condition`, `autonomous-stop-hook-cwd-anchor`, `-codex-gate`, `-topic-keyed`, `-session-clock`, `autonomous-multi-session`, e2e `autonomous-restart-resume-lifecycle`) — gain `INSTAR_HOOK_BACKOFF_DISABLE: '1'` in their env so suites that exec the hook repeatedly never hit a real sleep.
9
+ - `tests/unit/autonomous-stop-hook-notify.test.ts` — terminal-notify call-site count 6 → 7 (the backoff's mid-sleep emergency re-check adds one) + marker-history assertion advanced to `IDLE_BACKOFF`.
10
+
11
+ ## Behavioral side effects
12
+
13
+ 1. **An idle autonomous session re-injects its frame ~once per 5 minutes instead of ~15×/min** — ≥98% reduction in idle-loop token burn (the 2026-06-06 rapid-idle-refire waste: thousands of no-op re-injections over one operator sleep).
14
+ 2. **A productive loop is untouched**: any iteration whose active time exceeds QUICK_SECS (120s) resets the counter; tiers only engage after 3+ consecutive quick stops.
15
+ 3. **Reaction to a new user message while idle-deep**: ≤ POLL_SECS (5s) — the sleep breaks early on a new inbound file for the topic. Emergency stop and job stop/stop-all break the same way.
16
+ 4. **One new sidecar file per topic** in `.instar/autonomous/` (`<topic>.local.backoff.json`). The server's autonomous-dir enumeration filters on `.local.md`, so the sidecar is invisible to it. Stale sidecars self-reset on the next run (runStartedAt mismatch) and are removed on the backoff's own terminal exits; sidecars left by other terminal paths are inert.
17
+ 5. **Migration**: every existing agent's stock stop-hook is overwritten at next migration run (marker bump). Customized hooks (no stock fingerprint) skipped, as before.
18
+
19
+ ## Risks / blast radius
20
+
21
+ - **Hook timeout vs sleep** (the strand-class risk): a Stop hook killed by the host fails OPEN → session exits → loop strands silently. Mitigated three ways: the sleep self-clamps to registered-timeout/3 (live read of settings.json; the shipped registration is 10000s, so the clamp is far above T3); unreadable/missing registration falls back to a 20s cap; codex registrations get the same 20s cap. Worst case is therefore reduced pacing, never a stranded loop.
22
+ - **Sentinel interplay**: a session sleeping inside its Stop hook shows no pane activity for up to 5 min. The silence/socket sentinels target sessions with active work or dropped sockets, not completed turns awaiting the next injection; observed-not-theorized verification rides the dogfood loop after deploy.
23
+ - **Delayed sentinel/tmux-injected text** (not Telegram-routed): anything typed directly into the pane during a sleep sits in the input buffer until the next turn — bounded by T3 (5 min). Telegram messages are NOT affected (early-break).
24
+ - **Counter semantics during conversation**: replying to a user message usually takes < QUICK_SECS, so the counter can keep rising across an active conversation — but each new inbound message breaks the sleep within 5s, so perceived latency stays ≤5s; pacing only persists between messages, which is the desired behavior.
25
+
26
+ ## Tests
27
+
28
+ - `tests/unit/autonomous-stop-hook-idle-backoff.test.ts` (13): counter evolution (first-stop zero, quick-rise, long-gap reset, new-run reset), tier engagement + MAX_SLEEP clamp + DISABLE seam, early-breaks (inbound / emergency / state-removal, real async timing), static safety properties (timeout self-clamp present, sidecar suffix invisible to server), migration upgrade path (prior-era hook gains IDLE_BACKOFF, retains RESTART_NOTE_SILENT).
29
+ - All 8 pre-existing hook suites pass with the disable seam (57 tests across the affected files).
30
+ - Full typecheck clean; `bash -n` clean.
@@ -0,0 +1,74 @@
1
+ # Side-Effects Review — Transfer PLACE-half journaling (coherence finding #5)
2
+
3
+ **Version / slug:** `transfer-place-half-journal`
4
+ **Date:** `2026-06-06`
5
+ **Author:** `echo`
6
+ **Second-pass reviewer:** `not required`
7
+
8
+ ## Summary of the change
9
+
10
+ `POST /pool/transfer` now lands the PLACE half of a deliberate move: for a quiet
11
+ topic (never-seen or released ownership record) it CASes `place→claim` for the
12
+ target as one synchronous pair and journals the placement (`reason: 'user-move'`,
13
+ real epoch) so the entry replicates to the pinned-to machine — closing the
14
+ "no machine ever produced the evidence the #926/#930 read-side fallbacks read"
15
+ gap proven live (the working-set reflex answered `not-owner` after a transfer
16
+ even on v1.3.371+). A resting `placing` record naming the target is repaired via
17
+ claim (the bug-#11 shape). Response gains `placedOwnership`.
18
+
19
+ ## Decision-point inventory
20
+
21
+ One: which ownership-record shapes the block may mutate. Active-with-target →
22
+ skip (no-op). Never-seen/released → place+claim. Resting placing-with-target →
23
+ claim repair. Everything else (active other-machine, placing other-machine,
24
+ transferring) → strictly untouched.
25
+
26
+ ## 1. Over-block
27
+
28
+ Nothing new is rejected; the route's accept/reject surface is unchanged. The
29
+ block only ever ADDS ownership evidence; on any CAS refusal the transfer still
30
+ succeeds exactly as before (`placedOwnership:false`).
31
+
32
+ ## 2. Under-block
33
+
34
+ A topic actively owned by a third machine still journals nothing on transfer
35
+ (deliberate — never steal a live session; the pin drives re-placement on real
36
+ traffic, which CASes and journals through the existing router chokepoint). A
37
+ `placing` record naming a different machine is also left alone — repairing
38
+ someone else's in-flight placement is not this handler's call.
39
+
40
+ ## 3. Level-of-abstraction fit
41
+
42
+ Right layer: the same handler that already owns the RELEASE half (and its
43
+ journaling) now owns the PLACE half — the two halves of one move live at one
44
+ chokepoint. The state machine itself is untouched; the handler composes the
45
+ existing legal transitions (place, claim) exactly as the router's confirmClaim
46
+ precedent does.
47
+
48
+ ## 4. Signal vs authority compliance
49
+
50
+ **Required reference:** [docs/signal-vs-authority.md](../../docs/signal-vs-authority.md)
51
+
52
+ No blocking authority added. Both CAS failures and journal failures are
53
+ best-effort (`@silent-fallback-ok` / observability-never-endangers-the-observed):
54
+ the transfer response never fails because of this block, and the journal entry
55
+ is evidence, not actuation.
56
+
57
+ ## 5. Interactions
58
+
59
+ - **SessionRouter**: claim immediately follows place so the record never RESTS at
60
+ `placing` — the shape that queues every later message as ownership-contention
61
+ (bug #11). A real message for the topic now finds `active(target)` and forwards.
62
+ - **Working-set reflex (#926/#930)**: the journaled entry replicates and the
63
+ target's wsOwnerOf journal-placement fallback finally has something to read.
64
+ - **Post-transfer closeout**: unchanged — it keys on ownership moving away, which
65
+ this block makes MORE accurate (the registry now reflects the deliberate move).
66
+ - **Ownership nonces**: fresh `tplace`/`tclaim` nonces per call; no replay overlap
67
+ with router (`:c:`/`:cl:`) or release (`:rel:`) nonce families.
68
+
69
+ ## 6. External surfaces
70
+
71
+ One additive JSON response field (`placedOwnership`). No new routes, no config,
72
+ no notifications, no Telegram. Journal entries use the existing topic-placement
73
+ kind/op-key contract (`${topic}:${epoch}` — real epochs, so no dedupe collision
74
+ with router-emitted entries).