# Task: Fix AgentBus attachment rejection reply ## Identity - Task ID: 20260831-fix-agentbus-attachment-reply-6f2c9a41 - Mode: Feature - Branch: main - Worktree: /Users/inmanx/Documents/lwltAPI - Base commit: d7a821da1627548186e8834350e09a66c44140d7 - Owner: codex - Status: Planning ## Scope - Diagnose why a structured AgentBus roster attachment that returns `input_attachment.status = rejected` leaves the original task waiting but sends no rejection feedback to the channel user. - Add an attempt-level failed result for rejected roster attachments in both legacy in-memory and database-backed durable AgentBus delivery modes. - Preserve the original task's `awaiting_attachment` state, avoid scheduling parsing for rejected bytes, and add focused regression coverage. - Run the full repository gates, commit the bounded fix on `main`, and push it non-forced to `origin/main`. ## Intent And Constraints - Keep the existing fail-closed roster workflow: a rejected workbook must not enter Program parsing or ERP execution, and the same waiting task must remain available for a corrected attachment. - Return the existing bounded `input_attachment.message`; do not expose attachment URL, hostname, IP, file name, workbook bytes, cell values, raw converter output, or unsafe error details. - Preserve the durable accepted/result outbox, inbound frame reply routing, conversation correlation, and idempotent delivery keys. - Do not deploy, restart services, mutate Kubernetes, access ERP, read secrets, retry the live task, or send an external message. ## Outcome - Confirmed the feedback gap was not an AgentBus transport exception. Workbook rejection is represented as a successful `TaskMessageResult` while the business task intentionally remains `awaiting_attachment`; therefore the generic exception reply did not run and the terminal-task finalizer correctly skipped the still-waiting task. - Added an explicit attachment-attempt rejection branch immediately after task ingestion. It emits a failed `task.result` through the database outbox for durable channels or the existing pending-reply path for legacy listeners, then returns without requesting the parse queue. - Kept the task state and reusable waiting workflow unchanged. The channel receives the existing safe workbook rejection text and can submit a corrected `.xls/.xlsx` attachment in a later message. - Added direct-listener and durable-channel regressions covering reply routing, failure status/text, retained waiting state, and zero parse-queue requests. ## Verification - Focused AgentBus tests: 16/16 passed. - `node --run check:repo`: 10/10 passed. - `node --run check`: passed. - `node --run test:control-plane`: 139/139 passed. - `node --run test:legacy`: 256/256 passed. - `node --run build`: passed. - `check_project_docs.py`: passed. - `check_doc_drift.py --task-id 20260831-fix-agentbus-attachment-reply-6f2c9a41`: passed. - `git diff --check`: passed. ## Follow-ups - Deploy/restart and verify the corrected reply with a real WeChat attachment only under separate authorization. ## Promotion Candidates - Target canonical AgentBus/data-flow memory during a later Integration task. - Proposal: roster workbook rejection is an attachment-attempt failure that must create an immediate failed AgentBus result even though the reusable business task remains nonterminal in `awaiting_attachment`. - Evidence: `control-plane/src/agentbus.ts`, `control-plane/test/agentbus.test.ts`, and the focused 16/16 AgentBus regression. - Human confirmation required: no for the bounded reply behavior; deployment and live retry remain separately authorized.