Skip to content

fix(telegram): route polling diagnostics away from errors#82958

Merged
galiniliev merged 3 commits into
openclaw:mainfrom
galiniliev:bug-005-telegram-polling-log-level
May 25, 2026
Merged

fix(telegram): route polling diagnostics away from errors#82958
galiniliev merged 3 commits into
openclaw:mainfrom
galiniliev:bug-005-telegram-polling-log-level

Conversation

@galiniliev

@galiniliev galiniliev commented May 17, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Problem: Telegram polling startup diagnostics were routed through the monitor error logger.
  • Why it matters: healthy polling startup looked like a gateway error in console output and could trigger false alarms.
  • What changed: normal [telegram][diag] monitor/polling diagnostics now use runtime.log, while non-diag [telegram] warnings/errors and offset persistence/delete failures stay on runtime.error.
  • What did NOT change (scope boundary): Telegram polling, webhook, offset, retry, and transport behavior are unchanged.

Change Type (select all)

  • Bug fix
  • Feature
  • Refactor required for the fix
  • Docs
  • Security hardening
  • Chore/infra

Scope (select all touched areas)

  • Gateway / orchestration
  • Skills / tool execution
  • Auth / tokens
  • Memory / storage
  • Integrations
  • API / contracts
  • UI / DX
  • CI/CD / infra

Linked Issue/PR

Real behavior proof (required for external PRs)

  • Behavior addressed: Telegram polling startup emits the normal [telegram][diag] polling cycle started ... diagnostic through the normal log channel instead of the error channel, while non-diag [telegram] warnings/errors remain on the error channel.
  • Real environment tested: Local checkout running the Telegram monitor seam with the repo's Telegram Vitest project config.
  • Exact steps or command run after this patch: node scripts/run-vitest.mjs extensions/telegram/src/monitor.test.ts
  • Evidence after fix (screenshot, recording, terminal capture, console output, redacted runtime log, linked artifact, or copied live output): Terminal capture from the passing run shows the startup diagnostic on stdout, not stderr, and the restart warning test preserves non-diag output on runtime.error:
Test Files  1 passed (1)
Tests  34 passed (34)
  • Observed result after fix: The regression test logs polling startup diagnostics without using the error channel passes, the regression test keeps polling restart warnings on the error channel preserves non-diag warning output on runtime.error, and the full Telegram monitor test file reports 34 passed (34).
  • What was not tested: A live Telegram bot/gateway session was not run because the local evidence is a log-severity routing bug at the monitor seam and live credentials are not available in this workflow.
  • Before evidence (optional but encouraged): Redacted original evidence showed the normal startup diagnostic rendered with error coloring:
"[telegram] [diag] polling cycle started inFlight=0 outcome=not-started startedAt=n/a finishedAt=n/a durationMs=n/a offset=n/a"
rendered with ERROR coloring in console output.

Root Cause (if applicable)

  • Root cause: monitorTelegramProvider collapsed all polling monitor output to opts.runtime?.error ?? console.error, and TelegramPollingSession sends normal lifecycle diagnostics through the injected logger.
  • Missing detection / guardrail: There was no monitor-level assertion that normal polling startup diagnostics avoid the error channel or that non-diag warnings remain on the error channel.
  • Contributing context (if known): The lower-level polling session only receives a simple line logger, so the severity decision belongs at the monitor boundary.

Regression Test Plan (if applicable)

  • Coverage level that should have caught this:
    • Unit test
    • Seam / integration test
    • End-to-end test
    • Existing coverage already sufficient
  • Target test or file: extensions/telegram/src/monitor.test.ts
  • Scenario the test should lock in: Starting the polling monitor logs polling cycle started via runtime.log and does not call runtime.error, while non-diag polling restart warnings still call runtime.error.
  • Why this is the smallest reliable guardrail: The bug is at the monitor-to-polling logger wiring boundary, not in Telegram networking or polling behavior.
  • Existing test that already covers this (if any): None before this PR.
  • If no new test is added, why not: N/A

