@llblab/pi-telegram 0.52.2 → 0.53.0

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 (204) hide show
  1. package/AGENTS.md +9 -7
  2. package/BACKLOG.md +1 -18
  3. package/CHANGELOG.md +11 -0
  4. package/README.md +7 -11
  5. package/api/commands.ts +3 -0
  6. package/dist/api/commands.d.ts +1 -1
  7. package/dist/lib/activity-verbosity.d.ts +1 -5
  8. package/dist/lib/activity-verbosity.js +15 -42
  9. package/dist/lib/activity.d.ts +9 -0
  10. package/dist/lib/activity.js +39 -10
  11. package/dist/lib/agent-messages.js +7 -3
  12. package/dist/lib/bindings.d.ts +43 -5
  13. package/dist/lib/bindings.js +163 -20
  14. package/dist/lib/bus-api.d.ts +12 -0
  15. package/dist/lib/bus-api.js +182 -79
  16. package/dist/lib/bus-follower.d.ts +111 -31
  17. package/dist/lib/bus-follower.js +1324 -359
  18. package/dist/lib/bus-leader.d.ts +41 -91
  19. package/dist/lib/bus-leader.js +969 -637
  20. package/dist/lib/bus-transport.js +16 -9
  21. package/dist/lib/bus.d.ts +215 -18
  22. package/dist/lib/bus.js +1048 -327
  23. package/dist/lib/channel-posts.d.ts +5 -0
  24. package/dist/lib/channel-posts.js +434 -261
  25. package/dist/lib/command-templates.d.ts +26 -5
  26. package/dist/lib/command-templates.js +92 -176
  27. package/dist/lib/commands.d.ts +168 -82
  28. package/dist/lib/commands.js +1409 -291
  29. package/dist/lib/config.d.ts +1 -8
  30. package/dist/lib/config.js +34 -76
  31. package/dist/lib/delivery.d.ts +2 -2
  32. package/dist/lib/delivery.js +16 -16
  33. package/dist/lib/extension.js +639 -171
  34. package/dist/lib/generative-app-worker.mjs +19 -7
  35. package/dist/lib/generative-apps.d.ts +0 -5
  36. package/dist/lib/generative-apps.js +61 -49
  37. package/dist/lib/inbound.d.ts +5 -0
  38. package/dist/lib/inbound.js +35 -59
  39. package/dist/lib/journal.d.ts +33 -3
  40. package/dist/lib/journal.js +2063 -782
  41. package/dist/lib/lifecycle.d.ts +2 -6
  42. package/dist/lib/lifecycle.js +75 -58
  43. package/dist/lib/locks.d.ts +29 -3
  44. package/dist/lib/locks.js +289 -108
  45. package/dist/lib/logging.js +50 -14
  46. package/dist/lib/media.d.ts +22 -1
  47. package/dist/lib/media.js +46 -28
  48. package/dist/lib/menu-model.d.ts +19 -5
  49. package/dist/lib/menu-model.js +53 -11
  50. package/dist/lib/menu-queue.d.ts +5 -4
  51. package/dist/lib/menu-queue.js +45 -63
  52. package/dist/lib/menu-settings.d.ts +5 -4
  53. package/dist/lib/menu-settings.js +114 -78
  54. package/dist/lib/menu-status.d.ts +1 -1
  55. package/dist/lib/menu-status.js +8 -25
  56. package/dist/lib/menu-thinking.d.ts +6 -1
  57. package/dist/lib/menu-thinking.js +14 -21
  58. package/dist/lib/menu.d.ts +8 -61
  59. package/dist/lib/menu.js +92 -164
  60. package/dist/lib/model.d.ts +1 -1
  61. package/dist/lib/model.js +2 -16
  62. package/dist/lib/outbound-attachments.d.ts +6 -27
  63. package/dist/lib/outbound-attachments.js +45 -38
  64. package/dist/lib/outbound-buttons.js +22 -16
  65. package/dist/lib/outbound-markup.d.ts +0 -2
  66. package/dist/lib/outbound-markup.js +51 -64
  67. package/dist/lib/outbound-voice.js +6 -3
  68. package/dist/lib/outbound.d.ts +6 -6
  69. package/dist/lib/outbound.js +61 -51
  70. package/dist/lib/ownership.js +6 -2
  71. package/dist/lib/paths.d.ts +5 -0
  72. package/dist/lib/paths.js +37 -21
  73. package/dist/lib/pi.d.ts +2 -0
  74. package/dist/lib/pi.js +8 -1
  75. package/dist/lib/polling.d.ts +21 -37
  76. package/dist/lib/polling.js +59 -50
  77. package/dist/lib/preview.js +39 -19
  78. package/dist/lib/process-identity.d.ts +24 -0
  79. package/dist/lib/process-identity.js +133 -0
  80. package/dist/lib/prompts.js +2 -7
  81. package/dist/lib/queue.d.ts +14 -16
  82. package/dist/lib/queue.js +249 -126
  83. package/dist/lib/recovery.d.ts +2 -83
  84. package/dist/lib/recovery.js +20 -274
  85. package/dist/lib/replies.d.ts +16 -24
  86. package/dist/lib/replies.js +99 -116
  87. package/dist/lib/routing.d.ts +120 -7
  88. package/dist/lib/routing.js +4667 -1152
  89. package/dist/lib/runtime.d.ts +1 -11
  90. package/dist/lib/sections.d.ts +4 -29
  91. package/dist/lib/sections.js +7 -20
  92. package/dist/lib/skills.js +4 -3
  93. package/dist/lib/status.js +86 -57
  94. package/dist/lib/sync.d.ts +1 -3
  95. package/dist/lib/sync.js +67 -43
  96. package/dist/lib/target.d.ts +4 -0
  97. package/dist/lib/target.js +18 -0
  98. package/dist/lib/telegram-api.d.ts +18 -13
  99. package/dist/lib/telegram-api.js +148 -53
  100. package/dist/lib/text-groups.js +4 -39
  101. package/dist/lib/thread-cleanup-manager.d.ts +6 -27
  102. package/dist/lib/thread-cleanup-manager.js +369 -186
  103. package/dist/lib/thread-display.d.ts +1 -2
  104. package/dist/lib/thread-display.js +58 -38
  105. package/dist/lib/thread-naming.d.ts +28 -8
  106. package/dist/lib/thread-naming.js +175 -66
  107. package/dist/lib/thread-reconciler.d.ts +42 -16
  108. package/dist/lib/thread-reconciler.js +90 -50
  109. package/dist/lib/threads.d.ts +82 -20
  110. package/dist/lib/threads.js +2247 -855
  111. package/dist/lib/time-injection.js +1 -2
  112. package/dist/lib/turns.js +1 -19
  113. package/dist/lib/updates.d.ts +169 -80
  114. package/dist/lib/updates.js +2418 -641
  115. package/dist/lib/voice.d.ts +7 -22
  116. package/dist/lib/voice.js +7 -22
  117. package/dist/lib/wire.js +1 -1
  118. package/dist/lib/workspace-admission.d.ts +3 -1
  119. package/dist/lib/workspace-admission.js +425 -211
  120. package/dist/lib/workspace-identity.js +8 -13
  121. package/dist/lib/workspace-retirement.d.ts +1 -1
  122. package/dist/lib/workspace-retirement.js +328 -140
  123. package/dist/lib/workspace-slots.js +8 -4
  124. package/dist/package.json +1 -1
  125. package/docs/architecture.md +31 -29
  126. package/docs/inbound.md +1 -1
  127. package/docs/multi-instance-bus.md +15 -3
  128. package/docs/outbound.md +1 -1
  129. package/docs/public-api.md +29 -1
  130. package/docs/ui-style.md +25 -8
  131. package/lib/activity-verbosity.ts +59 -82
  132. package/lib/activity.ts +146 -102
  133. package/lib/agent-messages.ts +12 -5
  134. package/lib/bindings.ts +389 -82
  135. package/lib/bus-api.ts +263 -102
  136. package/lib/bus-follower.ts +2440 -601
  137. package/lib/bus-leader.ts +2209 -1290
  138. package/lib/bus-transport.ts +46 -12
  139. package/lib/bus.ts +1673 -444
  140. package/lib/channel-posts.ts +848 -327
  141. package/lib/command-templates.ts +152 -265
  142. package/lib/commands.ts +2398 -555
  143. package/lib/config.ts +177 -170
  144. package/lib/delivery.ts +41 -29
  145. package/lib/extension.ts +1206 -433
  146. package/lib/generative-app-worker.mjs +19 -7
  147. package/lib/generative-apps.ts +324 -211
  148. package/lib/inbound.ts +95 -97
  149. package/lib/journal.ts +5311 -1763
  150. package/lib/keyboard.ts +1 -3
  151. package/lib/lifecycle.ts +128 -78
  152. package/lib/locks.ts +677 -203
  153. package/lib/logging.ts +147 -58
  154. package/lib/media.ts +82 -43
  155. package/lib/menu-model.ts +85 -18
  156. package/lib/menu-queue.ts +88 -129
  157. package/lib/menu-settings.ts +260 -155
  158. package/lib/menu-status.ts +20 -60
  159. package/lib/menu-thinking.ts +41 -56
  160. package/lib/menu.ts +112 -285
  161. package/lib/model.ts +8 -22
  162. package/lib/outbound-attachments.ts +156 -125
  163. package/lib/outbound-buttons.ts +76 -49
  164. package/lib/outbound-markup.ts +96 -94
  165. package/lib/outbound-voice.ts +33 -27
  166. package/lib/outbound.ts +125 -125
  167. package/lib/ownership.ts +19 -10
  168. package/lib/paths.ts +148 -49
  169. package/lib/pi.ts +35 -15
  170. package/lib/polling.ts +144 -147
  171. package/lib/preview.ts +93 -40
  172. package/lib/process-identity.ts +164 -0
  173. package/lib/prompts.ts +4 -11
  174. package/lib/queue.ts +511 -300
  175. package/lib/recovery.ts +50 -454
  176. package/lib/rendering.ts +1 -3
  177. package/lib/replies.ts +248 -209
  178. package/lib/routing.ts +8509 -2186
  179. package/lib/runtime.ts +1 -12
  180. package/lib/sections.ts +24 -89
  181. package/lib/setup.ts +1 -3
  182. package/lib/skills.ts +9 -4
  183. package/lib/status.ts +215 -110
  184. package/lib/sync.ts +448 -361
  185. package/lib/target.ts +22 -3
  186. package/lib/telegram-api.ts +302 -127
  187. package/lib/text-groups.ts +5 -39
  188. package/lib/thread-cleanup-manager.ts +833 -331
  189. package/lib/thread-display.ts +213 -97
  190. package/lib/thread-naming.ts +232 -87
  191. package/lib/thread-reconciler.ts +155 -72
  192. package/lib/threads.ts +5318 -1845
  193. package/lib/time-injection.ts +1 -4
  194. package/lib/turns.ts +15 -28
  195. package/lib/updates.ts +5184 -1612
  196. package/lib/voice.ts +7 -35
  197. package/lib/wire.ts +1 -1
  198. package/lib/workspace-admission.ts +996 -416
  199. package/lib/workspace-identity.ts +14 -17
  200. package/lib/workspace-retirement.ts +878 -376
  201. package/lib/workspace-slots.ts +22 -13
  202. package/package.json +1 -1
  203. package/scripts/check-downgrade.mjs +0 -472
  204. package/scripts/measure-workspace.mjs +0 -108
@@ -21,8 +21,10 @@ function isValidSnapshot(bindings, reservedSlots, nowMs) {
21
21
  const slots = new Set();
22
22
  const keys = new Set();
23
23
  for (const binding of bindings) {
24
- if (!isSlot(binding.slot) || !binding.bindingKey ||
25
- slots.has(binding.slot) || keys.has(binding.bindingKey))
24
+ if (!isSlot(binding.slot) ||
25
+ !binding.bindingKey ||
26
+ slots.has(binding.slot) ||
27
+ keys.has(binding.bindingKey))
26
28
  return false;
27
29
  slots.add(binding.slot);
28
30
  keys.add(binding.bindingKey);
@@ -31,12 +33,14 @@ function isValidSnapshot(bindings, reservedSlots, nowMs) {
31
33
  }
32
34
  function eligibleByInactivity(bindings, reservedSlots, nowMs) {
33
35
  const reserved = new Set(reservedSlots);
34
- return bindings.filter((binding) => binding.protection === "eligible" &&
36
+ return bindings
37
+ .filter((binding) => binding.protection === "eligible" &&
35
38
  !reserved.has(binding.slot) &&
36
39
  typeof binding.inactiveSinceMs === "number" &&
37
40
  Number.isFinite(binding.inactiveSinceMs) &&
38
41
  binding.inactiveSinceMs >= 0 &&
39
- binding.inactiveSinceMs <= nowMs).sort((left, right) => left.inactiveSinceMs - right.inactiveSinceMs ||
42
+ binding.inactiveSinceMs <= nowMs)
43
+ .sort((left, right) => left.inactiveSinceMs - right.inactiveSinceMs ||
40
44
  left.slot.charCodeAt(0) - right.slot.charCodeAt(0));
41
45
  }
42
46
  /** Caller must recheck exact ownership and protected work before retirement. */
package/dist/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@llblab/pi-telegram",
3
- "version": "0.52.2",
3
+ "version": "0.53.0",
4
4
  "private": false,
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -59,18 +59,32 @@ The repository uses a **Flat Domain DAG**:
59
59
  - Narrow structural projections are allowed when they avoid importing broader runtime or wire DTOs.
60
60
  - Source file headers include `Zones:` tags so cross-cutting responsibility stays visible without folder nesting.
61
61
 
62
+ ### Live-Rebind Module Map
63
+
64
+ Release `0.53.0` adds the [live-rebind channel](./multi-instance-bus.md#live-rebind-channel) and bounded old-Thread cleanup. It advertises live save/apply/settle, command-set and selected-menu-delivery through protocol v2, retaining Workspace Restore for legacy continuity. A loaded 0.53.0 build prefers the live path; an instance still running an older build keeps Restore until it is reloaded. Windows runs the same channel and strict reads, exercised by the CI matrix; there is no platform-specific alternate protocol.
65
+
66
+ The channel reuses existing owners rather than adding a parallel command bus, queue or recovery store:
67
+
68
+ - `routing` / `threads`: Chooser authority, atomic same-session canonical binding/operation publication, recipient application and separate one-shot cleanup scheduling. Protected or uncertain work never becomes a delete grant.
69
+ - `commands`: Shared supported plans for Status/Abort/Stop/Next/Continue and registered prompt templates. Compatible leader status/control plans retain inline replies; held followers retain detached restricted delivery. Leader queue plans capture genuine warm originals before release and retain routing custody; followers execute only their saved carrier. Nonmatching menus/help/naming/confirmation retain native owners, and extension selected producers remain a separate leader-only contract.
70
+ - `updates` / `journal` / `queue` / `turns`: Existing exact source identity, receipt ownership, no-fold admission, publication/readiness and native removal ACKs. Semantic completion, queue acceptance and reply delivery are not source removal. Uncertain outcomes never permit another handler invocation, fallback admission or a second queue.
71
+ - `bus` / `bus-follower` / `bindings`: Authenticated generation/session/recipient-scoped transport and preparation. Wire syntax does not decide command availability or create execution authority; the captured recipient registry does.
72
+
73
+ Only the live cleanup origin uses the approved historical-protection reduction. Existing Restore/retirement, strict source readers, queued custody and retained completion ACKs keep their contracts. Command-channel policy and protocol identities belong in [Live-Rebind Channel](./multi-instance-bus.md#live-rebind-channel).
74
+
62
75
  ### Domain Ownership Map
63
76
 
64
- - `lib/extension.ts`: composition root for live ports, domain runtime construction, cross-domain port wiring, and lifecycle registration. It exposes wiring but owns no process identity, journal-binding selection, mutable late-binding state, admission lifecycle selection, reusable policy, or low-level adapter mechanics; those belong to `bus`, `journal`, `prompts`, `activity-verbosity`, `updates`, and other named domains.
77
+ - `lib/extension.ts`: composition root for live ports, domain runtime construction, cross-domain port wiring, and lifecycle registration. It exposes wiring but owns no process identity, journal-binding selection, mutable late-binding state, admission lifecycle selection, reusable policy, or low-level adapter mechanics; those belong to `bus`, `process-identity`, `journal`, `prompts`, `activity-verbosity`, `updates`, and other named domains.
65
78
  - `api`: Bot API helpers, retries, uploads/downloads, temp cleanup, byte limits, chat actions, lazy token clients, and API error recording. Its optional Workspace-admission client classifies valid threaded requests exactly, chat-only requests chat-wide, malformed declared targets profile-wide, and targetless methods as outside the fence; JSON and multipart leases span internal retries through final settlement. Admission blocks prevent issuance, while release errors remain protective diagnostics and never convert an already-settled non-idempotent request into replay. Production composition resolves this adapter from the current bot/profile admission runtime.
66
79
  - `config` / `setup`: `telegram.json`, bot token setup, named bot/session profiles, first-user pairing, authorization, env fallback, atomic persistence, effective config views, and live config accessors.
67
80
  - `locks` / `polling`: extension-local transport owner storage, exact-owner epoch exposure, process-global reload generations, completed-generation suspension evidence, owner-aware polling lifecycle/takeover/follower registration, and classic-vs-Threaded capability orchestration. Polling owns long-poll state, worker-before-poller startup, strict batch validation, journal-before-offset admission, one offset commit per response, and non-awaited worker signaling.
68
- - `journal`: private profile/bot-scoped raw-update authority with strict v1 identity/schema validation, exact deduplication, bounded transaction-serialized `0600` publication, process/session/acquisition-bound prompt/control receipts, owner-fenced completion, durable retry state, and generic removal that rejects queued or legacy failed authority. Prepared v1 `sourceCompletions` retain bounded acceptance-scoped ACKs atomically with exact removal, survive compaction, and require strict source-handle inspection; runtime consumption remains uncomposed. Runtime/recovery identity separates token rotation from future proof-gated queue-owner recovery. Read-only follower-journal discovery enumerates canonical profile-exact snapshots and segment roots and reports incomplete evidence for unexpected matching paths. Its optional Workspace-admission adapter conservatively classifies each append batch as exact-target, chat-wide, or profile-wide, holds all leases through publication, and releases acquired partial batches on rejection; production journal bindings resolve that adapter for leader, follower, recipient, and historical-path stores.
81
+ - `journal`: private profile/bot-scoped raw-update authority with strict v1 identity/schema validation, exact deduplication, bounded transaction-serialized `0600` publication, process/session/acquisition-bound prompt/control receipts, owner-fenced completion, durable retry state, and generic removal that rejects queued or legacy failed authority. Prepared v1 `sourceCompletions` retain bounded acceptance-scoped ACKs atomically with exact removal, survive compaction, and require strict source-handle inspection; private worker/Restore consumers and the live-rebind candidate use exact scoped observation without exposing mutation or recovery through public package membranes. Runtime/recovery identity separates token rotation from future proof-gated queue-owner recovery. Read-only follower-journal discovery enumerates canonical profile-exact snapshots and segment roots and reports incomplete evidence for unexpected matching paths. Its optional Workspace-admission adapter conservatively classifies each append batch as exact-target, chat-wide, or profile-wide, holds all leases through publication, and releases acquired partial batches on rejection; production journal bindings resolve that adapter for leader, follower, recipient, and historical-path stores.
69
82
  - `wire`: Non-coercing shallow decoded-value predicates reused by Config, IPC, journal, admission, shared-state, queue, markup and Restore codecs. `isWireRecord` means non-array object, not a plain-object/prototype or JSON-serializability guarantee; `hasOnlyWireKeys` checks own enumerable string keys without requiring fields or considering inherited, hidden or symbol keys; `isNonNegativeWireInteger` preserves safe-number bounds, including zero; `isNonEmptyWireString` deliberately preserves whitespace. Proxy/inspection errors propagate. Domain schemas, lossless/foreign-evidence checks, normalization, errors, physical protection and effect authority remain with their owners. Assistant action fields use the separate shared `outbound-markup.getTelegramActionString` trim policy for voice/buttons. Decimal-only safe API activity parsing must not inherit the legacy integer coercion used by thread/API compatibility paths; hash framing, canonical sorting, encoding, prefixes and truncation remain protocol-owned rather than a generic SHA wrapper.
70
83
  - `thread-naming`: Name/title value policy and the exact-target manual-name dialog under one owner. Owns generated hints, identity normalization/grapheme fallback, palette/entropy selection, distinct identity/manual-display validation, the three-field template formatter and its title adapter, plus expiring session-scoped input/reset/cancel state. Dialog state exists only inside its runtime factory; value-policy calls do not instantiate it. Threads, Routing, Bus leader and extension validation consume this contract directly. Threads keeps old exports and the full provision-request formatter signature through the same typed function reference, not a wrapper. Live occupancy/current-record/slot policy, display projection and API/store effects remain elsewhere. Naming algorithms, palette order, limits, scope/target fencing, expiry and UI copy are unchanged.
71
84
  - `workspace-identity`: Exact session/CWD normalization, bounded directory/session keys and local instance-slot encoding. Owns `TelegramWorkspaceBindingIdentity`, the precomputed-key constructor and the shared key-length bound used by collision handling; it depends only on Node crypto/path and existing platform/CWD defaults. Threads, Sync, Routing and both Bus roles consume identity functions directly from this owner; Threads retains old identity exports as compatibility reexports. These value calls do not borrow Threads storage or effect authority. No store, target allocation, admission, callbacks or reverse dependency; constructing a key grants no storage-reference or custody authority.
72
85
  - `target`: Pure `{ chatId, threadId? }` address-value identity. `areTelegramTargetsEqual` compares both fields exactly; a missing Thread differs from Thread zero, and object identity is no shortcut. `getTelegramTargetKey` keeps the canonical `private` sentinel. Delivery, activity and Workspace domains reuse these functions; optional-target and differently keyed policies remain local. Address equality never grants transport, execution or deletion authority.
73
- - `bus` / `bus-api` / `bus-leader` / `bus-follower` / `ownership`: Threaded Mode multi-instance bus contracts, profile-scoped process/endpoint identity, local leader/follower IPC, leader-only orchestration, follower-side manual registration/session runtime, follower-routed Bot API calls, and live message ownership. `bus` owns protocol v1 independently from package build, canonical capabilities, compatibility, process identity, profile-aware endpoints, IPC primitives, and replacement-invalidated non-routing registry observations. Registration rejects missing/mismatched protocol before provisioning while preserving compatible package skew; negotiated identity reaches status/state. Leader runtime, leader envelope handling, follower assembly, and follower registration construction require explicit protocol identity, preventing identity-less composition at both production and low-level runtime boundaries. `bus-leader` owns leader envelope handling and polling/server/prune orchestration; its Workspace-admission assembly holds a chat-wide lease across leader provisioning and profile-wide leases across follower provisioning/registration, disconnect/dead cleanup, leader/follower rename, display preference/reconciliation, and detached post-provision cleanup through its delayed API/store settlement. It consumes the profile operation runtime shared with Sync and routing; admission precedes that process-local mutation gate, fence rejection occurs before mutation, and release follows complete settlement. `bus-follower` owns registration/ack negotiation, active leader-auth/election state, heartbeat, authenticated clients, forwarded receiving, and recovery. Its production assembly holds profile-wide admission across follower-to-leader promotion, so a retained fence rejects it before leadership acquisition or store mutation. Production leader composition resolves the admission assembly at each operation boundary. The proof-aware follower Restore receiver replaces legacy target replacement: the old `leader.replaceFollowerTarget` producer, parser and receiver are removed, so even authenticated old-format requests are rejected before recipient effects. Profile admission surrounds exact retained-operation, authenticated leader/context, registration-generation, session/CWD and canonical binding/slot checks. `apply` updates only local registration after the leader's canonical commit; an already matching target does not switch again. `inspect` never switches targets and reports the observed local target plus readiness. Neither mode persists canonical state, manufactures deletion/probe evidence or dispatches input. Validated loading alone does not authorize the recipient effect. `threads.withWorkspaceRestoreSnapshot` now holds the canonical transaction while checking the exact retained intent, binding protection and recovery evidence, then supplies fresh binding/owner data to a synchronous read-only observation. Both `apply` and `inspect` run their existing recipient checks, local application and readiness construction inside this boundary, with fresh scoped-intent and live-context checks. The callback contract excludes asynchronous observers; neither cached projection nor callback completion grants canonical persistence. A follower with `canPersist: false` can observe but still cannot use the leader's registration publisher. Native regressions reject receipts, binding regression, owner detachment, intent adoption and context replacement arriving after load; valid reobservation never repeats apply. The transaction spans the local effect, releases on failure, and neither receiver mode changes canonical bytes. The leader recipient path uses the same observation: session/CWD/slot and active-owner selection consume its fresh binding/owner rows, not the warm store, and the transaction spans local identity application and readiness construction. Full-capacity native worker fixtures reject post-grant receipts, binding/owner regression and context changes both before first apply and during inspection after a lost apply reply, preserving the pending original and issued grant without undoing an earlier valid apply. These fixtures do not authorize activation or live fault injection. A composed capability-gated controller and authenticated envelope connect this receiver across native IPC, with one transport attempt and exact readiness-response validation; see the [bus contract](./multi-instance-bus.md#protocol-identity-and-compatibility). Successor inspection can verify a changed follower registration or process only against its actual session/CWD, one current canonical owner, the unchanged binding/slot and observed local target; an old local target remains not ready. Successors cannot use the original apply grant. Follower target preparation uses `threads.assertWorkspaceRestoreRegistration` before recovery allocation, visibility probes and owner transfer, after probe awaits, and before returning the prepared target. The read-only precondition checks fresh canonical and recovery evidence under the snapshot transaction; a protected target requires its exact binding key, slot and relocated target, never the old target. Lost evidence or late recovery conflicts cannot fall through to visibility-error recovery or leave a transient claim held. This is not registration/transport authority: callers still own authentication, profile/session/leader/generation checks and Workspace admission. Bootstrap now re-enters profile admission and the shared mutation gate for `commitWorkspaceRestoreRegistration`; declared Workspace bindings are checked again in the publication snapshot, even without retained Restore. The synchronous callback rechecks captured leader epoch, profile and operator before writing. Missing, unused, reused or expired publication authority cannot report success; the post-commit ACK rechecks current registration identity, allowing heartbeat, connection-time and Thread-name metadata changes. Lost post-publication authority never removes independently published state. Native authenticated bootstrap tests cover the real transaction and late recovery/authority changes. The root protocol identity now advertises `workspace-restore-v1`; every participating peer must run this build before its Restore is used.
86
+ - `process-identity`: PID liveness and stable process-birth identity: Linux `/proc` start ticks, macOS `ps` start time and Windows creation ticks read through PowerShell (cached only for the current process). Only an absent PID (`ESRCH`) or a mismatched birth proof yields `dead`; a live PID without a birth proof (inaccessible metadata, such as another user's process, or a generation fallback) is `unverifiable`. It is a leaf over Node child-process/crypto/fs/os so Locks, Bus, Journal, Workspace admission and Generative Apps share one proof without durable storage depending on the IPC protocol. Liveness never grants authority by itself.
87
+ - `bus` / `bus-api` / `bus-leader` / `bus-follower` / `ownership`: Threaded Mode multi-instance bus contracts, profile-scoped process/endpoint identity, local leader/follower IPC, leader-only orchestration, follower-side manual registration/session runtime, follower-routed Bot API calls, and live message ownership. `bus` owns session-native protocol v2 independently from package build, canonical capabilities, compatibility, process runtime identity, profile-aware endpoints, IPC primitives, and replacement-invalidated non-routing registry observations. Registration rejects missing/mismatched protocol before provisioning while preserving compatible package skew; negotiated identity reaches status/state. Leader runtime, leader envelope handling, follower assembly, and follower registration construction require explicit protocol identity, preventing identity-less composition at both production and low-level runtime boundaries. `bus-leader` owns leader envelope handling and polling/server/prune orchestration; its Workspace-admission assembly holds a chat-wide lease across leader provisioning and profile-wide leases across follower provisioning/registration, disconnect/dead cleanup, leader/follower rename, display preference/reconciliation, and detached post-provision cleanup through its delayed API/store settlement. It consumes the profile operation runtime shared with Sync and routing; admission precedes that process-local mutation gate, fence rejection occurs before mutation, and release follows complete settlement. `bus-follower` owns registration/ack negotiation, active leader-auth/election state, heartbeat, authenticated clients, forwarded receiving, and recovery. Its production assembly holds profile-wide admission across follower-to-leader promotion, so a retained fence rejects it before leadership acquisition or store mutation. Production leader composition resolves the admission assembly at each operation boundary. The proof-aware follower Restore receiver replaces legacy target replacement: the old `leader.replaceFollowerTarget` producer, parser and receiver are removed, so even authenticated old-format requests are rejected before recipient effects. Profile admission surrounds exact retained-operation, authenticated leader/context, registration-generation, session/CWD and canonical binding/slot checks. `apply` updates only local registration after the leader's canonical commit; an already matching target does not switch again. `inspect` never switches targets and reports the observed local target plus readiness. Neither mode persists canonical state, manufactures deletion/probe evidence or dispatches input. Validated loading alone does not authorize the recipient effect. `threads.withWorkspaceRestoreSnapshot` now holds the canonical transaction while checking the exact retained intent, binding protection and recovery evidence, then supplies fresh binding/owner data to a synchronous read-only observation. Both `apply` and `inspect` run their existing recipient checks, local application and readiness construction inside this boundary, with fresh scoped-intent and live-context checks. The callback contract excludes asynchronous observers; neither cached projection nor callback completion grants canonical persistence. A follower with `canPersist: false` can observe but still cannot use the leader's registration publisher. Native regressions reject receipts, binding regression, owner detachment, intent adoption and context replacement arriving after load; valid reobservation never repeats apply. The transaction spans the local effect, releases on failure, and neither receiver mode changes canonical bytes. The leader recipient path uses the same observation: session/CWD/slot and active-owner selection consume its fresh binding/owner rows, not the warm store, and the transaction spans local identity application and readiness construction. Full-capacity native worker fixtures reject post-grant receipts, binding/owner regression and context changes both before first apply and during inspection after a lost apply reply, preserving the pending original and issued grant without undoing an earlier valid apply. These fixtures do not authorize activation or live fault injection. A composed capability-gated controller and authenticated envelope connect this receiver across native IPC, with one transport attempt and exact readiness-response validation; see the [bus contract](./multi-instance-bus.md#protocol-identity-and-compatibility). Successor inspection can verify a changed follower registration or process only against its actual session/CWD, one current canonical owner, the unchanged binding/slot and observed local target; an old local target remains not ready. Successors cannot use the original apply grant. Follower target preparation uses `threads.assertWorkspaceRestoreRegistration` before recovery allocation, visibility probes and owner transfer, after probe awaits, and before returning the prepared target. The read-only precondition checks fresh canonical and recovery evidence under the snapshot transaction; a protected target requires its exact binding key, slot and relocated target, never the old target. Lost evidence or late recovery conflicts cannot fall through to visibility-error recovery or leave a transient claim held. This is not registration/transport authority: callers still own authentication, profile/session/leader/generation checks and Workspace admission. Bootstrap now re-enters profile admission and the shared mutation gate for `commitWorkspaceRestoreRegistration`; declared Workspace bindings are checked again in the publication snapshot, even without retained Restore. The synchronous callback rechecks captured leader epoch, profile and operator before writing. Missing, unused, reused or expired publication authority cannot report success; the post-commit ACK rechecks current registration identity, allowing heartbeat, connection-time and Thread-name metadata changes. Lost post-publication authority never removes independently published state. Native authenticated bootstrap tests cover the real transaction and late recovery/authority changes. The root protocol identity now advertises `workspace-restore-v1`; every participating peer must run this build before its Restore is used.
74
88
  - `sync`: demand-driven Telegram reconciliation, mutable sync-slice state, nested provisioning activity, and local assumption policy. It does not own a complete Telegram bot read-model; Bot API lacks a complete topic/thread listing surface. It owns sync slices, invalidation triggers, config-persist invalidation sequencing, exact-target admitted stale-topic API recovery, observation intake, status/debug freshness, paired manual-disconnect/session-restart cleanup assembly, prepared quiescent leader-quit detachment, and reconciliation scheduling across bot identity, pairing assumptions, live target bindings, reservations, and transport health after meaningful observable signals. Production topic lifecycle and disconnect/restart cleanup enter profile-wide admission before the shared Workspace operation gate. Lifecycle admission spans observation-driven store settlement; cleanup admission spans intent publication, Telegram cleanup, binding mutation, durable settlement, and transport release. It should call narrower domain primitives rather than letting `index.ts`, `threads`, or `status` accumulate cross-cutting reconciliation policy.
75
89
  - `thread-reconciler`: Threaded Mode control-plane planning for Telegram thread/tab lifecycle. It owns the reconciliation state machine (`stable`, `provisioning`, `sync-required`, `cleanup-required`), pure plans, proof-before-delete rules, pending-provision protection, fresh-creation grace windows, leader-epoch checks, and the single policy authority for destructive thread cleanup actions. It excludes live Telegram API calls, inbound routing, menu rendering, and direct persistence.
76
90
  - `thread-cleanup-manager`: Disconnected proof-only admission planning for manual inactive-Workspace cleanup. It emits exact profile/binding/target snapshots only when durable inactivity exists, all live-owner/accepted-work/delivery evidence is `clear`, identities are unique, and no reservation, provision, or cleanup competes. Missing, malformed, duplicate, or `unknown` evidence returns no candidates; age and ordering never create authority. Its disconnected bounded profile/token-scoped work store atomically persists exact candidate snapshots, records one exact Workspace-issued deletion permit as outcome-unknown, rejects mismatched permits, and confirms deleted state idempotently; strict reads reject malformed/private-file ambiguity. A disconnected executor requires an injected exclusive Workspace deletion boundary across fresh planner evidence, exact retained-snapshot comparison, permit acquisition/recording, delete callback, and confirmation. The future fence owner must acquire and recheck in admission-ledger order; a retirement fence cannot be nested inside an active ordinary admission lease. Regressions prove drift stops before permit, unavailable/already-issued state cannot fabricate authority, and ambiguous delete remains outcome-unknown without replay. A production-shaped adapter preserves full Workspace records through external-protection resolution, then snapshots exact cleanup fields, reservations, provisions, and cleanup intents; protection exceptions become `unknown`, while source failures propagate fail-closed. Production Settings exposes **Review inactive tabs** only: profile-wide admission surrounds fresh evidence capture, one canonical 128-bit-digest work-set is retained, and a separate summary reports proven count, explicit no-deletion state, and Back navigation. The exact confirmation callback fits Telegram's 64-byte bound and accepts only canonical work-set IDs. **Clean inactive tabs** renders only when composition supplies a destructive port; production intentionally omits it, so malformed/stale callbacks fail closed and review remains non-destructive. Permit composition must not call `acquireRetirementFence()` because retirement remains pressure-only. The one admission-ledger fence now carries discriminated `pressure-retirement | manual-thread-cleanup` authority, treats legacy missing kind as pressure, exposes `acquireThreadCleanupFence()`, includes kind in exact comparison/permits, and remains profile-singleton. Cleanup-specific adopt/issue/absence/release/complete APIs preserve existing retirement callers and reject cross-kind use. Review admission releases before cleanup-fence acquisition; that fence then spans exact full-record/protection revalidation, sole permit issuance, work-set recording, one delete attempt, absence confirmation, binding/work-set commit, and fence completion. The v1-compatible schema and kind-specific acquire/adopt/issue/absence/release/complete methods are implemented; pressure methods reject manual fences and cleanup methods reject pressure fences. A disconnected permit runtime acquires the cleanup fence, revalidates under it, releases drifted unissued fences, refuses already-issued replay, and retains `commit-ready` until an injected durable commit succeeds. `threads.commitInactiveWorkspaceCleanup()` now removes only an exact full inactive binding after rechecking local records, claims, reservations, provisions, cleanups, and retirement intents; the retained cleanup candidate carries sufficient exact cwd/workspace/instance/global-slot/binding/target/inactivity/update commit identity, and under the retained fence exact absence closes commit-unknown retry without reconstructing the deleted full binding. Commit composition removes the binding before confirming the work-set, and failure retains `commit-ready`. A hidden coordinator validates canonical review identity, resolves the full binding, records the sole permit before one injected delete call, then commits binding, work-set, and fence. A `commit-ready` retry finishes without another delete; ambiguous deletion remains `deletion-issued` and is never replayed. A typed Settings-port adapter exposes this coordinator only when explicitly supplied and reports deleted, outcome-unknown, and blocked counts. Fake-port tests exercise the callback lifecycle and successor recovery: takeover requires injected proof, exact fence identity is preserved, live/unverifiable predecessors fail closed, and `commit-ready` resumes without deletion replay. Cross-process workers prove stale `prepared` contenders call fake transport once: deletion requires successful work-set permit CAS, and redundant fences over deleted entries settle without replay. Work-set pre-rename failure and lost post-rename acknowledgement retain recoverable fence truth; durable `deleted` completes that fence without another transport call. Binding-snapshot pre-rename ownership loss reloads and restores the exact binding, while post-rename acknowledgement loss reloads durable absence as successful commit. Cleanup runtime composition additionally requires candidate/work-set/runtime/fence profile equality before mutation and captures one stable successor owner snapshot for adoption. The optional Settings port reports only redacted exact-authority recovery classes: commit pending, deletion outcome unknown with no retry, or unavailable authority. It exposes no target, path, token, or transport details. Production still omits `cleanInactiveThreads`, so Bot API activation remains separate.
@@ -78,7 +92,7 @@ The repository uses a **Flat Domain DAG**:
78
92
  - `workspace-slots`: Pure bounded global-letter selection and pressure-reclamation proposals. It consumes explicit protection/inactivity evidence and never discovers owners, persists state, or performs deletion.
79
93
  - `workspace-admission`: Durable profile-scoped reader/writer ledger for cross-process exact-target, chat-wide, and profile-wide admission leases plus one destructive retirement fence. It owns atomic lease/fence transactions, proven-dead process-birth recovery, conservative malformed/ambiguous-state handling, exact successor adoption, retained-slot projection, and the durable `fenced` → `deletion-issued` → `commit-ready` or `deletion-rejected` outcomes; one fence emits at most one deletion permit. Its runtime binding resolves `workspace-admission[.<profile>].json`, stores only the token SHA-256 profile authority, preserves separate named-profile identities across switching, permits changed-token rebind only when the prior ledger is provably empty, and fails closed while foreign leases or a fence remain. Issued fences cannot be released before confirmed absence and durable retirement commit; callers own journal/API/provisioning operations and retirement policy. Production composition supplies admission to journals, JSON/multipart API, leader/follower mutations, topic lifecycle, reroute restoration/reclamation, manual disconnect/session-restart cleanup, exact stale-target recovery, and Thread-store slot reservations; journal-evidence pruning also requires caller-supplied admission. Common async runners and the API adapter reject concurrent reuse of a live operation ID before a second caller can share or release its lease; once the first invocation exits, retry-stable recovery remains available. A 2/2 same-model independent post-fix quorum verified complete production-mutation composition at 0.96 confidence per reviewer. Demand-driven retirement is now operator-authorized and wired to fresh allocation; disposable operator smoke remains distinct from local validation.
80
94
  - `workspace-retirement`: Profile/leader-fenced pressure preparation over the store snapshot. It counts standalone reservations, selects one candidate only at full slot capacity, rechecks protection, and persists/resumes an exact durable intent. Workspace bindings accumulate their historical follower-journal routing keys and distinguish complete fresh metadata from incomplete legacy evidence. Its read-only accepted-work policy resolves those binding-specific journals plus the shared leader journal and combines them with local exact targets, failing closed when source coverage or target decoding is incomplete. It can prune a known empty follower-journal key only from complete readable evidence plus explicit writer quiescence under exact binding/profile/epoch fences and an exact-target admission lease held through durable publication. Incomplete legacy bindings consume discovered hashed journals as target-scoped evidence but remain incomplete so every later retirement repeats discovery. The shared Workspace operation runtime serializes topic lifecycle, reroute restoration/reclamation, provisioning, delayed post-provision reconciliation, follower/manual cleanup, rename, and display mutation through one exposed gate. Detached mutation work must reacquire fresh admission rather than inherit a lease already released by its caller. A successor may durably adopt one exact stale-epoch intent after profile/binding/protection revalidation; direct old-epoch execution remains blocked. The isolated executor consumes that gate and requires the durable admission ledger. It acquires or exactly adopts the matching fence, rechecks protection after admissions close, advances to `deletion-issued` before invoking an executor-only `deleteForumTopic` port with the sole permit, and never reissues from that phase. Success or exact absence advances to `commit-ready`; store commit failure retains the fence, and exact completion follows durable binding+intent removal. A successor resolves an issued unknown outcome only through a separate exact-absence probe. Leader composition exposes exact registry, active/queued work, known journals, and profile-exact legacy discovery as protection evidence. Missing queue targets and incomplete reads remain unknown. The common direct Bot API client counts exact JSON/multipart targets until settlement; message-scoped edits/deletes without a thread conservatively protect every binding in their chat. Known historical follower owner keys decode to process-birth identity before liveness checks. Durable intents block matching claims and binding mutations. Fresh leader/follower allocation now uses a serialized capacity wrapper: try ordinary allocation, release its leases on a typed capacity failure, then prepare/adopt/execute retirement under the shared mutation gate and retry once. Restore-only follower startup never evicts. The executor-only direct-client deletion port validates the exact permit and disables both retries and transport fallback. Strict journal protection reads cannot recover/reset evidence. A confirmed `commit-ready` fence can finish after binding removal without another deletion; unknown outcomes remain fenced. See [demand-driven rotation](./multi-instance-bus.md#demand-driven-slot-rotation) for history loss and recovery boundaries.
81
- - `threads`: Telegram UI thread/tab binding state mapped to Bot API `message_thread_id` / `ForumTopic` transport. Owns exact-`cwd` Workspace bindings and transient claims, first-proven inactivity metadata, fenced non-destructive owner detachment with retained Workspace identity/slot, fail-closed retirement occupancy snapshots, and exact durable retirement intents, leader/current-instance identity state, active-turn → follower → leader target preference, matching status projection assembly, profile-bound same-process handoff, exact-claim global-slot allocation and conservative missing/duplicate legacy migration, collision-safe compact thread-name selection, Workspace-aware rename persistence, fenced exact-session target relocation, and primitive provision helpers. Its profile/token/path-bound `workspaceRestore` operations own Restore transitions and publish the exact full source-bound operation in `state[.<profile>].json.workspaceRestore` with binding/owner relocation in one ownership-fenced rename, preserving session, slot, naming preferences and journal evidence. There is one stored commit proof, not two stores exchanging receipts. The same owner enforces strict private regular-file/link/size inspection, scope checks inside publication, capacity and transactional revision CAS. Snapshot `read/relocate/update` mechanics are private; there is no separate Restore module or store factory. POSIX files are `0600`; Windows uses directory ACLs. Restore metadata remains bounded to 26 operations and 1 MiB, within an 8 MiB canonical snapshot. Movement clears stale display/probe evidence without claiming deletion. Conflicting source, binding, slot or targets fail closed. Every supporting snapshot publisher compares the full Restore state and its monotonic revision immediately before rename. It also preserves each retained binding's session identity, slot and relocated target, reserves both targets against other bindings, and rejects owner projections on the old target or conflicting slot. Pending creation and reservation staging reject a retained Restore's binding key, slot or either known target before mutating memory; a creation attempt lacking binding identity also conflicts on the retained owner profile or instance, rather than falling through to another slot. Primitive provisioning therefore cannot publish a conflicting creation intent or call `createForumTopic`, while valid existing-target reuse remains available. Candidate and final-disk validation also reject conflicting pending provisions/reservations, including late evidence, without discarding either intent. Restore publication and transitions inspect the private bounded `.provision-recovery.json` receipt file, matching pending ID, creator instance/profile and leader epoch before considering a recovered target. Both predecessor and candidate references remain protected at final publication. Snapshot publication, Restore transitions and recovery receipt writes serialize through the canonical snapshot transaction before the transport-owner publication fence. Conflicting targets or unreadable recovery evidence block advancement without erasing either source; Restore inspection remains available. Recovery writers never replace a differing receipt or repair damaged JSON, and exact duplicates perform no rewrite. Protected snapshot loading also uses strict recovery-file reads. Before publishing a new Restore, final transactional validation requires a known target for every creation retained in the predecessor snapshot, including entries that an in-memory expiry filter would omit. Canonical targets or exact creator/profile/epoch recovery receipts may establish a non-conflicting target; missing or foreign receipts cannot establish availability. Contradictory canonical/recovered targets fail closed. Loading reads recovery evidence once and, while Restore is retained, validates that exact evidence against the predecessor provisions before replacing any working projection. Conflicting, contradictory or invalid matching receipts reject warm and cold loading without changing disk or the previous projection; retained intent inspection remains available independently. Valid receipts merge before expiry filtering, so a late known creation cannot disappear solely because its original timer elapsed. A failed callback reload remains under the existing worker retry/diagnostic policy without another recipient apply, forwarding or cleanup grant; loading is not effect-time authority. Candidate validation refuses conflicting writes; final disk validation prevents a valid warm projection from silently repairing regressed canonical state. Restore transitions likewise refuse advancement or retirement over inconsistent canonical bindings, while retained intent inspection remains available for source protection. Metadata changes, binding-preserving owner succession and non-destructive owner detachment remain permitted; runtime still authenticates successor session authority. The revision survives final removal, closing empty-record ABA; a read-only Restore observation cannot bless an older binding projection. Warm missing/backward/contradictory evidence, corruption, unsupported schema and revision exhaustion refuse mutation. Old draft receipts or a separate Restore file block rather than migrate or manufacture missing originals. Callers hold Workspace admission and exact source/session/target authority. The initial phase is `relocated`, with no separate `prepared` record or receipt handoff. Subsequent `recipient-issued`, `ready`, source-dispatch and cleanup grants remain distinct; executor adoption never resets issuance. Only authenticated readiness observations may confirm the original recipient or retain a same-session `readyRecipient` successor. Terminal source settlement needs positive journal-owner disposition ACKs, never readiness, queue admission or absence. Canonical `queued` facts remain admission-only; `queue-completed` requires matching queued acceptance/receipt/kind and may upgrade only its proven IDs, leaving siblings nonterminal. Cleanup and retirement reject admission-only sources, including legacy facts; cold terminal receipt facts without acceptance or admission with cleanup fail closed without repair. The prepared `recordSourceAcceptance` stores a separate source-hashed positive execution/recipient result under an issued routing grant; it never counts as settlement or authorizes cleanup/source removal. Exact duplicates are read-only, malformed/contradictory cold evidence is retained without repair, and executor adoption preserves the proof. Follower forwarding composes this pre-report publication from the worker's fresh exact deferred-source hash under its existing dispatch admission; a lost publication reply reconciles only the identical retained proof. Its completion report carries that same hash into journal-owned `removeCompletedExact`; missing/changed sources reject atomically, with no ID-only fallback. Follower Restore now derives its scope hash from the immutable request/operator/retained acceptance, excludes mutable executor/progress, and carries it through admission into atomic source removal plus a scoped journal ACK. The worker requires matching returned and strictly retained evidence with fresh post-publication/inspection authority checks before notification. Production binding composition supplies serialized strict completion ports while preserving ordinary recovery. Follower cold ACK hints now consume exact scoped evidence under fresh admission and authenticated read-only recipient inspection, re-reading after awaits; missing/foreign evidence cannot adopt or settle. Leader command Restore now publishes `completed` acceptance before disposal through a private execution-fenced routed carrier; deferred/queued reports bypass that publisher. Memoized detached evidence handles duplicates without changing the original binding. An optional prepared worker queue-publication barrier now holds readiness through async acceptance and exact receipt/owner reinspection, including grouped and same-process cold reconstruction; serialized production bindings now supply strict full-group v1 queue inspection with exact owner/unoffered source and owner hashes, without recovery or writer admission. Production queued Restore publication now waits for fresh Workspace admission, canonical/live leader identity, exact receipt/source/owner evidence and retained `queued` acceptance, then rechecks receipt and recipient after publication/admission without replay. Same-process worker reconstruction resumes only proof publication, not semantic execution. Native two-source media-group integration now holds whole-receipt readiness through partial proof, changed digest and offered ownership, and resumes only proof on same-process worker reconstruction. A private Restore command carrier now suppresses trailing implicit completion after queued reporting and rejects explicit disposal guards, preserving receipt ownership even if queue commit fails. Native `/continue` keeps one queued continuation through publication faults/reconstruction; `/compact` keeps its confirmation-dialog/completed-source semantics. Direct prompt Restore uses queued admission, not another unqueued completion producer. Cold completed-command ACK continuation now uses fresh admission and exact scope inspection before adoption, read-only canonical current-leader ownership, post-await proof rereads and live/canonical cleanup fences without apply, handler, RPC or disposal replay. Missing/partial/foreign evidence and changed authority preserve protection; actual successor ownership/startup and accepted-work clearance remain fixture preconditions. The strict journal now prepares separate `completeQueuedExact` whole-receipt owner/hash-CAS removal plus atomic scoped ACKs, with complete-group cold continuity and no ordinary/v3 downgrade. It is supplied by the serialized private binding sibling. The worker's explicit scope API still requires full-batch immutable scopes. Cached prepared subsets now require a captured strict full queued-receipt origin inspector: exact complete group/full owner and matching queued-entry hashes precede readiness. Every scoped receipt needs an origin witness. Queue membership is immutable for that owner/acquisition; native scoped ACK publication and cold continuity require complete unoffered group disposal, so matching retained queued-origin witnesses acknowledge that whole receipt after lost replies. Unscoped siblings acquire no marker. The worker consumes those scopes through captured exact disposal/readback capabilities, clearing memory only after returned and retained ACK checks under current binding/context/process/session authority. Required scopes stay sticky; failed or uncertain issuance cannot downgrade to ordinary completion, replay disposal or lend its attempt across worker stop/start. Read-only reconciliation requires every requested exact scope and a proven origin witness for each whole receipt; it never infers ordinary sibling completion from absence. Cold queued ACK hints now share exact leader canonical ownership, pre-adoption scope reads and post-await rereads, publishing terminal receipt facts grouped by receipt/kind without replay. Native cases seed the post-disposal boundary and still supply startup/ownership and work clearance. Production queued acceptance now returns immutable full-receipt scopes through the publication barrier. The worker detaches and retains them before readiness, refuses missing terminal capabilities and uses cached scopes when lifecycle callers complete owned receipts. Its captured post-ACK observer emits a routing hint without requesting Pi dispatch; canonical queue-completed publication still rereads exact proof under fresh admission. Completion-only mux selection permits read-only reconciliation of an issued attempt despite lost execution readiness, never another dispatch or disposal. Subset-scoped sources within one receipt now need strict confirmed whole-receipt queued origin before readiness. Any issued disposition, including pre-write uncertainty, closes execution readiness while permitting completion-only proof reconciliation. Mixed batches of independent whole receipts now settle the scoped group before a separate ordinary group, rechecking owner/context/process/session/binding between them. A component failure cannot roll back another positive ACK. Mux/runtime completion retries reuse exact acknowledged receipt objects for local cleanup only, never readiness or another disposal. Ordinary sources acquire no scoped ACK; their unknown disposition retains ordinary protection. Post-ACK authority loss suppresses a stale scoped worker wake. Native producer/lifecycle fixtures cover grouped, discard, lost ACK/readback and canonical publication interruption; Pi handoff remains supplied. Terminal proof lifetime follows [settlement ordering](./multi-instance-bus.md#restore-settlement-ordering); actual startup was accepted in the operator's 0.52.0 live smoke. Cleanup can be issued only after all originals settle; unknown issuance cannot become not-issued. Exact old-target completion or positively unissued cleanup permits terminal retirement without touching accepted recipient queues or authorizing operation-ID reuse. Lost commit replies reconcile only the exact full operation. These operations perform no transport, source dispatch or deletion. Production resolves this native view for authenticated follower reception, exact unfinished-source startup holds even after the target becomes bound, and pressure-retirement protection. Restore capability is advertised; every participating peer must run 0.52.0 or later. The same scoped Restore snapshot also stores at most 26 source-bound temporary-Thread entries for All commands. Each entry records the exact journal binding and update ID, operator, executor, a unique 128-bit title token, `creating` or `created` phase and the acknowledged operator-chat target. It holds no Workspace binding or slot. `reserveTemporaryThread` publishes `creating` before the caller's single creation request. An existing source entry is returned instead of licensing another creation, and only explicit retirement frees the source. `acknowledgeTemporaryThread` records the target once; `adoptTemporaryThread` and `retireTemporaryThread` are executor-fenced exact CAS transitions that release protection only. Created targets are refused to provisions, reservations, Workspace bindings and owner records, both when staged and at final publication. The only exception is a retained Restore of the same source, which may rebind an existing Workspace and slot to the tab. Transition publication checks this protection against the resulting file, not only its predecessor. Strict parsing rejects malformed tokens, duplicate sources, tokens or targets, empty lists and foreign-chat targets. Followers cannot publish. Routing's `sendAllTabTemporaryThreadChooser` uses this store for a known threadless owner command whenever this process owns a leader epoch (no flag or configuration; each effect rechecks epoch, journal binding, operator and context). Under profile admission it adopts or reuses the source's entry, or reserves one and issues a single `createForumTopic` titled `Route /<command> · <token prefix>`. A positive thread ID is acknowledged; any error or missing ID leaves `creating` as an unknown outcome. The command original is reported deferred, never completed, and stays in the All journal. A created entry publishes the full reroute/restore chooser inside the tab, whose target becomes the pending chooser's `sourceTarget`. An unknown entry is held with an All notice and never retried. A failed publication leaves the source retryable, and a replay or restart reuses the same tab. The All-command age limit still terminally settles a never-presented replay but never expires a presented tab. Forward from the tab uses the existing command dispatch and unbound-Thread cleanup: the command runs once in the selected Pi, routing reports the deferred All original complete, and the tab is removed through `thread-reconciler`. A worker completion observer then retires the entry under fresh profile admission and current temporary-Thread authority, adopting a predecessor executor first; absence of the entry or lost authority leaves it retained. When the fresh source still supports deferred abandonment, the tab's chooser also offers one **Cancel routing** action and states that it keeps the original privately, without sending it to Pi, and removes this tab. That click first commits the existing private retention and discard tombstone. It then makes one `thread-reconciler` removal attempt for the entry's own acknowledged target and retires the entry only after confirmed removal. A skipped or failed removal edits the chooser to say the tab could not be removed; the entry keeps protecting the tab, and nothing repeats the deletion automatically. A duplicate click abandons nothing twice. After restart the source belongs to the worker's first snapshot, so Cancel is not offered. A retained tab is protected against other cleanup. The shared `createTelegramCleanupTargetProtection` used by bus, Sync and Thread lifecycle now calls the store's `listTemporaryThreadTargets()`, a fresh strict read of acknowledged targets that protects on any read failure. Routing's `isRerouteTargetProtected` exempts only the exact own entry (token, source and target) passed by that tab's Forward, Cancel or pending unbound cleanup. For example, a prompt typed inside the tab can be routed, but its Forward cannot remove the tab. After the entry retires, a still-pending Forward cleanup is ordinary unbound cleanup. Restore from the tab passes the same own-entry exemption to its source-ownership check and then uses the shared Restore producer with the tab as destination. `threads` accepts that relocation only for the Restore of the same source. The command is dispatched once to the restored recipient and reported complete, and the completion observer retires the entry. The Workspace keeps its slot on the tab, and the tab is not removed. A native leader fixture proves this path with Restore authority enabled. Without a leader epoch or the stores, the legacy All chooser remains the fallback. The lifecycle sections below own Restore from the tab, cancellation cleanup and cleanup protection; unknown creation or removal outcomes are never released automatically. Its optional external-slot source makes every generic allocation, Workspace claim, and occupancy snapshot reserve retained admission-fence slots; malformed, unreadable, or non-uppercase evidence fails allocation closed. Its synchronous provision-commit helper transfers exact targeted creation-title evidence into the claim-committed Workspace binding and consumes matching pending evidence; callers retain admission, epoch checks, and durable publication. It should not turn dormant bindings into routing authority, own destructive cleanup policy, or grow into the general Telegram synchronization domain.
95
+ - `threads`: Telegram UI thread/tab binding state mapped to Bot API `message_thread_id` / `ForumTopic` transport. Owns exact-`cwd` Workspace bindings and transient claims, first-proven inactivity metadata, fenced non-destructive owner detachment with retained Workspace identity/slot, fail-closed retirement occupancy snapshots, and exact durable retirement intents, leader/current-instance identity state, active-turn → follower → leader target preference, matching status projection assembly, profile-bound same-process handoff, exact-claim global-slot allocation and conservative missing/duplicate legacy migration, collision-safe compact thread-name selection, Workspace-aware rename persistence, fenced exact-session target relocation, and primitive provision helpers. Its profile/token/path-bound `workspaceRestore` operations own Restore transitions and publish the exact full source-bound operation in `state[.<profile>].json.workspaceRestore` with binding/owner relocation in one ownership-fenced rename, preserving session, slot, naming preferences and journal evidence. There is one stored commit proof, not two stores exchanging receipts. The same owner enforces strict private regular-file/link/size inspection, scope checks inside publication, capacity and transactional revision CAS. Snapshot `read/relocate/update` mechanics are private; there is no separate Restore module or store factory. POSIX files are `0600`; Windows uses directory ACLs. Restore metadata remains bounded to 26 operations and 1 MiB, within an 8 MiB canonical snapshot. Movement clears stale display/probe evidence without claiming deletion. Conflicting source, binding, slot or targets fail closed. Every supporting snapshot publisher compares the full Restore state and its monotonic revision immediately before rename. It also preserves each retained binding's session identity, slot and relocated target, reserves both targets against other bindings, and rejects owner projections on the old target or conflicting slot. Pending creation and reservation staging reject a retained Restore's binding key, slot or either known target before mutating memory; a creation attempt lacking binding identity also conflicts on the retained owner profile or instance, rather than falling through to another slot. Primitive provisioning therefore cannot publish a conflicting creation intent or call `createForumTopic`, while valid existing-target reuse remains available. Candidate and final-disk validation also reject conflicting pending provisions/reservations, including late evidence, without discarding either intent. Restore publication and transitions inspect the private bounded `.provision-recovery.json` receipt file, matching pending ID, creator instance/profile and leader epoch before considering a recovered target. Both predecessor and candidate references remain protected at final publication. Snapshot publication, Restore transitions and recovery receipt writes serialize through the canonical snapshot transaction before the transport-owner publication fence. Conflicting targets or unreadable recovery evidence block advancement without erasing either source; Restore inspection remains available. Recovery writers never replace a differing receipt or repair damaged JSON, and exact duplicates perform no rewrite. Protected snapshot loading also uses strict recovery-file reads. Before publishing a new Restore, final transactional validation requires a known target for every creation retained in the predecessor snapshot, including entries that an in-memory expiry filter would omit. Canonical targets or exact creator/profile/epoch recovery receipts may establish a non-conflicting target; missing or foreign receipts cannot establish availability. Contradictory canonical/recovered targets fail closed. Loading reads recovery evidence once and, while Restore is retained, validates that exact evidence against the predecessor provisions before replacing any working projection. Conflicting, contradictory or invalid matching receipts reject warm and cold loading without changing disk or the previous projection; retained intent inspection remains available independently. Valid receipts merge before expiry filtering, so a late known creation cannot disappear solely because its original timer elapsed. A failed callback reload remains under the existing worker retry/diagnostic policy without another recipient apply, forwarding or cleanup grant; loading is not effect-time authority. Candidate validation refuses conflicting writes; final disk validation prevents a valid warm projection from silently repairing regressed canonical state. Restore transitions likewise refuse advancement or retirement over inconsistent canonical bindings, while retained intent inspection remains available for source protection. Metadata changes, binding-preserving owner succession and non-destructive owner detachment remain permitted; runtime still authenticates successor session authority. The revision survives final removal, closing empty-record ABA; a read-only Restore observation cannot bless an older binding projection. Warm missing/backward/contradictory evidence, corruption, unsupported schema and revision exhaustion refuse mutation. Old draft receipts or a separate Restore file block rather than migrate or manufacture missing originals. Callers hold Workspace admission and exact source/session/target authority. The initial phase is `relocated`, with no separate `prepared` record or receipt handoff. Subsequent `recipient-issued`, `ready`, source-dispatch and cleanup grants remain distinct; executor adoption never resets issuance. Only authenticated readiness observations may confirm the original recipient or retain a same-session `readyRecipient` successor. Terminal source settlement needs positive journal-owner disposition ACKs, never readiness, queue admission or absence. Canonical `queued` facts remain admission-only; `queue-completed` requires matching queued acceptance/receipt/kind and may upgrade only its proven IDs, leaving siblings nonterminal. Cleanup and retirement reject admission-only sources, including legacy facts; cold terminal receipt facts without acceptance or admission with cleanup fail closed without repair. The prepared `recordSourceAcceptance` stores a separate source-hashed positive execution/recipient result under an issued routing grant; it never counts as settlement or authorizes cleanup/source removal. Exact duplicates are read-only, malformed/contradictory cold evidence is retained without repair, and executor adoption preserves the proof. Follower forwarding composes this pre-report publication from the worker's fresh exact deferred-source hash under its existing dispatch admission; a lost publication reply reconciles only the identical retained proof. Its completion report carries that same hash into journal-owned `removeCompletedExact`; missing/changed sources reject atomically, with no ID-only fallback. Follower Restore now derives its scope hash from the immutable request/operator/retained acceptance, excludes mutable executor/progress, and carries it through admission into atomic source removal plus a scoped journal ACK. The worker requires matching returned and strictly retained evidence with fresh post-publication/inspection authority checks before notification. Production binding composition supplies serialized strict completion ports while preserving ordinary recovery. Follower cold ACK hints now consume exact scoped evidence under fresh admission and authenticated read-only recipient inspection, re-reading after awaits; missing/foreign evidence cannot adopt or settle. Leader command Restore now publishes `completed` acceptance before disposal through a private execution-fenced routed carrier; deferred/queued reports bypass that publisher. Memoized detached evidence handles duplicates without changing the original binding. An optional prepared worker queue-publication barrier now holds readiness through async acceptance and exact receipt/owner reinspection, including grouped and same-process cold reconstruction; serialized production bindings now supply strict full-group v1 queue inspection with exact owner/unoffered source and owner hashes, without recovery or writer admission. Production queued Restore publication now waits for fresh Workspace admission, canonical/live leader identity, exact receipt/source/owner evidence and retained `queued` acceptance, then rechecks receipt and recipient after publication/admission without replay. Same-process worker reconstruction resumes only proof publication, not semantic execution. Native two-source media-group integration now holds whole-receipt readiness through partial proof, changed digest and offered ownership, and resumes only proof on same-process worker reconstruction. A private Restore command carrier now suppresses trailing implicit completion after queued reporting and rejects explicit disposal guards, preserving receipt ownership even if queue commit fails. Native `/continue` keeps one queued continuation through publication faults/reconstruction; `/compact` keeps its confirmation-dialog/completed-source semantics. Direct prompt Restore uses queued admission, not another unqueued completion producer. Cold completed-command ACK continuation now uses fresh admission and exact scope inspection before adoption, read-only canonical current-leader ownership, post-await proof rereads and live/canonical cleanup fences without apply, handler, RPC or disposal replay. Missing/partial/foreign evidence and changed authority preserve protection; actual successor ownership/startup and accepted-work clearance remain fixture preconditions. The strict journal now prepares separate `completeQueuedExact` whole-receipt owner/hash-CAS removal plus atomic scoped ACKs, with complete-group cold continuity and no ordinary/v3 downgrade. It is supplied by the serialized private binding sibling. The worker's explicit scope API still requires full-batch immutable scopes. Cached prepared subsets now require a captured strict full queued-receipt origin inspector: exact complete group/full owner and matching queued-entry hashes precede readiness. Every scoped receipt needs an origin witness. Queue membership is immutable for that owner/acquisition; native scoped ACK publication and cold continuity require complete unoffered group disposal, so matching retained queued-origin witnesses acknowledge that whole receipt after lost replies. Unscoped siblings acquire no marker. The worker consumes those scopes through captured exact disposal/readback capabilities, clearing memory only after returned and retained ACK checks under current binding/context/process/session authority. Required scopes stay sticky; failed or uncertain issuance cannot downgrade to ordinary completion, replay disposal or lend its attempt across worker stop/start. Read-only reconciliation requires every requested exact scope and a proven origin witness for each whole receipt; it never infers ordinary sibling completion from absence. Cold queued ACK hints now share exact leader canonical ownership, pre-adoption scope reads and post-await rereads, publishing terminal receipt facts grouped by receipt/kind without replay. Native cases seed the post-disposal boundary and still supply startup/ownership and work clearance. Production queued acceptance now returns immutable full-receipt scopes through the publication barrier. The worker detaches and retains them before readiness, refuses missing terminal capabilities and uses cached scopes when lifecycle callers complete owned receipts. Its captured post-ACK observer emits a routing hint without requesting Pi dispatch; canonical queue-completed publication still rereads exact proof under fresh admission. Completion-only mux selection permits read-only reconciliation of an issued attempt despite lost execution readiness, never another dispatch or disposal. Subset-scoped sources within one receipt now need strict confirmed whole-receipt queued origin before readiness. Any issued disposition, including pre-write uncertainty, closes execution readiness while permitting completion-only proof reconciliation. Mixed batches of independent whole receipts now settle the scoped group before a separate ordinary group, rechecking owner/context/process/session/binding between them. A component failure cannot roll back another positive ACK. Mux/runtime completion retries reuse exact acknowledged receipt objects for local cleanup only, never readiness or another disposal. Ordinary sources acquire no scoped ACK; their unknown disposition retains ordinary protection. Post-ACK authority loss suppresses a stale scoped worker wake. Native producer/lifecycle fixtures cover grouped, discard, lost ACK/readback and canonical publication interruption; Pi handoff remains supplied. Terminal proof lifetime follows [settlement ordering](./multi-instance-bus.md#restore-settlement-ordering); actual startup was accepted in the operator's 0.52.0 live smoke. Cleanup can be issued only after all originals settle; unknown issuance cannot become not-issued. Exact old-target completion or positively unissued cleanup permits terminal retirement without touching accepted recipient queues or authorizing operation-ID reuse. Lost commit replies reconcile only the exact full operation. These operations perform no transport, source dispatch or deletion. Production resolves this native view for authenticated follower reception, exact unfinished-source startup holds even after the target becomes bound, and pressure-retirement protection. Restore capability is advertised; every participating peer must run 0.52.0 or later. The same scoped Restore snapshot also stores at most 26 source-bound temporary-Thread entries for All commands. Each entry records the exact journal binding and update ID, operator, executor, a unique 128-bit title token, `creating` or `created` phase and the acknowledged operator-chat target. It holds no Workspace binding or slot. `reserveTemporaryThread` publishes `creating` before the caller's single creation request. An existing source entry is returned instead of licensing another creation, and only explicit retirement frees the source. `acknowledgeTemporaryThread` records the target once; `adoptTemporaryThread` and `retireTemporaryThread` are executor-fenced exact CAS transitions that release protection only. Created targets are refused to provisions, reservations, Workspace bindings and owner records, both when staged and at final publication. The only exception is a retained Restore of the same source, which may rebind an existing Workspace and slot to the tab. Transition publication checks this protection against the resulting file, not only its predecessor. Strict parsing rejects malformed tokens, duplicate sources, tokens or targets, empty lists and foreign-chat targets. Followers cannot publish. Routing's `sendAllTabTemporaryThreadChooser` uses this store for a known threadless owner command whenever this process owns a leader epoch (no flag or configuration; each effect rechecks epoch, journal binding, operator and context). Under profile admission it adopts or reuses the source's entry, or reserves one and issues a single `createForumTopic` named as described above. A positive thread ID is acknowledged; any error or missing ID leaves `creating` as an unknown outcome. The command original is reported deferred, never completed, and stays in the All journal. A created entry publishes the full reroute/restore chooser inside the tab, whose target becomes the pending chooser's `sourceTarget`. An unknown entry is held with an All notice and never retried. A failed publication leaves the source retryable, and a replay or restart reuses the same tab. The All-command age limit still terminally settles a never-presented replay but never expires a presented tab. Forward from the tab uses the existing command dispatch and unbound-Thread cleanup: the command runs once in the selected Pi, routing reports the deferred All original complete, and the tab is removed through `thread-reconciler`. A worker completion observer then retires the entry under fresh profile admission and current temporary-Thread authority, adopting a predecessor executor first; absence of the entry or lost authority leaves it retained. When the fresh source still supports deferred abandonment, the tab's chooser also offers one **Cancel routing** action and states that it keeps the original privately, without sending it to Pi, and removes this tab. That click first commits the existing private retention and discard tombstone. It then makes one `thread-reconciler` removal attempt for the entry's own acknowledged target and retires the entry only after confirmed removal. A skipped or failed removal edits the chooser to say the tab could not be removed; the entry keeps protecting the tab, and nothing repeats the deletion automatically. A duplicate click abandons nothing twice. After restart a still-waiting source is revived with its Cancel; a selected or bound one belongs to the worker's first snapshot and is not offered Cancel. A retained tab is protected against other cleanup. The shared `createTelegramCleanupTargetProtection` used by bus, Sync and Thread lifecycle now calls the store's `listTemporaryThreadTargets()`, a fresh strict read of acknowledged targets that protects on any read failure. Routing's `isRerouteTargetProtected` exempts only the exact own entry (token, source and target) passed by that tab's Forward, Cancel or pending unbound cleanup. For example, a prompt typed inside the tab can be routed, but its Forward cannot remove the tab. After the entry retires, a still-pending Forward cleanup is ordinary unbound cleanup. Restore from the tab passes the same own-entry exemption to its source-ownership check and then uses the shared Restore producer with the tab as destination. `threads` accepts that relocation only for the Restore of the same source. The command is dispatched once to the restored recipient and reported complete, and the completion observer retires the entry. The Workspace keeps its slot on the tab, and the tab is not removed. A native leader fixture proves this path with Restore authority enabled. Without a leader epoch or the stores, the legacy All chooser remains the fallback. The lifecycle sections below own Restore from the tab, cancellation cleanup and cleanup protection; unknown creation or removal outcomes are never released automatically. Its optional external-slot source makes every generic allocation, Workspace claim, and occupancy snapshot reserve retained admission-fence slots; malformed, unreadable, or non-uppercase evidence fails allocation closed. Its synchronous provision-commit helper transfers exact targeted creation-title evidence into the claim-committed Workspace binding and consumes matching pending evidence; callers retain admission, epoch checks, and durable publication. It should not turn dormant bindings into routing authority, own destructive cleanup policy, or grow into the general Telegram synchronization domain.
82
96
  - `updates` / `routing`: update classification, authorization, callbacks, edits, reactions, forwarding, and inbound composition. `updates` owns production journal workers, leader/follower admission lifecycle construction, binding and settlement selection, queue-handoff projection across recipient journals/admission/IPC/live queue state, process/session queue-owner projection, post-public source binding, exact-signal late settlement, durable receipt readiness, same-process claim reconstruction, and structural worker state. `routing` converts message, callback, guest, section, reroute, and control admissions into exact receipts; its complete unbound-target and reroute restore/reclaim handlers run under the shared profile-wide Workspace operation boundary before store access. Its composed producer captures original journal references and canonical binding authority, then uses `advanceTelegramWorkspaceRestore` for native transitions and authenticated recipient observations under admission. The leader adapter updates its actual local identity; the follower adapter invokes the native one-attempt controller and publishes its live registry target only after exact readiness validation. Its final synchronous registry write runs through `threads.commitWorkspaceRestoreRegistration`: fresh disk/recovery validation and the caller's current-authority check remain inside the same canonical transaction through publication. The preparation assertion shares that validator but cannot substitute for the commit boundary. A late recovery conflict or disk-only binding regression retains the original and issued recipient grant without publishing new routing authority, forwarding input, deleting a Thread or undoing an already applied recipient target. Readiness and dispatch recheck the canonical relocated target as well as session, generation and the recipient's local target; local readiness cannot substitute for a regressed binding/owner projection. Only fresh issuance selects `apply`; retained or unknown issuance selects read-only `inspect`. Exact operation/session/generation/target/slot proofs and post-await/final-observation checks remain mandatory. Same-session successor readiness never changes the original issuance recipient; foreign sessions, ambiguous owners and regressed local targets stay protected. Lost readiness replies reconcile exact retained proof. The shared control path preserves original selection across uncertainty and limits recipient/dispatch callbacks to one admitted invocation; there is no replaceable producer or exported cleanup callback. Reroute forwarding resolves full live recipient binding/generation authority for the selected target and rechecks it after delivery; only a positive matching delivery ACK reports original-source completion through the admission carrier. Restore first publishes that acceptance from a fresh exact worker-source observation and the current recipient binding/generation; failure retains the original without resending. The report carries a detached source digest through admission; the worker checks current binding/context/process/session identity and requires `journal.removeCompletedExact` to match it transactionally before removal. Unsupported exact-disposal ports fail closed; duplicate ordinary reports cannot downgrade the guard. For scoped Restore reports, only an exact returned ACK plus strict retained readback emits the existing post-removal observer; missing inspection capability blocks disposal, and foreign/missing evidence or post-commit authority changes suppress notification. Exact capabilities are snapshotted at construction, and passed marker/inspection arguments are detached. A report or absent source still is not settlement proof, and lost-ACK continuation requires the strict active-journal scope-reader port. Original journal message targets survive rerouting and are not proof of accepted execution destinations; target-only inspection cannot replace conservative binding-wide accepted-work protection. The existing `workspace-retirement` capture now offers the prepared `requireBindingProvenance` option: relevant binding-associated entries remain protected regardless of original target, while nonempty shared/discovered sources without binding provenance return unknown instead of target-based clearance. Complete empty evidence can clear; incomplete or unreadable evidence cannot. Native queued-receipt and corrupted-family fixtures use strict read-only inspection with real reference leases and prove that capture changes no source files or receipts. The default retirement policy is unchanged. Restore cleanup now invokes this strict capture through the composition root before issuing cleanup and at the existing close/delete protection boundaries. A read-only canonical transaction supplies fresh binding references, unioned with retained predecessor references; cache-only metadata cannot clear work added while close awaited. Missing capture, unavailable snapshots, unknown journals and observation errors (including errors after a clear callback result) remain protective. Both roles have native worker fixtures for queued work whose original target differs, damaged journals and references published during close; accepted recipient work remains intact and skipped deletion never retires the intent or replays an issued grant. Other dispatch/cleanup fixtures explicitly supply a clear-evidence precondition and do not prove journal clearance. No own-source exemption exists: own accepted originals and unclassified shared controls may hold cleanup. A confirmed completion in the same source journal now also wakes a ready operation whose originals already have positive settlements and whose cleanup remains unissued. The wake reacquires current profile admission and authority, re-reads the retained operation and strict protection, and never adds the unrelated completion to its settlements. An unrelated queued receipt, foreign journal, ended authority or missing original settlement cannot supply this wake; unknown protection still holds, and an issued cleanup is never retried. Native worker callback-completion fixtures cover both roles with a separately supplied clearance precondition. The optional `onWorkspaceRestoreRecipientObserved` runtime hook in `bus-leader` uses existing authenticated heartbeat traffic, not a new RPC or completion ACK. Both peers must advertise Restore; missing auth/epoch/operator/profile-reader evidence suppresses observation. Delivery and the callback's currentness fence recheck leader epoch, operator, profile, runtime generation and exact live registration; heartbeat/connection timestamps and names are incidental. Runtime stop invalidates the fence before teardown, and listener settlement ends it. Identical in-flight observations coalesce, while old finalization cannot erase a successor observation. Listeners receive isolated snapshots and must return asynchronous work to retain their fence; the heartbeat ACK does not await listener work, and listener or diagnostic-sink failure cannot turn it into a failed ACK. Native IPC fixtures cover these boundaries, including default-profile identity and stop/restart. The composition root now returns the routing controller's continuation promise to preserve that fence through fresh admission and cleanup. Source evidence and recipient hints use distinct typed inputs: a hint cannot manufacture a source settlement. The recipient-hint path independently matches the live registration, retained ready-recipient instance/session/generation, normalized CWD, slot and target; it selects only ready operations in the current source journal whose original IDs already have positive settlements and whose cleanup is unissued. It rechecks this evidence after acquiring admission and carries both local authority and notification currentness through awaited effects. Eight native worker/IPC cases use strict real-journal inspection rather than supplied clearance: a recipient marker worker positively consumes accepted input without emitting a source-leader completion callback, then heartbeat-driven cleanup resumes once. Independent accepted work remains protective until separately consumed; damaged journals, missing original ACKs and uninspected successor generations cannot clear cleanup. A registration change after close retains the issued grant; an uncertain deletion reply cannot be replayed even by a current matching recipient. These fixtures prove native marker consumption, not live Pi scenario acceptance. Cold-snapshot successor inspection also crosses authenticated native IPC: after a new leader adopts the retained operation, a same-session follower successor answers `inspect` under fresh admission and the read-only canonical transaction without applying a local target, even while the original grant is still `recipient-issued`. Confirmation records only `readyRecipient`; the original recipient, request, source settlements and issued cleanup remain unchanged and cannot be reissued or retired. Foreign sessions, ended epochs and unadopted executors observe nothing. These fixtures supply successor registration publication as a precondition and do not prove startup composition. `advanceTelegramWorkspaceRestore` now adopts a retained operation whose full request and operator exactly match but whose executor differs, provided the caller's authority is current; a lost adoption reply reconciles from the retained operation. Adoption changes only executor authority: a `relocated` operation may still receive its first issuance, while `recipient-issued` and `ready` operations proceed only through inspection, and retained routing/cleanup evidence is never reset, settled or retired. The predecessor executor's later transitions are fenced by the executor CAS. Mismatched requests, other operators and ended authority neither adopt nor rewrite canonical bytes. A chooser re-click reaches this path; a new leader can also adopt a ready forwarded or completed-command Restore through exact scoped-ACK continuation. A new leader does not reconstruct source-bound controls. Restore has one controller: the legacy leader new-slot allocation and follower replacement branches are removed. Without that controller or current Restore authority (an unnegotiated peer or lost leadership), a fresh Restore click is refused before selection or any Restore transition, so the chooser keeps its ordinary routes and Cancel. After restart, root composition holds retained Restore originals as historical inputs. The Historical inputs menu entry and its confirmation submenu are removed; old callbacks are refused without routing or abandonment. Existing exact retained abandonment may still retire an unsent Restore through the cold continuation below. `threads.workspaceRestore.retireAbandoned` requires the exact operation, executor and operator, `ready` phase, absent routing and the complete sorted original set. It releases protection without cleanup: the relocated binding, owner and slot stay on the restored Thread, and the previous Thread is kept. Nothing is delivered, deleted or reissued. An interrupted retirement keeps protection and a later independently completed update may recheck its retained proof. The journal's read-only `inspectAbandonedPending(updateId)` returns proof only when exactly one committed `abandon-<sha256>` discard tombstone exists, the source is no longer pending and its private retention validates against the same binding, entry hash and disposition. Missing or altered retention throws, and inspection never repairs. Root composition exposes this strictly for the active leader journal under an `operator-disposition` reference. Any later completion in that journal selects ready, undispatched Restores and requires committed abandonment evidence for every original, then rechecks under fresh profile admission. Retirement then requires matching journal binding, update and owner authority (`telegram-owner:<operator>`); a predecessor executor is adopted first. Startup alone, journal absence, unverifiable evidence or another owner's authority keep protection. Recipient heartbeat hints also select a follower-owned `recipient-issued` operation when the live same-session registration already names the relocated target, normalized CWD and slot. Under fresh admission, `advanceTelegramWorkspaceRestore` adopts it and asks the follower controller only to `inspect`. Positive readiness records `readyRecipient` without changing the original recipient, and issues no dispatch or cleanup; a lost reply or unready target keeps the grant issued. An old target, foreign session, `relocated` phase, leader owner, other journal or stale hint never reaches the recipient. Once ready and still undispatched, the operation can end only after exact retained abandonment proof covers every original. A source-journal completion similarly selects a leader-owned `recipient-issued` operation issued to another leader instance, when this process has the same session and normalized CWD and its local leader identity already holds the relocated slot and target. After a fresh load and admission it adopts and inspects only. The read-only snapshot must show one current binding at the relocated target and one active owner record for this leader instance. Confirmation records a `readyRecipient` for this instance and session generation; it never calls `setCurrentLeaderIdentity`, dispatch or cleanup. Same-process lost replies stay with the original chooser's inspect path. A still-owned predecessor record, old local target, foreign session or CWD, follower owner, other journal or inactive context keep the grant issued. Both recovery paths call `advanceTelegramWorkspaceRestore` with `inspectOnly`. This also lets them take an operation still in `relocated`: the canonical binding already moved, so a same-session successor starts on the relocated target. In that case, and only when the owner was another instance, the first grant is issued to the observed successor and proven by `inspect`; `apply` never runs. `inspectOnly` never commits a relocation when no operation is retained. A successor still on the old target, or the same leader process that owns the chooser, is not selected. Issued, unready, partially abandoned or gated Restores stay protected. Without the strict abandonment reader, source absence never makes a Restore finishable. Exact evidence for any own-source exemption and interrupted startup integration remain activation gates; journal absence is never source completion evidence. The composed worker-owner observers pass committed queue receipts and completion IDs with the journal binding captured before completion commit. Routing snapshots the proof and generation, then re-enters the existing profile admission/gate without awaiting that continuation inside the dispatch gate. It rereads exact retained operations, records only matching unsettled source IDs, issues old-target cleanup once through its existing owner, and retires only terminal evidence. Routing protects both targets of every retained Restore, including against another Restore and ordinary unbound cleanup. Local queued and active work also protects its target. Cleanup exempts only its own old target under an exact retained issued grant, rechecking that evidence and protection at the reconciler's API boundaries. Known protection prevents grant issuance; protection appearing during cleanup retains the issued attempt without retry. A reconciler skip is not deletion confirmation and cannot retire the operation. Stale authority and unknown issued cleanup stay protected; a lost ACK cannot be reconstructed from absence. The continuation never captures an expired dispatch callback. For a ready forwarded Restore with unissued cleanup, completion/recipient hints now read exact immutable removal scopes under fresh admission through the active-journal `operator-disposition` reference. Positive ACKs authorize exact executor adoption and authenticated follower `inspect`, never apply, handler, forwarding or removal replay. Fresh session/CWD/slot/target and protocol checks gate inspection even when registration generation changes. Every unsettled proof is re-read after the await before canonical settlement; partial/missing evidence cannot release another source. The observed live-recipient fence remains active through cleanup. Missing/foreign receipts cannot re-key intent; interrupted settlement publication resumes on a later hint from unchanged journal evidence. Actual successor registration and accepted-work clearance remain fixture preconditions; terminal ACK lifetime and startup composition are still gated. Producer, controller, receiver and settlement are composed and gated by the negotiated `workspace-restore-v1` capability on both peers. Exact local message ownership keeps a published chooser callback local even after its Thread moves to a follower. Transport stays in `bus*`. Native full-capacity tests drive original and callback updates through the real worker and production producer for both roles.
83
97
  - `media` / `text-groups` / `time-injection` / `turns` / `inbound`: inbound extraction, rich reply plaintext, grouped debounce, split-text coalescing, optional time context, handlers, and prompt assembly/editing, including the `[guest]` Guest Mode speed note appended to guest turn text. Group replay replaces stale generation-local message/report bindings without duplicating content. Sticker format follows Bot API `Sticker.is_video` / `is_animated`: static WebP may enter image content, while video WebM and animated TGS remain file attachments with their native extension/MIME and are never read as image payloads. The Sticker object has no documented `mime_type`; frame extraction is not performed.
84
98
  - `queue`: queue contracts, transport stamps, lanes, readiness, mutations, dispatch, enqueueing, and lifecycle sequencing. Durable admission uses deterministic receipts, canonical source sets, replay dedupe, multiple folded-history receipts, append-before-dispatch reporting, exact handoff/control/discard settlement, and a readiness gate. Receipt-bearing inactive-profile work is preserved after current-profile work rather than dropped.
@@ -282,7 +296,7 @@ Keeping the current observation contract requires externally established exclusi
282
296
 
283
297
  The approved direction separates controlled recovery/migration from live source consumption. Existing full family and whole-profile inspectors retain their current evidence contracts. The locally implemented, independently reviewed and unwired `readTelegramUpdateJournalSource()` shares their family decoder/acquisition machinery and requires selected version `1 | 2`, exact profile/token constraints, and equality between expected and unchanged stored receipt scopes. Its caller must serialize relevant cooperating writers through consumption. Snapshot/segment evidence remains strict; ancestor observations establish canonical directory type and endpoint `dev`/`ino`/`mode`/`uid`/`gid`, plus a final anchor realpath check, not detection of every sibling-entry mutation. Concurrent manual relocation, backup restoration, permission/ACL changes or other storage manipulation outside the protocol is unsupported; transient ancestor-change detection is deliberately not promised. This is a declared narrower contract, not equivalent protection inferred from inode equality. No reader alone proves whole-profile readiness or permits activation.
284
298
 
285
- The legacy `createTelegramPollingStartRecoveryHandler` classifies standalone owners/state/transaction artifacts and supports one guarded deletion/retry attempt; it is not wired into the consolidated production command composition. Its owners-file checks do not establish shared-envelope or sibling-profile authority, so it must not receive the consolidated `state.json` as a recovery target. Current `/telegram-connect` instead uses the separate [damaged-state reset](#damaged-state-reset-operator-approved). Being first or becoming leader does not establish shared-root quiescence. Future journal recovery/preparation belongs in an explicit, authority-fenced startup stage, not incidental live reads; existing journal recovery inside ordinary `readCurrent()` remains unchanged until the new path is integrated. Preserve unknown accepted source evidence rather than treating runtime-artifact recovery as journal migration permission.
299
+ `/telegram-connect` has no artifact-classifying retry path: the former standalone owners/state/transaction recovery handler could not establish shared-envelope or sibling-profile authority and has been removed. Current `/telegram-connect` uses the separate [damaged-state reset](#damaged-state-reset-operator-approved). Being first or becoming leader does not establish shared-root quiescence. Future journal recovery/preparation belongs in an explicit, authority-fenced startup stage, not incidental live reads; existing journal recovery inside ordinary `readCurrent()` remains unchanged until the new path is integrated. Preserve unknown accepted source evidence rather than treating runtime-artifact recovery as journal migration permission.
286
300
 
287
301
  #### Bus/Journal Design Acceptance
288
302
 
@@ -370,7 +384,7 @@ This bounded structure design is applied locally: Workspace identity has a reusa
370
384
 
371
385
  **Layout.** The runtime root `<agentDir>/tmp/pi-telegram` (default `~/.pi/agent/tmp/pi-telegram`) has exactly two persistent root files: `state.json` and `logs.jsonl`. `sessions/<id>/` holds session-owned polling/recipient journals and custody; `attachments/` holds flat download scratch; `journals/` holds non-session service journals (`thread-cleanup` and `channel-posts`, named `<kind>.<full raw-profile SHA-256>.json`); `logs/` holds the rotated previous log; `runtime/` holds transaction guards, private staging, provisioning-recovery sidecars and IPC endpoints. Configuration stays outside the root.
372
386
 
373
- **Fresh start, no migration.** Released versions wrote `tmp/telegram`; 0.52.0 starts consolidated state without importing, merging, deleting or replaying the old root. A live older-release owner there is still consulted read-only to refuse a second poller; malformed/unreadable older-owner evidence refuses acquisition rather than becoming absence. The unreleased development standalone layout is not an upgrade source either. Operator-reported Linux live smoke after removing the development root passed (clean two-file census, new Thread, cursor without history, followers, temporary tabs). Native Windows/macOS behavior is covered by the release CI matrix. Windows lacks the no-follow nonblocking open evidence that strict journal reads require: ordinary queue receipts there use the ordinary journal read, while Restore proofs, cleanup census and other strict observations fail closed.
387
+ **Fresh start, no migration.** Released versions wrote `tmp/telegram`; 0.52.0 starts consolidated state without importing, merging, deleting or replaying the old root. A live older-release owner there is still consulted read-only to refuse a second poller; malformed/unreadable older-owner evidence refuses acquisition rather than becoming absence. The unreleased development standalone layout is not an upgrade source either. Operator-reported Linux live smoke after removing the development root passed (clean two-file census, new Thread, cursor without history, followers, temporary tabs). Native Windows/macOS behavior is covered by the release CI matrix. Strict journal reads run on every platform: where no-follow and non-blocking opens are unavailable (Windows), the lstat-before/fstat-after identity binding guards each open, so Restore proofs, cleanup census and scoped queue receipts behave the same and the CI matrix exercises them.
374
388
 
375
389
  **Envelope.** `state.json` is `{ version: 2, profiles: { [profileName]: { transport?, workspace?, admission?, runtime? } } }`. Profile names are logical keys, not filename suffixes or session identities. `transport` owns the exact leader/epoch/generation and polling-journal pointer; `workspace` owns canonical bindings/Restore/temporary facts; `admission` owns ordinary leases and destructive fences; `runtime` is a non-authoritative observation. Section owners keep their strict payload parsers and permissions; diagnostics never create routing/deletion authority.
376
390
 
@@ -414,19 +428,7 @@ The runtime sections and log have different authority and write pressure. Preser
414
428
 
415
429
  This baseline counts write-producing code paths rather than filesystem implementation details that vary between ext4, APFS, NTFS, and network-backed home directories. Optimization evidence should compare these deterministic triggers first, then use platform smoke evidence for rename, named-pipe, crash, and cleanup behavior. Recovery-critical fields inside `profiles.<profile>.workspace` are `bot`, `identities`, `workspaceBindings`, `reservations`, `pendingProvisions`, `syncObservations`, and `threads`; `profiles.<profile>.runtime` (runtime, live roster and diagnostics) is observational and may use bounded coalescing when authority checks remain unchanged.
416
430
 
417
- Run `node --experimental-strip-types scripts/measure-workspace.mjs` for an isolated, assertion-backed Thread-store work baseline at 1, 13, and 26 bindings. It creates and removes only its own temporary fixtures; it never loads configured profiles or calls Telegram. Counters cover asynchronous filesystem calls, bytes, and JSON parse/stringify calls, not object-spread clones, synchronous existence checks, transport-owner transactions, IPC, or elapsed-time performance. The script reports aggregate counts with each row's repetition count; the following counts are per operation and were identical across these fixture sizes:
418
-
419
- | Operation | Reads / parses | Stringifies | Writes / renames |
420
- | --- | --- | --- | --- |
421
- | Cold load | 1 / 1 | 0 | 0 / 0 |
422
- | Last-record lookup | 0 / 0 | 0 | 0 / 0 |
423
- | First persist after reload | 2 / 3 | 1 | 0 / 0 |
424
- | Steady unchanged persist | 2 / 3 | 1 | 0 / 0 |
425
- | Changed diagnostic persist | 2 / 3 | 2 | 1 / 1 |
426
-
427
- The first reloaded save and steady no-op saves both preserve the existing file. Structural comparison normalizes the candidate to wire JSON: one extra parse replaces the former disk reserialization, while object insertion order no longer causes an atomic rewrite. This trades comparison work for fewer unnecessary writes; it is not a latency/CPU improvement claim. At 26 bindings the seeded snapshot is 17,776 bytes, so an unchanged save still reads 35,552 bytes in this fixture. Fresh disk comparison and ownership/revision checks remain unchanged; no cache or index was introduced. Full IPC, authenticated registration, end-to-end routing, and allocation/clone costs require separate evidence.
428
-
429
- Run `node --experimental-strip-types scripts/measure-bus.mjs` for the complementary synchronous registry baseline. At 1/13/26 entries, re-registration visits each entry once; heartbeat performs one Map get and set without scanning; target lookup visits one entry for the first target and at most the fixture size for the last or a different-chat miss; roster listing visits every entry. Returned target/protocol views are mutation-isolated from registry authority. The script counts Map calls and visited entries, not allocations or time, and restores its process-local instrumentation before exit. Two repeated runs produced identical counts. This bounded result supplies no demonstrated need for a secondary target index, shared mutable views, or persistent IPC multiplexing. Escalate to full transport/provisioning measurement only when attributable latency, event-loop blocking, or unexpectedly growing work supplies a concrete performance claim to test.
431
+ Run `node --experimental-strip-types scripts/measure-bus.mjs` for an isolated, assertion-backed synchronous bus-registry work baseline. At 1/13/26 entries, re-registration visits each entry once; heartbeat performs one Map get and set without scanning; target lookup visits one entry for the first target and at most the fixture size for the last or a different-chat miss; roster listing visits every entry. Returned target/protocol views are mutation-isolated from registry authority. The script counts Map calls and visited entries, not allocations or time, and restores its process-local instrumentation before exit. Two repeated runs produced identical counts. This bounded result supplies no demonstrated need for a secondary target index, shared mutable views, or persistent IPC multiplexing. Escalate to full transport/provisioning measurement only when attributable latency, event-loop blocking, or unexpectedly growing work supplies a concrete performance claim to test.
430
432
 
431
433
  Version `0.24.0` intentionally does not read or migrate the former agent-level `locks.json`; upgrading resets Telegram ownership. Run `/telegram-connect` when a fresh owner is not elected automatically. Damaged shared-envelope handling is owned by [Consolidated Runtime Root](#consolidated-runtime-root) and its [damaged-state reset](#damaged-state-reset-operator-approved), not the legacy whole-file deletion/retry handler. Earlier releases left `recovery/` quarantine folders; startup now removes them from the current runtime root and session folders, and strict inspection ignores them.
432
434
 
@@ -452,11 +454,11 @@ The journal owns the `abandonPending` primitive for exact unclaimed v1 sources.
452
454
 
453
455
  Abandonment checks exact source binding and entry evidence, caller authority at publication boundaries, and existing discard/retention agreement on retry. It refuses queued, failed, retrying, foreign, changed or absent sources, does not repair corrupt evidence, and is not exposed by the v3 custody store. Retention/publication failure leaves original authority intact unless strict read-back proves the exact tombstone committed before a later compaction failure. The worker now exposes source-bound abandonment only for a captured v1 pending entry with its exact live deferred claim, session signal, journal binding and transport/context authority. `abandonTelegramDeferredUpdate` is the admission-carrier entrypoint; raw journal cancellation is not a substitute for worker coordination. The carrier suspends its execution fence during cancellation, including forwarded clones and late completion/queue reports. A failed or unknown acknowledgement leaves that source's claim suspended for exact cancellation retry while unrelated inputs can drain. Successful abandonment releases the claim without publishing task completion; its discard tombstone prevents restart replay. An unattempted request that fails eligibility leaves dispatch authority unchanged.
454
456
 
455
- Thread selection reserves the source before awaiting Workspace admission or destination lookup, and releases the reservation after routing settles. Cancellation cannot win against this in-flight reservation or an already reported queue/completion outcome, even before its late journal settlement runs. Conversely, old destination buttons refuse a suspended or abandoned source before routing effects. Eligible single-text prompt choosers now offer **⛔️ Cancel routing**, including the replace/restore submenu. Admission publishes this capability only for a captured v1 pending original, copied before handler projections can mutate execution input; capability publication is not cancellation authority. The click binds the current paired owner, source sender, profile/journal, session signal, leader epoch and exact chooser target/message under profile-wide Workspace admission. Ordinary prompt eligibility requires one supported private text projection with an exact whole-source capability; confirmed temporary tabs also permit command cancellation through their captured source. Unsupported journals, prior selection, partial forwarding, unknown issuance and cleanup-only states remain excluded. Ordinary source-only Cancel never deletes the original Telegram message or its Thread; temporary-tab cancellation has the separate conditional all-resolved cleanup contract below. After the discard acknowledgement, the chooser becomes an HTML cancellation notice with an empty keyboard; an edit failure retains the committed receipt so retry updates the UI without repeating abandonment. Uncertain storage results retain only cancellation retry, not destination/restore authority. Owner-facing recovery after restart uses the Status surface below; historical orphaned inputs remain held internally, without a historical-review menu.
457
+ Each pending chooser carries one routing phase: `waiting`, `selected`, `released` (a selection that routed nothing; All-command expiry re-arms), `forward-unknown`, `cleanup` (with its cleanup intent) or `finalizing` (with its pending confirmation). Only `waiting` with no command dispatch in flight counts as untouched, which is what Cancel, Restore sibling retention and cancellation review require. Thread selection reserves the source before awaiting Workspace admission or destination lookup, and releases the reservation after routing settles. Cancellation cannot win against this in-flight reservation or an already reported queue/completion outcome, even before its late journal settlement runs. Conversely, old destination buttons refuse a suspended or abandoned source before routing effects. Every unbound chooser whose sources can all be retained privately offers Cancel routing, whatever the content kind or group size. Admission publishes this capability only for a captured v1 pending original, copied before handler projections can mutate execution input; capability publication is not cancellation authority. The click binds the current paired owner, source sender, profile/journal, session signal, leader epoch and exact chooser target/message under profile-wide Workspace admission. Eligibility needs only an exact whole-source capability for every source of the chooser; content kind and group size do not matter. One tap retains each source once and keeps per-source receipts, so a retry finishes only the remainder; confirmed temporary tabs also permit command cancellation through their captured source. Unsupported journals, prior selection, partial forwarding, unknown issuance and cleanup-only states remain excluded. Ordinary source-only Cancel never deletes the original Telegram message or its Thread; temporary-tab cancellation has the separate conditional all-resolved cleanup contract below. After the discard acknowledgement, the chooser becomes an HTML cancellation notice with an empty keyboard; an edit failure retains the committed receipt so retry updates the UI without repeating abandonment. Uncertain storage results retain only cancellation retry, not destination/restore authority. Owner-facing recovery after restart uses the Status surface below; historical orphaned inputs remain held internally, without a historical-review menu.
456
458
 
457
459
  Before executing a pending v1 entry, the worker uses the journal's read-only `inspectPendingRetention` port to inspect only that entry's deterministic private retention path. An intact matching copy, or an unreadable/invalid candidate at that path, parks the source in an `abandoning` claim before routing. `abandoningClaimCount` exposes the protected subset of deferred claims. Other independently verifiable inputs continue draining; repeated wake-ups do not replay the parked source. Inspection validates bounded regular-file evidence and the full entry/binding/disposition match without repairing the archive, publishing a journal revision, or treating the requested disposition as committed. A fresh authorized caller may retry the exact journal abandonment through the worker; corrupt evidence stays protected and is never silently overwritten. The package-private `inspectTelegramAbandoningUpdates` carrier port prepares this handoff: it returns at most 20 update-id-ordered protected sources per page, detached original evidence, and exact-source retry closures. Observation reads only the worker's protected claims, not archive directories or journal files; it neither proves current eligibility/archive integrity nor authorizes dispatch. Page access and retries require the captured live worker generation, journal binding, transport/context and caller authority. Retry reuses the journal CAS, cannot be retargeted by editing display metadata, and caches an acknowledged receipt for presentation retries only while authority remains current. Ordinary deferred, queued and executing inputs are not candidates. Human-owner/source-kind filtering and the recovery control surface remain routing-owned.
458
460
 
459
- The leader's Status menu offers **❌ Pending cancellations** only while its active worker reports protected attempts. Routing projects up to five supported plain-text originals per review page, confined to the current paired owner/chat, journal binding, session and leader epoch. Commands, media groups, business inputs, forwarded envelopes and sources with a live selected/partially forwarded chooser are withheld. A chooser whose every originating carrier has a proven aborted signal is obsolete evidence, not a veto on a current source-only recovery capability; missing or live fences remain protective. Ordinary Cancel routing never gains this relaxation. The review holds one bounded current surface, with fresh random callback identities so even editing the same message after router recreation cannot revive an old indexed action. Refresh, navigation and generation/authority changes invalidate earlier controls. Each retry reacquires profile-wide Workspace admission, checks the exact current chooser and source, and commits through the worker capability. Acknowledged results retire matching old reroute controls and remove the recovery action without claiming task completion; failed edits retain the exact receipt for retry. Read-only review does not probe or recreate the original Thread. Corrupt evidence and unsupported sources stay protected and never fall through to agent dispatch.
461
+ The leader's Status menu offers a Pending cancellations review only while its active worker reports protected attempts. Routing projects up to five originals of any input kind per review page ([row copy](./ui-style.md#route-chooser)), confined to the current paired owner/chat, journal binding, session and leader epoch. Business inputs, forwarded envelopes and sources with a live selected/partially forwarded chooser are withheld. A chooser whose every originating carrier has a proven aborted signal is obsolete evidence, not a veto on a current source-only recovery capability; missing or live fences remain protective. Ordinary Cancel routing never gains this relaxation. The review holds one bounded current surface, with fresh random callback identities so even editing the same message after router recreation cannot revive an old indexed action. Refresh, navigation and generation/authority changes invalidate earlier controls. Each retry reacquires profile-wide Workspace admission, checks the exact current chooser and source, and commits through the worker capability. Acknowledged results retire matching old reroute controls and remove the recovery action without claiming task completion; failed edits retain the exact receipt for retry. Read-only review does not probe or recreate the original Thread. Corrupt evidence and unsupported sources stay protected and never fall through to agent dispatch.
460
462
 
461
463
  This restart barrier applies once the retention copy is atomically published and to workers that implement retention inspection. A failed attempt before any copy publication has no durable cancellation intent and must not be acknowledged as cancelled. Older 0.51.6 readers respect a committed discard tombstone, but do not recognize an interrupted pre-commit retention attempt; the latter is not a downgrade-safe completed cancellation. Status recovery handles these parked attempts; it is not a general historical-pending-input recovery API.
462
464
 
@@ -468,19 +470,19 @@ Production leader admission composes routing's narrow historical classifier; fol
468
470
 
469
471
  Acknowledged private-owner routing choosers, including commands and grouped prompts, own one fixed 60-minute lifetime from their first positive publication. `journal.routingInputs.arm` retains each exact v1 source's operator, `publishedAtMs`, `expiresAtMs` and `waiting` phase; refresh/restart never renews it. Destination validation precedes atomic `select` under Workspace admission. Selection still prevents another issuance, but does not extend the donor deadline: an unclaimed selected source with an unknown delivery outcome also expires. Queue admission carries the selected clock into the queued entry; queued/running recipient work is outside donor expiry. Unsupported carriers, unconfirmed clocks and historical originals without lifetime metadata acquire no invented deadline.
470
472
 
471
- The operator-approved optimistic chooser policy accepts nondelivery after the fixed deadline. Expiry reacquires profile-wide Workspace admission and exact owner/context/leader/source authority, then CAS-removes the unclaimed donor pending source and writes a body-free legacy-compatible discard tombstone. It creates no private prompt archive, execution completion or recipient cancellation. Exact tombstone readback reconciles lost ACKs; changed/queued/owner-bearing sources refuse. The originating carrier loses authority, old controls are retired, and late reports cannot revive the input or block unrelated work. A lost selection ACK may reconcile only the waiting-to-selected phase of an otherwise identical source, never grant another send. Clock-bearing historical sources survive cold spending until the same deadline; positively unbound temporary frames associated with them survive new-world forgetting. The worker retries only unconfirmed source disposition. A positive expiry ACK immediately drops its deferred source and claim, before observer/UI awaits. Failed cleanup metadata is retried once per minute by the existing one-timer-per-tab scheduler, reconstructing known groups from body-free journal evidence rather than retaining prompt bodies. Future metadata retries do not join settlement waits; only running attempts do. Same-instance session replacement may reprepare unissued expiry frames under fresh authority without resurrecting a source. Missing/unknown grant state or an issued destructive cleanup forbids retry.
473
+ The operator-approved optimistic chooser policy accepts nondelivery after the fixed deadline. Expiry reacquires profile-wide Workspace admission and exact owner/context/leader/source authority, then CAS-removes the unclaimed donor pending source and writes a body-free legacy-compatible discard tombstone. It creates no private prompt archive, execution completion or recipient cancellation. Exact tombstone readback reconciles lost ACKs; changed/queued/owner-bearing sources refuse. The originating carrier loses authority, old controls are retired, and late reports cannot revive the input or block unrelated work. A lost selection ACK may reconcile only the waiting-to-selected phase of an otherwise identical source, never grant another send. Clock-bearing historical sources survive cold spending until the same deadline; positively unbound temporary frames associated with them survive new-world forgetting. The saved clock also records where its chooser was published. At startup the routing classifier returns `revive` only for a still-`waiting`, unexpired clock with a recorded chooser, from the current owner, whose tab is unbound while live threads exist; the worker re-checks that proof, drops the source from its startup set and handles it as this generation's live input, and routing edits the recorded chooser in place (or posts a fresh one if that message is gone) without renewing the deadline. Every other clock-bearing source keeps the protective hold. The worker retries only unconfirmed source disposition. A positive expiry ACK immediately drops its deferred source and claim, before observer/UI awaits. Failed cleanup metadata is retried once per minute by the existing one-timer-per-tab scheduler, reconstructing known groups from body-free journal evidence rather than retaining prompt bodies. Future metadata retries do not join settlement waits; only running attempts do. Same-instance session replacement may reprepare unissued expiry frames under fresh authority without resurrecting a source. Missing/unknown grant state or an issued destructive cleanup forbids retry.
472
474
 
473
475
  With live bindings or a retained temporary entry, a known command or a fresh private plain-text prompt from All first enters the shared source-bound temporary-Thread path under current owner/profile/journal/context/leader authority and profile-wide Workspace admission. Threads atomically reserves a source/token intent before one `createForumTopic` attempt and records only its exact acknowledged target. The tab owns no Pi binding or A–Z slot; its presentation target is separate from the original All source. A creation error, missing target or lost publication result leaves unknown custody held, never a second creation attempt. A `created` entry can republish its chooser while its source is still pending after restart; a `creating` entry supplies no creation or dispatch grant. The acknowledged tab offers the shared Forward/Restore chooser and Cancel only when the current source has fresh private-abandonment capability. Publication defers rather than completes the original command; selection retains command semantics, and no current Pi is chosen automatically. Commands already completed by the compatibility path are not reconstructed. Unpresented expired commands keep the existing command-expiry fence; a confirmed retained tab is not evidence of expiry. Fresh threadless plain-text prompts use `New chat` with the same source-bound routing menu; fallback guidance remains when exact temporary-creation authority is unavailable. Recognized commands include built-in handlers (not only bot-menu entries), registered Telegram extension commands regardless of menu visibility, and discovered prompt-template commands. Bound-Thread and classic routing are unchanged. Local candidate composition is default with the required stores and owned epoch; there is no temporary-tab feature flag. Actual Pi/Telegram behavior was accepted in the operator's 0.52.0 live smoke; no owner-visible uncertainty recovery is scheduled.
474
476
 
475
477
  #### Temporary Thread Multi-Input Lifecycle (Approved Design)
476
478
 
477
- Temporary command tabs use the command itself as their title (for example `/start` or `/status`), without a visible internal token; fresh plain-text prompt tabs use `New chat`. Both use the same mode chooser and differ only in their title and introductory copy. A command delivered with a Telegram-provided unbound private target uses the same chooser and fresh exact-source Cancel capability; its first chooser renames that target to the command without creating another tab. A received target or successful rename alone never manufactures temporary authority. A fresh owner-authenticated private `forum_topic_created` with literal `is_name_implicit: true` supplies native creation evidence: routing retains a bounded process-local observation tied to the exact context, session generation, admission scope, operator, journal binding and executor. A later live single-source input in that exact target registers it through Threads `registerImplicitTemporaryThread` under profile admission, without calling or fabricating `createForumTopic`; the publication CAS refuses any binding, owner record, reservation, provisioning, cleanup or Restore conflict. Normal grouped membership, one-shot Forward, source disposition, last-Cancel quiet period and cleanup issuance then apply identically. Historical creation signals, context/epoch changes, manual names, string flags, foreign creators and missing observations grant nothing. The observation is consumed on registration, never reconstructed from a title or restart. Existing bindings/reservations and acknowledged temporary targets retain their protections. Their root chooser offers `Reroute…`, `Restore…`, and eligible `Cancel routing`; each mode opens its own live-target submenu without dispatching the held input. Submenus place `⬆️ Back` first to return to the mode chooser with its exact original description, retained on that pending chooser; navigation never substitutes or recomputes the root copy. Cancel appears only at the root. After cancellation, the 1-second quiet-period cleanup remains proof-gated. Private-chat temporary tabs skip the unsupported `closeForumTopic` call and issue only one `deleteForumTopic` attempt; literal positive deletion acknowledgement is still required, and uncertainty never authorizes a retry.
479
+ Every temporary routing tab carries one fixed routing name ([copy](./ui-style.md#route-chooser)), never its first input, because later prompts may join it: the bot creates its own tabs with that name and renames a native tab once, best-effort, when it adopts it. Commands and prompts share the same mode chooser. A command delivered with a Telegram-provided unbound private target uses the same chooser and fresh exact-source Cancel capability in that tab, without renaming it or creating another one. A received target or successful rename alone never manufactures temporary authority. A fresh owner-authenticated private `forum_topic_created` with literal `is_name_implicit: true` supplies native creation evidence: routing retains a bounded process-local observation tied to the exact context, session generation, admission scope, operator, journal binding and executor. The next live input group in that exact target, of any content kind and either one message or an album, registers it through Threads `registerImplicitTemporaryThread` under profile admission, with that group as the entry's first input (its smallest update ID is the source), without calling or fabricating `createForumTopic` (adoption renames it once, best-effort); the publication CAS refuses any binding, owner record, reservation, provisioning, cleanup or Restore conflict. Normal grouped membership, one-shot Forward, source disposition, last-Cancel quiet period and cleanup issuance then apply identically. Historical creation signals, context/epoch changes, manual names, string flags, foreign creators and missing observations grant nothing. The observation is consumed on registration, never reconstructed from a title or restart. Existing bindings/reservations and acknowledged temporary targets retain their protections. Their root chooser offers Reroute, Restore and eligible Cancel; each mode opens its own submenu of live thread targets without dispatching the held input. A submenu Back returns to the mode chooser with its exact original description, retained on that pending chooser; navigation never substitutes or recomputes the root copy. Copy, emoji and button layout live in [UI Style](./ui-style.md#route-chooser). Cancel appears only at the root. After cancellation, the immediate cleanup remains proof-gated. Private-chat temporary tabs skip the unsupported `closeForumTopic` call and issue only one `deleteForumTopic` attempt; literal positive deletion acknowledgement is still required, and uncertainty never authorizes a retry. A menu-picked command arrives threadless, so its original stays in All while the bot-created tab carries the chooser; once that input is consumed (Forward finalization, Restore dispatch, explicit or Restore-sibling Cancel, or chooser expiry, including after restart), the bot makes one best-effort `deleteMessage` of the All copy. Failure is recorded and never retried. Pending-cancellation recovery deletes nothing, and typed All inputs already live in their own tab and leave with it.
478
480
 
479
- This multi-input lifecycle is implemented in the local candidate, not authority for live deletion. It supersedes unconditional per-chooser tab removal. The reject-only guard prevents cleanup/retirement while another known same-tab chooser remains, including unresolved cleanup-only work. `temporaryThreads.inputs` now records bounded append-only journal source groups through the unbound producer before chooser publication; duplicates are read-only, partial/foreign/overlapping groups refuse, and faults retain the source without a new chooser. Cold reads preserve this protection without process-local chooser memory. A group has no readiness or disposition flag, and an absent legacy field does not prove complete coverage. `cancelledInputs` records exact whole known donor groups after either same-journal/operator retained-cancellation evidence or the separate body-free expiry tombstone. Expiry recording may clear a group's unknown Forward issuance or its expired Restore intent, but never mutates a canonical binding, recipient queue or immutable scoped settlement proof. If Restore already bound the tab, expiry releases the temporary frame without deletion. Otherwise fully resolved groups enter the existing one-second quiet-period cleanup. A partially acknowledged known cohort may finish donor disposition when every member is absent from that exact source journal and at least one member has same-operator expiry proof; this is not recipient completion or non-delivery proof. Fresh strict namespace/protection evidence still gates deletion; independent work and bound Threads remain protected. Store publication and returned/retained acknowledgement recheck that proof and operator/executor authority; a lost reply reconciles the exact fact read-only, while missing/foreign/corrupt proof stays protective. The producer composes this into explicit Cancel before temporary cleanup or chooser retirement. Cancelled groups cannot Restore; independent sources remain untouched. More than one known group still blocks cleanup and raw retirement, including all-cancelled membership: these facts grant no deletion. Each successful Cancel retires only its own chooser. If durable membership is fully resolved by exact cancellation/completion facts and no chooser remains, a process-local quiet period starts (1 s; new input in the tab cancels it). Its single attempt, under profile admission, rechecks authority, whole-group cancellation/expiry evidence, exact entry CAS, an empty strict journal census (any retained update naming the Thread, any state), absence of choosers and the normal reconciler protections. `issueTemporaryThreadCleanup` publishes canonical `cleanupIssued: true` only for an exact fully resolved entry with strict unbound canonical evidence checked inside the publication transaction; the normal target/source guards precede issuance and run again at API boundaries. The reconciler requires that exact retained issued frame and limits its plan to this tab; unrelated expired-provision cleanup never borrows the grant. Close/delete calls disable retries and transport fallback and require a positive acknowledgement. Confirmed current deletion alone permits entry retirement; skip, negative/lost reply, authority loss or post-rename publication interruption retains the marker. Cold reads classify already-issued entries as unknown, new membership refuses, and executor adoption never renews the grant. Missing evidence only refuses; an unpublished grant issues no API call and may still receive its first grant. The quiet period remains process-local, but issued uncertainty survives restart. The census cannot see updates in transit before journal append. Restore from a multi-input tab is allowed only when each other known group is durably cancelled, Forward-completed or a live unselected chooser that supports private abandonment. A previously completed Forward never supplies a new selection or cancellation grant. After positive settlement of every selected source, such siblings are abandoned with cancellation facts and their controls edited to cancelled, then `retireTemporaryThread(expected, authority, completed)` releases the entry (one newly completed selected group, all others durably cancelled or previously Forward-completed). Missing authority/proof or an unproven Restore leaves siblings pending and protected. On startup, a retained journal input recorded in a created temporary tab whose target a Workspace binding now owns is held as historical, never rerouted; an exact saved chooser clock may expire its unclaimed donor attempt without affecting the binding. Live pending sources and due retry-wait sources (including startup retries) use the same fresh membership/binding predicate through `shouldHoldPendingInput` before execution, with source/context/binding/transport checks after classification awaits. The hold grants neither cancellation nor delivery and does not block unrelated inputs. Recipient custody never uses this direct-source classifier. A native production witness admits a recorded command after the worker has already processed an unrelated command, proving it cannot fall through to ordinary bound dispatch. A production retry witness keeps recorded failure metadata intact without command execution, cancellation or deletion. Claimed retries cannot schedule repeated due-time wakes; independent due and future retries remain executable. Real-IPC Forward/Restore sibling witnesses now include recipient journal drain through the real worker and follower router: only the selected message executes, source disposal is observed, and repeated controls do not replay the command. Existing message-ownership composition keeps a locally published chooser's callbacks at its leader publisher after follower rebinding; the native fixture now records publication ownership rather than relying only on target ownership. Four native delivery-reply-loss witnesses cover both routing actions (Forward/Restore), before recipient execution and after worker disposal: the leader source remains unresolved without ACK, independent sibling Cancel preserves the selected group/tab, and a late reply or repeated issued Restore click cannot settle/replay it. Explicit Forward retry after a lost ACK reproduced command duplication when the recipient worker had already disposed its journal record; stable delivery identity alone was not terminal deduplication. The follower's bounded process-local delivery window now acknowledges such a retry without re-execution while it retains that delivery. Ordinary Forward from a temporary tab first publishes a durable per-group `forwardedInputs` issuance fact in the canonical Threads owner under current authority, before either local command handling/prompt preparation/queue admission or follower RPC. Only positively unpublished issuance may receive its first grant; a published fact (even if its reply is ambiguous) is never retried, including after reload, restart or leader replacement. Local repeated selection refuses the retained grant before handler or queue re-entry. Captured All-tab provenance and acknowledged typed-input membership remain protective if the metadata reader disappears; unavailable evidence never falls back to unguarded generic dispatch. Restore retains its separate canonical routing grant. Native local fixtures interrupt source completion before/after commit, prompt preparation and issuance publication/authority; issued sources stay nonterminal, independent siblings remain cancellable and cold restart never manufactures completion or another attempt. A process-local `foreignForwardIssued` mirror gates the live chooser. An issued group is refused by repeat Forward, explicit Cancel and Restore (the store also rejects them); before its fixed chooser deadline it keeps sibling accounting protective, while body-free donor expiry or positive `completedInputs` may resolve it; independent siblings remain operable and a restarted chooser cannot resend. Issuance is not proof of delivery, and recipient-side deduplication is limited to the bounded process-local delivery window; the chooser deadline supplies a loss-accepting exit for unclaimed unknown issued groups; generic journal forwarding and non-chooser retry policy are unchanged. Canonical Restore keeps its existing durable grants. Mixed native witnesses prove that a completed Forward allows Restore of another group without replay/recancellation, while an unknown Forward prevents sibling Restore before an intent is created. Prompt Restore leaves a command sibling pending at queue admission, then privately cancels it only after exact scoped worker receipt disposition. Independently Forwarded queued input is neither unassigned nor cancellation-capable: either receipt may dispose first, the other retains custody, and only both positive dispositions release temporary membership while keeping the bound tab/slot. An ordinary queued ACK emits the existing source-completion hint only after whole acknowledged removal and fresh context, owner, generation and originating journal-binding checks; it creates no immutable Restore marker. A published independent Forward group fact wakes pure inspection of already settled Restore only after its Workspace admission releases. The store refuses both Forward facts and cancellation for any source overlapping a retained Restore grant, regardless of target; malformed partial selected groups stay protective. Native ordinary prompt Forward plus sibling Cancel also delays deletion until receipt disposition and fresh all-resolved cleanup. Pi handoff is supplied by the fixture, not observed model/task completion. The retained All-command fixture registers 84 scenarios across creation, Forward, Cancel, cleanup/membership and Restore, including full slots, publication faults, sibling protection, native Unix IPC and recipient worker drain through the real non-reentrant Workspace gate. Full-slot follower cases hold a real Unix response before apply, after apply, and after read-only inspection until client timeout. Fresh same-session registration/context generations reconcile only through inspection; late replies never publish readiness, repeat apply or dispatch, cancel siblings, release independent queued recipient work or delete the tab. Successful continuation retains exact scoped source-disposition proof. A separate cold-successor witness loads fresh stores and a journal binding after an issued command lost acceptance authority, then starts a fresh context/generation/epoch under supplied same-session owner publication. Original command and sibling stay pending, spent routing/canonical facts remain unchanged, and stale Restore/Forward/Cancel controls cannot replay or dispose them. No chooser is reconstructed: the protective hold is proven, not a usable cold recovery surface. Pi effects and startup registration remain supplied adapters/preconditions; actual Pi startup and live behavior were accepted in the operator's 0.52.0 live smoke. Forward completes only its own input: no Forward removes the tab, the worker's completion ACK records a durable `completedInputs` group (process-local accumulation across the group's sources), and when every known group is cancelled or completed the delayed, fully rechecked cleanup removes the tab once. Cancelled and completed groups are disjoint, cannot Restore, and a completed Forward queued prompt holds the tab until its receipt completes. The tab chooser discloses removal only when no other input remains; a failed removal no longer edits the original chooser. Source-only prompt Cancel remains unchanged. The candidate's temporary-tab chooser is the default under the owned leader epoch, not a configurable feature flag. Upgrade all prospective canonical readers/writers before live activation; the metadata (including `forwardProtocol`, `forwardedInputs` and `cleanupIssued`) is not downgrade-safe through older snapshot writers, which could drop issuance facts.
481
+ This multi-input lifecycle is implemented in the local candidate, not authority for live deletion. It supersedes unconditional per-chooser tab removal. The reject-only guard prevents cleanup/retirement while another known same-tab chooser remains, including unresolved cleanup-only work. `temporaryThreads.inputs` now records bounded append-only journal source groups through the unbound producer before chooser publication; duplicates are read-only, partial/foreign/overlapping groups refuse, and faults retain the source without a new chooser. Cold reads preserve this protection without process-local chooser memory. A group has no readiness or disposition flag, and an absent legacy field does not prove complete coverage. `cancelledInputs` records exact whole known donor groups after either same-journal/operator retained-cancellation evidence or the separate body-free expiry tombstone. Expiry recording may clear a group's unknown Forward issuance or its expired Restore intent, but never mutates a canonical binding, recipient queue or immutable scoped settlement proof. If Restore already bound the tab, expiry releases the temporary frame without deletion. Otherwise fully resolved groups enter the existing one-second quiet-period cleanup. A partially acknowledged known cohort may finish donor disposition when every member is absent from that exact source journal and at least one member has same-operator expiry proof; this is not recipient completion or non-delivery proof. Fresh strict namespace/protection evidence still gates deletion; independent work and bound Threads remain protected. Store publication and returned/retained acknowledgement recheck that proof and operator/executor authority; a lost reply reconciles the exact fact read-only, while missing/foreign/corrupt proof stays protective. The producer composes this into explicit Cancel before temporary cleanup or chooser retirement. Cancelled groups cannot Restore; independent sources remain untouched. More than one known group still blocks cleanup and raw retirement, including all-cancelled membership: these facts grant no deletion. Each successful Cancel retires only its own chooser. If durable membership is fully resolved by exact cancellation/completion facts and no chooser remains, a process-local cleanup is queued with no grace delay (it still waits behind the resolving operation's Workspace admission, which Cancel releases right after its notice, answering the toast and deleting any All copy alongside the cleanup; new input in the tab before it runs cancels it). Its single attempt, under profile admission, rechecks authority, whole-group cancellation/expiry evidence, exact entry CAS, a strict per-Thread journal census (every namespace source must read strictly; any retained update naming the Thread in any state, any of its own groups, and any custody-bearing, failed or non-plain entry anywhere still protect; only an unrelated waiting plain message, edit, callback or reaction elsewhere is exempt, so a chooser held in another tab cannot pin every temporary tab, and so is a plain button tap in this tab, since it carries no input and the in-flight Cancel itself may outlast the quiet period), absence of choosers and the normal reconciler protections. `issueTemporaryThreadCleanup` publishes canonical `cleanupIssued: true` only for an exact fully resolved entry with strict unbound canonical evidence checked inside the publication transaction; the normal target/source guards precede issuance and run again at API boundaries. The reconciler requires that exact retained issued frame and limits its plan to this tab; unrelated expired-provision cleanup never borrows the grant. Close/delete calls disable retries and transport fallback and require a positive acknowledgement. Confirmed current deletion alone permits entry retirement; skip, negative/lost reply, authority loss or post-rename publication interruption retains the marker. Cold reads classify already-issued entries as unknown, new membership refuses, and executor adoption never renews the grant. Missing evidence only refuses; an unpublished grant issues no API call and may still receive its first grant. The quiet period remains process-local, but issued uncertainty survives restart. The census cannot see updates in transit before journal append. Restore from a multi-input tab is allowed only when each other known group is durably cancelled, Forward-completed or a live unselected chooser that supports private abandonment. A previously completed Forward never supplies a new selection or cancellation grant. After positive settlement of every selected source, such siblings are abandoned with cancellation facts and their controls edited to cancelled, then `retireTemporaryThread(expected, authority, completed)` releases the entry (one newly completed selected group, all others durably cancelled or previously Forward-completed). Missing authority/proof or an unproven Restore leaves siblings pending and protected. On startup, a retained journal input recorded in a created temporary tab whose target a Workspace binding now owns is held as historical, never rerouted; an exact saved chooser clock may expire its unclaimed donor attempt without affecting the binding. Live pending sources and due retry-wait sources (including startup retries) use the same fresh membership/binding predicate through `shouldHoldPendingInput` before execution, with source/context/binding/transport checks after classification awaits. The hold grants neither cancellation nor delivery and does not block unrelated inputs. Recipient custody never uses this direct-source classifier. A native production witness admits a recorded command after the worker has already processed an unrelated command, proving it cannot fall through to ordinary bound dispatch. A production retry witness keeps recorded failure metadata intact without command execution, cancellation or deletion. Claimed retries cannot schedule repeated due-time wakes; independent due and future retries remain executable. Real-IPC Forward/Restore sibling witnesses now include recipient journal drain through the real worker and follower router: only the selected message executes, source disposal is observed, and repeated controls do not replay the command. Existing message-ownership composition keeps a locally published chooser's callbacks at its leader publisher after follower rebinding; the native fixture now records publication ownership rather than relying only on target ownership. Four native delivery-reply-loss witnesses cover both routing actions (Forward/Restore), before recipient execution and after worker disposal: the leader source remains unresolved without ACK, independent sibling Cancel preserves the selected group/tab, and a late reply or repeated issued Restore click cannot settle/replay it. Explicit Forward retry after a lost ACK reproduced command duplication when the recipient worker had already disposed its journal record; stable delivery identity alone was not terminal deduplication. The follower's bounded process-local delivery window now acknowledges such a retry without re-execution while it retains that delivery. Ordinary Forward from a temporary tab first publishes a durable per-group `forwardedInputs` issuance fact in the canonical Threads owner under current authority, before either local command handling/prompt preparation/queue admission or follower RPC. Only positively unpublished issuance may receive its first grant; a published fact (even if its reply is ambiguous) is never retried, including after reload, restart or leader replacement. Local repeated selection refuses the retained grant before handler or queue re-entry. Captured All-tab provenance and acknowledged typed-input membership remain protective if the metadata reader disappears; unavailable evidence never falls back to unguarded generic dispatch. Restore retains its separate canonical routing grant. Native local fixtures interrupt source completion before/after commit, prompt preparation and issuance publication/authority; issued sources stay nonterminal, independent siblings remain cancellable and cold restart never manufactures completion or another attempt. A process-local `forward-unknown` chooser phase gates the live chooser. An issued group is refused by repeat Forward, explicit Cancel and Restore (the store also rejects them); before its fixed chooser deadline it keeps sibling accounting protective, while body-free donor expiry or positive `completedInputs` may resolve it; independent siblings remain operable and a restarted chooser cannot resend. Issuance is not proof of delivery, and recipient-side deduplication is limited to the bounded process-local delivery window; the chooser deadline supplies a loss-accepting exit for unclaimed unknown issued groups; generic journal forwarding and non-chooser retry policy are unchanged. Canonical Restore keeps its existing durable grants. Mixed native witnesses prove that a completed Forward allows Restore of another group without replay/recancellation, while an unknown Forward prevents sibling Restore before an intent is created. Prompt Restore leaves a command sibling pending at queue admission, then privately cancels it only after exact scoped worker receipt disposition. Independently Forwarded queued input is neither unassigned nor cancellation-capable: either receipt may dispose first, the other retains custody, and only both positive dispositions release temporary membership while keeping the bound tab/slot. An ordinary queued ACK emits the existing source-completion hint only after whole acknowledged removal and fresh context, owner, generation and originating journal-binding checks; it creates no immutable Restore marker. A published independent Forward group fact wakes pure inspection of already settled Restore only after its Workspace admission releases. The store refuses both Forward facts and cancellation for any source overlapping a retained Restore grant, regardless of target; malformed partial selected groups stay protective. Native ordinary prompt Forward plus sibling Cancel also delays deletion until receipt disposition and fresh all-resolved cleanup. Pi handoff is supplied by the fixture, not observed model/task completion. The retained All-command fixture registers 84 scenarios across creation, Forward, Cancel, cleanup/membership and Restore, including full slots, publication faults, sibling protection, native Unix IPC and recipient worker drain through the real non-reentrant Workspace gate. Full-slot follower cases hold a real Unix response before apply, after apply, and after read-only inspection until client timeout. Fresh same-session registration/context generations reconcile only through inspection; late replies never publish readiness, repeat apply or dispatch, cancel siblings, release independent queued recipient work or delete the tab. Successful continuation retains exact scoped source-disposition proof. A separate cold-successor witness loads fresh stores and a journal binding after an issued command lost acceptance authority, then starts a fresh context/generation/epoch under supplied same-session owner publication. Original command and sibling stay pending, spent routing/canonical facts remain unchanged, and stale Restore/Forward/Cancel controls cannot replay or dispose them. No chooser is reconstructed: the protective hold is proven, not a usable cold recovery surface. Pi effects and startup registration remain supplied adapters/preconditions; actual Pi startup and live behavior were accepted in the operator's 0.52.0 live smoke. Forward completes only its own input: no Forward removes the tab, the worker's completion ACK records a durable `completedInputs` group (process-local accumulation across the group's sources), and when every known group is cancelled or completed the delayed, fully rechecked cleanup removes the tab once. Cancelled and completed groups are disjoint, cannot Restore, and a completed Forward queued prompt holds the tab until its receipt completes. The tab chooser discloses removal only when no other input remains; a failed removal no longer edits the original chooser. Source-only prompt Cancel remains unchanged. The candidate's temporary-tab chooser is the default under the owned leader epoch, not a configurable feature flag. Upgrade all prospective canonical readers/writers before live activation; the metadata (including `forwardProtocol`, `forwardedInputs` and `cleanupIssued`) is not downgrade-safe through older snapshot writers, which could drop issuance facts.
480
482
 
481
483
  - `Membership`: A positively source-linked disposable temporary Thread owns no Pi binding or A–Z slot and may contain multiple independent unassigned inputs, each with its own routing controls. Track exact journal source/group membership, including additional inputs, rather than treating the first chooser or a process-local count as the whole Thread. Serialize admission, selection, cancellation, Restore and cleanup through the existing Workspace admission and mutation owners; unreadable, incomplete, selected, accepted, running or unknown-issued evidence blocks deletion.
482
484
  - `Per-input Cancel`: Privately retain the exact original and positively commit source-only cancellation before acknowledging `Routing cancelled` and retiring its route controls. Other unassigned inputs retain their choosers and custody; cancelling one input neither delivers nor cancels siblings. No separate Cancel-and-delete action or extra confirmation dialog is required, but the chooser must disclose the conditional whole-tab deletion consequence.
483
- - `Last-resolution cleanup`: Only an explicit Cancel or positive completion of an explicitly issued Forward that resolves the final known group may schedule deletion of the entire still-temporary Telegram tab, including all its messages. The operator-approved grace is 1 second (1,000 ms), superseding the earlier 2–3-second design. The current local candidate already matches it without a runtime change or production override. For Last Cancel, scheduling follows positively recorded whole-group cancellation and successful retirement of the final chooser, not the initial button tap. The timer establishes earliest eligibility for one proof-gated cleanup attempt, not an exact deletion time: Workspace admission, fresh protection checks and Bot API latency may delay or refuse it. Actual client timing was accepted in the operator's 0.52.0 live smoke. Mirrored native witnesses use shortened injected delays, not a production-default or Telegram-client timing measurement. This grace is presentation timing, not proof of emptiness or non-delivery. New input or a changed binding/authority cancels the scheduled cleanup. Immediately before issuance, reacquire current Workspace admission, recheck exact operator/profile/session/leader/source/target authority, positive disposable-tab provenance, complete source dispositions and all Thread protection, then publish the canonical one-shot temporary cleanup grant. A restored/bound Thread or any unresolved/unverifiable work remains protected. TTL, startup, silence and a zero chooser count do not manufacture this last-Cancel grant. Failed/unknown deletion cannot undo cancellation or cause automatic repeat issuance.
485
+ - `Last-resolution cleanup`: Only an explicit Cancel or positive completion of an explicitly issued Forward that resolves the final known group may schedule deletion of the entire still-temporary Telegram tab, including all its messages. The operator-approved grace is now zero, superseding the earlier 1-second and 2–3-second designs: deletion is attempted right after the cancellation notice. For Last Cancel, scheduling follows positively recorded whole-group cancellation and successful retirement of the final chooser, not the initial button tap. The timer establishes earliest eligibility for one proof-gated cleanup attempt, not an exact deletion time: Workspace admission, fresh protection checks and Bot API latency may delay or refuse it. Actual client timing was accepted in the operator's 0.52.0 live smoke. Mirrored native witnesses use shortened injected delays, not a production-default or Telegram-client timing measurement. This grace is presentation timing, not proof of emptiness or non-delivery. New input or a changed binding/authority cancels the scheduled cleanup. Immediately before issuance, reacquire current Workspace admission, recheck exact operator/profile/session/leader/source/target authority, positive disposable-tab provenance, complete source dispositions and all Thread protection, then publish the canonical one-shot temporary cleanup grant. A restored/bound Thread or any unresolved/unverifiable work remains protected. TTL, startup, silence and a zero chooser count do not manufacture this last-Cancel grant. Failed/unknown deletion cannot undo cancellation or cause automatic repeat issuance.
484
486
  - `Forward`: Forward only the selected input and preserve independently held siblings. Its existing source-tab cleanup cannot erase another unassigned or protected input; per-input completion is not whole-Thread deletion proof.
485
487
  - `Successful Restore`: Preserve this tab as the selected instance's bound Workspace Thread and keep its slot; only the selected input is delivered. Cancel the exact other still-unassigned inputs with private retention, positive source-only disposition and invalidated controls, without delivering them to Pi or physically removing the restored tab. Already selected, queued, running and unknown-issued work is outside sibling cancellation. Failed or unknown Restore does not cancel siblings. Composition must establish the exact sibling set under serialized membership and prevent held/partly-cancelled originals from falling through to normal bound-Thread execution after relocation; a retention/ACK fault preserves unresolved sources and cannot roll back independently accepted work.
486
488
  - `Validation and activation`: Native witnesses must cover two/three inputs, grouped sources, different cancellation orders, new admission during the grace, concurrent selection/Forward/Restore, stale controls, incomplete membership, retention/ACK faults, restart and one-shot unknown deletion. Operator-controlled live acceptance must explicitly authorize disposable test-tab deletion; it passed in the operator's 0.52.0 live smoke.
@@ -492,7 +494,7 @@ A Pi process restart starts a new routing world. Unfinished routing from the pre
492
494
  - `Spent prompts`: Pending prompts that Pi never accepted into its queue — unselected, chooser-held, temporary-tab or Restore-held, including an issued but unconfirmed Forward — are spent: removed from pending custody without Pi delivery, a private retained copy, a notification or task completion. The polling cursor already prevents Telegram redelivery; spending is disposition, never replay. Implemented: the leader worker's `spendHistoricalInput` removes startup-census pending sources that carry a routing input or that the domain classifier marks boolean true, under current authority, through ordinary removal without completion observers. A distinct retain-only verdict takes precedence over an old routing clock and spending; unsupported protected originals remain unchanged. Retry-wait sources, interrupted private abandonments, queued receipts and live arrivals keep their existing holds; unknown classification spends nothing. Also implemented: the leader's startup hint, fenced by the owned polling generation, calls routing `forgetPreviousWorld`. Under profile admission it atomically removes this operator's Restore intents and temporary entries whose executor belongs to another runtime instance (a reload is a new instance), then makes one non-idempotent `deleteForumTopic` attempt per previously classified disposable created tab still unreferenced by bindings, active records, temporary entries or Restore intents, and only after a fresh strict source census returns complete-empty. Retained, unreadable or unavailable source evidence blocks that deletion without reconstructing the forgotten intent.
493
495
  - `Old temporary tabs`: An unbound tab with positive disposable provenance gets one silent deletion attempt. Failure or an unknown outcome leaves the tab without retry.
494
496
  - `Unfinished Restore`: The intent is forgotten. Already committed canonical binding changes stay as they are, without rollback.
495
- - `Old controls`: Choosers and buttons from the previous process answer `⌛ Routing choice expired.` (implemented as `TELEGRAM_ROUTING_CHOICE_EXPIRED`, shared with the warm expiry edit).
497
+ - `Old controls`: Choosers and buttons from the previous process answer with the shared expired-choice notice `TELEGRAM_ROUTING_CHOICE_EXPIRED`, also used by the warm expiry edit ([copy](./ui-style.md#route-chooser)).
496
498
  - `Untouched`: Committed Workspace tabs and bindings, prompts already accepted into the Pi queue (exact receipts), follower custody, and in-process `/new` succession, which is not a restart.
497
499
 
498
500
  The user recreates a temporary tab and restores again when needed. This superseded the earlier cold policy: working-tab attestation, held-source inspection/scope capabilities and strict per-group cold disposition/finalization were removed. The historical classifier, temporary-tab hold, one-shot startup hint and polling-generation fence remain as inputs to spending and forgetting.
@@ -564,7 +566,7 @@ The canonical update transition contract is:
564
566
 
565
567
  The worker executes at most 64 eligible entries from one validated journal snapshot, commits ordinary completions through one journal transaction, then yields through a generation-checked event-loop boundary. Retry, queue, or prior-generation boundaries first flush completed ids and force a fresh snapshot, preserving exact state-transition atomicity without per-entry parse/rewrite churn. A deterministic 2,048-entry stress gate requires exactly 32 completion publications, 33 reads including the final empty snapshot, continued 1ms timer progress, and less than 250ms maximum observed heartbeat delay. Byte-capacity tests cover failed and retry-wait diagnostics, queue receipt/owner and handoff metadata, and operator dispositions; every rejected growth leaves the prior authority bytes unchanged. It still scans later independent entries after retry or terminal persistence. An unresolved reaction remains a queue-mutation dependency even in `retry-wait` or `failed`, but dispatch checks that dependency against the candidate queue item's exact chat and source message ids instead of globally blocking unrelated targets. Successful replay or an exact discard disposition releases the dependency. Worker state, debug status, state snapshots, and redacted runtime events expose journal depth, retry/terminal counts, the next retry, latest terminal identity, copyable operator commands, and the exact first foreign queued owner identity (instance, PID/birth, session, and acquisition) when semantic authority belongs to another process.
566
568
 
567
- The journal is the sole polling/admission authority. Each atomic journal revision publishes the admitted batch and monotonic `acceptedThroughUpdateId` together; cursor-only initial synchronization uses an empty batch revision. Existing config cursors are transferred once before polling: journal publication precedes config removal, restart retries are idempotent, established journal authority never regresses, and an unprovable non-empty journal fails closed. Upgrades create journals lazily before the first post-upgrade offset advance. A bot/profile identity change with unresolved authority fails closed. Once reconstructed authority is empty, the next read atomically rebinds profile and bot identity under the journal transaction and removes redundant old-identity segments best-effort; stable-`botId` token rotation remains valid even with entries. Downgrading below `0.37.0` with a cursor-schema journal is unsafe because an older runtime cannot recover `acceptedThroughUpdateId` and could repoll admitted updates. After rebuilding the checkout, run `node scripts/check-downgrade.mjs [agent-dir]`; the conservative older-schema validator rejects that retained authority even when entries are drained. It inspects flat snapshots and canonical session-folder `journal.*` and `inbox[.<profile>]` snapshots plus segment tails under shared directory/file/byte limits. Noncanonical directory names, symbolic links, orphan segments and private retention refuse inspection instead of being ignored; legacy `recovery/` folders hold no journal authority and are skipped. It never modifies or compacts files. Stop all participants before relying on the result: this journal-only advisory check is not writer closure, a strict whole-namespace recensus, proof of coordinator compatibility or permission to downgrade, replay or delete. The pre-0.52.0 `tmp/telegram` tree remains untouched. Current-runtime corruption recovery is the distinct guarded delete/reset policy above; unsupported schemas and saved `telegram.json` stay preserved.
569
+ The journal is the sole polling/admission authority. Each atomic journal revision publishes the admitted batch and monotonic `acceptedThroughUpdateId` together; cursor-only initial synchronization uses an empty batch revision. Existing config cursors are transferred once before polling: journal publication precedes config removal, restart retries are idempotent, established journal authority never regresses, and an unprovable non-empty journal fails closed. Upgrades create journals lazily before the first post-upgrade offset advance. A bot/profile identity change with unresolved authority fails closed. Once reconstructed authority is empty, the next read atomically rebinds profile and bot identity under the journal transaction and removes redundant old-identity segments best-effort; stable-`botId` token rotation remains valid even with entries. Downgrading below `0.37.0` with a cursor-schema journal is unsafe because an older runtime cannot recover `acceptedThroughUpdateId` and could repoll admitted updates. The pre-0.52.0 `tmp/telegram` tree remains untouched. Current-runtime corruption recovery is the distinct guarded delete/reset policy above; unsupported schemas and saved `telegram.json` stay preserved.
568
570
 
569
571
  Polling and inbound-worker diagnostics remain separate so an executing, deferred, locally queued, foreign-queued, or blocked journal head cannot masquerade as a stalled `getUpdates` request.
570
572
 
@@ -594,9 +596,9 @@ Waiting Normal/Priority prompts expose two independent dimensions:
594
596
 
595
597
  A prompt is one queue object with exactly one active lane membership and one current position. It has no duplicate, shadow entry, or reserved return slot in the other lane. Each prompt admitted directly to a lane joins that lane's tail. A `Normal → Priority` transition removes it from Normal and appends that same object to the Priority tail; a later `Priority → Normal` transition removes it from Priority and appends it to the current Normal tail rather than restoring any historical position. The immutable `queueOrder` records original admission identity only and is never a return address; `laneOrder` records the current destination-lane position. Keep/Skip changes and emoji changes within the same reaction category preserve both lane and lane position exactly.
596
598
 
597
- Telegram reactions are shortcut controls over those dimensions. Positive reactions (`👍`, `⚡️`, `❤️`, `🕊`, `🔥`) control Priority; negative reactions (`👎`, `👻`, `💔`, `💩`, `🗑`) control Skip. The runtime compares the complete old and new reaction sets and mutates only categories that changed, so adding or removing a negative reaction cannot silently change Priority, and changing a positive reaction cannot silently change Skip. The listed order selects the retained display emoji when several recognized emoji from one category coexist; it does not let one category override the other.
599
+ Telegram reactions are shortcut controls over those dimensions. Recognized positive reactions control Priority and recognized negative reactions control Skip; the emoji sets live in the [queue reaction registry](./ui-style.md#queue-reaction-shortcuts). The runtime compares the complete old and new reaction sets and mutates only categories that changed, so adding or removing a negative reaction cannot silently change Priority, and changing a positive reaction cannot silently change Skip. The registry order selects the retained display emoji when several recognized emoji from one category coexist; it does not let one category override the other.
598
600
 
599
- Priority and Skip may coexist, including `👍 + 💩`. The prompt remains at its Priority-lane position while waiting, and its durable journal receipts remain intact so Keep stays reversible and exact live handoff remains possible. Skip wins when dispatch reaches the prompt: the dispatcher first settles those receipts durably, then drops it without a model turn and continues; settlement failure retains the skipped head instead of allowing replay ambiguity. The prompt stays visible with only its negative emoji, is excluded immediately from the executable queue count shared by the Pi status bar and Telegram main menu, and keeps a struck-through physical ordinal. Returning it to Keep restores its contribution to the count without moving it. Graceful session shutdown discards all remaining queue receipts before clearing session-local memory, and startup discards receipts only after proving their former process dead, so a new or unrelated session never inherits queued work. Queue item detail exposes symmetric Priority/Normal and Keep/Skip selectors instead of an irreversible Delete action.
601
+ Priority and Skip may coexist when a prompt carries both a positive and a negative reaction. The prompt remains at its Priority-lane position while waiting, and its durable journal receipts remain intact so Keep stays reversible and exact live handoff remains possible. Skip wins when dispatch reaches the prompt: the dispatcher first settles those receipts durably, then drops it without a model turn and continues; settlement failure retains the skipped head instead of allowing replay ambiguity. The prompt stays visible with only its negative emoji, is excluded immediately from the executable queue count shared by the Pi status bar and Telegram main menu, and keeps a struck-through physical ordinal. Returning it to Keep restores its contribution to the count without moving it. Graceful session shutdown discards all remaining queue receipts before clearing session-local memory, and startup discards receipts only after proving their former process dead, so a new or unrelated session never inherits queued work. Queue item detail exposes symmetric Priority/Normal and Keep/Skip selectors instead of an irreversible Delete action.
600
602
 
601
603
  Menu and reaction controls share the same canonical queue state. A menu Keep can clear internal Skip without changing Priority or queue position, but Telegram's Bot API cannot remove a reaction created by the user; the visible user reaction can therefore remain until that user removes it. Once Pi has consumed or dropped a prompt, later reactions cannot retract or restore it.
602
604
 
package/docs/inbound.md CHANGED
@@ -49,7 +49,7 @@ Legacy `telegram.json` files may still define `attachmentHandlers` for media/fil
49
49
 
50
50
  At runtime, `attachmentHandlers` is appended after `inboundHandlers`. Existing configs continue to work, while new configs should use `inboundHandlers`.
51
51
 
52
- Handlers match by optional `type`, `mime`, or `match`. `mime` and `type` are independent selectors: if `mime` is present, `type` is not required. Wildcards such as `audio/*` or `text/*` are accepted. Each matching handler must provide `template`; a string is one command, and an array is ordered composition. Top-level `args` and `defaults` apply to composed steps unless a step defines private values. The command-template default timeout applies automatically. Use `template: [...]` for composition; the old local `pipe` alias is removed in 0.13.0.
52
+ Handlers match by optional `type`, `mime`, or `match`. `mime` and `type` are independent selectors: if `mime` is present, `type` is not required. Wildcards such as `audio/*` or `text/*` are accepted. Each matching handler must provide `template`; a string is one command, and an array is ordered composition. Top-level `args` and `defaults` apply to composed steps unless a step defines private values. The command-template default timeout applies automatically. Use `template: [...]` for composition; the old local `pipe` alias is removed in 0.13.0. A falsy root `when` skips that handler: inbound and voice selection continue with the next matching handler, while a text transform passes its input through unchanged. A falsy `when` on a composed step, or on any enclosing composition node, skips that step and passes the previous output on. `recover` runs only between failed `retry` attempts of the node that declares it; its output is ignored and a recovery failure stops further retries. `parallel` and `delay` are not executed by these handlers.
53
53
 
54
54
  `defaults` may provide additional placeholder values such as `{lang}` or `{model}`. `args` is only a string-array declaration of supported placeholders; defaults belong in `defaults` or inline placeholders such as `{lang=ru}`. Examples prefer explicit flag-style CLIs such as `--file {file}` and `--lang {lang=ru}` for readability, but positional forms such as `/path/to/stt {file} {lang=ru} {model=voxtral-mini-latest}` are equally valid when the target script supports them.
55
55