@llblab/pi-telegram 0.24.0 → 0.24.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/AGENTS.md CHANGED
@@ -41,7 +41,7 @@ The core product loop is mobile continuation: start or supervise work in the ter
41
41
  - `/AGENTS.md`: Durable engineering and runtime conventions
42
42
  - `/BACKLOG.md`: Canonical open work. Keep only open top-level tasks; when all subtasks under a top-level task are complete, remove that task from the backlog and record completed delivery in `CHANGELOG.md` if user-visible. Put detailed decomposition under the single owning top-level task with nested checkboxes and explicit done criteria instead of promoting completed slices into separate top-level backlog items.
43
43
  - `/CHANGELOG.md`: Completed delivery history focused on the final released behavior and user/operator/developer impact. Prefer multiple domain-scoped bullets with an inline-code domain label followed by a colon, change, and impact—for example, `Lock Fencing`: change + impact—instead of accumulating unrelated changes into one long entry; never use square brackets for the domain label. Never include personal usernames, user/chat ids, message/thread ids, or operator-specific thread labels in changelog/docs evidence; use role placeholders such as `<remote-peer>`, `<paired-owner>`, or `assigned leader thread`. Do not record transient implementation churn such as "added then removed" mechanics, internal reversions, or cleanup of an abandoned intermediate path unless the final product surface exposes that as a meaningful migration/breaking change.
44
- - `Pre-release changelog consolidation`: Treat the current version section as a working set during development, then consolidate it before the release commit, PR, tag, and GitHub Release. Merge repeated implementation and smoke chronology into the smallest truthful set of outcome-focused domain bullets; preserve distinct shipped behavior, safety/compatibility contracts, migrations, known limitations, and meaningful operator evidence. Remove superseded findings, repeated validation runs, and fixed-then-reworked mechanics. Do not rewrite older release sections during this gate.
44
+ - `Pre-release changelog consolidation`: Treat the current version section as a working set during development, then consolidate it before the release commit, PR, tag, and GitHub Release. Merge repeated implementation and smoke chronology into the smallest truthful set of outcome-focused domain bullets; preserve distinct shipped behavior, safety/compatibility contracts, migrations, known limitations, and meaningful operator evidence. Remove superseded findings, repeated validation runs, and fixed-then-reworked mechanics. Ordinary release gates do not rewrite older release sections. An explicitly requested retrospective consolidation may rewrite historical sections only after inventorying the noisy candidates and verifying final outcomes against the section plus available tag/commit evidence; preserve version identity, shipped contracts, breaking changes, migrations, limitations, and materially distinct outcomes.
45
45
 
46
46
  ## 4. Core Entities
47
47
 
@@ -78,7 +78,7 @@ The core product loop is mobile continuation: start or supervise work in the ter
78
78
  - The bridge is session-local, paired to one allowed Telegram user, and owns a local queue aligned with Pi lifecycle hooks
79
79
  - The Telegram lock owns external Telegram transport, not local Pi execution. Local extension state and queue runtime are per Pi instance: losing exact `/telegram-connect` ownership must not clear accepted queue state or stop local Pi dispatch, but preview, final delivery, attachments, menus, and other Bot API mutations fail closed once another runtime owns transport. A replacement owner must never receive stale direct mutations merely to preserve old-runtime Telegram output. Bus leader lock entries carry a stable `leaderEpoch` minted on acquisition and preserved across heartbeat refreshes; leader-owned Thread Reconciler cleanup/provisioning actions stamp that epoch and skip destructive side effects if current leadership differs.
80
80
  - Telegram transport ownership lives only in the extension-local `tmp/telegram/owners.json` store under `default` or named profile slots. Every mutation must serialize the complete cross-process read/check/write transaction through `owners.json.transaction` and fail closed on contention; atomic payload replacement alone does not make ownership linearizable. Refresh, release, takeover, and irreversible leader work additionally fence against the exact acquired owner and leader epoch. In classic/private-chat mode, transport ownership is the whole bridge ownership and `/telegram-connect` from another live Pi offers classic takeover confirmation. In Threaded Mode, transport ownership is the bus leader role and another live Pi registers as follower instead of offering takeover while the leader is live. If follower registration is unavailable, fall back to classic takeover.
81
- - Ownership transactions publish a fully initialized private guard directory containing one exact generation-specific `owner.<generation>.json` through same-parent atomic rename. The owner filename and payload generation must match so stale observation cannot rename replacement metadata. Release verifies the owner and atomically renames the stable guard away before cleanup. Directory recovery first claims owner metadata inside the still-occupied guard so a crashed recoverer can itself be replaced without exposing the stable path; transient guard moves and rollback both retry, while inactive process-global claim generations remain recoverable after failed restoration. If secondary recovery cleanup fails after publishing a replacement main guard, release that exact replacement before propagating the failure. Guards must not depend on hard links, direct file rename-overwrite, incomplete create-then-write state, or age-only recovery; malformed or unsupported guards fail closed.
81
+ - Polling checks exact `owners.json` ownership every second but refreshes the durable owner heartbeat only every two seconds; an eight-second stale threshold preserves bounded recovery headroom without turning every ownership check into an atomic disk rewrite. Ownership transactions publish a fully initialized private guard directory containing one exact generation-specific `owner.<generation>.json` through same-parent atomic rename. The owner filename and payload generation must match so stale observation cannot rename replacement metadata. Release verifies the owner and atomically renames the stable guard away before cleanup. Directory recovery first claims owner metadata inside the still-occupied guard so a crashed recoverer can itself be replaced without exposing the stable path; transient guard moves and rollback both retry, while inactive process-global claim generations remain recoverable after failed restoration. If secondary recovery cleanup fails after publishing a replacement main guard, release that exact replacement before propagating the failure. Guards must not depend on hard links, direct file rename-overwrite, incomplete create-then-write state, or age-only recovery; malformed or unsupported guards fail closed.
82
82
  - Telegram profiles are parallel bot/runtime realities, not merely alternate credentials. Persist every bot/session field (`botToken`, `botUsername`, `botId`, `allowedUserId`, `lastUpdateId`) under `telegram.json` `profiles.<name>`, including `profiles.default`; keep shared handlers and assistant/voice/time settings top-level. Bare and explicit `default` setup/connect commands address the same profile. Legacy root identity may normalize atomically only when unambiguous; conflicts fail closed without mutation. Any owner slot, IPC endpoint, state snapshot, diagnostics log, thread/bus binding, runtime cache, ownership map, or operator-visible status surface that could mix bot identities must be deliberately classified as global, session-local, or profile-scoped. Use the `default` owner slot for the default profile and validated profile names for named slots; give named profiles isolated observable surfaces unless there is an explicit top-level shared-config reason not to.
83
83
  - Telegram private-chat Threaded Mode is the public switch for the local multi-instance bus. There is no separate public `telegram.json` bus switch: classic/private-chat singleton DM behavior is the base product mode, and when Telegram reports Threaded Mode available for the bot the bridge enables leader/follower bus behavior. If Telegram reports Threaded Mode unavailable or thread operations prove it unavailable, the bridge returns to classic singleton behavior as a first-class mode. During a live Threaded Mode downgrade, the current transport leader keeps the singleton classic polling role and followers disconnect instead of taking over or offering takeover while active thread bindings prove this is a downgrade from a live bus organism. Do not inject slot/thread rename guidance in classic mode. Blocked instances should not silently register as followers unless the effective runtime mode is Threaded Mode.
84
84
  - In Threaded Mode, exactly one live leader owns `getUpdates` and direct Telegram Bot API calls for one bot token. `/telegram-connect` means join the local Telegram organism: if no live leader exists the instance becomes leader; if a live leader exists the terminal-visible instance registers as follower; ordinary connect must not offer manual takeover while the leader heartbeat is live. Leadership is an ephemeral transport role, not permanent ownership by the first terminal-visible Pi instance. Heartbeat acknowledgements carry the authenticated live follower-slot roster: on leader loss, the lowest observed live slot attempts the atomic lock first, while higher slots defer for one bounded grace and then re-check so a missing lower follower cannot block recovery indefinitely. Followers must be started by the operator as real Pi processes, register over the local bus, heartbeat, receive only their routed inbound updates, and send outbound replies/previews/files/chat-actions through the leader transport; Telegram must not spawn hidden Pi processes, launch follower subprocesses, or expose a slash command that creates a new local Pi instance. If a leader reloads while followers stay alive, followers must treat rejected/unknown/unauthorized heartbeats as a registration-loss signal and optimistically re-register with the currently active leader before considering promotion; after a short grace window without successful re-registration, a live follower may promote only through an atomic expected-owner transition after the exact observed leader lease becomes stale or inactive. An unreachable IPC endpoint does not authorize replacing a still-live lock owner; remain disconnected/retrying rather than creating split-brain polling. Terminal status must not remain `follower` while the leader registry can no longer route that follower's thread. Heartbeat pruning is liveness bookkeeping, not permission to delete, mark offline, or send a Telegram-visible disconnected notice for a follower's thread; preserve active follower tabs/bindings across transient reload/reconnect incidents and reserve destructive teardown/offline transitions for explicit disconnect or confirmed reconciliation cases. If the leader dies, a live follower should eventually be able to take over through stale-leader election/recovery so the local multi-instance organism keeps running. Explicit `/telegram-disconnect` is a manual thread teardown: a leader deletes its own bound thread before releasing transport ownership, while a follower sends an authenticated exact-registration-generation disconnect envelope and waits for the leader to delete its assigned thread, mark the durable binding offline, and remove live routing authority before unregistering. Cleanup must be confirmed by successful deletion or explicit already-gone evidence; incomplete cleanup preserves binding/routing state, keeps the session open, and returns actionable retry guidance. A promoted leader authorizes inherited follower-thread cleanup by its current leader epoch rather than the historical owner label. Status is reactive to the effective runtime role and bot capability: classic/non-thread mode shows ordinary `telegram connected`, active bus leadership shows `telegram leader`, and registered followers show `telegram follower`; stable multi-instance truth belongs in the bus role (`leader`/`follower`), while lifecycle is reserved for transient recovery state such as `electing` and must not duplicate stable roles with labels like `leader-active`. When leadership or Threaded Mode availability changes at runtime, the status line and `/telegram-status` must converge promptly instead of preserving a stale role label.
package/BACKLOG.md CHANGED
@@ -2,27 +2,25 @@
2
2
 
3
3
  _This backlog tracks only open release-relevant work: hotfixes, bounded maintenance, live runtime verification, evidence-gated Telegram client follow-ups, and upstream Pi API blockers. Completed outcomes and validation evidence belong in `CHANGELOG.md`, not in this queue._
4
4
 
5
- ## P1 — Native Windows Threaded Mode Follow-Ups
5
+ ## P1 — Cross-Platform Runtime Persistence Optimization
6
6
 
7
- Context: Native Windows smoke on the WIP `dev` build now passes for classic mode, classic ownership handoff, hot upgrade to Threaded Mode, leader/follower registration and delivery, and hot downgrade back to classic with follower disconnect. The observed downgrade status convergence can take around 10 seconds, which is acceptable for the current retry-based safety model but should remain evidence-gated if it becomes user-visible friction.
7
+ Context: `owners.json`, `state.json`, and `logs.jsonl` protect different ownership, recovery, and diagnostics boundaries. Their optimized persistence paths must preserve multiple concurrent Pi instances, classic singleton ownership, Threaded Mode leader election, exact owner/generation/epoch fencing, crash recovery, and native Windows behavior. Deterministic regressions, docs, and all local release gates pass; native Windows remains the final environment-only proof.
8
8
 
9
9
  Open work:
10
10
 
11
- - [ ] Capture text diagnostics if Windows classic restore/status convergence repeatedly exceeds the intended 5–15 second fallback window.
12
- - [ ] Add a focused regression or transport/status adjustment only if new Windows evidence shows a repeatable named-pipe, lock, heartbeat, queue, or status-convergence issue.
13
- - [ ] For every Windows connect/runtime crash report, classify the failing boundary (`owners.json` atomic write, named pipe, heartbeat, polling, queue, or status), ensure `logs.jsonl` captures enough redacted evidence before shutdown, and add a minimized regression when the failure can be simulated deterministically.
11
+ - [ ] Run the current diff through native Windows classic and Threaded Mode smoke: connect, ownership handoff, leader/follower registration, stale recovery, live downgrade, diagnostics rotation, and shutdown cleanup. Record named-pipe and atomic-file evidence explicitly rather than treating Linux tests as cross-platform proof.
14
12
 
15
- Done when: new Windows-specific runtime issues are either fixed with targeted coverage or left out of the backlog because the native smoke remains green.
13
+ Done when: native Windows evidence confirms that the measured filesystem-write reductions do not weaken singleton or leader/follower authority, recovery, diagnostics, or shutdown behavior.
16
14
 
17
15
  ## P1 — Evidence-Backed Telegram Client Follow-Ups
18
16
 
19
- Context: The release should avoid speculative live-test matrices. Future Telegram-client quirks should be handled only when there is concrete evidence or a minimized fixture.
17
+ Context: The release should avoid speculative live-test matrices. Future Telegram-client quirks should be handled only when concrete evidence or a minimized fixture exists.
20
18
 
21
19
  Open work:
22
20
 
23
21
  - [ ] Capture any new Telegram client or Bot API behavior that contradicts the documented Threaded Mode contract, including a live local/autonomous `…typing` observation when convenient.
24
22
  - [ ] Add a focused regression or documented client caveat only for confirmed behavior.
25
- - [ ] Keep one-off live environment names, thread names, and operator-specific observations out of repository context unless they demonstrate a general product issue.
23
+ - [ ] Keep one-off environment names, thread names, and operator-specific observations out of repository context unless they demonstrate a general product issue.
26
24
 
27
25
  Done when: new client quirks are either fixed with targeted coverage or documented as evidence-backed exceptions, without keeping broad manual smoke matrices in the backlog.
28
26