User-visible / Behavior Changes

Normal Telegram [telegram][diag] polling startup diagnostics no longer appear as error-level console output. Non-diag Telegram warnings/errors remain error-level output.

Diagram (if applicable)

Before:
Telegram monitor -> polling session diagnostic -> runtime.error -> error-colored startup line

After:
Telegram monitor -> [telegram][diag] polling session diagnostic -> runtime.log -> normal startup line
Telegram monitor -> non-diag [telegram] warning/error -> runtime.error -> error output
Persistence failures -> runtime.error -> error output

Security Impact (required)

  • New permissions/capabilities? (Yes/No) No
  • Secrets/tokens handling changed? (Yes/No) No
  • New/changed network calls? (Yes/No) No
  • Command/tool execution surface changed? (Yes/No) No
  • Data access scope changed? (Yes/No) No
  • If any Yes, explain risk + mitigation: N/A

Repro + Verification

Environment

  • OS: Local checkout
  • Runtime/container: Node v24.15.0 for local test execution
  • Model/provider: N/A
  • Integration/channel (if any): Telegram plugin polling monitor
  • Relevant config (redacted): Test fixture with isolated ingress disabled

Steps

  1. Run the Telegram monitor with an injected runtime logger.
  2. Start one polling cycle.
  3. Inspect runtime log and error calls.

Expected

  • polling cycle started is logged through runtime.log.
  • runtime.error is not called for normal [telegram][diag] startup diagnostics.
  • Non-diag [telegram] warnings/errors remain on runtime.error.

Actual

  • Before this patch, the monitor's injected logger was runtime.error.
  • After this patch, the monitor logger routes [telegram][diag] lines to runtime.log; the regression tests confirm runtime.error is untouched for startup diagnostics and still receives non-diag restart warnings.

Evidence

Attach at least one:

  • Failing test/log before + passing after
  • Trace/log snippets
  • Screenshot/recording
  • Perf numbers (if relevant)

Human Verification (required)

What you personally verified (not just CI), and how:

  • Verified scenarios: Full Telegram monitor test file passes locally with the Telegram-specific Vitest config.
  • Edge cases checked: Offset persistence/delete error paths still call logError/runtime.error; [telegram][diag] diagnostics use runtime.log; non-diag [telegram] warnings/errors remain on runtime.error.
  • What you did not verify: Live Telegram bot polling against Telegram API.

Review Conversations

  • I replied to or resolved every bot review conversation I addressed in this PR.
  • I left unresolved only the conversations that still need reviewer or maintainer judgment.

If a bot review conversation is addressed by this PR, resolve that conversation yourself. Do not leave bot review conversation cleanup for maintainers.

Compatibility / Migration

  • Backward compatible? (Yes/No) Yes
  • Config/env changes? (Yes/No) No
  • Migration needed? (Yes/No) No
  • If yes, exact upgrade steps: N/A

Risks and Mitigations

  • Risk: Normal [telegram][diag] Telegram monitor diagnostics become less visually prominent.
    • Mitigation: Actual non-diag warnings/errors and offset persistence/delete failures still use runtime.error; the changed startup line is explicitly a normal lifecycle diagnostic.

@openclaw-barnacle openclaw-barnacle Bot added channel: telegram Channel integration: telegram size: XS maintainer Maintainer-authored PR labels May 17, 2026
@clawsweeper

clawsweeper Bot commented May 17, 2026

Copy link
Copy Markdown
Contributor

Codex review: needs real behavior proof before merge.

Summary
The PR rewires Telegram polling monitor diagnostics to the normal runtime log channel, keeps offset persistence/delete failures on the error channel, and adds a monitor regression test.

Reproducibility: yes. from source inspection: current main wires the monitor logger to runtime.error, and the polling session emits the startup diagnostic through that injected logger. I did not execute a live Telegram repro in this read-only review.

