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.
- package/dist/commands/server.d.ts.map +1 -1
- package/dist/commands/server.js +36 -0
- package/dist/commands/server.js.map +1 -1
- package/dist/config/ConfigDefaults.d.ts.map +1 -1
- package/dist/config/ConfigDefaults.js +6 -0
- package/dist/config/ConfigDefaults.js.map +1 -1
- package/dist/core/types.d.ts +12 -0
- package/dist/core/types.d.ts.map +1 -1
- package/dist/core/types.js.map +1 -1
- package/dist/server/BootHealthBeacon.d.ts +40 -0
- package/dist/server/BootHealthBeacon.d.ts.map +1 -0
- package/dist/server/BootHealthBeacon.js +90 -0
- package/dist/server/BootHealthBeacon.js.map +1 -0
- package/package.json +1 -1
- package/src/data/builtin-manifest.json +2 -2
- package/upgrades/1.3.418.md +47 -0
- package/upgrades/side-effects/health-first-boot.md +79 -0
|
@@ -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.
|