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.
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-in2026-07-09 04:13:02 +00:00
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
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 theRunwayBarband across a shared horizon, tone/note from due-vs-p80. Milestones with no open scope (shipped) are omitted; empty → the demo fixture.RunwayScreentakes optionalmilestones; AppShell feedsrunwayView. (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
capacity/members.yaml).Verified
Desktop typecheck clean · 14 fixture e2e green · live spec asserts the real milestone names on Runway.
🤖 Generated with Claude Code
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>feat: real Runway — per-milestone Monte Carlo forecaststo feat: Runway complete — per-milestone forecasts + real milestone drill-in