LearnNewsExamplesServices
Frontmatter
id11389
titlesession-sunset Step 2: skip manual sandman invocation under convergent scope
stateClosed
labels
documentationenhancementaiagent-task:pendingmodel-experience
assigneesneo-gemini-3-1-pro
createdAtMay 15, 2026, 2:59 AM
updatedAtMay 15, 2026, 10:21 AM
githubUrlhttps://github.com/neomjs/neo/issues/11389
authorneo-opus-4-7
commentsCount0
parentIssuenull
subIssues[]
subIssuesCompleted0
subIssuesTotal0
blockedBy[]
blocking[]
closedAtMay 15, 2026, 10:21 AM

session-sunset Step 2: skip manual sandman invocation under convergent scope

Closeddocumentationenhancementaiagent-task:pendingmodel-experience
neo-opus-4-7
neo-opus-4-7 commented on May 15, 2026, 2:59 AM

Context

.agents/skills/session-sunset/references/session-sunset-workflow.md Step 2 (line 88-89) mandates that every sunsetting agent execute npm run ai:run-sandman to refresh the ## Active PR Cycle State into sandman_handoff.md before terminating their session. This was authored under solo-refresh assumptions where one agent sunsets at a time.

In the multi-agent swarm reality (Claude + Gemini + GPT all sunsetting under a coordinated convergent-scope event), three parallel invocations of ai:run-sandman against the same SQLite + Chroma substrate produce contention pile-up. Per past-session empirical anchor (Origin Session ID: cf76b29a-9cf5-4c35-a415-37d631a8a755, sunset 2026-05-14T23:08Z): operator directly surfaced this as "daemon-driven only" — manual 3-agent parallel invocation is approximately 15min × 3 agents = 45min of contention disaster against a shared substrate that the orchestrator-daemon's ai:dream + ai:golden-path periodic tasks (per ai/daemons/TaskDefinitions.mjs) already cover automatically.

The current Step 2 prose has no scope-conditional — it fires uniformly regardless of whether the agent is sunsetting solo or as part of a coordinated convergent swarm event. This is the substrate-friction surfaced by past-self at sunset, deferred to "tomorrow's filing batch."

The Problem

Sunset workflow Step 5 (Mental-Model State) and Step 6 (Marathon Metrics) already distinguish solo-refresh vs convergent scope (session-sunset-workflow.md lines 102-110). Step 2 does NOT — it's written as an unconditional mandate. Under operator-coordinated convergent sunsets, all three agents would each fire ai:run-sandman in parallel:

  1. Each invocation runs GoldenPathSynthesizer against shared SQLite (memory-core-graph.sqlite) + Chroma (memory-core collection on :8001).
  2. SQLite has a single-writer lock; concurrent writers from three agents serialize.
  3. Chroma embedding writes from three agents to the same collection serialize on the embedding-provider HTTP queue.
  4. Per ADR 0001 substrate "one SQLite file shared across N processes" — contention is the design assumption; parallel writes against the same writer are explicitly throttled, not parallel.
  5. End-state: 3× serial executions, ≈45 min of operator-blocking sunset time, with the OUTPUT being THREE consecutive overwrites of the same sandman_handoff.md file. Only the LAST write survives. The first two are pure substrate waste.

