instar 1.3.417 → 1.3.418

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,47 @@
1
+ # Upgrade Guide — vNEXT
2
+
3
+ <!-- assembled-by: assemble-next-md -->
4
+ <!-- bump: patch -->
5
+
6
+ ## What Changed
7
+
8
+ Adds a **boot health beacon** — the durable cure for the 2026-06-07 "server
9
+ temporarily down" restart loop (topic 21816 root cause #1, "Liveness Before Load").
10
+ The server boot loads large TopicMemory/SemanticMemory + reconciles sessions BEFORE
11
+ AgentServer binds its port, so for minutes nothing answers `/health` and the
12
+ supervisor can mistake a slow boot for a dead process → restart-before-boot loop.
13
+
14
+ `BootHealthBeacon` (`src/server/BootHealthBeacon.ts`) is a minimal HTTP listener
15
+ that answers `/health` from the very start of boot and is closed at the handoff
16
+ just before the real server binds (force-closing sockets so there's no EADDRINUSE).
17
+ Wired in `commands/server.ts`, gated by `monitoring.bootHealthBeacon.enabled`
18
+ (default OFF). The startupGrace bump (#979) covers the window until this is enabled.
19
+
20
+ ## What to Tell Your User
21
+
22
+ If an agent ever sat in a restart loop right after an update on a busy machine,
23
+ showing "server temporarily down" — this is the deeper, permanent fix: the server
24
+ now (when enabled) reports it's alive from the first second of boot, so a slow
25
+ startup can't be mistaken for a crash. Ships off; rolled out carefully.
26
+
27
+ ## Summary of New Capabilities
28
+
29
+ - `monitoring.bootHealthBeacon.enabled` (default false): when true, a minimal
30
+ `/health` responder answers during boot and hands the port to the real server at
31
+ listen time. Off ⇒ no behavior change.
32
+
33
+ ## Evidence
34
+
35
+ `tests/unit/BootHealthBeacon.test.ts` (4 tests, all passing — incl. the port
36
+ handoff). `tsc --noEmit` clean. Boot wiring placed in the universal foreground boot
37
+ path (daemon re-execs into `--foreground`, verified). causalAutopsy: latent — the
38
+ health-bound-after-heavy-load boot order was always present, harmful only once
39
+ memory/session volume on a loaded box pushed boot past the supervisor's window.
40
+
41
+ ## Scope (honest)
42
+
43
+ Ships DARK (default off) — zero behavior change until enabled. Additive: a new
44
+ isolated module + an import + two guarded blocks in the boot + an optional config
45
+ field. NOT a risky whole-boot reorder. The interim grace bump (#979) already
46
+ stopped the live loop; this is the durable belt-and-suspenders. Live canary
47
+ verification (flag on, watch /health during a real boot) is the rollout step.
@@ -0,0 +1,79 @@
1
+ # Side-Effects Review — health-first boot (boot health beacon)
2
+
3
+ **Version / slug:** `health-first-boot`
4
+ **Date:** `2026-06-07`
5
+ **Author:** `Echo`
6
+ **Tier:** 1 (ships DARK behind `monitoring.bootHealthBeacon.enabled`, default OFF — zero behavior change until enabled; additive; both-sides tested)
7
+ **Second-pass reviewer:** `Echo (self) — Tier-1; dark/off-by-default, additive, isolated module; the boot-wiring placement was carefully traced (foreground/daemon fork resolved)`
8
+
9
+ ## Summary of the change
10
+
11
+ The durable cure for the 2026-06-07 "server temporarily down" restart loop (topic
12
+ 21816, root cause #1 — "Liveness Before Load"). The server boot loads large
13
+ TopicMemory/SemanticMemory + reconciles dozens of sessions BEFORE AgentServer
14
+ binds its port, so for ~5-6 min under load nothing answers `/health` and the
15
+ supervisor can mistake a slow boot for a dead process → restart-before-boot loop.
16
+
17
+ Adds `BootHealthBeacon` (`src/server/BootHealthBeacon.ts`): a minimal HTTP listener
18
+ that answers `/health` 200 (and 503 `warming` to everything else) from the very
19
+ start of boot. Wired in `commands/server.ts`: started right after `setupServerLog`
20
+ (early, common/universal boot path — daemon mode re-execs into `--foreground`,
21
+ verified at server.ts:12463), and **closed at the handoff immediately before**
22
+ `server.start()` (AgentServer's listen). `stop()` force-closes lingering sockets +
23
+ awaits the socket close, so the real `listen` cannot hit EADDRINUSE and the gap is
24
+ sub-second. Config flag `monitoring.bootHealthBeacon.enabled` (default OFF) +
25
+ type + ConfigDefaults. The startupGrace bump (#979) covers the window until this is
26
+ turned on.
27
+
28
+ ## Decision-point inventory
29
+
30
+ - Enabled? `monitoring.bootHealthBeacon.enabled` — default OFF; absent ⇒ off (read
31
+ via optional chaining). The only gate.
32
+ - Where to start/stop the beacon (boot-order placement) — the load-bearing
33
+ decision; see Blast radius.
34
+
35
+ ## 1. Beacon fails to start
36
+
37
+ Wrapped in try/catch — non-fatal. Boot proceeds without the beacon (the grace bump
38
+ still covers the window). The server is never blocked from booting by a beacon
39
+ problem. Both guards (start + stop) log the error and are marked
40
+ `@silent-fallback-ok` (intentional best-effort fallback, not a silent swallow) so
41
+ the no-silent-fallbacks ratchet stays at its baseline.
42
+
43
+ ## 2. Handoff race (EADDRINUSE on the real listen)
44
+
45
+ `stop()` calls `server.close()` AND `closeAllConnections()` and awaits the `close`
46
+ event, so the port is released before `server.start()` binds it. `keepAliveTimeout=1`
47
+ prevents an idle keep-alive socket from holding the port. The unit test asserts a
48
+ real server can bind the same port immediately after `stop()`. The `stop()` call is
49
+ also try/caught so a stop failure still lets the real server attempt to bind.
50
+
51
+ ## 3. Wrong boot-order placement (silent no-op)
52
+
53
+ The start is placed in the **common** boot path: the `if (options.foreground)`
54
+ block is the universal server boot — daemon mode spawns the server with
55
+ `--foreground` (server.ts:12463), so every real server runs it. `bootBeacon` is
56
+ declared at the foreground-block body scope (indent-4), in scope at both the start
57
+ (after setupServerLog) and the stop (before server.start at the same scope). Started
58
+ before the heavy memory/session loads, so it covers the whole window.
59
+
60
+ ## 4. Blast radius
61
+
62
+ DARK (default off) ⇒ zero behavior change for every existing and new agent until the
63
+ flag is explicitly set. When enabled: one extra short-lived HTTP listener during
64
+ boot that is closed before the real server binds. It only ever *adds* a liveness
65
+ answer during boot; it cannot make a healthy server look unhealthy. Rollout:
66
+ dark → canary on Echo (flip flag, watch one boot) → fleet.
67
+
68
+ ## 5. Rollback
69
+
70
+ Set the flag off (or absent) ⇒ fully inert. Code revert is clean (new module + an
71
+ import + two guarded blocks + an optional config field). No state/format change.
72
+
73
+ ## 6. Tests
74
+
75
+ `tests/unit/BootHealthBeacon.test.ts` (4): /health→200 ok while booting; everything
76
+ else→503 warming; **stop() releases the port so a real server binds it immediately**
77
+ (the handoff); start/stop idempotent. tsc clean. The boot wiring is exercised by the
78
+ existing server e2e on the default (off) path (no behavior change); live canary
79
+ verification (flag on, observe /health during a real boot) is the rollout step.