Skip to content

SSE status projection drops checkoutProvenance and checkoutPreparation #1737

Description

@marcusrbrown

Problem

Contract 1.7.0 added checkoutProvenance to OperatorRunStatus, and 1.8.0 added checkoutPreparation. toOperatorRunStatus populates both. The SSE status projection then rebuilds the frame from a fixed field list that predates both, so neither field ever reaches operator stream consumers.

packages/gateway/src/web/sse/projection.ts (projectRunObservation):

// Copy only the contract fields; never spread runState or read its details.
const result: OperatorRunStatus = {
  runId: base.runId,
  entityRef: base.entityRef,
  surface: base.surface,
  phase: base.phase,
  status: overlaidStatus,
  startedAt: base.startedAt,
  stale: base.stale,
  ...(base.failureKind === undefined ? {} : {failureKind: base.failureKind}),
}

base is the deny-gated result of projectRunStatus, which already carries both fields when present. They are dropped here. This is unchanged from v0.118.1 through current main.

Why it matters

The checkout update/recovery plan (docs/plans/2026-09-24-001-feat-workspace-checkout-update-recovery-plan.md) says:

  • line 50: "the web surface only displays the new contract fields in this plan"
  • line 437 (Unit 6 goal): "Carry the preparation result through the gateway and to operators"
  • line 614: "refusals and failures are persisted with checkoutPreparation; the operator surface shows them"

The run stream is the operator surface's only channel for OperatorRunStatus; run summaries are a separate, leaner DTO. As shipped, a run refused by checkout preparation reaches the operator as a bare FAILED with no failureKind and no preparation record, and a run that started has no visible provenance. Dashboard consumers adopting 1.8.0 have nothing to render.

Expected

The projection copies checkoutProvenance and checkoutPreparation from base, conditionally like failureKind, so the deny gate still applies first. A projection test pins that both fields appear on the status frame when present and are absent otherwise.

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions