Skip to content

highway(operator-surface) wave 2: Tier-B browser conformance kit + Core 10 fixes (bounded L1 query, theme persists) + integration - #83

Merged
Brian Krabach (bkrabach) merged 8 commits into
mainfrom
highway/os-wave-2
Sep 5, 2026
Merged

highway(operator-surface) wave 2: Tier-B browser conformance kit + Core 10 fixes (bounded L1 query, theme persists) + integration#83
Brian Krabach (bkrabach) merged 8 commits into
mainfrom
highway/os-wave-2

Conversation

@bkrabach

Copy link
Copy Markdown
Collaborator

Two more lanes of the hw-operator-surface highway plus the integration work their union required.

Lane Item What landed Rows
tier-b-kit qgo tests/conformance/operator_surface/browser/ — real-browser conformance kit: pinned playwright 1.60.0 / chromium 148.0.7778.0, app on an ephemeral loopback port over isolated fixture data, every assertion reads back a JSON artifact (pixel sweeps, computed contrast, bounding boxes, post-swap DOM, motion trace) — never a "looks right" verdict; make playwright-install + make test-conformance-b (opt-in locally) + CI Tier 7; a durable LAST_RUN.json the ledger probes re-read OSV1-028/029 Freeze 2/3 → CONFORMS; 003/008/010 re-derived from measurement (GAP → VIOLATION: L1 paints 97 --blocked px on a calm page; the swap drops the live region; 4 light-mode text pairs fail rendered); 020/022/023 CONFORMS
core10 8vv + dg3 L1 no longer runs an unbounded query on its 20 s poll (LIST_MAX_LIMIT+1 one-past-the-window probe; the view CONFESSES the bound); every adapter read reachable from a GET handler passes an explicit limit; the theme choice persists (localStorage under webtheme.THEME_STORAGE_KEY, applied in <head> before first paint, prefers-color-scheme when nothing stored) OSV1-015/016 VIOLATION → CONFORMS

Integration (orchestrator commits):

  • Both kits pinned each other's absence on the shared rows → Conformance 2 (OSV1-021) and Freeze 4 (OSV1-030) re-derived with BOTH halves present: CONFORMS (Tier-A 22 + Tier-B 8 bad halves all executed; 14/14 fixture arms discriminate).
  • Two Tier-A bad halves (Core 10) had used the SHIPPED defects as their specimens; core10 fixed the defects → replaced with synthetic specimens so they stay discriminating regardless of product state. Same for Conformance 4's contrast bad half (now injects a literal 2.27:1 pair + a 13.96:1 control).
  • LAST_RUN.json re-recorded on the merged tree (3 runs, byte-identical on every asserted field). A suspected "6 animations run under prefers-reduced-motion" turned out to be the kit racing a 120 ms transition it had just triggered — fixed in the kit (poll to quiescence), not filed against the product; OSV1-011 stays CONFORMS with a browser half (0 in all 18 renders).
  • OSV1-031 (Freeze 5) tally: 5 red Core rows (003, 005, 008, 010, 012) — every one now MEASURED, none an unasserted GAP.

Verified on the union: pytest ledger/checks 60 · make ledger-mutate 60/60 · Tier-A 38 passed / 4 xfailed / 0 failed · Tier-B 52 passed / 35 xfailed / 0 failed (×3) · pyright 0 · ruff clean · unit+integration 1325 passed (2 port-pair flakes pass in isolation). OSV1 tally → 23 CONFORMS / 5 VIOLATION / 5 GAP / 3 N-A. The inline-style migration (np3) follows.

🤖 Generated with Amplifier

…dg3)

Two Core 10 anti-goals of contracts/operator-surface.v1.md, closed together
because they are the same promise from two directions: a view must not ask
for an unbounded read, and a view must not hold state that dies on refresh.

OSV1-015 -- the unbounded query (work_item_pipeline-8vv)

  `project_view` called `bd.list(..., limit=0)` -- bd's own "unlimited" --
  on a page that re-renders every 20 seconds, so every open tab
  re-materialised the whole item set three times a minute. It now passes
  `_L1_ITEM_QUERY_LIMIT + 1` (500, the repo's existing `LIST_MAX_LIMIT`
  ceiling, and exactly ten of this view's own pages). The `+ 1` is the
  one-past-the-window probe: it establishes whether more rows exist as a
  fact rather than inferring it from a full window.

  A bound is a truncation, so the view confesses it: `_truncation_note_html`
  renders "Showing 50 of 500+ items - read capped at 500 ..." when the
  ceiling binds, and never dresses a bounded window as a measured total.

  The L2 detail page's `bd.activity(item.id)` inherited its bound from the
  seam's default; it now states it (`limit=A.HISTORY_LIMIT`). Audit of every
  adapter read reachable from a GET handler: 4 calls, all now explicit.

OSV1-016 -- the theme that died on refresh (work_item_pipeline-dg3)

  `wtSetTheme` set an attribute and remembered nothing, so a chosen Light
  came back Dark on the next load. It now persists to `localStorage` under
  `webtheme.THEME_STORAGE_KEY` -- one declaration, shared by the writer and
  the reader -- and `webtheme.theme_boot_js()` resolves it in `<head>`,
  before the body paints, so there is no flash. Stored choice first, then
  `prefers-color-scheme`, then the server's `data-theme="dark"` default,
  which the resolver only ever REPLACES (PR #55 stays fixed).

  Apply and persist are split: `wtApplyTheme` never writes, so the sync call
  that re-derives the toggle's `aria-pressed` after each 20s body swap
  cannot freeze a first visit's OS preference into a choice nobody made.

Tests

  tests/unit/test_view_query_bounds.py -- static audit of every bounded
  adapter read reachable from a GET handler; confirmed red against `limit=0`,
  against a removed `limit=`, and against the inherited-default activity call.
  tests/unit/test_theme_persistence.py -- executes the emitted scripts under
  node against a fake DOM and does the real round trip (load, click Light,
  reload, assert Light); confirmed red against removing either half.
  Plus L1 route tests for the cap and its absence.

Ledger

  OSV1-015 and OSV1-016 flipped VIOLATION -> CONFORMS with evidence, probes
  retargeted from pins to invariants in the same change, mutations inverted
  to the regression direction (+1 new one). `pytest ledger/checks` 60 passed;
  `make ledger-mutate` 54/54 proven.

  Cross-lane, unavoidable, flagged for the integrator: OSV1-031's red-row
  tally 10 -> 8, and the line-anchored specimens in OSV1-005/-006 re-anchored
  where this change shifted them (same specimens, new line numbers).
…rtifact-backed, discriminating (Freeze 2/3/4)

The Tier-B half of `contracts/operator-surface.v1.md` now exists, runs a
pinned chromium against a live app over isolated fixture data, emits JSON
artifacts the tests re-check themselves, and runs as its own CI tier.

WHAT LANDED

  tests/conformance/operator_surface/browser/test_tier_b.py
    the file the contract names by path in Conformance 1-4 and Freeze 2.
    Four checks under their contract names: `calm.zero_alarm_pixels`,
    `state.not_colour_only` (rendered half), `swap.survives`,
    `perception.floors`. 52 pass, 35 xfail(strict) against named ledger rows,
    0 fail; ~105s end to end.
  _png.py      dependency-free PNG decode + colour histogram, so a pixel
               sweep is a number this repo computed
  _probe.py    the in-page JS that measures contrast, target boxes, overflow,
               motion and live regions, plus the pure-Python re-checks
  _artifacts.py  the artifact envelope, and the committed run summary
  conftest.py  app on 127.0.0.1:0 over the inherited isolated dolt server,
               a separate workspace per scenario, pinned chromium

THE RULE THE KIT RUNS UNDER (Freeze 3): measure -> write -> read back ->
assert. No assertion rests on a value that only lived in a local variable,
and none rests on a screenshot. Screenshots are saved as evidence for a
human's Freeze 8 look and nothing reads them.

EVERY FIXTURE DISCRIMINATES (Freeze 4) -- eight bad halves, all RUN:
an injected --alarm chip, the contract's own retired #D9A253 region, a
genuinely-blocked fixture, status chips stripped to a class, a naive
whole-body innerHTML replacement, the same with a forced reflow, a 900px
element at 430px, and the recorded --ink-quiet/--ground pair (with a
dark-mode control, so a probe that always said "below floor" would fail).

WHAT THE BROWSER ACTUALLY FOUND -- chromium 148.0.7778.0 / playwright 1.60.0

  Core 2   a calm L1 paints 97 --blocked pixels with nothing blocked
           (legend swatch, live dot, danger-button border). L0 is clean.
  Core 6   one of four survivals holds. Scroll survives; the open <details>
           does not (no <details> on this surface carries an id, so
           restoreState has zero targets); the pause CONTROL does not; and
           there is no live region to preserve at all.
  Core 7   L0 text contrast clean, L1/L2 not (.status-chip.st-resolved reads
           3.13:1 dark / 2.26:1 light); 26 of 35 interactive controls on L0
           under 44px, including the pause control itself at 26x26; control
           borders and icon strokes below 3:1. Reduced motion PASSES.

TWO CONTRACT WORDINGS MEASURED NON-DISCRIMINATING, recorded not reinterpreted:
Conformance 4's `scrollWidth == clientWidth` cannot fire while html/body carry
`overflow-x: clip` (a 900px element at 430px moves it not at all), so the kit
emits an element-level reading too; and Conformance 3's literal bad half does
not lose the scroll offset on chromium 148, so a reflow variant carries that
half.

LEDGER -- rows re-derived from the emitted numbers, never from a file
appearing. OSV1-003/-008/-010 GAP -> VIOLATION (now measured, not unmeasured);
OSV1-020/-022/-023/-028/-029 GAP -> CONFORMS; OSV1-021 and -030 stay GAP for
their Tier-A halves. Every probe re-reads LAST_RUN.json, the kit's committed
run summary, so the ledger checks browser-produced numbers for itself instead
of trusting the browser tier's green. `pytest ledger/checks -q` 60 passed;
`make ledger-mutate` 56/56 proven.

WIRING: `make playwright-install`, `make test-conformance-b`, and a CI step
"Tier 7 -- operator-surface conformance (Tier B, browser)" that installs
chromium and uploads the artifacts. Deselected everywhere else by
`-m "not tier_b"` in addopts -- deselected, not --ignore'd, so a kit that
stops importing fails the fast tiers loudly.

OUT OF SCOPE, NAMED: `test_row_osv1_027`'s pin (Freeze 1, another lane's row)
was NARROWED, not moved -- it asserted no `tests/conformance` path appears in
the Makefile/CI at all, which the Tier-B wiring now legitimately trips. The
Tier-B path is excluded before the check, leaving its original question
(is Tier-A wiring landing?) intact. Disposition unchanged.
…Tier-B kit

A second full `make test-conformance-b` from a clean artifact directory: 52
passed, 35 xfailed, 0 failed. Every number the ledger asserts on came back
byte-identical -- the calm sweep's 97 --blocked pixels on L1, L0's clean 0/0,
L1's 3-dark/5-light text failures, L0's 26-of-35 undersized controls, both
bad halves' discrimination.

The ONLY drift between the two runs is the `--watch` bucket in light mode
(5402 -> 5239 and friends), which nothing asserts on: Core 2 says only
`--alarm` and `--blocked` carry status meaning, so `--watch` is swept and
recorded for context and deliberately not scored. The drift is antialiasing
against a slightly different sub-pixel layout between runs, and it is exactly
the reason a status-hue sweep is scored on the two reserved hues rather than
on "how much colour is on the page".
…1-006 register re-measured on the merged tree, _mo031 anchor moved off the now-green OSV1-015
…FORMS with both halves landed; Freeze 4 re-derived VIOLATION from a run of the merged tree; harness mutations merged; OSV1-031 re-counted

Six conflicted files resolved as a UNION, never a pick-a-side:

* Makefile -- .PHONY is the union of both target lists; both target blocks
  kept (test-conformance-a in `test`'s reach, playwright-install and
  test-conformance-b deliberately outside it). No duplicate targets.
* tests/conformance/{,operator_surface/}__init__.py -- the Tier-A lane's
  longer docstrings, each folding in one sentence placing Tier B in
  `browser/` as its own `tier_b`-marked tier.
* mutation_harness.py -- both lanes' mutation functions, and the Mutation
  list merged rather than chosen. Every "the OTHER tier's kit file appears"
  pin-direction mutation is spent (both kits exist now) and was replaced by
  the regression- or fix-direction mutation each lane wrote. Two mutations
  were dropped because the direction they push no longer exists on the
  merged probe, each proven dead by the harness itself rather than assumed:
  _mo008_swap_restores_the_pause_flag (the merged OSV1-008 probe reads the
  Tier-B run summary, so the source-shape counterfactual "probe still PASSED
  under the counterfactual") and both _mo_tier_*_kit_appears helpers.
* test_operator_rows.py -- imports keep `ast` AND `json`; OSV1-009 keeps the
  contrast lane's retargeted CONFORMS probe; OSV1-027 keeps the tier-b
  lane's narrowing (the Tier-B path is stripped before the Tier-A wiring is
  checked) turned round to the CONFORMS direction it now needs.
* rows.yaml -- both lanes' dated LANDED paragraphs kept on every row that
  carried one; no pinning-row sentence left on a CONFORMS row.

Rows re-derived, each from evidence rather than from a file appearing:

* OSV1-021 (Conformance 2) GAP -> CONFORMS. The only fixture spanning both
  tiers; each lane pinned the other half's absence and both halves are now
  present. Probe asserts both, in the CONFORMS direction: the Tier-A check
  exists, ships its bad half and is NOT deferred, and the Tier-B hue and
  wordless readings hold. Red again if either half stops holding.
* OSV1-030 (Freeze 4) GAP -> VIOLATION, NOT the CONFORMS this integration
  set out to write. Both kits landed, but `make test-conformance-b` on the
  MERGED tree measures Conformance 4's contrast bad half at 5.36:1 in light
  -- above the 4.5:1 floor -- where the committed run recorded 3.09:1. The
  bad half injects the LIVE `--ink-quiet`/`--ground` pair, and the contrast
  lane closed OSV1-009 in wave 1 by moving that token, so the specimen the
  clause names no longer exists here. Neither lane could see it: each
  measured against a base without the other's change. 13 of the 14 fixture
  arms still demonstrate; this row is red for the fourteenth.
* OSV1-031 (Freeze 5) re-counted: still FIVE red Core-carrying rows, so the
  pin does not move -- but all five now read VIOLATION and none GAP, because
  tier-b-kit re-derived Core 2, 6 and 7's browser halves from a real run.
  Neither OSV1-021 nor OSV1-030 is Core-carrying, so neither moves it.

Verified on this tree: pytest ledger/checks 60 passed; make ledger-mutate
proven 58/58 (15 pinning across 11 pinning probes); ruff clean; pyright 0
errors. Recorded in OSV1-030's notes rather than absorbed: three further
merged-tree movements (reduced motion 0 -> 6 running animations, live
regions 0 -> 1, L0 controls 35 -> 34) that need the Tier-B run re-recorded
by a lane, and two Tier-A bad halves that have failed since 1713b30 because
the core10 lane's fixes removed the shipped code they used as a specimen.
…mance 4; Tier-B run re-recorded on the merged tree; OSV1-003/008/010/011/023/030 re-derived (reduced-motion is a measured settling transient, not a violation)

Three fixtures stopped naming a defect when the wave-2 lanes met, because each
borrowed the SHIPPED code as its bad specimen and the product was fixed under
it. All three now fabricate their own bad input:

  Tier A, Core 10  `unbounded_view_queries` / `unpersisted_view_state` take an
                   optional {module: source} map; the bad halves feed a
                   fabricated view (one `limit=0` read, one with no limit) and
                   a fabricated script module (a theme setter that persists
                   nothing beside a density setter that does), each with a
                   fixed twin as its control. The good halves still assert the
                   real tree.
  Tier B, C4       `INJECT_BELOW_FLOOR_PAIR_JS` injects a LITERAL below-floor
                   pair (#9aa3b2 on #eef2fb, 2.27:1) plus a LITERAL control
                   (#1b2430, 13.96:1), asserted in opposite directions in BOTH
                   themes. It used to inject the live --ink-quiet/--ground
                   tokens and measured 5.36:1 once the contrast lane moved the
                   token.

LAST_RUN.json re-recorded on this tree (chromium 148.0.7778.0 / playwright
1.60.0); three consecutive runs agree on every field the ledger asserts. Rows
re-derived from the new numbers: OSV1-003 (L0 sweep area 2 850 560 -> 2 813 440
px, verdicts unchanged), OSV1-008 (live regions before the swap 0 -> 1 on L0 --
the rebuilt hero's role=status -- and it does NOT survive; L1 still 0),
OSV1-010 (L0 controls 35 -> 34, L1 light text 5 -> 4, non-text 17/82 -> 16/79),
OSV1-023 (contrast arm re-derived onto the literal pair + control),
OSV1-030 (VIOLATION -> CONFORMS: all fourteen fixture arms run and bite).

OSV1-011 stays CONFORMS, re-derived rather than flipped. The 6 running
animations the integration brief reported as a product defect are a SETTLING
TRANSIENT, measured: they are `background-color` CSSTransitions of
--duration-fast (120ms) created while the page loads, and the kit sampled
exactly 120ms after applying the preference -- racing the animation it was
measuring, which is why a different 1-3 of 9 scenarios failed on every run. A
direct 0/120/300/700/1500/3000ms sweep caught one first sample at currentTime
116.67 of 120 and zero from 120ms on, everywhere. The kit now polls until the
page is quiescent (`_settled_motion`) and records the instant-of-change
reading beside it as `motion_at_preference_change`; MOTION_JS names each
animation's target path, property and currentTime. OSV1-011's probe re-reads
the settled count for all 18 renders (0 everywhere) instead of resting on the
static one-@media-block check alone.

Gates: ruff check + format clean; pyright 0 errors; pytest ledger/checks 60
passed; make ledger-mutate 60/60 proven, none unproven; test-conformance-a 38
passed / 4 xfailed / 0 failed; test-conformance-b 52 passed / 35 xfailed / 0
failed.
@bkrabach
Brian Krabach (bkrabach) merged commit 6c2e9fa into main Sep 5, 2026
2 checks passed
@bkrabach
Brian Krabach (bkrabach) deleted the highway/os-wave-2 branch September 5, 2026 11:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants