Skip to content

feat(kernel): dispatch host requests as capabilities - #1243

Open
sethkarten wants to merge 118 commits into
mainfrom
core02-host-request-dispatcher
Open

feat(kernel): dispatch host requests as capabilities#1243
sethkarten wants to merge 118 commits into
mainfrom
core02-host-request-dispatcher

Conversation

@sethkarten

@sethkarten sethkarten commented Aug 11, 2026

Copy link
Copy Markdown
Contributor

Summary

  • replace advisory host request handler registration with factory-minted capabilities and opaque dispatcher contexts
  • revoke in-flight authority on comm close, settlement, cleanup, disposal, and restart paths
  • migrate kernel host registrations and focused fixtures to explicit context-aware handlers

Validation

  • biome check on all changed paths
  • tsgo --noEmit
  • explicit kernel/host-request Vitest suite (167 passed, 7 skipped)

Note

Dispatch host requests as capability-branded handlers with abortable, provenance-checked contexts

  • KernelManager now mints a per-comm HostRequestContext (via mintHostRequestContext) with an AbortController-backed signal that is revoked on comm_close, during shutdown, and after settlement, preventing stale or replayed handler invocations.
  • createHostRequestHandler now requires an explicit contextAwareHostRequestHandler marker; unary or unmarked handlers are rejected at registration time rather than via Function.length heuristics.
  • assertGenuineHostRequestContext validates context objects by WeakSet provenance instead of structural checks, blocking payload-injected or fabricated contexts.
  • KernelManager gains a terminal state: once entered, start() rejects, host-request admission is closed, and restart waits for non-terminal shutdown to complete before reopening admission.
  • All production host handlers (agent-messages, agent-observe, agent-session, rlm-runtime, mcp-manager) are wrapped with createHostRequestHandler and contextAwareHostRequestHandler.
  • Test helpers in host-request-context.ts are updated to produce branded handlers and provide invokeHostRequestHandlerForTest / invokeHostRequestThroughKernelForTest for exercising dispatch semantics without a real kernel.
  • Risk: any externally registered host handler not wrapped with createHostRequestHandler + contextAwareHostRequestHandler will be rejected at dispatch time.

Changes since #1243 opened

  • Implemented request authority propagation for RLM child runs using abort signals and currency checks [77b188b]
  • Unified kernel startup failure cleanup to conditionally return to idle state [77b188b]
  • Added test coverage for request authority revocation in RLM child runs and kernel startup race conditions [77b188b]
  • Implemented immutable family catalog snapshots with multi-source reconciliation [0ff02b3]
  • Replaced live-derived relationships with catalog-based authorization for all agent family reach assertions [0ff02b3]
  • Plumbed sessionDir scoping through all catalog queries, name reservations, and worker launches [0ff02b3]
  • Hardened registry parsing with descriptor-relative reads and hostile artifact validation [0ff02b3]
  • Refactored session disposal to parallelize kernel shutdown and refinement drain with aggregated error handling [0ff02b3]
  • Bumped daemon protocol schema revision to 17 for authority-aware saved-session renames [0ff02b3]
  • Exported supervisor registry directory resolution and refactored ownership utilities [0ff02b3]
  • Strengthened sibling name reservation with canonical parent path resolution [0ff02b3]
  • Replaced host request authority from ID/generation/isCurrent() model to AbortSignal-based revocation [7dcf7fe]
  • Implemented RLM subagent deletion durability tracking with strict authority fencing and coordination [7dcf7fe]
  • Rewrote catalog family session traversal with descriptor-bound reads through persistent helper process [7dcf7fe]
  • Added session closing lifecycle with synchronous admission fencing and orderly async disposal [7dcf7fe]
  • Refactored sibling scope calculation and saved session name reservation to normalize depth and parent path uniformly [7dcf7fe]
  • Changed kernel host request dispatch to assign protocol status last in comm message payload [7dcf7fe]
  • Added readSessionHeaderInfoFromBuffer utility for bounded header parsing without body scan [7dcf7fe]
  • Changed deleteRlmSubagentRuntime return type to include deletionDurability result [7dcf7fe]
  • Modified AgentDaemon.persistedTopologyClaims and AgentDaemon.residentAgentFamilyCandidate utilities to gate parent session derivation based on depth values [2694177]
  • Expanded test coverage for depth-0 session fork handling in daemon mode [2694177]
  • Introduced stale incarnation detection and newer child preservation across the subagent deletion lifecycle [5dc3453]
  • Enhanced daemon subagent registry deletion with strict absence proof capability [5dc3453]
  • Fixed daemon catalog session listing to validate child artifact paths against parent session artifact directory structure [5dc3453]
  • Modified session closing to accept custom delivery and completion errors [5dc3453]
  • Added explicit pump suspension clearing before non-streaming prompts after abort [5dc3453]
  • Introduced tombstoned RLM subagent close retry infrastructure with exponential backoff [f7d3652]
  • Refactored AgentDaemon.closeSessionOnce() to support tombstoned retry context and resilient error handling [f7d3652]
  • Enforced session quarantine and privacy filtering across all daemon commands and listings [f7d3652]
  • Implemented session quarantine detection and public state filtering in daemon [f7d3652]
  • Introduced PrivateSessionUnavailableError and modified session state retrieval to enforce quarantine checks [f7d3652]
  • Modified RLM subagent release and deletion callbacks to support tombstoned durability with deferred cleanup [f7d3652]
  • Added AgentDaemon.findExactRlmState() helper for precise subagent state lookup [f7d3652]
  • Filtered heartbeats and cron jobs by session quarantine status [f7d3652]
  • Implemented session lease claiming and deferred release in AgentSessionRuntime [f7d3652]
  • Modified AgentSessionRuntime.dispose() and AgentSession.disposeAsync() to reset disposal promises on failure for retry support [f7d3652]
  • Tracked suspension reason in AgentSession to prevent direct prompts during update-restart preparation [f7d3652]
  • Implemented RLM child deletion quarantine and newer incarnation preservation in AgentSession [f7d3652]
  • Changed AgentSessionRuntime RLM subagent deletion to report deletionDurability='absent' for old incarnations [f7d3652]
  • Modified catalog session enumeration to use BigInt file stats for inode precision [f7d3652]
  • Filtered RLM child snapshots by deletion quarantine status [f7d3652]
  • Added comprehensive test coverage for tombstoned retirement, disposal retry, quarantine behavior, and inode precision [f7d3652]
  • Added sessionId to RLM subagent records in daemon supervisor tests [f7d3652]
  • Added catalog list mock to supervisor eviction tests [f7d3652]

Macroscope summarized cce55b6.


Note

High Risk
Touches kernel request authority, multi-phase RLM subagent deletion with durable host boundaries, and security-sensitive catalog traversal; regressions could revoke live work, delete wrong child incarnations, or mis-resolve agent families.

Overview
This PR turns IPython host requests into factory-minted handlers that only run with dispatcher-minted HostRequestContext (WeakSet-proven AbortSignal). Authority is revoked on comm close, settlement, shutdown, and dispose; the kernel has a one-way terminal state that blocks new admission. Production handlers (rlm.*, goals, compact, MCP, agent messaging/observe) are migrated to createHostRequestHandler, and rlm.run / rlm.delete_subagent propagate the signal into spawn and delete paths.

RLM subagent lifecycle gets a per-child deletion coordinator (generation + exact lease/incarnation) so explicit deletes, compaction reapers, spawn finalizers, and cancelled never-admitted children share one transaction. Deletes can return preserved_newer or land in private quarantine when durability is unknown; runtime/host APIs gain RlmSubagentDeletionAuthority, typed host deletion errors, and stricter deleteRlmSubagentRuntime matching on sessionFile / sessionId. Spawn admission can abort before publication; session disposal adds synchronous closing (beginClosing / isClosing), blocks reload/runtime rebuild during async teardown, and defers session lease release when the daemon owns retirement.

Agent family naming and reach now resolve siblings via catalog-filtered parents (with a direct parent-id/path fallback for passive children) and stricter isAgentFamilyParent when both id and path are present. The daemon catalog adds a family command and replaces sibling listing with a bounded walk: O_NOFOLLOW roots, a persistent Python openat helper for header/metadata/registry reads, registry layout validation, and fail-closed limits on nodes/edges/depth. Session listing gains buffer-based header parsing helpers for that path.

Reviewed by Cursor Bugbot for commit f7d3652. Bugbot is set up for automated code reviews on this repo. Configure here.

Comment thread packages/coding-agent/src/core/kernel/index.ts
Comment thread packages/coding-agent/src/core/kernel/index.ts
Comment thread packages/coding-agent/src/core/kernel/index.ts
Comment thread packages/coding-agent/src/core/kernel/index.ts
Comment thread packages/coding-agent/src/core/kernel/index.ts
@sethkarten
sethkarten marked this pull request as ready for review August 11, 2026 19:04
Comment thread packages/coding-agent/src/core/kernel/index.ts Outdated
@sethkarten
sethkarten marked this pull request as draft August 11, 2026 19:08
Comment thread packages/coding-agent/src/core/kernel/index.ts
@sethkarten
sethkarten marked this pull request as ready for review August 11, 2026 20:00
@sethkarten
sethkarten force-pushed the core02-host-request-dispatcher branch from c2f3e01 to 94e98f7 Compare August 12, 2026 17:49
Comment thread packages/coding-agent/src/core/kernel/index.ts
Comment thread packages/coding-agent/src/core/kernel/index.ts
alexzhang13
alexzhang13 previously approved these changes Aug 13, 2026
@sethkarten
sethkarten force-pushed the core02-host-request-dispatcher branch from 0f051bb to cce55b6 Compare August 13, 2026 03:55
@sethkarten
sethkarten requested review from alexzhang13 and removed request for alexzhang13 August 13, 2026 03:57
Base automatically changed from core01-root-kill-cleanup to main August 13, 2026 04:01
@sethkarten

Copy link
Copy Markdown
Contributor Author

Core checkpoint update (local, not yet pushed): the replacement-race remediation is validated through strict typecheck/formatting and focused recursion coverage. A late review found one directly related daemon-mode case where an old finalizer after same-ID republish threw instead of reporting a stale incarnation. The narrow correction and regression are being finalized now. Pre-existing or environment-only failures outside this lifecycle change are deferred rather than expanded into this PR. Publication will be append-only after the focused gate and exact-tip review pass.

Comment thread packages/coding-agent/src/core/agent-session.ts
Comment thread packages/coding-agent/src/core/agent-session.ts
Comment on lines +4604 to +4606
if (!existingJob || !this.isPublicCronJob(existingJob)) {
throw new Error(`No cron job found: ${command.jobId}`);
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟠 High daemon/daemon-mode.ts:4604

cron_cancel can cancel a public cron job owned by session B when the client supplies session A as activeSessionId. The handler validates that A is public but never compares existingJob.activeSessionId with it before calling cronStore.cancel(command.jobId), allowing cross-session cancellation of scheduled work. Reject jobs whose activeSessionId differs from the requested session.

-				if (!existingJob || !this.isPublicCronJob(existingJob)) {
+				if (
+					!existingJob ||
+					!this.isPublicCronJob(existingJob) ||
+					(command.activeSessionId !== undefined && existingJob.activeSessionId !== command.activeSessionId)
+				) {
🚀 Reply "fix it for me" or copy this AI Prompt for your agent:
In file @packages/coding-agent/src/modes/daemon/daemon-mode.ts around lines 4604-4606:

`cron_cancel` can cancel a public cron job owned by session B when the client supplies session A as `activeSessionId`. The handler validates that A is public but never compares `existingJob.activeSessionId` with it before calling `cronStore.cancel(command.jobId)`, allowing cross-session cancellation of scheduled work. Reject jobs whose `activeSessionId` differs from the requested session.

Evidence trail:
f7d36520bba57692bf11662c0b1601348496f11c: packages/coding-agent/src/modes/daemon/daemon-mode.ts:4563-4577, 4601-4616; packages/coding-agent/src/modes/daemon/daemon-supervisor.ts:1758-1762; packages/coding-agent/src/modes/agent-connection/daemon-agent-connection.ts:623-628

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 2 potential issues.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit f7d3652. Configure here.

throw cascadeError;
}
if (daemonOwnsSessionLeaseRelease) state.runtime.releaseSessionLease();
if (closeError) throw closeError;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shutdown aborts on child close

High Severity

closeSessionOnce now throws every captured closeError, including child-cascade failures during shutdown and update. shutdown() awaits closeSession with no catch, so one descendant teardown failure can abort the remaining session closes and skip process.exit.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit f7d3652. Configure here.

this._disposeAsyncPromise = undefined;
}
throw error;
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Dispose retry skips failed teardown

Medium Severity

Clearing _disposeAsyncPromise after failure does not re-run kernel dispose or drain. The failed attempt still calls dispose() in finally, so a retry sees _disposed and returns success. AgentSessionRuntime.dispose() can also release the session lease in finally before a retry continues teardown.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit f7d3652. Configure here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants