# Telegram Bridge Architecture

## Purpose

`pi-telegram` is a session-aware Pi runtime extension that binds Telegram destinations to running Pi instances and routes each accepted prompt into the assigned instance's currently active session. It owns the Telegram bridge boundary:

- Poll Telegram updates and enforce single-user pairing.
- Translate Telegram text, callbacks, media, and files into Pi turns.
- Stream previews and deliver final Pi responses back to Telegram.
- Provide Telegram-native controls for queueing, model/thinking/settings menus, compaction, abort/stop, prompt templates, reactions, and outbound artifacts.

The bridge is a mobile companion for a live Pi runtime, not a remote terminal or session browser. It should let an operator start work in the TUI and continue supervising the instance's active session from Telegram, while staying inside Pi's extension-facing contracts.

This document is the architectural map. Focused behavior standards live in sibling docs:

- [Public API](./public-api.md) — stable commands, config, package entrypoints, assistant markup, extension APIs, and compatibility boundaries.
- [Telegram Delivery API](./delivery.md) — target-aware operational views, logical message handles, lifecycle fencing, and leader/follower transport.
- [Telegram Activity API](./activity.md) — normalized Pi lifecycle events, activity/source identity, non-blocking extension dispatch, and delivery contexts.
- [UI Style](./ui-style.md) — inline UI labels, navigation, state markers, cards, and dialogs.
- [Callback Namespaces](./callback-namespaces.md) — callback prefix ownership and fallback rules.
- [Sections](./sections.md) — structured Telegram menu sections.
- [Updates](./updates.md) — update classification, default-routing plans, and raw Telegram update interception.
- [Voice Integration](./voice.md) — voice reply policy and STT/TTS provider surface.
- [Command Templates](./command-templates.md) — shell-free command-template contract.
- [Generative Apps](./generative-apps.md) — managed reusable application identity, state, generated button views, hybrid action routing, replacement, and bounded execution contract.
- [Telegram Multi-Instance Bus](./multi-instance-bus.md) — Threaded Mode bus leadership, Telegram UI thread targets, instance identity, and leader/follower routing.

## Runtime Topology

`index.ts` is a thin package entrypoint that re-exports the default extension from `lib/extension.ts`. `lib/extension.ts` is the only composition root. It wires live Pi ports, Telegram Bot API ports, session-local stores, lifecycle hooks, and domain runtimes. It should operate at high-level domain-runtime boundaries: non-trivial Threaded Mode capability decisions, leader/follower recovery, sync-slice bookkeeping, manual thread cleanup, and bus routing policies belong in their owning `/lib` domains. Reusable logic lives in flat `/lib/*.ts` domain modules rather than a deep local module tree.

### Extension Boundary Vs Supervisor Control

`pi-telegram` runs inside the current Pi process as an extension. That gives it safe access to public extension APIs such as aborting work, compacting, dispatching queued prompts, observing lifecycle events, and rendering Telegram-native controls. It does not own the terminal, the interactive-mode chat transcript, or the process lifecycle.

Keep this boundary explicit:

- Do not use raw TTY injection, ANSI terminal clearing, private TUI container mutation, or a shadow `pi` subprocess to simulate interactive commands.
- Do not treat Telegram as a generic remote shell for every Pi slash command.
- Commands that require interactive session replacement or TUI rerendering, such as a true Telegram `/new`, need a public Pi API that invokes the same runtime path as the terminal command.
- A separate PTY supervisor or daemon could choose to own those risks, but that would be a different product mode rather than this extension's runtime contract.

### Instance, Session, And Context Cost

Live Telegram routing belongs to the active authenticated Pi instance, while a durable Workspace Thread belongs to the exact profile/CWD/session identity. Ordinary Telegram prompts enter the session currently bound to that target. Local `/resume` replaces session-scoped runtime state and selects the destination session's binding; it never inherits the source Thread merely because the process is unchanged. Telegram exposes compaction and new-session replacement for the active session: `/new` first completes and removes its exact durable update, then dispatches an internal registered Pi command through `pi.sendUserMessage(..., { expandPromptTemplates: true })` so the handler runs with a real `ExtensionCommandContext` and calls the same `AgentSessionRuntime.newSession()` path as the terminal. Before invoking that path, the current transport owner CAS-publishes one expiring replacement intent inside the existing profile target snapshot. The intent discriminates `workspace-thread` from `classic-chat`. A same- or cross-process successor may consume either only for the exact profile, CWD, source session, target, and fresh lifetime: Threaded continuity re-keys the retained Workspace binding and preserves Thread, slot, and display identity, while Classic continuity preserves the exact chat target without creating a Workspace binding or entering topic lifecycle APIs. A confirmed callback is acknowledged and its dialog is deleted before session replacement begins. Once the successor has delivery authority, it atomically claims the intent by CAS-clearing it and then sends one separate terminal success result with bounded in-process transport retry. The old `withSession` path never publishes success, and an unclaimed intent never sends, preventing duplicate terminal notices across same-process startup and cleanup-ack ambiguity. Mismatch or expiry never authorizes binding takeover. Resume, fork, tree navigation, session switching, and full reload remain outside the stable Telegram API until Pi exposes safe public extension hooks for them.

`/telegram-connect` never launches a hidden or headless Pi process. A long-lived background Pi process can own Telegram only when something else explicitly launched that process and it satisfies the normal lock/runtime rules. Pi `print` and `json` modes stay passive and exit rather than becoming hidden polling owners.

Pi session JSONL and pi-telegram runtime JSONL serve different purposes. Pi session files contain model conversation, tool, usage, branch, and compaction entries. The shared, profile-labelled `logs.jsonl` contains redacted bridge operations from one or more instances and never become model context. Sharing a Telegram profile or working directory does not by itself merge Pi session identities or model histories.

A Telegram prompt is a normal Pi model turn. It inherits the active post-compaction context just like a TUI prompt in the same session; pi-telegram does not promise context isolation or token cost proportional only to the new message. The bundled `telegram-bridge` Skill owns agent operation, while `show-me` owns portable evidence-honest explanation shape plus Telegram phone-width Markdown and browser-artifact adaptation; neither owns the other's transport boundary. A small authority-aware system note routes applicable turns to these and the other bundled Skills. Existing session files created by older versions may still contain historical repeated guidance until session replacement or compaction removes it from active context.

The repository uses a **Flat Domain DAG**:

- Local imports must form a directed acyclic graph.
- Cohesive domain files are preferred over atomizing every helper.
- Shared buckets such as `lib/constants.ts` or `lib/types.ts` are avoided.
- Constants and state types live with their owning domain.
- Narrow structural projections are allowed when they avoid importing broader runtime or wire DTOs.
- Source file headers include `Zones:` tags so cross-cutting responsibility stays visible without folder nesting.

### Live-Rebind Module Map

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 bus protocol v3, 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.

The channel reuses existing owners rather than adding a parallel command bus, queue or recovery store:

- `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.
- `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.
- `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.
- `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.

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).

### Domain Ownership Map

