Files
obsidian-vault/personal/projects/archive/execution-broker-repo-cleanup-2026-10-16/docs/telegram-approvals.md
T

9.3 KiB
Executable File

Архив исходника Broker

Историческая копия из ae92c15 до очистки репозитория 2026-10-16; текущая установка — personal/projects/balda/execution-broker.


Telegram approval actions

A retry of the same Story and exact execution scope retains the actual plan previously approved by the owner. Broker loads that decision from its journal and sends a private, checksum-bound snapshot to Runner/Callee. Callee continues implementation and the quality gate without regenerating planning or asking for the same approval again. Changes to the task, repository revision, executor or session require a new approval. Later owner feedback is never replaced with an older approval. ACP permission choices and command authorization remain separate.

Broker can deliver pending workflow and worker ACP permission requests to a dedicated Telegram bot, even when the run started in Mattermost. Balda's existing notification route remains responsible for the original conversation and terminal result. Telegram never creates a new Story, run or Balda session. The original Balda conversation is the default approval channel. When Telegram is enabled for a source session, approval requests are delivered only to Telegram; Balda does not repeat the question or options. Result and cleanup notifications continue in the original conversation. The existing command authorization API remains available for operator recovery. Authored command allow/deny/ask policies, bearer authentication and operator grants retain their existing roles.

Configure

Create a dedicated bot with BotFather. Save its token in the deployment's private telegram-approval.token file, mode 0600; never put it in Git or a plugin. Set the owner's numeric Telegram user ID from an independently established identity. The bot does not enroll the first user who contacts it. The owner must open the bot's private chat and press Start before it can deliver requests.

Add this operator-owned block to broker.json:

{
  "telegram_approvals": {
    "enabled": true,
    "token_file": "/run/secrets/telegram_approval_token",
    "owner_user_id": 123456789,
    "chat_ids": ["mm-c-EXACT_SOURCE_SESSION"],
    "timeout_seconds": 1800,
    "min_run_ttl_seconds": 3600
  }
}

Omit this block or set "enabled": false to use the current approval method without starting a Telegram client, reading its token or requiring a bot secret. Only "enabled": true selects the Telegram approval route. The Bot API transport does not replace command authorization or change the original approval API.

This example allows 30 minutes for a Telegram decision and requires at least one hour of total run TTL, leaving time for planning and execution. For selected source sessions, min_run_ttl_seconds rejects a new shorter execution_start before admission or worker allocation; retry the same unaccepted request with an adequate ttl_seconds. Zero or omission preserves the caller-selected TTL. Already admitted requests retain their original deadline and idempotent replay. The execution deadline remains a hard bound, including queueing and planning; it is never extended when a question appears or the owner refreshes controls.

chat_ids identifies original Balda sessions. An explicit "*" selects all sessions in this single-operator Broker. It does not enable multi-user approval. Include deploy/compose.telegram-approvals.yaml, rebuild the Broker image, select that reviewed image in an operator override, and recreate only Broker after checking current runs and retaining a rollback image/configuration. The default deployment image pins remain unchanged. The bot uses outgoing long polling; no new public listener is needed. A configured Telegram webhook prevents polling and is never removed automatically. Run only one consumer for this bot token.

Actions and ownership

  • Workflow approval offers Approve and Cancel. Reply to the exact prompt to amend the requirements where the selected workflow supports amendments.
  • Updated Callee adapters send structured ACP option IDs and labels. The buttons offer only the provider's actual choices, such as Allow Once and Deny. Authored allow and deny roles retain their existing policy; only ask requests pause. Update worker packages as well as Broker to obtain structured ACP actions.
  • Every prompt also offers Cancel run. Unknown or older generic questions accept a reply to their exact Telegram message instead of inventing an approval value. Known installed Story packages retain their existing approved/cancel contract.
  • Only the configured owner's user ID in that owner's private chat can decide. Callback data contains an unpredictable, durable request nonce and an option index. It never contains credentials, paths, shell commands or approval answers.
  • Broker submits the selected answer against the original run, Human request, chat and topic. The accepted-response journal records the Telegram user ID. Concurrent operator recovery and Telegram responses accept one decision; a stale cancellation button cannot cancel an already answered request.

Each request sends one readable message with its action buttons. Workflow plans use the task's language and omit internal Story/run/request IDs. A long question is explicitly marked as a preview and offers Full details (Russian: Полный план). Only clicking that button sends the complete UTF-8 approval.txt file; it does not approve, cancel or resume the worker. Repeated clicks reuse the recorded document delivery. Read the complete details before approving a preview.

Reply to the message with buttons to change a Story plan; a standalone message or a reply to its attachment is not an approval response. Up to three requirement amendments regenerate planning in the same run and ask for approval again. ACP permission prompts accept only their exact offered option IDs; text feedback is not a requirement amendment for those prompts.

Recovery and expiration

Prompt bindings, delivery IDs and deadlines live in the private Broker run state. The Bot API update cursor is atomically saved in the Broker data directory after processing an action. A prompt is sent without buttons, its message ID is saved, and only then are controls attached. Restart completes an interrupted control publication on that same message. An ambiguous send may leave a duplicate text message without buttons; it cannot leave an untracked actionable prompt. Duplicate callbacks do not resume a worker twice. Resolved controls are removed; clicking an older actionable copy also removes that copy's controls before the update is acknowledged. Already expired callback acknowledgements do not block later updates.

The Telegram timeout is bounded by the original execution deadline. Expiry removes the approval controls and rejects their late actions. The same message explains expiration and offers Refresh request. Only the configured owner can refresh a still-pending Human; delivery creates a fresh nonce and asks for a new decision in the same run and worker. The renewal request is saved before clearing the old controls; after a restart, delivery finishes renewal without another callback. It does not accept an approval, extend the execution deadline, or send the request into Mattermost. Stale callbacks, changed Human requests and expired executions cannot refresh it. The existing command API also remains available until the normal run deadline. Telegram failures or expiry do not send a duplicate question into the original conversation. Disabling Telegram restores conversation delivery for a still-pending request. An explicit Cancel run button still requests cancellation. Replies to stale prompts, other users, group messages, unknown actions and changed request bindings cannot resume execution.

Provider sign-in challenges are excluded from this route. Managed-host signed capabilities and folder-access operator grants retain their independent authorization paths. This feature covers Broker-managed runs; Balda's own host ACP permission service is a separate integration. The context-review subagent and policy-based autoapproval are separate planned work.

Verification

Run make check and scripts/check-callee.sh. Tests cover allow/deny actions, exclusive approval delivery with Telegram enabled or disabled, bot failures, active status/event polling, switching a pending request back to the conversation, and continued terminal/result delivery, as well as the exact worker response, competing channels, unauthorized and stale clicks, timeout, restart, ambiguous sends, interrupted control publication and renewal, stale-copy cleanup failures, acknowledgement failure, complete documents, requirement amendments, secret-safe transport errors and private API projection. On 2026-10-12, candidate 05358d0 passed an isolated Docker acceptance run with the real Approval bot. The configured owner clicked Approve; Broker recorded one attributed response, the deterministic Callee fixture succeeded, all five artifact hashes matched, and worker container/volume cleanup was independently verified. The test stack had no Balda notification route, so this does not prove Mattermost delivery or a real-provider ACP permission request. The production rollout and source-session scope require their own deployment verification.

Bot transport contracts: Telegram Bot API.