API & Dashboard — Domain Plan

Audience: the project maintainer — technical, time-pressed, wants signal over ritual.

Status: durable domain plan (throughline). Unlike the release-scoped docs/plans/ working notes that follow the distil-then-retire lifecycle, this document is one of the standing domain throughlines meant to persist across releases. It is the index and the "why" for the application/mission-data API and the dashboard/UX surface; the release milestones and epics it references are the "what ships when." Where a release plan and this plan disagree on scope of the domain, this plan is the canonical map; where they disagree on what ships in a given tag, the milestone roadmap and the owning epic win. Keep this plan factual and current; do not let it accrete release-scoped tracking that belongs in an epic.


1. Purpose & scope

Purpose. Give the application/mission-data API and the dashboard a single durable home that states the invariants the surface must hold, groups the domain's lasting sub-areas, and points at the epics and design records that carry the work. Before this plan, this surface had no standalone throughline. This plan makes the throughline explicit and becomes the domain's index. It is a sibling to the Doctrine & Charter Domain Plan, the Packs Extraction Domain Plan, and (until its 2026-09-06 retirement, Convergence #3881) the SaaS & Hosted Sync domain plan.

In scope — the application surface. "API & dashboard" here means the data surface the project's own consumers read mission state from, and the UX that renders it:

  • The application / mission-data API (#645, Epic: Stable Application API Surface) — the stable, versioned surface that exposes mission and work-package state (the status projection reduced from status.events.jsonl — see status-model) to the dashboard and any external application consumer, so consumers bind to a documented data contract, not to internal reducers or on-disk file shapes.
  • The dashboard / UX (#650) — the mission dashboard that renders that data: the WP-lane board, the mission and work-package views, and the localhost daemon surface. Direction (2026-10-01): the CLI-bundled dashboard is deleted first (#5530, operator decision 2026-10-01), ahead of the read API; the Mission Status Read API (#5528), reader re-pointing (#5532) and route rehoming (#5533) continue afterwards as the replacement read path. A replacement UI is built in its own repository and consumes the Mission Status Read API (ADR 2026-10-01-2, Accepted 2026-10-12). Direction (2026-10-12): that read API is the open-core producer surface (internally "Build Kitty") — the stable entry point to ledger and event data the free CLI exposes — and its backend is now GA-gating. The replacement UI and any multiplayer surface are the consumer side ("Multiplayer Mode," Team Kitty), consuming the producer API across its public contract (see §3.1, §6).
  • Terminology fidelity in the UI (#650) — the dashboard renders the Mission canon end to end; the historical Feature-labelled UI drift is retired (see §3.3). This is a drift-elimination goal, not new vocabulary.

Explicit boundary / non-goal (FR-004) — the two things called "API".

This plan owns the application/mission-data API + dashboard. It is NOT the doctrine & charter Python import surface. There are two distinct surfaces the corpus calls an "API," and conflating them is the load-bearing miscategorisation this boundary exists to prevent:

  1. The application/mission-data API — THIS plan (#645). The data surface: mission and WP state, the reduced status projection, consumed by the dashboard and external application consumers over a documented data contract.
  2. The doctrine & charter public import surface — Doctrine & Charter Domain Plan §3.6 ("Stable public API surface for doctrine & charter"), design-spike #3179. A different API: the Python import / single- entry-point surface for the doctrine modules — the runtime → charter → doctrine layering where the runtime reaches doctrine through the charter proxy, never directly (doctrine/__init__.py declares 3 public names while ~79 files reach past it across ~30 submodule paths, with no architectural test pinning the public surface). That is a code-import boundary enforced by a layer test — not a data API consumed by a UI.

The shared-epic subtlety. §3.6 records that #3179 reconciles its epic home to #645 because it is a direct instance of #645's single-entry-point pattern (the #645/#460 service-extraction → typed-contract → architectural-test sequence). #645 is therefore a shared epic with two facets: (a) the application/mission-data API surface + dashboard slice — this plan's — and (b) the doctrine-module Python import surface slice — §3.6's. The seam: the importable Python entry-point for the doctrine modules is §3.6's and is not restated here; the application data contract the dashboard consumes is this plan's and is not restated there. Cross-reference §3.6 when a change touches both — do not duplicate it.

Why a durable domain plan and not a release plan. The surface is governed by standing invariants — an application consumer binds to a documented, versioned data contract, never to internal reducers or file shapes; the dashboard never asserts UI behaviour it cannot prove (frontend can fail silently); and the UI speaks the Mission canon, never re-drifting to a Feature label. Those invariants outlive any one tag; the experience-shaped delivery (deferred to the 4.x line, see §5) churns beneath them.


2. Where API/dashboard planning lives today (honest inventory)

There has been no standalone API/dashboard throughline before this document. The surface was distributed across two surfaces:

  1. Status model architecture — the append-only status.events.jsonl event log and its reduce() projection that any mission-data API must expose. It is the data source of record, not an API/dashboard plan.
  2. The epics themselves — #645 (Epic: Stable Application API Surface) and #650 (dashboard/UX, including the Feature-label drift retirement). Issue-tracker groupings with scope bullets, not written plans. Experience-shaped delivery was deferred to 3.3.x by the 3.2.x milestone roadmap; 3.3.x was retired on 2026-08-23 without shipping. #645 is now on the 4.x Work milestone and #650 in Product backlog (checked 2026-09-30), and the 4.0.0 Milestone Roadmap (Theme 3), as re-anchored 2026-10-12, makes the mission-status API backend GA-gating (the open-core producer surface) and #645 GA-gating as the charter-extraction precondition.

This plan now becomes the domain's index. It ties #645 and #650 together under one set of invariants and surfaces the gaps they leave open (§4), and it draws the boundary with the doctrine-charter public-import surface (§1, §3.6-cross-ref) that shares the word "API" and, now, the #645 epic home.


3. Standing concerns — the durable spine

The domain divides into three lasting sub-areas. Each states the invariant it must hold (the durable "why"), then lists the currently open work (the release-scoped "what," which turns over across versions).

3.1 The application/mission-data API contract

Invariant. External application consumers and the dashboard bind to one documented, versioned data contract for mission and work-package state — never to internal reducers, event-log internals, or on-disk file shapes. The contract exposes the reduced status projection as its stable surface; internal churn behind it is not externally visible.

Design of record. Epic #645 (Stable Application API Surface), whose service-extraction → typed-contract → architectural-test single-entry-point pattern (the #645/#460 precedent) is the shape of the contract; the status model projection as the data source the contract exposes. ADR 2026-10-01-2 (Accepted 2026-10-12) names the contract the Mission Status Read API and frames it as the open-core producer surface, not a hosted Team Kitty surface. It has two granularities: an overview built from meta.json and the event ledger, and a detail view with each WP's authored and resolved state and its assignment. It is read-only and independent of drain. The CLI's own read path is an in-process Python module in the specify_cli layer behind one read seam; the external form is a read-only Java service (services/mission-status-api/) that is to start in-repo as a modular component and be extracted as needed as an open-core surface — never into a Team Kitty repo (direction/target state: the service directory does not exist yet; contracts/mission-status/ and the conformance fixtures already ship and stay canonical beside the Python reducer, ADR Amendment 2026-10-12). The backend is now GA-gating (roadmap, Theme 3).

Open work. Enumerate and version the mission-data contract (the #645 application-data facet — distinct from the #3179 doctrine-import facet §3.6 owns), then pin it with a contract test so a consumer can rely on it across versions. Then fold the existing readers into it (#5532): agent tasks status --json and the orchestrator-api mission-state and list-ready reads (the former dashboard --json reader was deleted with the dashboard, #5530, before this step). Land a gate against bypassing it (ADR D-5).

3.2 The dashboard / UX surface

Invariant. The dashboard renders mission and WP state truthfully and never asserts a UI behaviour it cannot prove — a frontend can fail silently (a caught 404 shows a fallback), so dashboard behaviour is verified by a browser-level regression, not inferred from an API response. The localhost daemon surface stays loopback-only.

Design of record. Epic #650 (dashboard/UX); the browser-level UI regression discipline recorded in the repository guidelines (the WP-modal Playwright guard is the standing example — API responses do not prove the UI works).

Open work. The experience-shaped dashboard delivery deferred beyond 4.0.0 (§5): the WP-lane board, mission/WP views, and their browser-verified regressions. These now land in the replacement UI's own repository, which consumes the read API. In this repository the order changed (operator decision 2026-10-01): src/specify_cli/dashboard/ and spec-kitty dashboard are deleted first (#5530), without a deprecation release; the read API (#5528), reader re-pointing (#5532) and rehoming each former route (#5533) follow as the replacement read path (ADR D-1, D-8). The localhost daemon invariant lapsed with the deletion.

3.3 Terminology fidelity in the UI (retiring the Feature drift)

Invariant. The dashboard speaks the Mission canon end to end. The historical Feature-labelled UI drift — a legacy label that leaked into the dashboard against the Terminology Canon — is retired, and the UI never re-introduces a Feature label for a Mission-domain object.

Design of record. Epic #650 carries this as an explicit goal: kill the legacy Feature-labelled UI drift in favour of the Mission canon. The Terminology Canon (Mission, never "feature") is the standard the retirement restores; here it is a reviewer-verified fidelity concern, since the terminology guard does not scan the UI label surface.

Open work. Complete the #650 label-retirement sweep so no dashboard view renders the legacy Feature label, and keep it retired as the dashboard delivery lands in the 4.x line.


4. Known gaps

  1. The #645 two-facet split is unreconciled in the tracker. #645 now hosts both the application-data API facet (this plan, §3.1) and the doctrine-module import surface facet (doctrine-charter §3.6, #3179 reparented under #645). Without a facet split in the epic, a PO cannot tell which slice is the data contract and which is the Python import surface. §1's boundary statement is the reconciling map; the tracker should mirror it.
  2. The mission-data contract is unenumerated. The §3.1 invariant asserts a versioned data contract, but no contract or contract test exists yet — the dashboard binds to the projection directly today. This is the domain's key structural gap, gated behind #645. The orchestrator-api reads use the wall-clock reducer, reduce(). The dashboard uses the Lamport reducer, materialize_snapshot(). So two read surfaces can disagree today.
  3. Dashboard delivery is deferred, its invariants are not. The experience-shaped delivery is a post-4.0.0 concern (§5), but the invariants (contract-bound consumers, browser-proven UI, Mission-canon labels) are in force now and must not regress as the surface is built.
  4. Artifact and governance views have no home outside the dashboard. The dashboard also serves mission artifacts (research, contracts, checklists, dossier) and governance views (charter, lint, glossary). They are not mission status. The dashboard is now deleted first (#5530), so these views have no read surface until each is rehomed in its own context (#5533; #954, #955 and a follow-up), as the ADR's route table lists.

5. Release-scoped view (the "what ships when")

This plan tracks the why (the API/dashboard invariants and sub-areas); the epics track the what-ships-when. The table below is a snapshot for orientation, not a schedule. Verify live state via gh issue view <n> --repo spec-kitty/spec-kitty before acting.

Work Sub-area (§3) Owning epic Milestone (epic, checked 2026-09-30)
Enumerate + version the mission-data API contract Data API contract (3.1) #645 (application-data facet) 4.x Work
Mission Status Read API (overview + detail) and folding the existing readers into it Data API contract (3.1) #645 (#956, #957, #2789) 4.x Work
Remove the CLI-bundled dashboard (deleted first; read API, re-pointing and rehoming follow) Dashboard/UX (3.2) #645 / #650 (#5530; then #5528, #5532, #5533) 4.x Work
Dashboard WP-lane board + mission/WP views Dashboard/UX (3.2) #650 Product backlog
Retire the legacy Feature-labelled UI drift Terminology fidelity (3.3) #650 Product backlog

Read the WHY in §3; the epic tracks the WHAT-ships-when. The Feature-label row is the drift being killed — not a live UI label.


6. Cross-references

Sibling domain throughlines (the durable spine of docs/plans/):

  • Doctrine & charter — Doctrine & Charter Domain Plan. Its §3.6 (Stable public API surface for doctrine & charter) is the non-goal boundary for this plan (§1): §3.6 owns the doctrine/charter Python import / single- entry-point surface (#3179), a different API from this plan's application/mission- data surface — even though #3179 now shares the #645 epic home as a separate facet. (At this plan's commit the doctrine-charter plan still lives at docs/plans/doctrine-charter-domain-plan.md; the domains/ migration WP moves it and repoints these links.)
  • Packs extraction — Packs Extraction Domain Plan.
  • SaaS & hosted sync — domain plan retired 2026-09-06 (Convergence #3881). The former in-process sync projection no longer exists: hosted/team rendering is server-side in the authoritative upstream repos, and this repo's dashboard data surface is consumed locally, with hosted status delivered via zeitgeist_client (ephemeral by design). See the convergence-retirement ADR.

Design of record:

  • Status model architecture — the status.events.jsonl event log and reduce() projection the mission-data API exposes.
  • ADR 2026-10-01-2 — the Mission Status Read API and the removal of the CLI-bundled dashboard (Accepted 2026-10-12: the open-core producer surface; the service is to start in-repo and be extracted when frozen).
  • 4.0.0 Milestone Roadmap — the active cycle; Theme 3 makes the mission-status API backend GA-gating (2026-10-12 re-anchor).
  • 3.2.x milestone roadmap — superseded, prior cycle. Recorded the original deferral of experience-shaped (UX/dashboard) work to the retired 3.3.x milestone.

Epics: #645 (Stable Application API Surface — application-data facet here; the #3179 doctrine-import facet is doctrine-charter §3.6), #650 (dashboard/UX + Feature-drift retirement).

Plans index: docs/plans/index.md.