- `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.
- `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.
- `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.
- `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.
- `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.
- `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.
- `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.
- `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.
- `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.
- `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.
- `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 v3 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.
- `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.
- `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.
- `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.
- `thread-display`: Shared Letters/Names/Directories projection, Settings-mode/manual-override coordination, initial-create title selection, and serialized leader-owned title application. Owns bounded path disambiguation, ambiguous-label rejection, and profile/mode/epoch plus captured live-binding fences. Acknowledged `displayTitle` remains distinct from stable `threadName`; the caller owns triggers and live-owner discovery. Leader provisioning applies the configured projection before creation; registration ACKs deliver the acknowledged title before initial follower status, and heartbeat ACKs carry later changes. Stable runtime names remain restoration identity rather than presentation. Current-thread/TUI display identity is separate from restoration identity. Live bot choosers, notices, prompt labels, and cross-instance agent-target resolution use acknowledged display titles while captured numeric targets and live registrations remain the routing authority. Settings routes direct-owner changes locally and follower changes through an authenticated capability-gated envelope. The leader serializes preference writes and application.
- `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.
- `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.
- `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.
- `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.
- `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.
- `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.
- `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.
- `runtime`: session-local coordination primitives: counters, flags, setup guard, abort handler, typing timers, dispatch flags, and reset binding.
- `model` / `menu-model` / `menu-thinking` / `menu-status` / `menu-queue` / `menu-settings` / `menu` / `commands`: model identity, thinking levels, scoped model handling, menu render/callback behavior, slash commands, bot commands, and interactive controls.
- `sections`: Telegram menu-section registry, opaque section callback tokens, render/callback dispatch, safe section ports, and diagnostics.
- `keyboard`: shared inline-keyboard reply-markup shape only; feature domains own labels, callback data, and behavior.
- `preview` / `replies` / `rendering`: throttled native Rich Markdown draft delivery, native final reply delivery, reply parameters, transport-limit chunking, and remaining Telegram HTML rendering (bold, italic, strikethrough, spoilers, code, links) for bridge-owned UI/compatibility surfaces.
- `delivery`: public extension operational-view delivery, active-turn/instance/aggregate/authorized target policy, logical chunk handles, per-target ordering, runtime generation fencing, and the process-local runtime membrane. Its bridge adapter composes the established UI/compat reply renderer with narrow bus-aware Telegram API and ownership ports; it never exposes bot clients or Pi contexts.
- `activity`: public normalized Pi lifecycle registration, activity/source identity, assistant segment and reasoning normalization, executed-tool events, non-blocking per-handler queues, delivery contexts, compatibility adapters, and shutdown fencing. The same domain extends assistant-output observation for connected companion projection: eligible completed local/autonomous public segments retain source order and deduplicate event identity. `bindings` assembles observation, authority, sender, and failure-projection ports; routing owns exact delivery authority, outbound composes established transformations and reply delivery, and Bot API domains implement transport. No separate proactive state-machine domain exists.
- `outbound-markup`: top-level assistant action comment/fence parsing, shared JSON/CML grammar, attribute parsing, voice reply planning, and preview/delivery stripping.
- `outbound`: outbound text transformations, voice/button artifact delivery, and generated callback actions.
- `generative-apps`: managed deterministic application identity, canonical installation and explicit replacement, content-addressed module loading, state timelines, cross-process transition serialization, bounded executable-plus-argv adaptation, `telegram_bind`, and pre-model-queue `app::method` invocation. It does not own Telegram transport, arbitrary shell execution, or the external application adapted by one Generative App.
- `outbound-attachments`: `telegram_attach`, queued outbound files, stat/limit checks, ordinary photo/document delivery, and narrow single-artifact Rich Message planning/sending for probe-confirmed photo/video/audio formats. It owns known-failure fallback eligibility and ambiguous-send no-replay classification through structural error contracts without importing Bot API helpers.
- `channel-posts`: profile/token-bound authority for agent-authored channel publication intents, one-shot send/edit/delete fencing, outcome-unknown retention, exact successful post identity, capacity refusal, and bounded local listing. It never reads Telegram history; the composition root supplies direct-leader Bot API effects only after its durable grants.
- `status` / `logs`: status bar/status-message rendering, queue-lane summaries, the structural redacted event ring, profile-aware JSONL scope/reset/append behavior, exact-owner destructive commits, fail-soft synchronous and queued diagnostics persistence, status snapshot scheduling, grouped diagnostics, and allowlisted compact connection-failure copy shared by commands and lifecycle. `status` remains a structural leaf; `logs` composes filesystem evidence with status projections and contains every persistence failure so diagnostics cannot terminate or poison the runtime queue.
- `bindings` / `lifecycle` / `prompts` / `prompt-templates` / `pi`: Pi-facing command/tool/hook registration and cohesive cross-domain binding assembly, including queue mutation/dispatch/watchdog composition over admission and transport ports; session-generation fencing and start/shutdown sequencing across Queue, grouped input, Delivery, polling, capability monitor, follower refresh, and assistant-output projection; Telegram prompt guidance; prompt-template discovery/expansion; and centralized direct Pi SDK imports. `lifecycle` also owns bounded same-process connect intent across local `/resume`, cancellation/supersession, and fresh-context startup scheduling; it does not own transport authority, durable bindings, queue custody, or source-target continuity.
- `command-templates`: shell-free command-template helpers, composition expansion, placeholder substitution, executable resolution, warnings, and retry/timeout semantics.

### Host Compatibility Boundary

Pi is the primary and only officially supported host. `pi-telegram` may still accept narrow, host-neutral representation differences at its existing Pi-facing boundary when they preserve native Pi behavior and do not create a second runtime policy layer:

- `prompts` preserves either Pi's plain system-prompt string or an ordered block array supplied by a compatible host, appending Telegram guidance without collapsing host-owned blocks. An absent/null host system prompt is treated as empty, including the disconnected metadata-stripping path.
- `pi` normalizes settings-manager construction that is either synchronous or asynchronous, then adapts either Pi's legacy enabled-model methods or a generic `get` / `set` settings service before model-menu reads and scoped-model persistence use it. Hosts without an explicit reload method rely on fresh asynchronous construction; durable writes still require `flush`.
- `lifecycle` continues to require Pi's semantic `agent_settled` boundary. It does not infer terminal settlement from host-specific `agent_end`, retry, or stop events; a compatibility shim must reproduce that contract before it can safely support activity identity and unrecovered-error finalization.

This boundary uses no host-name detection, host package dependency, prototype patching, hidden agent process, PTY, or terminal forwarding. Representation adapters are best-effort compatibility rather than an OMP support guarantee. Alternate hosts and community contributors own validation of their compatibility shims and must supply every lifecycle semantic that the bridge requires.

### Guarded Invariants

Architecture invariant tests protect:

- Acyclic local imports.
- Direct Pi SDK imports centralized in the `pi` adapter.
- A thin `index.ts` package boundary and `lib/extension.ts` as the composition root without local runtime adapter logic.
- Runtime state isolation from local domain imports.
- Structural leaf-domain isolation.
- Menu/model boundary direction.
- API/config separation.
- Media/update/API decoupling.
- Outbound attachment isolation from queue, inbound media, and API helpers.

Mirrored domain regressions live in `/tests/*.test.ts`. Shared test fixtures should exist only when multiple suites genuinely reuse them.

## Configuration And Ownership

Telegram configuration lives in `~/.pi/agent/telegram.json`. Bot/session identity (`botToken`, `botUsername`, `botId`, `allowedUserId`) persists only under `profiles.default` or `profiles.<name>`; shared handlers and assistant/voice/time settings stay top-level. Per-profile polling/admission state lives only in the durable update journal as `acceptedThroughUpdateId`. Authoritative transport ownership lives separately in the `transport` section of the pi-telegram-private `~/.pi/agent/tmp/pi-telegram/state.json`, one profile entry per `default` or validated named profile (see [Consolidated Runtime Root](#consolidated-runtime-root)); unrelated extensions never read or write this file.

`telegram.json` is one global cross-instance configuration document. Ordinary reads rely on atomic publication and do not take the mutation guard. Only config writes and sender admission enter `telegram.json.transaction`; the update journal never uses it. Every cooperating Pi instance persists only its recursive delta from the snapshot it loaded, merges that delta into the latest disk document inside `telegram.json.transaction`, and publishes atomically only when the semantic result differs; a no-op merge adopts the newer disk snapshot in memory without replacing the file. Unrelated global and profile changes therefore survive stale writers. Two serialized writers changing the same leaf use commit order, so the later local delta wins. A non-transactional external editor cannot participate in that conflict protocol: it should write through same-directory atomic replacement while Pi is idle, then let instances reload; an editor racing the transaction may lose its same-leaf change and must retry from the resulting file.

### Setup Flow

First-contact pairing publishes through a profile-exact config-store operation, not a live setter followed by a save. Inside the existing config transaction, it rechecks execution/profile/token identity, reads the current disk owner, and writes only an unpaired profile; a different configured owner denies the candidate without overwrite. Only successful publication or confirmation of the same disk owner updates local authorization. Failure leaves the candidate unpaired for retry, and adopting disk evidence preserves unrelated local settings. Queued writes retain their request-time baseline for the requested disk delta, but cache adoption compares local deltas against the latest observed persisted state. An observed owner is not a local grant edit; later local unpair and external revocation must survive queued completion and subsequent saves. Message/edit/callback pairing and denial admission precede foreign message/target routing and unbound-Thread delegation, so fallback dispatch and ownership recording cannot bypass publication. `/start` menu side effects also stop when pairing returns false; configured matching owners remain authorized. Reactions require an existing positive safe-integer owner and that exact human sender before ownership lookup, forwarding, group flush or queue mutation—even in private chats. Unpaired, foreign-user, bot, missing-user and actor-chat reactions do not initiate pairing or perform those effects. This is publication safety, not operator-confirmed pairing: the first-contact UX is unchanged.

`/telegram-setup` progressively resolves the bot token:

1. Use the locally saved token when present.
2. Otherwise use the first supported Telegram token environment variable, prefilled as an exact `$NAME` reference instead of the resolved secret.
3. Otherwise show the example placeholder.

`profiles.<name>.botToken` may hold a literal token (compatibility) or an exact `$NAME`/`${NAME}` environment reference. References are resolved only at validation and activation boundaries: setup validates the resolved value while persisting the alias, the config store exposes the resolved token to transport and identity hashing, and every other boundary keeps the stored reference. An unresolved reference fails closed with a redacted named-variable diagnostic, and a `$`-prefixed value that is not a valid reference is malformed rather than a literal secret.

`ctx.ui.input()` only supports placeholder text, so setup uses `ctx.ui.editor()` when a real default must appear already filled in. Bare and explicit `default` setup/connect commands address the same `profiles.default` entry. Persisted config is written through a private temp file plus atomic rename and left with `0600` permissions. On first load, legacy root identity moves into `profiles.default` in that same serialized atomic transaction when no conflicting canonical value exists; identical duplicates collapse, complementary fields merge, and conflicts reject the load without modifying the file.

### Automatic Pairing Confirmation Design

**Status: approved UX direction; isolated storage preparation implemented, production unchanged.** The operator selected an automatically presented confirmation in trusted Pi UI, detached from the journal worker. Current runtime behavior remains the publication-safe automatic first-contact flow described above until implementation and review are complete. Existing configured owners and manual numeric-ID preconfiguration remain compatible.

#### Admission And UI

- A valid unpaired private human message creates a bounded candidate, not an authorized prompt. Edits and callbacks cannot create independent approval requests; they remain non-executable while unpaired. Guest messages are not a pairing surface.
- Return a distinct `pending` admission outcome before foreign routing, ownership recording, unbound handling, downloads, inbound handlers, menus, or model dispatch. The worker must not await either the dialog or approval-time config publication. Pending is not a transient execution error that retries the original prompt into authorization.
- Schedule the dialog through the session-owned pairing runtime after candidate admission. Use native `ctx.ui.confirm` with an AbortSignal and timeout; no custom editor, shadow process, model turn, or `/telegram-pair` command is needed. Initial support is terminal UI (`ctx.mode === "tui"`); `hasUI` alone also admits RPC and is insufficient for this terminal trust boundary. Without that surface, remain unpaired and retain manual preconfiguration as the fallback.
- Show the exact bot profile and numeric Telegram user ID, plus a bounded, control-character-safe display name as untrusted context. Example title: `Allow Telegram account?`; body explains which account gains access to the running Pi session and that earlier input will not be executed. Neither message text nor credentials enter the dialog or model history. No/ESC, timeout, UI error, or missing UI means no grant.
- Permit one candidate and one dialog per active profile/runtime. The candidate lasts 60 seconds from admission; duplicate input does not extend it. Keep the remaining window as a profile-wide cooldown after rejection/error/timeout to prevent immediate dialog flooding. A different requester cannot replace the visible candidate; operators can reject and request a fresh `/start` after the window. Keep this bounded trade-off explicit rather than adding an unbounded waiting list. This limits dialog frequency, not repeated first-requester denial of service; restart also resets ephemeral cooldown.

#### Lifecycle And Publication

- Candidate states are `pending → publishing → authorized`, or `pending/publishing → denied/cancelled`. UI acceptance starts publication; it is not itself authority. Recheck candidate identity, lifetime, active profile/bot, session generation, and exact current transport owner at the final commit boundary. Reuse the config owner's atomic existing-owner comparison; never clear or replace a configured account as part of pairing.
- The approval task owns fresh lifecycle/transport authority. It must not borrow an update execution fence, Workspace lease, or gate that ended when the triggering journal handler returned. No filesystem mutex, Workspace operation gate, or journal worker slot spans the dialog wait. Publication must use a reviewed lock order and a synchronous final ownership check/commit, without holding a filesystem lock across asynchronous work.
- Session replacement, shutdown, disconnect, profile/token change, or transport ownership loss cancels the pending dialog through its own AbortController. Late Yes, late UI failure, or stale notification cannot grant, restart, or mutate a successor candidate. A publication failure remains unpaired; retry needs a new request/approval. If publication may already have committed, inspect durable exact-owner evidence rather than issuing a second blind grant.
- Pending/UI state is ephemeral and never restored as consent. Do not use `pi.appendEntry`, model history, or a new shared sidecar as an authorization ledger. Any completion notice is best-effort, target/profile/generation-fenced, and outside journal-worker completion; notice failure cannot revoke a committed owner or replay old input.

#### Durable Admission Exclusion

The independent design review rejected a memory-only pending flag and approval-time backlog deletion: the worker already snapshots multiple entries before awaiting their execution. Instead, persist an immutable journal-owned `preApprovalExcluded` boolean with each newly admitted entry. It is a permanent execution veto, never a grant; `false` still requires ordinary current sender authorization. The candidate's triggering entry and every entry serialized into the journal while the exact persisted profile is unpaired receive `true`. Duplicate append preserves the original classification even if config has since changed. This metadata belongs beside `entry.update`, never inside caller-supplied Telegram payload fields.

The worker now requires a versioned snapshot and validates the complete exclusion evidence before reconstructing any queue authority. Missing v2 bits, malformed bits, unknown/missing versions, or excluded queued entries block the snapshot. Excluded executable entries bypass execution preparation, registered handlers, and default routing and proceed only to fenced journal settlement; a held snapshot retains its veto across an earlier handler's await. The durable polling adapter now prepares only contiguous non-excluded runs from the journal's `nonExcludedUpdateIds` result, synchronously after publication and before yielding to the local worker. Excluded positions remain boundaries, so filtering cannot invent a new comment/forward pair across them. The low-level poll loop no longer performs preparation. Failed publication performs no preparation; a preparation/diagnostic failure cannot withhold the wakeup of already-admitted work. Group plans remain ephemeral, not crash-restored journal authority. Candidate offering is still pending and may reach only a narrow path that checks the current unpaired state and exact local polling-owner authority. Only valid private human messages can offer a candidate; excluded edits, callbacks, reactions, deletions, and lifecycle/service payloads settle without their normal effects. After approval, excluded entries settle without execution or another dialog. Include the evidence in every worker snapshot/copy and preserve it across segments, compaction, retry, and restart. `markQueued` rejects excluded sources. Trusted internal events outside external journal admission retain their existing separate authority checks; they are not relabeled by Telegram payload fields.

This proves exclusion by **serialized durable admission**, not by network receipt time or the remote sender's clock. A fetched/buffered response admitted after the grant follows post-grant classification. No stronger promise about physically earlier sends is made. No new polling cursor, approval-time watermark, backlog purge, or cross-file grant ledger is introduced.

#### Transaction Order And Crash Boundaries

The inspected implementation offers synchronous journal append (`appendBatch` wraps its `runMutation`) and exact synchronous transport commit (`lockRuntime.commitIfOwned`). Config persistence queues a promise, so wrapping that promise-returning method in `commitIfOwned` would not protect its eventual write. The preparatory store now supplies `withPairingAdmission(profile, tokenSha256, publish)` for trusted synchronous publication under exact persisted config evidence and an optional per-call `commitIfOwned` port inside `persistAllowedUserId`'s queued write. A real lock-runtime regression proves the latter encloses the config rename and rejects an owner replaced before queue execution. New confirmation callers must require that guard; its omission preserves only the existing automatic first-contact path until integration. The observation seam is now exercised through opt-in journal admission; production adapters and UI remain disconnected. Do not await inside the observation callback or hold ownership while awaiting the persistence queue.

- Admission: acquire existing Workspace admission first; inside that operation acquire the config transaction, read exact persisted profile/token/owner evidence, then enter the journal transaction and atomically append entries plus their exclusion bits. Release both filesystem transactions before preparing groups or signaling the worker. After append returns, the durable polling adapter consumes the journal-owned non-excluded ID projection without an intervening await; moving preparation merely after an awaited append would race an already-draining local worker. The projection is not sender authorization. The config-owned observation callback wraps the synchronous append; it must not reacquire Workspace admission from inside config/journal locks.
- Approval: wait for UI and the config persistence queue without locks; then enter exact transport-owner transaction → config transaction → final candidate/session/profile/token/deadline checks → owner comparison → atomic config rename. The rename linearizes the grant. Use the same bounded transaction primitives; no UI, network, awaited operation, or diagnostics publication runs while these filesystem locks are held.
- Existing code has config-only publication, journal-only mutation, and short owner-fenced Thread/log/endpoint commits. Before activation, verify every added adapter preserves the proposed graph: Workspace admission precedes config; config may enter journal, never journal → config; owner-fenced grant may enter config, never config → owner. A source-level callback/lock-order inventory and contention tests are required, not inferred from the acyclic import graph. An isolated two-process config regression now holds the observation transaction while a separate grant process holds exact owner authority and waits for config; the observer sees exclusion, the grant completes only after release, and a later observation sees the disk owner despite a stale local cache. This proves the config/grant seam, not the still-unwired Workspace → config → journal composition.
- Before journal publication there is no durable admission. After excluded-entry publication, restart retains the veto. After Yes but before config rename there is no grant and consent is not restored. After rename but before local status/memory update the disk owner remains authoritative and old exclusions remain. An unknown publication outcome is reconciled through exact disk evidence; it never authorizes blind grant reissue or revocation.

#### Schema And Migration Gate

Preparatory storage protection is implemented independently of the future veto schema: snapshot and segment parsers classify unsupported integer versions before applying the current shape rules; recovery scans the retained files for unsupported versions before any repair/quarantine/reset, and non-corruption probe errors propagate. Receipt-scope and binding-key codecs use a separate fixed v1 identity version, verified by golden encodings. Production construction still uses v1. Explicitly supplying the synchronous `withPairingAdmission` store port selects v2: every persisted entry requires its immutable exclusion boolean, preserved through failure/retry, segments and compaction. Mixed queue receipts containing an excluded source fail atomically. V2 refuses legacy files, implicit identity rebinding, and corruption/missing-snapshot recovery without repair or reset; migration is not implemented.

The opt-in snapshot/segment schema v2 carries the mandatory boolean; v1 continues to reject that field. V2 append requires the existing admission cursor and suppresses absent IDs at or below its previously committed value, preventing a settled excluded entry from being re-admitted after approval. Segment replay rejects exclusion changes and below-cursor resurrection. This mode is for cursor-ordered polling only: do not enable it on out-of-order follower inboxes by inventing a maximum cursor. Their source-evidence/forwarding contract remains an integration gate. No second cursor or tombstone ledger is added. Separate the storage-schema version from stable receipt scopes, queue-owner identities, and journal-binding key codecs: those immutable recovery identities must not change merely because the file format changes. Missing/malformed evidence in the new schema fails closed, and unsupported versions must not enter automatic quarantine/reset as if they were disposable corruption.

Before starting a worker or enabling candidate grants, prepare its source under config → journal serialization with no surviving legacy worker snapshots. For an already configured polling profile, preserve existing accepted work and mark legacy entries non-excluded; current sender checks still apply. For an unpaired polling profile, stamp pending/retry legacy entries excluded. The proposed follower policy below instead blocks unpaired retained follower entries; it does not invent an ordered cursor for them. Unexpected queued/claimed/handoff authority in an unpaired legacy journal blocks migration and approval for explicit reconciliation; never silently discard or reinterpret it. Preserve revisions, update IDs, cursor, receipts, owner births/generations, failures, and handoff evidence. A failed migration does not start a worker or UI candidate. Regression tests must prove the unchanged identity codecs and guarded startup ordering.

Automatic approval stays disconnected until schema/migration, lock-order, and worker-copy proofs pass. Mixed-version owners/consumers and downgrade remain an explicit rollout gate: do not imply that an older runtime understands the new veto or human-approval requirement. No running instances or live journals are migrated by this design work.

#### Follower Source Policy Candidate

**Reviewed design; not implemented or activated.** Keep cursor-ordered polling on v2 and out-of-order follower inboxes on v1. This is narrower than adding another storage mode or consent ledger: excluded polling entries must never reach forwarding, while new follower admission must require an already persisted exact user owner. Retained unpaired follower work is a reconciliation gate, not permission to discard it.

The config prerequisite is implemented as `withPairedUserAdmission(profile, tokenSha256, userId, publish, assertExecutionCurrent?)`: it returns explicit denial for an absent/different owner or invalid sender ID, observes exact persisted authority under config transaction, and refreshes an unpaired cache before the trusted synchronous callback without writing config. Changed local profile/token, a conflicting cached owner, or an unpublished local unpair refuses instead of silently switching authority. Default/named-profile tests cover peer grants, queued settings and local edits, stale guards, rejected publication, and unchanged config bytes. Combined interleavings also cover local unpair after observation and external revocation before queued completion, including a subsequent save that must not recreate the owner. This method is exercised by isolated journal and receiver tests, not by production follower factories, and does not replace receiver provenance or publication-time fences.

The journal prerequisite now exists as the optional `withPairedAdmission` port. It preserves v1 and runs after Workspace admission but before journal locking or recovery-capable reads; explicit denial becomes `sender-denied` without publication. Inputs are normalized once before deriving Workspace scopes, checking sender authority and persisting the same canonical data. The paired-only port and v2 exclusion port are mutually exclusive. Tests prove peer-grant cache refresh, `20 → 10` admission without a cursor, duplicate preservation, canonical-input scope consistency, and guard release after denial/stale context/publication failure. This guards append only: production wiring and startup/read/recovery consumers remain separate cutover work.

`createTelegramBusFollowerPairedAdmission()` binds the config port to the journal hook for one canonical message/edit/callback/reaction carrier with an exact source ID. It selects message/edit/callback `from` or reaction `user`, requires a positive safe ID and explicit `is_bot: false`, and rejects defined `sender_chat`/`actor_chat`, ambiguous carriers and invalid grouping metadata. Original forwarding authors and callback-message authors do not authorize the sender. Bot API evidence: [`User`](../.agents/skills/telegram-bot/api.md#user) requires the boolean flag; [`Message`](../.agents/skills/telegram-bot/api.md#message) may expose a fake `from` for chat senders, while [`CallbackQuery`](../.agents/skills/telegram-bot/api.md#callbackquery) and [`MessageReactionUpdated`](../.agents/skills/telegram-bot/api.md#messagereactionupdated) identify the acting user separately. An isolated real IPC receiver/config/journal composition proves provenance checks precede config admission, peer grants refresh the receiver cache, all four kinds survive unordered v1 delivery, and denial/staleness/publication failure does not append or wake the worker. Wakeup follows guard release; config bytes remain unchanged. The required execution assertion and publication-boundary fences remain caller-owned; the helper does not capture or invent receiver lifetime authority.

The source constraints are concrete. `createTelegramBusFollowerDurableAdmissionRuntime()` appends each authenticated delivery without a cursor; its receiver checks secret, registration generation, recipient binding and source ID, but production journal factories do not yet select the paired-only port. A synthetic store witness admits IDs `20 → 10` into v1 and retains both; substituting cursor-ordered v2 with a fabricated maximum cursor suppresses `10`. The lifecycle's `bind()` currently constructs the worker, resumes terminal entries, and performs dead-owner cleanup before `worker.start()`, so checking migration only at `start()` is too late.

- **New deliveries:** Preserve transport authentication, exact generation/binding/delivery identity and current-session checks. Before append, acquire Workspace admission → config transaction (sender authority) → journal source serialization → journal transaction. A config-owned paired-only seam must confirm the envelope sender is the exact persisted owner of the expected profile/token and refresh that authority in the receiving process before worker signaling. It must never create an owner. Boolean "profile is paired" alone is insufficient; a follower cache loaded before another process's grant may still be unpaired. The guard belongs inside the journal's already-Workspace-admitted synchronous append path, not around public `appendBatch()` or async `admit()`: those wrappers would reacquire Workspace under config or span the wrong boundary. Release these admission/transaction guards before worker signaling and ACK. The existing polling observation port selects v2, so neither it nor the automatic first-contact publisher substitutes for a paired-only v1 seam.
- **Source guarantee:** Only the updated leader's exclusion-gated, sender-authorized path may forward content. Followers cannot offer pairing candidates. Bind this contract to the negotiated producer/consumer capability and exact registration; an envelope assertion is not consent. Do not advertise the capability while using an ungated producer or receiver. Mixed/old runtimes remain an operator-coordinated activation prohibition, not a software-enforced downgrade claim.
- **Legacy followers:** A configured profile preserves validated v1 accepted work, receipts, births/generations and handoffs without a schema rewrite. If the profile is unpaired, any retained follower source entry—pending, retry, terminal or queued—blocks source startup and a new UI grant until exact operator-authorized reconciliation. Preserve bytes; do not auto-clear, quarantine, assign a maximum cursor, or silently relabel the work. This deliberately narrows automatic legacy migration. Reconcile such state before manual preconfiguration too; no retroactive consent guarantee is inferred from an operator editing the config file.
- **Readiness and migration:** Use complete, bounded, strict read-only inspection of the current profile's polling journal and discovered follower snapshots/segments, not recovery-capable `read()` as a preflight. Unknown identity, unreadable/corrupt evidence or incomplete inventory blocks readiness. Stop and await the old local worker, then re-resolve/revalidate profile/token/registration binding before preparation; the binding captured before the await cannot authorize successor startup. Place preparation before worker construction, terminal retry, queue-owner cleanup and handoff consumers, and publish lifecycle availability only after it succeeds. Also cover non-worker readers: Workspace journal protection capture currently calls recovery-capable `read()` and must not repair/reset evidence ahead of readiness. Discovery alone is insufficient: strict inspection must reject symlinks/unknown identities, bound the inventory, and close namespace creation, recovery and handoff paths through journal source serialization or explicit quiescence. Operator-coordinated quiescence of other legacy consumers remains necessary. Preserve fixed recovery identities; no "ready" sidecar or cached boolean grants authority.
- **Final grant:** Recheck source readiness inside the queued publication's existing config transaction, under exact transport ownership, only when creating a previously absent owner. New paired follower writers must use the same config admission. The check cannot reacquire config or await; journal locks follow config. Recheck candidate/session/profile/token/deadline immediately before rename after inspection. A startup-only inventory or checks outside that transaction do not close the append/grant race.

Required witnesses before accepting this policy: out-of-order first deliveries survive; a legitimate forwarded message after a peer grant refreshes a stale follower cache without writing a grant; unpaired/different-owner/stale-generation admission has no publication or wakeup; unpaired retained follower data survives restart and blocks UI publication; configured legacy receipts remain intact; preparation precedes every recovery consumer; inventory/append/grant contention cannot produce a ready-but-unexcluded path. If these cannot be proved without another durable authority, reopen the source design rather than widening v2 by assumption.

#### Strict Journal Inspection Candidate

**The isolated reader and local implementation review are complete; it has no production consumer and is not activated.** `inspectTelegramUpdateJournalFamily({ directory, path, profile, botIdentity, limits })` returns absence or a validated file plus file/byte/work accounting. Its optional `knownBotId` result is a validation constraint, possibly inherited from the caller, not enrichment of the stored identity. It requires canonical paths and available `O_NOFOLLOW`/`O_NONBLOCK` flags, refusing unsupported platforms rather than weakening acquisition. Linux fixtures cover metadata, resource and mutation boundaries; canonicalized fixture roots also pass with a symlink-backed temp directory. On unavailable open flags, tests assert refusal and unchanged evidence instead of expecting successful decoding, with an explicit coverage diagnostic. Synthetic load-time variants cover each missing flag and both together; these are not native Windows or whole-profile readiness evidence. Isolated filesystem probes establish why wrapping the ordinary reader is insufficient: reading an empty foreign-profile journal rewrites its identity; revisioned snapshots skip redundant retained segments even when those segments declare an unsupported schema; follower discovery follows canonical snapshot symlinks outside the scanned directory. Source inspection also shows unbounded `readdirSync()` allocation and separate snapshot/unapplied-segment byte budgets. These are counterexamples to reuse as strict preflight, not evidence that normal legacy recovery has changed.

- `Owner and result`: Keep the inspector in `journal`, reuse its schema/entry/receipt validators, and extract shared pure replay only when needed. Inspect one exact journal family first; profile inventory is a later caller. Return validated evidence or absence, not permission, a cached ready flag, or a synthesized empty journal. Do not call `read()`, the current `readCurrentStrict()` closure, recovery, identity rebinding, compaction, publication, or lock-file creation from the inspector.
- `Acquisition`: Accept an approved canonical directory anchor, a journal path within it, expected profile/token identity, and explicit positive safe-integer file-count, aggregate-byte, per-collection/state-entry and aggregate-work limits. Bound directory enumeration before collecting/sorting names, including ignored entries and a bounded overflow witness. Open only regular non-symlink files; reject linked path components beneath the anchor, unexpected segment entries, wrong types, uncertain absence, and observable namespace/handle changes. Read bounded bytes from the opened handle, reject invalid UTF-8, and count snapshot plus every retained segment against one aggregate budget before parsing. A size check followed by unbounded `readFileSync(path)` is insufficient.
- `Schema and identity`: Recognize only supported v1/v2 snapshots, validate every retained segment including revisions covered by the snapshot, and require exact profile/token identity without empty-file rebinding or same-bot token substitution. Maintain one validation-only known bot-ID constraint across expected identity, snapshot and every segment, including redundant segments: two conflicting known IDs fail even when the snapshot omits that field. Preserve the stored snapshot identity; a missing optional bot ID cannot cause identity enrichment. Unknown, mixed, malformed, or incomplete evidence fails closed with bytes untouched. Existing deterministic legacy failure-ID projection may remain a decoder behavior; it does not authorize a rewrite or new recovery identity.
- `Replay`: Start only from a validated snapshot; a retained segment directory without a snapshot is not empty-source proof. Validate filenames, matching revisions, intrinsic `previousRevision === revision - 1`, and unique disposition failure IDs for every segment, but do not demand a complete historical chain below the snapshot. Apply only the contiguous newer chain (`revision === currentRevision + 1`), preserving cursor, revisions, receipts, owners, births/generations, failure/handoff metadata and v2 immutable exclusion checks. Bound raw `entries`, `upsertedEntries`, `removedUpdateIds` and `operatorDispositions` before invoking codecs; also bound reconstructed entries/dispositions. Charge aggregate work for raw collection validation and repeated reconstructed-state validation so small deltas cannot hide excessive replay work. Avoid argument-spread maxima; positive caller limits are not an engine argument-count guarantee. Never infer a polling cursor from follower IDs or repair a gap.
- `Serialization boundary`: The caller owns Workspace/config/journal ordering and must establish writer quiescence or the corresponding existing transaction before consuming evidence. Stable metadata checks and repeat enumeration detect some changes; they do not defeat hostile same-user path substitution or prove namespace closure. Do not hold a filesystem mutex across an await. Profile discovery, namespace creation, recovery and handoff writers must be audited before final grant can use this reader; ignored/archive storage needs proof that it cannot feed an automatic consumer, not an assumption based on its name.
- `Migration boundary`: Rejecting mixed schemas is initially safe but is not a crash-complete migration protocol. A v2 snapshot followed by interrupted cleanup of older v1 segments needs a separately proven reconciliation rule before activation. Do not add a sidecar, remove uncertain segments, or claim downgrade safety to bypass that gate.
- `Proof cohort`: Exercise v1/v2 current and legacy metadata, exact empty-identity rejection, redundant unsupported/mixed segments, revision gaps, missing snapshots, symlinks/wrong types, aggregate size/count/entry overflow, and unchanged tree bytes on every outcome. Fault injection must distinguish detectable concurrent changes from guaranteed serialization. Native Windows/path behavior, complete profile inventory and grant-time contention remain separate evidence gates. The retained single-family reader has no consumer or production wiring; its tests do not establish writer quiescence.

#### Canonical Profile Journal Inventory

`inspectTelegramProfileJournalNamespace()` inventories only the legacy flat polling/follower namespace using the strict family reader; its isolated implementation review is complete. It refuses any `sessions` entry rather than silently certifying the new namespace. Active followers use `sessions/<id>/journal.<recipient hash>[.<profile>].json`. `inspectTelegramSessionJournalNamespace()` shares the same inspection kernel and adds the canonical session tree alongside polling and retained flat recipients; session families have the role-neutral `session` source label. Its read-only native tests cover shared limits, foreign non-reading and post-inspection nested-file changes. Candidate Workspace protection now invokes this strict evidence surface on each capture, even for a binding whose recorded sources are complete, and uses its bounded catalog for discovered current-profile readers. Invalid/incomplete evidence or missing discovered-path resolution yields unknown accepted-work protection. Native tests preserve every source byte, scoped read references and freshness after a later corruption. No tuple pruning or filesystem cleanup is enabled by this integration; private-retention classification, external consumer references and writer closure remain gates. Retention now participates in the shared census and file/byte/work accounting. Every original is classified against its exact journal; protection refuses uncommitted copies or missing committed originals instead of guessing cancellation. A retained-only family without its exact v1 snapshot remains unknown. Committed originals remain preserved and independently reference-audited; classifying them is not permission to erase history. It returns deterministic source roles/paths/evidence, shared accounting and a validation-only bot-ID constraint. Tests cover exact aggregate boundaries, unread foreign contents, segment-only cross-family conflicts and root changes after the last family inspection. It does not certify consumer-reference closure or authorize a grant, migration, cleanup, or startup.

- `Names and scope`: The legacy inventory covers `inbox[.<profile>].json` and `follower-inbox-<16 lowercase hex>[.<profile>].json` paths plus their `.segments` directories. Supported profile namespace components are the current lowercase ASCII alphanumeric names of at most 32 characters; `default` has no suffix. Treat any case-insensitive `inbox` substring as journal-like, even in otherwise unrelated names such as `personal-inbox-notes.txt`. Reject noncanonical aliases, malformed journal-like names, journal-shaped symlinks/wrong types, and sanitizing profile names rather than guessing ownership. Canonically distinct foreign-profile names can be classified without reading their contents; count them and unrelated entries against the directory limit. Never infer a Workspace binding or allocation authority from a filename hash.
- `Inventory and limits`: Stream a bounded root census before inspecting families, deduplicate snapshot/segment pairs, always inspect the polling path (including absence), and inspect current-profile follower paths deterministically. Share file/byte/work budgets across families rather than resetting each call. Keep the family collection/state ceiling; inventory work charges at least one unit per family visit, including absence, and otherwise the family's decoded/revalidated collection count. Reject exhaustion before another visit. Re-enumerate within the same root-entry bound and reject observable namespace changes; missing discovered families cannot silently become empty evidence. The legacy census compares metadata for every root entry, including unrelated and foreign files. The session-aware census additionally covers session folders, their leaves and every segment/private-original entry, including foreign-profile metadata without opening foreign contents. Directory accounting spans the entire observed tree; each recensus has the same whole-tree ceiling. Observable nested segment edits, new sessions and foreign-file metadata changes also invalidate the result. Operational quiescence must cover this whole observed root, not merely current-profile journal writers. Return source roles, paths, validated evidence and accounting, not a ready flag or partial success.
- `Cross-family identity`: Carry the validation-only known bot-ID constraint across families as well as across each family's retained files. The family reader may expose that constraint separately from its unchanged snapshot identity; do not enrich stored identities or recovery keys. This must catch contradictory IDs present only in segments while both snapshots omit the field.
- `Private retention`: `inspectTelegramUpdateJournalRetention()` is a separate read-only evidence surface over one exact v1 journal family and its `.retained` originals, using the existing no-follow bounded acquisition kernel. It validates canonical `abandon-<sha256>.json` names, the full private envelope, known journal identity, entry/disposition digest, unique source IDs and exact committed discard tombstones. No tombstone means `uncommitted`, even when the journal entry is absent; a copy alone never proves cancellation. Contradictory/foreign/damaged/linked evidence or a missing snapshot refuses classification. Reads and recensus share aggregate file/byte/work limits with the snapshot/segments. The session-aware whole-namespace guard now consumes this classification and returns original-preservation facts separately from executable entries. Reverse tombstone-to-original checks reject missing copies; a valid copy without commit stays `uncommitted` and blocks protection clearance. This does not authorize replay, deletion or writer closure; the legacy flat-only inventory continues to refuse private-retention directories.
- `Archive consumers`: The source audit finds no replay reader of private originals. `updates` invokes `inspectPendingRetention` before dispatch and holds copied/unverifiable pending inputs as `abandoning`; fresh cancellation uses the same copy for exact retry. `extension` retains `inspectAbandonedPending` under an operator-disposition reference for routing. `routing` uses that committed proof to settle an unsent Restore and rechecks every cancelled group before temporary-tab cleanup. A cold `inspectAbandonedPending` still reads the original even after executable entries are gone. Therefore its exact journal tombstone is a continuing durable dependency, not evidence that the archive is disposable. Retention inspection returns the validated original `journalBindingKey` and `failureId` alongside its path/update ID; callers must not reconstruct these from the current session, filename hash or a changed bot identity. This audit does not close arbitrary out-of-namespace references or writer lifetimes, and does not permit dropping tombstones or originals.
- `Unclassified storage`: A `recovery` entry initially blocks this inventory without archive traversal. Unknown journal-shaped temporary/legacy residue also blocks. Relaxation requires an audited proof of non-consumption or separately authorized reconciliation, not treating a directory name as permission to ignore accepted work. Arbitrary/out-of-namespace durable consumer references remain a separate mandatory reconciliation gate; a canonical directory census alone cannot establish their absence.
- `Integration boundary`: Neither strict inventory is a production recipient selector or authorizes session-file cleanup. Production uses exact session recipients and combined discovery without claiming strict namespace closure. Caller-proven serialization/quiescence remains mandatory; repeated metadata/census checks do not defeat hostile same-user substitutions. Tests must cover exact shared-budget boundaries, default/named namespaces, foreign-file non-reading, ambiguous names/types/links, absent and orphaned families, hidden cross-family ID conflicts, observable census changes, unchanged evidence, and unsupported-platform refusal. Reader/writer closure and final grant-time contention follow only after this evidence layer is independently reviewed.

#### Source Closure Audit Boundaries

Source audit confirms that canonical inventory is not yet usable as a production readiness check:

- `Profile path correction`: Historical production wiring passed `(agentDir?, profileName?)` resolvers directly to profile-only ports, allowing a named profile to become a relative `<profile>/tmp/pi-telegram/` root. The authorized bounded inventory inspected every current and retained historical CWD hint for exact candidates using the sole configured/retained `default` profile; no defective-path source existed. The canonical root's 30 v1 families were inspected without repair and retain five queued source records in two follower families, so they remain migration authority rather than empty-state evidence. Production now uses dedicated profile-only polling/admission resolvers that bind `resolveAgentDir()` and produce canonical suffixed paths; a composition invariant rejects the old callback shape. The isolated two-CWD fixture remains as historical counterexample evidence and preserves its queued work and leases. This correction does not establish writer exclusion, migrate canonical v1 custody or activate prepared v3 consumers.
- `Prepared reference preflight`: `paths.requireTelegramStoragePathReference(selected, approved)` returns only an already absolute, normalized, exactly matching spelling; relative paths, traversal aliases and different resource/profile paths throw without filesystem access or normalization of the returned reference. The approved path must come from independent caller authority. A corrected resolver output is not evidence that historical references were reconciled. This lexical check proves neither physical identity nor consumer/writer closure, and it does not authorize migration. Production uses the corrected profile-only resolvers. `Storage reference preparation` in `tests/integration.test.ts` reconstructs the historical callback shape only in a disposable fixture: default-profile publication still works, named leader/admission resolution refuses before mutation, and correct follower/recipient paths cannot bypass a mismatched admission location. All fixture files, segments, receipts, leases and directory names remain unchanged after refusal. The no-op-guard negative control fails both this composition test and the mirrored path test. The completed inventory found no defective-path source in the identified scope; moving canonical v1 storage and activating consumers remain separate gates.
- `Reference coverage`: Inspected receipt/handoff callers select exact active lifecycle bindings rather than opening arbitrary receipt-supplied paths. Historical Workspace keys feed the canonical follower-path hasher; arbitrary path resolver wiring currently receives ordinary discovery results. No automatic reader of quarantined journal contents was found. Provision-recovery metadata and follower state hints do have automatic readers, but do not replay journal entries. None of these observations authorizes relaxing recovery refusal or proves live-reference completeness.
- `Coordinator reference roots`: Current Workspace bindings are not the only address owners. Retirement intents retain an exact `binding`; Restore operations retain `request.binding` independently of the relocated current binding plus an opaque source journal key and routing acceptance/settlement facts. Temporary tabs retain source keys in membership and cancellation/completion/issuance groups. Terminal membership is not permission to drop the underlying cold proof. Normalized snapshot cloning preserves exact session tuples in these independent roots. Metadata pruning of one current binding therefore cannot establish reference closure across the coordinator. Production abandonment, completion and queued-receipt proof adapters now follow the exact source journal key, not the active session. Historical receipt observation does not acquire readiness; matching durable completion is terminal evidence, while absence, another owner or an offered receipt is not. Actual `/new` and session-boundary lost-reply lifecycle reconciliation remain separate acceptance gates.
- `Historical journal proof lookup`: The binding runtime exposes narrow `inspectSourceAbandonment`, `inspectSourceCompletion` and `inspectQueuedReceipt` observations by exact journal key, not a historical store or execution port. Completion and whole unoffered receipt matching reuse the ordinary store's private validators/matchers rather than introducing a second proof dialect. It requires a canonical serialized key with the current profile/bot receipt scope and a polling, retained flat or canonical session filename beneath the approved polling root. Exact token-scope originals can remain inspectable after bot-ID discovery. Strict bounded no-follow retention acquisition validates the snapshot, tombstone and original; missing, linked or damaged evidence refuses rather than recovering. Cooperating source serialization surrounds the read, and profile/token/bot/root agreement is rechecked before and after acquisition and after serialization release. `routing` supplies each original group's key; `extension` owns its scoped operator-disposition reference. Native session-switch witnesses use the same recipient hash and update ID in both sessions, proving old cancellation without reading successor custody or publishing active readiness. Prompt/control native fixtures additionally preserve same-hash/same-update-ID/same-receipt-name successor custody, reject wrong owners, partial groups and offers, and inspect durable completion after a caller loses its disposal reply. Returned proof mutation cannot alter the source. This grants neither replay nor cleanup/writer closure.
- `Prepared address CAS`: `commitWorkspaceJournalEvidence` accepts an optional exact `journalSources` subset. Omission preserves tuples for every existing production caller. Supplied metadata must be a bounded canonical subset of the exact expected binding; additions, malformed records and stale expected snapshots refuse without partially updating legacy keys/completeness. The native persisted/cold Restore fixture demonstrates that current-binding pruning leaves the independent saved Restore addresses intact. This is only an in-memory metadata CAS followed by existing persistence, not a filesystem grant, all-writer transaction or reference-closure proof. No production caller yet supplies a subset; tuple-aware removal and physical cleanup remain gated.
- `Consumer ordering`: Replacement now snapshots originating runtime/recovery key values before awaited shutdown, rejects changed/missing bindings afterward, and uses a fresh matching descriptor before worker construction or recovery reads. Startup replacement and forced transport replacement have held-stop regressions, an old-code negative control and independent mutable-descriptor probes. Legacy same-key reuse without replacement remains unchanged; matching keys alone do not establish session/registration lifetime or compatibility of captured worker dependencies. Terminal retry and dead-owner cleanup precede worker start. Status and polling bootstrap also use recovery-capable reads. Workspace protection is now consumed by demand-driven slot rotation and uses a strict non-repairing binding reader rather than ordinary recovery-capable `read()`. Source-readiness and migration consumers retain their separate gates.
- `Quiescence gaps`: Worker stop aborts/awaits draining but can leave unsettled handlers. Config append guards do not serialize other journal mutations or recovery. Whole-root churn also includes transaction staging before acquisition, state staging before owner-fenced rename, logs, admission ledgers, recovery metadata and endpoints. Holding config or owners alone does not quiesce that root. A journal transaction itself creates an `inbox`-containing name rejected by inventory, so acquiring journal locks and then invoking this census is not a supported composition. Metadata stability cannot protect an unguarded interval through grant publication.
- `Prepared worker source lifetime`: A native config/journal/lifecycle fixture reproduced fresh maintenance reads followed by an old worker's revoked input context, blocking the next input despite unchanged source/runtime keys. The gated v3 resolver now keeps one narrow worker port per actual store handle in a `WeakMap`. Lifecycle snapshots the custody port captured at worker construction: renewing it triggers stop, fresh post-stop binding validation and worker replacement even with equal string keys or an in-place descriptor update. Repeated descriptors over the same store still reuse compatible dependencies; legacy bindings remain unchanged. No persistent key, schema, capability or production activation changed. Native leader-restart and active-follower tests cover renewal and stable reuse; a held-handler fixture preserves the exact durable `running` claim while independent input progresses, then rejects the cancelled origin's late effect. Negative controls prove both captured identity and stable per-store port reuse are required. This is source-handle freshness, not proof of arbitrary callback validity or global readiness; renewed callable lifetimes require a fresh store handle rather than in-place rewriting of its methods.
- `Prepared donor receipt projection`: Native temporary config, Workspace admission, v3 store, lifecycle and real queue binding reproduced control effects from stale donor readiness after offer, transfer or discard while raw transport authority was lost. The strict worker port now observes the complete source-ID group, kind, exact queued owner/acquisition and absence of an offer at readiness/owner lookup. It can only restrict an already retained receipt, never adopt a new one. Unavailable observation fails closed without repair or removing local work; unchanged/cancelled ownership and a later successful observation remain usable without transport reacquisition. Native grouped-receipt fixtures cover another store handle mutating without a wake, unrelated accepted work, late prompt revocation and lost completion ACKs. Three isolated loader controls establish the need for current observation, explicit completion acknowledgement and confirmed local cleanup. The shared [settlement contract](#queue-and-dispatch-safety) preserves acknowledged prompt cleanup before `agent_start`; a late CAS refusal cannot undo an earlier control effect. Production still uses legacy bindings, without this observation port. These are point-of-use observations, not a lock spanning every later effect, proof of all writers/consumers, multi-journal atomic completion, live acceptance or performance evidence.
- `Prepared pending mutations`: Native config/Workspace/v3/lifecycle/queue composition now proves accepted independent work progresses after transport loss while a governing reaction is pending or held in its actual handler. Successful Skip settles without a model turn; a failed running mutation stays outcome-unknown, blocks only the governed item and is not replayed. The fixture exposed a genuine lost wake: an older blocked drain result erased a newer signal after accepted-work completion. The worker now consumes newer wakes within the same drain run, preserving `waitForDrain`; signals preceding a later write failure cannot clear its latch or cause hot retry. Business-deletion probes also reproduced both wrong-namespace durable removal and memory-only removal after discard failure. Bot API `Message.business_connection_id` and `BusinessMessagesDeleted` establish that even equal chat/message IDs do not identify bot-chat work, so default routing now ignores this carrier rather than manufacturing deletion intent. Raw handlers remain usable. Independent loader controls falsify the namespace and wake fixes. These are native disposable composition results, not live Business/Telegram or Windows acceptance.
- `Immutable pending-mutation exclusion`: The native fixture reproduced a permanently excluded reaction stranding already accepted work after transport loss. The dependency scan now ignores only `preApprovalExcluded === true`; missing legacy evidence and explicit false remain protective. Real config unpairing establishes the veto, and re-pairing, duplicate append and reopening do not remove it. Both accepted prompts dispatch through the actual queue binding while transport remains unavailable; the excluded entry stays identical and no reaction handler runs. A loader control restoring the old scan fails both unpaired and re-paired cases. Observation does not dispose of excluded input or establish general source readiness.
- `Preparation prerequisites`: Reuse the completed native prerequisites; an unprepared source's read refusal is not permission to recover during queue preflight. The common worker's `removeCompleted` slot now delegates to `removeExcluded` only in the prepared v3 port. Native restoration and shutdown/restart cases drain the retained pending exclusion without executing its reaction or replaying accepted prompts, retaining the admission cursor. The journal owner rejects mixed excluded/non-excluded requests atomically; adapter checks preserve unclaimed, ready, running, queued and offered work. Queue/failure mutation stays forbidden. This is not generic raw completion, retry-quarantine disposition or production activation; existing strict exclusion-removal failure/replay-barrier tests remain authoritative. A native queue-binding call after worker shutdown exposed an unleased pending-mutation read of the retained source. Lifecycle now snapshots its reference binding and scopes pending-mutation/count reads when the long-lived reference is absent; active reads reuse it. Acquisition refusal occurs before I/O, and read failure releases the temporary reference without clearing accepted work. Stopped receipt readiness/owner projection reads nothing and cannot restore execution. The real registry/queue fixture covers stop, failure, capacity denial, restart, transport loss and forgotten-source refusal; a loader control removing the scoped reference fails. This tracks participating observation, not callable renewal or global writer exclusion. The donor handoff coordinator supplies a concrete retained mutation caller: its remote stage can reject after lifecycle shutdown, then attempt cancellation. That synchronous cancellation now uses the same scoped reference mechanism before the existing exact journal CAS; it does not reactivate the worker. Native tests hold the remote promise across shutdown and prove cancellation with original custody, denial before mutation at reference capacity, and failed cancellation after real recipient acceptance/lost ACK. Donor memory and recipient ownership survive; the latter case verifies that the native CAS was reached rather than mistaking a swallowed test assertion for refusal. A loader restoring unscoped cancellation fails all three cases. Forwarded durable admission and recipient acceptance have no await before their initial mutation. A separate native registration counterexample established the startup gap: a real prior-generation handler holds worker replacement while real local IPC registration publishes its generation; the receiver previously ACKed delivery into the retained old journal. The follower assembly now exposes inbound generation only after `onRegistered` succeeds for that exact generation and current context. Registration state itself remains available to prepare the worker. Native tests prove early refusal, old/new journal preservation, retry into the new binding after release, context-replaced refusal and failed-preparation refusal. Loader controls independently falsify early-publication and context checks. This is local IPC/lifecycle evidence, not live Telegram or native-Windows acceptance. The deferred media producer has additional native config/v3/lifecycle/media-group/turn-preparer/enqueue evidence using the execution-guard wiring supplied by `routing`: an active delayed attachment creates one queued receipt under a held reference; clearing groups and stopping the worker while preparation is held makes the existing post-await enqueue fence refuse before memory append, queued report or custody mutation. The exact running record remains unchanged. Removing that fence through an isolated loader falsifies the stopped case. No extra callback authority or reference reacquisition was added. A separate native paired-runtime denial witness confirmed that a reply returning after worker shutdown could previously default to complete and remove the running source without a reference. Admission now rechecks the shared execution fence after `defaultHandle` returns, before exposing any outcome to the custody session. Active denial completes once under the live reference; an interrupted denial makes no completion attempt, retains its exact running record, and is not replayed on restart while unrelated accepted prompts still dispatch after transport loss. A loader removing the new check reproduces the durable removal. This closes composed default-handler return, not every standalone session/report consumer. Same-generation follower refresh has separate native IPC evidence: after lifecycle shutdown, both a new context object and a reused object with an advanced session generation previously admitted into a stopped worker, and `setContext` did not reprepare it. The assembly's ready proof now binds registration generation, context and the supplied Pi session generation, checked on every inbound generation lookup. Its async `setContext` delegates heartbeat context publication and reuses binding preparation when that proof is stale; the refresh hook awaits it without changing bus membership. Failed preparation remains unready, is diagnostic rather than a thrown session-start failure, and can be retried. Native cases prove early refusal, unchanged journal, same registration generation and subsequent processing with the refreshed context, including failure/retry. Independent generation/preparation loader controls fail. Production supplies the context/session-generation ports; standalone callers without them retain their caller-owned lifecycle contracts. Initial/re-registration now captures Pi session generation before receiver startup and retains one local attempt identity. Checks after startup, RPC, preparation and first heartbeat refuse expired work; stop and a changed-context refresh invalidate the attempt. Owned stale cleanup clears only that request's local authority, never a newer attempt. Native local-IPC cases reproduce and fence response-time session drift on a reused object, startup-time drift, stop, overlapping newer registration and refresh during the initial heartbeat; stable registration and a fresh retry still succeed. Independent controls falsify session, attempt and refreshed-owner protection. This is client request authority, not remote provisioning rollback or global consumer/writer closure. The actual control-handoff reconciler now consumes the coordinator's already-serialized payload and changes only its destination journal binding; it no longer clones a live control's `execute` function. Native v3 config/journal, reconciler, wire-codec, recipient staging and queue-dispatch composition verifies one recipient-local execution and no model turn, rejection with original donor custody, and a lost post-acceptance ACK retaining donor memory without another transfer or effect. Restoring the old whole-item clone falsifies all three cases. This closes the concrete serialization blocker, not production legacy-copy replay, global physical-reference/writer closure, historical migration or live acceptance. Further cutover work requires its operator-authorized inventory and activation evidence. Preserve exact cancellation/settlement authority and actual unsettled-handler barriers. Source inspection/grant wiring remains disconnected.

#### Source Operation Serialization

`Journal.createTelegramJournalSourceSerialization()` is the journal-owned lock-only source serializer at `tmp/pi-telegram/runtime/journals.transaction`; it never touches `telegram.json` or its transaction. Tests cover callback result/error preservation, release/retry, an unchanged (even unreadable) config, and that holding it never blocks pairing observation, paired admission or owner-fenced grant in another process. It reads no config, validates no profile/token/sender, and exposes no lock capability. The callback's own result is not authority. Acquire required Workspace admission and any sender (config) admission first; never acquire owners inside it. Promise-returning callbacks are outside the contract: their continuations run after lock release, not as protected asynchronous transactions.

The opt-in journal-store composition now separates continuations rather than adding a second prepared-worker projection. Independent review covers all 12 stateful methods, source-callback rejection before journal locking/read/recovery, actual contention, publication-failure release/retry and unchanged receipt CAS:

- `Append`: Canonicalize once → Workspace admission → choose polling observation or paired-human admission → private journal transaction. Without a sender-admission mode, use the lock-only continuation when configured. Do not wrap an admission callback in another config transaction.
- `Other store operations`: Lock-only journal source serialization → opt-in `sourceAccess` family acquisition → private journal transaction → direct consumption of that operation-local evidence. The same ordering applies after append's selected admission continuation. Acquiring before journal staging is valid only when source serialization excludes all participating family writers through consumption. Without `sourceAccess`, ordinary recovery-capable `readCurrent()` remains unchanged. Ordinary `read()` is optimistic: it first runs the same strict, repair-free evidence read without config or journal guards, because atomic publication makes it safe; only a refused or reconciliation-requiring read retries once through this serialized path, which owns repair. Receipt/owner/handoff CAS and process-birth proof stay authoritative; no caller-supplied lock-held bypass or ambient reentrancy depth is exposed.
- `Resource binding`: Participating continuations must use the same actual config resource. Arbitrary injected callbacks cannot prove that themselves; real factory/operation tests must establish one acquisition per operation. The dispatcher is implemented and locally reviewed. `sourceAccess` requires the lock-only continuation and captures an independently approved directory plus physical inspection limits; its store integration is independently reviewed, including generated-state refusal remediation. Production wiring remains absent.
- `Evidence`: Real isolated probes show an outer observation plus existing admitted append times out on nested config acquisition. Current-token admission can reject an otherwise valid old-source receipt completion after token rotation; a lock-only transaction still permits exact receipt CAS while rejecting a wrong acquisition ID. Current observation also permits profile-switch/revocation cases, so it is not a lifetime fence. A journal `read()` can repair an empty foreign snapshot while another process holds config, proving append-only coverage is insufficient. These are storage/order witnesses, not permission for obsolete handlers to execute.
- `Remaining gates`: Serialization does not provide exact reference reconciliation, old-token migration policy, settled-handler or legacy-snapshot barriers, executable receipt freshness, whole-root quiescence, all-writer closure or final-grant readiness. The whole-root census cannot run inside a journal transaction. Final grant requires an internal already-in-config-transaction check, not reacquisition of this wrapper. Production stores, inspectors and UI remain disconnected from this candidate.

#### Production Journal Reference Inventory

The current composition has one factory owner: `createTelegramUpdateJournalBindingRuntime()` in `lib/extension.ts`, and it always constructs the legacy `createTelegramUpdateJournalStore()`. Its leader resolver is retained by lifecycle worker assembly, Workspace retirement protection, polling offset reads/cutover, and bootstrap entry inspection. Its follower resolver is retained by follower lifecycle assembly. Recipient/path resolver factories are retained by Workspace retirement discovery and queue-handoff reconciliation. These are readers and/or writers sharing dynamically selected profile paths; none exposes a close acknowledgement, and resolver creation itself is not a lifetime lease.

This inventory closes only repository-visible production composition references. It does not prove external package callers, old running builds, arbitrary injected resolvers, or historical path consumers are absent. Consequently no component may mint `writer-exclusion: excluded` yet. Closure requires explicit lifecycle-owned reference registration/release for each listed class plus mixed-version process evidence; a source census, singleton role, or process-local inventory is insufficient.

#### Strict Source Consumption Gate

Read-only design probes establish that reference admission must precede journal transaction staging: the existing transaction helper can create a missing parent before an inspector invoked in its callback rejects a relative or out-of-anchor reference. An absent anchor/intermediate directory is not absent-source proof. Any bootstrap is caller-owned; the journal reference check does not establish Workspace-ledger path authority.

Strict consumption cannot be implemented as inspection followed by ordinary reading. Probes reproduced empty-profile rebinding, replay/publication enrichment of a token-only snapshot, and different computed receipt scopes despite compatible inspector constraints. Conversely, token rotation can preserve a known-ID receipt scope while failing exact token inspection. The opt-in store consumer now rejects selected-schema/scope mismatch and consumes acquired evidence directly, preserving stored identity rather than merging it during publication. Before any write, the generated complete file passes the existing schema validator for both v1 and v2; an invalid cursor or overflowed attempt count refuses the transition rather than adjusting authority or corrupting subsequent reads. Legacy mode retains its existing validation behavior. Logical-state capacity and `serializedBytes` include the resulting revision and remain separate from physical inspection accounting. Validated operation-local segment names/sizes/raw work and snapshot revision drive compaction planning without ordinary rescans. Before publication, budgets cover segment-first state and snapshot replacement with complete cleanup-failure residue; every subset of that residue is bounded. Existing compaction triggers remain, and an existing redundant segment is retained when it is the bot-ID witness absent from a token-only snapshot. Segment staging is a sibling of the snapshot, outside the strictly enumerated segment directory. These siblings do not establish namespace readiness. Capacity refusal preserves evidence but does not promise progress under insufficient limits. This consumer is independently reviewed but remains unwired; migration is not implemented.

A fault-injected unrelated entry creation invalidated family inspection while both config and journal locks were held. Independent review also reproduced refusal after intermediate permissions changed and were restored, and after an initially absent snapshot was created and deleted. A `dev`/`ino`/`mode`-only ancestor comparison would lose these metadata witnesses; inode equality does not establish continuous identity, and directory descriptors alone do not freeze names, permissions or ACLs. Current checks remain sequential endpoint evidence, not continuous absence or immutable namespace proof.

Keeping the current observation contract requires externally established exclusion of relevant ancestor metadata/namespace changes through consumption, including already-issued asynchronous staging and contenders. Authorized publication changes metadata intentionally and retains its own authority boundary. No production mechanism currently establishes this exclusion for the shared root. Infrastructure errors latch worker blocking; an explicit live-worker signal clears that latch, but retry timers do not, and failed receipt completion is not automatically retried. Byte preservation alone does not establish progress.

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.

`/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.

#### Bus/Journal Design Acceptance

The operator requires reliability and elegance together: minimize independent mechanisms and states while retaining explicit owners and demonstrable safety/progress. The earlier syntax-only comparison favored cursor-ordered, exclusion-bearing polling v2 and cursorless, paired-only follower v1: uniform syntax removes neither admission policy, consent checks nor receipt ownership. That finding constrains rollout but does not resolve custody; the approved ownership correction below supersedes its no-redesign recommendation. A new discriminator, version, ledger or wrapper must remove more conceptual burden than it introduces, including rollout and recovery; superficial uniformity is insufficient.

The comparison exposed a delivery-guarantee boundary independent of schema: retained follower entries deduplicate, but exact receipt completion can remove that evidence and a later identical delivery can be admitted after store reconstruction. Coordinator probes first verified re-admission with actual config, paired admission, journal and follower admission components. A subsequent owned IPC proxy dropped actual ACK bytes between the real forwarder and authenticated receiver; real admission workers/update routing then invoked the authorized callback sink twice for one source, with the leader retaining retry-wait until its successful retry. A queued-message variant also committed a real worker receipt, completed its prompt handoff, and admitted the retry under a new acquisition for the same source. Both variants used injected authorized handlers; actual Pi queue dispatch, model execution and Telegram API effects were not exercised. Uniform entry syntax would not fix the independently settled copies. The next contract must preserve one execution owner across retries, restart and role changes; a fabricated follower watermark, expiry or memory-only set is insufficient. This is narrower than exactly-once external effects across a crash before completion is recorded.

Inline counterexamples reject two standalone remedies: follower completion retention, and delaying follower execution until the polling origin disappears. Both work in a narrow model where only an accepted ACK retires the origin, but both fail when replay may instead execute locally. An owned IPC variant changed the routing runtime's current instance to the same stable recipient before retry: real routing bypassed the receiver, executed the primary source locally and removed it; draining the still-pending follower copy then invoked its sink again. This simulates the role-dependent routing branch, not actual election or process promotion. Origin absence proves neither a specific delivery handoff nor that another source copy remains unexecuted. The probe-only gate/sentinel and explicit wake must not be copied into runtime code; independent waiting-entry progress was not implemented.

A further owned probe uses the actual runtime binding and owner/lifecycle/worker assembly, rather than changing an existing routing runtime's identity. After one lost ACK, the recipient finishes its follower source; the old leader stops; registration becomes false and leader authority becomes true for the same recipient instance/context. Starting the assembly's leader lifecycle executes the retained primary source locally. Both journals finish empty after two sink invocations and only one forwarding request. Transport/election authority remains fixture-supplied: this is not OS election, live promotion, Pi model or Telegram API evidence. The inspected production promotion path stops registration and starts locked polling; the assembly independently binds the two journals and does not reconcile their delivery custody.

The correction therefore needs durable delivery custody, not merely a completion cache or an origin-presence predicate. Existing queue handoff already changes exact ownership in one journal: offer freezes the donor, acceptance CAS installs the recipient, and an ambiguous ACK cannot restore donor authority. Its API requires an already queued receipt; raw input must not masquerade as a queued Pi prompt/control. The operator approved continuing with one authoritative input record and explicit execution ownership, with bus delivery transferring/reference-waking that authority instead of creating a second executable copy. This is logical uniqueness per input, not a requirement to combine every profile into one physical file. Legacy journals and their receipts remain intact until separately authorized reconciliation. The ownership contract below governs the next local implementation slice; storage encoding, raw-owner recovery and lifecycle integration remain separately evidenced, and no production activation is implied. A disconnected worker-facing adapter now proves the first integration seam: acquire and start precede handler execution; complete removes exact custody; a single-input queued outcome atomically becomes its durable queue receipt; deferred returns the running receipt; and an ambiguous running claim never executes again. A session-scoped extension retains deferred receipts and atomically groups them into one queue receipt; consumed raw receipts cannot later settle. Late deferred complete/grouped-queue outcomes require that same retained session receipt, so stale or missing callbacks fail closed. Handler failure and fresh-session observation of retained `running` discard local settlement capability, preventing synthetic completion of outcome-unknown work. A disconnected custodied admission handle now runs the existing registry/default routing inside that session; immediate and late reports settle through the same exact receipt authority. Lifecycle bindings may opt into a strict v3 worker port: v3 snapshots require custodied execution, legacy raw completion/queue/failure methods throw, and custodied handler failure remains blocked running work rather than legacy retry state. A gated resolver reads no v3 dependency while disabled; when enabled, its runtime identity binds both source runtime and recipient execution binding so either change forces lifecycle replacement. Real-v3 assembly evidence preserves retained running input across follower registration-generation replacement and follower-to-leader promotion without another handler call or settlement. Worker selection skips running, foreign-ready, and handoff-frozen inputs while draining independent tail; each custodied commit yields and rereads durable state before unresolved work reports `execution` or `input-custody`. Diagnostics expose only update ID and `running-outcome-unknown`, `foreign-ready`, `handoff-frozen`, or `legacy-retry-state`, never owner, acquisition, binding, payload, path, or token details. Running outcome-unknown wins mixed-class priority. Legacy retry/failed state under v3 is quarantined while independent pending tail drains; it is never replayed through the legacy failure policy. A standalone disposition authority now hashes immutable failure metadata without retaining update payload and permits only exact `requeue-v3|discard` operator intent. Claimed/provenanced entries and generic terminal `retry` are excluded. The bounded segmented operator-disposition audit now accepts a discriminated legacy-custody record, avoiding a second log. Its v3-only mutation is reachable only through an injected operator authorization seam and profile admission: exact evidence atomically becomes unclaimed pending for `requeue-v3` or is removed for `discard`; duplicate authority is idempotent and collisions fail closed. Production omits authorization. The strict worker port now constructs an explicit four-method custody projection rather than returning the structurally narrowed backing store; runtime reflection proves operator listing and disposition are absent. This closes a former capability leak hidden by TypeScript's width subtyping. The disconnected operator runtime requires a caller-owned exact binding-reference scope around every list/apply call and retains no store reference. The scope must span the operation, not only lookup, so retirement/pruning cannot race a stale binding; removal, replacement or recovery mismatch fails closed. The existing bounded reference registry now has an `operator-disposition` class for this composition, but remains process-local evidence only. No production or Telegram command owns this runtime. A source invariant forbids the composition root from acquiring writer closure, installing protocol mode, executing cutover or migration publication, supplying legacy disposition authorization, or constructing the operator runtime. A separate strict non-repairing source-inspection port returns only update ID, retry/failed state, attempt count, bounded failure class and evidence SHA-256; it does not enter writer/source mutation serialization; update payload, failure summary and execution authority remain inside the journal owner. Duplicate reconciliation normalizes exact retained authority before invoking the injected authorizer; malformed extra fields never cross that boundary. If snapshot publication is commit-unknown, exact retry finds the durable audit and performs no second transition; a new disposition cannot target the resulting pending entry. Running custody still has no admissible legacy evidence. A real-v3 replacement regression begins with retained `running` and proves neither the old nor replacement session can execute or settle it after recipient identity changes. Source `recoveryKey` and recipient execution binding are distinct mandatory identities. An assembled regression proves late reports from two deferred sources publish one grouped durable queue receipt. Grouped late reports retain one exact duplicate result for each remaining source callback; the worker accepts the same already-published queue authority idempotently and rejects conflicts. Lifecycle assembly selects this path only for an optional binding-owned custody port. Its strict v3 worker adapter permits exact queued completion but throws before legacy raw completion, queue, or failure mutation; handler errors remain running outcome-unknown. The worker consumes already-durable results without legacy completion/queue writes, synchronizes late claims, and lifecycle assembly selects this path only from an optional binding-owned custody port plus exact binding key. The strict v3 binding also exposes queued receipt offer/accept/cancel through serialized admission wrappers; lifecycle lookup now proves exact recipient acceptance and exact duplicate retries return the same owner. Recipient worker projection is queried only with the matching journal binding key and survives lifecycle replacement. These APIs transfer Pi queue authority and remain distinct from raw input handoff. Cancelling a frozen raw handoff and signaling the worker makes the input executable and clears its redacted blocked projection. A legacy journal writer cannot clear quarantined v3 retry evidence because strict source-version selection rejects that mutation; any future operator disposition therefore needs explicit v3 authority separate from worker settlement. A disconnected bus admission mode validates delivery, source and recipient identity, then wakes the existing durable source reference without journaling the forwarded carrier as a second executable copy. Duplicate delivery can repeat only the wake; stale registration generation cannot wake, and selection fails closed without wake authority rather than falling back to copy admission. The gated delivery identity carries an optional bounded source `recoveryKey` outside the unchanged legacy delivery hash. Reference mode requires that key, bounded exact acquisition/handoff IDs, and explicit authenticated-transport proof; missing or mixed legacy evidence is rejected before wake. Legacy copy mode does not require or infer these fields. Wake carries the complete reference into a disconnected binding-owned resolver. It requires exact recovery key, recipient binding/live owner, update, acquisition and accepted handoff on one unfrozen `ready` claim before signaling; stale, running, missing or mismatched evidence cannot wake or mutate. An authenticated receiver composition against a real shared v3 journal now proves exact and duplicate delivery only signal the accepted ready claim; stale acquisition or registration generation cannot wake or fall back to copy admission. A disconnected sender selector requires mutual `input-custody-reference-v1` capability, and its constructor accepts only an exact accepted handoff when producing recovery/acquisition/handoff evidence. The dedicated `leader.wakeInputCustody` envelope carries no executable Telegram carrier and is forced through authenticated reference admission; legacy durable admission rejects it. A shared-v3 regression composes accepted handoff, leader resolver, mutually capable forwarder, authenticated payload-free receiver and exact wake; exact request replay reuses the cached ACK without another signal. A recipient adapter resolves recovery/binding/live-owner authority, performs exact acceptance CAS, verifies the returned handoff, and only then exposes the reference and signals. The payload-free `leader.offerInputCustodyHandoff` envelope carries exact source/handoff and recipient lifetime evidence into it; parsing, authentication, capability, binding and handler gates fail closed, while duplicate acceptance returns durable duplicate evidence. A real-v3 composition runs donor offer-before-send through the authenticated handoff receiver; acceptance CAS signals once, and client replay reconciles locally without another request. No immediate wake follows acceptance because it would duplicate signaling; payload-free wake remains only an idempotent recovery nudge for already accepted custody. Unknown outcomes remain frozen; after recipient acceptance, retry first reconciles the accepted shared-journal reference and returns duplicate settlement without re-offer, transport, or new authority. Full handoff-then-wake request composition remains disconnected. Frozen pre-accept lookup yields no reference, preventing transport. Missing reference fails retryably before transport; mixed peers retain legacy carrier delivery. A disconnected leader resolver reads shared v3 state without mutation and returns a forward reference only for the exact recipient-owned unfrozen `ready` claim; donor-frozen, running, stale binding or owner mismatch returns no reference. A single optional custody bus bundle derives acceptance, wake and forward-reference resolution from one recovery-key lookup carrying the same recipient binding/live owner, journal and signal authority. Lifecycle assembly/runtime binding exposes that bundle only when supplied; losing its active authority disables lookup and makes acceptance/wake fail closed together. A follower transport adapter rereads the optional bundle for every capability check, acceptance, wake and forward lookup. Removing the bundle on downgrade/reconnect simultaneously disables capability/resolution and makes stale operations fail closed without cached authority. A disconnected receiver assembly rereads these ports across downgrade/reconnect: bundle removal rejects before handlers, replacement generation uses only the new bundle, and stale generation cannot call either bundle or legacy admission. Live target ownership now carries the exact current registration protocol identity into forwarder selection: capability upgrade enables reference mode and downgrade returns to legacy, while persisted records grant neither mode. Forwarders may additionally revalidate current ownership after reference resolution and immediately before transport. If generation, binding, or protocol changed, they return `recipient-ownership-stale` without sending, preventing an old capable snapshot from crossing reconnect. Production follower-client composition uses one canonical live-registry validator immediately before transport. Removal, same-generation protocol replacement, or generation replacement invalidates old ownership; only a fresh current projection passes. The receiver generation check remains an independent second fence. A post-accept retry using stale ownership is rejected before transport after registry replacement, so it cannot reach either receiver execution or its cached ACK. Production still omits the custody bundle and capability; A disconnected readiness evaluator requires requested absent/v3 source, proven legacy-writer exclusion, completed historical migration and capability-ready peers; all mixed, legacy, unsupported, ambiguous or unknown evidence returns a bounded blocker. A disconnected lazy resolver reads no source/peer evidence while disabled or blocked by writer/migration proof, maps inspection loss to source-unready and inventory loss to capability mismatch, and creates no journal/lifecycle binding. Read-only adapters now normalize real strict family inspection as absent/v3/legacy/ambiguous and live follower generation/protocol inventory as ready/legacy/unknown; corrupt source and missing live identity fail closed without mutation. A real disk/registry composition rereads on every call: absent/v3 plus peers advertising durable admission and custody reference enables; peer downgrade, source corruption, or missing identity blocks; replacement upgrade re-enables. Migration and writer exclusion now enter through typed versioned evidence bound to exact profile/recovery identity; missing, unknown, incomplete, present-writer or mismatched evidence blocks before source/peer inspection. A disconnected retained-evidence store adds a bounded strict v1 codec, revision CAS under injected serialization, kind-specific validation and injected publication authority. Malformed, stale, unauthorized or cross-kind evidence never reaches the persistence port. Writer and migration records in one snapshot must share exact profile/recovery identity; even authorized mixed-identity publication fails before persistence. No current component may mint writer exclusion because existing census/serialization cannot prove arbitrary writer or consumer absence. Lifecycle runtime now admits an injected logical source lease: bind acquires, replacement releases/reacquires, shutdown releases despite retaining a reusable binding object, and restart reacquires. Release failure cannot retain runtime authority. One bounded exact-release process-local registry now backs production leader/follower lifecycle leases; capacity and stale release fail closed, and shutdown/restart/replacement update inventory. It is neither durable nor whole-root proof. The registry also scopes sync/async operations and releases on return, throw or rejection. Production status/polling cursor reads, cursor cutover and bootstrap entry reads now use short-lived leader leases; missing binding acquires none. Workspace-retirement protection now scopes shared, retained-binding and discovered journal reads through the same registry and releases before planning continues, including read failure. A composition invariant now rejects direct resolver journal reads in the entrypoint. Remaining production resolver uses are leased lifecycle bindings, scoped polling/retirement operations, or queue-handoff recovery-key computation without journal I/O. Composition invariants reject raw store construction in `index.ts`, require follower durable writes through the leased lifecycle, scope the sole cursor append, and prove current root/API exports expose no journal mutation factory. Old-process exclusion now has a pure evaluator, but not an inventory authority: exact profile/recovery identity, caller-proven complete writer list and process-birth liveness are mandatory. Alive means present; mismatch/incomplete/unverifiable means unknown; only every listed birth proven dead means excluded. Registry absence is never death. The journal transaction owner now exposes an optional outer writer-admission seam through all binding factories. It gates append, mutation and ordinary read (which may repair) before source serialization/journal locking; denial writes nothing, while strict inspection remains read-only. Production leaves it unset. The approved preparation direction is one third Workspace-ledger destructive kind, `journal-writer-closure`, not another ledger and not a cleanup/retirement alias. Its discriminated payload binds profile/recovery identity and closure operation ID but has no target, deletion permit or absence phase. Acquisition requires zero ordinary leases; while held, ordinary profile admission fails. The journal writer seam will acquire/release one ordinary profile lease before config/journal locking, so closure and writers serialize through ledger transactions without nesting the config transaction. Current lock-order regression proves denial never enters pairing/source serialization and allowed append enters writer admission, then pairing (config) admission, then source serialization. Legacy missing-kind fences remain pressure retirement. The third kind and strict identity-only payload codec reject deletion fields and identity drift while retirement/cleanup fence types remain narrowed. The top-level ledger union is integrated across admission, retirement coordination, and cleanup ports: closure blocks ordinary admission and competing destructive work globally, owns no Thread slot, and every deletion operation narrows the kind before accessing deletion authority. Compile-time deletion fence/permit authority is also a dedicated retirement-or-cleanup union; `journal-writer-closure` cannot inhabit it. Exact closure acquisition/release is now available on the ledger but remains disconnected from production. Acquisition requires zero leases, resumes the exact durable authority after lost ACK without republishing, rejects same-operation drift, and blocks other destructive work; release requires exact current-owner authority. The optional journal-writer adapter acquires a profile lease before entering the journal seam and retains its ID after ambiguous acquisition. Release failure is diagnostic-only after the journal operation settles: retaining a possible lease blocks closure safely, while throwing from `finally` would falsely erase the known operation outcome. The existing binding runtime propagates one supplied adapter to leader, active follower, recipient and path-discovered journals; regression coverage closes all four classes. Production omission still means no writer closure activation. Writer-exclusion evidence cannot yet be minted truthfully inside this fence: releasing it allows a newly starting legacy writer, retaining it blocks v3 writers too, and retained v1 `excluded` evidence records neither closure operation nor startup authority. Closure publication therefore requires a prior durable operator-authorized startup-exclusion authority plus protocol-class admission semantics. A strict standalone authority schema now binds profile/recovery, closure operation, inventory SHA-256, operator authority ID, explicit enforced/revoked status, authorization time, and `custody-v3` as the sole allowed protocol. It is retained by the readiness store through strict revisioned CAS, injected publication authorization and cross-kind identity checks. The full candidate is decoded and normalized before authorization, so malformed/extra evidence never crosses the authority callback; enforced and revoked states are retained exactly. Proven readiness now consumes it fail-closed: `excluded` writer evidence must link the same enforced authority ID, closure operation and inventory digest. Legacy unlinked evidence, revocation or any link drift blocks activation, and the store rejects conflicting linked authorities. Proven readiness also requires the durable installed protocol mode to match the same profile/recovery, startup authority, closure and inventory digest. A crash before mode installation or before linked exclusion publication therefore remains disabled. The non-nesting operator coordinator now enforces the safe order: verify retained enforced authority → evaluate exact inventory/liveness under closure → atomically install mode → reread authority → CAS-publish linked exclusion. A pre-publication revocation or race leaves mode installed but no readiness evidence, so activation remains disabled; exact retry reconciles installed mode and existing evidence without duplicate authority. Production has no caller. Migration completion now has a standalone strict authority binding the same cutover identities plus a complete historical source/disposition digest, resulting `absent|v3` family, operator authorization time and explicit revocation. It is now retained through authorized revisioned CAS and consumed by proven readiness only when migration evidence links the same migration/startup/closure/inventory authority. Revocation, legacy unlinked evidence, or a live source family different from the authorized `absent|v3` result blocks activation on every resolution. The disconnected migration publisher rereads retained authority, compares the exact historical inventory digest and inspects the live source before CAS-publishing linked completion. Exact retry is revision-stable; it performs no migration or source mutation. Its strict standalone Workspace mode codec now binds `custody-v3` to exact profile/recovery, startup authority, closure operation, inventory digest, installer owner and install time. The ledger now retains it by atomically replacing the matching zero-lease closure; fence+mode state is invalid and exact lost-ACK installation resumes without republish. While mode exists, generic `journal-write` and new closure acquisition fail closed. Dedicated v3 writer admission must present matching recovery, startup authority, closure and inventory digest; operation kind alone never grants access. While mode is active, generic `journal-write` and `journal.*` admission requires an already-held same-owner dedicated v3 profile lease. This permits nested append/input admission under the outer writer seam but rejects caller-chosen journal operation names as authority. Production installs no mode. Mode→closure publication is crash-proven: after an acknowledged-unknown atomic rename, a fresh ledger resumes the exact closure without invoking authorization again or restoring mode. Re-closing an installed mode is possible only through an injected production-unset authorizer: with zero leases, one ledger transaction replaces the exact recovery-bound mode with a new closure; active writers block before authorization and denied callbacks leave mode unchanged. Exact closure retry handles lost publication ACK. A compile probe established that this must be one compatibility cohort across the ledger, retirement coordinator, and cleanup-manager ledger port; publishing a wider snapshot before those consumers narrow by kind is forbidden. Required slices are: generalize fence payload codec without changing existing kinds; add closure acquire/exact release only; wire writer admission; then allow complete inventory capture and evidence publication while the same fence remains held. No step may infer external writer absence. Exported legacy factories and arbitrary installed-package consumers remain outside process-local proof; writer-exclusion minting therefore requires package/API closure or explicit retirement, and rollout stays gated. Optional lifecycle exposure and replacement invalidation remain disconnected. Production bindings expose neither port. Its optional late-settlement callback lets the worker clear an exact deferred projection or register already-durable queue authority without repeating a legacy journal mutation. The real worker drain accepts an optional already-settled custody result: completion rereads durable state without legacy removal, while outcome-unknown blocks without creating retry authority. Production still selects only the legacy path.

##### Input Custody Contract

- Identity: The actual source journal binding and update ID identify the input; an exact acquisition identifies its current execution owner. Neither current leader/follower role nor a request ID creates a new acquisition. Obtain source references from the worker's bound authority, never from a caller-supplied path or source-ID field alone.
- Admission: Preserve the existing durable admission, immutable exclusion and ordered-source replay veto. A bus receiver validates sender, provenance, recipient binding and lifetime before it can accept ownership; source identity or lock possession is not consent.
- Execution: Persist ownership before semantic processing. A local projection may schedule work but cannot independently authorize it. Role replacement must resume or reconcile the existing ownership, not reconstruct the original input as fresh local work.
- Transfer: Reuse the existing owner/acquisition and offer/accept discipline. Freeze donor execution before offering; acceptance CAS changes ownership of the same source record. Preserve the exact forwarded execution payload and recipient binding. A missing ACK does not cancel an accepted transfer or restore donor execution; repeated requests observe the same acquisition rather than minting another.
- Settlement: Only the exact current ownership and phase can record completion, failure, transfer or transition into a Pi queue receipt. Raw input is not a queued Pi prompt/control. Queue admission must preserve the source reference and remain atomic for grouped source IDs; stale raw-owner settlement cannot erase the resulting queue authority.
- Completion: Once confirmed completion is recorded, the existing ordered-origin replay barrier prevents re-creation. A late reference/notification cannot recreate input from its payload. Missing, malformed or mismatched storage is not completion evidence.
- Recovery: Distinguish work proven not to have started from work whose outcome is unknown. PID death, role replacement and a fresh registration do not prove an external action was unexecuted. Select and validate raw-owner recovery separately; do not inherit queued-owner discard or automatic raw replay merely because those paths already exist.
- Progress: Waiting or foreign-owned entries must not block independent local input. Admission must leave logical and physical headroom for required ownership transitions; capacity refusal preserves data but does not prove drain progress. No mutex spans a handler/UI/transport await. Replacement must account for actual unsettled handlers and pending mutations; do not restore discarded prepared-worker readiness projections.
- Compatibility: Ownership-aware storage/consumers must reject interpretations that would turn an owned input into ordinary executable pending work. Keep old formats, receipt scopes, files and production factories unchanged until explicit versioning, source-reference reconciliation and capability-gated rollout are validated. The guarantee does not cover exactly-once external effects across an unrecorded effect/commit crash.

The custody storage codec is v3. It retains v2's required cursor and immutable exclusion evidence, adding an optional `inputClaim` with `ready`/`running` phase, existing exact owner/acquisition fields, a recipient binding bounded to 256 characters, an optional exact execution-update projection, and an optional handoff `{ handoffId, offeredAtMs, recipientOwner }`. A queued v3 entry may instead retain `inputProvenance` with the former exact owner, binding and projection; this is immutable transition evidence, not concurrent raw execution authority. Excluded input cannot carry a claim; raw and Pi queue authority cannot coexist on one entry; running claims cannot be retry-wait/failed. Snapshots and all retained segments share the decoder. Unsupported claim phases/fields remain rejected rather than speculatively interpreted.

The opt-in `createTelegramInputJournalStore()` reuses the journal's private transaction/publication owner, not a second ledger. It requires strict source access, source serialization, polling admission, a captured process identity and a bound `getInputContext` port. Besides read/append, it exposes veto-only removal, acquisition, ready-claim release/recovery, offer/accept/cancel handoff, grouped input-to-queue transition, exact queue settlement/recovery, start and exact-receipt completion, not the legacy unowned mutation ports. Each input mutation takes optional profile-wide Workspace admission before config/source/journal access. Acquisition only claims admitted pending input; matching repeats retain the same acquisition and projection. Start checks the exact acquisition, originating session and recipient binding, and grants only one ready-to-running transition. Publication rechecks the captured execution context through an operation-local callback. Completion requires running authority and may settle the original exact receipt after its session disappears; its token fingerprint qualifies the fixed source/receipt binding without changing existing receipt scopes. Reading metadata or receiving `started: false` grants no execution or sender consent.

A successful v3 append independently verifies the remaining publication chain for the worst bounded representative of every currently present next-transition class; `acquire` and `start` then bind that reserve to their exact update. The reserve covers logical journal bytes and strict source files/bytes/work, including both a durable segment whose snapshot replacement is commit-unknown and a replaced snapshot whose redundant-segment cleanup entirely fails. The acquisition envelope uses maximally encoded claim fields, a duplicate of the original update and 4 KiB of additional projection growth; a larger routed projection refuses without changing the raw input. Each v3 mutation requests immediate snapshot compaction. Admission covers either direct start/completion or one `ready → unclaimed → reacquire → start → complete` recovery branch across five retained transition segments. A successful offer separately reserves accept-to-completion, cancel-to-completion and dead-donor release/reacquire-to-completion resolution before freezing the donor. Branch reserves are reused rather than summed: this guarantees one operation-bound progress chain at a time, not simultaneous transitions, repeated ready-owner recovery under persistent cleanup failure, or recovery from unbounded filesystem failure. Settlements are never withheld merely to reserve the next unrelated input.

`releaseInput()` uses the exact source/acquisition receipt and owning process identity to clear only a pending unoffered `ready` claim, preserving the original input. It needs no current session context, so the originating process can finish cancellation after replacement. An unclaimed exact source is a no-op postcondition; another acquisition, `running`, offered ownership, failure/queue state or absent input refuses. `recoverReadyInput()` additionally requires a recovery identity matching the store runtime and checks the exact stored claim before its synchronous process-birth liveness probe. `alive` and `unverifiable` retain authority; only `dead` clears it. An offered ready claim is still proven unstarted: accept and dead-owner recovery serialize on the same record, so acceptance first fences the stale donor receipt while recovery first leaves unclaimed input that a later accept cannot recreate. A liveness error fails closed. Commit-unknown release retries observe unclaimed state without claiming that a handler ran. `running` is rejected before liveness and remains outcome-unknown.

`offerInputHandoff()` requires the exact ready donor receipt plus its current session/binding context. Its stable handoff ID binds fresh token entropy, source binding, update ID, exact donor owner, recipient owner and persisted recipient binding. The token is neither persisted nor needed after publication: the returned durable source reference plus stored handoff ID identifies later resolution, and an exact same-recipient offer retry with fresh entropy returns that existing ID. The persisted offer leaves owner, routed projection and original update unchanged while freezing donor start/release. `acceptInputHandoff()` requires only that source reference, stored ID, named recipient runtime and same persisted binding, then CAS-replaces the donor with one new ready acquisition carrying the handoff ID and removes the offer. A repeated accept before or after start returns that same acquisition; after recovery or recorded completion it refuses and cannot recreate input. `cancelInputHandoff()` requires the donor's exact receipt and stored ID and only removes the unaccepted offer under donor context; after acceptance the stale donor no longer matches, so cancellation cannot restore it. Commit-unknown offer/accept/cancel retries observe the durable phase. These primitives do not send IPC, ACK a bus delivery or invoke a handler.

`queueInputs()` atomically replaces a non-empty exact set of `running` claims from the current process/session/binding with one prompt/control queue receipt. It sorts and de-duplicates source IDs, mints one queue acquisition for the whole group, removes every `inputClaim`, and retains each claim's owner, binding and routed projection only as `inputProvenance`. A retry after commit-unknown publication must match the complete receipt group and every former acquisition, then returns the same queue receipt; a stale owner, partial group, changed kind/receipt, offered/ready claim or foreign context refuses without mutation. Consequently raw completion, release, recovery and start cannot erase or regrant queued authority. The exact queue receipt may complete after input session context disappears, behind the same profile-wide Workspace admission. Queue publication reserves its exact grouped completion through segment-before-snapshot and complete cleanup-failure prefixes; it does not promise capacity for an unknown group before that operation is presented.

`removeExcluded()` requires retained v3 source/cursor evidence and checks the complete requested ID set atomically. Every present requested entry must carry the immutable exclusion veto, including pending, retry-wait or failed entries; any non-excluded input, claimed work or Pi receipt rejects the batch. Missing IDs inside the retained cursor are no-ops, not evidence of prior execution; missing storage or IDs above the cursor refuse. Removal needs neither current pairing nor an execution context and preserves the cursor, all non-excluded work and its diagnostics/ownership. Source inspection and crash-visible publication budgets remain mandatory: a readable one-file budget can refuse the removal segment even though the final logical state would shrink. This path grants no capacity exemption or drain-progress guarantee.

Project-native tests cover competing processes, reconstruction, stale owner/session/binding refusal, immutable exclusions, logical/physical headroom, commit-unknown publication, cleanup refusal, projection bounds, exact ready release/dead recovery, frozen-donor refusal, token-free offer reconstruction, cross-process accept/recovery races, grouped running-to-queue transition, exact provenance retention, stale raw settlement refusal and post-context queue completion. A compaction failure after segment publication can leave a durable running marker even when `startInput` throws: retry does not regrant it. This is commit-unknown, not proof that a user handler ran; no handler is invoked by these primitives. Non-excluded raw failure settlement, bus/worker integration of durable source references and queue receipts, v3 queue-handoff exposure, outcome-unknown running-owner recovery and production consumer support remain unimplemented. V1/v2 stores still refuse v3 before recovery or mutation; current workers, production factories and `index.ts` remain unchanged. The reproduced bus/lifecycle repeat is not fixed by these disconnected primitives.

Read-only migration probes constrain that comparison. Publishing a v2 snapshot over retained v1 segments is unreadable. For a logically empty current v1 state with an existing cursor and no segment-only bot-ID witness, identity-preserving v1 consolidation at the existing final revision → verified redundant cleanup → v2 publication survived simulated interrupted prefixes and all eight cleanup subsets of a three-segment fixture. Dispositions, cursor, revision and recovery scope were preserved. This is a candidate, not an implemented migrator or process-crash suite. Nonempty/unknown authority, missing cursor and a segment-only identity witness require refusal; absent family produces no write or invented cursor. Sibling staging remains outside family evidence but blocks the current full-profile inspector. External references, held handlers, writer exclusion and startup authority remain caller-owned gates.

#### Owners And Validation

- A narrow `pairing` runtime is justified only for the shared candidate/dialog lifecycle used by updates and command/bootstrap paths. It owns bounded ephemeral requests, cancellation and decision state, not durable configuration, journal settlement, Telegram transport, or Pi SDK mechanics. `config` owns durable grants, `journal` owns admitted-input evidence, `updates` owns sender admission before routing, and existing Pi/binding/lifecycle owners supply native UI and session ports. Keep `index.ts` as a thin re-export and `lib/extension.ts` composition-only; approve the minimal import graph before extraction.
- Independently verify the refined schema/migration and lock-seam design before implementing it. First prove durable entry exclusion with UI disconnected, then test the ephemeral lifecycle with an injected clock and controllable dialog/publication promises, integrate all admission paths, and run shared validation plus an independent post-integration review.
- Required witnesses: blocked dialog with worker progress; duplicate and competing requesters; exact expiry and cooldown; reject/ESC/error/no-UI; shutdown/profile/token/owner replacement; late Yes; failed/ambiguous publication; competing configured owner; pre-approval journal backlog and restart; message/edit/callback/guest and unbound/foreign paths; configured-owner compatibility; redacted/sanitized UI; no model turn before grant. Mocked UI is not terminal keyboard/rendering acceptance. Live acceptance requires separately authorized disposable profiles and Threads.

### Runtime Ownership

- `/telegram-connect` acquires or moves the active profile's owner slot before polling starts. `/telegram-disconnect` keeps its destructive confirmation, then stops polling and releases only that exact slot. In Threaded Mode it tears down the disconnecting instance's bound Telegram thread: leaders delete their own thread directly, and followers send an authenticated exact-generation disconnect envelope seeking confirmed leader cleanup before unregistering. If cleanup fails, explicit manual disconnect may instead stop its captured local transport without claiming Thread deletion. Graceful Pi `quit` always preserves the owner slot as restart intent, allowing a reopened same-`cwd` session to reclaim the stale lease. When `threads.automaticCleanup` is enabled (the default), quit also deletes the bound Telegram tab without releasing that restart intent; disabling it preserves the tab. After delivery, polling and inbound-worker shutdown complete, a quitting leader detaches its exact owner record under profile admission while retaining the Workspace, letter and restart ownership. Publication rechecks the captured session generation, profile, leader epoch and successful current-generation suspension; unfinished startup/teardown, unproven suspension and pending cleanup stay protected. Preparation/publication errors are diagnostic and cannot block remaining session cleanup. Failed automatic deletion likewise falls back to safe suspension.
- Explicit manual disconnect captures one lifecycle-generation-bound stop before entering cleanup admission. The cleanup path rechecks that captured authority before observing a target, after intent publication, before API/store effects and after awaited reconciliation. A newer connection revokes old cleanup and fallback stop; teardown also checks its generation after suspension before durable lock release. Cleanup admission failure may trigger only the captured local stop, not an unguarded latest-runtime stop or new Thread mutations. Failed cleanup reports unconfirmed outcome with debug guidance rather than claiming deletion was skipped or exposing raw errors. A stop/release error propagates as incomplete without another teardown attempt. Session-restart cleanup remains fail-closed behind admission fences and never uses this manual fallback.
- Without an explicit carried connection intent, session start schedules polling resume asynchronously only when the owner slot already points at the current `pid`/`cwd`, or when a stale same-`cwd` owner can be safely replaced after process restart. Under a live foreign leader, startup instead attempts capability-gated restore-only follower admission when the selected profile has a remembered exact-`cwd` Workspace binding; it never provisions an unremembered Workspace. Startup and `/resume` do not wait on leader election, Bot API probes, poller handoff, or thread reconciliation before restoring the Pi session.
- On local `/resume`, an in-flight `/telegram-connect` or established connection supplies one process-local, 30-second intent containing the selected profile, exact CWD and target session file. The file matches only the lifecycle successor; the fresh public session ID still owns binding selection. Startup claims intent before asynchronous initialization and uses the normal connection path instead of concurrent auto-restore. Quit/reload/disconnect, mismatch, expiry or supersession cancel it. The predecessor carries no Pi context, callback, Thread or slot, and late completion can clear only its own attempt. Resume startup has no automatic forced takeover or repeated failure retry; errors remain diagnostic with a compact recovery notice.
- The polling owner alone bounds `getUpdates`: each request derives its cancellation budget from Telegram's declared long-poll timeout plus 10 seconds of transport grace (10 seconds for the zero-timeout initial sync and 40 seconds for the normal 30-second poll). The request-local controller inherits poller cancellation, rejects its owner at the budget, and fences any late transport result. Ordinary Bot API and media operations do not receive speculative blanket deadlines. Existing caller signals remain authoritative through API retry waits, only retry-safe methods replay explicit retryable responses, and non-idempotent sends preserve commit-unknown evidence instead of risking duplicate mutation.
- Ordinary non-conflict poll/admission failures retry with exponential pauses of `1s → 2s → 4s → 8s → 16s → 30s`, capped at 30 seconds without a retry-count ceiling. Only successful durable admission resets this backoff; a successful HTTP response followed by journal failure does not. Retry sleeps remain poller-abortable, and accepted inputs/cursor ordering are unchanged. Outages therefore recover through the existing poller without manual reconnect.
- Ten consecutive `getUpdates` conflict responses, including initial cursor sync, terminate polling with `persistent-conflict`; a successful response or a different error resets the count. The controller detaches its inner promise before notifying the locked lifecycle, avoiding teardown waiting on itself. That lifecycle stops ownership checks, lease refresh, capability monitoring, typing, and classic or bus transport (including leader health, pruning, and IPC), withdraws local direct authority, and transactionally releases only its exact lock. A failed durable release leaves local authority revoked; explicit reacquisition mints a fresh epoch. Accepted queue receipts and local Pi dispatch survive. One terminal diagnostic distinguishes lost local ownership from a competing client despite an apparently owned lock and reports cleanup failures; ordinary status refreshes retain generic `error` until transport recovers. Remove the competing client, then use `/telegram-connect`; no automatic retry continues after the terminal threshold.
- Manual and automatic polling starts share a lifecycle generation. A later suspend, disconnect, persistent-conflict stop, or accepted start invalidates older startup continuations; reconnect captures its generation before waiting for transport teardown and rechecks it before acquiring ownership and after awaited startup work. Obsolete completion or failure cannot report a successful connection or roll back a replacement. Admission rejects stale/unauthorized contexts before advancing its own startup generation, so a rejected call cannot cancel valid in-flight initialization. After awaited bus startup, thread-aware completion checks its generation before starting leader health or changing fallback/startup-option state; teardown clears health independently of the current mode flag. Startup probes, capability-monitor transitions, and observed-target transitions share an orchestration lifecycle fence and check it inside their effect-owning helpers after awaited queries, persistence, or transport work. Monitor stop also invalidates pending observations. These checks suppress subsequent state changes, fallback, health, and status effects; already-issued API/persistence calls retain their own transport/storage fencing.
- `pollingActive` reports only whether this runtime still owns an unresolved polling lifecycle; it is not health evidence. A separate observable state records `starting`, `long-poll`, `persisting-journal`, `persisting-offset`, `retrying`, or `stopped`, together with phase start, current update id, last successful response time/count, and terminal stop reason. This distinguishes a stuck HTTP poll from downstream update work without a wall-clock stale heuristic.
- Built-in read-only menu commands return after required local mutation and schedule context-fenced rendering and command synchronization independently, so those effects cannot withhold the next inbound offset.
- Pi `print`/`json` run modes stay passive. Inherited child sessions that share `telegram.json` but do not own the exact `pid`/`cwd` slot must not poll or call `getUpdates` unless the operator force-takes ownership.
- Session replacement through `reload`, `new`, `resume`, or `fork` suspends polling/watchers without releasing ownership or publishing inactivity so the next session in the same process can resume. Late shutdown cannot clear a replacement context even when its identity is reused: the captured session generation must still match. For replacements other than `/resume`, a registered follower snapshots its assigned target into a short-lived same-process handoff, stops the old receiver/heartbeat, and re-registers through the live leader without marking or replacing its Telegram thread. Local `/resume` suppresses that source-target handoff and selects the destination session's binding instead. Hard process termination cannot run graceful teardown, so stale recovery retains its restart-hint path.
- Live external owners require explicit takeover confirmation. Long-lived timers compare against snapshotted owner identity and stop local transport work when the slot no longer matches.
- The profile's `transport` section owns only Telegram transport control. Local extension and accepted queue state remain per Pi instance when ownership moves, but previews, final delivery, dispatch transport mutations, and delayed Bot API work fail closed until exact direct or follower authority becomes valid again.
- Exact ownership remains checked every second and re-confirmed every two seconds by lock-free reads. A lock-free miss is confirmed through the serialized refresh path: a serialized not-owner answer records `ownership-lost` and stands down at once, while an observation that cannot be verified at all records `ownership-check-failed` and stands down only after two consecutive tolerated misses; the leader writes no heartbeat, and a live owner is replaceable only by dead-PID or bus liveness proof (see [Leader Election](./multi-instance-bus.md)). Every acquisition, entry migration, release, takeover, and stale recovery is one `transport`-section transaction through the shared `runtime/state.json.transaction` guard (see [Consolidated Runtime Root](#consolidated-runtime-root)); it fences stale recovery and delayed release against replacement-owner ABA and fails closed on malformed state, unverifiable ownership, contention timeout, or unsupported filesystem behavior. Publication uses private staging below `runtime/` and atomic rename.
- `state.json` is authoritative and private: `transport` (ownership), `workspace` (canonical Workspace/Restore evidence) and `admission` per profile. The non-canonical runtime/roster/diagnostics projection is the `runtime` section, published only by the transport owner without touching canonical sections; it and `logs.jsonl` never grant routing authority. The leader reads optional follower slot hints from it; a missing or malformed projection is ignored. Followers remain authenticated bus registrations rather than transport/Workspace/runtime writers; they may publish their process-owned admission leases.
- Ordinary ownership and state mutations fail closed on a malformed or foreign `state.json`; read-only ownership queries report no owner, not proof of process absence. The legacy whole-file reset is not wired for the shared envelope. A non-election leader start performs the [damaged-state reset](#damaged-state-reset-operator-approved); section-scoped recovery is not planned. Startup best-effort removes obsolete current-runtime root/session `recovery/` directories, never the pre-0.52.0 tree.

### Pre-release Module Seam Proposal

This bounded structure design is applied locally: Workspace identity has a reusable lower owner, while Thread naming rules reuse the existing `thread-naming` owner rather than creating a second naming domain. The four large effect owners stay in place; every retained move requires its own tests and shared gates. A closed dependency set or file length alone does not justify extraction: show actual cross-domain reuse or a concrete dependency-direction/cycle problem, and prefer an existing cohesive owner.

**Decision: shared value contracts under the smallest suitable owner, not domain folders or effect-kernel surgery.**

- **Workspace identity → `lib/workspace-identity.ts` (implemented).** Own session/CWD normalization, directory/session keys, local instance-slot encoding and the `TelegramWorkspaceBindingIdentity` contract. The ten-declaration closure in `threads.ts` is about 130 source lines and depends only on its own declarations plus Node crypto/path and the existing platform/CWD defaults. It needs no store, admission, transport, callback bag or reverse import. Keep algorithms, byte limits, exact key spelling, legacy keys and platform behavior unchanged. `threads.ts` imports the lower owner and retains its existing export names as compatibility reexports; the precomputed-key constructor, session-key function and key-length bound remain available to the store without recomputing or reinterpreting canonical evidence. Allocation, reservation, target selection, mutation and protection remain in Threads. Normalization is not storage-reference or custody authority.
- **Thread name policy → existing `lib/thread-naming.ts` (implemented).** Generated identity normalization, grapheme fallback, palette/entropy selection and distinct identity/manual-display validation share one owner with the existing manual-name dialog. The template formatter and pure title adapter use their actual value inputs, with no nominal import back to Threads. Internal rule consumers import Naming directly; old Threads exports, including the provision-request formatter signature, remain compatibility references to those same functions. Occupied-name collection, current-record policy, slot pressure and rename/provision effects stay in Threads; display projection stays in `thread-display`. Preserve random/entropy edges, palette order, limits, dialog target/scope/expiry semantics and UI-kit grammar. A separate name-policy domain buys no necessary boundary when this existing owner can provide the reusable contract.
- **Updates: retain worker/admission/custody together for this epic.** The public registry/execution-fence section is a possible later boundary, but its private carrier symbol and admission wrapper are coupled to worker execution. Any future extraction must move the unique carrier owner rather than copy a symbol or borrow an ended grant. A new lower module must not import `updates.ts` for its flow types; registry lifetime, consume/pass order and stale/late settlement require their own cohort. Merely splitting the worker body would create a broad callback interface without clearer ownership.
- **Journal: retain the transaction core.** `createJournalStoreCore` joins v1 and custody-v3 adapters with snapshot/segment acquisition, queue receipts, source references, compaction and unknown publication outcomes. Moving read/write helpers cannot split this authority. Reference-registry or codec extraction is deferred until its lifetime/type dependency closure improves the graph rather than routing callbacks back into the root.
- **Routing: retain the chooser/Restore operation closure.** Pending source groups, selection, one-shot issuance, receipt callbacks, cleanup and previous-world disposal share one owner. Extracting visual fragments with the same large dependency bag is not a boundary. The separate assistant-output authority block is coherent but small; no new module is justified by its size alone.

**Validation and stop boundary.** Keep the current flat DAG and composition-only `extension.ts`; avoid `types`/`utils` buckets and facade proliferation. Identity tests live with the identity owner; naming value/dialog tests share the Naming suite, while store/Restore tests remain in Threads. Explicit compatibility checks retain old exports and signatures; declaration/body equivalence and focused runtime tests guard behavior. Typecheck, focused and full tests, build/current dist, public API, Domain DAG, context and diff checks gate retained moves. Reassess after these two value-policy boundaries; if remaining splits increase interfaces or risk, finish the structural epic without forcing all four owners into smaller files. Release, reload and live-state work remain outside this proposal.

### Consolidated Runtime Root

**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.

**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.

**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.

**Kernel (Locks).** `readTelegramRuntimeState` and `mutateTelegramRuntimeStateSection` own physical authority. Reads neither create nor repair files and refuse unsupported/malformed envelopes, non-private/non-regular sources and changed physical observations; missing state is an empty envelope only when the initial observation positively reports absence. A publisher acquires one shared `runtime/<state basename>.transaction`, reads the latest envelope, supplies detached current-section/sibling observations to one synchronous reducer and replaces only its named profile/section; semantic no-ops keep file identity. Authority is rechecked before mutation, after the reducer, before writing, immediately before atomic rename and before a positive acknowledgement. Nested transactions for the same path are refused. A lost rename reply or post-publication authority loss returns `publication-unknown`; the committed fact remains and never grants replay or rollback.

**Transport.** `createTelegramLockRuntime({ statePath })` keeps acquire/election/expected-owner/unresponsive-owner/release semantics in its profile's `transport` section, preserving sibling fields and the polling pointer through release and succession. Read-only ownership queries fail closed (no owner) on unreadable state so unrelated Pi hooks never crash; acquisition/publication still validate and refuse without replacing it. `publishStateSectionIfOwned` publishes only Workspace or runtime data under exact retained owner and caller authority with an optional `expectedScope`; it never publishes transport/admission or borrows a surrounding `commitIfOwned` grant.

**Session-bound grant.** `Locks.createTelegramOwnedStateAuthorityCapture(lock, session)` captures the exact current Pi context, session generation and owned leader epoch before the caller's first await through a structural session port (Locks does not import Lifecycle). The grant stays current only while that context/generation is current, the lock is owned for that context and the epoch is unchanged. Session replacement, same-context restart, clear, release and release-then-reacquire (a new epoch, as disconnect/connect does) revoke it; a successor captures a fresh grant and never renews the old one. Through the real Workspace store, a persist captured before a new session refuses without changing bytes while the successor publishes; an epoch-only capture would have committed that stale write.

**Workspace (Threads).** `createTelegramTopicTargetStore({ consolidated })` uses `createTelegramConsolidatedWorkspaceStorage` and the lossless `parseTelegramWorkspaceStateSection` decoder: malformed/filtered records, unsupported headers, altered normalization, unknown fields or foreign profile evidence block rather than becoming empty state; missing section means absence and whole-section removal is not admitted. Publication captures path/profile/grant before the queue await; whole-Workspace writes compare the current section with the last loaded/committed baseline inside the reducer, so a concurrent canonical change requires refresh. Transaction frames supply Restore/temporary/registration observations to existing guards without nested ownership transactions. Complete-empty journal binding keys stay serialized as `[]` so completeness survives reload. Provisioning-target recovery sidecars use `runtime/<state basename>.provision-recovery.<16-hex profile hash>.json` via `resolveTelegramWorkspaceProvisionRecoveryPath`.

**Admission.** `createTelegramWorkspaceAdmissionLedger({ path, stateProfile, profileKey, owner })` selects the shared `admission` section; the runtime binding selects exactly one `getStatePath` or legacy `getPath` identity. Admission stays process-owned: followers acquire/release exact ordinary leases while another process owns transport; destructive fences and `journal-write:custody-v3` permissions keep their predicates and one-shot issuance. Unknown fields are refused rather than dropped; only positively dead process/birth owners are pruned inside a mutation.

**Runtime projection (Status).** `createTelegramRuntimeProjectionStore` publishes the non-authoritative runtime/roster/diagnostic projection through a structural storage port (Status imports no local nominal domain), omitting `recentRuntimeEvents`. Submission captures detached content and exact profile/path/grant before the queued await; malformed runtime observations may be replaced only under fresh owner authority; unknown post-rename replies are never re-published to recover an ACK.

**Logging.** `createTelegramRuntimeDiagnosticsRuntime({ sharedFile: true })` writes one profile-labelled `logs.jsonl`. Scope resets append profile-tagged markers; the global 5 MiB threshold rotates the mixed segment to `logs/logs._prev.jsonl` under captured grant and the `runtime/logs.jsonl.transaction` guard. Event append is fail-soft and non-authoritative.

**IPC.** Bus Transport's `layout: "consolidated"` maps leader `bus.<16hex>.sock` and follower `f.<16hex>.sock` (hashed raw profile and exact recipient) under `runtime/`; Windows uses hashed native named pipes. The local server publishes a colocated private `.pt-<16hex>.sock` listener behind an atomically renamed relative logical symlink. Logical addresses stay canonical; an over-budget Unix path uses the existing private external socket shortening only at socket resolution, never for state or journal relocation.

**Validation.** Native fresh-root production tests start real leader plus follower for default and named profiles and observe one poller, the two-file root census, leader/follower publications under `runtime/`, channel success and lost-ACK issuance under `journals/` surviving a replacement extension instance without resend, rotation under `logs/`, preserved bindings and byte-identical released `tmp/telegram`. An authenticated polling callback traverses the production inactive-tab review, profile admission and strict protection observer to prepare exactly one inactive binding through `resolveTelegramServiceJournalStorage`; the cleanup journal shares `journals/` with channel records and leaves no staging files. Replacement and a repeated review retain byte-identical prepared work without issuance or deletion, and complete-empty journal keys/source tuples survive Workspace reload. These are fake-HTTP host-harness tests in one OS process, not real Pi/Telegram, whole production section-owner sequencing or native-platform acceptance.

**Shared owner-port composition.** Native property tests compose the production session-bound grant and Thread store's Workspace/Restore/runtime ports with process/birth-owned nonleader admission and actual default/named section stores on one physical root. Context, same-context generation, epoch, owner, profile and path revocation refuse both queued publications. A concurrent Workspace change refuses its whole-section CAS while independent runtime publication succeeds; neither changes transport, admission, named-profile sections, issued Restore or complete-empty references. Registration uses the existing Workspace transaction frame without nesting a shared transaction, and the nonleader lease remains releasable after transport/session changes. Transport PIDs/liveness are supplied fixtures; this proves local owner-port composition, not actual extension sequencing under those races, real multi-process/profile runtime continuity, Pi startup or platform/live acceptance.

**Production registration ownership race.** The fresh-root fixture also holds an authenticated native follower registration inside the actual leader provisioner while fake HTTP awaits a Thread-creation reply. Exact same-process owner succession changes the epoch before that reply returns. For default and named profiles separately, the late ACK cannot publish the new binding/owner, old diagnostics and teardown cannot overwrite the successor runtime/transport, and the held process/birth-owned admission lease releases. A real sibling-profile Workspace section and channel issuance bytes remain unchanged; no second creation, cleanup or model dispatch occurs. This is production composition with disposable native Linux storage and supplied Pi hooks in one OS process, not an actual Pi session change, interrupted Restore settlement, multi-process/profile continuity or platform/live acceptance.

**Production follower session race.** The same default/named-profile fixture replaces the follower context (same session ID) or renews its generation (same context object) through composed `session_start` hooks while the initial authenticated registration awaits fake-HTTP Thread creation. The independent leader retains its acknowledged remote binding and slot; the stale local attempt grants no direct-delivery authority, makes no API call on refusal and leaves the recipient journal family absent. Only a fresh acknowledged connect grants local delivery, reusing the retained binding without a second creation. Admission releases; sibling-profile Workspace, channel issuance and released storage remain exact, with no cleanup or model dispatch. This is supplied-hook production composition in one OS process, not actual Pi lifecycle acceptance, interrupted Restore settlement or an inbound execution/readiness witness.

#### Damaged-State Reset (Operator-Approved)

**A working `/telegram-connect` outranks preserving damaged runtime state.** Before a non-election leader acquisition (explicit `/telegram-connect` or session auto-start), `Locks.resetDamagedTelegramRuntimeState` takes the shared `state.json` transaction guard and validates the envelope, every profile's `transport` section and, through the composition root, every `workspace` and `admission` section. Valid state is never rewritten. Damaged JSON, an unsupported envelope, unknown sections, invalid section evidence or a non-private/non-regular file is atomically replaced with `{ version: 2, profiles: {} }`; acquisition then proceeds normally and one `lock`/`state-reset` diagnostic is recorded. Filesystem access errors are not damage and still refuse. Follower elections never reset.

The reset deliberately forgets every profile's polling cursor/journal pointer, bindings/slots, unfinished Restore/temporary facts, admission/deletion fences and Workspace evidence; no backup, import, merge or replay is attempted. Pi history, `telegram.json` and the released `tmp/telegram` are untouched. Orphaned session journals follow the normal sweep. If another live leader was using the damaged file, its own ownership checks fail closed and stop its polling; any remaining competing `getUpdates` client is handled by the existing persistent-conflict stand-down rather than by another reset. Old Telegram tabs/messages may remain and are not cleaned up. Ordinary readers and section mutations still refuse damaged state without repair; only this pre-acquisition step resets it.

### Persistence I/O Baseline

The runtime sections and log have different authority and write pressure. Preserve that distinction when optimizing them:

- The `transport` section is safety-critical authority. Acquire, release, takeover, stale recovery, and entry migration mutate it. Since 0.54 the steady-state baseline is zero rewrites: the one- and two-second ownership checks are lock-free reads. Every mutation serializes the full cross-process read/check/write through the shared `runtime/state.json.transaction` guard and replaces only that profile's section.
- The `workspace` section holds recovery-critical thread/capability state. Every explicit thread-store `persist()` builds a semantic snapshot, but an unchanged payload skips directory preparation, temporary-name generation, file creation, and rename after comparing JSON values independently of object-key order and ignoring `writtenAtMs`; array order, value types, and explicit null remain significant, and changed snapshots retain the full atomic replacement path. No-op saves still read and compare current disk state, rather than trusting a cache that could hide another owner's publication. Diagnostics scheduling coalesces requests across a bounded 100 ms window and writes only the `runtime` section (`persistStatus()`, skipped when the JSON value is unchanged), so an idle leader's polling snapshots never rewrite the canonical `workspace` section. Only the exact transport owner commits either section; non-owners reload current state instead of publishing.
- `logs.jsonl` is fail-soft observational evidence, never routing authority. Runtime events admitted in one JavaScript turn batch by captured profile path into one size check, one profile-wide file transaction, and one append while preserving event order. Batching adds no timer or shutdown-loss window; separate profiles remain isolated, and one failed group does not drop another. Scope reset and rotation retain their serialized copy/replace path. The 5 MiB value is a rotation threshold: an authorized writer rotates between batched records before the next record crosses it, so overshoot is bounded to one admitted record plus reset metadata; a writer without reset authority defers rotation to the owner.

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.

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.

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.

### Threaded Mode Multi-Instance Bus

Telegram private-chat Threaded Mode is the public switch for multi-instance Telegram operation. Classic single-DM polling is the base mode. When Telegram private-chat threads are available for the bot, the bridge enables the local leader/follower bus automatically; when threads are unavailable or later disabled, the bridge returns to classic single-DM polling as a first-class mode. Before a non-owner `/telegram-connect` chooses follower registration or singleton takeover, it discards process-local status/capability projections and reads the current owner-published mode: `enabled` registers a follower without a takeover prompt, while `disabled` uses the classic confirmation flow.

Named Telegram profiles are orthogonal to Threaded Mode. The selected profile chooses the bot/session slice (`botToken`, `botId`, `botUsername`, `allowedUserId`) and scopes its durable journal cursor, its `state.json` profile entry (transport, Workspace, admission, runtime), its log labels, thread/bus ownership, and leader/follower IPC endpoints; it must not change the Threaded Mode rules. Within one selected profile, leader/follower election, bus transport, thread provisioning, routing, ownership forwarding, cleanup, and runtime diagnostics behave exactly as they do for the `default` slot. A different selected profile is a parallel bot runtime: its `state.json` profile entry, profile-labelled log records, hashed service journals, thread bindings, Unix sockets, and Windows named pipes are isolated from the default profile and other named profiles while shared bridge settings remain top-level/global.

Profile reality follows three explicit storage classes. `telegram.json` shared settings and extension registries are process-global platform configuration; `profiles.default` and `profiles.<name>` bot/session fields plus observable transport/routing authority are profile-scoped; queues, active turns, ownership caches, menu state, and runtime controllers are session-local memory. Config persistence serializes cross-process writers and applies each recursive mutation delta to the latest disk snapshot, so unrelated global/profile updates do not stale-replace one another. Each profile's journal transaction independently publishes its monotonic admission cursor together with admitted work; polling never writes runtime state through config persistence. Runtime profile switching follows stop-old/commit-new ordering: reload keeps the selected identity stable, old polling/lock/bus teardown finishes while all dynamic resolvers still point at the old profile, and only then may activation expose the new token, lock key, state path, target namespace, and IPC endpoint. Downloaded attachments are flat `kind-scope-messageId[-index][-name|.ext]` files under `tmp/pi-telegram/attachments` and are session artifacts rather than identity or routing authority. The scope is the bot username (else bot ID) for the bot's private chat, a group username or numeric ID, and for Guest Mode the remote peer's username or numeric ID, because guest message IDs belong to the peer chat. Scratch cleanup removes regular files older than 24 hours. It never age-deletes journals, ownership, state, logs, or other top-level runtime files and therefore cannot redirect live traffic or orphan immutable journal segments.

When Threaded Mode is active, the current polling owner is also the Telegram bus leader. The leader owns the local bus endpoint (Unix-domain socket on Unix-like platforms, named pipe on native Windows), polls `getUpdates`, performs direct Bot API calls, records follower heartbeats, prunes stale followers, and provisions Telegram UI thread targets through live runtime/bus state. Followers heartbeat every `1s`; the leader uses a `15s` stale grace and a `1s` prune loop so transient IPC stalls do not create false routing gaps while active forwarded updates/API calls still refresh liveness. Heartbeat pruning is silent liveness bookkeeping and does not send a Telegram-visible disconnected notice, because the common cause may be leader reload or IPC handoff rather than a dead follower. Heartbeat pruning alone preserves stored owner records and Workspace bindings. The same leader can retain bounded, non-routing observations of actually registered PID/generation/target tuples for later absence proof and retry of uncommitted preservation; the [pruning contract](./multi-instance-bus.md#follower-heartbeat-is-missed) owns cancellation, admission identity and lifetime limits. When Thread cleanup is enabled, only a subsequent OS check that confirms the exact registered PID absent may create fenced cleanup intent, serialized ahead of replacement registration. With cleanup disabled, that proof instead permits a profile-admitted, fenced non-destructive detachment: the store removes the uniquely matching owner record and records first inactivity while retaining the exact Workspace binding and its letter. Publication rechecks PID absence, runtime generation, profile, leader epoch, replacement registrations and the record snapshot; missing or ambiguous restoration identity blocks it. The Thread and its messages remain untouched, accepted-work protection remains independent, and no deleted-Thread observation is invented. Successful follower target reuse refreshes the binding and clears inactivity. Durable Workspace bindings remain restoration hints after detachment; heartbeat silence or unverifiable process evidence cannot stamp inactivity. If an authenticated live follower carries an exact target that is absent from current bindings, the leader recovers it only behind a synchronous visibility probe: success activates it, explicit stale evidence provisions a replacement, and ambiguous failure rejects registration. A carried slot is restored only when it is not already occupied. `tmp/pi-telegram/logs.jsonl` is a session-local redacted runtime evidence stream for race debugging; it resets on extension start and runtime scope changes, and must not become routing/provisioning authority. `tmp/pi-telegram/state.json` is an extension+bot observable/debug snapshot aligned with status diagnostics: `source: "snapshot"` and `writtenAtMs` mark it as observational, not authoritative. All instances on one Telegram profile read the same snapshot, but only the active transport lock owner persists it; followers become writers only after promotion. Status-only persistence reloads current disk bindings before serialization, preventing a stale follower/status view from erasing newer leader-owned targets. Fresh capability observations may skip redundant startup probes, but stale snapshots re-probe before suppressing bus/thread behavior. Top-level `bot` mirrors bot-wide capabilities such as thread mode, `runtime` describes process role/status, `liveRoster` mirrors followers/current targets/reservations, `diagnostics` mirrors recent status/debug signals including the latest thread-reconciler phase/counts, `threads` stores current routeable bindings, `workspaceBindings` stores profile-scoped normalized exact-`cwd` target/name/slot reuse hints, TTL-bounded reservations explain short-lived slot collision guards, and TTL-pruned `pendingProvisions` protects in-flight topic creation slots from cleanup/allocation races. Fresh provisioning writes pending state before the Bot API create call, adds the returned target to the pending record, persists a `starting` binding, then promotes it to `active` and clears pending state. If final binding persistence fails after Telegram returns a thread id, the targeted pending provision remains as cleanup/retry evidence. Once targeted pending provisions expire, they are retained for `thread-reconciler` close/delete cleanup and pending scratchpad removal after a successful cleanup apply; untargeted expired pending records can prune without cleanup because no Telegram thread id exists. Runtime events coalesce status-snapshot writes so transient bus/API/update failures remain inspectable even when the operator has not opened `/telegram-status`. The bridge must not keep a durable `telegram-targets.json` target history; stale/offline/failed thread observations are pruned instead of reused. Previous-process leader bindings that still probe alive become reservations/collision guards, not routeable active threads, so a reloaded leader can take the next free slot without duplicating the same visible tab name. The thread chat is always the private bot DM with the paired owner (`allowedUserId`). In Telegram private-chat Threaded Mode, the leader creates/reuses its own thread before polling — it is a real bound instance, not a dispatcher. Followers authenticate bus envelopes with the leader-minted capability secret stored in the active lock entry. Bot capability monitoring does not probe through the bus until the process either owns that direct lock or has completed authenticated follower registration. Leader lock entries also carry a stable `leaderEpoch` minted on acquisition and preserved across heartbeat refreshes; leader-owned cleanup/provisioning plans stamp that epoch, and Thread Reconciler apply skips destructive work if leadership has moved on before side effects run. Followers own their own Pi session state, queue, active turns, previews, menus, and lifecycle hooks, but route allowlisted, target-scoped Telegram API calls through the leader. When a follower promotes after heartbeat loss, status/state diagnostics expose only the transient `electing` lifecycle phase; stable `leader`/`follower` identity stays in the bus role so diagnostics do not duplicate role state. The TUI status bar and `/telegram-status` report `leader` or `follower` role so a registered follower is not shown as generically disconnected. Terminal status identity and the `[telegram|thread:name]` prompt label use the same target-aware current-instance resolver: registered local metadata wins over a stale shared binding for the matching target, while the binding remains a fallback for partial metadata.

Fresh follower binding is manual and process-first: the operator starts another Pi process, then runs `/telegram-connect`; only then may that process allocate a profile-scoped normalized exact-`cwd` Workspace identity and cause the leader to create a Thread. A later process reopening that remembered Workspace automatically sends capability-gated restore-only admission under a live leader. The leader may reclaim, visibility-probe, or stale-replace the remembered target, but an absent binding returns quietly without creating a Thread. `/telegram-connect [profile] as=Name` supplies a unique capitalized Latin-word identity only to fresh Workspace provisioning; an existing Workspace keeps its persisted name. Telegram `/name Name` stores the owning Thread's durable `manualThreadName` and immediately applies it over the active automatic display projection; bare `/name` opens five-minute exact-target input whose next valid text is consumed before agent dispatch. Name input, cancel, and reset are consume-once; stale scope, target, message ID, expiry, and duplicate callbacks cannot mutate. Reset clears only the override and restores the current automatic projection. Leader command routing reuses its already-held profile admission for the rename body rather than recursively entering the non-reentrant Workspace gate; standalone leader renames acquire their own admission. Followers send an authenticated exact-generation `workspace-thread-rename-v1` request, and the leader owns any Bot API mutation plus durable binding persistence. Concurrent processes from one directory receive deterministic Workspace suffixes, while leader/follower roles remain transient projections over that durable identity. Telegram does not expose `/thread`, auto-spawn arbitrary unbound threads, or launch hidden follower subprocesses. In Threaded Mode, `/telegram-connect` does not offer manual takeover while a live leader exists; takeover is reserved for stale-leader election/recovery. Leadership remains an ephemeral transport role that another live follower can take over after stale heartbeat detection. A confirmed runtime transition from Threaded to Singleton stops threaded transport and suspends the process-local leader target before classic polling can accept new work; durable Workspace slot, generated name, manual display name, and binding evidence remain retained. Re-enabling Threaded Mode restores or replaces that logical binding before publishing one new live target. Already-admitted turns keep their captured destination and are never silently retargeted or duplicated.

### Unbound Thread Detection

For ordinary unbound prompts outside the source-bound temporary lifecycle below, Threaded Mode can expose a new thread without an existing instance binding when the owner writes in `All`. The bridge detects this during update execution: if a message from the owner has a `message_thread_id` that no instance owns, the message is routed to the unbound-thread handler instead of the leader's normal message handler. In the default runtime, this handler first reclaims the thread for the leader when the leader has no active bound thread, assigns the current leader thread identity, persists the active binding, and serves the prompt locally. If the leader already has an active thread, the handler preserves the prompt in the source Telegram thread and shows the complete forward plus replace/restore chooser. Successful forward deletes the chooser and closes/deletes the confirmed temporary source through `thread-reconciler` proof-before-delete planning and stale-epoch fencing. Successful restore always deletes the chooser, rebinds the source thread to the selected Pi instance, and closes/deletes only that instance's replaced old thread. If foreign batch forwarding partially fails, retry sends only the remaining messages before cleanup. If Telegram cannot confirm thread or chooser deletion, the chooser becomes a cleanup-only or deletion-only retry control so already-routed content never dispatches twice and no visible button expires prematurely. Unknown `forum_topic_created` service events are recorded as observations and are not destructive cleanup proof, because Telegram can deliver creation events before local provisioning/binding writes become visible across reloads. If Threaded Mode is unavailable, the message is processed normally through classic routing.

Unsettled plain-text choosers retain their route control while the journal source is deferred: creating a later chooser does not prune them after 30 minutes. Selected routes that still owe cleanup likewise keep their retry control. Age alone neither abandons nor dispatches a source; only the positively armed source-only lifetime below permits its exact expiry disposition. The existing 100-chooser capacity bound refuses additional allocation rather than evicting unresolved work. The production source-bound All-command path keeps its original deferred after chooser publication and uses the temporary lifecycle below. A compatibility chooser remains for callers without the required authority/store/transport composition; it retains its older publication-completion and command-expiry semantics, not the new temporary-tab guarantees. Historical orphaned originals stay held; no owner recovery path is scheduled.

The journal owns the `abandonPending` primitive for exact unclaimed v1 sources. It first writes the original entry and requested operator disposition to a private, content-addressed `<journal>.retained/abandon-<digest>.json` evidence copy, then atomically removes the active entry and publishes the existing `legacy-custody` discard tombstone in the journal. The copy alone is not proof of cancellation: the journal disposition is the commit authority. The tombstone prevents duplicate admission by current and 0.51.6 v1 readers without a schema change, fabricated execution failure, or task-completion claim. Retention survives journal compaction; archives are not executable journal sources. On POSIX, copies use mode `0600` and newly created directories `0700`; Windows uses the existing journal permission mechanism and inherited ACL boundary.

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.

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.

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.

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.

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.

Historical classification cannot rely on a clean v1 pending entry alone. The native integration test `Historical pending source alone cannot prove no follower acceptance` holds the acknowledgement after durable recipient admission, then revokes the source generation: reopening the source yields exactly its pre-forward snapshot, with no queue receipt, owner, input claim or provenance, while the recipient still owns admitted input. A topic-created reply marker does not distinguish those histories either. This demonstrates an information boundary, not that the reporter's particular inputs were forwarded. Recreating a chooser after startup cannot supply the missing historical evidence. Each worker generation now records all update IDs in its first fully validated journal snapshot before batching or execution. Without retention evidence, those sources cannot acquire ordinary fresh-cancellation capabilities, including through a newly published chooser or direct worker call. The baseline is not advanced on read/validation failure and is renewed for every generation; entries arriving before the first valid snapshot are conservatively included. Later admitted pending inputs retain normal cancellation, and independently protected retention attempts retain exact recovery. This fresh-cancellation fence does not establish non-delivery. Historical prior recipient acceptance remains unknown; removal of its review UI grants neither cancellation nor replay.

Production leader admission composes routing's narrow historical classifier; follower custody never enters this classifier. It selects supported private plain-text startup inputs with no currently live bound Thread (also protecting them when Threaded Mode is unavailable). It does not infer deletion or repair bindings. Eligible raw unsupported commands/media/unknown historical private-Thread originals without receipt/claim/provenance authority receive a distinct `retain` verdict regardless of whether their target is bound or Restore/temporary membership survives. This operator-approved policy stops ordinary bound startup dispatch for that subset; same-kind live arrivals stay outside the startup census and dispatch normally. Business, forwarded and known owner-bearing sources keep their existing owner paths. Holding is evidence protection, not sender authorization; it exposes no historical-review UI. Missing routing authority or unreadable Thread state fails closed. The domain-owned `shouldReviewHistoricalInput` classifier receives detached v1 pending evidence, the context and abort signal before any companion/default handler runs. Generation, context, journal binding, transport and exact source evidence are rechecked across its await; classification/read failure does not fall through to dispatch. Boolean true selects legacy `historical` review/spending; `retain` installs a separate `retained` claim, also included in `historicalClaimCount`, without a journal mutation or invented cancellation intent. Retain-only sources cannot be cold-spent, recovered through historical retry, generically cancelled or claimed by grouped queue outcomes. An exact acknowledged chooser clock has its own operator-approved expiry policy below; no clock is inferred from age alone. Each classifier receives detached evidence and its verdict is source-rechecked before installation. Each new generation must classify them again. Routing can also report a last-boundary historical hold if ownership changes after early classification: this suspends the carrier, refuses prior selection/queue reports, and cannot be requested retroactively after the handler returns. Its source-kind predicate receives detached original evidence through the current worker capability; a handler projection that strips forwarding/media metadata cannot manufacture eligibility. Predicate calls and their results remain generation-fenced. The native update-plan boundary recognizes only that exact carrier's acknowledged terminal hold; intentional suspension must not become a retryable execution error.

`inspectTelegramHistoricalInputs` remains a package-private bounded worker capability requiring a fresh current carrier and caller authority; it scans neither archive directories nor journal files. Ordinary abandonment still rejects historical sources, and late or grouped queue outcomes cannot steal their claims. The Historical inputs main-menu entry and historical review/Stop retrying submenu are removed. The reserved `reroutecancel:history:` prefix consumes old controls with an unavailable answer, never forwarding them to companion handlers or Pi, reopening a view, acquiring mutation admission, or abandoning a source. Held originals remain unchanged; this UI removal adds no expiry, retention intent or Thread deletion. Existing interrupted private-retention attempts still use the separate Pending cancellations review, which warns that previously accepted work may continue. Native worker and cold-router tests cover retired list, selection, confirmation, paging and refresh controls. Cross-domain IPC fixtures lose an ACK after recipient admission and prove that removal leaves uncertain source evidence and independently accepted recipient work intact. Protected-attempt recovery is tested with a supplied interrupted-retention precondition, not a retired UI grant. A production-root fixture proves that the normal menu omits Historical inputs while retained Restore originals remain held. Newly confirmed eligible prompt choosers now use the source-only lifetime described below; historical evidence never acquires a fabricated deadline. Elapsed time never proves non-delivery; the explicit chooser expiry policy below may end donor attempts without that claim and separately license fully resolved disposable-tab cleanup. The operator accepted this behavior in the operator's 0.52.0 live smoke.

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.

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.

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.

#### Temporary Thread Multi-Input Lifecycle (Approved Design)

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. Mobile clients sending from `All` first create an implicitly named native tab and then deliver the input itself to `All`: an `All` input whose text starts with the name of such an observation from the same exact scope, created at most ten seconds earlier, registers that native tab as its temporary tab through `registerImplicitTemporaryThread` instead of creating a second one, and renames it once to the routing name. 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.

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.

- `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.
- `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.
- `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.
- `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.
- `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.
- `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.

#### Restart As A New World (Operator-Approved, Implemented Locally)

A Pi process restart starts a new routing world. Unfinished routing from the previous process is not restored, reconstructed or announced:

- `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.
- `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.
- `Unfinished Restore`: The intent is forgotten. Already committed canonical binding changes stay as they are, without rollback.
- `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)).
- `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.

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.

The routing identity split is deliberate:

- Live routing owner: `instanceId` from the currently registered follower/leader runtime. A live instance may have only one active bound thread; provisioning a new target removes older current-state bindings for the same `instanceId` and closes duplicate Telegram threads when possible.
- Current binding owner: explicit `owner` metadata (`leader`, `manual-follower`, or API-level pending thread creation) plus cwd/thread-name metadata; string compatibility keys are derived internally and must not be the persisted source of ownership truth.
- Instance slot: extension-owned single-letter `A`-`Z` ordering metadata. New instances advance through the alphabet and wrap after `Z` only to a free slot; live concurrent instances are capped to available alphabet slots rather than duplicating occupied letters. The compact `bot.lastSlot` cursor persists while its binding remains live/recovering, including true `Z → A` wraparound. When post-grace follower compaction removes the binding represented by the cursor, the same reconciliation pass realigns it to the newest-created remaining live binding so removed historical followers cannot dictate fresh allocation; unexpired pending provisions and reservations remain collision guards. Other thread deletion paths may intentionally preserve an orphaned cursor to continue ring sequence.
- Instance thread name: durable human-facing Workspace metadata that replaces slot-only thread titles. Fresh threads choose an unused baked 4-6 letter Latin-word name, excluding current records, dormant Workspace bindings, and pending provisions; exhausted per-slot palettes fall through the remaining curated names rather than duplicating a reserved identity. Telegram-originated prompt prefixes expose this label, never follower/leader roles or generic seeds. Renaming a live target updates its matching Workspace binding.
- Telegram destination: `TelegramTarget` as `{ chatId, threadId? }`, where `threadId` is Telegram `message_thread_id` for UI thread targets.

Guest-mode updates are owned by the current transport leader by default in Threaded Mode. Guest queries have no Telegram thread binding and no local follower identity, so the leader queues and answers them unless a future explicit guest-owner policy is added. Followers may still transport `answerGuestQuery` through the leader for replies to work if a guest turn is ever delegated deliberately, but implicit guest routing does not pick an arbitrary follower.

All inbound updates are gated by the configured authorized user id.

## Core Flows

### Inbound Turn Flow

1. Poll updates through `getUpdates` under the polling owner's request budget.
2. Validate and atomically journal each complete response batch before advancing its offset once.
3. Signal the independent source-bound worker and begin the next poll without awaiting semantic execution.
4. Run stable public raw-update handlers in registration order, then authorize and route retained built-in traffic.
5. Coalesce media groups, likely split long text, and one adjacent forward-plus-comment pair in either order when needed.
6. Download files with size limits and partial-download cleanup, then run configured/programmatic inbound handlers.
7. Build a prompt or control queue item carrying an exact durable receipt for every contributing update id.
8. Remove local prompt journal authority synchronously immediately before `sendUserMessage`, so session/process replacement can lose an unstarted prompt at that narrow crash boundary but can never replay a prompt already admitted to Pi; controls and foreign forwarding retain their explicit settlement boundaries.
9. Handle `edited_message` updates separately while the original turn is still queued and dispatch only when all safety gates are clear.

Attachments stream into private unique `.part` files and publish by rename only after complete, size-checked download. Windows `EPERM`/`EACCES` sharing failures allow at most six rename attempts, with abortable `50/100/200/400/800 ms` waits; no metadata/content HTTP request is replayed. Non-Windows, non-sharing and exhausted errors propagate, cancellation stops retries, and failure removes the partial file without deleting the existing target. This is attachment publication policy, not a journal/state recovery rule or strict Windows evidence.

#### Durable Admission And Recovery

Here, **durable** means recovery across ordinary process exit, crash, kill, and replacement after a successful atomic rename is visible to the filesystem. It does not promise survival across host, kernel, filesystem, storage-device, or power failure: journal and offset publication do not call `fsync`/`fdatasync`, and parent directories are not flushed. A host-level failure may therefore lose a recently acknowledged rename despite correct process-level ordering. Operators requiring that stronger boundary must place the agent directory on storage with an independently managed durability/backup policy; `0.28.0` must not be described as power-loss durable.

The profile-scoped journal separates transport progress from semantic progress. Polling and local leader/classic admission use the owners-named journal, normally `tmp/pi-telegram/sessions/<id>/inbox[.<profile>].json`; active follower recipient custody uses `sessions/<id>/journal.<recipient hash>[.<profile>].json`. Existing root custody and missing-session compatibility are retained, not migrated. See [Session-Owned Journal Storage](./multi-instance-bus.md#session-owned-journal-storage) for path selection, succession and sweeping. The selected post-v1 storage design is one revisioned compacted snapshot plus immutable atomic transaction segments beside it. Existing v1 files load as implicit revision `0`, while positive snapshot revisions are explicit. Immutable revision segments publish privately and atomically under the existing journal transaction lock; exact repeats are idempotent, while gaps and conflicting duplicate revisions fail closed. Each segment carries one complete mutation, and readers reconstruct ordered upserts, removals, and operator-disposition state only from revisions newer than the snapshot. Malformed or gapped segments, filename/revision disagreement, and foreign journal identity fail closed. Compatibility recovery for the former broad temp-cleanup bug rebuilds a missing snapshot when its complete revision-1 segment chain removes known base authority before any upsert and reconstructs to an empty journal, and repairs a revisionless snapshot when the first surviving segment supplies its exact positive predecessor revision and the reconstructed tail validates. If repair fails, the transaction-locked loader follows the operator-approved corruption policy: it deletes the damaged segment directory first, then atomically replaces the snapshot with a fresh empty private journal (a non-file snapshot path is deleted), records an informational recovery event listing the deleted paths, and continues startup. Damaged inputs are lost by design; no `recovery/` quarantine is created. Deleting segments first prevents stale segment replay beneath a fresh revisionless snapshot. A crash or failed publication can leave an absent snapshot or the old damaged regular snapshot; deleted segments are not restored, and a later read may reset again. Private `.retained` originals are not touched by this reset. After the initial snapshot, append, batch completion, queue receipt/owner/handoff, retry/terminal, recovery, and operator dispositions publish only changed upserts/removals and disposition replacement in one segment. This avoids rewriting retained raw updates during completion-heavy drains without splitting exact queue, failure, recovery, or disposition transactions.

Compaction runs under the journal transaction lock when either 256 unapplied segments or 4 MiB of segment bytes is reached. It publishes the complete private (`0600`) snapshot at revision `R` before best-effort deletion of segments `<= R`; failed cleanup leaves redundant segments that readers ignore. Interrupted cleanup therefore leaves either an older snapshot plus newer authoritative segments or a newer snapshot plus harmless redundant older segments. Revision gaps, conflicting duplicates, malformed segments, and identity mismatches fail closed. The logical reconstructed journal and aggregate unapplied segment bytes are independently bounded at 10,000 entries and 32 MiB as applicable; rejected growth publishes neither snapshot nor segment bytes. Compaction may temporarily require exactly one private complete snapshot of at most 32 MiB. Capacity pauses polling without deleting or resetting valid authority. The separately approved slotless session-family sweep can delete valid recipient families; it is not a capacity-recovery or settlement path. Only a history that cannot be reconstructed safely uses the delete-and-reset fallback above.

`pending` entries remain immediately executable while raw interception, routing, or grouping is incomplete. Execution failures become `retry-wait` with durable attempt count, next eligible time, failure class, bounded summary, and latest failure time, except that an exact HTTP 400 stale/deleted Telegram thread error carrying its proven request `{chatId, threadId}` terminally settles the currently executing source after shared binding invalidation; follower settlement remains idempotent when the leader already persisted that stale binding. The `failed` state remains schema-compatible only for legacy candidate journals and is converted to automatic retry during lifecycle startup. `queued` entries carry exact prompt/control receipts plus the acquiring Pi runtime instance, OS pid/birth identity, session generation, acquisition id, and acquisition time. Queueing alone is never completion.

Queue receipt ownership is independent from the Telegram transport lock. A same-instance, same-process generation may reconstruct its local receipt across a fenced session replacement and may settle it after transport ownership moves. A different process reports the receipt as foreign, never republishes it into its local queue, and cannot complete it even if it reads the acquisition id. Startup no longer treats process replacement as proof that an owner died: foreign and legacy unowned receipts remain durable.

Cleanup and live handoff are compare-and-set under the journal transaction. Queue discard during exact queue-lifecycle cancellation requires the exact local owner/acquisition and removes all receipt sources atomically. Before admission worker start, the lifecycle groups each foreign receipt and asks the journal to recheck OS pid liveness plus process-birth identity under the same transaction; a live owner returns `owner-alive` and a live owner without stable birth proof returns `owner-unverifiable`, both without mutation, while exact negative proof atomically discards the complete session-owned receipt without replay. Replacement registration carries its exact pid/process-birth before this check; when registration and cleanup race, that live identity wins the liveness proof and the queued receipt remains untouched. A replacement or unrelated worker therefore never executes queue work whose prior owner is proven dead.

Authenticated live handoff uses journal CAS plus bounded local IPC. The donor creates a one-time high-entropy token and durably offers the complete receipt to one exact recipient runtime/process/session identity; the journal stores only a digest bound to queue kind, receipt sources, donor acquisition, and recipient identity. While offered, donor completion/discard and dead-owner recovery fail closed, so authority cannot disappear during payload transfer. Prompt payloads carry all queue fields; control payloads carry only their stable `status`/`model` identity and rebuild executable closures locally. The separately negotiated `queue-handoff-v1` capability gates this envelope for leader and both peer generations. Each receipt carries its exact source journal binding; the donor derives the recipient follower-journal binding from the authenticated stable follower profile before routing. The bus validates payload shape/size and exact donor/recipient registration generations, and the recipient selects only that matching active lifecycle, stages one complete receipt idempotently, accepts the journal CAS, and returns the exact receipt plus newly minted owner in its ACK. Malformed, legacy-unbound, inactive-generation, or unavailable bindings fail closed.

During recipient staging, presenting the token atomically replaces the journal owner with a fresh acquisition carrying the handoff digest, removes the offer, and permanently fences donor settlement. The donor treats only an ACK carrying that exact accepted owner as success and never repeats acceptance against a donor-bound journal runtime. The recipient can repeat the same acceptance idempotently; a different token cannot claim an already accepted receipt. The coordinator contract orders offer → stage/accept exact receipt-and-owner ACK → donor removal → recipient readiness for direct leader→follower and follower→follower routing. Before acceptance, negative or mismatched acknowledgement exactly cancels the offer and keeps donor work. After acceptance, a lost acknowledgement cannot roll authority back: cancellation fails closed and donor memory remains frozen until exact accepted-owner reconciliation removes it. Recipient registration carries exact process-birth/session identity, and staged payloads remain outside the live dispatch store until accepted journal authority has been reconstructed. Production advertises `queue-handoff-v1` only with this exact role/journal selection and uses the same coordinator ordering for direct leader→follower and follower→follower routes.

Queued semantic authority has no elapsed-time lease. A timeout cannot prove either owner death or effect quiescence, so it cannot safely resolve a receipt. Resolution is limited to authenticated live handoff, exact owner discard/settlement, or transaction-rechecked negative PID plus process-birth evidence that permits terminal cleanup without replay. Live or unverifiable owners remain queued rather than risking duplicate or cross-session execution. Workspace pressure may request the same terminal dead-owner cleanup only after full `A`–`Z` allocation failure, current inactive-binding authority, complete strict source enumeration, no local/live/delivery authority, whole unoffered same-target receipt groups, and preflight death proof for every group. Journal CAS remains the mutation authority. Partial success or interruption is safe progress only: a fresh all-clear protection capture and normal retirement fence are still mandatory before Thread deletion.

The initial `offset: -1` cursor bootstrap is allowed only when both cursor and journal are absent or empty. Thereafter process-level ordering is journal atomic rename → one monotonic offset atomic rename → worker signal. Failure before journal publication leaves the offset unchanged; failure after journal publication but before offset publication permits Telegram redelivery and journal dedupe; failure after offset publication but before worker signal replays from the journal on restart. Queue-owner, retry, terminal, handoff, and completion transitions use the same journal publication primitive and therefore share this process-crash boundary. The final completion window is at-least-once, so replay-sensitive external effects must use `update_id` or the stable delivery id as an idempotency key.

Threaded Mode forwarding is a two-journal handoff. Only peers that share the current base protocol and mutually advertise `durable-follower-admission-v1` may route or become election-eligible. The follower validates its exact binding and registration generation, durably appends the source-bound delivery, and only then returns the exact receipt. The leader classifies each attempt as `accepted`, `retryable`, or `terminal-rejected` with its delivery identity and failure class; only `accepted` with the expected `deliveryId` and `sourceUpdateId` may complete leader journal authority. Missing, negative, stale-generation, or mismatched-receipt acknowledgements remain durable, and a callback error answer is only an operator-facing side effect. The follower's bounded [delivery replay window](./multi-instance-bus.md) acknowledges a repeated `deliveryId` without re-execution.

Delivery ids derive only from envelope kind, source `update_id`, and stable recipient binding. Live registration generation remains a separate attempt fence. Message ownership carries the stable binding and rebinds to its current authenticated follower registration after replacement. `ownership.getForwardOwnership()` projects the protocol identity from the exact matching live instance, registration generation, and binding on every lookup; protocol is not cached with message history. The same port serves messages, edits, callbacks, and reactions, including callbacks without a Thread ID. If a cache lookup returns a foreign record but no matching durable-capable protocol can be projected, that record remains foreign and fails forwarding validation rather than falling through to local execution. The final bus validator independently rechecks generation, binding, and complete protocol identity before transport. Lost acknowledgements therefore retain the same delivery identity; only the exact durable receipt completes the source. Package build skew is allowed only while protocol version and capabilities remain compatible.

Worker execution ownership is per `update_id` across same-runtime generations. Aborting a generation ends its authority but does not prove its handler settled; replacement replay remains blocked on that exact settlement. Late success and failure are both diagnostic events. Public and built-in handlers receive the same optional execution fence (`signal`, generation/update identity, and pre-effect assertion); the runtime binds it non-enumerably to every internal update carrier and checks it before routing-plan effects. Prompt construction rechecks after downloads and inbound handlers before queue mutation, pairing rechecks around persistence, command/menu and extension-command delegation retain the source fence across detached effects, lifecycle sync rechecks after store load before reconciliation, and reroute clones carry the source fence through forwarding, thread replacement, cleanup, persistence, and Bot API rename boundaries. Legacy handlers remain source-compatible but must not commit unfenced late effects.

The canonical update transition contract is:

- `pending → executing`: the generation-local worker selects an unclaimed source; `executing` is a runtime phase, not a separately persisted entry state.
- `executing → completed | queued | pending | retry-wait`: exact local completion removes the entry, queue admission persists its receipt, deferred grouping retains replay authority, and every execution failure persists retry evidence.
- `retry-wait → executing`: only after `nextRetryAtMs`; repeated signals before eligibility do not execute the entry. Automatic retries continue indefinitely with exponential `1s → 2s → 4s → 8s → 16s → 32s → 60s` delay capped at `60s`, while later independent updates continue draining.
- Legacy `failed → retry-wait`: startup atomically resumes terminal entries written by earlier `0.28.0` candidates. Ordinary execution/retry policy never silently discards valid inbound authority and exposes no Pi command for manual retry/discard. Approved damaged-history reset and disposable-session sweeping are separate storage-loss policies, not successful execution or receipt settlement.
- `queued → offered → staged → queued`: only the exact persisted donor may offer or cancel a live handoff; an offer preserves donor ownership but freezes ordinary settlement and recovery. Authenticated bounded IPC stages one exact payload/receipt outside the live queue. Exact recipient acceptance mints a fresh acquisition, reconstructs local ownership, removes donor work, then publishes recipient dispatch readiness.
- `queued → completed`: only the exact persisted owner receipt may complete or discard queued sources; generic completion rejects queued state. Process-birth-proven owner death atomically discards the complete unoffered session-owned receipt without replay; live, unverifiable, or offered owners remain queued.

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.

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.

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.

Long-text split recovery remains conservative: only human text at or above the near-limit threshold opens its debounce window. Forward annotation has two semantic layers: the forward owns its source text/caption/media, while an optional separate owner-authored annotation normally precedes it. A bounded one-second pairing window joins that annotation and adjacent forward in either transport order, including a media-only forward without source caption text; the matching opposite-kind message flushes immediately. Same-kind rapid messages, commands, bots, ordinary non-forward captions, media groups, different senders/targets, reversed ids, and distant message ids do not enter this pairing path. Prompt construction always places the owner annotation first, followed by `[forward|from:...]` with the forward's own source text/caption, then source-attributed forwarded attachments, regardless of arrival order.

### Queue And Dispatch Safety

The bridge keeps its own Telegram queue. The Pi status bar's yellow `+N` suffix projects only executable prompts still waiting: current agent work from Telegram, terminal, or autonomous sources never contributes, and the dispatched Telegram head is subtracted while it remains retained pending `agent_start` consumption.

Queue items have two explicit dimensions:

- `kind`: `prompt` or `control`.
- `queueLane`: `control`, `priority`, or `default`.

Dispatch rank:

1. `control` lane.
2. `priority` prompt lane.
3. `default` prompt lane.

#### Priority, Reactions, Keep, and Skip

Waiting Normal/Priority prompts expose two independent dimensions:

- `Priority` / `Normal` selects the FIFO lane and therefore scheduling order.
- `Keep` / `Skip` selects whether the prompt executes when dispatch reaches it.

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.

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.

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.

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.

Guest Mode is the deliberate exception to deferred Keep/Skip semantics. A guest prompt has no source message reaction surface and may share zero-valued chat/message placeholders with other guest prompts, so queue-menu callbacks address it by immutable `queueOrder` and expose an immediate `Skip`. The leader settles its durable admission, removes it while other agent work may continue, stops placeholder animation, and replaces the inline globe placeholder with non-printing content. Bot API inline messages have no delete method, so this visual clear is the supported deletion equivalent. The guest prompt never reaches a model turn.

A standalone `/continue` is a source-addressed control-lane prompt, not a Normal/Priority prompt. An authorized negative reaction to its original chat/message immediately settles the exact waiting continuation's receipts before removing it, even while unrelated work is active. Failed or unknown settlement retains it for the existing reaction retry path; duplicate reactions cannot settle twice. Positive reactions and removal of the negative reaction neither change its control lane nor reconstruct cancelled work. The dispatched head awaiting `agent_start` and already-started work are never cancelled; appends and reorders preserve that Pi-owned head. Synthetic model-switch continuations have no source message IDs and are not reaction-addressable by their fallback reply anchor. Reaction authorization and chat/message namespace isolation remain unchanged.

Admission and planning validate lane contracts. Invalid lane/kind pairings fail predictably instead of being silently coerced.

Prompt preparation completes downloads, inbound handlers, and binary image reads before synchronous final assembly and queue commit. Enqueue captures only intended abort-history identities before preparation; afterward it reads the current queue, folds surviving selected prompts using their current text and receipts, allocates the new turn's order, and appends without another asynchronous boundary. The handed-off head remains in place until `agent_start` consumes it, even if preparation finishes first. Concurrent arrivals, removals, and lane/reaction edits remain intact; preparation failure or stale-generation completion leaves intervening queue changes untouched.

Dispatch requires:

- No active Telegram turn.
- No pending Telegram dispatch already sent to Pi.
- No compaction in progress.
- `ctx.isIdle()` is true.
- `ctx.hasPendingMessages()` is false.

A dispatched prompt remains queued until `agent_start` consumes it. This keeps the active Telegram turn bound for previews, attachments, aborts, and final replies. A low-level `agent_end` error also retains that active turn because Pi may retry automatically; a later successful `agent_end` delivers through the original target and metadata, while `agent_settled` proves that an unrecovered error can be finalized once before queue dispatch resumes.

Post-agent-end queue dispatch uses a session-bound deferred dispatcher. It is activated on session start, clears timers on shutdown, and skips callbacks from older generations before touching `ExtensionContext`. Dispatch stays session-bound after polling ownership moves elsewhere. When a queued Telegram prompt is forwarded into Pi, the bridge synchronously commits its exact durable receipt before calling normal `sendUserMessage(content)`; failed receipt commitment blocks dispatch, while the unavoidable crash window between commitment and Pi admission favors at-most-once execution over replay. It does not use Pi's `followUp` delivery option or inject terminal input.

Settlement returns an explicit acknowledgement only after exact source removal is confirmed. Missing readiness, frozen/transferred ownership, observation failure and an unknown completion result are not acknowledgements. The mux resolves every unsettled receipt to its owning runtime before mutation, rejects unknown/conflicting ownership, and requires each completion result; a completed prefix is not whole-request success. A private weak acknowledgement keyed by the original receipt object and its unchanged normalized metadata lets later local discard clean up a confirmed prompt still awaiting `agent_start`, including after worker replacement. It is never execution authority: it neither re-arms dispatch nor survives cloning/serialization, and is not a durable completion ledger. Failed or ambiguous completion creates no acknowledgement: prompt dispatch and bulk clearing retain the local item rather than inferring success from an absent source. This does not establish retention for every internal mutation primitive: direct message-ID removal still updates memory before containing settlement failure. Its former automatic Business-deletion producer was invalid because Business and bot-chat namespaces are independent, and default routing now ignores it. Do not restore that producer or infer private-message deletion intent from matching numeric IDs. The internal explicit deletion plan and helper are not a new automatic deletion capability.

One monotonic session generation also fences agent/tool/message events, compaction callbacks, preview state, scheduled final delivery, controls, and shutdown. Distinct Pi context objects observed within one session adopt that generation; contexts already observed under an older generation remain stale after replacement. Session start invalidates pending preview work, delayed finals check their captured context before delivery, and shutdown rechecks after asynchronous polling/preview boundaries with a bounded preview-clear wait.

For a configured Rich response with final text and exactly one supported queued PNG/JPEG, MP4, or MP3 artifact, queue orchestration asks `outbound-attachments` for one reply-anchored multipart Rich result before finalizing ordinary text. A successful result clears the preview, records exact message ownership, and suppresses duplicate text/file delivery. A known-safe rejection returns to the established paths; an ambiguous send stops the turn without fallback or replay. HTML mode, multiple or unsupported files, Guest Mode, and all voice-policy outputs bypass this optimization.

#### Queue Lifetime

The prompt queue is session-local, not a restart-persistent inbox. Waiting prompts are discarded on shutdown and dead-owner cleanup, and dispatch stays connected-local as described above. The operator excluded restart-persistent prompt storage from 0.52.0 and future plans to avoid unnecessary complexity; it is cancelled, not deferred. Operator rule before any reload or restart: wait for the queue to drain, or knowingly accept losing the waiting work and re-send what still matters afterwards. Nothing is preserved or replayed automatically. Existing durable admission, receipt ownership, custody and anti-replay protections remain unchanged and do not promise reconstruction of the waiting prompt queue.

### Controls And Menus

Telegram controls execute through command/callback domains, not by entering the normal prompt queue unless they intentionally create a prompt turn. Built-in read-only menu commands are admitted once required local state mutation finishes: first-user pairing still persists before `/start` is accepted, while menu rendering and BotFather command synchronization run as context-fenced best-effort effects with diagnostic failure sinks. Their unresolved Telegram calls therefore cannot retain the durable polling offset or prevent the next `getUpdates` request. Detached effects, deferred dispatch/watchdog, typing, and diagnostics callbacks contain primary and diagnostic failure; stale typing context is ignored, while snapshot publication serializes one write plus one retained coalesced rerun. Raw companion handlers still run before durable built-in routing and should return quickly even though their execution no longer retains polling.

Immediate controls:

- `/start` opens the main inline application menu.
- `/model`, `/thinking`, `/queue`, and `/settings` are hidden shortcuts to menu sections.
- `/compact` opens an inline confirmation dialog and then runs compaction when the bridge is idle.
- `/next` dispatches the next queued turn, aborting Pi first when needed. Target-bound command composition must forward the announcement request, exact-turn marker, superseding cancellation, and deferred-dispatch ports rather than silently dropping them. Active-turn settlement attempts its abort notice against the interrupted prompt before queue dispatch continues; definite or ambiguous notice failure is recorded but cannot block the selected turn. The queue owner then emits `Dispatching next queued turn.` against the exact selected prompt's chat/thread/reply id before its one model dispatch; skipped, inactive, pending-mutation, and admission-blocked candidates never receive it. A successful dispatch notice carries its reply-dedup anchor through the following agent-start reset, so later messages in that turn do not repeat the queued-prompt reply header. A later `/abort` or `/stop` cancels both pending `/next` notices before taking ownership, preventing duplicate abort results and stale future dispatch announcements. The `/next` command itself is never a lifecycle-notice reply target. Aborted pending assistant text is not projected as a second reply, while already completed intermediate output remains visible.
- `/abort` aborts active work while preserving queued items. Abort-history preservation is enabled only for Telegram-owned active turns; later local/non-Telegram agent starts clear stale abort-history mode so the next Telegram prompt appends instead of absorbing old queued turns as history.
- `/stop` aborts and clears waiting Telegram queue items.

Queued controls:

- `/continue` creates a Telegram-owned `continue` prompt in the highest-priority control lane. A negative reaction to the original standalone command cancels it only while waiting, with exact durable settlement as specified above.
- Prompt-template commands expand Telegram-safe Pi template aliases before entering the prompt queue.
- Model-switch continuation uses the control lane when any interruptible in-flight agent run in the current Pi session must be stopped and resumed. A Telegram-owned run retains its prompt target; otherwise the exact model-menu chat/Thread/message supplies continuation and reply ownership.

Queue and menu mutations are reachable through Telegram updates handled by the current polling owner. After ownership moves, the old instance keeps processing its accepted local queue, but it no longer receives new menu callbacks or control updates for remote mutation. UI label, navigation, tab, toggle, card, and dialog rules are defined in [UI Style](./ui-style.md). Callback prefix ownership is defined in [Callback Namespaces](./callback-namespaces.md).

### Compaction And Typing Status

Manual `/compact` requires inline confirmation because accidental taps are disruptive. Confirmed manual compaction and auto-compaction both set the bridge compaction flag, block queued prompt dispatch, retain that flag in explicit diagnostics, and clear it on native compact completion or failure, timeout fallback, or session shutdown. Pi owns its terminal compaction lifecycle; pi-telegram keeps `Active` scoped to Telegram-owned work and otherwise preserves the stable connected/leader/follower role. Mid-run threshold compaction reports notices in place between tool output and the next assistant response; compaction observed after terminal assistant output waits for final Telegram delivery so transport chronology matches the terminal.

The five-minute observer timeout releases the local compaction flag and observer-owned typing and requests deferred queue dispatch; it is not Pi completion, cancellation or failure. Pending automatic terminal-notice and Activity correlation survive that timeout so a later native success/failure/cancellation still reports once. A new compaction supersedes the prior correlation; session shutdown discards it. Existing session and transport fences still govern publication.

Native typing during compaction follows connected-instance activity rather than terminal status:

- Confirmed manual `/compact` starts a native `typing` keepalive in the command target and stops it on completion/failure.
- Automatic/session compaction with an active Telegram turn reuses that turn's target.
- Automatic/session compaction without an active Telegram turn uses the connected instance's assigned target; an unconnected instance sends nothing.
- Thread-targeted typing is sent only to the concrete thread. Aggregate `All` mirroring is intentionally omitted because duplicating every keepalive multiplies shared-chat flood pressure. Compaction completion, failure, or timeout stops only a loop actually started by the compaction observer; a pre-existing agent-owned loop remains active. Authority loss and shutdown still stop the keyed loop.
- Pi `ui_prompt_start` pauses typing while an extension-owned local prompt waits for the operator; `ui_prompt_end` emits the matching Activity boundary and resumes typing whenever agent or compaction work remains unsettled.

At every connected instance `agent_start`, the lifecycle binding starts Telegram's native `…typing` indicator in that instance's assigned target, whether the run came from Telegram, the local TUI, or an autonomous continuation such as Grow Loop. Terminal `Active` remains Telegram-turn-specific; the native indicator answers the separate question of whether the instance is doing agent work. Each loop refreshes its exact target every three seconds and keeps one action in flight. The leader API runtime coalesces identical chat/thread/action calls for two seconds, permits at most one concurrent chat action per chat, and shares a Telegram 429 `retry_after` fence across every Thread key in that chat; expired gates prune opportunistically and each gate family retains at most 256 active keys. Suppression never schedules a delayed retry. A failed typing action remains a structured diagnostic but cannot project `error` onto an otherwise healthy connected/leader/follower status. Assistant message start/update hooks still re-arm typing during Telegram-owned turns so transient provider/model errors do not leave a continuing run without activity feedback, and agent/session completion stops it.

### Rendering And Delivery

Rich Markdown is the default model-answer membrane. Complete assistant replies send final Markdown directly as `InputRichMessage.markdown` through `sendRichMessage` when `assistant.rendering` is `rich`, and through the legacy Markdown-to-HTML renderer when `assistant.rendering` is `html`; guest replies use native Rich Markdown through `InputRichMessageContent` in `answerGuestQuery` results. Reasoning/thinking blocks, menus, status rows, queue controls, settings, diagnostics, and other harness-owned surfaces stay on explicit Telegram HTML/plain rendering, while completed tool activity uses native Rich block objects for visually distinct structured disclosure. Streaming previews may use `sendRichMessageDraft` only when `assistant.draftPreviews` is enabled and draft delivery succeeds. The bridge still strips top-level assistant action comments before delivery and may split output only for Telegram transport limits.

Assistant delivery guarantees:

- Model-authored Markdown is the source of truth; the bridge does not pre-render assistant Markdown to HTML unless the operator selects `assistant.rendering: "html"` for compatibility.
- Before native Rich Markdown delivery, the bridge normalizes known Bot-API-fragile source forms without changing visible meaning, including space-after-marker blockquotes and dollar-prefixed ticker atoms that Telegram may otherwise treat as unterminated math.
- Prompt context blocks use compact metadata (`[tag|key:value]`) as the stable inbound contract. `[telegram...]` names the current surface only: owner/current turns use `[telegram]` or `[telegram|thread:<name>]`; guest-mode turns use `[telegram|guest:<group-title-or-peer-username-or-id>]`. In a private Guest Mode turn the paired owner's `from` identity is never the guest: the remote private-chat identity wins, then non-owner caller metadata, with a non-bot replied peer available only as a final identity fallback when stronger conversation evidence is absent; username falls back to the remote display name and numeric id. Reply attribution still belongs independently in `[reply|from:...]`, and a replied bot can never define or replace the current `[telegram|guest:...]` location identity. Source authors for quoted/forwarded material and their files are carried by `[reply|from:<username-or-id>]`, `[forward|from:<username-or-id>]`, and `[attachments|from:<username-or-id>]`, while plain `[attachments]` remains current-turn attachments and is ordered before reply/forward/source context. Media embedded in inbound Telegram `rich_message` blocks is downloaded like ordinary message media and stays attached to its forward-source block instead of being mislabeled as current-user material. Guest-mode turns append a `[guest]` block to their turn text stating the one-reply/limited-window constraint and instructing a fast, concise, self-contained answer; the note travels with the turn text rather than the system prompt.
- Quoted rich replies use Telegram `rich_message` blocks as the prompt-context source when available, so `[reply]` context receives rendered plain text instead of raw `InputRichMessage.markdown` fallback text. Replied media runs through the same inbound handlers and voice transcription providers as current-message media, with provenance-scoped `[outputs|from:…]` appended inside the reply block.
- Long native Markdown replies are split only at Telegram Rich Message transport limits; oversized fenced code, display-math, and fully wrapped inline-formatting blocks are rewrapped per chunk so persisted Rich Markdown chunks remain structurally valid.
- When Draft previews are enabled, streaming previews pass structurally closed assistant Markdown prefixes through to `sendRichMessageDraft` with ownership checks, voice and guest-turn suppression, and serialized flushes. Telegram Guest Mode allows exactly one answer that cannot be patched afterward, so guest turns never start preview state even while `assistant.draftPreviews` is enabled. Unclosed inline spans, links, fenced code, comments, and display-math blocks are held back until a safe boundary exists. Draft failures are recorded and the failing frame is skipped instead of degrading to raw plain-message previews, because partial Markdown can be invalid while the final message remains valid.
- Preview flushes are serialized so older edits cannot race newer drafts; final delivery waits for active draft flushes and does not perform a post-final draft-clear call. Successful final text delivery clears the local pending preview text only while the captured session and transport remain active, so a late delivery or Rich-attachment cleanup cannot erase replacement preview state.

UI/compat rendering guarantees:

- Bridge-owned UI surfaces such as tool rows, reasoning/thinking blocks, commands, menus, status messages, queue controls, diagnostics, settings, and interactive sections use Telegram HTML/plain rendering helpers by default. These texts are authored for operational UI rather than model output, so explicit HTML/plain markup remains clearer, safer, and easier to maintain.
- In those UI/compat surfaces, real code blocks stay literal and escaped, supported absolute links stay clickable, unsupported links degrade safely, tables use compact monospace rendering with grapheme/display-width accounting, and list/quote/heading spacing stays Telegram-safe.

Final delivery attaches reply metadata only where requested. Reply parameters apply only to the first chunk of split messages; continuation chunks are adjacent normal messages. Media-group turns reply to the representative message id.

### Outbound Artifacts And Assistant Actions

Outbound files staged during an active Telegram turn are delivered after that turn completes but before any separate final text. Final delivery clears an existing preview first so an edited older message cannot appear above a later upload. Files use `telegram_attach`, are checked atomically per tool call, and use configurable size limits before photo/document upload. When no Telegram turn is active, `telegram_attach` sends files immediately to the paired/default chat, an assigned follower thread, or an explicit `chat_id` plus optional `thread_id`; `telegram_message` provides direct local/TUI Markdown text delivery for explicit user requests and runs the same `telegram_button` markup planner so buttons attach to that text message. Direct local/TUI delivery is singleton-controlled: classic mode requires this Pi instance to own `/telegram-connect`, while Threaded Mode followers must be registered and route through the leader-owned transport. Already accepted active-turn reply/attachment delivery remains session-local.

The channel-post journal records only this agent path's own publication intent. `prepare` is exact and idempotent; `beginPublication` durably changes one prepared operation to outcome-unknown before any future non-idempotent send; only `confirmPublished` records the returned numeric channel/message identity. A retry never regains issuance from outcome-unknown or published state. The store validates profile and token fingerprint, refuses malformed/duplicate/over-capacity state, and lists newest retained records without claiming Telegram history. The public-`@username` direct-leader sender now uses the tool-call ID to prepare and begin this journal transition before `sendRichMessage`, then records the returned numeric channel/message identity plus bounded username/title observed by `getChat`. Retained outcome-unknown state refuses automatic replay. Bounded agent-facing listing is available locally. Exact edit/delete journal transitions fence each tool-call mutation as outcome-unknown before direct-leader `editMessageText` or `deleteMessage`, and require the same mutation ID to confirm edited or deleted state. Numeric-channel publication requires explicit `channel: true`; direct-leader `getChat` must prove the exact negative ID and channel type before issuance, and the send response must preserve that identity. Cross-process regressions prove one winner for concurrent publication/edit/delete issuance and no restart regrant. Reads fail closed before parsing links, foreign/loose files, unsupported no-follow platforms, identity races, or oversized input. No legacy post schema is migrated: absent state starts empty and unknown versions/fields fail closed. The 0.44 downgrade checker leaves this inert journal untouched because old code cannot issue its effects. Only an explicit successful list returns retained authored Markdown. Channel publication/list/mutation failures and runtime events use fixed messages without retained content, token, path, or arbitrary transport detail. Production-helper regressions model a lost successful caller ACK and an ambiguous send response: the same operation returns retained success or refuses outcome-unknown without a second transport call. The retry uses a freshly opened replacement store, proving durable behavior across helper replacement/restart. A native entrypoint regression disconnects/reconnects direct ownership and proves both retained success and ambiguous outcome avoid a second `sendRichMessage`. Sender-rights and live rollout evidence remain separate 0.45.0 work. Channel media posts upload one local `.jpg`/`.jpeg`/`.png`/`.webp` photo or `.mp4` video through the multipart transport with `text` as the HTML caption; kind, byte size (photo ≤ 10 MiB, video ≤ 50 MiB), and 1024 visible caption characters are validated before issuance, and unsupported types or albums are rejected rather than downgraded to links. The journal binds the inspected kind/file name/byte size/SHA-256 media identity and caption, so duplicate requests and lost acknowledgements never re-upload. A media-post edit replaces the caption through `editMessageCaption` with the same Markdown-to-HTML rendering, where `||spoiler||` now renders as `<tg-spoiler>`.

Assistant-authored final-message actions use hidden top-level comments, with an additional fenced wrapper for in-body buttons:

- `telegram_voice` accepts one positional compact action cell or JSON object and creates one voice artifact through configured outbound handlers, programmatic voice handlers, or registered synthesis providers.
- `telegram_button` accepts a JSON object, adaptive JSON/CML matrix, or positional Compact Matrix Literal. Named JSON objects and positional cells may coexist, with commas optional only between completed matrix or row elements. Each top-level cell creates one full-width row, while a nested row groups buttons horizontally without an artificial parser-width cap; every callback enqueues its configured prompt text as a normal Telegram prompt turn. The JSON-first grammar, positional trim/escape rules, atomic rejection, and renderer-owned width policy are specified in [Adaptive Button Literal](./compact-matrix-literal.md).

Standalone column-zero triple-backtick `telegram_button` blocks reuse the same cell/matrix grammar and callback store, including adjacent top-level JSON/CML objects as bracketless comma-free vertical rows, and compile to native Rich Markdown button rows between paragraphs. Rendering validates each complete block before registering any callbacks, escapes label text, preserves disabled cells, and leaves larger enclosing fences literal. Previews hide complete and unfinished action fences. HTML mode projects those controls into the footer. In-body callbacks acknowledge without rewriting the Rich message; selected-style highlighting remains footer-only.

Action recognition remains restricted to top-level column-zero comments and exact-name button fences so nested examples cannot trigger voice, buttons, or callbacks. The Telegram surface independently strips every complete assistant-authored HTML comment from previews and final delivery regardless of Markdown position or comment owner; an unclosed comment is withheld through the remaining tail, and a comment-only result sends no text message. Pi's terminal transcript and model context remain unchanged.

Unknown callback data outside owned prefixes is forwarded as `[callback] <data>` only after built-in and extension handlers decline it.

### Generative Apps

The `generative-apps` Skill owns the general Generative Apps concept, application shapes, and hybrid method/prompt model. This section records only how the `pi-telegram` runtime composes that concept into the bridge.

The bridge owns canonical `<agent-dir>/genapps/<app>/<app>.mjs` identity, installation/replacement, bounded runtime ports, state revision/timeline integrity, `app::method` routing before Pi queue admission, ordinary prompt routing through Pi, and Telegram delivery of returned Markdown/buttons. External capability ownership remains outside the bridge.

`telegram_bind` is the agent-facing lifecycle surface. Installation and explicit replacement invoke mandatory `init`; replacement stages and initializes a complete candidate before publishing it under the same app name. During an active Telegram turn, successful Tool output is planned and delivered directly to that exact target by default, and the Tool result suppresses model duplication; `display: false` retains agent-only diagnosis. Outside an active turn no implicit target is chosen. Buttons emitted as `app::method` or `app::method(<strict JSON>)` take the inference-bypass route. Missing apps, malformed actions, stale revisions, invalid output, or method failure fail closed without becoming ordinary prompts.

The concrete runtime and wire reference remains in [Generative Apps Runtime For Telegram](./generative-apps.md). The bundled `generative-apps` Skill owns the concept and agent workflow; `generated-control-surface` owns its separate ephemeral interface protocol; `telegram-bridge` owns transport, target authority, delivery, and general turn operation.

## Extension Surfaces

`pi-telegram` intentionally owns one `getUpdates` loop per bot. `polling` owns that internal loop; `updates` owns classification/default-routing plans plus the public handler registry layered extensions use to observe or consume updates without opening a competing polling connection. Layered extensions should integrate through extension surfaces instead of polling the same bot independently.

- Raw update observation/consumption: [Updates](./updates.md).
- Telegram-native slash commands: `registerTelegramCommand()` from [Public API](./public-api.md#commands).
- Target-aware operational views and chat actions: [Telegram Delivery API](./delivery.md).
- Normalized non-blocking Pi lifecycle events: [Telegram Activity API](./activity.md); the separate [`pi-telegram-extension-demo`](https://github.com/llblab/pi-telegram-extension-demo) project remains the companion-extension reference.
- Structured inline UI sections: [Sections](./sections.md).
- Callback namespace discipline: [Callback Namespaces](./callback-namespaces.md).
- Voice/STT/TTS providers: [Voice Integration](./voice.md).
- Inbound/outbound command-template handlers: [Command Templates](./command-templates.md).

Extension callbacks must avoid `pi-telegram` owned prefixes such as `compact:`, `new:`, `tgbtn:`, `menu:`, `model:`, `thinking:`, `status:`, `queue:`, `settings:`, and `section:`. Workflow-specific Telegram slash commands should use the public command registry instead of becoming new core built-ins unless they are bridge lifecycle, transport ownership, queue safety, or essential operator controls.

The bridge does not mirror arbitrary `ctx.ui.confirm/input/select/custom` prompts from other extensions into Telegram. Companion extensions that need Telegram operation should expose a Telegram-native command, section, settings row, callback, status line, inbound/update handler, or assistant action-markup path instead of relying on hidden TUI-only prompts.

## Diagnostics And Operational Behavior

Deferred diagnostics snapshots are session-owned. Each 100 ms coalesced request captures the exact context/session generation before its timer or queued microtask; a successor requires a fresh request. Shutdown synchronously suspends requests, cancels the timer and drops predecessor reruns, then drains any started publication before cleanup can proceed. Fencing occurs before status projection, not only before publishing the runtime section: its cursor getter uses a journal reader that can create transaction guards or recover a missing snapshot. Already-dequeued callbacks cannot clear a successor timer or recreate retired journal families. Explicit status rendering stays immediate, while its best-effort snapshot request shares the same owned scheduler. The session scope is structural; Status stays independent of Lifecycle and Locks, and neither diagnostics nor its drain grants transport, storage recovery or routing authority. Deterministic removed-directory and snapshot-with-segments regressions guard fixture isolation without sleeps, deletion retries or cursor relaxation; native fixtures are not live or cross-platform acceptance.

Status rendering distinguishes connected, active, dispatching, queued, tool-running, model-switching, and compacting states; the Telegram status menu gives compaction precedence over generic active or pending work. Its compact Tokens row shows only input and output totals, while the adjacent Cache row groups `R` cache-read tokens, `W` cache-write tokens, and `CH` for the latest assistant request's cache-read share of prompt tokens rather than a misleading cumulative-session ratio; the labels remain distinct from companion-provided usage limits. Observed automatic compaction sends the same start and completion notices as the manual command without duplicating notices for command-owned compaction. If no terminal hook arrives, the current observation times out after five minutes: it releases only observer-owned status/typing, records a diagnostic, and requests a guarded queue-dispatch recheck. Timeout is not proof that Pi compaction completed or was cancelled and emits no invented terminal notice. Superseded timeout callbacks and stale-context terminal hooks cannot abandon or cancel a newer observation. If a queue mutation removes the last waiting item while Telegram-owned work still has running tools, status remains active instead of degrading to connected.

Queue reaction behavior, lane-tail transitions, Keep/Skip independence, multi-reaction precedence, and the Bot API reaction-removal limitation are defined in [Priority, Reactions, Keep, and Skip](#priority-reactions-keep-and-skip). Reaction changes first flush a matching delayed text or media group so the governed turn exists before mutation, and dropping marked heads cannot leave status permanently queued.

`/telegram-status` records grouped diagnostics for transport/API, polling/update, prompt dispatch, controls, typing, compaction, setup, session lifecycle, attachment queue/delivery, and recent redacted runtime events. Polling diagnostics expose the exact phase, phase start, current update, last successful `getUpdates` response, and stop reason; outbound success never substitutes for inbound progress. Expected preview noise such as unchanged edit responses is filtered out. The compact TUI status renders only `error`; detailed failure text remains in diagnostics and profile-scoped logs instead of expanding the status line.

Complete intermediate assistant text blocks from Telegram-originated activity are sent once to the immutable originating target before active-turn final delivery; final and terminal-partial segments stay with settlement. If settlement nevertheless resolves to text exactly equal to an intermediate already admitted for that Telegram turn, it preserves lifecycle settlement but suppresses the second persistent reply. This same-owner equality fence covers ordinary finals and recovered fallback answers; it does not deduplicate different text or infer Telegram acknowledgement from chat history. While this instance has exact direct or follower transport authority, completed public blocks from local/autonomous work are always sent once and in source order to the instance's authorized target. Connected companion projection is not configurable; disconnect or authority loss is its boundary. Both paths use the configured Rich or HTML renderer and exclude reasoning, tool traffic, token deltas, local prompt text, unknown sources, and stale generations. Each admitted block remains fenced to its exact target, profile/token stamp, leader epoch or follower registration generation, and session generation; non-idempotent acknowledgement ambiguity never authorizes replay.

`assistant.activity` is an independent bridge-owned projection over normalized Activity events. Each process reloads the shared file-backed setting at `agent-start` before activity admission, so multi-instance mode cannot continue projecting a stale broader process-local selection. Omitted values resolve to `verbose`, while invalid values fail closed to `quiet`; `thinking` and `tools` select one technical class, while `verbose` enables both. Provider-exposed thinking uses persistent ordinary HTML containing only a standard expandable blockquote with a bounded redacted latest-text window and inline Markdown rendered as Telegram HTML. Like answer drafts, it accumulates for two seconds before the first frame, publishes at most one update every two seconds, and flushes remaining buffered reasoning on terminal completion. Completed executed tools use native Rich Messages: each closed `<Tool>: <status>` root details node renders snake-case names as title words while preserving an uppercase two- or three-letter repeated prefix per word, then the native disclosure chevron reveals an open-by-default `arguments` child plus closed retained `update N` and `result`/`error` child details with lowercase monospaced, marker-free summaries and JSON pre blocks; known-safe Rich rejections fall back to the previous HTML disclosure. The projection captures the exact target and transport stamp at activity admission, serializes updates, preserves tool-start order, closes coalescing across assistant/thinking boundaries, bounds retained text/update memory plus edit frames and message/tool size, disables previews and HTTP(S) auto-link recognition inside technical evidence, and never replays a possibly committed send. Session generations own independent queues, so replacement drops queued old work without waiting on an old call. Bridge-owned assistant output and activity projection share one activity-publication sequence admitted synchronously from the activity bus, so later tool disclosures cannot overtake earlier assistant blocks. Activity targets and transport authority are captured before queued work starts. Active Telegram-turn final replies/artifacts and automatic compaction notices use that same publication owner before the existing direct/follower transport split, without mutually waiting on separate output tails. Final settlement captures the exact active turn and assistant result and reserves its publication position before config loading. Empty outcomes without a publication candidate reserve no position. Replacement, preparation failure, or an unused reservation releases the position without resetting or replying for a replacement turn. Final errors also publish through this owner. Reservations accept one task; cancellation cannot undo a published task, and session reset releases unresolved reservations while fencing old queued tasks. Terminal assistant messages with a publication candidate reserve the final position synchronously; settlement consumes that reservation only for the exact originating turn. Compaction notices enter the same queue immediately, behind the reserved final rather than through a separate notice buffer. Settlement, a new agent run, or session replacement cancels an unconsumed reservation. Notice target and authority are captured when the event is observed. Pi lifecycle completion does not wait for network publication. This order is process-local and does not serialize unrelated instances or independent registered activity handlers. Settlement, replacement, disconnect, failure, or stale authority clears only local ownership; already-sent activity messages remain in chat.

Telegram prompt guidance is context- and authority-aware. The package and source-checkout extension contribute `telegram-bridge`, optional `generated-control-surface`, and `generative-apps` Skills through Pi resource discovery. Generated Control Surface treats `interface = f(state, capabilities, intent)` as a renderer-neutral primitive, compiling transient evidence-backed controls over domain-owned workflows, systems, navigation, supervision, and decisions without creating parallel application state. It composes an ordered ragged sequence of independently sized semantic rows rather than filling a rectangular grid: compact rows contain genuine peers, singleton rows isolate structurally independent actions, and rectangular layouts remain reserved for genuinely spatial state. Text-bearing controls use at most two columns and flow into additional rows, while denser rows are reserved for short position-bearing glyphs or codes and never exceed the eight-column phone-width UX maximum. Vertical extent is independent: a true spatial surface may retain substantially more rows, while non-spatial button walls route to grouping, disclosure, or pagination. Symmetry is treated as an evidence claim about equal relationships or real spatial topology; an abstract layout catalog supplies adaptable singleton, peer, staged, navigational, repeated-pair, and rectangular shapes without forcing tasks into preset grids. Repeated controls carry the smallest sufficient action delta when visible conversation is unambiguous; larger or error-prone state moves to a deterministic task-owned Markdown artifact, correctness-sensitive transitions move to a small domain-owned transition implementation, and repeated clicks are adjudicated against current state rather than stale button appearance. Its filesystem adapter reserves the first full-width row for parent traversal outside root, places available Previous/Next controls together in one compact row immediately afterward, orders visible directories, hidden directories, visible files, and hidden files alphabetically within each category before fixed ten-entry pagination, renders path/range metadata as stacked status-style key-value rows instead of middle-dot prose, emits the complete Telegram control set through one JSON-matrix action, suppresses duplicate plain/monospaced listings and default Refresh unless user preference overrides presentation, and retains an ordinary numbered fallback when buttons are unavailable. Only an exact direct owner or live registered follower exposes the two pi-telegram delivery tools, their active-tool metadata, and the compact routing suffix. Disconnect or authority loss removes those tool surfaces for subsequent requests without touching foreign tools; reconnect/recovery restores only the pi-telegram subset that was active before suspension, including across same-process reload. Repeated stable interactions may graduate from that model-mediated surface into a reviewed Generative App whose deterministic bound methods bypass Pi queue admission; the `generative-apps` Skill owns this compilation and operating workflow while the underlying capability retains domain authority. Telegram-originated turns route to the stable Skill contracts and retain dynamic blocks such as `[voice] delivery: automatic voice`; the Skills and public documentation own syntax, target routing, Threaded Mode behavior, Generative App operation, and diagnostics.

## In-Flight Model Switching

When `/model` is used during an interruptible active agent run in the current Pi session, the bridge emulates Pi's interactive stop/switch/continue workflow:

1. Apply the selected model immediately.
2. Queue or stage a synthetic Telegram continuation turn before aborting.
3. Abort immediately, or wait for every active tool execution to finish before aborting.
4. Dispatch the continuation in the same session context under the selected model.

A Telegram-originated run retains its active prompt target and reply anchor. For local/TUI or autonomous work without an active Telegram turn, the exact authorized model-menu chat, Thread, and message become the continuation target and reply anchor. Merely busy non-agent lifecycle work remains ineligible because no active agent abort handler exists. Pending selection and fallback-target state clear together on cancellation, new agent start, settlement, or session replacement.

## Shutdown And Timer Lifecycle

`session_shutdown` is the hard boundary for session-bound runtime work. It suspends Telegram polling through the locked polling runtime, aborts the poll controller, stops native typing, unbinds deferred queue dispatch, suspends pending media/text-group debounce work for rebinding to the replacement session, clears preview state, clears active turns, and drops the active abort handler.

Non-critical timers are `unref()`ed so print/headless processes are not kept alive only by Telegram housekeeping. This includes typing keepalive intervals, bounded typing-idle waits, deferred queue dispatch, media/text-group debounce windows, preview flush timers, and polling retry sleeps. Polling retry sleep is abort-aware, so shutdown does not wait for the normal retry delay after a polling error.

Non-interactive `pi -p` runs must remain passive unless Pi provides a live Telegram session lifecycle. Loading the extension with `telegram.json` or existing lock state must not by itself keep the print-mode process alive or let a non-owner send companion Telegram output.

## Related

- [README.md](../README.md)
- [Project Context](../AGENTS.md)
- [Project Backlog](../BACKLOG.md)
- [Changelog](../CHANGELOG.md)
