instar 1.3.43 → 1.3.45

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.
Files changed (103) hide show
  1. package/dashboard/index.html +68 -14
  2. package/dashboard/process-health.js +204 -53
  3. package/dist/commands/server.d.ts.map +1 -1
  4. package/dist/commands/server.js +292 -3
  5. package/dist/commands/server.js.map +1 -1
  6. package/dist/core/HandoffReceiver.d.ts +56 -0
  7. package/dist/core/HandoffReceiver.d.ts.map +1 -0
  8. package/dist/core/HandoffReceiver.js +103 -0
  9. package/dist/core/HandoffReceiver.js.map +1 -0
  10. package/dist/core/HandoffWireTransport.d.ts +61 -0
  11. package/dist/core/HandoffWireTransport.d.ts.map +1 -0
  12. package/dist/core/HandoffWireTransport.js +114 -0
  13. package/dist/core/HandoffWireTransport.js.map +1 -0
  14. package/dist/core/HttpLeaseTransport.d.ts +68 -0
  15. package/dist/core/HttpLeaseTransport.d.ts.map +1 -0
  16. package/dist/core/HttpLeaseTransport.js +97 -0
  17. package/dist/core/HttpLeaseTransport.js.map +1 -0
  18. package/dist/core/HttpLiveTailTransport.d.ts +88 -0
  19. package/dist/core/HttpLiveTailTransport.d.ts.map +1 -0
  20. package/dist/core/HttpLiveTailTransport.js +95 -0
  21. package/dist/core/HttpLiveTailTransport.js.map +1 -0
  22. package/dist/core/LeaseCoordinator.d.ts +14 -0
  23. package/dist/core/LeaseCoordinator.d.ts.map +1 -1
  24. package/dist/core/LeaseCoordinator.js +38 -0
  25. package/dist/core/LeaseCoordinator.js.map +1 -1
  26. package/dist/core/LiveTailSource.d.ts +65 -0
  27. package/dist/core/LiveTailSource.d.ts.map +1 -0
  28. package/dist/core/LiveTailSource.js +87 -0
  29. package/dist/core/LiveTailSource.js.map +1 -0
  30. package/dist/core/MultiMachineCoordinator.d.ts +14 -0
  31. package/dist/core/MultiMachineCoordinator.d.ts.map +1 -1
  32. package/dist/core/MultiMachineCoordinator.js +22 -0
  33. package/dist/core/MultiMachineCoordinator.js.map +1 -1
  34. package/dist/core/ReplyMarkerTransport.d.ts +58 -0
  35. package/dist/core/ReplyMarkerTransport.d.ts.map +1 -0
  36. package/dist/core/ReplyMarkerTransport.js +66 -0
  37. package/dist/core/ReplyMarkerTransport.js.map +1 -0
  38. package/dist/core/handoffReceiverWiring.d.ts +57 -0
  39. package/dist/core/handoffReceiverWiring.d.ts.map +1 -0
  40. package/dist/core/handoffReceiverWiring.js +65 -0
  41. package/dist/core/handoffReceiverWiring.js.map +1 -0
  42. package/dist/core/handoffSentinelBootWiring.d.ts +53 -0
  43. package/dist/core/handoffSentinelBootWiring.d.ts.map +1 -0
  44. package/dist/core/handoffSentinelBootWiring.js +52 -0
  45. package/dist/core/handoffSentinelBootWiring.js.map +1 -0
  46. package/dist/core/handoffSentinelWiring.d.ts +60 -0
  47. package/dist/core/handoffSentinelWiring.d.ts.map +1 -0
  48. package/dist/core/handoffSentinelWiring.js +59 -0
  49. package/dist/core/handoffSentinelWiring.js.map +1 -0
  50. package/dist/core/seamlessnessConfig.d.ts +8 -0
  51. package/dist/core/seamlessnessConfig.d.ts.map +1 -1
  52. package/dist/core/seamlessnessConfig.js +1 -0
  53. package/dist/core/seamlessnessConfig.js.map +1 -1
  54. package/dist/core/types.d.ts +6 -0
  55. package/dist/core/types.d.ts.map +1 -1
  56. package/dist/core/types.js.map +1 -1
  57. package/dist/messaging/TelegramAdapter.d.ts +6 -0
  58. package/dist/messaging/TelegramAdapter.d.ts.map +1 -1
  59. package/dist/messaging/TelegramAdapter.js +8 -0
  60. package/dist/messaging/TelegramAdapter.js.map +1 -1
  61. package/dist/messaging/ingressDedup.d.ts +55 -0
  62. package/dist/messaging/ingressDedup.d.ts.map +1 -0
  63. package/dist/messaging/ingressDedup.js +69 -0
  64. package/dist/messaging/ingressDedup.js.map +1 -0
  65. package/dist/messaging/stuckMessageRecovery.d.ts +46 -0
  66. package/dist/messaging/stuckMessageRecovery.d.ts.map +1 -0
  67. package/dist/messaging/stuckMessageRecovery.js +52 -0
  68. package/dist/messaging/stuckMessageRecovery.js.map +1 -0
  69. package/dist/server/AgentServer.d.ts +64 -0
  70. package/dist/server/AgentServer.d.ts.map +1 -1
  71. package/dist/server/AgentServer.js +24 -0
  72. package/dist/server/AgentServer.js.map +1 -1
  73. package/dist/server/handoffInitiateRoutes.d.ts +40 -0
  74. package/dist/server/handoffInitiateRoutes.d.ts.map +1 -0
  75. package/dist/server/handoffInitiateRoutes.js +57 -0
  76. package/dist/server/handoffInitiateRoutes.js.map +1 -0
  77. package/dist/server/machineRoutes.d.ts +47 -0
  78. package/dist/server/machineRoutes.d.ts.map +1 -1
  79. package/dist/server/machineRoutes.js +138 -0
  80. package/dist/server/machineRoutes.js.map +1 -1
  81. package/dist/server/routes.d.ts +20 -0
  82. package/dist/server/routes.d.ts.map +1 -1
  83. package/dist/server/routes.js +65 -0
  84. package/dist/server/routes.js.map +1 -1
  85. package/package.json +1 -1
  86. package/src/data/builtin-manifest.json +49 -49
  87. package/upgrades/1.3.44.md +72 -0
  88. package/upgrades/1.3.45.md +28 -0
  89. package/upgrades/side-effects/cross-machine-seamlessness-consent-acquire.md +52 -0
  90. package/upgrades/side-effects/cross-machine-seamlessness-exactly-once-ingress.md +73 -0
  91. package/upgrades/side-effects/cross-machine-seamlessness-handoff-ack-yield.md +82 -0
  92. package/upgrades/side-effects/cross-machine-seamlessness-handoff-begin.md +48 -0
  93. package/upgrades/side-effects/cross-machine-seamlessness-handoff-boot-wiring.md +68 -0
  94. package/upgrades/side-effects/cross-machine-seamlessness-handoff-receiver-wiring.md +52 -0
  95. package/upgrades/side-effects/cross-machine-seamlessness-handoff-receiver.md +46 -0
  96. package/upgrades/side-effects/cross-machine-seamlessness-handoff-sentinel-wiring.md +47 -0
  97. package/upgrades/side-effects/cross-machine-seamlessness-lease-wire.md +46 -0
  98. package/upgrades/side-effects/cross-machine-seamlessness-livetail-source.md +50 -0
  99. package/upgrades/side-effects/cross-machine-seamlessness-livetail-streaming.md +50 -0
  100. package/upgrades/side-effects/cross-machine-seamlessness-livetail-wire.md +65 -0
  101. package/upgrades/side-effects/cross-machine-seamlessness-noloss-recovery.md +61 -0
  102. package/upgrades/side-effects/cross-machine-seamlessness-reply-marker.md +65 -0
  103. package/upgrades/side-effects/process-health-tab-eli16-pass.md +49 -0
