Skip to content

Task subagent shutdown releases the parent's poll lock and overwrites its DM-owner claim #83

Description

@hakula139

Problem

A native omp task subagent can release the parent bridge's bot.lock and replace the parent's dm-owner.json identity during session_shutdown, even though the child skipped bridge startup. The parent's actual poller remains alive.

Parent and child share a PID and the module-scoped lock nonce, but have separate extension closures and Poller instances. The child's stopBot() stops only its own unused poller while releasing the shared parent's lock. The preceding refreshTopicClaim(ctx) also replaces the DM owner's durable session identity because its PID matches.

This leaves a live parent poller without its lock, allowing another session to acquire it, and points durable untopiced-DM ownership at the ended child. This is the unguarded session_shutdown path, not the agent_end path fixed by #65 for #64.

Repro

An isolated offline harness used two real exported telegramExtension() factories and real Poller instances in one process:

  1. Use a temporary HOME and OMP_TELEGRAM_STATE_DIR, with enabled test state configured for session poller fallback rather than the standalone daemon. Capture each factory's event handlers separately. Give parent and child distinct session IDs and file paths. The child has hasUI: false and yield in its active tools.
  2. Intercept global fetch: return stub responses for getMe and setMyCommands, and leave getUpdates pending until its AbortSignal is aborted. Do not replace the pollers or the filesystem lock functions, and do not contact Telegram.
  3. Emit the parent's session_start. It acquires the real temporary poll lock, writes the parent DM-owner identity, and starts a pending getUpdates request.
  4. Emit the child's session_start. The existing task-subagent guard skips bridge startup.
  5. Emit and await the child's session_shutdown.

Observed after step 5:

State Expected Actual
bot.lock Still held by parent Removed
dm-owner.json session identity Parent Child
Parent getUpdates signal Not aborted Not aborted: parent poller is still alive

As a control, the real parent's shutdown aborted the parent's pending request and left no poll lock. Adding the same early task-subagent guard used at startup to session_shutdown preserved the parent lock and DM owner in an isolated local fix, while normal parent cleanup still worked.

These observations are from the isolated reproduction, not instrumentation of an original live Telegram interruption.

Acceptance criteria

  • A task subagent's shutdown cannot release the parent's poll lock or overwrite the parent's DM-owner identity.
  • The parent poller remains protected by its lock until the parent releases it.
  • Normal parent shutdown still stops and drains its poller and releases its own lock.
  • A regression covers two separate real extension factories in the same process, not only parent/child contexts passed to one closure.

Entry points

All references are against v0.13.0:

Environment

  • omp 18.2.4
  • omp-telegram 0.13.0 (v0.13.0, commit 0ce609d7e019f32a7ea734b35aa87dbb1190f990)
  • Bun 1.3.13
  • Linux x86_64

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