The canary probe (tools/simulation/ui/specs-canary/canary.spec.ts) asserts against SPA markup that two merged PRs replaced. Two of its four screens can no longer pass, and nothing noticed because the probe is workflow_dispatch-only — the pull_request run of e2e-smoke.yml skips the canary step.
Evidence: run 34787979138, on the same head SHA (eabae19) whose pull_request run was green.
1. dashboard — the populated-rows assertion is structurally unsatisfiable.
Error: dashboard rendered its table with no rows against a populated fixture
Locator: locator('.capture-tile').first().locator('tbody tr')
Expected: not 0
Received: 0
Timeout: 60000ms
SCREENS[0].ready is .capture-tile, and line 154 asserts ready.locator("tbody tr") is non-empty. Since the dashboard rework (396ba23, #654) a .capture-tile is a <Link> holding three <div>s, and the dashboard has no <table> on it at all — tiles, a trend chart, a stock <ul> and a sales <ul>. That commit re-pointed ready at the new markup and left the row assertion behind, so the count is always 0.
2. history — the flock filter is no longer a <select>.
Error: no <option> containing "Sim House A" — the list did not load, or the label format changed
Locator: getByLabel('Flock').locator('option').filter({ hasText: 'Sim House A' })
Expected: 1
Received: 0
canary.spec.ts:120 calls selectOptionContaining, which needs <select><option>. Since 60d2053 (#642, searchable entity pickers) HistoryPage.tsx renders a FlockPicker, so there are no <option> elements. specs/manager.spec.ts:129 already drives this same control correctly through commitNamedPicker.
The backend was healthy throughout: every request in the canary window returned 200 (/api/v1/flocks, /daily-entries, /stock, /reports/*), and the stock and reports screens passed. The 60s waits are timeouts on locators that resolve to zero elements.
Scope
- Give each screen its own populated-rows locator instead of the hardcoded
ready.locator("tbody tr"); the dashboard's rows are its capture tiles.
- Drive the history flock filter through
commitNamedPicker.
- Verify by running
bash tools/simulation/ui/run-canary.sh against a seeded sim stack.
The drift itself is the deeper finding: the canary is dispatch-only, so a markup change that breaks it produces a green PR and a probe nobody can trust when they next reach for it.
The canary probe (
tools/simulation/ui/specs-canary/canary.spec.ts) asserts against SPA markup that two merged PRs replaced. Two of its four screens can no longer pass, and nothing noticed because the probe isworkflow_dispatch-only — thepull_requestrun ofe2e-smoke.ymlskips the canary step.Evidence: run 34787979138, on the same head SHA (
eabae19) whosepull_requestrun was green.1. dashboard — the populated-rows assertion is structurally unsatisfiable.
SCREENS[0].readyis.capture-tile, and line 154 assertsready.locator("tbody tr")is non-empty. Since the dashboard rework (396ba23, #654) a.capture-tileis a<Link>holding three<div>s, and the dashboard has no<table>on it at all — tiles, a trend chart, a stock<ul>and a sales<ul>. That commit re-pointedreadyat the new markup and left the row assertion behind, so the count is always 0.2. history — the flock filter is no longer a
<select>.canary.spec.ts:120callsselectOptionContaining, which needs<select><option>. Since 60d2053 (#642, searchable entity pickers)HistoryPage.tsxrenders aFlockPicker, so there are no<option>elements.specs/manager.spec.ts:129already drives this same control correctly throughcommitNamedPicker.The backend was healthy throughout: every request in the canary window returned 200 (
/api/v1/flocks,/daily-entries,/stock,/reports/*), and the stock and reports screens passed. The 60s waits are timeouts on locators that resolve to zero elements.Scope
ready.locator("tbody tr"); the dashboard's rows are its capture tiles.commitNamedPicker.bash tools/simulation/ui/run-canary.shagainst a seeded sim stack.The drift itself is the deeper finding: the canary is dispatch-only, so a markup change that breaks it produces a green PR and a probe nobody can trust when they next reach for it.