2026-05-10 — Phase-aware governance UI (TASKSET 3)
status: published
mr: MR-7, MR-10
Context
Section titled “Context”The petrova.host dashboard previously showed governance signals (CI, needs-human, audit) but had no way to visualise the phase progression of each consumer repo across the fleet. The only phase surface was the flat “Recent transitions” table on the repo detail page, which lacked structure and required manual interpretation.
TASKSET 3 closes this gap as the third step in the governance-completeness plan (after TASKSET 1: derived needs-human/ci-status signals and TASKSET 2: full MR audit coverage).
Decision
Section titled “Decision”Ship a petrova.phases.list MCP tool backed by a new PhasesSource that aggregates two existing data stores:
state/<slug>.yaml—current_phase+gate_open(real-time sweeper output)state/transitions/<slug>.jsonl— historical phase events (written newest-first bypetrova sweep-state)
The tool returns a PhasesFleet shape: per-repo PhaseEntry[] each containing a sorted PhaseRecord[], plus the union of all phase numbers seen across the fleet.
The dashboard surfaces this via two new/extended views:
/console/phases— fleet × phase grid. Rows = repos, columns = all phase numbers seen fleet-wide. Each cell shows ✓ (closed, links to decision doc), ◆ (open), or · (not started). A “current” column and a gate indicator sit beside the slug./console/repo/[slug]— “Phase timeline” block replaces the flat transitions table. Phases shown newest-first (highest number first) with status badge, closed/opened date, and a clickable decision-doc link when the URL can be constructed from{repo_url}/blob/main/docs/decisions/{at}-{note}.md.
“phases” is added as a nav entry in Shell.astro between “acts” and “governance”.
Alternatives considered
Section titled “Alternatives considered”- Re-using transitions.recent directly in the dashboard — discarded because the raw JSONL order is newest-first and non-sequential (kahn-hq has Phase-11 before Phase-8), making it unsuitable for a grid without server-side aggregation.
- Adding a
phasesfield to state YAML via the sweeper — would add sweep latency and require a schema bump and a sweeper code path. The source data already exists in the transitions JSONL; aggregating at query time is cheaper and keeps the sweeper focused on ephemeral signals.
Consequences
Section titled “Consequences”- positive: operators can see at a glance which repos are lagging behind on phase closure; decision doc links are one click away from the grid.
- positive: the
petrova.phases.listtool is available to MCP consumers (e.g. Claude Code) for phase-aware automation. - neutral:
PhasesSourceis not cached; fleet-wide queries scan all transition files on each request. Acceptable for the current fleet size (<10 repos); a cache layer can be added in a later taskset if needed. - constraint: decision-doc URLs are constructed heuristically from
{at}-{note}.md; if a doc was committed under a different filename the link will 404. This is the same pattern used by the existing transitions tool.
References
Section titled “References”- TASKSET 1 decision:
2026-05-10-derived-needs-human-and-ci-status.md - TASKSET 2 decision:
2026-05-10-governance-audit-completeness.md host/src/sources/phases.ts(new)host/src/tools/phases.ts(new)dashboard/src/pages/console/phases.astro(new)