Skip to content

[rush-daemon][WS2.4][3/9] Route phased requests - #2

Open
mojaza wants to merge 1 commit into
mainfrom
mojazayeri-microsoft-rushd-ws2-route-phased-requests
Open

[rush-daemon][WS2.4][3/9] Route phased requests#2
mojaza wants to merge 1 commit into
mainfrom
mojazayeri-microsoft-rushd-ws2-route-phased-requests

Conversation

@mojaza

@mojaza mojaza commented Aug 22, 2026

Copy link
Copy Markdown
Owner

Summary

Details

The router validates the request's explicit phase/plugin shape and integration-resolved operation identifiers, reconciles retained workspace invalidations before scheduling, clears and reapplies the requested enabled-state mapping through IOperationGraph.setEnabledStates, and runs at most one manually scheduled warm iteration. Safe selection expands the requesting client's dependency closure, while missing operations remain disabled.

A stable graph-level event multiplexer preserves any integration-owned Rush dual-emit sink while attaching only the active client's selected closure. Raw stdout/stderr chunks and structured WS1 events are forwarded in engine order through serialized async writes, honoring destination backpressure. Client subscriptions detach deterministically after completion, failure, abort, or disconnect, including from operation records retained by the warm graph. Event sequences remain monotonic per client session.

Requests sharing a warm graph are serialized until the later shared-build merging layer. Cancellation and disconnect abort only the current iteration under the existing graph contract; the router never aborts the daemon graph lifetime or closes its runners. Results are scoped to the enabled client closure and retain prior successful outcomes when real graph hooks collapse a repeated warm request to no work.

Limitations

Open microsoft#5895 still lacks a command-independent plugin/phase shape and complete per-iteration runner-lifetime support. This PR therefore begins after an integration has parsed a phased command, supplied the exact warm engine shape, and resolved real graph operation identifiers. It does not duplicate PhasedScriptAction, construct a fake or empty graph, claim unsupported command/plugin graph construction, or add control-frame command admission. The default executable remains opt-in/dead-code-safe with no apps/rush or rush-lib launcher integration.

This layer also does not implement WS2.5 request cwd/env/terminal context, WS2.6 exit-code/warnings policy parity, WS2.7 stdin/raw-mode/PTY behavior, WS2.8 command classification or wait/no-wait wire admission, or WS2.9 concurrent shared-build selection merging.

The Rush dual-emit callback is synchronous, so the router preserves frame order and serializes all destination writes against transport backpressure, but cannot pause an operation producer while an already-emitted chunk awaits the client.

How it was tested

  • node common/scripts/install-run-rush.js install
  • node common/scripts/install-run-rush.js test --only @rushstack/rush-daemon-protocol --only @rushstack/rush-daemon
  • Focused real-OperationGraph coverage for selection/shape validation, invalidation-before-schedule ordering, dependency closure, exactly one warm iteration, client-only streams/events, ordered async writes, operation failures, cancellation, disconnect/write failure, stale subscription cleanup, scheduling-hook failures, cross-router serialization, monotonic event sequences, and repeated warm no-op retained results.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot AI 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.

🟡 Changes recommended

The router currently does not robustly validate enabledState values from the wire, which can cause invalid selections to be silently misinterpreted.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Pull request overview

Adds an opt-in WS2.4 routing layer that accepts an integration-resolved phased request and executes it against a warm IOperationGraph, scoping streamed output/events and results to the requesting client while preserving the graph’s long-lived lifecycle.

Changes:

  • Introduces PhasedRequestRouter to validate request identity/shape/selection, reconcile invalidations, apply enabled-states, and run at most one warm iteration with serialization across shared graphs.
  • Adds a client-scoped event sink + event multiplexer to forward WS1 events and stdout/stderr chunks in-order with backpressure handling and deterministic unsubscribe/cleanup.
  • Extends the rush-daemon protocol with typed phased-request contracts, exports new public APIs, and updates docs/API review files + lockfiles.
File summaries
File Description
libraries/rush-daemon/src/PhasedRequestRouter.ts New router that serializes phased requests, validates shape/selection, applies enabled states, schedules/executes one warm iteration, and collects client-scoped results.
libraries/rush-daemon/src/PhasedRequestEventSink.ts New _IOperationGraphEventSink that filters to a client’s active closure and performs ordered, backpressured writes for events and log chunks.
libraries/rush-daemon/src/PhasedRequestEventMultiplexer.ts New graph-level multiplexer preserving an integration-owned sink while attaching/detaching a single active request sink.
libraries/rush-daemon/src/PhasedRequestClient.ts New client contract for backpressured event/log chunk writes with abort signaling.
libraries/rush-daemon/src/index.ts Exports IPhasedRequestClient and PhasedRequestRouter.
libraries/rush-daemon/src/test/PhasedRequestRouterTestUtilities.ts Test fixtures for warm OperationGraph routing, runners, and a capturing client.
libraries/rush-daemon/src/test/PhasedRequestRouter.test.ts Coverage for selection/shape validation, invalidation ordering, dependency closure, write ordering/backpressure, abort/disconnect, hook failures, and shared-graph serialization.
libraries/rush-daemon/README.md Documents the new opt-in router boundary and its non-goals/limitations.
libraries/rush-daemon/package.json Adds @rushstack/terminal dependency for new runtime/test usage.
libraries/rush-daemon-protocol/src/DaemonPhasedRequest.ts New phased-request wire contracts (engine shape, selection, per-operation results, request result).
libraries/rush-daemon-protocol/src/index.ts Exports phased-request protocol types.
libraries/rush-daemon-protocol/README.md Notes phased-request contracts as part of the protocol’s capabilities.
common/reviews/api/rush-daemon.api.md API review updates for PhasedRequestRouter and IPhasedRequestClient.
common/reviews/api/rush-daemon-protocol.api.md API review updates for new phased-request protocol types.
common/config/subspaces/default/pnpm-lock.yaml Lockfile updates for added dependency and related snapshot churn.
common/config/subspaces/default/repo-state.json Updates shrinkwrap hash after lockfile changes.
common/changes/@rushstack/rush-daemon/mojazayeri-route-phased-requests_2026-08-21-17-24.json Change entry for @rushstack/rush-daemon (minor).
common/changes/@rushstack/rush-daemon-protocol/mojazayeri-phased-request-contracts_2026-08-21-17-24.json Change entry for @rushstack/rush-daemon-protocol (minor).
Review details

Files not reviewed (1)

  • common/config/subspaces/default/pnpm-lock.yaml: Generated file
  • Files reviewed: 17/18 changed files
  • Comments generated: 1
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment on lines +325 to +336
function addSelectedOperation(
enabledState: DaemonPhasedOperationEnabledState,
operation: Operation,
enabledOperations: Operation[],
ignoreDependencyOperations: Operation[]
): void {
if (enabledState === true) {
enabledOperations.push(operation);
} else {
ignoreDependencyOperations.push(operation);
}
}
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