Replace the demo cone on Morning service with a real, seeded Monte Carlo forecast over the open backlog. The LLM never does this — it's plain, reproducible code (evidence-based scheduling). core (@commitea/core/forecast-v0): - Code-resident lognormal cold-start priors per estimate bucket (D3): sampled actual = estimate * exp(N(mu, sigma)), mu > 0 (actuals run long), sigma shrinks as tickets grow. Replaced by the team's empirical fit at n >= 20 (#5 supplies the actuals). - forecast(): seeded mulberry32 + Box-Muller over the scheduler's deterministic order (order is fixed from estimates/deps; only durations vary, so the cone stretches, never reorders). Returns p50/p80/p95 landing + a per-issue burn-up curve (p10/p50/p90). 12 unit tests; reproducible. renderer: - lib/dates.ts: working-day -> calendar mapper (skips weekends) + buildBurnUpData. - BurnUpCone gains a data-driven twin; falls back byte-identical to the fixture cone when no forecast (demo mode unchanged). - Focus card shows the real "80% of the open backlog lands by <range>", real scope count, and names the cold-start priors. v0 scope (each a later slice): single serial worker (capacity is #8); cold-start priors only (empirical fit is #5); no historical actual polyline (needs lifecycle events, #5). Header chrome (reconcile time, ahead/behind badge) stays fixture until milestone due dates land. Verified: 51 core tests green, desktop typecheck clean, 14 fixture e2e green, live spec asserts the real cone renders (25 open issues, "lands by Nov 11-27"). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
36 lines
1.9 KiB
TypeScript
36 lines
1.9 KiB
TypeScript
import { dirname, join } from 'node:path'
|
|
import { fileURLToPath } from 'node:url'
|
|
|
|
import { _electron as electron, expect, test } from '@playwright/test'
|
|
|
|
const here = dirname(fileURLToPath(import.meta.url))
|
|
const MAIN = join(here, '..', 'out', 'main', 'index.js')
|
|
|
|
// Opt-in only (GITEA_LIVE=1). Launches WITHOUT COMMITEA_E2E so the main process
|
|
// reconciles the real repo via .env.local, and asserts real data renders.
|
|
test.describe('live backlog', () => {
|
|
test('The pot + Focus render real gitea data', async () => {
|
|
test.skip(!process.env.GITEA_LIVE, 'GITEA_LIVE not set — opt-in live test')
|
|
const app = await electron.launch({ args: [MAIN], env: { ...process.env } })
|
|
const win = await app.firstWindow()
|
|
await win.waitForLoadState('domcontentloaded')
|
|
const rail = win.getByRole('navigation', { name: 'Primary' })
|
|
|
|
// The pot — waiting here also lets the reconcile (issues + deps) complete
|
|
await rail.getByRole('button', { name: 'The pot' }).click()
|
|
await expect(win.getByText('Gitea read client behind an injected fetch')).toBeVisible({ timeout: 20000 })
|
|
await win.screenshot({ path: join(here, '.artifacts', 'screens', 'live-board.png'), fullPage: true, animations: 'disabled' })
|
|
|
|
// Back to Focus — the deterministic scheduler's real Now/Next/Later. These
|
|
// rationale phrases are emitted only by the scheduler, never by the demo fixture.
|
|
await rail.getByRole('button', { name: 'Morning service' }).click()
|
|
await expect(win.getByText(/on the critical path|unblocks #|waits on #|· ready/).first()).toBeVisible()
|
|
// Real Monte Carlo cone — this headline is emitted only for real forecasts.
|
|
await expect(win.getByText(/80% of the open backlog lands by/)).toBeVisible()
|
|
await expect(win.getByText(/Cold-start priors/)).toBeVisible()
|
|
await win.screenshot({ path: join(here, '.artifacts', 'screens', 'live-focus.png'), fullPage: true, animations: 'disabled' })
|
|
|
|
await app.close()
|
|
})
|
|
})
|