Skip to content

Make the buyer panel's stale-price and share notices actionable - #17

Draft
mcbradd wants to merge 5 commits into
mainfrom
claude/buyers-panel-share-price-refresh-jy8ap2
Draft

mcbradd wants to merge 5 commits into
mainfrom
claude/buyers-panel-share-price-refresh-jy8ap2

Conversation

@mcbradd

@mcbradd mcbradd commented Sep 5, 2026

Copy link
Copy Markdown
Owner

The buyer decision panel showed three things the buyer could not act on. This makes each one a control.

Scope has narrowed as main advanced: the color-balancing work this PR originally carried is now superseded by main's own minColors collation policy and has been dropped (see Validation).

Share link now propagates the break

The workspace stripped the query out of the address bar on arrival, so the only shareable URL lived behind an unlabelled copy icon, and a recipient who forwarded what they saw in the address bar sent an empty break.

  • The address bar carries the current break and stays in sync as it is edited, so the visible URL is always the shareable one.
  • The history entry is marked as this browser's own (history.state.colorbreakOwn), so a reload of your own break is not re-announced as someone else's shared calculation or a recovery prompt.
  • The control is a labelled Share button that uses the platform share sheet on touch first, then the clipboard, then a readable link.

Note: the address bar now carries the public break composition (products, quantities, slots). Bids, shipping, seller costs and actuals were already excluded from the share URL and still are.

Stale prices are a refresh button

"Prices over 6 hours old" is now the control that acts on it, driven by main's own refreshPublishedPrices — the same engine the product picker uses, so usable prices survive a failed refresh and the buyer never loses an estimate by asking.

The badge speaks the picker's vocabulary exactly (Searching… / Updating… / Updated / Up to date / No newer data / Partial update / Retry), carries aria-busy while running, and stays visible after the check so the answer outlives the condition that prompted it. A plain-language line states the outcome, including the honest "No newer prices are published yet."

Ranked cards: empty Chance column

A legacy .contributors .card-row three-column rule outranked the four-cell contributor grid at 720px and up, so the Adds cell wrapped onto its own line and Chance read as an empty column. Header and row columns now align to the pixel.

Column tooltip

Chance and Adds ran together in one paragraph. Tip now renders blank-line-separated paragraphs and sets a leading term apart, alongside main's EstimateTip and its visual-viewport sizing.

Also fixes an unhandled rejection when the catalog or sealed-price fetch fails during line repair.

Validation

main has been merged in four times as it advanced (thirteen commits). The last merge changed what this PR should contain:

  • Color balancing: dropped, superseded. main implemented the same idea more generally — minColors on the sheet, a collation-policy layer mapping balanceColors → minColors: 5 with per-product evidence, exact DP bounds over color groups, duplicateKey identity, reserved color spaces in sampling, and its own omission when the card list cannot prove the guarantee. main's version is a strict superset, so simulation.ts and outcome-model.ts were taken wholesale and this PR's two color-balancing tests removed; main's collation-integration.test.ts covers the behavior.
  • Price refresh: rewired, not duplicated. main landed refreshPublishedPrices with phases, per-shard revisions and partial retry. This PR's weaker refreshPriceSnapshot was deleted and the buyer badge now calls main's function, so scryfall.ts differs from main only in one status message.
  • BuyerWorkspace.tsx / BuyerDetails.tsx / methodology.html: this PR's controls and copy placed inside main's AnswerProvider, AnswerGraphic and MIN/MAX paragraph.

Post-merge the full npm run check is green: 464 tests across 100 files, root .mjs suites, shared-module boundary, unused-symbol check, coverage gate, both price-snapshot gates, ready examples, production build, deploy-path and OCR-bundle smoke tests. build-number.txt is 13.

tools/check-refresh-flow.mjs (not wired into any script or workflow) fails on a sheet-header height assertion — but it fails identically on origin/main with the same browser, so it is not this PR's. It appears to expect Playwright's headless-shell build, which this environment does not carry.

Re-verified in Chromium against the merged production build, with no page errors: the URL carries the break, the Share button is present, the stale badge renders as the refresh button and a full round trip reports "No newer data" with the matching answer line, the ranked row renders four cells with header and value columns aligned to the pixel, and the column tooltip renders two paragraphs.

🤖 Generated with Claude Code

https://claude.ai/code/session_01XPJ6p3JK61STwJazS24aoF

The buyer panel told the buyer three things they could not act on, and one
of them was wrong.

Share link. The workspace stripped the break out of the address bar on
arrival, so the only shareable URL lived behind an unlabelled copy icon and
a recipient who forwarded what they saw sent an empty break. The address bar
now carries the current break and stays in sync with it, the history entry is
marked as this browser's own so a reload is not re-announced as someone
else's shared calculation, and the control is a labelled Share button that
uses the platform share sheet on touch before falling back to the clipboard
and then to a readable link.

Color balancing. MTGJSON marks draft common sheets color balanced. The
simulator ignored the flag and reported it as a technical issue, which both
understated every mono color's floor (a modeled opening could miss a color
that a real pack cannot) and put a defect notice in front of someone with no
way to fix it. Sampling now applies the one guarantee the flag carries: the
sheet spends its first five picks on one card of each mono color, then draws
the rest by its own printed weights. Slot bounds follow the same rule. No
stronger per-color distribution is claimed, and colorless and land commons
still come through the free picks. The omission now fires only when the
resolved sheet has lost a whole color and the guarantee cannot be honored.

Stale prices. "Prices over 6 hours old" is now the button that refreshes
them: it re-reads the published snapshot past the browser and service-worker
caches and recalculates, and says plainly when no newer publication exists.

Also fixes the ranked-card list, where a legacy three-column rule outranked
the four-cell contributor grid at 720px and up, so Adds wrapped onto its own
line and Chance read as an empty column; and the column tooltip, which ran
two definitions together in one paragraph.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XPJ6p3JK61STwJazS24aoF
…hare-price-refresh-jy8ap2

# Conflicts:
#	build-number.txt
#	src/future.css
…hare-price-refresh-jy8ap2

# Conflicts:
#	build-number.txt
…hare-price-refresh-jy8ap2

# Conflicts:
#	build-number.txt
#	public/methodology.html
#	src/domain/simulation.test.ts
#	src/domain/simulation.ts
#	src/features/buyer/BuyerDetails.tsx
#	src/features/buyer/BuyerWorkspace.tsx
#	src/features/shared/Primitives.tsx
…hare-price-refresh-jy8ap2

# Conflicts:
#	build-number.txt
#	public/methodology.html
#	src/data/outcome-model.ts
#	src/domain/simulation.ts
#	src/features/buyer/BuyerWorkspace.tsx
@mcbradd mcbradd changed the title Make the buyer panel's notices actionable and simulate color balancing Make the buyer panel's stale-price and share notices actionable Sep 6, 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