feat: Runway complete — per-milestone forecasts + real milestone drill-in #48

Merged
christian merged 2 commits from feat/runway-real into main 2026-07-09 04:43:46 +00:00
Owner

The Runway milestone list is now real — the last big fixture screen. Each open gitea milestone's open scope gets its own Monte Carlo forecast (reusing the P2 engine); the p80 landing range shows, and is compared to the due date (on track / at risk) when one exists. Ranges, never point dates.

Change

  • backlog.ts: runwayView(issues, milestones, deps)RunwayMilestone[] — per milestone: forecast its open scope, map p50..p90 to a date range, normalize the RunwayBar band across a shared horizon, tone/note from due-vs-p80. Milestones with no open scope (shipped) are omitted; empty → the demo fixture.
  • RunwayScreen takes optional milestones; AppShell feeds runwayView. (The header's calibration note was already real, #1.)

Live result

P1/P2/P4/P5 each with a real forecast — e.g. "P2 — Scheduler + Monte Carlo · 80% Aug 14–25 · 32d of work". The fixture lists Beta/Pilot-ready/v1.0, so the real milestone names prove it (screenshot in run).

Scope / honest edges

  • Each milestone forecasts its remaining work from today, independently — they aren't sequenced relative to each other yet, so a smaller later phase can show an earlier date. Cross-milestone sequencing is a refinement.
  • Capacity stays fixture — true per-person capacity (focus factor, allocation) is #8, config-driven (capacity/members.yaml).
  • The Milestone drill-in detail screen is still fixture; wiring it to the clicked milestone's real scope/cone is a follow-up.

Verified

Desktop typecheck clean · 14 fixture e2e green · live spec asserts the real milestone names on Runway.

🤖 Generated with Claude Code

The Runway milestone list is now **real** — the last big fixture screen. Each open gitea milestone's open scope gets its own Monte Carlo forecast (reusing the P2 engine); the p80 landing range shows, and is compared to the due date (on track / at risk) when one exists. Ranges, never point dates. ## Change - `backlog.ts`: **`runwayView(issues, milestones, deps)`** → `RunwayMilestone[]` — per milestone: forecast its open scope, map p50..p90 to a date range, normalize the `RunwayBar` band across a shared horizon, tone/note from due-vs-p80. Milestones with no open scope (shipped) are omitted; empty → the demo fixture. - `RunwayScreen` takes optional `milestones`; AppShell feeds `runwayView`. (The header's calibration note was already real, #1.) ## Live result P1/P2/P4/P5 each with a real forecast — e.g. *"P2 — Scheduler + Monte Carlo · 80% Aug 14–25 · 32d of work"*. The fixture lists Beta/Pilot-ready/v1.0, so the real milestone names prove it (screenshot in run). ## Scope / honest edges - Each milestone forecasts its remaining work **from today, independently** — they aren't sequenced relative to each other yet, so a smaller later phase can show an earlier date. Cross-milestone sequencing is a refinement. - **Capacity stays fixture** — true per-person capacity (focus factor, allocation) is **#8**, config-driven (`capacity/members.yaml`). - The **Milestone drill-in** detail screen is still fixture; wiring it to the clicked milestone's real scope/cone is a follow-up. ## Verified Desktop typecheck clean · 14 fixture e2e green · live spec asserts the real milestone names on Runway. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
christian added 1 commit 2026-07-09 04:00:19 +00:00
The Runway milestone list is now real. Each open gitea milestone's open scope gets
its own Monte Carlo forecast (reusing the P2 engine); the p80 landing range is
shown, and compared to the milestone's due date (on track / at risk) when one
exists. Ranges, never point dates.

- backlog.ts: runwayView(issues, milestones, deps) → RunwayMilestone[] — per
  milestone: forecast its open scope, map p50..p90 to a date range, normalize the
  RunwayBar band across a shared horizon, tone/ note from due-vs-p80. Milestones
  with no open scope (shipped) are omitted; empty → the demo fixture.
- RunwayScreen takes optional `milestones`; AppShell feeds runwayView. The header's
  calibration note was already real (#1).

Scope: each milestone forecasts its remaining work *from today* independently —
they aren't scheduled relative to each other yet (so a smaller later phase can
show an earlier date). Cross-milestone sequencing is a refinement. Capacity stays
fixture — true per-person capacity (focus factor, allocation) is #8, config-driven.

Verified: desktop typecheck clean, 14 fixture e2e green. Live: Runway shows the
real P1/P2/P4/P5 milestones with per-milestone forecasts (e.g. "P2 — Scheduler +
Monte Carlo · 80% Aug 14–25 · 32d of work"); the fixture lists Beta/Pilot/v1.0,
so the real names prove it (new assertion + screenshot).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
christian added 1 commit 2026-07-09 04:12:13 +00:00
Clicking a milestone on Runway now opens its real detail: scope + done %, a Monte
Carlo cone over the remaining open work, and the milestone's issues grouped by
lifecycle column. Threaded the gitea milestone id through the Runway row → AppShell
→ a milestoneView().

- backlog.ts: milestoneView(id, ...) → { name, due, scope/done, forecast cone +
  range, groups by lifecycle column }. Reuses forecast + buildBurnUpData + lifecycle
  inference. null for an unknown id → the screen shows the demo fixture.
- RunwayMilestone gains an `id`; runwayView sets it; RunwayScreen.onOpenMilestone(id).
- MilestoneScreen takes optional `data`; renders real header/stats/cone/issue-groups
  when present, fixture otherwise.

Verified: desktop typecheck clean, 14 fixture e2e green. Live: clicking "P2 —
Scheduler + Monte Carlo" opens a real detail — 7 issues · est 20d, 0/7 done, cone
"80% Aug 17–26", issues in Triage/In-review from the real event stream (screenshot).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
christian changed title from feat: real Runway — per-milestone Monte Carlo forecasts to feat: Runway complete — per-milestone forecasts + real milestone drill-in 2026-07-09 04:13:02 +00:00
christian merged commit 69106b603d into main 2026-07-09 04:43:46 +00:00
Sign in to join this conversation.
No description provided.