Skip to content

fix(agent-tools): wire channel_service into hard_delete_channels (#1290)#1294

Merged
axisrow merged 2 commits into
mainfrom
ao/tg_content_factory_5863f66be3-70/fix-1290-hard-delete
Jul 23, 2026
Merged

fix(agent-tools): wire channel_service into hard_delete_channels (#1290)#1294
axisrow merged 2 commits into
mainfrom
ao/tg_content_factory_5863f66be3-70/fix-1290-hard-delete

Conversation

@axisrow

@axisrow axisrow commented Jul 22, 2026

Copy link
Copy Markdown
Owner

Closes #1290

What

hard_delete_channels was dead since introduction: the tool built FilterDeletionService(db) without channel_service, so every call hit raise RuntimeError(\"hard_delete requires channel_service (dev mode)\"). The error was swallowed by the generic except and returned to the user as \"Ошибка удаления каналов\". The operation could never succeed regardless of arguments.

Root cause

src/agent/tools/filters.pyFilterDeletionService(db) missing the channel_service argument; hard_delete_channels_by_pks raises immediately when it is None.

The existing tests mocked FilterDeletionService entirely, so the real path was never exercised — that is exactly why the bug went undetected.

Fix

Wire a ChannelService when building the service, mirroring the CLI's _build_deletion_service in src/cli/commands/filter.py. ChannelService.delete() is a pure DB op (works with pool=None, queue=None), so this matches the proven CLI path and restores agent/CLI parity.

Test (TDD, mutation-verified)

  • New test_real_service_path_actually_deletes drives the real FilterDeletionService + :memory: DB (no service mock). Confirmed red on current main (Ошибка удаления каналов: hard_delete requires channel_service), green after the fix.
  • Mutation check: reverting the fix (back to FilterDeletionService(db)) turns the test red again.

Tests run

  • tests/test_agent_tools_filters.py + tests/test_filter_deletion_service.py — 60 passed
  • test_agent_tool_smoke_contract.py, test_tool_permissions_autoderive.py, test_agent_tools_init.py, test_agent_tools_registry.py — 103 passed (registry/parity intact)
  • ruff check — clean

Notes / risks

  • Decision per the issue's "решить осознанно": I chose to wire the service (parity with CLI, which has no dev-gate either) rather than remove the tool. The destructive-confirmation gate (require_confirmation + destructiveHint) remains the real guard.
  • No schema/API changes.

@axisrow

axisrow commented Jul 23, 2026

Copy link
Copy Markdown
Owner Author

🔍 Local review (cycle 1)

Reviewed locally (/review + Codex companion), no bots pingged.

Verdict Reviewer Finding Location
FIX codex Dev-mode hard-delete boundary is bypassed — agent_dev_mode_enabled not checked (CLI/web both enforce it) src/agent/tools/filters.py:220
SKIP codex Hard delete leaves active collectors uncancelled (queue=None skips task cancellation; orphan messages possible) src/agent/tools/filters.py:55

FIX → addressed in next commit: added dev-mode gate after confirmation, parity with CLI/web, TDD + mutation-verified.
SKIP → pre-existing gap identical to CLI _build_deletion_service and purge_filtered_channels (both queue=None); not a regression introduced here. Plubming a live CollectionQueue into the agent-tool context is a separate architectural change, out of scope for #1290.

axisrow and others added 2 commits July 23, 2026 14:52
The hard_delete_channels tool built FilterDeletionService(db) without a
channel_service, so every call hit `raise RuntimeError("hard_delete requires
channel_service (dev mode)")`, was swallowed by the generic except, and was
returned to the user as "Ошибка удаления каналов". The operation could never
succeed regardless of arguments.

Existing tests mocked FilterDeletionService entirely, so the real path was
never exercised — that is why the bug went undetected since the tool's
introduction.

Fix: build the service with a ChannelService (pool=None, queue=None —
delete() is a pure DB op, identical to the CLI's _build_deletion_service in
src/cli/commands/filter.py). Adds a regression test that drives the real
service/DB (no service mock); mutation-verified red without the fix.

Co-Authored-By: Claude <noreply@anthropic.com>
…bled (#1290)

Codex local review caught that the wired service made the irreversible
hard-delete reachable from the agent without the dev-mode guard that BOTH the
CLI (src/cli/commands/filter.py:227) and web (src/web/filter/handlers.py:31)
enforce. With confirm=true an agent call could permanently erase channels in
production despite developer mode being disabled — the "real dev-gate" the
issue's acceptance criteria asked for was missing.

Add the gate after require_confirmation (parity with CLI): refuse with a clear
message unless agent_dev_mode_enabled == "1". Tests:
- test_dev_mode_off_rejects_hard_delete: off → refusal, channel preserved
  (mutation-verified red without the gate)
- test_real_service_path_actually_deletes: updated to enable dev-mode
- mock tests updated to stub get_setting -> "1"

Co-Authored-By: Claude <noreply@anthropic.com>
@axisrow
axisrow force-pushed the ao/tg_content_factory_5863f66be3-70/fix-1290-hard-delete branch from 721d237 to 86c24d8 Compare July 23, 2026 06:54
@axisrow

axisrow commented Jul 23, 2026

Copy link
Copy Markdown
Owner Author

📋 Review summary — all cycles (local mode)

PR #1294fix(agent-tools): wire channel_service into hard_delete_channels (#1290). Reviewed locally (/review + Codex sol/xhigh), no bots pinged. Rebased onto fresh main 764bbda9 before round 3.

Cycle Reviewer Finding Verdict Resolution
1 codex Dev-mode hard-delete boundary bypassed — agent_dev_mode_enabled not checked (CLI/web enforce it) FIX Fixed in 86c24d88
1 codex Hard delete leaves active collectors uncancelled (queue=None) SKIP Pre-existing gap (identical to CLI _build_deletion_service + purge_filtered_channels); not a regression. Plumbing live CollectionQueue into agent-tool context = separate task, out of scope for #1290
2 codex — (gate review, stale base) APPROVE
3 codex — (gate review, fresh base 764bbda9) APPROVE
3 claude (/review) gate effective, accessor correct, no blockers APPROVE

Totals: 1 FIX (resolved), 1 SKIP (out-of-scope pre-existing), 0 UNVERIFIED.

Issue #1290 acceptance criteria:

  • confirm=true invocation performs deletion — and is now refused by a real dev-gate when agent_dev_mode_enabled != "1" (parity with CLI/web).
  • ✅ Regression test on agent-tool → FilterDeletionService path, mutation-verified red without the fix (test_real_service_path_actually_deletes).

Local mode does not auto-merge. CI is green on 86c24d88; merge is the owner's call.

@axisrow
axisrow merged commit 5300114 into main Jul 23, 2026
4 checks passed
@axisrow
axisrow deleted the ao/tg_content_factory_5863f66be3-70/fix-1290-hard-delete branch July 23, 2026 07:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

bug: agent-tool hard_delete_channels всегда падает RuntimeError — FilterDeletionService создаётся без channel_service

1 participant