instar 1.3.142 → 1.3.144
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 +8 -4
- package/dist/commands/server.js.map +1 -1
- package/dist/lifeline/ServerSupervisor.d.ts +18 -0
- package/dist/lifeline/ServerSupervisor.d.ts.map +1 -1
- package/dist/lifeline/ServerSupervisor.js +149 -0
- package/dist/lifeline/ServerSupervisor.js.map +1 -1
- package/dist/lifeline/TelegramLifeline.d.ts +8 -0
- package/dist/lifeline/TelegramLifeline.d.ts.map +1 -1
- package/dist/lifeline/TelegramLifeline.js +22 -0
- package/dist/lifeline/TelegramLifeline.js.map +1 -1
- package/dist/lifeline/agentSleepWake.d.ts +6 -0
- package/dist/lifeline/agentSleepWake.d.ts.map +1 -0
- package/dist/lifeline/agentSleepWake.js +33 -0
- package/dist/lifeline/agentSleepWake.js.map +1 -0
- package/dist/monitoring/SleepController.d.ts +8 -0
- package/dist/monitoring/SleepController.d.ts.map +1 -1
- package/dist/monitoring/SleepController.js +25 -0
- package/dist/monitoring/SleepController.js.map +1 -1
- package/dist/server/machineAuth.d.ts +8 -2
- package/dist/server/machineAuth.d.ts.map +1 -1
- package/dist/server/machineAuth.js +28 -2
- package/dist/server/machineAuth.js.map +1 -1
- package/package.json +1 -1
- package/src/data/builtin-manifest.json +3 -3
- package/upgrades/1.3.143.md +44 -0
- package/upgrades/1.3.144.md +53 -0
- package/upgrades/side-effects/agent-hard-sleep-mechanism.md +115 -0
- package/upgrades/side-effects/machineauth-shared-sequence.md +60 -0
|
@@ -105,16 +105,42 @@ export function machineAuthMiddleware(deps) {
|
|
|
105
105
|
next();
|
|
106
106
|
};
|
|
107
107
|
}
|
|
108
|
+
/**
|
|
109
|
+
* Process-global monotonic sequence for ALL machineAuth-signed outbound requests.
|
|
110
|
+
*
|
|
111
|
+
* The receiver's NonceStore tracks ONE monotonic sequence PER SENDING MACHINE
|
|
112
|
+
* (src/core/NonceStore.ts) — so EVERY signed channel from this process (lease
|
|
113
|
+
* broadcast, machine heartbeat, handoff, reply-marker, live-tail, …) MUST draw
|
|
114
|
+
* from a single shared counter. They previously each used their own
|
|
115
|
+
* `Date.now()`-seeded counter; the fast-firing heartbeat pushed the receiver's
|
|
116
|
+
* per-machine watermark high while the slow lease counter stayed low, so every
|
|
117
|
+
* lease broadcast was rejected as an out-of-order replay and the standby never
|
|
118
|
+
* learned the holder (found live 2026-05-31:
|
|
119
|
+
* `Sequence 1780200440053 <= last seen 1780200440744`). Seeding from `Date.now()`
|
|
120
|
+
* keeps it monotonic across a process restart (wall-clock only advances), so the
|
|
121
|
+
* receiver's persisted watermark from a prior run is never above our fresh seed.
|
|
122
|
+
*/
|
|
123
|
+
let __machineAuthSequence = Date.now();
|
|
124
|
+
/** The next process-global machineAuth sequence (strictly increasing). */
|
|
125
|
+
export function nextMachineAuthSequence() {
|
|
126
|
+
__machineAuthSequence += 1;
|
|
127
|
+
return __machineAuthSequence;
|
|
128
|
+
}
|
|
108
129
|
/**
|
|
109
130
|
* Sign an outgoing request with machine credentials.
|
|
110
131
|
*
|
|
111
132
|
* @param machineId - This machine's ID
|
|
112
133
|
* @param privateKeyPem - Ed25519 private key in PEM format
|
|
113
134
|
* @param body - The request body (will be JSON stringified for hashing)
|
|
114
|
-
* @param
|
|
135
|
+
* @param _legacySequence - IGNORED. Retained for signature compatibility with
|
|
136
|
+
* existing callers. The sequence is now drawn from the process-global
|
|
137
|
+
* `nextMachineAuthSequence()` so every channel shares one monotonic counter
|
|
138
|
+
* (see the note above — per-caller counters collided on the receiver's
|
|
139
|
+
* per-machine watermark). New callers may omit it.
|
|
115
140
|
* @returns Headers to include in the request
|
|
116
141
|
*/
|
|
117
|
-
export function signRequest(machineId, privateKeyPem, body,
|
|
142
|
+
export function signRequest(machineId, privateKeyPem, body, _legacySequence) {
|
|
143
|
+
const sequence = nextMachineAuthSequence();
|
|
118
144
|
const timestamp = Math.floor(Date.now() / 1000).toString();
|
|
119
145
|
const nonce = crypto.randomBytes(16).toString('hex');
|
|
120
146
|
const bodyHash = crypto.createHash('sha256')
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"machineAuth.js","sourceRoot":"","sources":["../../src/server/machineAuth.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"machineAuth.js","sourceRoot":"","sources":["../../src/server/machineAuth.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAGH,OAAO,MAAM,MAAM,aAAa,CAAC;AACjC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,4BAA4B,CAAC;AAyB1D,uEAAuE;AAEvE;;;;;GAKG;AACH,MAAM,UAAU,qBAAqB,CAAC,IAAqB;IACzD,OAAO,CAAC,GAAY,EAAE,GAAa,EAAE,IAAkB,EAAQ,EAAE;QAC/D,MAAM,SAAS,GAAG,GAAG,CAAC,OAAO,CAAC,cAAc,CAAuB,CAAC;QACpE,MAAM,SAAS,GAAG,GAAG,CAAC,OAAO,CAAC,aAAa,CAAuB,CAAC;QACnE,MAAM,KAAK,GAAG,GAAG,CAAC,OAAO,CAAC,SAAS,CAAuB,CAAC;QAC3D,MAAM,QAAQ,GAAG,GAAG,CAAC,OAAO,CAAC,YAAY,CAAuB,CAAC;QACjE,MAAM,SAAS,GAAG,GAAG,CAAC,OAAO,CAAC,aAAa,CAAuB,CAAC;QAEnE,iCAAiC;QACjC,IAAI,CAAC,SAAS,IAAI,CAAC,SAAS,IAAI,CAAC,KAAK,IAAI,CAAC,QAAQ,IAAI,CAAC,SAAS,EAAE,CAAC;YAClE,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,wCAAwC,EAAE,CAAC,CAAC;YAC1E,OAAO;QACT,CAAC;QAED,4CAA4C;QAC5C,MAAM,QAAQ,GAAG,IAAI,CAAC,eAAe,CAAC,YAAY,EAAE,CAAC;QACrD,MAAM,KAAK,GAAG,QAAQ,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC;QAC3C,IAAI,CAAC,KAAK,IAAI,KAAK,CAAC,MAAM,KAAK,QAAQ,EAAE,CAAC;YACxC,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC;gBACtB,KAAK,EAAE,eAAe;gBACtB,SAAS;gBACT,MAAM,EAAE,KAAK,CAAC,CAAC,CAAC,mBAAmB,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,iBAAiB;gBACrE,EAAE,EAAE,GAAG,CAAC,EAAE,IAAI,GAAG,CAAC,MAAM,CAAC,aAAa,IAAI,SAAS;aACpD,CAAC,CAAC;YACH,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,wBAAwB,EAAE,CAAC,CAAC;YAC1D,OAAO;QACT,CAAC;QAED,8EAA8E;QAC9E,MAAM,MAAM,GAAG,QAAQ,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;QACtC,IAAI,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC;YAClB,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,yBAAyB,EAAE,CAAC,CAAC;YAC3D,OAAO;QACT,CAAC;QAED,MAAM,WAAW,GAAG,IAAI,CAAC,UAAU,CAAC,QAAQ,CAC1C,QAAQ,CAAC,SAAS,EAAE,EAAE,CAAC,GAAG,IAAI,EAAE,6BAA6B;QAC7D,KAAK,EACL,MAAM,EACN,SAAS,CACV,CAAC;QAEF,IAAI,CAAC,WAAW,CAAC,KAAK,EAAE,CAAC;YACvB,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC;gBACtB,KAAK,EAAE,iBAAiB;gBACxB,SAAS;gBACT,MAAM,EAAE,WAAW,CAAC,MAAM;gBAC1B,EAAE,EAAE,GAAG,CAAC,EAAE,IAAI,GAAG,CAAC,MAAM,CAAC,aAAa,IAAI,SAAS;aACpD,CAAC,CAAC;YACH,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,6BAA6B,WAAW,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;YACnF,OAAO;QACT,CAAC;QAED,8BAA8B;QAC9B,MAAM,QAAQ,GAAG,MAAM,CAAC,UAAU,CAAC,QAAQ,CAAC;aACzC,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;aACtC,MAAM,CAAC,KAAK,CAAC,CAAC;QACjB,MAAM,aAAa,GAAG,GAAG,SAAS,IAAI,SAAS,IAAI,KAAK,IAAI,QAAQ,IAAI,QAAQ,EAAE,CAAC;QAEnF,2CAA2C;QAC3C,MAAM,YAAY,GAAG,IAAI,CAAC,eAAe,CAAC,sBAAsB,CAAC,SAAS,CAAC,CAAC;QAC5E,IAAI,CAAC,YAAY,EAAE,CAAC;YAClB,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,8BAA8B,EAAE,CAAC,CAAC;YAChE,OAAO;QACT,CAAC;QAED,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,MAAM,CAAC,aAAa,EAAE,SAAS,EAAE,YAAY,CAAC,CAAC;YAC/D,IAAI,CAAC,OAAO,EAAE,CAAC;gBACb,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC;oBACtB,KAAK,EAAE,mBAAmB;oBAC1B,SAAS;oBACT,EAAE,EAAE,GAAG,CAAC,EAAE,IAAI,GAAG,CAAC,MAAM,CAAC,aAAa,IAAI,SAAS;iBACpD,CAAC,CAAC;gBACH,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,mBAAmB,EAAE,CAAC,CAAC;gBACrD,OAAO;YACT,CAAC;QACH,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC;gBACtB,KAAK,EAAE,iBAAiB;gBACxB,SAAS;gBACT,KAAK,EAAE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC;gBACvD,EAAE,EAAE,GAAG,CAAC,EAAE,IAAI,GAAG,CAAC,MAAM,CAAC,aAAa,IAAI,SAAS;aACpD,CAAC,CAAC;YACH,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,+BAA+B,EAAE,CAAC,CAAC;YACjE,OAAO;QACT,CAAC;QAED,6CAA6C;QAC5C,GAAW,CAAC,WAAW,GAAG;YACzB,SAAS;YACT,QAAQ,EAAE,MAAM;SACY,CAAC;QAE/B,IAAI,EAAE,CAAC;IACT,CAAC,CAAC;AACJ,CAAC;AAYD;;;;;;;;;;;;;;GAcG;AACH,IAAI,qBAAqB,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;AACvC,0EAA0E;AAC1E,MAAM,UAAU,uBAAuB;IACrC,qBAAqB,IAAI,CAAC,CAAC;IAC3B,OAAO,qBAAqB,CAAC;AAC/B,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,WAAW,CACzB,SAAiB,EACjB,aAAqB,EACrB,IAAa,EACb,eAAwB;IAExB,MAAM,QAAQ,GAAG,uBAAuB,EAAE,CAAC;IAC3C,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC,QAAQ,EAAE,CAAC;IAC3D,MAAM,KAAK,GAAG,MAAM,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;IACrD,MAAM,QAAQ,GAAG,MAAM,CAAC,UAAU,CAAC,QAAQ,CAAC;SACzC,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;SAClC,MAAM,CAAC,KAAK,CAAC,CAAC;IAEjB,MAAM,OAAO,GAAG,GAAG,SAAS,IAAI,SAAS,IAAI,KAAK,IAAI,QAAQ,IAAI,QAAQ,EAAE,CAAC;IAC7E,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,EAAE,aAAa,CAAC,CAAC;IAEzC,OAAO;QACL,cAAc,EAAE,SAAS;QACzB,aAAa,EAAE,SAAS;QACxB,SAAS,EAAE,KAAK;QAChB,YAAY,EAAE,QAAQ,CAAC,QAAQ,EAAE;QACjC,aAAa,EAAE,GAAG;KACnB,CAAC;AACJ,CAAC;AAaD;;;GAGG;AACH,MAAM,OAAO,cAAc;IACjB,UAAU,GAAG,IAAI,GAAG,EAAqB,CAAC;IAC1C,YAAY,CAAiC;IAErD;QACE,+CAA+C;QAC/C,IAAI,CAAC,YAAY,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,OAAO,EAAE,EAAE,MAAM,CAAC,CAAC;QAC9D,IAAI,IAAI,CAAC,YAAY,CAAC,KAAK;YAAE,IAAI,CAAC,YAAY,CAAC,KAAK,EAAE,CAAC;IACzD,CAAC;IAED,8DAA8D;IAC9D,QAAQ;QACN,MAAM,SAAS,GAAc;YAC3B,SAAS,EAAE,MAAM,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC;YACjD,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,MAAM,EAAE,aAAa;YAC7C,QAAQ,EAAE,KAAK;SAChB,CAAC;QACF,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,SAAS,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC;QACpD,OAAO,SAAS,CAAC;IACnB,CAAC;IAED;;;OAGG;IACH,OAAO,CAAC,YAAoB;QAC1B,MAAM,SAAS,GAAG,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC;QACpD,IAAI,CAAC,SAAS;YAAE,OAAO,KAAK,CAAC;QAC7B,IAAI,SAAS,CAAC,QAAQ;YAAE,OAAO,KAAK,CAAC;QACrC,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,CAAC,SAAS,EAAE,CAAC;YACrC,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC;YACrC,OAAO,KAAK,CAAC;QACf,CAAC;QACD,SAAS,CAAC,QAAQ,GAAG,IAAI,CAAC;QAC1B,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC;QACrC,OAAO,IAAI,CAAC;IACd,CAAC;IAED,mCAAmC;IAC3B,OAAO;QACb,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACvB,KAAK,MAAM,CAAC,GAAG,EAAE,SAAS,CAAC,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC;YAC/C,IAAI,GAAG,GAAG,SAAS,CAAC,SAAS,EAAE,CAAC;gBAC9B,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YAC9B,CAAC;QACH,CAAC;IACH,CAAC;IAED,8BAA8B;IAC9B,OAAO;QACL,aAAa,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;IACnC,CAAC;CACF"}
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "./builtin-manifest.schema.json",
|
|
3
3
|
"schemaVersion": 1,
|
|
4
|
-
"generatedAt": "2026-05-31T04:
|
|
5
|
-
"instarVersion": "1.3.
|
|
4
|
+
"generatedAt": "2026-05-31T04:48:35.698Z",
|
|
5
|
+
"instarVersion": "1.3.144",
|
|
6
6
|
"entryCount": 193,
|
|
7
7
|
"entries": {
|
|
8
8
|
"hook:session-start": {
|
|
@@ -1521,7 +1521,7 @@
|
|
|
1521
1521
|
"type": "subsystem",
|
|
1522
1522
|
"domain": "communication",
|
|
1523
1523
|
"sourcePath": "src/lifeline/TelegramLifeline.ts",
|
|
1524
|
-
"contentHash": "
|
|
1524
|
+
"contentHash": "6105f8a126654011c81e900be2c049ff52dc1b9b369831432ad910a9650dc84e",
|
|
1525
1525
|
"since": "2025-01-01"
|
|
1526
1526
|
},
|
|
1527
1527
|
"subsystem:orphan-process-reaper": {
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# Upgrade Guide — vNEXT
|
|
2
|
+
|
|
3
|
+
<!-- bump: patch -->
|
|
4
|
+
|
|
5
|
+
## What Changed
|
|
6
|
+
|
|
7
|
+
**Multi-machine: fixes the next bug blocking cross-machine session transfer.**
|
|
8
|
+
When two machines talk, each message carries an ever-increasing number so the
|
|
9
|
+
receiver can reject replayed old messages. A machine has several lines of
|
|
10
|
+
communication to its peer (the in-charge lease, the heartbeat, handoffs, the live
|
|
11
|
+
tail), and each kept its own number seeded from the clock — so they drifted apart.
|
|
12
|
+
The receiver only tracks one highest-number-seen per machine, so the fast
|
|
13
|
+
heartbeat pushed that number high and the quieter lease line's messages then
|
|
14
|
+
looked out-of-order and were dropped as replays. The standby machine therefore
|
|
15
|
+
never received the lease announcement and refused to take over a conversation.
|
|
16
|
+
This change makes every line on a machine share ONE ever-increasing number from a
|
|
17
|
+
single chokepoint, so legitimate messages are never mistaken for replays. The
|
|
18
|
+
receiver's replay protection (unique tokens + a 30-second freshness window + the
|
|
19
|
+
per-machine number) is unchanged. Single-machine agents are unaffected.
|
|
20
|
+
|
|
21
|
+
## What to Tell Your User
|
|
22
|
+
|
|
23
|
+
If you run on one machine, nothing changes. If you run one agent across two
|
|
24
|
+
machines, this fixes a hidden issue where the second machine was silently dropping
|
|
25
|
+
the messages that tell it which machine is in charge — a step toward moving a
|
|
26
|
+
conversation between machines working end to end. Nothing to configure.
|
|
27
|
+
|
|
28
|
+
## Summary of New Capabilities
|
|
29
|
+
|
|
30
|
+
| Capability | How to Use |
|
|
31
|
+
|-----------|-----------|
|
|
32
|
+
| Shared machine-auth sequence | Automatic. All of a machine's signed peer requests now share one monotonic sequence, so the lease/heartbeat/handoff/live-tail channels no longer collide on the receiver's per-machine replay watermark. No configuration. |
|
|
33
|
+
|
|
34
|
+
## Evidence
|
|
35
|
+
|
|
36
|
+
- `tests/unit/machine-auth.test.ts` (21) updated to the new chokepoint contract,
|
|
37
|
+
plus a regression: two channels signing via signRequest stay strictly monotonic
|
|
38
|
+
(no cross-transport collision), and a direct NonceStore stale-sequence-rejection
|
|
39
|
+
test (receiver behavior preserved).
|
|
40
|
+
- `tests/integration/machine-routes.test.ts` (23) green — no sequence regression.
|
|
41
|
+
- `tsc --noEmit` + repo lint clean.
|
|
42
|
+
- Live evidence that motivated it: the standby's security log showed
|
|
43
|
+
"Sequence …053 <= last seen …744" rejecting every lease broadcast.
|
|
44
|
+
- Side-effects: `upgrades/side-effects/machineauth-shared-sequence.md`.
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# Upgrade Guide — vNEXT
|
|
2
|
+
|
|
3
|
+
<!-- bump: patch -->
|
|
4
|
+
|
|
5
|
+
## What Changed
|
|
6
|
+
|
|
7
|
+
**Agent hard-sleep can now actually stop and wake the server (dark + dry-run).**
|
|
8
|
+
The previous step taught an idle agent how to DECIDE whether it is safe to sleep but
|
|
9
|
+
never acted. This step builds the mechanism that acts on that decision: when sleep is
|
|
10
|
+
enabled and the agent is deeply idle and safe, its heavy background server is
|
|
11
|
+
stopped to save the machine's resources, and it wakes the instant a message arrives.
|
|
12
|
+
|
|
13
|
+
The handshake reuses the proven restart lifecycle: the decision layer writes a
|
|
14
|
+
sleep-request file, the supervisor stops the server and marks it intentionally
|
|
15
|
+
asleep (so it is NOT treated as a crash and is NOT auto-restarted), and an inbound
|
|
16
|
+
message makes the lifeline write a wake-request that the supervisor honors by
|
|
17
|
+
respawning the server. The waiting message is held in the existing durable queue and
|
|
18
|
+
delivered once the server is healthy, so nothing is lost. A safety marker means that
|
|
19
|
+
even if an outside watchdog force-restarts the agent mid-sleep, it reads the marker
|
|
20
|
+
on startup and stays asleep instead of fighting it. The existing crash-recovery
|
|
21
|
+
behavior is unchanged except in the one case where the agent chose to sleep, proven
|
|
22
|
+
by the existing supervisor tests staying green.
|
|
23
|
+
|
|
24
|
+
## What to Tell Your User
|
|
25
|
+
|
|
26
|
+
Nothing changes on any normal agent — this ships off by default, and the file that
|
|
27
|
+
triggers a sleep is only ever written when sleep is explicitly turned on. The future
|
|
28
|
+
ability it builds toward: a completely idle agent quiets its server to save your
|
|
29
|
+
machine, then wakes the moment you message it, holding your message until it is back
|
|
30
|
+
up. Turning it on is a deliberate step we would validate on one test agent first.
|
|
31
|
+
|
|
32
|
+
## Summary of New Capabilities
|
|
33
|
+
|
|
34
|
+
- ServerSupervisor honors a sleep-request by stopping the server and entering an
|
|
35
|
+
intentionally-asleep state that suppresses auto-respawn; honors a wake-request by
|
|
36
|
+
respawning. A slept-marker keeps a rebooted (or watchdog-bounced) supervisor asleep.
|
|
37
|
+
- The decision layer writes a TTL-stamped sleep-request only in live mode.
|
|
38
|
+
- The lifeline writes a wake-request on the next inbound message when the server is
|
|
39
|
+
asleep; the existing forward-retry queue replays the held message after wake.
|
|
40
|
+
- All gated by the existing monitoring.agentSleep config — OFF + dry-run by default.
|
|
41
|
+
|
|
42
|
+
## Evidence
|
|
43
|
+
|
|
44
|
+
- `tests/unit/ServerSupervisor-sleep-wake.test.ts` — sleep stops + marks + enters
|
|
45
|
+
slept; no-request no-op; expired-request ignored; wake respawns + clears; wake-when-
|
|
46
|
+
not-slept no-op; idempotent re-sleep; boot-marker signal.
|
|
47
|
+
- `tests/unit/agentSleepWake.test.ts` — marker present writes the wake-request; no
|
|
48
|
+
marker is a no-op (steady-state awake never writes).
|
|
49
|
+
- `tests/unit/SleepController.test.ts` — sleepRequestWriter writes the TTL-stamped flag.
|
|
50
|
+
- Regression: the existing ServerSupervisor-handshake / supervisor-health-check /
|
|
51
|
+
supervisor-cpu-starvation suites stay green — the slept short-circuit is the only
|
|
52
|
+
loop-flow change and is a no-op until a live sleep-request is honored.
|
|
53
|
+
- Side-effects: `upgrades/side-effects/agent-hard-sleep-mechanism.md`.
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
# Side-Effects Review — Agent hard-sleep stop+wake mechanism (Stage B, slice 2)
|
|
2
|
+
|
|
3
|
+
**Version / slug:** `agent-hard-sleep-mechanism`
|
|
4
|
+
**Date:** `2026-05-31`
|
|
5
|
+
**Author:** `echo`
|
|
6
|
+
**Second-pass reviewer:** `adversarial review performed — found a critical brick (wake-trigger gated on health) + a broken manual escape hatch; BOTH fixed + tested before commit. Concurs the dark code is inert. Enablement remains the reviewed gate (live on a test agent with Justin watching).`
|
|
7
|
+
|
|
8
|
+
## Summary of the change
|
|
9
|
+
|
|
10
|
+
Acts on the slice-1 SleepController verdict: in live mode it writes
|
|
11
|
+
`state/sleep-requested.json`; the ServerSupervisor honors it by stopping the server
|
|
12
|
+
tmux session and entering a `slept` state; the health loop then short-circuits
|
|
13
|
+
(suppressing auto-respawn) and only watches for `state/wake-requested.json`, which
|
|
14
|
+
the TelegramLifeline writes on the next inbound message → the supervisor respawns
|
|
15
|
+
the server and the existing forward-retry queue replays the buffered message. Files:
|
|
16
|
+
`SleepController.ts` (+`sleepRequestWriter`), `ServerSupervisor.ts`
|
|
17
|
+
(checkSleepRequest/checkWakeRequest/`slept` guard/boot-marker), `TelegramLifeline.ts`
|
|
18
|
+
(+`requestWakeIfSlept` via the pure `agentSleepWake.ts` helper). No new config (the
|
|
19
|
+
slice-1 `monitoring.agentSleep` gates it), no new route, no agent-installed file.
|
|
20
|
+
|
|
21
|
+
## Decision-point inventory
|
|
22
|
+
|
|
23
|
+
- `ServerSupervisor` health-loop control flow — modify — adds ONE short-circuit: `if (slept) { checkWakeRequest(); return; }` at the loop top.
|
|
24
|
+
- `ServerSupervisor.checkSleepRequest` / `checkWakeRequest` — add — the stop/respawn handlers (mirror checkRestartRequest).
|
|
25
|
+
- `ServerSupervisor` boot — modify — reads `slept-marker.json` to stay asleep across a supervisor reboot.
|
|
26
|
+
- `SleepController.requestSleep` consumer — add — `sleepRequestWriter` (live-mode only).
|
|
27
|
+
- `TelegramLifeline.forwardToServer` — pass-through — prepends a non-blocking `requestWakeIfSlept()` side-call.
|
|
28
|
+
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
## 1. Over-block
|
|
32
|
+
|
|
33
|
+
No block/allow surface over messages. The only "blocking-like" behavior is the
|
|
34
|
+
`slept` short-circuit suppressing auto-respawn — which is exactly intended and gated
|
|
35
|
+
on `slept`, set only after a live sleep-request is honored. A genuine crash (slept
|
|
36
|
+
=== false) still flows through the unchanged `evaluateUnhealthyServer` path.
|
|
37
|
+
|
|
38
|
+
## 2. Under-block
|
|
39
|
+
|
|
40
|
+
Could the server fail to wake (the brick risk)? **The adversarial second-pass review
|
|
41
|
+
caught a real brick in the first cut and it was fixed:** the wake-trigger was
|
|
42
|
+
originally placed inside `forwardToServer()`, which is gated on `supervisor.healthy`
|
|
43
|
+
— but a slept server is not healthy, so an inbound message took the "server down →
|
|
44
|
+
queue" path and never wrote `wake-requested.json` → the server would never wake.
|
|
45
|
+
**Fix:** `requestWakeIfSlept()` now runs at the TOP of `processUpdate()`, before any
|
|
46
|
+
health gate, so EVERY inbound update writes the wake flag when slept (covered by the
|
|
47
|
+
helper test + the corrected call-site). The review also caught that `/lifeline
|
|
48
|
+
restart` (the manual escape hatch) didn't clear the slept-marker, so a manual restart
|
|
49
|
+
re-read the marker and re-slept — **fixed** via `ServerSupervisor.wakeFromSleep()`,
|
|
50
|
+
called from both `/lifeline restart` and `/lifeline reset` (tested).
|
|
51
|
+
|
|
52
|
+
Remaining wake robustness: the supervisor checks the wake flag every 10s while slept;
|
|
53
|
+
a single missed flag write self-heals on the next inbound; a fleet-watchdog mid-sleep
|
|
54
|
+
bounce stays asleep via the boot-marker AND wakes on the next inbound. The
|
|
55
|
+
scheduler-wake (a cron job due during sleep) is the one tracked gap (conservative-null
|
|
56
|
+
for now), enablement-gated — dark default means no real agent is affected.
|
|
57
|
+
|
|
58
|
+
## 3. Level-of-abstraction fit
|
|
59
|
+
|
|
60
|
+
Correct. The mechanism reuses the proven `restart-requested.json` lifecycle shape
|
|
61
|
+
(file flag consumed in the health loop) rather than inventing a new lifecycle; the
|
|
62
|
+
stop is the existing tmux `kill-session`, the wake is the existing `spawnServer()`.
|
|
63
|
+
The lifeline wake-trigger is extracted into a pure, unit-tested helper
|
|
64
|
+
(`writeWakeRequestIfSlept`) rather than buried in the un-testable heavy class.
|
|
65
|
+
|
|
66
|
+
## 4. Signal vs authority compliance
|
|
67
|
+
|
|
68
|
+
**Required reference:** [docs/signal-vs-authority.md](../../docs/signal-vs-authority.md)
|
|
69
|
+
|
|
70
|
+
- [x] No — the SleepController remains the decision-maker (signal, with all guards);
|
|
71
|
+
this slice is the mechanism it drives. The stop IS an authority (stops a process),
|
|
72
|
+
but it is gated exactly like a planned restart: positive proof (the slice-1
|
|
73
|
+
would-sleep verdict with every guard), ships OFF + dry-run, never fires unless
|
|
74
|
+
enabled && !dryRun, and KEEPs-awake on any ambiguity upstream.
|
|
75
|
+
|
|
76
|
+
## 5. Interactions
|
|
77
|
+
|
|
78
|
+
- **Shadowing:** the `slept` short-circuit runs before the health/restart logic; it
|
|
79
|
+
is a no-op when `slept===false` (always, until a live sleep-request lands), so it
|
|
80
|
+
cannot shadow the existing restart/health paths in normal operation. Verified by
|
|
81
|
+
the unchanged `ServerSupervisor-handshake` + `supervisor-health-check` suites.
|
|
82
|
+
- **Double-fire:** sleep is idempotent (`checkSleepRequest` early-returns when
|
|
83
|
+
already slept); wake is idempotent (early-returns when not slept). The
|
|
84
|
+
`sleep-requested`/`wake-requested` flags are consumed on read.
|
|
85
|
+
- **Races:** the fleet watchdog vs sleep — resolved by the boot-marker (reboot stays
|
|
86
|
+
asleep). The lifeline writing a wake flag while the supervisor is mid-respawn —
|
|
87
|
+
harmless (the supervisor clears `slept` first, so a redundant wake flag is consumed
|
|
88
|
+
next tick as a no-op).
|
|
89
|
+
- **Feedback loops:** none — the flags are one-shot, consumed by the consumer.
|
|
90
|
+
|
|
91
|
+
## 6. External surfaces
|
|
92
|
+
|
|
93
|
+
- **Install base:** pure additive source, no config/route/agent-installed-file
|
|
94
|
+
change → every agent picks it up on update; behavior is byte-identical until
|
|
95
|
+
`monitoring.agentSleep` is enabled live. The slice-1 dark default holds.
|
|
96
|
+
- **Other agents / external systems:** none.
|
|
97
|
+
- **Persistent state:** three transient `state/*.json` flags + one `slept-marker.json`
|
|
98
|
+
(best-effort, consumed/removed by the supervisor).
|
|
99
|
+
- **Timing:** the existing 10s health tick; no new timer.
|
|
100
|
+
|
|
101
|
+
## 7. Rollback cost
|
|
102
|
+
|
|
103
|
+
Pure additive code, no config/migration. Revert → `checkSleepRequest` /
|
|
104
|
+
`checkWakeRequest` / the `slept` guard / the lifeline side-call disappear; the
|
|
105
|
+
supervisor + lifeline behave exactly as before. No persistent state needs cleanup
|
|
106
|
+
(the flags are transient). No user-visible change during rollback (dark by default).
|
|
107
|
+
|
|
108
|
+
## Conclusion
|
|
109
|
+
|
|
110
|
+
This review confirmed the mechanism is a tightly-scoped, additive layer on the
|
|
111
|
+
proven restart lifecycle, with ONE load-bearing change (the `slept` short-circuit)
|
|
112
|
+
that is a no-op until a live sleep-request is honored and is regression-covered by
|
|
113
|
+
the existing supervisor suites. The brick risk is closed at multiple layers
|
|
114
|
+
(per-forward wake re-write, 10s wake poll, boot-stay-asleep marker). It ships dark;
|
|
115
|
+
the enablement (turning sleep ON) is the reviewed validation step on a test agent.
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# Side-Effects Review — machineAuth shared monotonic sequence
|
|
2
|
+
|
|
3
|
+
**Version / slug:** `machineauth-shared-sequence`
|
|
4
|
+
**Date:** `2026-05-31`
|
|
5
|
+
**Author:** `echo`
|
|
6
|
+
**Second-pass reviewer:** `not required`
|
|
7
|
+
|
|
8
|
+
## Summary of the change
|
|
9
|
+
|
|
10
|
+
`signRequest` (the single function every machineAuth-signed outbound request flows
|
|
11
|
+
through) now assigns the X-Sequence from a process-global monotonic counter
|
|
12
|
+
(`nextMachineAuthSequence()`, seeded from `Date.now()`) instead of the per-caller
|
|
13
|
+
`sequence` argument (now ignored). Fixes the cross-transport replay collision: the
|
|
14
|
+
receiver tracks one monotonic sequence per sending machine, but each channel had
|
|
15
|
+
its own `Date.now()`-seeded counter, so a lower-seeded channel (the lease
|
|
16
|
+
broadcast) was rejected as out-of-order forever.
|
|
17
|
+
|
|
18
|
+
## Decision-point inventory
|
|
19
|
+
|
|
20
|
+
1. **signRequest sequence source** → always `nextMachineAuthSequence()` (global,
|
|
21
|
+
monotonic), regardless of the passed arg.
|
|
22
|
+
|
|
23
|
+
## 1. Over-block
|
|
24
|
+
|
|
25
|
+
**What legitimate inputs does this reject?** None — it makes MORE requests succeed.
|
|
26
|
+
Previously-rejected legitimate lease broadcasts now pass. The receiver's replay
|
|
27
|
+
defenses are unchanged: nonce uniqueness + 30s timestamp window + per-machine
|
|
28
|
+
monotonic sequence all still run. A genuine replay (reused nonce, or stale
|
|
29
|
+
timestamp, or a sequence below the watermark) is still rejected exactly as before.
|
|
30
|
+
|
|
31
|
+
## 2. Under-block
|
|
32
|
+
|
|
33
|
+
**What does this still miss?** Nothing new. Anti-replay strength is unchanged; the
|
|
34
|
+
fix only makes a single sender's many channels share one monotonic sequence
|
|
35
|
+
(which is what the per-machine watermark always assumed). Cross-MACHINE replay is
|
|
36
|
+
still caught (each machine has its own watermark on the receiver).
|
|
37
|
+
|
|
38
|
+
## 3. Blast radius
|
|
39
|
+
|
|
40
|
+
- `signRequest` is used by every machineAuth sender: lease broadcast, heartbeat,
|
|
41
|
+
handoff, reply-marker, live-tail, MessageRouter relay, and the `instar pair`/
|
|
42
|
+
handoff CLI. ALL now share the global counter — this is the intended fix (the
|
|
43
|
+
chokepoint guarantees no caller can bypass it).
|
|
44
|
+
- The per-caller sequence counters in server.ts / MessageRouter become inert
|
|
45
|
+
(their value is ignored); left in place to minimize churn — harmless dead args.
|
|
46
|
+
- Tests: `machine-auth.test.ts` (21) updated to the new contract + a regression
|
|
47
|
+
for the interleaved-channel monotonicity + a direct NonceStore stale-rejection
|
|
48
|
+
test. `machine-routes.test.ts` integration (23) green. tsc + lint clean.
|
|
49
|
+
|
|
50
|
+
## 4. Rollback
|
|
51
|
+
|
|
52
|
+
Pure code (no migration/config/schema). Rollback = revert the PR. The sequence
|
|
53
|
+
reverts to per-caller, re-introducing the collision (so don't revert without
|
|
54
|
+
re-introducing bug #3).
|
|
55
|
+
|
|
56
|
+
## 5. Failure modes
|
|
57
|
+
|
|
58
|
+
- Process restart → counter re-seeds from the new (higher) `Date.now()`, still
|
|
59
|
+
above any prior watermark. Monotonic across restarts by construction.
|
|
60
|
+
- Concurrency → single-threaded JS; `nextMachineAuthSequence` increments atomically.
|