refactor(model): name Feature status by domain, not RAG color

StatusLevel held green/orange/red — the RAG vocabulary CONTEXT.md
explicitly lists under _Avoid_ for the Status term, leaking a
presentation concern into the model and authored TOML. Replace with
on-track/at-risk/off-track; color now lives only in the renderer's
tone() mapping. Breaking change to authored .toml status values.
This commit is contained in:
Julien Calixte
2026-06-18 18:13:53 +02:00
parent 64efc91392
commit 40ee9f509c
6 changed files with 14 additions and 20 deletions

View File

@@ -58,20 +58,14 @@ const gridStyle = computed(() => ({
function tone(row: FeatureRow): Tone {
if (row.delivered) return row.onTime ? 'success' : 'error'
if (row.status === 'green') return 'success'
if (row.status === 'orange') return 'warning'
if (row.status === 'red') return 'error'
if (row.status === 'on-track') return 'success'
if (row.status === 'at-risk') return 'warning'
if (row.status === 'off-track') return 'error'
return 'neutral'
}
function statusWord(row: FeatureRow): string {
return row.status === 'green'
? 'on track'
: row.status === 'orange'
? 'at risk'
: row.status === 'red'
? 'blocked'
: 'in flight'
return row.status ? row.status.replace('-', ' ') : 'in flight'
}
function markerAt(row: FeatureRow, w: WeekId): MarkerKind | null {

View File

@@ -1,5 +1,5 @@
// Default Macroplan shown on first load — exercises every state:
// on-time delivery, late delivery with slips, in-flight (green/orange/red),
// on-time delivery, late delivery with slips, in-flight (on-track/at-risk/off-track),
// an overdue Feature, and a Milestone with unmet required Features.
export const SAMPLE_PLAN = `title = "Q3 — Checkout revamp"
@@ -32,7 +32,7 @@ learning = "Vendor lead time was the real constraint — derisk vendors up front
name = "Dashboard"
start = 2026-06-01
original = 2026-06-08 # already past 'now' and undelivered → overdue
status = "red"
status = "off-track"
note = "No recovery plan yet — needs an owner."
[[feature]]
@@ -40,14 +40,14 @@ name = "Search"
start = 2026-06-08
original = 2026-06-22
reestimates = [2026-07-06] # re-estimated once, still in flight → △
status = "orange"
status = "at-risk"
note = "Third-party search API is flaky; spike a fallback."
[[feature]]
name = "Notifications"
start = 2026-06-22
original = 2026-07-06
status = "green"
status = "on-track"
[[milestone]]
name = "Code freeze"

View File

@@ -11,7 +11,7 @@ export class PlanParseError extends Error {
}
}
const STATUSES = ['green', 'orange', 'red'] as const satisfies readonly StatusLevel[]
const STATUSES = ['on-track', 'at-risk', 'off-track'] as const satisfies readonly StatusLevel[]
// ── Field schemas ──────────────────────────────────────────────────────────
// A TOML date (smol-toml returns a Date subclass) or a yyyy-mm-dd string,

View File

@@ -76,10 +76,10 @@ describe('F2 — on-time / late classification (ADR-0001)', () => {
})
it('in-flight (undelivered) → ◯ only, onTime null, bar ends at the furthest estimate', () => {
const r = rowOf(base('reestimates = [2026-06-29]\nstatus = "red"'), 'X')
const r = rowOf(base('reestimates = [2026-06-29]\nstatus = "off-track"'), 'X')
expect(r.onTime).toBeNull()
expect(r.delivered).toBe(false)
expect(r.status).toBe('red')
expect(r.status).toBe('off-track')
expect(r.barEndWeek).toBe('2026-06-29') // furthest open estimate
expect(r.markers.some((m) => m.kind === 'original')).toBe(true)
})
@@ -91,7 +91,7 @@ describe('bar extent relative to now', () => {
it('extends an overdue undelivered bar to the now week, keeping ◯ at the estimate', () => {
// original 2026-06-08 is before now (week of 2026-06-15) and undelivered → overdue
const r = rowOf(feat('status = "red"'), 'X')
const r = rowOf(feat('status = "off-track"'), 'X')
expect(r.delivered).toBe(false)
expect(r.barEndWeek).toBe('2026-06-15') // runs up to now, past the 06-08 estimate
expect(r.markers.find((m) => m.kind === 'original')?.week).toBe('2026-06-08')

View File

@@ -1,6 +1,6 @@
import type { WeekId } from './week'
export type StatusLevel = 'green' | 'orange' | 'red'
export type StatusLevel = 'on-track' | 'at-risk' | 'off-track'
// ── Raw model: as authored, after TOML parse + validation, before derivation ──