Skip to content

fix(infra/agents): session-routing guard for coalesced gateway restart continuations (#86742)#87323

Merged
steipete merged 9 commits into
openclaw:mainfrom
openperf:fix/86742-restart-continuation-session-guarded-queue
Jun 7, 2026
Merged

fix(infra/agents): session-routing guard for coalesced gateway restart continuations (#86742)#87323
steipete merged 9 commits into
openclaw:mainfrom
openperf:fix/86742-restart-continuation-session-guarded-queue

Conversation

@openperf

@openperf openperf commented May 27, 2026

Copy link
Copy Markdown
Member

Summary

  • Problem: Issue [Bug]: gateway restart continuationMessage can be accepted but not queued after coalesced restart #86742 (refresh of [Bug]: gateway restart continuationMessage is silently dropped when restart coalesces with an in-flight restart #74424) reports that gateway tool action: "restart" with continuationMessage returns success (mode: "emit", coalesced: true) while the continuation is silently never persisted nor delivered after the restart, because the SIGUSR1 restart was already in flight or already scheduled. Two prior attempts (fix(gateway/restart): write sentinel with continuationMessage on coalesced restart #74443 by hclsys, Fix restart continuations after explicit restarts #73812 by VACInc) were closed without merging; the issue creator explicitly notes that aisle-research-bot flagged fix(gateway/restart): write sentinel with continuationMessage on coalesced restart #74443 as a Medium security finding ("Cross-session continuation overwrite when coalescing gateway restart requests", CWE-200) because a naive global rewrite of restart-sentinel.json could overwrite or misroute another session's continuation. The accepted resolutions the issue creator names are "queue the continuation for the correct pending restart" OR "an explicit non-queued result"; fix(gateway): report unqueued restart continuations #83370 (stainlu, currently ready for maintainer look) covers the explicit-non-queued half via continuationQueued: false reporting; the cross-session overwrite hole on the silent-overwrite Path B (updatePendingRestartEmitHooks) remains.
  • Root Cause: src/infra/restart.ts exposes two coalesced-restart paths from scheduleGatewaySigusr1Restart. Path A (hasUnconsumedRestartSignal) is correctly hooks-less — SIGUSR1 already fired and the caller cannot opt in. Path B (pendingRestartTimer || pendingRestartPreparing) calls updatePendingRestartEmitHooks(opts?.emitHooks) which unconditionally overwrites the existing pending emit hooks. The emit hooks own writing the restart-sentinel.json payload (containing the caller's sessionKey, deliveryContext, threadId, continuation) — so a second session's coalesced restart silently replaces the first session's continuation and routes the post-restart continuation back to the wrong session. This is the CWE-200 hole aisle-research-bot identified on fix(gateway/restart): write sentinel with continuationMessage on coalesced restart #74443.
  • Fix: Add a session-routing guard to updatePendingRestartEmitHooks so it only accepts new hooks when the new caller's sessionKey matches the pending restart's sessionKey. Threading sessionKey?: string through the scheduleGatewaySigusr1Restart opts and remembering it as pendingRestartSessionKey module state. Add emitHooksQueued: boolean to the ScheduledRestart return shape so callers can detect that their hooks were rejected (matches the field name fix(gateway): report unqueued restart continuations #83370 chose for the same purpose). Wire the gateway tool to pass agentSessionKey and surface continuationQueued: scheduled.emitHooksQueued in the tool response whenever the caller supplied a continuation.
  • What changed:
    • src/infra/restart.ts — new pendingRestartSessionKey module state; scheduleGatewaySigusr1Restart opts gain sessionKey?: string; ScheduledRestart gains emitHooksQueued: boolean; updatePendingRestartEmitHooks becomes session-guarded and returns whether the slot was claimed; the Path B coalesced branch threads that result back into the response and logs a restart continuation dropped warning when the guard rejects new hooks. Path A continues to return emitHooksQueued: false because the hooks cannot run for the already-emitted cycle. clearPendingScheduledRestart, the fresh-schedule and skipDeferral paths reset pendingRestartSessionKey alongside pendingRestartEmitHooks. emitPreparedGatewayRestart keeps pendingRestartSessionKey alive across the await beforeEmit() window and only clears it after the chained-hook loop exits — without this, a coalesced different-session caller could slip past the guard during the in-flight preparation window (ClawSweeper P1 review point on initial PR head 8f9cec097c6c, addressed in latest head).
    • src/agents/tools/gateway-tool.ts — pass sessionKey to scheduleGatewaySigusr1Restart and report continuationQueued: scheduled.emitHooksQueued in the tool result when the caller supplied a continuation.
    • src/auto-reply/reply/commands-session.tshandleRestartCommand now also threads sentinelPayload.sessionKey into scheduleGatewaySigusr1Restart (sibling cross-session guard ClawSweeper P1 review identified — the chat /restart also writes a session-scoped sentinel with continuation, and previously bypassed the new guard by omitting the scheduler sessionKey opt).
    • src/infra/infra-runtime.test.ts — three new tests pin the session-guard semantics: different sessions → second caller observes emitHooksQueued: false and its hooks are not invoked; same session → debounce/replace behavior preserved; different session coalescing during in-flight beforeEmit preparation → guard still holds (the in-flight preparation race the ClawSweeper P1 review asked for).
    • src/agents/tools/gateway-tool.test.ts — existing mock fixture upgraded to the full ScheduledRestart shape (was a partial { scheduled, delayMs }); new regression test pins continuationQueued: false propagation when the coalesced restart belongs to another session.
    • src/auto-reply/reply/commands-session-restart.test.ts — new regression test asserts handleRestartCommand passes sessionKey to the scheduler so the sibling /restart path is covered by the same cross-session guard.
  • What did NOT change (scope boundary):
    • restart-sentinel.json schema (RestartSentinelPayload) is unchanged — same single-slot continuation + sessionKey shape; the fix is in the scheduler, not the sentinel.
    • Path A behavior (in-flight SIGUSR1 already emitted) is unchanged — the new caller's hooks still cannot run for the current cycle, only the explicit reporting via emitHooksQueued: false is added.
    • Legacy callers that pass no sessionKey (existing behavior) continue to chain/overwrite as before — the guard only fires when both sides identify a session.
    • #83370 (stainlu) is complementary: its continuationQueued surfacing in the tool response was the explicit-non-queued half of the issue creator's OR clause; this PR adds the queued-for-the-correct-restart half by rejecting cross-session overwrites at the scheduler level.
    • Config surface unchanged (no schema, defaults, doctor migrations, or docs/reference/config edits).
    • Plugin surface unchanged (no plugin SDK, manifest, extensions/api.ts / runtime-api.ts, registry, or loader edits).
    • Session store / sessions.json untouched (relevant given the June SQLite migration).
    • pi-embedded-runner untouched.

Reproduction

  1. Configure a workflow where multiple Discord/Slack/Feishu sessions can each call gateway tool action: "restart" with continuationMessage near each other (e.g. a deploy script plus an agent-driven plugin install both restarting the gateway).
  2. Session A issues gateway.restart with continuation A. The scheduler stores pendingRestartEmitHooks whose beforeEmit writes restart-sentinel.json with sessionKey: A and continuation A.
  3. Before the restart timer fires, session B issues gateway.restart with continuation B.
  4. Before this PR: updatePendingRestartEmitHooks(B's hooks) replaces A's hooks. The restart fires; the sentinel is written by B's beforeEmit with sessionKey: B and continuation B. After restart, the gateway dispatches continuation B as if A had asked for it (or simply drops A's continuation depending on routing) — A's promised reply is silently lost (this is the CWE-200 hole). Both tool responses look successful.
  5. After this PR: the same sequence keeps A's pendingRestartEmitHooks in place; B's coalesced call returns coalesced: true, emitHooksQueued: false, continuationQueued: false so the agent that issued B knows the continuation was not queued. The gateway log records restart continuation dropped: another session owns the pending restart. A's continuation still fires after restart as promised.

Real behavior proof

Behavior addressed (#86742): cross-session coalesced restarts no longer silently overwrite the existing pending continuation. Same-session debounce/replace is preserved. Legacy callers (no sessionKey) keep the old chain behavior. The gateway.restart tool response now surfaces continuationQueued: false when the caller's continuation could not take ownership of the pending restart slot.

Real environment tested (Linux, Node 22, real-component tsx harness driving production scheduleGatewaySigusr1Restart end-to-end): tsx-resolved import of production scheduleGatewaySigusr1Restart + __testing.resetSigusr1State. A real SIGUSR1 listener is registered so the scheduler runs in emit mode. Each scenario invokes the production scheduler twice with combinations of sessionKey and inspects the returned coalesced / emitHooksQueued fields. No mocks of the scheduler itself.

Exact steps or command run after this patch:

  1. node_modules/.bin/tsx /tmp/qmd86742/repro.mts (real-component session-routing-guard sweep)
  2. node scripts/run-vitest.mjs src/infra/infra-runtime.test.ts src/agents/tools/gateway-tool.test.ts
  3. pnpm exec oxfmt --check --threads=1 src/infra/restart.ts src/infra/infra-runtime.test.ts src/agents/tools/gateway-tool.ts src/agents/tools/gateway-tool.test.ts

Evidence after fix (verbatim real-component harness output, ANSI stripped):

================ #86742 cross-session continuation guard ================

Drives production scheduleGatewaySigusr1Restart with two callers from
different sessionKeys and verifies the second caller's emit hooks are
rejected (rather than overwriting the first session's continuation).

--- Scenario A: session-A schedules, session-B coalesces (DIFFERENT session) ---
[restart] request coalesced (already scheduled) reason=session-B-restart pendingReason=session-A-restart delayMs=60000 actor=<unknown>
[restart] continuation dropped: another session owns the pending restart (callerSessionKey=agent:main:session-B pendingSessionKey=agent:main:session-A)
  first.coalesced=false first.emitHooksQueued=true
  second.coalesced=true second.emitHooksQueued=false
  >>> OK: session-A owns slot, session-B explicitly reported as not-queued

--- Scenario B: same session debounces (replace hooks) ---
[restart] request coalesced (already scheduled) reason=second pendingReason=first delayMs=60000 actor=<unknown>
  same1.emitHooksQueued=true same2.coalesced=true same2.emitHooksQueued=true
  >>> OK: same session can debounce/replace its own hooks

--- Scenario C: legacy callers without sessionKey still chain ---
[restart] request coalesced (already scheduled) reason=legacy-second pendingReason=legacy-first delayMs=60000 actor=<unknown>
  legacy1.emitHooksQueued=true legacy2.coalesced=true legacy2.emitHooksQueued=true
  >>> OK: legacy callers (no sessionKey) preserve current overwrite behavior

--- Scenario E: cross-session race DURING beforeEmit await (in-flight preparation) ---
[restart] request coalesced (already scheduled) reason=session-B-during-prep pendingReason=unspecified delayMs=0 actor=<unknown>
[restart] continuation dropped: another session owns the pending restart (callerSessionKey=agent:main:session-B pendingSessionKey=agent:main:session-A)
  e1.emitHooksQueued=true e2.coalesced=true e2.emitHooksQueued=false
  session-B beforeEmit ran during prep window: false
  >>> OK: in-flight preparation owner survived; session-B rejected

--- Scenario D: existing has sessionKey, new caller doesn't ---
[restart] request coalesced (already scheduled) reason=unspecified pendingReason=unspecified delayMs=60000 actor=<unknown>
  known.emitHooksQueued=true anonymous.coalesced=true anonymous.emitHooksQueued=true
  >>> OK: undefined sessionKey on new caller doesn't trigger guard (legacy compat)

================ VERDICT ================
PASS — session-routing guard works as designed:
  - Different sessions: explicit emitHooksQueued=false (no overwrite, no silent loss)
  - Same session: debounce/replace preserved
  - Legacy callers (no sessionKey): behavior unchanged
  - Mixed undefined: legacy compat (guard only fires when both sides identify session)

Vitest output for the two touched test files:

 RUN  v4.1.7

 Test Files  3 passed (3)
      Tests  45 passed (45)
   Duration  11.18s

Observed result after fix:

  • The new Rejects coalesced emit hooks from a different session test confirms session A's beforeEmit runs and session B's does not, while session B observes emitHooksQueued: false synchronously.
  • The new Allows same-session coalesced restart to replace its own preparation hook test confirms the existing debounce/replace semantics are intact.
  • The new gateway-tool regression test confirms the tool response surfaces continuationQueued: false when the coalesced caller belongs to another session.
  • Logs include restart continuation dropped: another session owns the pending restart with both session keys for operator diagnosis.

What was not tested:

  • A live multi-session restart race on a real gateway (Discord + Telegram concurrent gateway.restart). The real-component harness drives the production scheduler with two sessionKeys but does not invoke a real channel gateway.restart tool call end-to-end; the gateway-tool branch is covered by mocked-scheduler unit tests instead.
  • Interaction with future PRs that may rewrite the sentinel schema to natively support multi-session continuations — this PR is intentionally a scheduler-level guard that keeps the existing single-slot sentinel safe.

Regression tests:

  • infra-runtime.test.tsrejects coalesced emit hooks from a different session and reports emitHooksQueued=false (#86742) + allows same-session coalesced restart to replace its own preparation hook (#86742) + rejects coalesced emit hooks from a different session while preparation is in flight (#86742) (the in-flight beforeEmit race the ClawSweeper P1 review asked for) + the preserved keeps existing preparation hook when a hookless restart coalesces and uses the latest preparation hook when scheduled restarts coalesce tests.
  • gateway-tool.test.ts → upgraded full-shape mock plus new reports continuationQueued=false when a coalesced restart belongs to another session (#86742).

Risk / Mitigation

  • Risk: A second same-session restart caller might lose a meaningful continuation when same-session debounce replaces hooks. Mitigation: this preserves existing behavior (updatePendingRestartEmitHooks always replaced when caller had hooks pre-fix); the only change is rejecting cross-session overwrites. Same-session callers can choose to inspect emitHooksQueued: true to confirm their hooks installed.
  • Risk: Legacy callers without sessionKey continue to chain/overwrite, leaving the CWE-200 hole open for any code path that doesn't identify a session. Mitigation: the two known cross-session callers that write a session-scoped sentinel + continuation are gateway-tool.ts action: "restart" and commands-session.ts handleRestartCommand (chat /restart); this PR updates both to always pass sessionKey. The remaining legacy callers (CLI run-loop's scheduleGatewaySigusr1Restart({ delayMs: 0, reason: "SIGUSR1" })) do not write a sentinel continuation and are restart-only callers, not affected by the overwrite hole.
  • Risk: The ScheduledRestart return shape now has a new required field emitHooksQueued. Mitigation: the only production callers reading the return are gateway-tool.ts (this PR), commands-session.ts (calls but does not destructure additional fields), the CLI run-loop (calls but does not destructure additional fields), and config-write-flow.ts (uses ReturnType<typeof scheduleGatewaySigusr1Restart>, type-only). The test mock fixture in gateway-tool.test.ts was upgraded in this PR.
  • Risk: Overlap with fix(gateway): report unqueued restart continuations #83370 (stainlu, ready for maintainer look). Mitigation: this PR is intentionally a follow-up, not a replacement. fix(gateway): report unqueued restart continuations #83370 surfaces continuationQueued: false in the tool response when the scheduler reports emitHooksQueued: false. This PR adds the actual scheduler-level session guard plus matching tests for the cross-session path. If fix(gateway): report unqueued restart continuations #83370 lands first, this PR rebases cleanly: the new emitHooksQueued field and the gateway-tool continuationQueued plumbing match.

Change Type (select all)

  • Bug fix
  • Security hardening

Scope (select all touched areas)

  • Gateway / orchestration
  • Skills / tool execution

Linked Issue/PR

Refs #86742

@openclaw-barnacle openclaw-barnacle Bot added agents Agent runtime and tooling size: S labels May 27, 2026
@clawsweeper

clawsweeper Bot commented May 27, 2026

Copy link
Copy Markdown
Contributor

Codex review: needs maintainer review before merge. Reviewed June 7, 2026, 6:30 AM ET / 10:30 UTC.

Summary
The branch adds session-key ownership and queued-continuation reporting to gateway restart scheduling/tool paths, threads /restart and update.run through trusted runtime session routing, preserves safe-restart hook bypass behavior, updates regression tests, and refreshes a Swift gateway protocol model.

PR surface: Source +98, Tests +354, Other +12. Total +464 across 9 files.

Reproducibility: yes. Current main is source-reproducible: gateway.restart writes its continuation sentinel only from scheduler hooks, while the scheduler can coalesce and overwrite or skip those hooks; the PR body also includes terminal harness proof for the fixed path.

Review metrics: 2 noteworthy metrics.

  • Restart result signals: 2 added. ScheduledRestart.emitHooksQueued and the gateway-tool continuationQueued result signal change how callers detect unqueued continuations.
  • Scheduler control options: 2 added. sessionKey and preservePendingEmitHooksOnDeferralBypass now influence ownership and forced-bypass behavior in the central restart scheduler.

Merge readiness
Overall: 🐚 platinum hermit
Proof: 🦞 diamond lobster
Patch quality: 🐚 platinum hermit
Result: ready for maintainer review.

Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch.

Rank-up moves:

  • [P2] Confirm the latest merge ref has the focused infra/gateway restart tests and required checks green before landing.

Risk before merge

  • [P1] The merge changes a restart hot path that decides whether a promised continuation is delivered, rejected, or preserved across coalesced restarts.
  • [P1] The agent-facing gateway tool now prefers trusted runtime session identity over model-supplied sessionKey; that is the safer boundary, but maintainers should accept the intentional routing behavior before merge.
  • [P1] The PR overlaps active restart/gateway work mentioned in the discussion, so exact-head merge-ref CI and focused restart tests should be checked before landing.

Maintainer options:

  1. Land with exact-head restart proof (recommended)
    Accept the scheduler-owned session guard and land once the latest merge ref has the focused infra/gateway restart tests and required checks green.
  2. Ask for stronger live restart proof
    If maintainers want higher confidence than the terminal harness, require a packaged or live Gateway restart proof that shows the accepted continuation survives and the rejected continuation is reported.

Next step before merge

  • No automated repair is queued because the latest head has no discrete line-level defect; the remaining action is maintainer merge-risk review and exact-head validation.

Security
Cleared: The diff does not introduce a concrete supply-chain issue and appears to strengthen the restart continuation session boundary.

Review details

Best possible solution:

Land the scheduler-owned session guard after exact-head checks and maintainer acceptance of the runtime-session boundary, then let the linked bug close through the merged fix.

Do we have a high-confidence way to reproduce the issue?

Yes. Current main is source-reproducible: gateway.restart writes its continuation sentinel only from scheduler hooks, while the scheduler can coalesce and overwrite or skip those hooks; the PR body also includes terminal harness proof for the fixed path.

Is this the best way to solve the issue?

Yes. The scheduler is the right owner boundary because it owns pending restart coalescing; rejecting cross-session hook replacement and explicitly reporting unqueued continuations is safer than rewriting the global sentinel after the fact.

AGENTS.md: found and applied where relevant.

Codex review notes: model gpt-5.5, reasoning high; reviewed against bae607b9f196.

Label changes

Label changes:

  • add rating: 🐚 platinum hermit: Overall readiness is 🐚 platinum hermit; proof is 🦞 diamond lobster and patch quality is 🐚 platinum hermit.
  • add status: 👀 ready for maintainer look: ClawSweeper has no concrete contributor-facing blocker left for this PR. Sufficient (terminal): The PR body includes after-fix terminal output from a real-component tsx harness driving the production restart scheduler plus focused Vitest and formatter checks.
  • remove rating: 🦪 silver shellfish: Current PR rating is rating: 🐚 platinum hermit, so this older rating label is no longer current.
  • remove status: ⏳ waiting on author: Current PR status label is status: 👀 ready for maintainer look.

Label justifications:

  • P2: This is a normal-priority bugfix for racy restart continuation loss/misrouting with limited but real workflow impact.
  • merge-risk: 🚨 message-delivery: The diff changes whether restart continuations are queued, dropped, preserved, and reported across coalesced gateway restarts.
  • merge-risk: 🚨 security-boundary: The diff relies on session-key ownership to prevent one session or model-supplied parameter from claiming another session's pending continuation.
  • rating: 🐚 platinum hermit: Overall readiness is 🐚 platinum hermit; proof is 🦞 diamond lobster and patch quality is 🐚 platinum hermit.
  • status: 👀 ready for maintainer look: ClawSweeper has no concrete contributor-facing blocker left for this PR. Sufficient (terminal): The PR body includes after-fix terminal output from a real-component tsx harness driving the production restart scheduler plus focused Vitest and formatter checks.
  • proof: sufficient: Contributor real behavior proof is sufficient. The PR body includes after-fix terminal output from a real-component tsx harness driving the production restart scheduler plus focused Vitest and formatter checks.
Evidence reviewed

PR surface:

Source +98, Tests +354, Other +12. Total +464 across 9 files.

View PR surface stats
Area Files Added Removed Net
Source 4 135 37 +98
Tests 4 358 4 +354
Docs 0 0 0 0
Config 0 0 0 0
Generated 0 0 0 0
Other 1 12 0 +12
Total 9 505 41 +464

Acceptance criteria:

  • [P1] node scripts/run-vitest.mjs src/infra/infra-runtime.test.ts src/infra/restart-coordinator.test.ts src/agents/tools/gateway-tool.test.ts src/auto-reply/reply/commands-session-restart.test.ts.
  • [P1] pnpm exec oxfmt --check --threads=1 src/infra/restart.ts src/infra/infra-runtime.test.ts src/infra/restart-coordinator.ts src/infra/restart-coordinator.test.ts src/agents/tools/gateway-tool.ts src/agents/tools/gateway-tool.test.ts src/auto-reply/reply/commands-session.ts src/auto-reply/reply/commands-session-restart.test.ts.

What I checked:

  • current-main scheduler still overwrites pending hooks: On current main, updatePendingRestartEmitHooks accepts only hooks and unconditionally replaces pendingRestartEmitHooks, which matches the reported coalesced-continuation overwrite/drop path. (src/infra/restart.ts:443, bae607b9f196)
  • current-main gateway tool does not report queued status: On current main, the gateway restart action writes the sentinel only inside emitHooks.beforeEmit and returns the scheduler result without any continuationQueued signal. (src/agents/tools/gateway-tool.ts:429, bae607b9f196)
  • PR head adds scheduler ownership guard: The PR head adds pendingRestartSessionKey, guarded hook replacement, emitHooksQueued, and explicit false reporting for already-emitted, hookless, or different-session coalesced paths. (src/infra/restart.ts:475, 81e173766d1d)
  • PR head trusts runtime session for restart/update routing: The PR head prefers opts.agentSessionKey over model-supplied params.sessionKey and surfaces continuationQueued from scheduled.emitHooksQueued when a continuation was requested. (src/agents/tools/gateway-tool.ts:397, 81e173766d1d)
  • PR head covers sibling chat restart path: The chat /restart path now passes the sentinel payload session key into the scheduler, so it participates in the same cross-session guard. (src/auto-reply/reply/commands-session.ts:706, 81e173766d1d)
  • regression coverage on PR head: The PR head has focused tests for different-session rejection, same-session replacement, earlier reschedule rejection, in-flight preparation, and safe-restart hook preservation. (src/infra/infra-runtime.test.ts:337, 81e173766d1d)

Likely related people:

  • steipete: Recent GitHub commit history shows repeated touches to src/infra/restart.ts, src/agents/tools/gateway-tool.ts, and src/auto-reply/reply/commands-session.ts; the PR branch also contains multiple follow-up repair commits by this author. (role: recent area contributor and PR branch repair author; confidence: high; commits: 59fca2d738c5, de1c4f8aecf0, bf968f6303e1; files: src/infra/restart.ts, src/agents/tools/gateway-tool.ts, src/auto-reply/reply/commands-session.ts)
  • obviyus: GitHub history for the command/session restart path includes earlier merged work binding restart continuations and hardening restart acknowledgements. (role: restart-continuation feature contributor; confidence: medium; commits: fe5f0cddb929, f5173589a45c; files: src/auto-reply/reply/commands-session.ts, src/gateway/server-restart-sentinel.ts)
  • NikolaFC: GitHub history shows the safe restart coordinator was introduced in the same restart-coordination surface that this PR updates for skip-deferral hook preservation. (role: safe restart coordinator introducer; confidence: medium; commits: 103cdd9d96f8; files: src/infra/restart-coordinator.ts, src/gateway/server-methods/restart.ts)
  • vincentkoc: GitHub history shows recent restart drain control work in the central restart runtime, and the shallow checkout blames the current snapshot of the implicated files to a recent source import commit by Vincent Koc. (role: recent restart drain contributor; confidence: medium; commits: f6f8d74419a1, 451765ad272b; files: src/infra/restart.ts, src/agents/tools/gateway-tool.ts, src/auto-reply/reply/commands-session.ts)
What the crustacean ranks mean
  • 🦀 challenger crab: rare, exceptional readiness with strong proof, clean implementation, and convincing validation.
  • 🦞 diamond lobster: very strong readiness with only minor maintainer review expected.
  • 🐚 platinum hermit: good normal PR, likely mergeable with ordinary maintainer review.
  • 🦐 gold shrimp: useful signal, but proof or patch confidence is still limited.
  • 🦪 silver shellfish: thin signal; proof, validation, or implementation needs work.
  • 🧂 unranked krab: not merge-ready because proof is missing/unusable or there are serious correctness or safety concerns.
  • 🌊 off-meta tidepool: rating does not apply to this item.

Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics.

How this review workflow works
  • ClawSweeper keeps one durable marker-backed review comment per issue or PR.
  • Re-runs edit this comment so the latest verdict, findings, and automation markers stay together instead of adding duplicate bot comments.
  • A fresh review can be triggered by eligible @clawsweeper re-review comments, exact-item GitHub events, scheduled/background review runs, or manual workflow dispatch.
  • PR/issue authors and users with repository write access can comment @clawsweeper re-review or @clawsweeper re-run on an open PR or issue to request a fresh review only.
  • Maintainers can also comment @clawsweeper review to request a fresh review only.
  • Fresh-review commands do not start repair, autofix, rebase, CI repair, or automerge.
  • Maintainer-only repair and merge flows require explicit commands such as @clawsweeper autofix, @clawsweeper automerge, @clawsweeper fix ci, or @clawsweeper address review.
  • Maintainers can comment @clawsweeper explain to ask for more context, or @clawsweeper stop to stop active automation.

@clawsweeper clawsweeper Bot added rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. status: ⏳ waiting on author ClawSweeper has contributor-facing work open and is waiting for author action. P2 Normal backlog priority with limited blast radius. merge-risk: 🚨 message-delivery 🚨 May drop, duplicate, misroute, suppress, or wrongly target messages. merge-risk: 🚨 security-boundary 🚨 May affect sandboxing, authorization, credentials, or sensitive data. labels May 27, 2026
@clawsweeper

clawsweeper Bot commented May 27, 2026

Copy link
Copy Markdown
Contributor

ClawSweeper PR egg

✨ Hatched: 🥚 common Cosmic Diff Drake

Hatch command

Comment @clawsweeper hatch when this PR is hatchable.

Hatchability rules:

  • Merged PRs are hatchable.
  • Open PRs are hatchable when they are status: 👀 ready for maintainer look, status: 🚀 automerge armed, or labeled clawsweeper:automerge.
  • Closed unmerged PRs are hatchable only when one of those hatchable labels is still present in the durable record.

Rarity: 🥚 common.
Trait: stacks clean commits.
Image traits: location flaky test forest; accessory proof snapshot camera; palette coral, mint, and warm cream; mood curious; pose peeking out from the egg shell; shell frosted glass shell; lighting golden review-room light; background tiny shells and proof notes.
Share on X: post this hatch
Copy: My PR egg hatched a 🥚 common Cosmic Diff Drake in ClawSweeper.

What is this egg doing here?
  • Eggs appear after the PR passes real-behavior proof. It is here for vibes, not verdicts: it does not change labels, ratings, merge decisions, or automation.
  • The shell reacts to review momentum: open follow-up work warms it up, re-review makes it wobble, and a clean final review lets it hatch.
  • Hatchability usually comes from sufficient real-behavior proof, no blocking P0/P1/P2 findings, no security attention needed, and clean correctness. A merged PR is already final, so merge makes the egg hatchable independently.
  • The hatch is seeded from this repository and PR number, so the same PR keeps the same creature; the reviewed head SHA can only change safe visual details.
  • Rarity is just collectible sparkle: 🥚 common, 🌱 uncommon, 💎 rare, ✨ glimmer, and 🌈 legendary.

@openperf
openperf force-pushed the fix/86742-restart-continuation-session-guarded-queue branch from 8f9cec0 to ef1b98b Compare May 27, 2026 15:12
@clawsweeper clawsweeper Bot added the proof: sufficient ClawSweeper judged the real behavior proof convincing. label May 27, 2026
@openperf
openperf force-pushed the fix/86742-restart-continuation-session-guarded-queue branch from ef1b98b to 592364d Compare May 27, 2026 15:34
@clawsweeper clawsweeper Bot added rating: 🦞 diamond lobster Very strong PR readiness with only minor maintainer review expected. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. and removed rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. status: ⏳ waiting on author ClawSweeper has contributor-facing work open and is waiting for author action. labels May 27, 2026
@openperf
openperf force-pushed the fix/86742-restart-continuation-session-guarded-queue branch 2 times, most recently from db40282 to 7e74eaf Compare May 27, 2026 22:34
@BingqingLyu

This comment was marked as spam.

@clawsweeper clawsweeper Bot added rating: 🌊 off-meta tidepool PR readiness rating does not apply to this item. and removed proof: sufficient ClawSweeper judged the real behavior proof convincing. rating: 🦞 diamond lobster Very strong PR readiness with only minor maintainer review expected. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. labels May 29, 2026
@clawsweeper clawsweeper Bot added proof: sufficient ClawSweeper judged the real behavior proof convincing. rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. and removed rating: 🌊 off-meta tidepool PR readiness rating does not apply to this item. labels May 29, 2026
@clawsweeper clawsweeper Bot added the rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. label Jun 7, 2026
@steipete
steipete force-pushed the fix/86742-restart-continuation-session-guarded-queue branch 2 times, most recently from f76eb84 to bf968f6 Compare June 7, 2026 10:17
openperf and others added 9 commits June 7, 2026 11:30
…t continuations (openclaw#86742)

When two sessions issue gateway.restart with continuationMessage close
together, the scheduler Path B updatePendingRestartEmitHooks
unconditionally overwrote the existing pending hooks, silently dropping
the first sessions continuation and potentially routing the second
sessions continuation back to the first session (CWE-200 finding
flagged by aisle-research-bot on prior attempt openclaw#74443).

Add a session-routing guard: scheduleGatewaySigusr1Restart now accepts
an optional sessionKey and tracks the pending restarts owning session.
Coalesced callers from a different session are rejected at the hook-
update step and the new ScheduledRestart.emitHooksQueued: false field
surfaces the drop to the caller. The gateway tool propagates this as
continuationQueued: false in the tool response, matching openclaw#83370 narrow
report-only surface.

Same-session debounce/replace and legacy hookless callers behave the
same as before.

Refs openclaw#86742
@clawsweeper clawsweeper Bot added rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. and removed rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. status: ⏳ waiting on author ClawSweeper has contributor-facing work open and is waiting for author action. labels Jun 7, 2026
@steipete
steipete force-pushed the fix/86742-restart-continuation-session-guarded-queue branch from 81e1737 to efe8a0d Compare June 7, 2026 10:31
@openclaw-barnacle openclaw-barnacle Bot added the scripts Repository scripts label Jun 7, 2026
@steipete

steipete commented Jun 7, 2026

Copy link
Copy Markdown
Contributor

Land-ready proof for head efe8a0df74acbdd02f3cf84526c03b52bc71a204.

What changed:

  • Guarded coalesced restart continuation ownership by trusted session key so a later different-session restart cannot overwrite the accepted sentinel/continuation.
  • Threaded trusted runtime session identity through gateway.restart, update.run, and /restart scheduling.
  • Preserved accepted restart hooks for hookless forced restarts when explicitly bypassing deferral, including the pending-timer path.
  • Refreshed/defaulted generated Swift SendParams optional initializer fields so the protocol output remains source-compatible.

Proof run:

  • pnpm protocol:check
  • node scripts/run-vitest.mjs src/infra/infra-runtime.test.ts src/agents/tools/gateway-tool.test.ts src/auto-reply/reply/commands-session-restart.test.ts src/infra/restart-coordinator.test.ts (3 shards, 62 tests)
  • pnpm exec oxfmt --check --threads=1 src/infra/restart.ts src/infra/infra-runtime.test.ts scripts/protocol-gen-swift.ts && git diff --check
  • .agents/skills/autoreview/scripts/autoreview --mode branch --base origin/main --output /tmp/pr87323-autoreview-final-after-force-preserve.txt (clean: no accepted/actionable findings)
  • Testbox-through-Crabbox tbx_01ktgt72f5r62yhsjxxypa8qf3, Actions run https://github.com/openclaw/openclaw/actions/runs/27089987649, 3 real restart scenarios passed: cross-session pulled-earlier restart, hookless forced pending-timer bypass, hookless forced active-deferral bypass.
  • GitHub PR checks: 132 success, 33 neutral/skipped, 0 pending, 0 failed.

Known proof gaps: none for the touched restart/session-routing surfaces.

@steipete
steipete merged commit afcbdd7 into openclaw:main Jun 7, 2026
165 of 167 checks passed
github-actions Bot pushed a commit to Desicool/openclaw that referenced this pull request Jun 8, 2026
…t continuations (openclaw#86742) (openclaw#87323)

* fix(infra/agents): session-routing guard for coalesced gateway restart continuations (openclaw#86742)

When two sessions issue gateway.restart with continuationMessage close
together, the scheduler Path B updatePendingRestartEmitHooks
unconditionally overwrote the existing pending hooks, silently dropping
the first sessions continuation and potentially routing the second
sessions continuation back to the first session (CWE-200 finding
flagged by aisle-research-bot on prior attempt openclaw#74443).

Add a session-routing guard: scheduleGatewaySigusr1Restart now accepts
an optional sessionKey and tracks the pending restarts owning session.
Coalesced callers from a different session are rejected at the hook-
update step and the new ScheduledRestart.emitHooksQueued: false field
surfaces the drop to the caller. The gateway tool propagates this as
continuationQueued: false in the tool response, matching openclaw#83370 narrow
report-only surface.

Same-session debounce/replace and legacy hookless callers behave the
same as before.

Refs openclaw#86742

* fix(infra): preserve queued restart continuation on forced bypass

* fix(infra): make forced restart hook preservation explicit

* fix(infra): guard restart continuation ownership before reschedule

* fix(infra): report hookless coalesced restarts accurately

* fix(infra): trust runtime session for restart sentinel routing

* fix(infra): preserve earlier restart reschedule semantics

* fix(agents): trust runtime session for update continuations

* fix(infra): preserve hookless forced restart continuations

---------

Co-authored-by: Peter Steinberger <[email protected]>
wangmiao0668000666 pushed a commit to wangmiao0668000666/openclaw that referenced this pull request Jun 9, 2026
…t continuations (openclaw#86742) (openclaw#87323)

* fix(infra/agents): session-routing guard for coalesced gateway restart continuations (openclaw#86742)

When two sessions issue gateway.restart with continuationMessage close
together, the scheduler Path B updatePendingRestartEmitHooks
unconditionally overwrote the existing pending hooks, silently dropping
the first sessions continuation and potentially routing the second
sessions continuation back to the first session (CWE-200 finding
flagged by aisle-research-bot on prior attempt openclaw#74443).

Add a session-routing guard: scheduleGatewaySigusr1Restart now accepts
an optional sessionKey and tracks the pending restarts owning session.
Coalesced callers from a different session are rejected at the hook-
update step and the new ScheduledRestart.emitHooksQueued: false field
surfaces the drop to the caller. The gateway tool propagates this as
continuationQueued: false in the tool response, matching openclaw#83370 narrow
report-only surface.

Same-session debounce/replace and legacy hookless callers behave the
same as before.

Refs openclaw#86742

* fix(infra): preserve queued restart continuation on forced bypass

* fix(infra): make forced restart hook preservation explicit

* fix(infra): guard restart continuation ownership before reschedule

* fix(infra): report hookless coalesced restarts accurately

* fix(infra): trust runtime session for restart sentinel routing

* fix(infra): preserve earlier restart reschedule semantics

* fix(agents): trust runtime session for update continuations

* fix(infra): preserve hookless forced restart continuations

---------

Co-authored-by: Peter Steinberger <[email protected]>
badgerbees pushed a commit to badgerbees/openclaw that referenced this pull request Jul 8, 2026
…t continuations (openclaw#86742) (openclaw#87323)

* fix(infra/agents): session-routing guard for coalesced gateway restart continuations (openclaw#86742)

When two sessions issue gateway.restart with continuationMessage close
together, the scheduler Path B updatePendingRestartEmitHooks
unconditionally overwrote the existing pending hooks, silently dropping
the first sessions continuation and potentially routing the second
sessions continuation back to the first session (CWE-200 finding
flagged by aisle-research-bot on prior attempt openclaw#74443).

Add a session-routing guard: scheduleGatewaySigusr1Restart now accepts
an optional sessionKey and tracks the pending restarts owning session.
Coalesced callers from a different session are rejected at the hook-
update step and the new ScheduledRestart.emitHooksQueued: false field
surfaces the drop to the caller. The gateway tool propagates this as
continuationQueued: false in the tool response, matching openclaw#83370 narrow
report-only surface.

Same-session debounce/replace and legacy hookless callers behave the
same as before.

Refs openclaw#86742

* fix(infra): preserve queued restart continuation on forced bypass

* fix(infra): make forced restart hook preservation explicit

* fix(infra): guard restart continuation ownership before reschedule

* fix(infra): report hookless coalesced restarts accurately

* fix(infra): trust runtime session for restart sentinel routing

* fix(infra): preserve earlier restart reschedule semantics

* fix(agents): trust runtime session for update continuations

* fix(infra): preserve hookless forced restart continuations

---------

Co-authored-by: Peter Steinberger <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agents Agent runtime and tooling merge-risk: 🚨 message-delivery 🚨 May drop, duplicate, misroute, suppress, or wrongly target messages. merge-risk: 🚨 security-boundary 🚨 May affect sandboxing, authorization, credentials, or sensitive data. P2 Normal backlog priority with limited blast radius. proof: sufficient ClawSweeper judged the real behavior proof convincing. rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. scripts Repository scripts size: L status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants