docs: Document agent-log persistence [doc-updater] - #3569
Conversation
Update docs to reflect the operator-observability work in #3547: - get_container_logs now falls back to a persisted post-reap capture; deployment-diagnostics.md's caveat about reaped-pod logs was stale. - New get_agent_transcript MCP tool, agent-logs REST routes, and the session-state index route were missing from orchestrator/README.md. - New agent_log_store.py module missing from STRUCTURE.md.
There was a problem hiding this comment.
Review: docs — Document agent-log persistence
Documentation-only PR (3 markdown files, +40/−12) covering the operator-observability work in #3547. For a docs PR the review is accuracy against the referenced code, so I traced every factual claim to its implementation. All claims are accurate.
Verified against code
agent_log_store.py— Redis-backed,AGENT_LOG_TTL_SECONDS = 24 * 60 * 60(24h), captured byremove_agent_jobbefore Job deletion via_persist_job_logs_best_effort(kubernetes_spawner/_jobs.py:62,112). ✅get_container_logsfallback — both the REST route (routes/containers.py:511-524) and the MCP tool (mcp_tools/_health.py_handle_get_container_logs) fall back to the persisted capture and return"source": "persisted"+captured_at+exit_code. The doc's "both the REST route and the MCP tool" is precisely correct. ✅- New routes —
GET /agent-logs(metadata-only;list_recordsswaps the body forlog_bytes) andGET /agent-logs/{job_name}(full body viaget) exist atroutes/containers.py:534,550. ✅ - Session State section —
POST/GET /session-stateandGET /session-state/indexexist atroutes/session_state.py:56,117,131; the index route's docstring confirms it "backs theget_agent_transcriptMCP tool." ✅ get_agent_transcript—mcp_tools/_health.py:235reads the transcript from the session-state store;SESSION_STATE_TTL_SECONDS = 6 * 60 * 60matches the "~6-hour retention" claim. Correctly added to the Orchestrator-Backed Tools list. ✅- STRUCTURE.md entry for
agent_log_store.pyis accurate. ✅
Markdown structure (headings, blank lines, code fences, issue links) is well-formed.
Non-blocking suggestion
The failure-mode enumeration in deployment-diagnostics.md frames the capture as covered whenever "the orchestrator observes the exit and reaps the Job itself," then lists the residual logs_unavailable cases (non-remove_agent_job removal, TTL expiry, Redis unavailable). One real case isn't called out: the capture is strictly best-effort — if read_job_log_snapshot returns empty because the pod was already GC'd by the time remove_agent_job ran (a race even on the reap path), no capture is written despite remove_agent_job having executed. An operator might otherwise assume a capture always exists once the orchestrator did the reaping. Consider adding a half-sentence noting the capture is best-effort and can be absent even on the remove_agent_job path. Purely a completeness nit; not blocking.
Note (not a finding)
except ValueError, TypeError: appears in agent_log_store.py:133 and containers.py:494,511. This looks like Python-2 syntax but is valid under Python 3.14 (PEP 758, unparenthesized exception groups); the repo runs 3.14.6 and I confirmed the runtime semantics catch both types. Flagging only so a future reader on an older interpreter is aware — no change needed here, and none of it is in this diff.
No blocking issues found.
— Authored by egg
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
Address review suggestion: the persisted log capture can be absent even when remove_agent_job ran, if the pod was already GC'd before the pre-removal log read. Clarify a missing capture does not imply the orchestrator failed to reap the Job.
|
Thanks for the thorough trace-to-code review. One actionable item; addressed in-PR.
— Authored by egg |
This comment has been minimized.
This comment has been minimized.
There was a problem hiding this comment.
Re-review: docs — Document agent-log persistence
The prior review (approve-with-suggestions at 5743b5c) had one non-blocking item: the persisted log capture is strictly best-effort and can be absent even when remove_agent_job ran, so a missing capture must not be read as "the orchestrator failed to reap the Job." The branch was reworked to a single commit on top of main (7812a25); the only content delta from the reviewed state is the half-sentence that closes that suggestion. I re-traced the new claim and re-verified the surrounding claims against code.
The new claim is accurate
if the pod was already GC'd by the time
remove_agent_jobran, the pre-removal log read comes back empty and no capture is written — so a missing capture does not imply the orchestrator failed to reap the Job.
Confirmed against the actual code path:
_persist_job_logs_best_effort(orchestrator/kubernetes_spawner/_jobs.py:62) callsread_job_log_snapshotand doesif not snapshot: return(and a secondif not pipeline_id or logs is None: return) — noput, so no capture is written.remove_agent_jobstill proceeds toremove_containerafterward, so the reap happens regardless. ✅read_job_log_snapshot(orchestrator/kubernetes_client.py:455) resolves the pod and reads it inside atrythat returnsNoneon any exception. When the pod is already GC'd,get_pod_for_job/read_namespaced_podraises and the snapshot comes backNone→ early return in the caller. This is exactly the "read comes back empty, no capture" case the doc describes. ✅
Re-verified the rest of the diff
ttlSecondsAfterFinishedrace example — real: one-shot Jobs are created withttl_seconds_after_finished(default 600s,kubernetes_client.py:351), so raw k8s GC winning the race beforeremove_agent_jobis a genuine non-remove_agent_jobremoval path. ✅24-hour TTL—AGENT_LOG_TTL_SECONDS = 24 * 60 * 60(agent_log_store.py:46). ✅- Fallback payload
"source": "persisted"+captured_at+exit_code— present in both the REST route (routes/containers.py:518-520) and the MCP tool (mcp_tools/_health.py:100,226). The doc's "both the REST route and the MCP tool" holds. ✅ - New routes —
GET /agent-logs(metadata-only; docstring confirmslog_bytesin place of the body,routes/containers.py:534) andGET /agent-logs/{job_name}(full body,:550). ✅ - Session State section —
POST/GET /session-stateandGET /session-state/indexexist (routes/session_state.py:117,131); the index docstring literally states it backs theget_agent_transcriptMCP tool and returns metadata only. ✅ get_agent_transcript(~6-hour retention) —mcp_tools/_health.py:235;SESSION_STATE_TTL_SECONDS = 6 * 60 * 60(session_state_store.py:54). Correctly added to the Orchestrator-Backed Tools list inorchestrator/README.md. ✅- STRUCTURE.md
agent_log_store.pyentry is accurate. ✅
The suggestion was addressed substantively, not superficially, and the change is internally consistent with the failure-mode enumeration around it. No new inaccuracies introduced. Markdown is well-formed.
No blocking issues. Approving.
— Authored by egg
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
…-065011-3175/work # Conflicts: # docs/guides/deployment-diagnostics.md
Conflict Resolution SummaryResolved merge conflicts with
Context: How each region was resolved:
Verification: Please review:
— Authored by egg |
This comment has been minimized.
This comment has been minimized.
There was a problem hiding this comment.
Re-review: docs — Document agent-log persistence
Requesting changes. The delta since my prior review (7812a25) is a single merge of main (d17ab78). That merge introduced one concrete defect that neither the conflict-resolution pass nor a diff-only read of the flagged conflict would catch, because git auto-merged it silently.
Blocking: agent_log_store.py is listed twice in docs/development/STRUCTURE.md
main had independently documented the same #3547 work via #3570 (dc2d9655c, docs: reflect #3547 agent-log persistence…), which added an agent_log_store.py entry to STRUCTURE.md. This PR added its own agent_log_store.py entry. The two insertions landed on different lines of the tree listing, so git merged them as two independent additions — no textual conflict was raised, and the conflict-resolution summary (which only covers deployment-diagnostics.md) never touched STRUCTURE.md.
The result on the branch head (d17ab78):
144:├── agent_log_store.py # Redis-backed store for one-shot agent pod logs captured by `remove_agent_job` just before Job deletion; `get_container_logs` falls back to it once the live pod is gone (24h TTL) (#3547)
145:├── session_state_store.py # …
146:├── agent_log_store.py # Redis-backed store for one-shot agent pod logs captured at Job removal: `remove_agent_job` snapshots the pod's log tail before deletion, `get_container_logs` falls back to it once the live pod is gone; 24h TTL (#3547)
The same module now appears twice in the directory tree — in two different positions, with two different descriptions of the same file and the same issue. A structure listing that shows one file in two places is factually wrong, and this is a docs PR whose entire value is documentation accuracy. My prior review verified the single entry was accurate (✅ STRUCTURE.md agent_log_store.py entry is accurate); the merge is what created the duplicate, so it's squarely in scope for this re-review.
Fix: collapse to a single entry. Since main already carries one (currently line 146), the simplest resolution is to drop this PR's added line 144 (or keep whichever wording you prefer and delete the other). Confirm the tree has exactly one agent_log_store.py line afterward:
grep -c 'agent_log_store.py' docs/development/STRUCTURE.md # must be 1Everything else in the merge is clean
docs/guides/deployment-diagnostics.md— this was the git-flagged conflict. The resolution reads coherently end-to-end: no leftover conflict markers, no duplicated or orphaned paragraphs. It correctly kept this PR's fuller "Short-lived crashed pod logs are reaped quickly" prose while folding inmain's unique facts (the Job carried no pipeline label; theget_agent_transcripttranscript survives independentlyonly if the agent got far enough to push a transcript at least once; the #1805 follow-up now largely covered pipeline-wide). Verified against both parents.orchestrator/README.md— unchanged by the merge; the endpoint-table and tool-list additions I verified at7812a25still hold.- No conflict markers anywhere in the three changed files;
agent_log_store.pyis the only duplicated tree line.
Fix the STRUCTURE.md duplicate and this is good to go.
— Authored by egg
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
|
Thanks for catching the silent merge duplicate. One actionable item; fixed in-PR.
Note: — Authored by egg |
This comment has been minimized.
This comment has been minimized.
There was a problem hiding this comment.
Re-review: docs — Document agent-log persistence
Approving. The single blocking issue from my prior review (d17ab78) is fully resolved.
Blocking issue resolved: duplicate agent_log_store.py in STRUCTURE.md
Commit b2b4f84 ("docs: drop duplicate agent_log_store.py entry in STRUCTURE.md") collapses the two tree entries down to one. Verified at the branch tip:
grep -c 'agent_log_store.py' docs/development/STRUCTURE.md→ 1 (was 2).- The retained entry is
main's version —agent_log_store.py … Redis-backed store for one-shot agent pod logs captured at Job removal … 24h TTL (#3547)— correctly positioned immediately aftersession_state_store.pyin the store-module cluster (STRUCTURE.md:145). This PR's independently-added duplicate line was dropped, exactly as requested. session_state_store.pystill appears exactly once — the dedup did not clip an adjacent line.
Rest of the diff re-verified clean
- No conflict markers in any of the three changed files (
STRUCTURE.md,deployment-diagnostics.md,orchestrator/README.md). deployment-diagnostics.mdandorchestrator/README.mdare unchanged since I verified them at the merge — the persisted-fallback /get_container_logs/get_agent_transcript/ new-routes prose all remain accurate against the source (agent_log_store.py,routes/containers.py,routes/session_state.py,mcp_tools/_health.py).
The fix is substantive, not superficial. No new issues introduced. Good to merge.
Note (out of scope, unchanged): the pre-existing mypy failure in shared/egg_agent/client.py remains a base-branch issue — that file is byte-identical to origin/main and untouched by this docs PR.
— Authored by egg
|
egg review completed. View run logs 9 previous review(s) hidden. |
Update documentation to reflect the operator-observability work in 789ce6b / 8f94f3a / e928f75 (#3547):
get_container_logsnow falls back to a persisted post-reap capture instead of failing outright once the pod is gone; documented the newget_agent_transcriptevidence source and narrowed the true-miss case./agent-logsREST routes, the/session-state/indexroute, andget_agent_transcriptto the orchestrator-backed tool list.agent_log_store.pymodule.Triggered by: #3566 (closes #3547)
Authored-by: egg