feat(#3278): persist Claude session per (pipeline,slice,role) across event pods (re-land of orphaned #3286) - #3332
Merged
Merged
Conversation
…event pods Re-land of the orphaned #3278 work. PR #3286 was merged into the already-merged stacked branch egg/3279-reseed-threshold-injection rather than main, so its commits never reached main even though the PR shows MERGED and "Closes #3278". This re-applies the #3278-only diff (the #3279 threshold injection is already on main) onto current main. New: orchestrator/session_state_store.py (Redis TTL'd per-(pipeline, slice,role) store holding pointer+transcript together), routes/ session_state.py (GET/POST /api/v1/pipelines/<pid>/session-state), sandbox/egg_lib/{session_state_sync,cli_session_state}.py (slug + file I/O + egg-orch session-state pull|push). Wired: concurrent_executor.spawn_event injects CLAUDE_CONFIG_DIR + EGG_SESSION_STATE_FILE gated on session_resume_enabled(); consensus_ wrapper pull-before/push-after; api.py blueprint reg; orch_cli verb. Closes #3278
james-in-a-box Bot
pushed a commit
that referenced
this pull request
Jun 26, 2026
Merging main into the PR branch pulls in #3332's session-store files (session_state_store.py, session_state.py, session_state_sync.py) and edits to concurrent_executor.py / consensus_wrapper.py, which add SDLC ledger tokens (slice-N / TASK-N / cq-N) not present in the committed baseline. The advisory ratchet's TestRepoBaselineIsClean flagged these as net-new in the pull/3333/merge corpus that CI tests. Regenerated via scripts/check-ledger-references.py --update-baseline so a fresh checkout of the merged corpus scans clean.
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.
Why this PR exists (re-land)
#3278 was marked done but its code never reached
main. PR #3286 ("Closes #3278", MERGED) was a stacked PR whose base wasegg/3279-reseed-threshold-injection, notmain. #3279 (PR #3284) merged to main at 05:25; #3286 then merged at 07:32 into the already-merged #3279 branch, which was a dead branch — so #3286's commits never propagated to main. All four of #3278's new files are absent frommaintoday, while #3279's threshold injection is present. GitHub still shows #3286 as MERGED / Closes #3278, hence the issue looked done.This re-applies the #3278-only diff (everything #3286 added on top of the #3279 branch tip) onto current
main. The #3279 content is already on main and is excluded. Sole rebase conflict was the env-var table indocs/architecture/context-discipline.md, resolved to keep main's (#3284)EGG_RESEED_THRESHOLDrow alongside #3278's newEGG_SESSION_STATE_FILE/CLAUDE_CONFIG_DIRrows.What
Make BRC warm resume (#3200) actually fire by persisting the Claude Code session per
(pipeline, slice, role)across the one-shot event pods — the durable copy is orchestrator-owned and reached only over the controlled API, so the sandbox never writes host state.claude --resume <session_id>re-enters a session by reading its local transcript ($CLAUDE_CONFIG_DIR/projects/<cwd-slug>/<session_id>.jsonl). Under the orchestrator-owned event loop (#3164) every BRC event is a fresh pod, so that transcript dies with the pod. Persisting only thesession_id+occupancypointer (the original #3276 scope) would let the gate recordbelow_threshold"resume" decisions while every event silently cold-starts. The transcript itself has to cross pods.Design (constraint: sandbox never writes host state)
$CLAUDE_CONFIG_DIRis the pod's own filesystem (no host mount); Claude Code writes the transcript locally during the run, unchanged.session_state_store.pykeeps one TTL'd key per(pipeline, slice, role)holding the pointer and transcript together (no split-brain; TTL reaps abandoned state). Only the orchestrator writes it.egg-orch session-state pull(before the agent) re-materialises the prior transcript + pointer into the pod so--resumefinds a real session;egg-orch session-state push(after) ships the updated session back. Both best-effort andtimeout-bounded; a failed sync degrades to a safe cold reseed.The existing
egg_agentsubstrate (session.py/reseed.py/__main__.py) is untouched.Changes
orchestrator/session_state_store.py— Redis store (TTL, size-guarded, best-effort).orchestrator/routes/session_state.py—GET/POST /api/v1/pipelines/<pid>/session-state(registered inapi.py).sandbox/egg_lib/session_state_sync.py— slug + transcript/pointer file I/O (pure).sandbox/egg_lib/cli_session_state.py—egg-orch session-state pull|push(best-effort); verb wired inorch_cli.py.orchestrator/concurrent_executor.py— injectCLAUDE_CONFIG_DIR+EGG_SESSION_STATE_FILEinto event pods, gated onsession_resume_enabled()(default pods byte-identical).orchestrator/consensus_wrapper.py— pull before / push after the agent, preserving exit code; golden regenerated.docs/architecture/context-discipline.md— documents the cross-pod persistence layer.Tests
The original #3278 test suite comes along (store, route, sync, CLI, env-injection gating, wrapper golden). Per request, the suite was not re-run locally in this re-land session — relying on CI.
Verification still owed in-cluster
--resumeend-to-end across two real event pods (the spike confirmed file mechanics + relocation locally; the resume call itself needs in-cluster gateway/API-key auth). Also worth measuring transcript transfer cost per resumed event.Related
Closes #3278