本卡屬 FR-181(母卡 FR-181 母案 CM-3595),卡 B-6d,批 10。只改 主 repo。依賴:B-6b、B-6c。
對帳改走長輪詢的主系統端:把 B-6c 定義的 file_verifier port 實作成「每檔 ask(verify_file)」注入給套件,跟 A-1 已經注入的四個 port 放同一處。注意對帳是逐檔問、每檔佔等回答配額一條,先做序列(百檔約 2 分鐘),實測時間寫回寫;要並發另開卡。同時主系統釘契約 0.5.2、remote-agent 1.17.2。驗收要用一個「證據存 Agent 側」的租戶(DEV 的 STORAGE_CONFIG 設 remote_agent 指本機 Agent)上傳幾檔實按對帳,含竄改、刪檔、Agent 停掉三種情況。
extend:core/plugins/_agent_channel.py channel_adapters() 回傳 dict 加 file_verifier=LazyFileVerifier()——實作 (agent, file_uid):agent_request_service.ask(agent, KIND_VERIFY_FILE, {"file_uid": file_uid}, timeout=15) 回 result["sha256"];AgentRequestFailed 且 reason=missing → 回 None;逾時/busy → 原樣拋給套件記 unreachable。🔴 reconcile 是逐檔同步 ask,N 檔=N 次 ask 各佔等回答配額一條——改成每檔序列呼叫(不並發),百檔約 2 分鐘,回寫記實測時間;若要並發另開卡。釘 0.5.2/1.17.2、poetry update 兩支
repo:~/Projects/Billows/Audit-Manager/compliance-manager-be
改既有:core/plugins/_agent_channel.py
改既有:pyproject.toml
改既有:poetry.lock
改既有:test/test_agent_outbound_only.py(對帳路徑加進「開關關不直推」五條變六條)
core/plugins/_agent_channel.py:加 class LazyFileVerifier(照同檔 LazyReplySink 的延遲解析形狀):__call__(agent, file_uid) → request_service().ask(agent, KIND_VERIFY_FILE, {"file_uid": file_uid}, timeout=15) 回 result["sha256"];AgentRequestFailed 且 reason == "missing" → None;其他例外原樣拋。channel_adapters() 回傳 dict 加 file_verifier=LazyFileVerifier()。pyproject.toml 釘 jedi-agent-protocol==0.5.2、jedi-remote-agent==1.17.2;env -u VIRTUAL_ENV poetry update jedi-agent-protocol jedi-remote-agent(只指名這兩支)。test/test_agent_outbound_only.py 第②支「開關關不直推」五條加第六條:reconcile 走 verifier 不碰 AgentDataPlaneClient.command。system_configs.STORAGE_CONFIG 設成 remote_agent 指本機 Agent(🔴 只改 DEV);上傳 3 檔 → 管理頁對帳 {total:3, matched:3};到 Agent 的 upload 目錄手改一檔內容 → mismatched 1;刪一檔 → missing 1;停本機 Agent(kill 核過的 PID)再對帳 → error 3 reason unreachable、整個請求 30 秒內回;實測 3 檔對帳耗時寫回寫。DEV 本機 Agent(證據存 Agent 的租戶,STORAGE_CONFIG=remote_agent 指本機 Agent)上傳 3 檔 → 管理頁「對帳」→ {total:3, matched:3};Agent 側手改一檔 bytes → mismatched 1;刪一檔 → missing 1;Agent 停掉 → error 3 reason unreachable、30 秒內回不 500;守衛六條綠
~/Projects/Billows/Audit-Manager/compliance-manager-be/docs/features/FR-181-2611-agent-outbound-only-channel/design.md §3 決策定案(D1~D8)、§4 端到端流程兩張圖、§5 詳細設計本卡那節、§7 拆分表本卡那列;為什麼這樣定看 discussion.mdcore/plugins/_agent_commands.py(檔頭說明三個觸發點)、app/remote_agent/service/agent_command_service.py、core/plugins/_agent_config_notify.py、core/plugins/_agent_keys.py、infra/upload_file/remote_agent_adapter.py、core/plugins/remote_agent.py(plugin mount 與 handle)jedi-remote-agent/jedi_remote_agent/api/routing.py(端點表與 AUTH_AGENT)、api/routes/(心跳 route 範本)、app/service/agent_data_plane_client.py(直推出口,留著)、app/service/heartbeat_vulndb.py(_CORE_KEYS 心跳守衛);契約 jedi-agent-protocol/jedi_agent_protocol/commands.py、heartbeat.py、events.pyguidant_agent/sync/app/config_pull.py(WorkerComponent 拉取範本)、enroll.py(心跳 client 與通行證)、event_sender.py+outbox.py(送不到補送)、task_queue.py、sync/api/data_plane_server.py(8443 與 blueprint 掛點)、sync/api/cmd_*.py(直推 handler,本案改薄)、files/api/blob_route.py、scan/api/routes/、docs/ARCHITECTURE.md