Real behavior proof
Needs real behavior proof before merge: The PR body includes copied Vitest terminal output, but external PR proof needs redacted terminal/log/recording evidence from a real Telegram monitor or gateway run; updating the PR body should trigger re-review, or a maintainer can comment @clawsweeper re-review. After adding proof, update the PR body; ClawSweeper should re-review automatically. If it does not, ask a maintainer to comment @clawsweeper re-review.

Next step before merge
Human review is needed because the PR has the protected maintainer label and the contributor proof is mock-only; there is no narrow automation repair to request.

Security
Cleared: The diff only changes Telegram plugin logging and a colocated test; it does not add dependencies, permissions, secrets handling, package metadata, CI, or new network/code-execution paths.

Review details

Best possible solution:

Land the narrow monitor logger-boundary fix after maintainer review and real runtime log evidence, keeping normal polling diagnostics on runtime.log and true persistence failures on runtime.error.

Do we have a high-confidence way to reproduce the issue?

Yes from source inspection: current main wires the monitor logger to runtime.error, and the polling session emits the startup diagnostic through that injected logger. I did not execute a live Telegram repro in this read-only review.

Is this the best way to solve the issue?

Yes for the code shape: the monitor boundary owns the severity decision because TelegramPollingSession receives only a line logger, and the PR preserves explicit error logging for offset persistence/delete failures.

What I checked:

  • Current main routes monitor logs to the error channel: On current main, monitorTelegramProvider defines the shared log function as opts.runtime?.error ?? console.error, so downstream diagnostics injected through log are error-channel output. (extensions/telegram/src/monitor.ts:111, 58f1db1bc8eb)
  • Startup diagnostic uses the injected logger: TelegramPollingSession emits [telegram][diag] polling cycle started ... through this.opts.log, which makes the current monitor wiring the source of the wrong severity. (extensions/telegram/src/polling-session.ts:674, 58f1db1bc8eb)
  • PR head changes the severity boundary: At PR head, log uses runtime.log/console.log, logError keeps explicit offset delete/persist failures on runtime.error, and the polling session still receives the normal log function. (extensions/telegram/src/monitor.ts:111, 8d19cc435b0d)
  • PR adds a focused regression test: The new test runs the monitor seam with an injected runtime and asserts polling cycle started reaches runtime.log while runtime.error is untouched. (extensions/telegram/src/monitor.test.ts:475, 8d19cc435b0d)
  • Feature history points to the monitor/polling extraction: The monitor-to-polling logger seam appears to date to the polling session extraction, which kept the monitor logger injected into the new session object. (src/telegram/monitor.ts, 1d301f74a6a9)
  • Related issue and protected label context: The provided GitHub context shows this PR closes [Bug]: Telegram polling startup diagnostic is logged at error level #82957 and carries the protected maintainer label, so this cleanup review should not close it automatically.

Likely related people:

  • steipete: Introduced/extracted the Telegram polling session seam that carries the monitor logger into TelegramPollingSession, and has repeated follow-up work in the Telegram monitor/polling history. (role: feature-history owner; confidence: high; commits: 1d301f74a6a9, 0c0f1e34cba0, 6a2c5b2b54a7; files: src/telegram/monitor.ts, src/telegram/polling-session.ts, extensions/telegram/src/monitor.ts)
  • vincentkoc: Recently split Telegram monitor runtime types and lazy-loaded monitor runtime graphs, touching the same monitor boundary after the plugin move. (role: recent area contributor; confidence: medium; commits: ae4fdaea8207, 4309dc6d5ee9, 5b952836e3d9; files: extensions/telegram/src/monitor.ts, extensions/telegram/src/monitor.types.ts, extensions/telegram/src/monitor-polling.runtime.ts)
  • scoootscooob: Moved the Telegram implementation from src/telegram into extensions/telegram, carrying this monitor/polling logging boundary into the plugin package. (role: migration carrier; confidence: medium; commits: e5bca0832fbd; files: src/telegram/monitor.ts, extensions/telegram/src/monitor.ts, src/telegram/polling-session.ts)

