instar 1.3.861 → 1.3.863
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 +49 -1
- package/dist/commands/server.js.map +1 -1
- package/dist/core/SessionPoolLocalClaim.d.ts +24 -0
- package/dist/core/SessionPoolLocalClaim.d.ts.map +1 -0
- package/dist/core/SessionPoolLocalClaim.js +38 -0
- package/dist/core/SessionPoolLocalClaim.js.map +1 -0
- package/dist/lifeline/TelegramLifeline.d.ts.map +1 -1
- package/dist/lifeline/TelegramLifeline.js +7 -15
- package/dist/lifeline/TelegramLifeline.js.map +1 -1
- package/dist/lifeline/queuedNotice.d.ts +31 -0
- package/dist/lifeline/queuedNotice.d.ts.map +1 -0
- package/dist/lifeline/queuedNotice.js +40 -0
- package/dist/lifeline/queuedNotice.js.map +1 -0
- package/package.json +1 -1
- package/src/data/builtin-manifest.json +3 -3
- package/upgrades/1.3.862.md +27 -0
- package/upgrades/1.3.863.md +65 -0
- package/upgrades/side-effects/lifeline-reconnect-notice.md +121 -0
- package/upgrades/side-effects/session-pool-self-placement-confirmation.md +99 -0
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* queuedNotice — the user-facing "your message was queued" text the lifeline
|
|
3
|
+
* sends when it cannot forward a message to the server right now.
|
|
4
|
+
*
|
|
5
|
+
* Why this is its own module (bug fix, reported by peer agent Luna/Sagemind
|
|
6
|
+
* 2026-07-17): the lifeline has TWO distinct "couldn't deliver right now"
|
|
7
|
+
* states, and they must never be conflated in the user-facing text:
|
|
8
|
+
*
|
|
9
|
+
* - serverHealthy === false → the server is genuinely down / unreachable.
|
|
10
|
+
* Historical wording: "Server is temporarily down. …" (accurate).
|
|
11
|
+
*
|
|
12
|
+
* - serverHealthy === true → the server is confirmed UP, but THIS forward
|
|
13
|
+
* failed (a transient 10s timeout / 5xx / 503-boot / connection blip).
|
|
14
|
+
* The old code told the user "Server is restarting." — which is false
|
|
15
|
+
* and alarming: nothing restarted. This branch is a reconnect, not a
|
|
16
|
+
* restart, so the notice must say so.
|
|
17
|
+
*
|
|
18
|
+
* Centralizing the wording here (instead of three inline if/else blocks in
|
|
19
|
+
* TelegramLifeline) makes the healthy-vs-down distinction a single, tested
|
|
20
|
+
* decision — the message and photo/file handlers all route through it.
|
|
21
|
+
*/
|
|
22
|
+
/**
|
|
23
|
+
* Build the user-facing queued-notice text.
|
|
24
|
+
*
|
|
25
|
+
* @param kind which noun to use ("message" | "photo" | "file")
|
|
26
|
+
* @param queueLength current number of items in the durable queue
|
|
27
|
+
* @param serverHealthy the supervisor's live health verdict at send time
|
|
28
|
+
*/
|
|
29
|
+
export function buildQueuedNotice(kind, queueLength, serverHealthy) {
|
|
30
|
+
const noun = kind; // 'message' | 'photo' | 'file' are already the display nouns
|
|
31
|
+
if (serverHealthy) {
|
|
32
|
+
// Healthy server + failed forward → reconnecting, NOT restarting.
|
|
33
|
+
return (`I'm having trouble reaching my server right now — your ${noun} is queued ` +
|
|
34
|
+
`(${queueLength} in queue) and I'll deliver it as soon as I reconnect.`);
|
|
35
|
+
}
|
|
36
|
+
// Genuinely-down server (unchanged wording — preserves the accurate message).
|
|
37
|
+
return (`Server is temporarily down. Your ${noun} has been queued (${queueLength} in queue). ` +
|
|
38
|
+
`It will be delivered when the server recovers.`);
|
|
39
|
+
}
|
|
40
|
+
//# sourceMappingURL=queuedNotice.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"queuedNotice.js","sourceRoot":"","sources":["../../src/lifeline/queuedNotice.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAIH;;;;;;GAMG;AACH,MAAM,UAAU,iBAAiB,CAC/B,IAAoB,EACpB,WAAmB,EACnB,aAAsB;IAEtB,MAAM,IAAI,GAAG,IAAI,CAAC,CAAC,6DAA6D;IAChF,IAAI,aAAa,EAAE,CAAC;QAClB,kEAAkE;QAClE,OAAO,CACL,0DAA0D,IAAI,aAAa;YAC3E,IAAI,WAAW,wDAAwD,CACxE,CAAC;IACJ,CAAC;IACD,8EAA8E;IAC9E,OAAO,CACL,oCAAoC,IAAI,qBAAqB,WAAW,cAAc;QACtF,gDAAgD,CACjD,CAAC;AACJ,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "./builtin-manifest.schema.json",
|
|
3
3
|
"schemaVersion": 1,
|
|
4
|
-
"generatedAt": "2026-07-
|
|
5
|
-
"instarVersion": "1.3.
|
|
4
|
+
"generatedAt": "2026-07-17T20:16:29.908Z",
|
|
5
|
+
"instarVersion": "1.3.863",
|
|
6
6
|
"entryCount": 202,
|
|
7
7
|
"entries": {
|
|
8
8
|
"hook:session-start": {
|
|
@@ -1594,7 +1594,7 @@
|
|
|
1594
1594
|
"type": "subsystem",
|
|
1595
1595
|
"domain": "communication",
|
|
1596
1596
|
"sourcePath": "src/lifeline/TelegramLifeline.ts",
|
|
1597
|
-
"contentHash": "
|
|
1597
|
+
"contentHash": "a7a7255d17ab19f681b96dc5334ce44d86ea07a1f285b2bf8f9e19e9a35e19ab",
|
|
1598
1598
|
"since": "2025-01-01"
|
|
1599
1599
|
},
|
|
1600
1600
|
"subsystem:orphan-process-reaper": {
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# Upgrade Guide — vNEXT
|
|
2
|
+
|
|
3
|
+
<!-- assembled-by: assemble-next-md -->
|
|
4
|
+
<!-- bump: patch -->
|
|
5
|
+
|
|
6
|
+
## What Changed
|
|
7
|
+
|
|
8
|
+
When the session pool chooses the current machine for a new conversation, its
|
|
9
|
+
ownership row now advances from `placing` to `active` after the established
|
|
10
|
+
local injection or spawn path succeeds.
|
|
11
|
+
|
|
12
|
+
## What to Tell Your User
|
|
13
|
+
|
|
14
|
+
A conversation started on the machine that receives it no longer remains
|
|
15
|
+
stuck in a “starting” ownership state after it is already running.
|
|
16
|
+
|
|
17
|
+
## Summary of New Capabilities
|
|
18
|
+
|
|
19
|
+
No new setting. This repairs the existing session-pool placement lifecycle.
|
|
20
|
+
|
|
21
|
+
## Evidence
|
|
22
|
+
|
|
23
|
+
- Unit and integration coverage verifies the guarded transition, idempotence,
|
|
24
|
+
and the no-confirm-on-failed-spawn ordering.
|
|
25
|
+
- A live single-agent CROSS-MACHINE laptop/Mini test advanced a fresh Mini
|
|
26
|
+
placement from `placing` to `active` at epoch 2.
|
|
27
|
+
- Focused tests and TypeScript build pass.
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
# Upgrade Guide — vNEXT
|
|
2
|
+
|
|
3
|
+
<!-- assembled-by: assemble-next-md -->
|
|
4
|
+
<!-- bump: patch -->
|
|
5
|
+
|
|
6
|
+
## What Changed
|
|
7
|
+
|
|
8
|
+
When the lifeline can't hand a message off to the server but the server is
|
|
9
|
+
confirmed **healthy** (a transient timeout / 5xx / connection blip on a single
|
|
10
|
+
forward), the queued-message notice no longer says the false, alarming
|
|
11
|
+
"Server is restarting." It now reflects the real state: "I'm having trouble
|
|
12
|
+
reaching my server right now — your message is queued (N in queue) and I'll
|
|
13
|
+
deliver it as soon as I reconnect." The genuinely-down message
|
|
14
|
+
("Server is temporarily down…") is unchanged. The message, photo, and file
|
|
15
|
+
handlers all route through one shared helper (`buildQueuedNotice`) so the two
|
|
16
|
+
states can't drift apart again.
|
|
17
|
+
|
|
18
|
+
## What to Tell Your User
|
|
19
|
+
|
|
20
|
+
If a message of yours briefly can't be delivered while my server is actually
|
|
21
|
+
up, you'll now see an honest "reconnecting, your message is queued" note
|
|
22
|
+
instead of a scary "Server is restarting" alarm. Nothing about delivery
|
|
23
|
+
changed — your message was never lost; it queues and delivers as before. This
|
|
24
|
+
only fixes the wording so it stops claiming a restart that never happened.
|
|
25
|
+
|
|
26
|
+
## Summary of New Capabilities
|
|
27
|
+
|
|
28
|
+
No new setting. This is a bug fix to an existing user-facing notice.
|
|
29
|
+
|
|
30
|
+
## Evidence
|
|
31
|
+
|
|
32
|
+
- New unit test (`tests/unit/lifeline/queuedNotice.test.ts`, 8 cases) proves the
|
|
33
|
+
healthy-but-forward-failed branch never says "restart" or "temporarily down"
|
|
34
|
+
and always says "reconnect", and that the genuinely-down wording is preserved
|
|
35
|
+
byte-for-byte.
|
|
36
|
+
- Full lifeline unit suite passes (18 files / 160 tests); TypeScript build and
|
|
37
|
+
`pnpm build` are clean; exactly one "Server is restarting" string remains in
|
|
38
|
+
the compiled lifeline (the separate callback-query server-down case, out of
|
|
39
|
+
scope).
|
|
40
|
+
|
|
41
|
+
## The problem in one breath
|
|
42
|
+
|
|
43
|
+
The lifeline is the small always-on process that watches Telegram and hands your messages to my main server. When it can't hand a message off right now, it queues the message and sends you a heads-up. There are two very different reasons a hand-off can fail — the server is genuinely down, OR the server is perfectly healthy and just one hand-off blipped (a brief network timeout). The old code sent the SAME scary "Server is restarting. Your message has been queued…" text for BOTH cases. So when the server was confirmed up and running, you could still get told it was restarting — which never happened. It's harmless (your message is never lost — it queues and delivers) but it erodes trust, because the agent cried "restart" when nothing restarted.
|
|
44
|
+
|
|
45
|
+
## What already exists
|
|
46
|
+
|
|
47
|
+
- **The lifeline** — the tiny watchdog process that forwards your Telegram messages to the server and queues them if it can't. Already durable: queued messages survive and replay.
|
|
48
|
+
- **The server health check** — the lifeline always knows whether the server is up (`supervisor.healthy`). That verdict was already available at the exact spot where the wrong message was sent; the code just wasn't using it to pick the right words.
|
|
49
|
+
- **The genuinely-down message** — for a truly-down server the lifeline already said the accurate "Server is temporarily down…", and that wording is unchanged.
|
|
50
|
+
|
|
51
|
+
## What this adds
|
|
52
|
+
|
|
53
|
+
One small, tested helper (`buildQueuedNotice`) now decides the notice wording from the live health verdict. When the server is healthy but the hand-off failed, you get: "I'm having trouble reaching my server right now — your message is queued (N in queue) and I'll deliver it as soon as I reconnect." When the server is genuinely down, you get the exact same accurate "temporarily down" message as before. The three places that send this notice (text, photo, file) all route through the one helper, so they can never drift apart again.
|
|
54
|
+
|
|
55
|
+
## The new pieces
|
|
56
|
+
|
|
57
|
+
- **`buildQueuedNotice(kind, queueLength, serverHealthy)`** — a pure, side-effect-free function that returns the right notice text. It is NOT allowed to make any decision about delivery or restarts; it only chooses words from a health verdict it is handed. That line matters: the authority to restart still lives entirely in the existing restart machinery — this helper just describes the current state honestly.
|
|
58
|
+
|
|
59
|
+
## The safeguards
|
|
60
|
+
|
|
61
|
+
The genuinely-down wording is byte-for-byte identical to before (a test locks that in, so no downstream dedup behavior shifts). A unit test proves the healthy-but-failed branch never contains the words "restart" or "temporarily down", and always mentions "reconnect"; and that the two states always produce different text. Scope is deliberately tight: the drift-promoter threshold question and the callback-query down-message are explicitly out of scope and were left untouched.
|
|
62
|
+
|
|
63
|
+
## What you actually need to decide
|
|
64
|
+
|
|
65
|
+
Nothing risky. This is a wording/logic bug fix with no new capability, no config, no state, and no schema change. The only judgment call is the exact replacement wording, which reads in plain language and is honest about what's happening. If it turns out wrong, the back-out is a one-line revert.
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
# Side-Effects Review — Lifeline "reconnecting" notice (fix false "Server is restarting")
|
|
2
|
+
|
|
3
|
+
**Version / slug:** `lifeline-reconnect-notice`
|
|
4
|
+
**Date:** `2026-07-17`
|
|
5
|
+
**Author:** `Echo (instar-dev agent)`
|
|
6
|
+
**Second-pass reviewer:** `Echo (Phase-5 self-review — see below)`
|
|
7
|
+
|
|
8
|
+
## Summary of the change
|
|
9
|
+
|
|
10
|
+
The lifeline forwards inbound Telegram messages to the server and, when it cannot forward right now, queues the message and sends the user a heads-up. There are two distinct "couldn't deliver right now" states — the server is genuinely **down** (`supervisor.healthy === false`) versus the server is **healthy but this one forward failed** (transient 10s timeout / 5xx / 503-boot / connection blip, `supervisor.healthy === true` and `forwardToServer()` returned non-`ok`). The healthy-but-failed branch was sending the user the false, alarming `Server is restarting. Your message has been queued…` even though the server was confirmed up. Reported by peer agent Luna (Sagemind) 2026-07-17, verified against source; it also hit operator Justin directly.
|
|
11
|
+
|
|
12
|
+
Files touched:
|
|
13
|
+
- `src/lifeline/queuedNotice.ts` (new) — a pure helper `buildQueuedNotice(kind, queueLength, serverHealthy)` that centralizes the notice wording.
|
|
14
|
+
- `src/lifeline/TelegramLifeline.ts` — the four queue-ack call sites (text healthy-fail, text down, photo, file/document) now route through the helper; the two photo/file inline `if/else` blocks collapse to one call each.
|
|
15
|
+
- `tests/unit/lifeline/queuedNotice.test.ts` (new) — unit coverage.
|
|
16
|
+
|
|
17
|
+
## Decision-point inventory
|
|
18
|
+
|
|
19
|
+
- `TelegramLifeline` queue-ack wording (text/photo/file handlers) — **modified (wording/logic only)** — picks the user-facing notice string from the live `supervisor.healthy` verdict. This is a message-*wording* decision, not a message *block/allow* or delivery decision. No gating authority added, removed, or changed.
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
## 1. Over-block
|
|
24
|
+
|
|
25
|
+
No block/allow surface — over-block not applicable. The change never suppresses, delays, or rejects a message; it only chooses the text of a heads-up that is already being sent (still gated by the unchanged `shouldSendQueueAck` rate-limiter). Message queueing/delivery is entirely unchanged.
|
|
26
|
+
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
## 2. Under-block
|
|
30
|
+
|
|
31
|
+
No block/allow surface — under-block not applicable. The queued message still enqueues and replays exactly as before; the only behavioral delta is the words in the notice.
|
|
32
|
+
|
|
33
|
+
---
|
|
34
|
+
|
|
35
|
+
## 3. Level-of-abstraction fit
|
|
36
|
+
|
|
37
|
+
Correct layer. The wording decision belongs precisely where the send happens — the lifeline handler that already holds the `supervisor.healthy` verdict and the queue length. The new helper is a pure string builder (lowest sensible level: no I/O, no decision authority). It does not re-implement or run parallel to any existing gate; it consumes a health verdict the caller already computed. Centralizing the three previously-duplicated sites into one tested function is a strict simplification (DRY), not a new abstraction competing with an existing one.
|
|
38
|
+
|
|
39
|
+
---
|
|
40
|
+
|
|
41
|
+
## 4. Signal vs authority compliance
|
|
42
|
+
|
|
43
|
+
**Required reference:** docs/signal-vs-authority.md
|
|
44
|
+
|
|
45
|
+
- [x] No — this change has no block/allow surface.
|
|
46
|
+
|
|
47
|
+
`buildQueuedNotice` holds ZERO authority: it neither restarts anything, nor decides whether to send, nor gates delivery. It is handed a health SIGNAL (`supervisor.healthy`, computed by the existing supervisor) and returns descriptive text. The authority to restart the lifeline remains entirely with the existing `RestartOrchestrator` / `LifelineDriftPromoter`; this change deliberately stops the notice from *asserting* a restart the system did not perform — i.e. it makes the user-facing text HONEST about the current state rather than claiming an action. No brittle logic gains blocking authority.
|
|
48
|
+
|
|
49
|
+
---
|
|
50
|
+
|
|
51
|
+
## 4b. Judgment-point check (Judgment Within Floors standard)
|
|
52
|
+
|
|
53
|
+
No new static heuristic at a competing-signals decision point. The wording is chosen from a single, enumerable boolean (`serverHealthy` true/false) — an invariant two-state fork, not a point where multiple live signals conflict. There is no arbiter needed and none added.
|
|
54
|
+
|
|
55
|
+
---
|
|
56
|
+
|
|
57
|
+
## 5. Interactions
|
|
58
|
+
|
|
59
|
+
- **Shadowing:** none. The notice send sits after `shouldSendQueueAck` (unchanged) and does not run before/after any gate whose outcome it could mask.
|
|
60
|
+
- **Double-fire:** none introduced. The version-skew path (`handleVersionSkew`, fired on a 426) is a separate code path and is untouched; this change does not add a second notice.
|
|
61
|
+
- **Races:** none new. `this.queue.length` is read at send time exactly as before; no new shared state is introduced (the helper is stateless/pure).
|
|
62
|
+
- **Feedback loops:** none. The text is terminal output to the user; it feeds nothing back into the forward/queue machinery.
|
|
63
|
+
- **Down-branch wording preserved byte-for-byte:** the `serverHealthy === false` output is identical to the previous inline strings (locked by a test), so any downstream that keys on that exact text (e.g. the duplicate-message dedup window) sees no change.
|
|
64
|
+
|
|
65
|
+
---
|
|
66
|
+
|
|
67
|
+
## 6. External surfaces
|
|
68
|
+
|
|
69
|
+
- **Other agents / install base:** ships in the instar package `dist/`; every agent gets the corrected wording when it updates and its lifeline restarts onto the new version. No migration needed — the lifeline is compiled package code, not an agent-installed file (`.claude/settings.json`, config defaults, CLAUDE.md template, hook scripts, or built-in skills), so `PostUpdateMigrator` is not involved.
|
|
70
|
+
- **Telegram:** the only external-visible change is the improved notice text a user reads when a forward transiently fails. No API shape, topic, or delivery-path change.
|
|
71
|
+
- **Persistent state:** none. No schema, ledger, or state-file change.
|
|
72
|
+
- **Timing/runtime:** the branch is selected from the live `supervisor.healthy` at send time — same input the old code had at the same spot.
|
|
73
|
+
- **Operator surface (Mobile-Complete):** no operator-facing actions added or touched. This is a USER-facing message, not an operator action/approval/grant surface.
|
|
74
|
+
|
|
75
|
+
---
|
|
76
|
+
|
|
77
|
+
## 6b. Operator-surface quality (Operator-Surface Quality standard)
|
|
78
|
+
|
|
79
|
+
No operator surface — not applicable. This change touches a **user-facing** Telegram notice, not a dashboard renderer, approval page, or grant/revoke/secret-drop form. (For completeness on the user-facing text quality: the new notice leads with the real state in plain language — "I'm having trouble reaching my server right now — your message is queued (N in queue) and I'll deliver it as soon as I reconnect." — exposes no raw internals, and is honest rather than alarming.)
|
|
80
|
+
|
|
81
|
+
---
|
|
82
|
+
|
|
83
|
+
## 7. Multi-machine posture (Cross-Machine Coherence)
|
|
84
|
+
|
|
85
|
+
**machine-local BY DESIGN.** The lifeline is a per-machine process: each machine's lifeline forwards to that machine's own server and its `supervisor.healthy` verdict is about the local server. The notice is emitted by whichever machine actually received and tried to forward the user's message, so there is no cross-machine state to replicate or proxy. It emits a user-facing notice, but one-voice gating is not newly needed: the send is already governed by the existing per-topic `shouldSendQueueAck` rate-limiter and the pre-existing duplicate-message suppression window — this change alters only the words, not the send cadence or the number of voices. No durable state (nothing to strand on topic transfer) and no generated URLs.
|
|
86
|
+
|
|
87
|
+
---
|
|
88
|
+
|
|
89
|
+
## 8. Rollback cost
|
|
90
|
+
|
|
91
|
+
Pure code change — revert the two source files (and the new helper/test) and ship as the next patch. No persistent state, no data migration, no agent-state repair, no user-visible regression during the rollback window (worst case is the old wording returns). One-line-scale back-out.
|
|
92
|
+
|
|
93
|
+
---
|
|
94
|
+
|
|
95
|
+
## Conclusion
|
|
96
|
+
|
|
97
|
+
The review confirms a tightly-scoped, low-risk wording/logic fix with no decision-point authority, no block/allow surface, no persistent state, and no multi-machine coherence hazard. The design change made during review was to extract the wording into a single pure helper (rather than edit three inline strings), which both makes the fix unit-testable in isolation and removes the duplicated photo/file `if/else` — closing the "three copies drift apart" failure mode structurally. The genuinely-down wording is preserved byte-for-byte to avoid any downstream dedup/text-matching side effect. Scope was deliberately held to the three reported sites; the drift-promoter threshold question and the callback-query down-message were left untouched (flagged to the reporter as separate items). Clear to ship.
|
|
98
|
+
|
|
99
|
+
---
|
|
100
|
+
|
|
101
|
+
## Second-pass review (if required)
|
|
102
|
+
|
|
103
|
+
**Reviewer:** Echo (self, Phase-5 — the change touches the messaging/lifeline path)
|
|
104
|
+
**Independent read of the artifact: concur**
|
|
105
|
+
|
|
106
|
+
Concur with the review. Re-verified independently: (1) the only remaining `Server is restarting` string in `TelegramLifeline.ts` is the callback-query genuine-`!supervisor.healthy` branch (out of scope, and at least plausibly-true in a down state); (2) all four queue-ack sites now route through `buildQueuedNotice`; (3) the down-branch bytes are unchanged (test-locked); (4) no self-triggered action is added — the notice is a one-shot response to an inbound user message, not a self-firing loop. No concern raised.
|
|
107
|
+
|
|
108
|
+
---
|
|
109
|
+
|
|
110
|
+
## Evidence pointers
|
|
111
|
+
|
|
112
|
+
- `npx tsc --noEmit` — clean (exit 0).
|
|
113
|
+
- `npx vitest run tests/unit/lifeline/queuedNotice.test.ts` — 8/8 pass.
|
|
114
|
+
- `npx vitest run tests/unit/lifeline/` — 18 files / 160 tests pass (no regression).
|
|
115
|
+
- `pnpm build` — dist compiles; `dist/lifeline/queuedNotice.js` present; exactly 1 `Server is restarting` remains in `dist/lifeline/TelegramLifeline.js` (the intentional callback-down site).
|
|
116
|
+
|
|
117
|
+
---
|
|
118
|
+
|
|
119
|
+
## Class-Closure Declaration (display-only mirror)
|
|
120
|
+
|
|
121
|
+
Not a self-triggered controller and not a fix to an agent-authored artifact (prompt/hook/config/skill/standards text). This is a fix to compiled TypeScript runtime behavior — a one-shot, user-message-driven notice, not a loop/monitor/sentinel/reaper/scheduler/recovery path. `unbounded-self-action` class: `n/a` — one-shot user-driven action, not a self-triggered loop.
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
# Side-Effects Review — Session-pool self-placement confirmation
|
|
2
|
+
|
|
3
|
+
**Version / slug:** `session-pool-self-placement-confirmation`
|
|
4
|
+
**Date:** `2026-07-17`
|
|
5
|
+
**Author:** `Instar Agent (instar-codey)`
|
|
6
|
+
**Second-pass reviewer:** `continuation_impl_review` (independent Codex reviewer) — CONCUR after two correction rounds
|
|
7
|
+
|
|
8
|
+
## Summary
|
|
9
|
+
|
|
10
|
+
Successful local session delivery now confirms a self-owned `placing` row as
|
|
11
|
+
`active`. Confirmation remains outside `SessionRouter`, after the real local
|
|
12
|
+
inject/spawn seam. Failed spawns do not confirm.
|
|
13
|
+
|
|
14
|
+
## Decision-point inventory
|
|
15
|
+
|
|
16
|
+
- Post-local-delivery ownership transition — **modified** — a successful local
|
|
17
|
+
tail may confirm only its own still-placing row.
|
|
18
|
+
|
|
19
|
+
## 1. Over-block
|
|
20
|
+
|
|
21
|
+
No message is newly blocked. Missing, active, or remotely-owned rows are no-ops.
|
|
22
|
+
|
|
23
|
+
## 2. Under-block
|
|
24
|
+
|
|
25
|
+
The transition cannot run before delivery because every callsite is after a
|
|
26
|
+
synchronous injection that returned true or inside a spawn/respawn success
|
|
27
|
+
continuation. A rejected injection or spawn does not confirm.
|
|
28
|
+
Registry confirmation failure is diagnostic-only after delivery and cannot fall
|
|
29
|
+
into the delivery-failure handler. If the transition commits but observer
|
|
30
|
+
emission fails, the committed outcome remains true and diagnostics avoid
|
|
31
|
+
claiming an unknowable row state.
|
|
32
|
+
|
|
33
|
+
## 3. Level-of-abstraction fit
|
|
34
|
+
|
|
35
|
+
The state predicate is a small pure core. Server wiring owns the timing because
|
|
36
|
+
it alone knows when the legacy local delivery tail has actually succeeded.
|
|
37
|
+
|
|
38
|
+
## 4. Signal vs authority compliance
|
|
39
|
+
|
|
40
|
+
The ownership registry remains the sole transition authority. Local delivery
|
|
41
|
+
success is evidence supplied to that authority, not a parallel ownership store.
|
|
42
|
+
|
|
43
|
+
## 4b. Judgment-point check
|
|
44
|
+
|
|
45
|
+
No heuristic is introduced. The enumerable rule is `status=placing AND
|
|
46
|
+
owner=self AND local delivery succeeded`.
|
|
47
|
+
|
|
48
|
+
## 5. Interactions
|
|
49
|
+
|
|
50
|
+
Ordinary traffic to an active local session calls the helper but performs no
|
|
51
|
+
write. Remote placement confirmation remains unchanged. SpawnAdmission still
|
|
52
|
+
runs before every local spawn and a refusal cannot reach confirmation.
|
|
53
|
+
|
|
54
|
+
## 6. External surfaces
|
|
55
|
+
|
|
56
|
+
`GET /pool/ownership-view` now reports `active` after a successful self-placement.
|
|
57
|
+
No schema, authentication, configuration, or user command changes.
|
|
58
|
+
|
|
59
|
+
## 7. Multi-machine posture (Cross-Machine Coherence)
|
|
60
|
+
|
|
61
|
+
**Replicated.** The transition is written to the existing ownership registry
|
|
62
|
+
and propagated by its existing replication path. A live laptop/Mini test proved
|
|
63
|
+
the receiving Mini's row reached `active`.
|
|
64
|
+
|
|
65
|
+
## 8. Rollback cost
|
|
66
|
+
|
|
67
|
+
Pure code rollback with no migration. Rollback restores stuck `placing` rows
|
|
68
|
+
for new self-placements.
|
|
69
|
+
|
|
70
|
+
## Evidence
|
|
71
|
+
|
|
72
|
+
- `tests/unit/SessionPoolLocalClaim.test.ts`
|
|
73
|
+
- `tests/unit/session-pool-activation-wiring.test.ts`
|
|
74
|
+
- `tests/integration/session-pool-local-claim.integration.test.ts`
|
|
75
|
+
- `tests/unit/no-silent-fallbacks.test.ts` (both contained error paths are
|
|
76
|
+
explicitly annotated and continue to report through `onError`)
|
|
77
|
+
- Live single-agent CROSS-MACHINE topic 3462 placement: owner Mini, epoch 2,
|
|
78
|
+
status `active`.
|
|
79
|
+
|
|
80
|
+
## Conclusion
|
|
81
|
+
|
|
82
|
+
The change is narrow and preserves honest failure semantics. It should ship
|
|
83
|
+
with the independent session-lifecycle second pass concurred.
|
|
84
|
+
|
|
85
|
+
## Second-pass review
|
|
86
|
+
|
|
87
|
+
The first pass found that live injection's boolean result was ignored and that
|
|
88
|
+
confirmation exceptions could falsely enter delivery-failure handling. Both
|
|
89
|
+
were fixed and regression-tested. The second pass found a post-commit honesty
|
|
90
|
+
edge: observer emission could throw after CAS committed while diagnostics
|
|
91
|
+
claimed the row remained placing. The authoritative CAS result is now separate
|
|
92
|
+
from best-effort observation; committed confirmation stays true, diagnostics
|
|
93
|
+
make no unverified state claim, and the observer-failure regression is pinned.
|
|
94
|
+
The reviewer then concurred with no remaining findings.
|
|
95
|
+
|
|
96
|
+
## Class-Closure Declaration (display-only mirror)
|
|
97
|
+
|
|
98
|
+
No agent-authored-artifact defect or self-triggered controller is added or
|
|
99
|
+
modified — not applicable.
|