# Team delivery / integration state contract

This document records the currently-audited ownership contract for the states
called out in issue #1243.

## Scope

- dispatch lifecycle: `pending`, `notified`, `delivered`, `failed`
- integration lifecycle: `integrated`
- readiness / leader-activity lifecycle: `stale`

## Authoritative owners

### `pending` / `notified` / `delivered` / `failed`

Durable owner:

- Rust runtime dispatch log when the bridge is enabled
  - `crates/rcs-runtime-core/src/dispatch.rs`
  - surfaced through `src/runtime/bridge.ts`
- legacy JSON fallback only when the bridge is disabled or unreadable
  - `src/team/state/dispatch.ts`
  - `src/team/state.ts`

Observed code paths:

- queue: `DispatchLog::queue()` ↔ `enqueueDispatchRequest()`
- notify: `DispatchLog::mark_notified()` ↔ `markDispatchRequestNotified()`
- deliver: `DispatchLog::mark_delivered()` ↔ `markDispatchRequestDelivered()`
- fail: `DispatchLog::mark_failed()` ↔ `markDispatchRequestFailed()` / `transitionDispatchRequest(..., 'failed')`

Transition contract:

- `pending -> notified`
- `pending -> failed`
- `notified -> delivered`
- `notified -> failed`
- same-state reason/timestamp patching is allowed
- `failed -> notified` is **not** allowed for the same `request_id`

Rationale:

- Rust already enforces `failed` as terminal for a dispatch record.
- TS fallback must mirror that contract so hook, fallback, and replay paths do
  not answer the same state question differently.

### `integrated`

Durable owner:

- team monitor integration snapshot written by runtime integration logic
  - `src/team/runtime.ts`
  - `src/team/state.ts`
  - `src/team/state/monitor.ts`

Observed code paths:

- merge/cherry-pick/rebase decisions in `integrateWorkerCommitsIntoLeader()`
- failure path in `recordIntegrationFailure()`

Success contract:

- `integrated` requires durable git evidence:
  - leader HEAD advanced, and
  - integrated worker commit is actually reachable from leader HEAD

### `stale`

Durable owner depends on subject:

- runtime authority staleness:
  - `crates/rcs-runtime-core/src/lib.rs`
  - `crates/rcs-runtime-core/src/engine.rs`
  - surfaced via `src/runtime/bridge.ts`
- leader/session staleness:
  - `src/team/leader-activity.ts`
  - `src/hooks/session.ts`

Contract:

- `stale` is an eligibility / readiness signal, not a success state
- tmux/HUD observations may contribute evidence, but they are not the durable
  semantic owner of dispatch or integration success

## First contract hardening change

When a hook-authored dispatch receipt has already become `failed`, later fallback
confirmation must not mutate that same request back to `notified`.

Instead:

- keep the request `failed`
- patch `last_reason` to record the confirmed fallback path
- treat fallback success as an operational recovery event, not as a rewrite of
  the original hook-attempt state machine
