fix(web,harness): the demo's second view was the phantom improvise-m4rv removed

CROSSES TWO BOUNDARIES OUTSIDE THIS AGENT'S GROUND, deliberately and reported:
web/demo.improv and harness/tests/contract.spec.js. Dropping the invented
Default view takes the shipped demo from two views to one, and the spec
asserted the phantom in two places -- improvise-m4rv's acceptance criteria
name the spec directly.

The load-bearing half is the improvise-iioi click test, which needs the view
panel to hold two rows so that a click can name a DIFFERENT row than the
cursor does; with one view both readings give the same answer and the test
stops discriminating. The phantom was supplying that second row by accident.

So the demo gains a real second view, Season -- a genuine alternate pivot
(Quarter by measure, paged by Product) rather than an auto-arrangement. Plan
stays first and stays Initial View, so the cursor still starts at index 0 and
tests/web_demo_model.rs is unaffected: every visible cell of the ACTIVE view
is still a Record (gotcha 46). Verified by cargo.

The spec's axis assertion at index 0 moves from the phantom's "R:Product
C:Quarter" to Plan's own "R:Product P:Quarter", derived from
viewmodel::view_axis_summary rather than guessed.

NOT VERIFIED: harness/ has no node_modules and web/pkg is unbuilt here, so
Playwright could not be run. These edits are mechanical substitutions and
need a browser-job run before they are believed.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FC2jVn8Au7E9JPkw6bwXXH
This commit is contained in:
Edward Langley
2026-09-21 14:46:24 -07:00
parent c84707261c
commit 72b77566c5
2 changed files with 20 additions and 12 deletions
+12 -12
View File
@@ -73,7 +73,7 @@ test.describe("every field the render model projects reaches the screen", () =>
// The axis line is the shared `view_axis_summary`; its absence would mean // The axis line is the shared `view_axis_summary`; its absence would mean
// a second derivation had crept in. // a second derivation had crept in.
await expect(page.locator("#views li").nth(0).locator(".axes")).toHaveText( await expect(page.locator("#views li").nth(0).locator(".axes")).toHaveText(
"R:Product C:Quarter", "R:Product P:Quarter",
); );
await page.keyboard.press("Escape"); await page.keyboard.press("Escape");
@@ -196,21 +196,21 @@ test.describe("a pointer event reaches the client and its answer is painted", ()
// A view row (improvise-iioi). The activation must read the CLICKED index, // A view row (improvise-iioi). The activation must read the CLICKED index,
// not `view_panel_cursor` — so the cursor must not already be on the row // not `view_panel_cursor` — so the cursor must not already be on the row
// clicked, or both readings give the same answer. `Default` is index 0 and // clicked, or both readings give the same answer. `Plan` is index 0 and
// holds the cursor by default, so move to it and click `Plan`. // holds the cursor by default, so move to it and click `Season`.
await page.keyboard.press("Shift+V"); await page.keyboard.press("Shift+V");
await expect(page.locator("#views li.selected")).toContainText("Default"); await expect(page.locator("#views li.selected")).toContainText("Plan");
// Switch to Default by KEYBOARD, leaving the cursor on it. The click then // Switch to Plan by KEYBOARD, leaving the cursor on it. The click then
// names a different row than the cursor does, which is the whole point. // names a different row than the cursor does, which is the whole point.
await page.keyboard.press("Enter"); await page.keyboard.press("Enter");
await expect(page.locator("#view-name")).toHaveText("Default");
const plan = page.locator("#views li").filter({ hasText: "Plan" }).first();
await plan.click();
// Reading the cursor instead of the index re-selects Default and fails.
await expect(page.locator("#view-name")).toHaveText("Plan"); await expect(page.locator("#view-name")).toHaveText("Plan");
await expect(page.locator("#views li.active")).toContainText("Plan");
await expect(page.locator("#views li.selected")).toContainText("Plan"); const season = page.locator("#views li").filter({ hasText: "Season" }).first();
await season.click();
// Reading the cursor instead of the index re-selects Plan and fails.
await expect(page.locator("#view-name")).toHaveText("Season");
await expect(page.locator("#views li.active")).toContainText("Season");
await expect(page.locator("#views li.selected")).toContainText("Season");
// A formula row: navigation only, because FormulaPanel binds no Enter and // A formula row: navigation only, because FormulaPanel binds no Enter and
// a click mirrors Enter. The Rust guard is on the KEYMAP — clients.md. // a click mirrors Enter. The Rust guard is on the KEYMAP — clients.md.
+8
View File
@@ -10,6 +10,14 @@ _Index: none
_Dim: none _Dim: none
format: ,.0 format: ,.0
## View: Season
Quarter: row
_Measure: column
Product: page, Latte
_Index: none
_Dim: none
format: ,.0
## Formulas ## Formulas
- Profit = Revenue - Cost - Profit = Revenue - Cost