本卡屬 FR-166(母卡 CM-母卡號(建完補)),卡 P0-6,階段 P0 底層、批 2。只改 jedi-python-package。依賴:P0-5。
主系統與 Agent 之間的心跳要多收多發幾個欄位;結果回報改成任何終態重送都不重做;加收 Agent 自主執行紀錄的批次端點、要求重啟端點、離線 7 天自動收尾的排程函式。
心跳契約是 Agent 與主系統的對外約定,一次定完;冪等改動碰核心
extend:心跳收發照 heartbeat_console.py 白名單收法加欄位;receive_result 短路條件從 cancelled 擴成任何終態(改既有判斷,不另開路徑);reaper 照 run_daily_tick 既有排程形狀
repo:~/Projects/Jedicogy/module/jedi-python-package
改既有:app/service/agent_enrollment_service.py 608
改既有:app/service/agent_task_service.py 170
改既有:api/routing.py 142
改既有:app/service/heartbeat_console.py
改既有:common/code.py(事件碼)
新開:app/service/heartbeat_offline.py
新開:app/service/agent_offline_reaper.py
新開:api/routes/local_run_route.py
新開:api/routes/agent_restart_route.py
細節在 design.md 對應段(~/Projects/Billows/Audit-Manager/compliance-manager-be/docs/features/FR-166-2610-agent-standalone-console/design.md §5,開 design.html 看導覽),本段只列本卡要做到的點:
outbox_size/local_admin_set/uptime_sec/last_restart_reason/console_allow_cidr_installed/sync_state/ldap_source(照 heartbeat_console.py 白名單收法,新檔 heartbeat_offline.py);回 offline_operators[]/console_allow_cidr/restart/ldap_config(後者由宿主 hook 填,本卡留接口)。receive_result:短路條件從 status == cancelled 擴成 status in TERMINAL;test:同 uid 重送 succeeded 回 200 且 write_success 只呼叫一次(突變:改回只 cancelled 要紅)。POST /agents/local-runs:AUTH_AGENT;批次 ≤50 否則 400;agent_id 從通行證取,body 的忽略;(agent_id, local_uid) 衝突視為已收回 200。POST /remote-agents/{uid}/restart:AUTH_ADMIN;body {mode: when_idle|now} 寫 restart_requested。agent_offline_reaper.run_daily_tick():dispatched/running 且 Agent last_heartbeat_at < now-7d → failed、agent_unreachable;0 筆不 log。common/code.py 加五個(值與 BE event_code.py 鏡像,先查 6089 之後空號)。同 uid 重送 succeeded 回 200 且 write_success 只跑一次(test);心跳回應含 offline_operators[];POST /agents/local-runs 51 筆回 400、重複 (agent_id,local_uid) 去重;reaper 對離線 8 天的 dispatched 標 failed、7 天不動
對照雛形:~/Projects/Billows/Audit-Manager/compliance-manager-be/docs/features/FR-166-2610-agent-standalone-console/prototype/index.html(上方「跟著走」)。