fix(chat): mark execution dispatched + persist real session_id (#686) - #795
Merged
Conversation
AndriiPasternak31
added a commit
that referenced
this pull request
May 11, 2026
… test The new test/unit/test_chat_dispatched_marker.py landed with two bare sys.modules.pop() calls that exceeded the Issue #762 lint baseline (tests/lint_sys_modules.py — added on dev). PR #795 lint job failed. Fix: - Module bootstrap (`for _shadow in (...): sys.modules.pop(_shadow, None)` + sys.path mangling): deleted entirely. tests/unit/conftest.py already inserts src/backend into sys.path and preloads the canonical `utils` package via _preload_backend_utils(); the per-file bootstrap was redundant. Kept the `_BACKEND` Path constant — used by the AST tests. - Fixture teardown (`for mod in (...): sys.modules.pop(mod, None)`): switched to `monkeypatch.delitem(sys.modules, mod, raising=False)`. monkeypatch handles both the pre-yield eviction (so `from db.schedules import ...` re-imports against the fresh TRINITY_DB_PATH) and the post-yield restore at fixture teardown — same isolation guarantee, scoped automatically. Verified locally: - AST scan finds zero bare sys.modules mutations in this file - pytest tests/unit/test_chat_dispatched_marker.py: 10 passed Refs #686, #762 Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The interactive /api/chat handler lacked the mark_execution_dispatched() defense that lives in services/task_execution_service.py, so cold-start or large-prompt chat executions were being false-stamped FAILED by cleanup_service.mark_no_session_executions_failed after 60s while the agent was still healthy and processing. Mirrors task_execution_service.py:401-410 (commit 2798ca9, issue #279): 1. routers/chat.py:317-321 — call db.mark_execution_dispatched() before agent_post_with_retry so the no-session sweep skips the row. 2. routers/chat.py:411-428 — on SUCCESS, replace the 'dispatched' sentinel with the real Claude session UUID from response_data/session_data/metadata (UC1 — closes the observability gap so /api/chat rows show the real UUID instead of permanently reading 'dispatched'). Tests (tests/unit/test_chat_dispatched_marker.py): - DB-level: real sqlite verifies dispatched rows survive the 60s no-session sweep AND NULL/'' rows are still caught. - AST-level: parses routers/chat.py and asserts marker ordering, the try/except wrapper, the claude_session_id kwarg on the SUCCESS update, and the FAILED-path update_execution_status survive future refactors. - Mirror invariant: routers/chat.py and task_execution_service.py must BOTH contain the mark_execution_dispatched call — guards against the recurring bug class behind #279 and #686. Docs updated: cleanup-service.md and task-execution-service.md now document both producers of the 'dispatched' sentinel. Fixes #686 Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
… test The new test/unit/test_chat_dispatched_marker.py landed with two bare sys.modules.pop() calls that exceeded the Issue #762 lint baseline (tests/lint_sys_modules.py — added on dev). PR #795 lint job failed. Fix: - Module bootstrap (`for _shadow in (...): sys.modules.pop(_shadow, None)` + sys.path mangling): deleted entirely. tests/unit/conftest.py already inserts src/backend into sys.path and preloads the canonical `utils` package via _preload_backend_utils(); the per-file bootstrap was redundant. Kept the `_BACKEND` Path constant — used by the AST tests. - Fixture teardown (`for mod in (...): sys.modules.pop(mod, None)`): switched to `monkeypatch.delitem(sys.modules, mod, raising=False)`. monkeypatch handles both the pre-yield eviction (so `from db.schedules import ...` re-imports against the fresh TRINITY_DB_PATH) and the post-yield restore at fixture teardown — same isolation guarantee, scoped automatically. Verified locally: - AST scan finds zero bare sys.modules mutations in this file - pytest tests/unit/test_chat_dispatched_marker.py: 10 passed Refs #686, #762 Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Reject malformed claude_session_id values from the agent-server response before passing to db.update_execution_status. On rejection, leave the 'dispatched' sentinel in place so the cleanup sweep stays correct; observability is lost for that row but trust boundary on agent-supplied data is preserved. Refs #686 Co-Authored-By: Claude <noreply@anthropic.com>
- .gitignore: ignore src/backend/config/agent-templates/quota-*/ so future test runs don't leave behind discoverable template directories (mirrors existing test-*/ pattern). - docs/security-reports/cso-diff-2026-05-12.md: CSO diff audit of this branch vs origin/dev. Verdict: CLEAR. One LOW housekeeping item (the quota-* residue) addressed by this commit. Refs #686 Co-Authored-By: Claude <noreply@anthropic.com>
AndriiPasternak31
force-pushed
the
AndriiPasternak31/issue-686-plan
branch
from
May 12, 2026 00:00
ece8a7d to
b16f2d8
Compare
The new tests/unit/test_cleanup_unreachable_orphan.py landed with three bare module-level sys.modules assignments (lines 64/76/79) that exceeded the Issue #762 lint baseline. PR #795 lint job failed. Fix: move the docker / services.docker_service / database stubs into an autouse fixture using monkeypatch.setitem. Each test method's lazy `from services.cleanup_service import CleanupService` and `@patch(...)` resolution both happen after fixture setup, so the stubs land in time — and monkeypatch handles teardown so the next test isn't poisoned. Verified locally: - AST scan finds zero bare sys.modules mutations in this file - pytest tests/unit/test_cleanup_unreachable_orphan.py: 6 passed Refs #686, #762 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
AndriiPasternak31
marked this pull request as draft
May 12, 2026 00:12
AndriiPasternak31
marked this pull request as ready for review
May 12, 2026 00:20
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fixes #686 — the interactive
/api/chathandler was missing themark_execution_dispatched()defense that lives inservices/task_execution_service.py, so cold-start or large-prompt chat executions were being false-stamped FAILED bycleanup_service.mark_no_session_executions_failedafter 60s while the agent was still healthy and processing. This is the parallel codepath of #279 (which fixed the same bug class for/task).routers/chat.py:317-321— calldb.mark_execution_dispatched()beforeagent_post_with_retryso the no-session sweep skips the rowrouters/chat.py:411-428— on SUCCESS, replace the'dispatched'sentinel with the real Claude session UUID derived fromresponse_data→session_data→metadata(UC1, closes the observability gap so/api/chatrows show the real UUID instead of permanently reading'dispatched')task_execution_service.py:401-410(commit 2798ca9, issue bug: Chat-triggered executions fail with 'Silent launch failure' despite agent being healthy #279)Tests
tests/unit/test_chat_dispatched_marker.py(3 layers):''rows are still caughtrouters/chat.pyand asserts marker ordering, the try/except wrapper, theclaude_session_idkwarg on the SUCCESS update, and the FAILED-pathupdate_execution_statussurvive future refactorsrouters/chat.pyandtask_execution_service.pymust BOTH contain themark_execution_dispatchedcall — guards against the recurring bug class behind bug: Chat-triggered executions fail with 'Silent launch failure' despite agent being healthy #279 and bug: MCP-triggered chat executions fail with 'Silent launch failure' (regression / parallel codepath of #279) #686Docs
docs/memory/feature-flows/cleanup-service.md— broadened the no-session sweep +mark_execution_dispatcheddocs to list both producers of the'dispatched'sentineldocs/memory/feature-flows/task-execution-service.md— Coverage-table note on the Interactive chat row + Step 3b "parallel codepath" sub-paragraph; service still does NOT cover/chat, only the dispatched-sentinel mechanism is now sharedTest plan
pytest tests/unit/test_chat_dispatched_marker.py— 3 test layers pass locally