Remaining risk / open question:

  • The PR body only provides Vitest/seam output, not a real Telegram monitor or gateway run after the fix.
  • The shared log helper also moves recoverable polling network restart/suppression messages to normal output; that appears consistent with the patch boundary but is worth maintainer confirmation.

Codex review notes: model gpt-5.5, reasoning high; reviewed against 58f1db1bc8eb.

@YonganZhang

Copy link
Copy Markdown
Contributor

Drive-by +1 from #83047 — happy to see this landing with regression-test coverage. Two small observations from my independent fix attempt that might or might not already be covered:

  • [telegram] (non-diag) lines still want the error channel — the discriminator should be inclusion-based (includes("[telegram][diag]") routes to runtime.log), not exclusion-based, so true error lines like [telegram] Restarting polling after polling-network-failure: ECONNRESET and [telegram] reconnect delivery drain failed: ... keep landing on runtime.error. Worth a test row if not already present.
  • polling-session.ts:260 self-wraps incoming info: ... into [telegram][diag] ${msg} before forwarding, which confirms [diag] is the intended info marker — same conclusion the test should encode.

Closing my parallel PR. Thanks for picking this up.

@galiniliev galiniliev self-assigned this May 25, 2026
@galiniliev

Copy link
Copy Markdown
Contributor Author

Codex review: blocking finding before merge.

This fixes a real Telegram logging bug, but the implementation moves too much output off the error channel. It changes the shared monitor logger, not just the startup diagnostic path.

Finding

  • Blocking: extensions/telegram/src/monitor.ts:111 changes the single log helper to runtime.log, then passes that helper into TelegramPollingSession at extensions/telegram/src/monitor.ts:288. That also moves non-diagnostic failure/restart lines to normal output: reconnect delivery drain failures, timed-out spool handlers, polling stalls, runner stop timeouts, and polling network/conflict errors all still call this.opts.log(...) in extensions/telegram/src/polling-session.ts. The PR preserves offset persistence failures on logError, but not these other actual polling failure paths. Best fix: route only [telegram][diag] lifecycle diagnostics to runtime.log, keep non-diag [telegram] ... failure/restart lines on runtime.error, or split the polling-session contract into info/error loggers with tests for both.

Context

Bug fixed: #82957, Telegram polling startup diagnostics incorrectly rendered as error output.

Affected surface: Telegram plugin polling monitor, extensions/telegram/src/monitor.ts and extensions/telegram/src/polling-session.ts.

Provenance: likely introduced by the existing monitor/polling logger seam; current origin/main wires monitor log to runtime.error, while polling-session startup diagnostics use that injected logger. The startup bug is real, but the PR's fix broadens the severity change beyond the reported diagnostic.

Verification: source-reviewed against fetched origin/main and PR head 8d19cc435b0d. I did not run local PR tests because the checkout is on another review branch, not the PR head. Live PR CI is currently failing/unstable on run 25983083930.

@galiniliev galiniliev force-pushed the bug-005-telegram-polling-log-level branch from a6fabe4 to 979c6f3 Compare May 25, 2026 01:34
@galiniliev

Copy link
Copy Markdown
Contributor Author

Verification before merge:

  • Head SHA: 979c6f31a489300f33a562e412afc558ef3e9599
  • Local focused test after code fix: node scripts/run-vitest.mjs extensions/telegram/src/monitor.test.ts -> 34 passed (34)
  • Local changelog/rebase sanity: git diff --check -> clean
  • CI: run 26378692736 on head 979c6f31a489300f33a562e412afc558ef3e9599 completed successfully
  • Real behavior proof: PR body records the Telegram monitor seam proof; no live Telegram bot/gateway session was run because this is a logger-severity routing change at the monitor seam and live credentials were not available

@galiniliev galiniliev merged commit b5c1199 into openclaw:main May 25, 2026
92 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

channel: telegram Channel integration: telegram maintainer Maintainer-authored PR P2 Normal backlog priority with limited blast radius. size: S

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Telegram polling startup diagnostic is logged at error level

2 participants