Recognize raw, provider-qualified, and topic-qualified Telegram targets as the same current source when their semantic identities match. Prevent successful final message-tool sends from continuing into duplicate replies.
Co-authored-by: Ayaan Zaidi <hi@obviy.us>
* fix(gateway): harden hook admission and shutdown
Flush structured 413 and 408 hook responses before closing oversized or timed-out request sockets, and reject deferred wake requests that target an explicit session.
Direct Gateway close now marks startup and readiness as draining immediately and attempts every HTTP listener shutdown before reporting an incomplete close.
* test(gateway): model request destruction in fuzzing
Give the HTTP request fuzz double the IncomingMessage destroy contract exercised after 413 and 408 responses finish.
* fix(gateway): preserve response and shutdown bounds
Route installed webhook body-limit failures through the shared response-first close owner and require complete Feishu 413/408 responses before terminal connection closure.
Retain the current-main grace bound for agent-harness disposal so one stuck harness cannot block listener teardown.
* test(telegram): model response-close request cleanup
Keep the slow-body request alive through response finish, then assert cleanup when the mock response transport closes.
* fix(security): harden canonical bounded JSON body reading
* refactor(admin): use canonical bounded JSON body reader
* refactor(telegram): use canonical bounded JSON body reader
The assertion-safety baseline prune for extensions/telegram/src/miniapp/routes.ts (2 to 1) is explicitly approved.
* test(security): cover canonical JSON body migrations
* refactor(plugin-sdk): name response-first body profile
* fix(telegram): flush miniapp body-limit responses before close
* fix(gateway): bind auth limits to ingress attribution
* fix(gateway): close remaining ingress auth gaps
* fix(gateway): carry attribution into new ingress paths
* fix(gateway): close ingress ownership gaps
* fix(gateway): complete proxy ingress hardening
* fix(gateway): stabilize managed Tailscale ingress
* fix(gateway): make Tailscale cleanup ownership-safe
Refuse reset-on-exit publication until Tailscale exposes an atomic owner-bound cleanup operation, and migrate legacy configs with Doctor.
* fix(gateway): finish ingress ownership repair
* fix(gateway): own managed Tailscale route lifetime
Run managed Serve and Funnel routes as foreground claims tied to the Gateway lifecycle. Retire named Service config through Doctor because Tailscale Services cannot run in foreground mode.
Co-authored-by: Pavan Kumar Gondhi <pavangondhi@gmail.com>
* fix(gateway): align Tailscale consumers and build guards
Remove the retired named-service config from Telegram Mini App URL resolution and register the lifecycle worker as an explicit production entry.
Co-authored-by: Pavan Kumar Gondhi <pavangondhi@gmail.com>
* fix(gateway): preserve retired Tailscale inputs
Keep Funnel enabled when removing an ignored named-Service setting and accept the legacy positive reset flag as a no-op now that managed routes always follow Gateway lifetime.
Co-authored-by: Pavan Kumar Gondhi <pavangondhi@gmail.com>
* fix(gateway): preserve Tailscale route diagnostics
Prefer the actionable foreground CLI failure captured during timeout cleanup, and cover the original delayed-failure ordering.
Co-authored-by: Pavan Kumar Gondhi <pavangondhi@gmail.com>
* fix(gateway): reconcile Tailscale ingress with main
Preserve current ingress ownership contracts after the rebase, retire the obsolete device-auth migration check, validate route-owner IPC, and move Tailscale auth coverage onto the managed listener.
Co-authored-by: Pavan Kumar Gondhi <pavangondhi@gmail.com>
* fix(gateway): finish ingress rebase coverage
Unify the rebased net imports and let module-reset WebSocket tests prepare attribution through the same fresh module instance as the handler.
Co-authored-by: Pavan Kumar Gondhi <pavangondhi@gmail.com>
* test(gateway): align run-loop server fixture
---------
Co-authored-by: joshavant <830519+joshavant@users.noreply.github.com>
The finished-turn digest ('🧠 N thoughts · 💬 N notes · 🛠️ N tool calls ·
⏱️ Ns') was synthesized onto three surfaces: Slack's Block Kit card footer
(removed in #123851), Discord's final-answer subtext, and a duplicate Telegram
implementation added to match Discord.
Nothing gated it — no config key for the receipt has ever existed on any
channel — so PR #122976, which deleted it from Slack's native progress surface,
could only ever be a partial removal. Finish it: live progress surfaces keep
their in-flight indicators, and a finished turn leaves the answer with nothing
synthesized appended.
Telegram's window collapsed *into* the digest, so it now retires like every
other surface; Discord already discarded its draft after the final landed. The
core tracker keeps only the live counters Slack's working footer reads.
Generated titles came back in Title Case because none of the title prompts stated a capitalization style; asked for a "title" with no case rule, models default to Title Case and nothing downstream corrects it. The tool-call purpose titles already ask for sentence case, so session titles, Discord auto-thread titles, and Telegram DM topic labels were the outliers.
Sets sentence case in each title prompt rather than post-processing: the titles follow the user's language, and sentence-case rules are language-specific, so a mechanical normalizer would mangle German nouns and proper nouns like OpenClaw or GitHub.
* fix(slack): keep commentary progress on draft lane
* fix(channels): route commentary through one progress owner
Keep non-verbose commentary in Slack and Discord draft lanes while preserving one durable commentary payload when verbose progress makes those drafts yield. Freeze that owner decision for the turn so session changes apply on the next turn.
Co-authored-by: Dallin Romney <dallinromney@gmail.com>
Punchcard-Session: amber-workshop-workshop-36
* fix(channels): refresh queued commentary owner
Recompute the frozen draft-versus-durable commentary owner for every queued follow-up turn and carry that decision into final payload projection.
Punchcard-Session: amber-workshop-workshop-36
* fix(channels): clarify commentary owner opt-in
* fix(channels): preserve queued draft preambles
* fix(channels): require explicit queued progress ownership
* refactor(channels): record commentary progress owner
* fix(telegram): tolerate unscoped queued updates
* test(discord): use canonical draft fixture after rebase
---------
Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
Reject reserved /healthz webhook configurations before registration, preventing silent Telegram update loss. Warn through Doctor and document recovery.
Co-authored-by: Peter Lee <22994703+xialonglee@users.noreply.github.com>
Co-authored-by: Ayaan Zaidi <hi@obviy.us>
Preserve reply and selected-quote metadata from later Telegram debounce and fragment-batch messages while keeping reply-chain recovery bounded.
Co-authored-by: iridescentWen <whatmakesbetter@outlook.com>
Co-authored-by: Ayaan Zaidi <hi@obviy.us>
Telegram native-command registration resolved provider names through the bundled channel-plugin fallback, which jiti-transpiles the entire plugin plus core graph from source when no registry entry is loaded (~190s silent CPU) — tripping the 300s no-output CI watchdog on the two Telegram test files that register at module scope. Telegram defines no resolveNativeCommandName hook, so the load resolved nothing. Thread the existing includeBundledChannelFallback option through the spec-listing helpers and use loaded-registry-only lookups in the Telegram plugin, matching the Discord sibling. Runtime names are byte-identical; both files drop from 200s to ~5s.
Reject unbound foreign-channel fallback at shared approval-account selection while preserving recorded bindings and explicit forwarding targets. Cover Telegram and Matrix routing contracts.
Co-authored-by: vatsalgargg <vatsalg80@gmail.com>
Co-authored-by: Ayaan Zaidi <hi@obviy.us>
Preserve raw query separators in Telegram rich-message bare URLs by leaving parser-generated links to Telegram entity detection. Authored Markdown links remain typed, while file references remain code-formatted.
Co-authored-by: Ayaan Zaidi <hi@obviy.us>
Treat <internal> blocks as private reasoning in the shared parser and remove Telegram raw-reasoning fallbacks. This keeps model reflections out of user-visible replies while preserving surrounding answer text.
Closes#122623
Co-authored-by: Ayaan Zaidi <hi@obviy.us>
Co-authored-by: WangYan <wang.yan29@xydigit.com>
Class provenance: #114388 made multi-agent ownership explicit; prior partial sweeps #122883 and #122978 repaired Codex, Copilot, ClickClack, and policy fixtures.
Per-file changes:
- extensions/telegram/src/bot.create-telegram-bot.test.ts: declare startup owners for the four reload fixtures and add the default Telegram binding for the topic override case while preserving dynamic account/topic routing assertions.