Skip to content

Telegram forum topic opens then never updates: later frames rejected as trusted attachment lease is stale #4647

Description

@project-catsy

Description

On gjc/0.14.0 (Telegram daemon generation 169), starting a new interactive session creates a Telegram forum topic and posts the identity header, then no later conversation frames are delivered. The topic looks opened and then frozen.

This is not BotFather / Threaded Mode / chatId misconfiguration. The topic is created. Identity is sent. Every subsequent publication is rejected before send.

Observed on a live session 01a010b5-a66f-7000-800f-497c9708882a (topic 2067, title Telegram session chat not updating):

  • telegram-topics.json: identitySent: true, replaySeq: 2
  • telegram-presentation-state.json: only :1:2 delivered; :1:1 and :1:3 through :1:59 all rejected
  • daemon health stayed green (ownershipPhase: ready, attachments present)

This is distinct from #4527 (outbound freeze after session-host handoff with no attach). Here the attachment is live, identity publishes, and later frames fail closed on the trusted-lease gate.

Steps to Reproduce

  1. Install gjc/0.14.0. Enable Telegram notifications with a complete bot token + private chat id, Threaded Mode on.
  2. Confirm the Telegram daemon is running (gjc daemon status). At the time of the incident: generation 169, serving epoch 87.
  3. Start a new ordinary interactive session (gjc in a repo). Do not use /notify off.
  4. Watch Telegram: a new forum topic appears and the identity header is posted.
  5. Continue the session (prompt, tools, turn stream). Wait past the 20s topic-host lease TTL if the first live frames are delayed (lean/idle batching makes this easy).

Expected Behavior

After the topic and identity header are created, later turn_stream / context_update / tool frames for that live trusted attachment should publish into the same topic. Heartbeat should keep renewing the host lease for a still-attached owner.

Actual Behavior

Identity (:1:2) is the only delivered publication. Later frames are rejected before Bot API send. The topic never updates.

Root cause in installed 0.14.0 telegram-daemon.ts:

  1. Attachment starts with logicalSessionIdTrusted = false. #leaseAllows() returns true in that window, so createForumTopic + identity can send.
  2. After Router replay, logicalSessionIdTrusted = true. Later frames require an authorized recovery lease and a non-expired topic host lease (leaseExpiresAt > now, TTL = HEARTBEAT_TTL_MS = 20s).
  3. renewActiveTopicLeases() only renews sessions that already pass #leaseAllows(). Once the host lease expires, renewal is skipped forever.
  4. handleSessionMessage then throws:
Telegram publication rejected before send: trusted attachment lease is stale

Generation 156 made ordinary interactive sessions topic-eligible. That is why the room now appears. The trusted-lease / renewal cycle was not fixed with that change, so the newly eligible path dies after identity.

Error Output

Exact warn from ~/.gjc/logs/gjc.2026-08-18.log (pid 22650 is the Telegram daemon):

{"timestamp":"2026-08-18T02:12:08.747+09:00","level":"warn","pid":22650,"message":"SDK notification subscription notification:01a010b4-ae6e-7000-b6ed-d1b916fa263a:d3a7b01f-d87f-48eb-8195-570e4b788fee failed locally: Telegram publication rejected before send: trusted attachment lease is stale"}

Same session that created the identity-only topic (01a010b5-…8882a) then rejected every later publication id :1:3:1:59 in telegram-presentation-state.json. Topic record after the freeze:

{
  "topicId": "2067",
  "identitySent": true,
  "replayGeneration": 1,
  "replaySeq": 2,
  "authorityState": "disconnect_grace",
  "leaseExpiresAt": 1786986857311
}

Fail site (installed 0.14.0):

if (session.logicalSessionIdTrusted && !this.#leaseAllows(session))
  await this.#failPublicationPreSend(publicationId, "trusted attachment lease is stale");

#failPublicationPreSend marks the publication rejected and throws Telegram publication rejected before send: ${reason}.

Platform

macOS (darwin 25.5.0, arm64)

gjc version

gjc/0.14.0

Bun version

1.3.14

Provider

Not provider-specific. Session used xAI Grok 4.6 for title generation; the Telegram failure is in the notification daemon, not the model path.

Area

Other (Telegram notification daemon / forum topics)

Additional context

  • Daemon at incident: generation 169, serving epoch 87, chatId paired and creating topics successfully.
  • Local checkout of this repo is still generation 151 and contains the same #leaseAllows + reject string. The 160–169 daemon cleanup (orphan reap, ownership-off-critical-path, eligibility from config) does not fix this. Restarting/reaping the daemon only recreates identity-only topics.
  • Suggested fix: split socket authority from host-lease TTL. Heartbeat and pre-send should renew an owned topic lease even after expiry, then re-check #leaseAllows. Confirmed locally: after that change, a new interactive session updates the Telegram topic past identity.
  • Related but not the same: telegram daemon: outbound publications freeze after session-host handoff; health stays green #4527 (attach/reconcile hang, no identity). Generation 156 changelog (“Telegram notifications are delivered again… ordinary interactive session declared itself topic-ineligible”) is the precursor that exposes this next gate.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions