Fixes the case where the H1 chip, the pipeline stepper and the manual-changer
dropdown disagreed (e.g. 1043-02-26 on analyst_verified): the status sat between
the canonical 10 and a legacy bucket, so each surface read a different list.
Root fix — ONE authoritative status model + canonicalize the real intermediate
states (chair-approved):
- New mcp-server/.../case_status_model.py — the single registry: ordered
StatusDef list (key/label/description/phase/selectable/terminal/on_enter),
the 5 phases, STATUS_ORDER, phase_of/label_of, and a drift assertion that the
CaseStatus enum matches it. `on_enter` is the seam for a status to *do*
something on entry, declared next to its definition (no dispatcher wired yet).
- models.CaseStatus enum: analyst_verified + research_complete promoted to
first-class canonical statuses (the agents set them — they belong in the
model, not a legacy fallback).
- tools/cases.py: the forward-only STATUS_ORDER guard now derives from the
registry instead of an inline list.
- GET /api/status-model exposes the model so the frontend mirror can be
generated against it.
- web-ui case-status.ts mirrors it: the two intermediates moved from the
legacy map into CASE_STATUSES / PHASES(thinking) / STATUS_LABELS /
STATUS_DESCRIPTIONS; status-badge icons+tones extended. So the chip (status),
stepper (its phase) and dropdown (now includes it) all agree.
Invariants: G2 — collapses the scattered status definitions (enum, inline
STATUS_ORDER, two frontend label maps) onto one backend authority + a documented
frontend mirror; no parallel status list remains. Agent-prompt alignment +
backfill follow in a separate change. py_compile + tsc + eslint clean.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
A case parked on a status the trimmed PHASES list dropped — but the agents
still set, e.g. `analyst_verified` (HEARTBEAT.md), `research_complete`
(legal-researcher) — rendered with NO active phase: phaseIndexOf returned -1,
so the pipeline stepper went fully blank and the chair couldn't see where the
case stood (reported on 1043-02-26, currently at analyst_verified).
Add LEGACY_STATUS_PHASE in case-status.ts mapping each legacy/intermediate
status to its display phase (analyst_verified/research_complete → "ניתוח וכיוון"),
and a single phaseIndexOf() exported from the SSoT. status-hero.tsx and
workflow-timeline.tsx both dropped their identical local phaseIndexOf (which had
the bug) and import the shared one — no parallel path (G2).
Display-only data-mapping fix; the stepper design is unchanged. Does NOT address
the root drift (agents still set analyst_verified) — that prompt-alignment is a
separate, carefully-sequenced follow-up needing cross-company agent sync.
Invariants: G2 (single phase-resolution path, legacy handled in the SSoT, no
new parallel logic). No backend / status-model change.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
qa_passed was set by the old agent pipeline but not included in the
trimmed 10-status CASE_STATUSES list or LEGACY_STATUS_LABELS, causing
the status badge and workflow timeline to render nothing ("לא ידוע").
Added qa_passed → "טיוטה" to LEGACY_STATUS_LABELS as a display-only
fallback so any case still carrying this value renders correctly until
migrated. Case 8174-12-24 status updated to drafted via PUT /api/cases.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>