ganttView ran schedule() — the single-serial-worker layout — while the Monte
Carlo forecast ran scheduleWithCapacity() over the real lanes. So the bars you
saw didn't match what was forecast (serial 1.0/day vs the team's actual lanes).
Switch ganttView to scheduleWithCapacity(open, deps, workers): startDay/endDay
now come from the same lane layout each forecast trial uses, and `who` shows the
lane an issue actually landed on (falling back to assignee, then blank). The
dogfood harness had the same split — updated it to match and to print the lane
per row.
Verified: typecheck clean, 14 fixture e2e green, live-onboarding e2e renders the
real capacity-aware Gantt with no uncaught errors.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
scripts/dogfood-report.ts drives the real @commitea/core engine (schedule +
capacity-aware Monte Carlo forecast + per-milestone runway) against the live
christian/commitea backlog and prints the project report each screen derives.
Read-only; `yarn tsx scripts/dogfood-report.ts`. Adds tsx as a devDependency.
First run surfaced two real gaps the fixtures hid: every open issue was
unassigned (so capacity load-balanced work onto the slow half-time lane and the
standup plan-per-person was empty) and no milestone had a due date (so Runway
couldn't judge on-track/at-risk). Both were fixed as PM actions on the repo via
the write path — all open issues assigned, milestone due dates synthesized from
the forecast — so the app's own numbers are now honest.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Adds shareable desktop packaging so the app can be handed to teammates.
- electron-builder@25 + electron-builder.yml: appId io.stephenmann.commitea,
productName CommiTea, icon from the logo (build/icon.png, 1024²), macOS dmg
targets for arm64 + x64. Ships only out/** (electron-vite already bundles
renderer/preload/main with core + react inlined), npmRebuild off,
electronVersion pinned to 34.5.8 (workspace hoisting defeats auto-detect).
- Unsigned by decision: mac.identity null, hardenedRuntime off. electron-builder
ad-hoc signs so arm64 runs; not notarized — teammates right-click → Open once.
- Scripts: `yarn pack` (--dir sanity build), `yarn dist` (both dmgs). package.json
gains version/author/description (required by electron-builder).
- README.md: dev/build/package commands + the Gatekeeper install step.
Verified: packaged arm64 app boots from a fresh profile (lands on onboarding);
`yarn dist` produced CommiTea-0.1.0-arm64.dmg (98M) and CommiTea-0.1.0.dmg (x64,
102M), each mounting with a drag-to-Applications layout.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Every remaining fixture-only surface now renders reconciled gitea data,
with the fixture kept only as the no-config demo fallback.
- lib/views/project-data.ts: ProjectData — the uniform input (reconciled
backlog + deps + timelines + calibration + workers + today) that AppShell
assembles once and every view builder consumes.
- lib/views/{issue-detail,gantt-view,deps-graph,standup-view,inbox-view}.ts:
pure builders, ProjectData → the fixture-shaped object each screen already
renders. Real signals only; honest degradation where a signal isn't derivable
(buffered p80 vs per-issue Monte Carlo; flat "idle in review"; no fabricated
inbox mentions/outages).
- Screens take an optional `data?` and fall back to the fixture; AppShell wires
the real view whenever the backlog is reconciled. Issue "blocks" chips and the
rail inbox badge now resolve from real data too.
- Dev-only rail surfaces (First run / States / Primitives) gated on
import.meta.env.DEV || demo — shown in dev + e2e, hidden in a packaged app.
Rail host label reflects the connected instance.
- Extended the live onboarding e2e to click Board → Gantt → Deps → Issue
sidecar → Standup → Inbox on real gitea data with a pageerror guard; 14
fixture e2e stay green, typecheck + prod build clean.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>