Conversation
…sion proxies and repository map bug
… unified message router to consume prevData
…onData reducer Tasks 3a (lastStatus), 3d+3e (messageHistory with dedup for assistant/ tool_use_summary messages) migrated from UnifiedMessageRouter into reduceSessionData. The reducer now handles: - lastStatus: inferred from status_change, result, stream_event - messageHistory: append/replace with dedup logic for assistant+tool_use_summary - backendSessionId, pendingPermissions: already in previous commit
…ith orchestration SessionRuntime.handleBackendMessage now: 1. Runs reduceSessionData (pure) to apply state transitions 2. Runs orchestrate* methods for side effects (emitEvent, git, capabilities) 3. Delegates to routeBackendMessage for T4 broadcasting Orchestration methods moved from router to runtime: - orchestrateSessionInit: git, registry, capabilities, queue - orchestratePermissionRequest: emits permission:requested event - orchestrateAuthStatus: emits auth_status event - orchestrateResult: auto-naming, git refresh, queue - orchestrateStatusChange: queue on idle - orchestrateControlResponse: capabilities policy
… and fix bridge wiring (Task 4)
UnifiedMessageRouter now handles only T4 translation (UnifiedMessage →
ConsumerMessage broadcast). All setter callbacks (setState, setLastStatus,
setMessageHistory, storePendingPermission, etc.) removed — state transitions
go exclusively through SessionStateReducer via SessionRuntime.
Router shrinks from 644 → 305 lines. Router test file trimmed by ~435 lines.
Bridge wiring fixes:
- compose-runtime-plane: add getCapabilitiesPolicy + emitEvent lazy deps
- compose-message-plane: trim createUnifiedMessageRouterDeps to {broadcaster, tracer}
- runtime-manager-factory: add emitEvent, getGitTracker, getCapabilitiesPolicy deps
- session-bridge-deps-factory: remove emitEvent from router deps factory
- session-bridge.ts: wire getCapabilitiesPolicy and emitEvent into composeRuntimePlane
- cli-message-factories: update createMockSession for data field structure
…k 2.3) CapabilitiesPolicy.applyCapabilities was calling persistSession(session) with the pre-setState session reference — a stale object since SessionRuntime.setState replaces this.session via spread-reassignment. Fix: persist in SessionRuntime.orchestrateControlResponse after handleControlResponse returns. At that point this.session reflects any setState calls made by applyCapabilities through the stateAccessors adapter. Removes persistSession constructor parameter from CapabilitiesPolicy entirely; persistence is now exclusively orchestrated by SessionRuntime.
…ter (Task 5.3) - Create effect-types.ts: Effect discriminated union (BROADCAST, BROADCAST_TO_PARTICIPANTS, BROADCAST_SESSION_UPDATE, EMIT_EVENT, AUTO_SEND_QUEUED) - Create effect-executor.ts: executeEffects() bridges pure reducer output to side-effectful runtime services; injects sessionId on all EMIT_EVENT payloads automatically - Expand session-state-reducer to return [SessionData, Effect[]] with buildEffects() producing typed effects per message type - Wire executeEffects into SessionRuntime.handleBackendMessage; remove orchestrateStatusChange, orchestratePermissionRequest, orchestrateAuthStatus (replaced by effects); simplify orchestrateResult to git-refresh only - Delete UnifiedMessageRouter and its test: all T4 broadcast/emit logic now lives in the pure reducer + effect executor - Remove routeBackendMessage from SessionRuntimeDeps, RuntimeManagerFactoryDeps, and all wiring; remove getMessageRouter from compose-runtime-plane; clean up compose-message-plane, session-bridge-deps-factory, and session-bridge.ts accordingly
…ia buildSessionServices (Phase 6) Task 6.1: Add SessionServices interface capturing all 10 sub-services from the 4 compose planes (runtimeApi, backendApi, infoApi, broadcastApi, lifecycleService, persistenceService, consumerGateway, broadcaster, core, store). Task 6.2: Add buildSessionServices() factory in session-coordinator/build-services.ts using the same lazy-closure pattern as the old SessionBridge constructor to resolve circular deps between planes. Rewrite SessionCoordinator to use buildSessionServices() instead of new SessionBridge(). Add BridgeFacade interface (on/off/emit/getSession/ broadcastProcessOutput/broadcastNameUpdate/renameSession/executeSlashCommand) for backward-compat access by E2E tests and wiring test spies. Task 6.3: Delete src/core/session-bridge.ts. - adapter-test-helpers: replace createBridgeWithAdapter() with buildSessionServices() backing; export BridgeTestWrapper type for integration test typing - 4 integration test files: drop SessionBridge import, use BridgeTestWrapper - team-events.integration.test: use buildSessionServices() in local factory - ws-server-flow.integration.test: use createBridgeWithAdapter() helper - Remove SessionBridge from src/core/index.ts and src/index.ts public exports All 2873 tests pass, typecheck clean.
SessionInfo stores lifecycle state directly as info.state, not nested under info.data.state — that pattern belongs to Session objects inside SessionRuntime/SessionRepository.
Summary of ChangesHello @teng-lin, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! This pull request introduces a fundamental architectural shift in how session state is managed, transitioning from a mutable, class-based approach to an immutable, functional reducer pattern. This change aims to improve the clarity, maintainability, and testability of session logic by centralizing state mutations and explicitly separating side effects. The refactor also significantly streamlines the core infrastructure by removing deprecated components and introducing a more cohesive service composition. Highlights
Changelog
Activity
Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here. You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension. Footnotes
|
…ionRuntime Replace 4 inline deps.persistSession calls with purpose-specific methods: - persistNow() for critical mutations (setAdapterName, sendUserMessage) - markDirty() for frequent transitions (handleBackendMessage, orchestrateControlResponse) markDirty() collapses multiple rapid state changes into a single write via a 50ms debounce timer.
…s (~450 lines removed)
Fold the four compose-*-plane.ts files directly into buildSessionServices().
All lazy circular-dep resolution stays; only the function-call layer is removed.
- Delete: compose-runtime-plane.ts, compose-consumer-plane.ts,
compose-message-plane.ts, compose-backend-plane.ts, types.ts
- Delete: corresponding .test.ts files (4 files, 6 tests)
- Move BridgeCoreContext definition into session-services.ts
- Move SessionBridgeInitOptions definition into build-services.ts
Closes plan Task 6.3 (second half).
There was a problem hiding this comment.
Code Review
The pull request refactors SessionRuntime into a pure reducer and effect executor pattern, deleting SessionBridge and UnifiedMessageRouter. This significantly reduces complexity and improves maintainability by centralizing state mutations and separating side effects. The changes also introduce SessionData for immutable state snapshots and SessionServices for a flat registry of services. The Python script fix_router.py is used to update references to the removed UnifiedMessageRouter and adapt the routeBackendMessage signature. Overall, the refactor aligns with functional programming principles, making the session management more predictable and testable.
I am having trouble creating individual review comments. Click here to see my feedback.
src/core/session/effect-executor.ts (1-8)
This new file effect-executor.ts is a crucial part of the refactoring, as it centralizes the execution of side effects emitted by the pure reducer. This clearly separates concerns and improves the testability of the state management logic.
src/core/session-bridge/compose-message-plane.ts (117)
The removal of messageRouter from the returned object is consistent with the deletion of the UnifiedMessageRouter class as part of the refactor.
src/testing/cli-message-factories.ts (71-144)
The createMockSession function is significantly refactored to support the new SessionData structure. It now correctly extracts SessionData properties from overrides and initializes the data object, ensuring that mock sessions adhere to the new immutable state pattern. This is a critical change for maintaining consistency across tests.
src/index.ts (67)
The removal of SessionBridge export is consistent with the deletion of the SessionBridge class as part of the refactor.
src/core/bridge/session-bridge-deps-factory.ts (125)
The removal of createUnifiedMessageRouterDeps is a significant change, as UnifiedMessageRouter has been deleted and its responsibilities absorbed into the reducer/effect pipeline within SessionRuntime.
src/core/index.ts (45)
The removal of SessionBridge export is consistent with the deletion of the SessionBridge class as part of the refactor.
src/core/session-bridge/compose-message-plane.ts (8)
The removal of createUnifiedMessageRouterDeps is consistent with the deletion of UnifiedMessageRouter and its integration into SessionRuntime's internal logic.
src/core/session-bridge/compose-message-plane.ts (17)
The removal of UnifiedMessageRouter import is consistent with the deletion of the UnifiedMessageRouter class as part of the refactor.
src/core/session-bridge/compose-message-plane.ts (56)
The removal of messageRouter: UnifiedMessageRouter; from the MessagePlane interface is consistent with the deletion of the UnifiedMessageRouter class as part of the refactor.
src/core/session/effect-types.ts (1-10)
This new file effect-types.ts is a crucial part of the refactoring, as it defines the Effect type, which represents a typed description of a side effect. This enables the pure reducer pattern by separating side effects from state mutations.
src/core/session-bridge/compose-runtime-plane.test.ts (28)
The removal of const getMessageRouter = vi.fn(() => ({ route })); is consistent with the deletion of UnifiedMessageRouter and its integration into SessionRuntime's internal logic.
fix_router.py (47-48)
This line removes the direct state mutation from unified-message-router.ts, which is a key part of refactoring to a pure reducer pattern. This is a critical change for centralizing state management.
src/core/session/session-state-reducer.ts (44-56)
The new reduceSessionData function is the core of the pure reducer pattern. It takes SessionData and a UnifiedMessage, applies various sub-reducers to produce the next state, and then builds a list of Effect objects. This clearly separates state mutation from side effects.
src/core/session-bridge/compose-runtime-plane.test.ts (59)
The removal of routeBackendMessage: (session: Session, message: unknown) => void; from the runtime.deps interface is consistent with the deletion of UnifiedMessageRouter and its integration into SessionRuntime's internal logic.
src/core/session-bridge/compose-runtime-plane.ts (14)
The removal of UnifiedMessageRouter import is consistent with the deletion of the UnifiedMessageRouter class as part of the refactor.
src/core/session/session-state-reducer.ts (37-38)
The addition of imports for Effect and SessionData are crucial for the new pure reducer pattern, as reduceSessionData now operates on SessionData and returns Effect[].
src/core/session/session-runtime.ts (704-709)
The executeEffects call is crucial for handling side effects after the state has been reduced. This clearly separates pure state logic from impure side effects, improving testability and maintainability.
src/core/session/session-runtime.ts (684-688)
The introduction of prevData and the call to reduceSessionData are central to the refactoring. reduceSessionData is a pure function that returns the next state and a list of effects, adhering to the new reducer pattern.
src/core/session-coordinator.ts (51)
The removal of SessionBridge import is consistent with the deletion of the SessionBridge class as part of the refactor.
src/core/session/session-runtime.ts (119)
The change from private readonly session: Session, to private session: Session, // readonly removed — we reassign via spread is a critical change that enables the immutable state pattern. By allowing session to be reassigned, SessionRuntime can now update its internal session reference with new SessionData objects produced by the reducer, ensuring immutability.
src/core/session/session-runtime.ts (100)
The removal of routeBackendMessage from SessionRuntimeDeps is consistent with the deletion of UnifiedMessageRouter and its integration into SessionRuntime's internal logic.
src/core/session/session-runtime.ts (39)
The addition of reduceSessionData import is crucial for the new pure reducer pattern, as SessionRuntime now uses this function to manage session state.
src/core/session-coordinator.ts (150-165)
The call to buildSessionServices is the core of the refactoring, assembling all the new service planes into a single services object. This replaces the monolithic SessionBridge constructor with a more modular approach.
src/core/session/session-runtime.test.ts (339)
The removal of routeBackendMessage: () => calls.push("route"), is consistent with the deletion of UnifiedMessageRouter and its integration into SessionRuntime's internal logic.
src/core/session-coordinator/build-services.ts (1-13)
This new file build-services.ts is a crucial part of the refactoring, centralizing the assembly of all four compose planes into a single SessionServices object. This significantly reduces complexity in SessionCoordinator and improves modularity.
src/core/session/session-repository.ts (193-202)
The introduction of the data property encapsulating state, pendingPermissions, messageHistory, pendingMessages, queuedMessage, lastStatus, adapterName, and adapterSupportsSlashPassthrough is a core change for implementing the immutable SessionData pattern. This centralizes the serializable state.
src/core/session/session-repository.ts (37-41)
The Session interface is updated to reflect the new SessionData structure. The data property now holds the serializable state, while other properties remain for runtime handles. This is a significant architectural change for state management.
src/core/team/team-events.integration.test.ts (26)
The change from SessionBridge to buildSessionServices is consistent with the deletion of the SessionBridge class and the new service-oriented architecture.
src/core/session-services.ts (1-9)
This new file session-services.ts defines the SessionServices interface, which is a central part of the refactoring. It provides a clear and flat registry of all services, replacing the monolithic SessionBridge and improving modularity.
src/core/session/session-data.ts (1-9)
This new file session-data.ts defines the SessionData interface, which is a central part of the refactoring. It enforces immutability for session state, making state management more predictable and testable.
src/core/bridge/runtime-manager-factory.ts (39-48)
The removal of routeBackendMessage and the addition of emitEvent, gitTracker, gitResolver, and capabilitiesPolicy reflect the refactoring of UnifiedMessageRouter and the new responsibilities of SessionRuntime in orchestrating these services. This is a significant change in the architecture.
src/core/session/session-runtime.ts (109-112)
The addition of gitTracker, gitResolver, emitEvent, and capabilitiesPolicy to SessionRuntimeDeps reflects the new responsibilities of SessionRuntime in orchestrating these services directly, rather than relying on UnifiedMessageRouter.
src/core/session/session-runtime.test.ts (38-49)
The addition of gitTracker, gitResolver, emitEvent, and capabilitiesPolicy to the makeDeps function reflects the new responsibilities of SessionRuntime in orchestrating these services directly, rather than relying on UnifiedMessageRouter.
src/core/session-coordinator.ts (167-192)
The creation of the bridge facade is a crucial step for maintaining backward compatibility with existing tests and utilities that relied on the SessionBridge interface. This allows for a gradual transition to the new service-oriented architecture.
src/core/session-coordinator.ts (146-148)
The introduction of _bridgeEmitter as a plain EventEmitter is a key part of the refactoring, replacing the direct event emission from SessionBridge and allowing for a more modular event handling approach.
src/core/session-coordinator.ts (120-122)
The introduction of services and _bridgeEmitter as private readonly properties is central to the refactoring. services holds the new flat registry of session services, and _bridgeEmitter replaces the event emission mechanism previously handled by SessionBridge.
src/core/bridge/runtime-manager-factory.test.ts (31-42)
The removal of routeBackendMessage and the addition of emitEvent, getGitTracker, gitResolver, and getCapabilitiesPolicy reflect the refactoring of UnifiedMessageRouter and the new responsibilities of SessionRuntime in orchestrating these services. This is a significant change in the architecture.
src/core/session-coordinator.ts (82-111)
The introduction of the BridgeFacade interface is a good design choice for maintaining backward compatibility with existing E2E tests and utilities while transitioning away from the SessionBridge class. This facade abstracts the underlying service changes.
src/core/session-bridge/compose-runtime-plane.ts (103-111)
The removal of routeBackendMessage and the addition of emitEvent, gitTracker, gitResolver, and capabilitiesPolicy reflect the refactoring of UnifiedMessageRouter and the new responsibilities of SessionRuntime in orchestrating these services. This is a significant change in the architecture.
src/core/session-bridge/compose-runtime-plane.ts (65-66)
The removal of getMessageRouter and the addition of getCapabilitiesPolicy and emitEvent reflect the refactoring of UnifiedMessageRouter and the new responsibilities of SessionRuntime in orchestrating these services.
src/core/session-coordinator/build-services.ts (48-61)
The composeRuntimePlane call with lazy getters for getOrCreateSession, getBroadcaster, getQueueHandler, getSlashService, getBackendConnector, getPersistenceService, getGitTracker, getCapabilitiesPolicy, and emitEvent effectively resolves circular dependencies between the planes. This is a well-designed solution for complex inter-service communication.
src/core/session/session-runtime.ts (712-718)
The orchestration of high-level side effects for session_init, result, and control_response is now handled directly within SessionRuntime, centralizing these complex interactions.
src/core/session/session-state-reducer.ts (89-253)
The buildEffects function is a well-designed component that constructs a list of Effect objects based on the message type and the previous/next SessionData. This centralizes the logic for determining what side effects should occur after a state transition, making the reducer pure and the effects explicit.
src/core/session/session-runtime.ts (726-777)
The new orchestrateSessionInit method encapsulates the complex logic for handling session_init messages, including backend session ID storage, git info resolution, registry population, and capabilities policy initialization. This centralizes and clarifies the initialization flow.
src/core/session-bridge/compose-runtime-plane.ts (40-41)
The removal of getMessageRouter and the addition of getCapabilitiesPolicy and emitEvent reflect the refactoring of UnifiedMessageRouter and the new responsibilities of SessionRuntime in orchestrating these services.
src/core/session-bridge/compose-runtime-plane.test.ts (48-49)
The removal of routeBackendMessage and the addition of getCapabilitiesPolicy and emitEvent reflect the refactoring of UnifiedMessageRouter and the new responsibilities of SessionRuntime in orchestrating these services.
src/core/session/session-runtime.ts (790-806)
The new orchestrateResult method handles result messages, including git info refreshes and broadcasting session updates. This centralizes and clarifies the result message flow.
src/core/session/session-state-reducer.ts (564-635)
The new reduceMessageHistory function centralizes the logic for updating the message history, including handling assistant messages, result messages, and tool use summaries. It correctly identifies and updates existing messages or appends new ones, ensuring that the message history is consistently managed.
src/core/session-bridge/compose-runtime-plane.test.ts (29-33)
The addition of getCapabilitiesPolicy and emitEvent reflects the new responsibilities of SessionRuntime in orchestrating these services directly, rather than relying on UnifiedMessageRouter.
src/core/team/team-events.integration.test.ts (160-169)
The createBridgeWithAdapter helper is updated to use buildSessionServices and return a bridge facade that exposes necessary methods. This is a crucial adaptation for tests to interact with the new service-oriented architecture.
src/core/session/session-runtime.ts (780-787)
The new orchestrateControlResponse method handles control_response messages, delegating to capabilitiesPolicy and ensuring that any state changes are persisted. This centralizes and clarifies the control response flow.
src/testing/adapter-test-helpers.ts (168-187)
The new BridgeTestWrapper type defines a minimal bridge-like facade for testing purposes. This is a good approach to maintain backward compatibility with existing tests while transitioning to a new service-oriented architecture.
src/testing/adapter-test-helpers.ts (193-251)
The createBridgeWithAdapter function is updated to use buildSessionServices and return a BridgeTestWrapper facade. This is a crucial adaptation for tests to interact with the new service-oriented architecture, ensuring that the tests are compatible with the refactored codebase.
src/core/bridge/runtime-manager-factory.ts (18-23)
The removal of routeBackendMessage and the addition of emitEvent, getGitTracker, gitResolver, and getCapabilitiesPolicy reflect the refactoring of UnifiedMessageRouter and the new responsibilities of SessionRuntime in orchestrating these services. This is a significant change in the architecture.
…/ and clean up stale imports - Move all 12 src/core/bridge/ modules to src/core/session-coordinator/: runtime-manager, runtime-manager-factory, runtime-api, backend-api, session-lifecycle-service, session-info-api, session-broadcast-api, session-persistence-service, session-deps-factory (renamed from session-bridge-deps-factory), bridge-event-forwarder, slash-service-factory, message-tracing-utils - Delete src/core/bridge/ directory (now empty) - Fix broken import in build-services.ts: ../bridge/session-bridge-deps-factory.js → ./session-deps-factory.js All other ../bridge/* → ./* - Fix stale import in consumer-gateway.ts: ../interfaces/session-bridge-coordination.js → ../interfaces/session-coordination.js - Update session-services.ts: type imports from ./bridge/ → ./session-coordinator/ - Fix implicit any in session-deps-factory.ts registerConsumer identity param - Fix implicit any in build-services.ts emit lambda via explicit cast All 2867 tests pass, pnpm typecheck clean.
Delete modules that were pure pass-through delegations with no logic: - BackendApi (50 lines) — inlined as connectBackendForSession helper - SessionBroadcastApi (60 lines) — replaced with direct broadcaster calls - SessionPersistenceService (39 lines) — replaced with direct store calls - bridge-event-forwarder (28 lines) — inlined into build-services.ts Move message-tracing-utils.ts → src/core/messaging/ (was misplaced in session-coordinator/, but it's a pure T1 boundary utility) SessionServices interface simplified: - backendApi → backendConnector (raw connector) - broadcastApi removed (broadcaster already exposed) - persistenceService removed (store already exposed) + capabilitiesPolicy added (needed for disconnectBackend path) All consumers updated: session-coordinator.ts, adapter-test-helpers.ts, team-events.integration.test.ts. All 2851 tests pass, pnpm typecheck clean.
Inline into build-services.ts (the single composition root): - runtime-manager-factory.ts (51 lines) — createRuntimeManager - slash-service-factory.ts (68 lines) — createSlashService - session-deps-factory.ts (224 lines) — all dep factory functions Absorb SessionInfoApi into SessionCoordinator: - session-info-api.ts (57 lines) — getSession, seedSessionState, setAdapterName, getAllSessions now inlined as private helpers SessionServices interface updated: - infoApi removed (absorbed into coordinator) + runtimeManager added (coordinator needs it for session reads) session-coordinator/ contents reduced from 14 → 8 files (4 source + 4 tests). Remaining source files that require Milestone 3 to absorb: - build-services.ts — composition root - runtime-manager.ts — per-session runtime map - runtime-api.ts — lease-guarded runtime operations - session-lifecycle-service.ts — session create/close lifecycle All 2842 tests pass, pnpm typecheck clean.
…t/Effect pattern Tasks 5.1-5.3 from architecture plan: - Added SessionEvent discriminated union for inputs to process() - Added SessionRuntime.process(event) as single canonical entry point - Updated RuntimeApi, RuntimeManager, and SessionLifecycleService to route all actions (backend message, inbound command, policy command, lifecycle signal) through process() - Effect types and Executor were already built earlier and working - All 2846 tests pass
- removed runtime-api.ts, runtime-manager.ts, session-lifecycle-service.ts - inlined simple facade access to session runtime inside build-services.ts - simplified SessionServices interface types
…essionData Per the architecture plan, both halves of per-session state should live in session-data.ts: SessionData (immutable, serializable) and SessionHandles (mutable, non-serializable runtime references). session-repository.ts re-exports SessionHandles for backward compatibility.
- Drop onInboundObserved, onInboundHandled, onBackendMessageObserved, onBackendMessageHandled, onSignal — none were wired up in production (build-session-services.ts), only existed as migration scaffolding. - Remove the 2 test cases that tested those deleted hooks. - Port all test calls from private handleBackendMessage/handleInboundCommand/ handleSignal/handlePolicyCommand to the public process() entry point, aligning tests with the documented single-entry-point design. - SessionRuntimeDeps is now a clean, minimal interface aligned with the architecture-post-refactor.md specification.
…GNAL Replace the two separate event types (LIFECYCLE_SIGNAL with flat string union, POLICY_COMMAND with PolicyCommand object) with a single typed SYSTEM_SIGNAL variant carrying a SystemSignal discriminated union. SystemSignal kinds (all UPPER_SNAKE_CASE): BACKEND_CONNECTED / BACKEND_DISCONNECTED / SESSION_CLOSED CONSUMER_CONNECTED / CONSUMER_DISCONNECTED GIT_INFO_RESOLVED / CAPABILITIES_READY IDLE_REAP / RECONNECT_TIMEOUT / CAPABILITIES_TIMEOUT SessionRuntime.process() now has 3 clean cases: BACKEND_MESSAGE | INBOUND_COMMAND | SYSTEM_SIGNAL handleSystemSignal() merges the old handleSignal() + handlePolicyCommand() into one method dispatching on signal.kind. All call sites updated: build-session-services.ts (4 sites), session-runtime.test.ts (5 sites), session-event.test.ts (rewritten). Matches architecture-post-refactor.md SessionEvent spec exactly.
SessionData now has a 'readonly lifecycle: LifecycleState' field.
SessionRuntime.transitionLifecycle() now spread-updates this.session.data
instead of assigning a private field.
This means lifecycle is part of the pure, serializable session state —
matching the architecture-post-refactor.md contract where:
SessionData = all immutable state the reducer can inspect and produce.
Changes:
- session-data.ts: add lifecycle field (+ LifecycleState import)
- session-runtime.ts: remove private lifecycle field;
getLifecycleState() → this.session.data.lifecycle
transitionLifecycle() → spread-update data.lifecycle
getSessionSnapshot() → read from data
- session-repository.ts: seed lifecycle: 'awaiting_backend' in createSession
- session-data.test.ts: add lifecycle to inline data literal
- cli-message-factories.ts: add 'lifecycle' to dataKeys + defaultData
…session-state-reducer - Created sessionReducer as the single entry point for all pure state transitions. - Abstracted pure history array mutations to history-reducer.ts. - Abstracted pure effect descriptions to effect-mapper.ts. - Bounded session-state-reducer.ts strictly to AI context reduction (SessionState). - Updated SessionRuntime.process() to call the top-level pure sessionReducer and execute effects. - Moved SessionRuntimeDeps interface to build-session-services.ts to decouple runtime from orchestration dependencies. - Ensure all 2800+ tests pass with the new separated architecture.
…ttern Delete build-session-services.ts (~867 lines) and session-services.ts (~115 lines). Replace all accessor callback bags with direct getRuntime/service references. Phase 1: Replace CapabilitiesStateAccessors, QueueStateAccessors, and ConsumerPlaneRuntimeAccessors with getRuntime across capabilities-policy, message-queue-handler, backend-connector, and consumer-gateway. Phase 2: Inline all composition into SessionCoordinator constructor. Coordinator now owns runtimes map and constructs all services directly. Delete the 5 create* factory functions and forwardBridgeEventWithLifecycle. Phase 3: Simplify SessionRuntimeDeps from a callback bag to direct service refs. Replace persistSession/sendToBackend/tracedNormalizeInbound/warnUnknownPermission callbacks with store/backendConnector/tracer/logger. Remove ensureMutationAllowed guard and canMutateSession/onMutationRejected hooks. Remove onSessionSeeded and onInvalidLifecycleTransition hooks (inline logger.warn and gitTracker calls). Net: ~800 lines removed, zero behaviour changes, all 181 test files pass.
Route SYSTEM_SIGNAL through sessionReducer() instead of calling transitionLifecycle() directly, activating the previously unreachable reduceSystemSignal() branch. Lifecycle transitions are identical.
Add dedicated test files for effect-mapper, effect-executor, and history-reducer (all previously at 0% or partial), and extend session-state-reducer tests to cover compacting, modelUsage, control_response, session_lifecycle effects, and reducer edge-case branches. New files: effect-mapper.test.ts, effect-executor.test.ts, history-reducer.test.ts +53 tests across 5 files (+2871 total, was 2816)
Add 18 tests covering previously uncovered branch conditions in session-runtime.ts and session-reducer.ts: session-runtime.ts (80.57% → 89.2% branches, 100% lines): - sendControlRequest: null backendSession early-return branch - handleBackendMessage: history trim when backend messages exceed limit - orchestrateSessionInit: session_id event emission, gitResolver with cwd, slash_commands/skills registry hydration, applyCapabilities path - orchestrateControlResponse: markDirty when session reference changes - orchestrateResult: git update broadcast when refreshGitInfo truthy - applyLifecycleFromBackendMessage: running/compacting → active branches - sendPermissionResponse: event emission when no backendSession - storePendingPermission: public accessor coverage session-reducer.ts (92.08% → 94.96% branches, 100% lines): - status_change with permissionMode → BROADCAST_SESSION_UPDATE patch - tool_progress message → BROADCAST effect - configuration_change with m.mode string → permissionMode in patch - INBOUND_COMMAND path (reduceInboundCommand) for active and closing Overall branch coverage: 85.95% → 90.68% (exceeds 90% threshold)
…ctor - Merge session-coordinator.wiring.test.ts into session-coordinator.test.ts (new TrackingProcessManager + "SessionCoordinator wiring" describe block) - Move session-coordinator.permission-flow.integration.test.ts → src/core/coordinator/permission-flow.integration.test.ts (fix relative import path for new location) - Rename session-services.integration.test.ts → session-core.integration.test.ts (SessionBridge class no longer exists) - Rename session-services.adapter-consumer.integration.test.ts → session-core.adapter-consumer.integration.test.ts - Update BridgeTestWrapper JSDoc in adapter-test-helpers.ts - Update docs/architecture.md to reflect post-refactor module names
The worktree's node_modules is a symlink to the main repo's node_modules. .gitignore had `node_modules/` (trailing slash) which only matches directories, not symlinks — so the symlink was tracked and committed in d810fbf. On CI checkout this became a regular file at that path, causing pnpm `mkdir node_modules` to fail with ENOTDIR (exit 236). - git rm --cached node_modules (untrack the symlink) - Add bare `node_modules` to .gitignore to cover files/symlinks too
- Remove dangling ToC entry (What Changed From Pre-Refactor) - Fix SessionCoordinator API: remove non-existent process(sessionId, event), add renameSession(), executeSlashCommand(), store/broadcaster/backendConnector - Fix SystemSignal types: remove TIMEOUT, remove extra fields (backendSession, gitInfo, capabilities), add SESSION_CLOSED - Fix INBOUND_COMMAND: add ws: WebSocketLike field - Fix Effect type: remove SEND_TO_BACKEND, RESOLVE_GIT_INFO, SEND_CAPABILITIES_REQUEST, APPLY_CAPABILITIES, TRACE_T4 (these are handled by SessionRuntime methods directly, not through the effect system) - Fix EffectExecutor section: list only the 5 actual effects it dispatches - Fix SessionData: remove id (lives on Session), add backendSessionId - Fix file layout: move type files to session/ (effect-types.ts, session-event.ts, session-data.ts), add session-lease-coordinator.ts, update interfaces/ to show actual files, update all line counts - Fix inbound/outbound flow diagrams: runtime.process() not coordinator.process() - Fix BackendConnector description: BACKEND_CONNECTED has no backendSession field - Update status header: target → current state
Summary
Refactors
SessionRuntimefrom a stateful, mutation-heavy class into a pure reducer + effect executor pattern. Deletes ~1,000 lines of now-redundant infrastructure (SessionBridge,UnifiedMessageRouter) and replaces them with a flatSessionServicesregistry assembled bybuildSessionServices().Key changes
SessionDatatype (session-data.ts): Immutable serializable snapshot of all session state (state,messageHistory,pendingPermissions,lastStatus). The single source of truth passed through the reducer pipeline.reduceSessionData/SessionStateReducer(session-state-reducer.ts): Pure function — takes(SessionData, UnifiedMessage) → SessionData. All session state mutations now flow through this reducer; no more scatteredthis.field =assignments inSessionRuntime.EffectExecutor(effect-executor.ts,effect-types.ts): ProcessesSessionEffect[]emitted alongside each reduced state — broadcasts, storage writes, router calls — keeping side effects separated from business logic.SessionCoordinatorwiring (session-coordinator.ts,build-services.ts,session-services.ts): IntroducesbuildSessionServices()factory that assembles all four compose planes into a flatSessionServicesregistry.SessionCoordinatorwires launcher, registry, policies, and services without going throughSessionBridge.SessionBridgedeleted (session-bridge.tsremoved, ~400 lines): All callers migrated tobuildSessionServices()+BridgeTestWrapper. Public exports removed fromsrc/core/index.tsandsrc/index.ts.UnifiedMessageRouterdeleted (unified-message-router.tsremoved, ~640 lines + ~1,050 lines of tests): Routing logic absorbed into the reducer/effect pipeline.CapabilitiesPolicy: Removed incorrectpersistSessioncall (wrong abstraction layer).BridgeFacadeinterface onSessionCoordinator: Backward-compat facade exposingemit,broadcastNameUpdate,renameSession,executeSlashCommandfor coordinator wiring tests. Uses a localconst bridgevariable so spy interception works correctly.E2E test fix:
info.data.state→info.statein watchdog relaunch test (SessionInfostores state directly, not underdata).Test plan
pnpm typecheck— cleanpnpm test— 2873 tests pass (193 test files)pnpm test:e2e:claude:smoke— watchdog relaunch test passes withinfo.state = "starting"fixsession-bridge.ts,unified-message-router.tsno longer referenced anywherebuildSessionServices()assembles all four compose planes correctlySessionDataflows immutably through reducer (no mutation inSessionRuntime)