Skip to content

architecture: the domain imports the HTTP layer for LiveSession, so the session hub lives in serve.ts #91

Description

@naashw

Intent

The domain layer imports the HTTP layer. packages/cli/src/task-review.ts:34 reads:

import { createSession } from './serve.js'

createSession and the LiveSession type it returns live in serve.ts (:82, :102), the module that also owns the node:http server, the route table, the static file handler and the SSE writers. serve.ts imports task-server.ts in return (type-only), and task-server.ts imports task-review.ts.

LiveSession is not transport. It is an in-memory event hub: subscribe, publish, hold the last state so a late subscriber can catch up. SSE is one way to serialise it, the CLI renderers are another. Placing it in the HTTP module makes every domain module that wants to publish progress depend on the web server.

The practical cost is that serve.ts cannot be changed or replaced without touching the domain, and a headless run still pulls the HTTP module in. The rest of the task-*.ts split is genuinely respected by the imports; this one edge points the wrong way.

Not a defect in behaviour: nothing is broken today. Filed as an enhancement so the boundary is recorded rather than rediscovered at the next change to serve.ts.

Scope

In scope:

  • Moving LiveSession/createSession out of serve.ts into a module the domain can depend on.
  • The resulting import direction between domain and transport.

Out of scope:

  • The SSE wire format and the routes, which stay in serve.ts.
  • Splitting task-server.ts or task-runner.ts, a separate discussion.
  • Any behaviour change: this is a move, not a redesign.

Approach

Extract the session hub into its own module (alongside server-context.ts, which already holds shared server state), leaving serve.ts as a consumer that subscribes and serialises to SSE. Domain modules then import the hub, never the server.

MODIFIED Requirements

Requirement: The domain MUST NOT depend on the HTTP layer

The system SHALL keep progress publication independent of the HTTP server, so that domain modules depend on the session hub and the server depends on both.

Scenario: a headless run

  • GIVEN a review executed with no web server started
  • WHEN the domain publishes progress events
  • THEN no module owning HTTP routes or SSE writers is imported

Scenario: the transport is changed

  • GIVEN a change to the SSE frame format in serve.ts
  • WHEN the change is made
  • THEN no file under the task-* domain modules needs editing

Tasks

1. Extract

  • 1.1 Move LiveSession, createSession and their state out of serve.ts into a dedicated module
  • 1.2 Repoint task-review.ts and any other domain importer at the new module

2. Verify the direction

  • 2.1 Confirm no task-*.ts module imports serve.js any more
  • 2.2 Confirm serve.ts still owns the routes, the static handler and the SSE writers

3. Prove it

  • 3.1 Keep the existing session tests green with no assertion changes

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions