Correct the transposed E-W double-dummy rows at the ingest door - #413
Merged
Conversation
The Game Analysis double-dummy table has been showing ACBL club boards with its East and West rows swapped: on Stoneridge Creek board 12 of 2026-09-02 it put 10 hearts on East and 11 on West, where the deal gives East 11 and West 10. North and South are unaffected, which is why it reads as subtle rather than obviously broken. The cause is in the extension's two ACBL adapters, which map the `EW:` double-dummy row West-first. ACBL publishes a pair -- and the two digits of a slash form like `3/4H` -- in the order the direction label itself reads, so `E-W` means [East, West]. That is the same convention seat-order-contract.md already pins down for `ew_pair.players`, and this is the third time the same flip has been found in a different field. The producer fix is a store release away, so correct it here, where a deploy reaches every current user this week. Two boundaries, not one. Every 1.3 envelope in existence was stamped by this file's previous version, which corrected players and knew nothing about the table -- and the ingest page archives what it corrects, so club_games is full of 1.3 games whose table is still transposed. Folding the new correction in under the old `< 1.3` gate would have skipped all of them permanently. So players gate on `< 1.3` and the table on `< 1.4`, and the extension goes 1.2 to 1.4 with 1.3 reserved for our own restamp. Deal-proved, per the contract's rule that seat changes are verified against a deal and never against a document: all 88 distinct deals in the extension's fixtures/my-acbl were solved with bridge-solver, and of the tokens whose two seats differ, 22 of 22 on the EW row match East-first and 14 of 14 on the NS row match North-first, with nothing contradicting either. End to end, a 1.1 envelope carrying board 12's table as the page showed it now renders 3625335243a7b8a97a89 -- byte-identical to the solver's own output for that deal. What this cannot reach: a game already handed on and cached in the Game Analysis app's sessionStorage or event cache. Re-sending it from the extension refreshes it. The server-side archive is fine -- it is corrected on read. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
The Game Analysis double-dummy table shows ACBL club boards with its East and West rows swapped. Stoneridge Creek board 12, 2026-09-02:
North and South are unaffected, which is why it reads as subtle rather than obviously broken. The solver at
bridge-craftwork.com/bridge-solver/gets the same deal right, which is how it surfaced.Why it happens
The extension's two ACBL adapters map the
EW:double-dummy row West-first. ACBL publishes a pair — and the two digits of a slash form like3/4H— in the order the direction label itself reads, soE-Wmeans[East, West]. That is the same conventionseat-order-contract.mdalready pins down forew_pair.players, and this is the third time the same flip has turned up in a different field.The producer fix is a store release away. This corrects it at the door, where a deploy reaches every current user this week.
Two boundaries, not one
Every
1.3envelope in existence was stamped byseatOrder.js's previous version, which corrected players and knew nothing about the table — and the ingest page archives what it corrects, soclub_gamesis full of1.3games whose table is still transposed.Folding the new correction in under the old
< 1.3gate would have skipped every one of them permanently. So:schema_versiondouble_dummyThe extension goes 1.2 → 1.4, with 1.3 reserved for our own restamp. That half is in a separate
bridge-classroom-fetchPR; this one stands alone and needs no coordination to deploy.Evidence
Per the contract's own rule — seat changes are verified against a deal, never against a document:
fixtures/my-acblsolved withbridge-solver. Of the tokens whose two seats differ, 22 of 22 on the EW row match East-first and 14 of 14 on the NS row match North-first. Nothing contradicts either.1.1envelope carrying board 12's table exactly as the page showed it, run through this helper and then the analysis page's own encoder, renders3625335243a7b8a97a89— byte-identical to the solver's output for that deal.Scope
seatOrder.jsis the single copy of the rule —scripts/build-site.shcopies it todist/ingest/seat-order.jsfor the static ingest page, and the SPA imports it for the archive read path. Neither call site's signature changed.What this cannot reach: a game already handed on and cached in the Game Analysis app's
sessionStorageor event cache. Re-sending it from the extension refreshes it. The server-side archive is fine — it is corrected on read.Tests
735 passing.
seatOrder.test.jsgains the table cases (including a stored1.3row whose table is fixed while its already-correct players are left alone);useClubGames.seatOrder.test.jscovers the same on the archive read path.🤖 Generated with Claude Code