Meanwhile, the orchestrator-daemon (per ai/daemons/TaskDefinitions.mjs#L85-95) already registers dream (periodic-dream:3600000ms) and golden-path (periodic-golden-path:3600000ms) as service-tasks that produce the same artifact automatically on hourly cadence. The daemon-driven path is the canonical writer; the manual ai:run-sandman invocation duplicates work the daemon already owns.

Operator-direction at 2026-05-14 sunset (paraphrase, peer-citation per feedback_peer_cited_authority_neutral_ask): "daemon-driven only" — manual ai:run-sandman should be used only when the daemon path has failed or the operator-explicit context demands it.

The Architectural Reality

  • Current Step 2 text (session-sunset-workflow.md:88-89):
        ### Step 2: Refresh Active PR Cycle State (The Pre-Sunset Capture)
      You MUST execute `npm run ai:run-sandman` via the `run_command` tool...
  • Scope vocabulary already established in the same file: scope: solo-refresh vs scope: convergent (lines 102, 110) — used by Steps 5 and 6 but NOT by Step 2.
  • Daemon-driven canonical writer in ai/daemons/TaskDefinitions.mjs#L85-95: dream + golden-path service-tasks run automatically per the periodic-interval schedule.
  • Operator-direction anchor: past-self sunset comment at https://github.com/neomjs/neo/issues/11372#issuecomment-4455463278 (2026-05-14T23:06:09Z) names this exact friction: "npm run ai:run-sandman is 15min × 3 agents = 45min contention disaster if run in parallel during convergent sunset. Operator directive: daemon-driven only. Substrate-friction worth fixing in session-sunset-workflow.md Step 2 — needs explicit convergent-scope skip-clause."

The Fix

Modify session-sunset-workflow.md Step 2 to add an explicit scope-conditional skip-clause. Proposed prose:

<h3 class="neo-h3" data-record-id="6">Step 2: Refresh Active PR Cycle State (The Pre-Sunset Capture)</h3>

**Scope-conditional execution:**

- **`scope: solo-refresh`** (single-agent sunset, daemon-driven path unavailable or stale): You MUST execute `npm run ai:run-sandman` via the `run_command` tool. This forces the `GoldenPathSynthesizer` (the canonical writer) to query GitHub and emit the `## Active PR Cycle State` into `sandman_handoff.md`.

- **`scope: convergent`** (multi-agent coordinated sunset event): **SKIP** this step. Three parallel `ai:run-sandman` invocations against the shared SQLite + Chroma substrate produce ≈45min of contention serialization (3× the solo cost) and overwrite each other's output — only the last write survives. The orchestrator-daemon's `dream` + `golden-path` periodic service-tasks (`ai/daemons/TaskDefinitions.mjs#L85-95`) cover the same artifact emission automatically on hourly cadence; the daemon-driven path is the canonical writer for convergent-scope events. The lead-role agent (per `lead-role-mode.md`) MAY exceptionally run `ai:run-sandman` once on behalf of the swarm if the daemon path is empirically stale (e.g., `sandman_handoff.md` mtime > 4h or the daemon process is verified dead) — declare the exception in the sunset payload Step 5 if exercised.

Do NOT attempt to edit `sandman_handoff.md` manually under any scope — it is overwritten by the canonical writer (daemon OR `ai:run-sandman`).

Acceptance Criteria

  • AC1: session-sunset-workflow.md Step 2 contains the scope-conditional skip-clause above (or substantively equivalent prose).
  • AC2: The scope: convergent branch explicitly references the orchestrator-daemon's dream + golden-path service-tasks as the canonical writer for convergent-scope events, with a file:line pointer to ai/daemons/TaskDefinitions.mjs.
  • AC3: The lead-role exception (single agent runs on behalf of swarm if daemon empirically stale) is documented with a concrete staleness threshold (e.g., sandman_handoff.md mtime > 4h) so future agents have a deterministic test rather than judgment-call.
  • AC4: The "do not edit manually" warning carries forward unchanged (it applies under both scopes).
  • AC5: No changes to Steps 1, 3-10 — Step 2 is the only modified section.
  • AC6: PR body cites the empirical anchor (past-self comment at #11372 + the contention math + operator-direction paraphrase) so reviewers can V-B-A the premise.

Out of Scope

  • Daemon-side improvements — the orchestrator-daemon's dream + golden-path cadence (1h interval) and the contention behavior of ai:run-sandman itself are not modified. Those are substrate concerns owned by ai/daemons/ and would be separate tickets (e.g., a goldenPathInvocationLock mutex around the SQLite-writer-block; a daemon-stalemate-detection-and-recovery mechanism). This ticket is workflow-skill scope only.
  • Solo-refresh behavior — unchanged. The mandate still fires for single-agent sunsets where the daemon-driven path may not have caught up.
  • Step 7 (mark_read) ordering — separate concern; Step 7 already executes regardless of Step 2 outcome.
  • Lead-role baton handoff (Step 8) — also unchanged; the baton routing logic is orthogonal to Step 2's writer-invocation question.

Avoided Traps

  • Drop Step 2 entirely — rejected. Solo-refresh sunsets DO need the manual writer-invocation because the daemon path may have stalled (e.g., daemon dead, last-write > 4h stale). Convergent-scope is the narrow skip case, not the general case.
  • Mandatory lead-role single-invocation in convergent — rejected as overreach. Adding "lead MUST run ai:run-sandman" creates a new coordination requirement (lead-role discipline must be active; baton-pass timing must align). Lead-role-exception path documented as MAY (operator-discretion), not MUST.
  • Reuse the existing scope-vocabulary without scope-conditional — rejected as semantically incomplete. The existing scope: solo-refresh vs scope: convergent vocabulary in Steps 5+6 governs reporting granularity; here we need the vocabulary to govern execution-or-skip. Reusing the same vocabulary surface is the right pattern; expanding its semantic load (reporting + execution) is the right scope expansion.
  • Move the skip-clause into lead-role-mode.md — rejected as substrate-friction misrouting. The friction surfaces during session-sunset (every agent's exit path); routing the discipline into the lead-role-mode file means non-lead agents (peers) don't see it during their own sunset flow. The skip-clause belongs where every agent will see it.

Related

  • Authority anchor: past-self sunset comment at https://github.com/neomjs/neo/issues/11372#issuecomment-4455463278 (2026-05-14T23:06:09Z) — names this exact friction.
  • Substrate authority: .agents/skills/session-sunset/references/session-sunset-workflow.md — file being modified.
  • Daemon canonical writer: ai/daemons/TaskDefinitions.mjs#L85-95 + ai/daemons/Orchestrator.mjs#L497-519 (dream + golden-path service-task wiring per #11009 orchestrator class extraction).
  • Companion skill discipline: lead-role-mode.md — the lead-role exception path documented in §convergent branch references this for the operator-discretion lead-takes-on-swarm-behalf path.
  • ADR 0001 (SQLite single-writer): justifies the contention math — three parallel writers against shared SQLite serialize regardless of agent identity.
  • Discussion thread context: the convergent-vs-solo-refresh framing originated in Epic #11372 (Phase 1 Lane allocation broadcast) where 3-agent coordination became routine.

Origin Session

  • Origin Session ID: e095c569-beac-4743-998f-e07d4344492e
  • Past-session anchor (where the friction was first named): cf76b29a-9cf5-4c35-a415-37d631a8a755

Retrieval Hint

Search for session-sunset Step 2 convergent scope skip-clause sandman contention daemon-driven canonical writer.

tobiu closed this issue on May 15, 2026, 10:21 AM
tobiu referenced in commit 7dcf7df - "docs(agentos): make run-sandman step scope-conditional at sunset (#11389) (#11391) on May 15, 2026, 10:21 AM