@@ -0,0 +1,61 @@
1
+ # Side-Effects Review — Cross-Machine Seamlessness: no-loss stuck-message recovery (D-noloss)
2
+
3
+ **Spec:** docs/specs/CROSS-MACHINE-SEAMLESSNESS-SPEC.md §8 G3a ("Stuck-`processing` recovery")
4
+
5
+ The complement to the inbound dedup gate. With dedup alone, a crash AFTER claiming an
6
+ inbound event but BEFORE the reply commits would lose the reply (Telegram won't redeliver
7
+ once polled). This adds the spec's explicit "re-run from the stored input by the current
8
+ lease holder" mechanism: a `processing` entry stuck past `maxProcessingMs` is re-routed from
9
+ its `inputSnapshot`, producing the lost reply. Together with the dedup gate this makes the
10
+ flag's guarantee genuinely *exactly-once* (no-loss AND no-duplicate). Still flag-gated dark
11
+ (`multiMachine.exactlyOnceIngress`, default false).
12
+
13
+ ## What changed
14
+ - `src/messaging/stuckMessageRecovery.ts` — NEW. `recoverStuckMessages(deps)`: lease-gated
15
+ (a standby never injects); `reclaimStuck(maxProcessingMs)` → for each entry with a stored
16
+ input and `attempts < maxReplayAttempts` (default 3), re-claim under the current epoch and
17
+ call the injected `reinject(topic, dedupeKey, text)`. Pure orchestration over injected deps.
18
+ - `src/commands/server.ts` — after `server.start()`, ONLY when the ledger is wired (flag on)
19
+ AND telegram is present: builds `reinject` (sets the per-topic current-inbound key, then
20
+ routes the stored text via the same `telegram.onTopicMessage` path a fresh forward uses),
21
+ runs recovery at boot, and on a cadence (`max(30s, maxProcessingMs)`), lease-gated.
22
+
23
+ ## Over-block / under-block
24
+ - OVER-re-run (the risk = re-answering a message the agent legitimately left unanswered, or a
25
+ persistently-failing turn looping): bounded by (1) only entries stuck past `maxProcessingMs`
26
+ (a genuinely timed-out turn, not one in flight), (2) `attempts < maxReplayAttempts` cap —
27
+ after the cap the entry is left alone, never re-run again, (3) lease-gate (only the awake
28
+ machine), (4) flag-off default. Proven both sides in stuck-message-recovery.test.ts.
29
+ - UNDER-recover: an entry with no `inputSnapshot` can't be replayed (nothing captured) → skipped
30
+ honestly rather than guessed. Inputs ARE captured by the dedup gate's `decideIngress(input:text)`.
31
+ - The known single-duplicate residual (spec §3 / §8 G3a impossibility floor): a crash AFTER the
32
+ reply physically sent but BEFORE `reply_committed` persisted → re-run produces one duplicate.
33
+ This is the documented Two-Generals floor, bounded to one, not a defect.
34
+
35
+ ## Signal vs authority
36
+ - recoverStuckMessages decides which entries to re-run; the re-injection authority is the
37
+ existing onTopicMessage routing. The module holds no Telegram/server coupling (injected deps).
38
+
39
+ ## Interactions
40
+ - Re-injection sets `currentInboundByTopic[topic]` BEFORE routing so the eventual reply commits
41
+ the correct entry (same coupling the inbound gate uses) — closing the loop: re-run → reply →
42
+ commit → not re-run again.
43
+ - Telegram-only for v1 (the `--no-telegram` sessionManager path is a tracked refinement; the
44
+ block is guarded on `telegram` present).
45
+ - Cadenced re-scan is `unref()`'d (never holds the process open) and lease-gated (a standby's
46
+ timer no-ops).
47
+
48
+ ## Rollback cost
49
+ - Low. Flag default-off ⇒ the whole block is skipped (messageLedger undefined). Revert = drop the
50
+ post-start block + the module. No persisted schema beyond the opt-in ledger SQLite.
51
+
52
+ ## Tests
53
+ - `tests/unit/stuck-message-recovery.test.ts` (7): re-runs a stuck entry from stored input;
54
+ standby no-op; already-replied not re-run; in-flight (within window) not re-run; attempts-cap
55
+ gives up (no storm); no-input skipped; + boot wiring-integrity (server.ts calls it after
56
+ server.start(), gated on the ledger + coordinator lease).
57
+
58
+ ## NOT in this increment (tracked, topic-13481)
59
+ - Behavioral boot-recovery e2e (needs a live Telegram adapter) — exercised by the live flag-flip
60
+ test-as-self, which is the gate before defaulting the flag on. Cross-machine marker (D-xmachine)
61
+ + CONTINUATION resume (D3) remain.
@@ -0,0 +1,65 @@
1
+ # Side-Effects Review — Cross-Machine Seamlessness: reply-marker propagation (D-xmachine)
2
+
3
+ **Spec:** docs/specs/CROSS-MACHINE-SEAMLESSNESS-SPEC.md §8 G3a ("dual-medium reply_committed marker")
4
+
5
+ The cross-machine half of exactly-once. The same-machine dedup gate + no-loss recovery handle
6
+ one machine; this closes the window where, AFTER a handoff/failover, a provider redelivery of a
7
+ message the OLD holder already answered arrives at the NEW holder — whose ledger wouldn't know,
8
+ so it would re-answer. The holder now propagates a `reply_committed` marker to standby peers on
9
+ each commit; the standby applies it via `applyRemoteReplyMarker`, so the new holder's dedup gate
10
+ drops the redelivery. Still flag-gated dark (`multiMachine.exactlyOnceIngress`, default false).
11
+
12
+ ## What changed
13
+ - `src/core/ReplyMarkerTransport.ts` — NEW. `broadcast(marker)` signs + POSTs
14
+ {dedupeKey, platform, replyIdempotencyKey, epoch, topic} to each standby peer's
15
+ `/api/message-marker` over the authenticated machine channel. NO encryption (the marker
16
+ carries no conversation content — authentication only). No peers → reachable no-op. Never
17
+ throws (best-effort; the dedup gate + provider redelivery are the backstop).
18
+ - `src/server/machineRoutes.ts` — `POST /api/message-marker` (machineAuth) + `onReplyMarker`
19
+ ctx callback. Validates the marker shape; 503 when no receiver (exactly-once off).
20
+ - `src/server/AgentServer.ts` — `replyMarkerTransport?` + `onReplyMarker?` options → routeCtx /
21
+ machineRoutes.
22
+ - `src/server/routes.ts` — RouteContext.replyMarkerTransport; the outbound commit at
23
+ `/telegram/reply/:topicId` reads the just-committed `replyIdempotencyKey` from the ledger and
24
+ fires `replyMarkerTransport.broadcast(...)` (fire-and-forget, after the local commit).
25
+ - `src/commands/server.ts` — constructs `ReplyMarkerTransport` (peer resolver = registry
26
+ machines with a lastKnownUrl) ONLY when `exactlyOnceIngress` + coordinator.enabled; wires
27
+ `onReplyMarker` → `messageLedger.applyRemoteReplyMarker`.
28
+
29
+ ## Over-block / under-block
30
+ - The marker NEVER over-marks a fresh event: `applyRemoteReplyMarker` only sets reply_committed
31
+ on an entry not already acted-on, and the dedupeKey is the same provider-stable id both
32
+ machines compute — so a marker for event X can only dedup event X. The deterministic
33
+ `replyIdempotencyKey` (hash(dedupeKey+index)) is identical on both machines.
34
+ - UNDER-propagate (a lost marker): best-effort — if the marker doesn't reach the standby, the
35
+ provider's at-least-once redelivery + the standby's own ledger (once it catches up) still
36
+ dedup; the residual is the documented single-duplicate Two-Generals floor, not a new failure.
37
+ - Signed channel: `/api/message-marker` requires machineAuth (unsigned → 401, proven in the e2e);
38
+ the marker carries no secrets so no encryption is needed.
39
+
40
+ ## Signal vs authority
41
+ - The transport propagates; the receiving ledger's `applyRemoteReplyMarker` is the authority on
42
+ its own state (only promotes a not-yet-acted entry). The dedup gate remains the single drop authority.
43
+
44
+ ## Interactions
45
+ - Fires AFTER the local `commitInboundReply` (the local guarantee never depends on propagation).
46
+ - Skipped for proxy/system sends (same guard as the commit) — a proxy message isn't a user reply.
47
+ - Peer resolver mirrors the live-tail/handoff resolvers (registry machines with lastKnownUrl,
48
+ excludes self/revoked). Solo agent → no peers → no-op.
49
+
50
+ ## Rollback cost
51
+ - Low. Flag default-off ⇒ transport not constructed, route 503s, no propagation. Revert = drop
52
+ the transport + route + the broadcast call. No persisted schema.
53
+
54
+ ## Tests
55
+ - `tests/unit/reply-marker-transport.test.ts` (3): no-peers no-op; signs + POSTs to each peer;
56
+ resolves false (never throws) when all peers reject.
57
+ - `tests/e2e/reply-marker-cross-machine-e2e.test.ts` (2): a PEER-signed marker over real HTTP +
58
+ machine-auth applies to the receiver's ledger, then a redelivery of that message is DEDUPED
59
+ (already-replied) — the cross-machine guarantee end-to-end; + unsigned marker rejected (401).
60
+
61
+ ## Completion status
62
+ - With D-dedup + D-noloss + D-xmachine, the exactly-once guarantee is COMPLETE in all dimensions
63
+ (no-dup same+cross machine, no-loss on crash), all DARK behind the flag. Remaining before the
64
+ flag flips: D3 (CONTINUATION resume verify) + the over-Telegram two-machine test-as-self (the
65
+ live acceptance bar, needs the operator's machines).
@@ -0,0 +1,49 @@
1
+ # Side-Effects Review — Process Health tab ELI16 + structure pass
2
+
3
+ **Version / slug:** `process-health-tab-eli16-pass`
4
+ **Date:** 2026-05-27
5
+ **Author:** echo
6
+ **Spec:** `docs/specs/PROCESS-HEALTH-DASHBOARD-TAB-SPEC.md` (v4, the original feature spec; this PR is a UX-refinement follow-up that does NOT change the spec's behavioral surface)
7
+
8
+ ## Summary of the change
9
+
10
+ Eight rounds of user-driven copy + UX iteration on the Process Health dashboard tab (originally shipped in v1.3.27 via PR #435). Pure dashboard-only refinement — no `src/` / `scripts/` / `.husky/` / `skills/` changes — so this PR is outside the instar-dev gate's in-scope set. The reference implementation now backs a durable agent memory (`feedback_dashboard_copy_eli16.md`) that codifies the **Dashboard Standard** for future dashboard features.
11
+
12
+ **Files changed (UI):**
13
+ - `dashboard/process-health.js` (renderers): rewritten `CATEGORY_WORDS`, `ATTRIBUTION_LABELS`, `STAGES`, `INSIGHT_STATUS_WORDS`; new `TYPE_WORDS`, `STATUS_WORDS`, `CAUSE_CONFIDENCE_WORDS`, `statusDotClass`, `statusDot`, `labeledRow`. Restructured `renderCaptured` and `renderPatterns` around the fixed label vocabulary + `<details>` expandability + status color dots. `renderMaturation` reshaped per-stage as expandable `<details>` with plain-English descriptions. Dropped the redundant per-card framing line in v7.
14
+ - `dashboard/index.html`: added page-intro paragraph + per-section subtitles that distinguish each section and cross-reference adjacent ones; new CSS for `.ph-intro`, `.ph-h-sub`, `.ph-item`, `.ph-item-summary`, `.ph-item-text`, `.ph-item-body`, `.ph-item-row`, `.ph-label`, `.ph-value`, `.ph-status-dot` (+ 5 status-color variants), `.ph-stage-summary`, `.ph-stage-body`; chevron disclosure indicator on every `<details>` (opacity 0.8).
15
+
16
+ **Files changed (tests):**
17
+ - `tests/unit/process-health-render.test.ts`: assertions rewritten for new label vocabulary + new status copy + new framing absence + structural assertions on `<details>` + status-dot CSS classes (3 new structural tests added).
18
+ - `tests/integration/process-health-tab.test.ts`: assertions updated for new copy; new framing-absence check.
19
+ - `tests/e2e/process-health-tab-lifecycle.test.ts`: assertions updated for new copy.
20
+
21
+ **Files changed (release):**
22
+ - `upgrades/NEXT.md` (NEW for this PR, `bump: patch`).
23
+
24
+ ## Decision-point inventory
25
+
26
+ - **Pure UX refinement vs. functional change?** Pure UX. No new endpoints, no new data fields, no new auth surfaces, no behavioral changes to the polling controller, no changes to the route layer, no changes to migration parity. Only the rendered text + DOM structure changes.
27
+ - **Drop the recommendation field entirely vs. keep + relabel?** Dropped. Justin explicitly directed "avoid language that implies user needs to act unless ABSOLUTELY essential". The recommendation field is upstream prose that is action-implying by content; relabeling chrome around it doesn't change that. Actionable insight delivery is the deferred §10 surface anyway; v1 of the tab is the calm informational surface.
28
+ - **Drop the per-card framing line vs. keep + rephrase?** Dropped in v7. Once "verify before acting" was rephrased to "Same kind of problem has come up more than once" in v5, it became the third echo of the section title + section subtitle. The no-action-authority signal that the framing was originally carrying is now structural (the rendered card has nothing actionable on it), not chrome.
29
+ - **Add status color dots vs. status text only?** Dots. Lets the user scan the collapsed list and read state at a glance without expanding each item. Colors are calm (amber/blue/green/gray) — never alarm reds, per the existing visual rules.
30
+
31
+ ## Side-effects analysis
32
+
33
+ - **Behavioral:** None. The polling controller, route layer, and migration paths are unchanged. Only the rendered DOM differs.
34
+ - **Architectural:** None. Same file structure; the renderer module is the same self-contained ESM as before. No new build step, no new runtime dependency.
35
+ - **Security:** The safety contract (`sanitizeForDisplay`, textContent-only DOM writes, element ban, safeUrl) is unchanged. New label spans (`.ph-label`, `.ph-value`) use textContent only. The XSS negative fixture continues to fire zero live elements + no canary. The `detail.full` redaction is unchanged.
36
+ - **Migration parity:** Not applicable — no agent-installed-file changes (`templates.ts` / `PostUpdateMigrator` / shadow markers untouched).
37
+ - **Performance:** Marginal increase in DOM nodes per item (each captured item now has 4–5 `<div>`s of body content instead of 0–4 flat children). Diff-aware rendering still works (signature mechanism is structure-agnostic). No new fetches.
38
+ - **Reversibility:** Fully reversible — revert the commit and the previous render returns.
39
+
40
+ ## Standard captured (the durable artifact this PR exists to back)
41
+
42
+ The 8-round iteration converged on a design that's now codified as the **Dashboard Standard** in `feedback_dashboard_copy_eli16.md` (agent memory): 7 rules (ELI16 copy + codename maps + grounding intro + self-contained section titles with subtitles + expandable items + fixed label vocabulary + no action-implying language), 8 default substitutions, 4 calm status-color tokens, and the show-don't-tell iteration pattern. The Process Health tab is now the reference implementation.
43
+
44
+ ## Evidence pointers
45
+
46
+ - All 46 tests green: 30 unit + 12 integration + 4 e2e — includes structural assertions for the unified label order, status-dot CSS classes, and that the dropped framing line is genuinely absent.
47
+ - Safety verified end-to-end: XSS negative fixture still fires zero live elements + no canary; `detail.full` redaction unchanged.
48
+ - Typecheck: `tsc --noEmit` clean.
49
+ - Live-rendered both views (collapsed + expanded) to Chrome headless across 8 iterations and sent screenshots to the user for thumbs-up before each commit. Justin approved v8 with "this is good enough, let's go with it; save this as the standard for future dashboard features".