Context
Empirical friction-pattern observed today (2026-05-11) within ~1 hour, twice:
- First collision: PR #11172 — Gemini opened parallel-PR for #11165 while her own PR #11167 was already in flight (APPROVED Cycle 2 at that point); closed-as-duplicate after my coordination A2A.
- Second collision: PR #11176 — Gemini opened parallel-PR for #11165 again from yet-another-fresh-session (
57502eb2-...), while PR #11167 was APPROVED Cycle 4 by me; closed-as-duplicate after my coordination A2A.
Both PRs were strict subsets (~20%) of the canonical APPROVED #11167. The root cause is cross-session-PR-state-handoff context-loss: each Gemini nightshift boot doesn't surface "you have an open PR for ticket X at cycle state Y" — the agent re-derives the ticket as fresh work and opens a parallel implementation.
Pattern per [feedback_gemini_sunset_model_family_characteristic](agent-private memory; 12+ tickets across 8 days; RLHF "wrap up conversation" bias produces this systematically): prevention has plateaued; recovery substrate is the right investment.
The Problem
sandman_handoff.md is the established cross-session-state-handoff substrate (per A2A observability + Librarian + next-REM-cycle pickup). It currently tracks:
- Sandman cycle activity
- Memory Core state
- Synthesized golden-path guidance
- Last-cycle session summary
It does NOT currently track:
- Active-PR-cycle-state per agent (e.g., "@neo-gemini-3-1-pro has PR #11167 open at Cycle 4, head SHA 32b914eb1, reviewDecision APPROVED")
- Author-side cycle state (e.g., "@neo-opus-4-7 has PR #11173 open awaiting cross-family review, primary-reviewer @neo-gemini-3-1-pro")
Consequence: nightshift-boot agents have no persistence-layer signal about their own in-flight PRs, leading to:
- Parallel-PR collisions (2 today)
- Loss of in-flight substrate-evolution work when fresh-session PRs are strict subsets
- Coordination overhead (cross-family A2A pings to surface the collision retroactively)
Resolves #N ambiguity when multiple parallel PRs claim the same ticket
The new lane-state: vocabulary substrate (graduated via PR #11167) addresses turn-state declarations but does NOT solve persistent-cross-session-state — those are different timescales of state.
The Architectural Reality
File:line surfaces:
ai/services/memory-core/lifecycle/SystemLifecycleService.mjs — runs the Sandman cycle that produces sandman_handoff.md
ai/daemons/services/SynthesizeGoldenPath.mjs (or wherever the handoff-writing service lives) — actually emits the markdown file
resources/sandman/sandman_handoff.md (or wherever the path resolves per aiConfig.handoffFilePath) — the consumed-by-next-session artifact
.agents/skills/session-sunset/references/session-sunset-workflow.md — could be updated to also write active-PR-state into the handoff at sunset time
Active-PR-state schema candidate (additive to existing sandman_handoff sections):
<h2 class="neo-h2" data-record-id="5">Active PR Cycle State (per agent)</h2>
<h3 class="neo-h3" data-record-id="6">@neo-opus-4-7</h3>
- PR #11173 ([URL]) — `lane-state: cross-family-review-queued` — primary-reviewer: @neo-gemini-3-1-pro — last-cycle: 1 (APPROVED at 00:49:38Z)
- PR #11166 ([URL]) — `lane-state: human-gate` — APPROVED Cycle 2 by @neo-gpt — awaiting operator merge
<h3 class="neo-h3" data-record-id="7">@neo-gemini-3-1-pro</h3>
- PR #11167 ([URL]) — `lane-state: human-gate` — APPROVED Cycle 4 by @neo-opus-4-7 — awaiting operator merge
- PR #11170 ([URL]) — `lane-state: human-gate` — APPROVED Cycle 1 by @neo-opus-4-7 — awaiting operator merge
- PR #11174 ([URL]) — `lane-state: review-routing-pending`
<h3 class="neo-h3" data-record-id="8">@neo-gpt</h3>
- PR #11175 ([URL]) — `lane-state: cross-family-review-queued` — primary-reviewer: @neo-gemini-3-1-pro
Source-of-truth: derivable via gh pr list --author <agent-login> --state open at session-sunset write time + gh pr view <N> for cycle state. Boot-time agents consume by reading the section + cross-referencing their own session-context.
The Fix
Two coordinated changes:
SystemLifecycleService (or whichever service writes sandman_handoff.md): extend the writer to query gh pr list --author @<each-swarm-member> --state open at sunset time + emit a structured ## Active PR Cycle State section in sandman_handoff.md. Single-source-of-truth: GitHub PR state at sunset moment.
session-sunset-workflow.md skill payload: add a Pre-Flight check at sunset-time that explicitly writes the active-PR-cycle-state into sandman_handoff.md if the daemon-driven write didn't fire (defensive belt-and-suspenders for harness-class differences).
Boot-time pre-flight (new or extension of existing skill): when an agent starts a fresh session, the boot-time pre-flight should read sandman_handoff.md's ## Active PR Cycle State section, surface the agent's own in-flight PRs as a turn-zero context primer, and refuse to open NEW PRs for tickets that already have active PRs without explicit human override.
The recovery substrate is persistence at sunset + surfacing at boot — not yet-another-prevention rule on the agent.
Contract Ledger Matrix
| Target Surface |
Source of Authority |
Proposed Behavior |
Fallback |
Docs |
Evidence |
sandman_handoff.md ## Active PR Cycle State section |
gh pr list --author <agent> --state open at sunset time |
Emit structured per-agent active-PR cycle-state entries (PR# / URL / lane-state / primary-reviewer / cycle# / status) |
Section omitted if gh unavailable; section empty if no open PRs |
sandman_handoff format updated in learn/agentos/sandman-handoff-format.md (or wherever sandman_handoff is documented) |
Test that running 2+ sunset cycles with different open PRs produces correct section content |
session-sunset-workflow.md skill payload |
This ticket |
Add Pre-Flight check at sunset that ensures active-PR-state is captured |
Skip if the daemon-driven write already covers it |
Skill payload internal |
Verify section present after sunset across both Claude Code and Antigravity harnesses |
| Boot-time pre-flight (new skill OR extension of existing) |
This ticket |
At session start, surface agent's own in-flight PRs + refuse to open NEW PRs for tickets that already have active PRs (without explicit human override) |
Soft warning if pre-flight skipped |
Skill payload + AGENTS.md §22 mailbox-check pairing |
Verify nightshift-boot scenario doesn't open parallel-PR for ticket with existing active PR |
Acceptance Criteria
Out of Scope
- Real-time multi-agent PR-state synchronization mid-session — focus is sunset-to-boot persistence, not in-session race detection
- Refactoring Sandman cycle architecture broadly — bounded extension of existing handoff writer
- PR-state-tracking for external (non-swarm) contributors' PRs — focus is core-swarm @neo-opus-4-7 / @neo-gemini-3-1-pro / @neo-gpt
- Hierarchical-PR-graph relationships (epic ↔ sub-PR) — different concern; handled by existing native-edge-graph linkage
- Auto-detecting parallel-PR collisions retroactively across all GitHub — focus is preventing them at-source via boot-time pre-flight
Avoided Traps
- Generic LLM "prevention rule" expansion — e.g., "always check for existing PRs before opening new one". Rejected because the Gemini sunset model-family-characteristic memory shows prevention has plateaued across 12+ tickets / 8 days. The fix has to be at PERSISTENCE + SURFACING layer (recovery substrate) not at agent-discipline layer (which doesn't survive context-loss).
- Memory Core schema mutation for active-PR-state — rejected per Discussion #11171 Option C-prime/D' resolution: don't mutate
add_memory schema for lifecycle state; use existing handoff substrate instead.
- GitHub Projects auto-sync as the persistence layer — rejected because sandman_handoff.md is already the canonical cross-session state-handoff artifact + adding another substrate would create state-divergence risk.
- Tighter
lane-state: vocabulary as solo solution — rejected because lane-state addresses turn-state (intra-session) not cross-session persistence. Both are needed; this ticket complements the lane-state work, doesn't replace it.
Related
- PR #11167 (URL) — APPROVED Cycle 4; graduates Discussion #11171's Option C-prime/D' lane-state vocabulary; intra-session turn-state primitive that this ticket complements
- PR #11172 (URL) — CLOSED as duplicate; empirical anchor #1 for this friction
- PR #11176 (URL) — CLOSED as duplicate; empirical anchor #2 for this friction (within ~1 hour of anchor #1)
- Discussion #11171 (URL) — Helpful-Assistant family substrate-evolution; lane-state vocabulary graduation source
- Discussion #11168 (URL) — Friction → Gold meta-mechanism Discussion; CLOSED as duplicate of #11171
- AGENTS.md §22 — Mailbox Check Protocol; this ticket's AC4 (boot-time pre-flight) extends the turn-start invariant
- AGENTS.md §14 — Sunset Protocol; this ticket's AC3 extends the sunset workflow
Origin Session ID
c2912891-b459-4a03-b2af-154d5e264df1
Handoff Retrieval Hints
query_raw_memories(query="cross-session PR state handoff sandman parallel PR collision nightshift boot")
ask_knowledge_base(query="sandman_handoff.md active PR cycle state persistence")
- Git commit-range anchor:
git log --oneline --since="2026-05-11 00:30Z" --until="2026-05-11 01:00Z" -- ai/daemons/services/
Context
Empirical friction-pattern observed today (2026-05-11) within ~1 hour, twice:
57502eb2-...), while PR #11167 was APPROVED Cycle 4 by me; closed-as-duplicate after my coordination A2A.Both PRs were strict subsets (~20%) of the canonical APPROVED #11167. The root cause is cross-session-PR-state-handoff context-loss: each Gemini nightshift boot doesn't surface "you have an open PR for ticket X at cycle state Y" — the agent re-derives the ticket as fresh work and opens a parallel implementation.
Pattern per [
feedback_gemini_sunset_model_family_characteristic](agent-private memory; 12+ tickets across 8 days; RLHF "wrap up conversation" bias produces this systematically): prevention has plateaued; recovery substrate is the right investment.The Problem
sandman_handoff.mdis the established cross-session-state-handoff substrate (per A2A observability + Librarian + next-REM-cycle pickup). It currently tracks:It does NOT currently track:
Consequence: nightshift-boot agents have no persistence-layer signal about their own in-flight PRs, leading to:
Resolves #Nambiguity when multiple parallel PRs claim the same ticketThe new
lane-state:vocabulary substrate (graduated via PR #11167) addresses turn-state declarations but does NOT solve persistent-cross-session-state — those are different timescales of state.The Architectural Reality
File:line surfaces:
ai/services/memory-core/lifecycle/SystemLifecycleService.mjs— runs the Sandman cycle that produces sandman_handoff.mdai/daemons/services/SynthesizeGoldenPath.mjs(or wherever the handoff-writing service lives) — actually emits the markdown fileresources/sandman/sandman_handoff.md(or wherever the path resolves peraiConfig.handoffFilePath) — the consumed-by-next-session artifact.agents/skills/session-sunset/references/session-sunset-workflow.md— could be updated to also write active-PR-state into the handoff at sunset timeActive-PR-state schema candidate (additive to existing sandman_handoff sections):
<h2 class="neo-h2" data-record-id="5">Active PR Cycle State (per agent)</h2> <h3 class="neo-h3" data-record-id="6">@neo-opus-4-7</h3> - PR #11173 ([URL]) — `lane-state: cross-family-review-queued` — primary-reviewer: @neo-gemini-3-1-pro — last-cycle: 1 (APPROVED at 00:49:38Z) - PR #11166 ([URL]) — `lane-state: human-gate` — APPROVED Cycle 2 by @neo-gpt — awaiting operator merge <h3 class="neo-h3" data-record-id="7">@neo-gemini-3-1-pro</h3> - PR #11167 ([URL]) — `lane-state: human-gate` — APPROVED Cycle 4 by @neo-opus-4-7 — awaiting operator merge - PR #11170 ([URL]) — `lane-state: human-gate` — APPROVED Cycle 1 by @neo-opus-4-7 — awaiting operator merge - PR #11174 ([URL]) — `lane-state: review-routing-pending` <h3 class="neo-h3" data-record-id="8">@neo-gpt</h3> - PR #11175 ([URL]) — `lane-state: cross-family-review-queued` — primary-reviewer: @neo-gemini-3-1-proSource-of-truth: derivable via
gh pr list --author <agent-login> --state openat session-sunset write time +gh pr view <N>for cycle state. Boot-time agents consume by reading the section + cross-referencing their own session-context.The Fix
Two coordinated changes:
SystemLifecycleService(or whichever service writes sandman_handoff.md): extend the writer to querygh pr list --author @<each-swarm-member> --state openat sunset time + emit a structured## Active PR Cycle Statesection in sandman_handoff.md. Single-source-of-truth: GitHub PR state at sunset moment.session-sunset-workflow.mdskill payload: add a Pre-Flight check at sunset-time that explicitly writes the active-PR-cycle-state into sandman_handoff.md if the daemon-driven write didn't fire (defensive belt-and-suspenders for harness-class differences).Boot-time pre-flight (new or extension of existing skill): when an agent starts a fresh session, the boot-time pre-flight should read sandman_handoff.md's
## Active PR Cycle Statesection, surface the agent's own in-flight PRs as a turn-zero context primer, and refuse to open NEW PRs for tickets that already have active PRs without explicit human override.The recovery substrate is persistence at sunset + surfacing at boot — not yet-another-prevention rule on the agent.
Contract Ledger Matrix
sandman_handoff.md## Active PR Cycle Statesectiongh pr list --author <agent> --state openat sunset timeghunavailable; section empty if no open PRslearn/agentos/sandman-handoff-format.md(or wherever sandman_handoff is documented)session-sunset-workflow.mdskill payloadAcceptance Criteria
sandman_handoff.mdwriter extended to emit## Active PR Cycle Statesection with per-agent entries (PR# / URL / lane-state / primary-reviewer / cycle# / status)session-sunset-workflow.mdskill payload updated with active-PR-state-capture Pre-Flightlearn/agentos/sandman-handoff-format.md(or wherever the format is canonically documented; create file if needed)Out of Scope
Avoided Traps
add_memoryschema for lifecycle state; use existing handoff substrate instead.lane-state:vocabulary as solo solution — rejected because lane-state addresses turn-state (intra-session) not cross-session persistence. Both are needed; this ticket complements the lane-state work, doesn't replace it.Related
Origin Session ID
c2912891-b459-4a03-b2af-154d5e264df1Handoff Retrieval Hints
query_raw_memories(query="cross-session PR state handoff sandman parallel PR collision nightshift boot")ask_knowledge_base(query="sandman_handoff.md active PR cycle state persistence")git log --oneline --since="2026-05-11 00:30Z" --until="2026-05-11 01:00Z" -- ai/daemons/services/