Skip to content

Twin (grouped) interpolation with synced blocks#59

Merged
IanMayo merged 6 commits into
mainfrom
claude/twin-table-interpolation-rbbvxp
Jul 3, 2026
Merged

Twin (grouped) interpolation with synced blocks#59
IanMayo merged 6 commits into
mainfrom
claude/twin-table-interpolation-rbbvxp

Conversation

@IanMayo

@IanMayo IanMayo commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

Summary

Adds support for a real-world lookup format Grid-Sight couldn't handle: Speed (rows) × Direction (columns) with a merged Season column — Summer (30–80 kts, 6 rows) and Winter (20–60 kts, 4 rows) — i.e. two stacked grids sharing the Direction axis.

Started as an investigation (both symptoms traced to one root cause: the addressing layer assumes a single leading row-header column with no row groups), then implemented the fix per the agreed synced-blocks design.

Behaviour

  • Enabling Grid-Sight now offers an enabled S (sliders) lozenge on the corner; the previously mis-placed H/# lozenges are no longer shown on the label columns / merged group cell.
  • Clicking S adds one shared Direction slider plus a Speed slider in each season block.
  • Speed sliders are synced by value — dragging one moves the other. In the overlap (30–60) both blocks interpolate and show their highlight rectangle.
  • When the shared speed leaves a block's range (e.g. 70, inside Summer / outside Winter), that block's slider is disabled and its readout + highlight are cleared (not clamped).

Verified in Chromium; hand-checked interpolation (Summer @45kt/90° = 13.85, Winter = 9.55).

Changes

New, isolated from the single-grid slider path so ordinary tables cannot regress:

  • src/core/twin-grid.ts — pure, rowspan-aware detection + model (one rowHeader × colHeader sub-grid per group).
  • src/enrichments/twin-interp.ts — pure per-block bilinear eval + the twin-specific out-of-range rule (clear, not clamp).
  • src/enrichments/twin-slider.ts — the synced-blocks controller (shared Direction slider, per-block Speed slider, value-sync, out-of-range disable). Reuses bilinear and the existing highlight classes.
  • src/ui/header-utils.ts — branch the sliders descriptor to the twin controller and suppress the mis-placed classic lozenges on twin tables.
  • public/demo/twin-table/index.html — reproduction fixture, now the driving demo (Introduce walkthrough #15).
  • specs/016-twin-interpolation/investigation.md — findings + the decided design.

Deferred: group-awareness for heatmap / statistics / sort / filter / outlier — today they are simply not offered on a twin table rather than mis-applied.

Tests

  • Unit: twin-grid (6), twin-interp (6), twin-slider controller (6) — model, per-block interpolation, sync, out-of-range disable, teardown.
  • E2E: tests/e2e/twin-interpolation.spec.ts (4) — lozenge placement, slider injection, value-sync, out-of-range clearing.
  • Full node suite green (711); no regressions.

🤖 Generated with Claude Code

https://claude.ai/code/session_01DQkMTSjZd2fWS8H45WLcsh

Reproduce a real-world "twin" lookup format — Speed (rows) x Direction
(columns) with a merged Season column (Summer/Winter) grouping the speed
rows into two independent, stacked grids that share the Direction axis —
and investigate whether Grid-Sight can offer interpolation over it.

- public/demo/twin-table/index.html: faithful reproduction fixture
  (Summer 30-80 kts x 6 rows, Winter 20-60 kts x 4 rows), registered as
  demo #15 in the shared demo nav.
- specs/016-twin-interpolation/investigation.md: feasibility write-up.
  Confirms (against the live addressing layer) that the current single
  row-header slider binding fails closed on this shape — both axes bind to
  null, so no slider is offered rather than a wrong number. Prototyped a
  group-aware binding that partitions on the rowspan group cell into two
  rectangular sub-grids and feeds the existing bilinear() unchanged; proves
  twin interpolation is a small, well-contained addressing-layer extension.
  Recommends a season-selector + shared re-ranging sliders design.

Verified end-to-end in Chromium: the fixture renders both merged group
cells, Grid-Sight mounts without error, and zero sliders appear (fail
closed). No src changes; interpolation core untouched.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DQkMTSjZd2fWS8H45WLcsh
github-actions Bot pushed a commit that referenced this pull request Jul 3, 2026
@github-actions

github-actions Bot commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

🧹 PR preview for #59 has been removed.

@codacy-production

codacy-production Bot commented Jul 3, 2026

Copy link
Copy Markdown

Up to standards ✅

🟢 Issues 0 issues

Results:
0 new issues

View in Codacy

🟢 Metrics 176 complexity · 6 duplication

Metric Results
Complexity 176
Duplication 6

View in Codacy

NEW Get contextual insights on your PRs based on Codacy's metrics, along with PR and Jira context, without leaving GitHub. Enable AI reviewer
TIP This summary will be updated as you push new changes.

claude added 3 commits July 3, 2026 09:57
Normalise pipe spacing and fill the reproduction table's cells so the
tables lint cleanly (Codacy CodeStyle / markdownlint table-column-style).
Uses a ditto mark for continuation rows instead of ragged empty cells.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DQkMTSjZd2fWS8H45WLcsh
The merged group column breaks enrichment lozenge placement the same way
it breaks slider binding: H/# mount on the Speed label column and on the
merged Season cell, and the first speed of each block gets none. Documents
this as a second manifestation of the shared single-row-header assumption
and notes twin support is an addressing-layer concern, not slider-only.
Verified against the live rendered DOM.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DQkMTSjZd2fWS8H45WLcsh
Adds support for "twin" lookup tables — Speed (rows) x Direction (columns)
grouped by a merged Season column (Summer/Winter) — which the single-grid
addressing layer previously mis-read (no sliders offered; H/# lozenges
mis-placed on the label columns and the merged group cell).

New, isolated from the single-grid slider path so ordinary tables cannot
regress:

- src/core/twin-grid.ts — pure, rowspan-aware detection + model: partitions
  the body into one rowHeader x colHeader sub-grid per group.
- src/enrichments/twin-interp.ts — pure per-block bilinear eval with the
  twin-specific out-of-range rule (clear, not clamp).
- src/enrichments/twin-slider.ts — synced-blocks controller: one shared
  Direction slider + one Speed slider per block, synced by value; a block
  whose range excludes the shared speed is disabled and its readout +
  highlight cleared. Reuses bilinear + the slider highlight classes.
- src/ui/header-utils.ts — on a twin table, offer only the twin-aware S
  toggle on the corner (the mis-placed H/# are no longer shown) and route
  slider applicable/active/toggle to the twin controller.

Design (synced blocks, no selector) recorded in
specs/016-twin-interpolation/investigation.md. The demo (#15) now drives the
feature. Deferred: group-awareness for heatmap/statistics/sort/filter/outlier
(not offered on twin tables rather than mis-applied).

Tests: twin-grid (6), twin-interp (6), twin-slider controller (6), and e2e
tests/e2e/twin-interpolation.spec.ts (4) covering sync + out-of-range +
lozenge placement. Full node suite green (711); verified end-to-end in
Chromium.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DQkMTSjZd2fWS8H45WLcsh
@IanMayo IanMayo changed the title Investigate twin (grouped) interpolation tables Twin (grouped) interpolation with synced blocks Jul 3, 2026
github-actions Bot pushed a commit that referenced this pull request Jul 3, 2026
Three fixes from live testing of the twin sliders:

- Vertical Speed sliders were inverted vs the table rows (dragging down
  raised the interpolation). Dropping `direction: rtl` puts the min at the
  top so the thumb tracks the rows: top = slowest (top row), bottom =
  fastest. Verified by click-mapping in Chromium (top→30, bottom→80).
- The shared corner readout now shows the current Speed alongside the
  Direction ("Speed 45 · Direction 90"), not Direction alone.
- Turning Grid-Sight off left the injected direction row, per-block sliders,
  and highlights behind. Both teardown paths (per-table deactivateToggle and
  the global disable()) now call disableTwinSliders, so GS-off restores the
  original markup on grouped tables too.

Tests: added a corner-readout unit assertion and an e2e GS-off teardown case
(no twin adornments remain). Full node suite green (712); all twin e2e green;
verified end-to-end in Chromium.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DQkMTSjZd2fWS8H45WLcsh
github-actions Bot pushed a commit that referenced this pull request Jul 3, 2026
Each live block now shows the circle marker at the interpolated (speed,
direction) point inside its highlight rectangle — matching the single-grid
slider's [data-gs-marker]. The marker is placed by interpolating between the
four bracketing cells' centres (same math as heatmap-marker.ts), reuses the
existing marker CSS, repositions on window resize, hides when the block is
out of range, and is removed on teardown.

Tests: two unit cases (per-block marker shown/hidden by range; removed on
teardown) and an e2e assertion (one visible marker per block). Node suite
green (714); twin e2e green; verified in Chromium.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DQkMTSjZd2fWS8H45WLcsh
github-actions Bot pushed a commit that referenced this pull request Jul 3, 2026
@IanMayo IanMayo merged commit 27ca08a into main Jul 3, 2026
4 checks passed
@IanMayo IanMayo deleted the claude/twin-table-interpolation-rbbvxp branch July 3, 2026 12:03
github-actions Bot added a commit that referenced this pull request Jul 3, 2026
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