Glass swatch library release (WYSIWYG exclusions + metadata flags) - #143
Draft
dompm wants to merge 42 commits into
Draft
Glass swatch library release (WYSIWYG exclusions + metadata flags)#143dompm wants to merge 42 commits into
dompm wants to merge 42 commits into
Conversation
PR #75 renamed the SheetPanel prop to `onUpdatePieceTransform` in App.tsx but SheetPanel still destructures `onTransformChange`, so the per-piece wrapper closes over an undefined callback. Konva fires the drag events, the wrapper resolves (it's a real arrow fn), then crashes trying to call undefined → "i is not a function" repeats on every `_drag` and `_endDragAfter`. Side effects: no live preview while moving, dragged pieces only land on the next click, occasional stale selection. Rename the App-side prop back to `onTransformChange` so it matches what SheetPanel actually destructures. No SheetPanel changes needed. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…r multi-color mixes
…ns like clover and avocado
…age, and fix Vanilla Cream Opal category
…classifier correctly handle Blackberry Cream
…utomatically in the scraper
…efault sorting view
…s for external hosting
…duct link and front-lit indicators, and commit registry to Git
…he library build Replaces the images[0] positional rule in scripts/build_swatch_library.py with an argmax over every gallery candidate, scored by the vendored research/delighting-035 picker (scripts/swatch_picker.py + its report-019 dependency scripts/audit_flagger.py, provenance headers in each). Addresses glass-library-integration-review.md Addendum 2 (SGE image picking structurally broken) and Blocker-1 patch #2 (below-floor products get Quarantined instead of shipping a bad image). - Candidates are scored on 320px CDN thumbnails (cached, idempotent); full images are re-downloaded only when the final pick differs from what is already on disk. - Anti-churn stability rule: a shipped image is only replaced when the picker's margin over it exceeds 0.15 (and never protected when it no longer clears the 0.45 floor). Rationale documented in apply_stability_rule(); suppressed 223 of 410 argmax disagreements in the full rebuild while allowing 187 genuine fixes through. - Failed re-fetches now revert image_url to the previously-shipped URL so a network outage cannot wedge an item into a registry/disk mismatch. - Legacy quarantine-list, -v2 preference, formula dedup, crop/calibration logic kept. - docs/library-picker-rebuild/: before/after diff report + 20-change contact sheet from the full rerun (registry/images themselves are gitignored runtime data in frontend/public/assets/, regenerated by running this script). Both maintainer SGE validation cases verified fixed in the final registry (youghiogheny-yuf5100gr -> gallery position 4, youghiogheny-y700hs -> position 3); reactive/Alchemy recovered set ships the -v2 images, unrecoverable set excluded. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…-white false quarantines
Decision 3 (glass-library-integration-review.md Addendum): replace the blanket
is_reactive_cloud drop rule with REACTIVE_CLOUD_CROP_OVERRIDE -- the two
000009-0030/-0050 SKUs are re-included using the adjudicated clean crop
(x:[650,1200], y:[0,1200] of the 1200x1200 -v2 image), which excludes the
reaction-demo tile corner insert entirely. Adjudication recorded in research
trunk's refetch_manifest.json (recovered entries with human_verification_caveat).
Decision 4 (036 report): WHITE_ON_WHITE_OVERRIDE restores the two products the
picker floor wrongly quarantined (Opaque White 000013-0030, silver-gray Cascade
002249-CA37) via an explicit per-SKU list instead of lowering the floor globally.
Decision 5: registry entries now carry a 'lighting' field ('front-lit'/'back-lit')
derived from the report-015/019 per-manufacturer priors, alongside the existing
front_lit bool.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ership overrides Replaces the stale pre-rebuild registry (1333 entries, committed in 06ac88e) with the current picker-corrected one from the 036 rebuild (1265 entries; docs/library-picker-rebuild/report.md), plus the four ownership-cleanup entries: - bullseye-0000090030f1010 / -0000090050f1010: Reactive Cloud KEEP+crop (Decision 3) -- point at the -cropped.jpg derived from the -v2 image, crop_box [650, 0, 1200, 1200], real-world width scaled accordingly. - bullseye-0000130030f1010 / -002249ca37f1010: white-on-white false-positive restores (Decision 4). - every entry now carries the 'lighting' field (Decision 5). The 548MB catalog_images/ stay untracked; run python3 scripts/build_swatch_library.py to fetch them. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…-setup docs Decision 2 (review Blocker 2): with the registry committed but the 548MB catalog_images/ untracked, a clean checkout must degrade loudly, not silently: - registry fetch failure now renders an explicit setup message (run scripts/build_swatch_library.py) instead of the generic no-matches empty state - per-thumbnail onError fallback shows an 'image not fetched' note instead of a broken image when catalog images 404 - README gains a 'Glass swatch library data' section documenting the two-part data layout and the fetch/refresh workflow - docs/library-picker-rebuild/OWNERSHIP.md records ownership and the decision log for the integration-review cleanup Decision 5: the front-lit warning badge now keys off the registry's new 'lighting' field (front_lit kept as fallback). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…product The Phase B dedup loop skips picker-Quarantined rows before the REACTIVE_CLOUD_CROP_OVERRIDE is consulted, so a future run in which the picker floors both of the product's (borderline-by-construction) hybrid photos would silently drop the adjudicated KEEP+crop entries. Route the reactive-cloud ids through apply_manual_overrides too, restoring status Downloaded with the -v2 source URL; Phase B/C then apply the crop as usual. Verified with a unit-level harness: quarantine->Downloaded conversion for both override lists, pass-through for other ids, and the crop fast-path returning the 550x1200 cropped files. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…erified border-scrubbed crops (#124) * feat: prefer Bullseye whole-sheet/grip photos over flat renders, with hardware crop Diagnosis: Bullseye galleries lead with a full-bleed solid-color macro render (_01) that scores perfectly on the picker's audit/coverage components (no background, edge-to-edge 'sheet'), while the real whole-sheet photo -- white studio ground, sometimes clamp grips on the right edge, a product label and a sharpie batch number -- is penalized as advisory product_on_white (audit 0.35) and capped on coverage by its white border. The flat render therefore beat the real sheet photo by 0.04-0.28 base score wherever both existed. Fix (swatch_picker component (f), Bullseye-only, no ML): - grip/whole-sheet detector on downloaded pixels: near-white ground fraction, dominant-sheet blob, dark clamp blobs touching the right edge - relative rank adjustment: grip +0.35 / whole-sheet +0.15 / flat chip -0.30, the penalty only when a sibling candidate is itself a whole-sheet photo - crop box (fraction coords) excludes the clamps, label column (fixed 80%%-of- sheet-width right cut) and the sharpie strip (12%% top inset); applied in the build's existing crop_box pipeline at full resolution - churn gate: a shipped Bullseye pick may only change when it is the diagnosed flat-chip -> detected whole-sheet/grip upgrade; everything else keeps the current image and is listed in the report (6 kept this run: 2 white-on-white sheets, 2 photo-vs-photo taste swaps, 2 pale striker tints whose grip photo the detector cannot yet crop safely) - --only-manufacturer scoping: re-runs one manufacturer's collection, carries every other manufacturer's registry rows through verbatim - legacy-quarantine -v2 rows are carried through when the recovery file is absent in the checkout instead of silently dropping shipped products Result: 273 Bullseye picks upgraded (242 whole-sheet, 31 grip), all 273 with hardware/label/sharpie cropped out; 0 rows removed; non-Bullseye rows byte-identical. Review board (old|new for every change): docs/library-picker-rebuild/bullseye_grip_review.jpg Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix: full-resolution border scrub for Bullseye grip crops (no background survives) Lead review of the first board found a systematic artifact: most crops kept a thin near-white sliver along the bottom edge (plus occasional corner wedges). Root cause is two-fold: (1) the sheet bbox's bottom rows are a bright specular reflection band with a DARK cut-edge line below it, so an outermost-row check stops at the dark line and traps the white band inside the crop; (2) the band's depth varies 17-38px per photo and, at the picker's 320px thumb scale, JPEG downsampling blends it below the white threshold entirely -- a thumb-scale-only scrub passed 47 crops that were still dirty at full resolution. The scrub (swatch_picker._scrub_crop_box) is redesigned and now runs twice: - cheap thumb-scale pass in bullseye_features() as the churn-gate prefilter - AUTHORITATIVE full-resolution pass in the build's Phase C on the actual downloaded pixels, immediately before cropping Mechanics: scan a deep window (15% of the crop) in from each edge, cut past the deepest near-white-contaminated row/col, apply a safety inset on all four sides (err toward trimming sheet, never keeping background), then SELF-VERIFY the final crop's border bands are clean. A scrub that loses >20% of the crop area or fails verification returns failure -- the product keeps its currently-shipped pick and is listed as uncertain instead of shipping a bad crop. Result vs the branch base: 232 Bullseye picks upgraded (all flat-chip -> whole-sheet/grip, every crop re-verified at full res: zero border rows/cols above the 5% near-white QA threshold across all 232). 48 products are now held as uncertain (was 6): pale/white opalescents, white-mix streaky lines and bright iridescents whose near-white content cannot be safely rectangle-cropped -- listed in docs/library-picker-rebuild/report.md. 0 rows removed; all non-Bullseye rows byte-identical. Review board regenerated: docs/library-picker-rebuild/bullseye_grip_review.jpg Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
…rdering bug (#128) PR #124's crop phase only ran on picks that changed that run, so products whose already-shipped pick was itself an uncropped grip/whole-sheet photo never got the border scrub. Swept all 217 Bullseye rows shipped with cropped:false by classifying pixels (not URL/filename heuristics) through the existing grip/whole-sheet detector, applying the same authoritative full-res scrub + hard-reject discipline as #124. Found and fixed a real ordering bug in swatch_picker._scrub_crop_box: the left/right contamination check used the pre-row-trim row range, so a contamination band confined to the top/bottom (e.g. a specular reflection strip near the cut edge) got double-counted as contaminating every column, forcing a false symmetric left+right trim that blew the 20% area-loss budget on otherwise-croppable grip photos (confirmed on the four products named in the task: Butterscotch/Marigold Yellow/Plum Striker/Gold Purple Opalescent). The final self-verification band is unchanged and still catches genuine residual contamination regardless of ordering. Also wrote a bespoke black-corner scrub (new contamination class: a black mount/frame wedge in the top-left AND bottom-left corners, invisible to the white-background detector since white opalescent glass reads as its own background) for Dense White Opalescent Thin-rolled, and resolved the two other user-named cases by fetching full product galleries: Clear Transparent 3mm has no flat alternative to its shipped side-view (kept, flagged for a second source); Light Mineral Green's washed gradient look is the true appearance of the finish across all 3 candidates, and the picker's raw preference for a tighter macro crop would repeat the flat-chip anti-pattern #124 demotes, so the shipped pick was kept. Result: 8 of 217 newly cropped, 19 hard-rejected to the uncertain list (kept uncropped, mostly false-positive whole-sheet detections on pale glass), 188 correctly left alone. Bullseye: 358 cropped / 209 uncropped of 567. Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
…+ raw results) scripts/vlm_pick_judge.py: re-scrapes each sampled product's full live gallery (throttled ~1 req/s/host), builds a numbered contact sheet, and asks one 'claude -p' subprocess per (product, model) to forced-choice pick the straight-on flat swatch photo (strict parse, one retry). 41-product sample = 4 user-named Oceanside failures + a low/high pick_score mix across all 4 manufacturers. Judged with both sonnet and haiku. Registry read-only. scripts/vlm_judge_report.py: renders the review board + pilot report from the results (committed next). docs/library-picker-rebuild/vlm_judge_pilot_results.json: raw per-product results (heuristic index, both judges' picks, latency, cost). The data/ working dir (thumbs, contact sheets, caches) stays gitignored. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Deliverable A: docs/library-picker-rebuild/vlm_judge_pilot_board.jpg -- 41 rows, heuristic pick | sonnet pick | haiku pick per product, named failures highlighted. Deliverable B: docs/library-picker-rebuild/vlm_judge_pilot.md -- named- failure verdicts (3 fixed outright, 1 improved-to-quarantine, 1 already fine on the current gallery), agreement stats (sonnet-haiku 73%), NONE-rates (sonnet 2%, haiku 12% incl. a verified false NONE), measured cost/latency, corpus projection ($68 sonnet / $21 haiku for 1,269 products), recommendation: one-time sonnet judge-everything backfill -- confidence gating is not viable because all named failures had HIGH heuristic scores (1.0-1.5). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…cro fix Sonnet forced-choice judge over the 5 flagged products (5 calls, $0.26, zero parse failures), applied through the registry per the sweep_uncropped_bullseye.py precedent: - bullseye-0002430030f1010 (Translucent White 3mm): CHANGED #4 -> #1. Shipped pick was the product-label macro (_04.jpg, heuristic score 0.9044). Winner is the flat white sheet on a BLACK ground -- added a self-verifying dark-edge trim (generalizing report.md's bespoke dark-corner scrub, as it requested), crop [46,38,1192,1162], 89% kept. Row carries pick_score=null + vlm_judge provenance marker. - bullseye-0011010000f1010 (Clear single-rolled): NONE as predicted -- single-image gallery (side view); kept, confirmed second-source case. - bullseye-0012470031f1010 (Mineral Green irid): CONFIRMED shipped _02 over the macro _01, independently validating the sweep's reasoning. - bullseye-0001130050f1010 / bullseye-0002430050f1010 (white glass): both CONFIRMED; the judge did not fall for the 000243-0050 gallery's own label macro. WARNING documented in vlm_judge_targeted.md: the current picker still argmaxes the label macro 0.907 vs 0.603 (margin 0.30 > stability 0.15), so an unguarded full rebuild will churn this row back -- needs a vlm_judge-marker guard in build_swatch_library.py (not modified here; concurrent-edit freeze). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
build_swatch_library.py's rebuild had no knowledge of the vlm_judge provenance marker vlm_judge_targeted.py writes onto a registry row: the stability rule only protects a previously-shipped image when its OLD score clears PICKER_FLOOR, but a judge-picked row always has pick_score=None and typically isn't even in this run's freshly-scraped candidate_scores -- so a plain rebuild silently reverted judge overrides (e.g. Translucent White) straight back to the heuristic's confidently-wrong pick. Guard now checks the existing row for a vlm_judge marker before the picker-quarantine skip, the stability rule, and the Bullseye churn gate, and carries the row through byte-for-byte when present -- same posture as the existing carried_v2_rows pattern. Verified with a monkeypatched rebuild simulation: the Translucent White judge row survives a rebuild where the heuristic argmax tries to re-pick the label-macro image, while a non-judge-marked control row is still processed by the normal machinery.
Adds a corpus-wide, structured-signal-based striker classifier to build_swatch_library.py rather than relying on literal "Striker" name matches (which miss real cases -- Translucent White and Salmon Pink both ship pale/ unfired but neither has "Striker" in its name): - Bullseye: membership in the vendor's own `strikers` Shopify collection, reduced to base color codes (independent of thickness/format variant). This is the same signal that drives the "striker" page badge/tooltip on a Bullseye product page -- a per-product metafield not exposed on the regular /products.json feed (confirmed empirically: Translucent White/Salmon Pink's body_html says nothing about striking, but their live page embeds "key":"striker"/"value":"true"). 140 registry rows match (26 explicitly named "Striker" + 114 hidden, including both known cases). - Wissmach: a 'Striker' tag or a "color matures upon firing" family of phrases in body_html -- Wissmach puts this disclaimer directly on the product page. 6 registry rows match (3 named + 3 hidden: Gold Tone Opal, String of Pearls Opal Reactive, Oyster Pearl Opal Reactive). - Oceanside and Youghiogheny: investigated (tags, body_html keyword scan, and a live-page probe for a Bullseye-style metafield badge) with no striker signal found. Youghiogheny's "High Strike" line was specifically checked against Youghiogheny's own glossary and confirmed to be a different thing -- a hand-rolled, non-fusible mottled art-glass product line, already fully colored as shipped, not a kiln-refire color. Deliberately not flagged. `striker` (bool) and `strikes_to` (cleaned color-name string, or null) are now always present on every registry row. Verified with a monkeypatched rebuild covering all 4 manufacturers plus known striker/non-striker controls.
…rows Adds scripts/vlm_judge_striker.py: a sonnet judge pass over every registry row flagged `striker: true`, asking specifically for the PALE/unfired candidate (what actually ships) instead of the vivid/fired color a naive photo-quality heuristic would prefer. Also backfills striker/strikes_to onto the currently-committed registry (a full corpus rebuild will regenerate these fields going forward via the classifier landed in 939df9c). Audited so far: 34 of 146 confirmed striker rows (the 29 literal "Striker"- named products across Bullseye/Wissmach, plus the 5 hand-confirmed hidden cases: Translucent White x2, Salmon Pink x2, Wissmach Orange-Red Opal Striker Luminescent). 16 picks switched from a fired/vivid or outright wrong photo to the pale/unfired sheet; 11 confirmed already-correct; 6 have no valid pale candidate in their own gallery (left as-is, flagged); 1 manual cross-thickness override applied (Salmon Pink 2mm's own gallery's only non-vivid photo was a different, unrelated blue glass color entirely -- reused the 3mm sibling's genuine pale photo of the same base color instead). The remaining ~112 hidden (non-"Striker"-named) Bullseye striker rows are not yet individually audited -- follow-up work, tracked separately.
…ception)
CTO pivot 2026-07-16 (supersedes "switch the striker photo to its pale unfired
sheet"): unfired striker glass is now filtered OUT of the shipped library
entirely. WYSIWYG -- striker colors only develop once fired to ~1200F+, and the
~99% of users who work cold-process (foil/came) never reach that temp, so a
striker sheet keeps its dull unfired color forever; showing it (fired OR pale)
misleads them. Strikers are premium-priced (gold-derived pinks/rubies/purples).
- build_swatch_library.py: should_exclude_striker()/is_prestruck()/
partition_striker_exclusions() run as the last registry-assembly step (catches
scraped + all carry-through row sources). --exclude-strikers-in-place applies
just this filter to an existing registry with no network scrape (used here).
Schema fields striker/strikes_to kept -- they now DRIVE the exclusion.
- Registry: 1332 -> 1186 rows; 146 unfired strikers quarantined (Bullseye 140,
Wissmach 6). Every kept row byte-identical to before; documented quarantine
list in docs/library-picker-rebuild/striker_quarantine.{md,json}, not a
silent drop.
- Pre-struck exception keeps ZERO products: the brief's "S-suffix" rule does
NOT exist. Bullseye's coding system defines the trailing letter as a GRADE
code (F/P/B/C, no S, no pre-struck code); all strikers ship in F grade and no
row carries "Struck" wording. Detector kept as a defensive forward guard on
whole-word struck/pre-struck/pre-fired (never "striker").
- Identification 100% complete; Bullseye flags cross-checked against the live
strikers collection: 0 missed, 0 spurious. Oceanside 0, Youghiogheny 0,
Wissmach 6 -- cold-glass mainstays striker-sparse as expected.
- vlm_judge_striker.py marked SUPERSEDED (its photo switches are moot; excluded
rows do not ship). Reverted the uncommitted moot photo-switch changes.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
# Conflicts: # frontend/src/App.css # frontend/src/App.tsx
…flags
Extends the WYSIWYG library policy (CTO, 2026-07-17) on top of the 2026-07-16
striker exclusion.
Exclusion -- second category `kiln_transformative`:
- Bullseye Alchemy line (4 rows: 001015-0031/0051 Silver-to-Gold, 001016-0031/
0051 Silver-to-Bronze). Ships silver-toned; develops gold/bronze only when
kiln-fused, which cold-process (foil/came) users never do -- same WYSIWYG
failure as strikers, distinct mechanism. Matched by whole-word Alchemy /
Silver-to-X (is_kiln_transformative), kept as its own reason category so the
quarantine taxonomy stays clean.
- Quarantine: 146 -> 150 (146 unfired_striker + 4 kiln_transformative). Shipped
library 1186 -> 1182. striker_quarantine.{md,json} now carry a per-row
`category` and per-category/per-manufacturer breakdowns.
Kept-but-flagged metadata (sparse booleans, WYSIWYG-safe rows stay shipped):
- reactive:true (15 rows) -- Reactive Cloud/Ice/Red Reactive + Wissmach/Yough
reactives. Reaction needs in-contact kiln fusing; stable in cold work.
- iridized:true (162 shipped rows; 166 registry-wide, 4 are excluded Alchemy) --
whole-word irid/iridescent/iridized; the rainbow is real angle-dependent
thin-film reflection. Marks picker special-casing + future spectral-veil
targets. Whole-word rule rejects "Viridian" (substring), so 166 not 167.
Implementation: classify_exclusion()/apply_metadata_flags() in
build_swatch_library.py; full-rebuild path applies flags then partitions;
--apply-library-policy-in-place (alias --exclude-strikers-in-place) lands it on
the existing registry with no network scrape, merging into the existing
quarantine. Byte-identity verified: exactly 173 shipped rows change and every
change is a pure reactive/iridized flag addition -- no other field touched, 4
Alchemy removed.
Also adds docs/library-picker-rebuild/RELEASE_CHECKLIST.md.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Deploying vitrai with
|
| Latest commit: |
8d27a96
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://811e79ea.vitrai.pages.dev |
| Branch Preview URL: | https://library-release.vitrai.pages.dev |
… stamps
Bullseye galleries share one photo set across cart sizes; the builder stamped the
cart-size width (10in for -1010) onto whichever gallery image was picked, but ~45%
of picks are zoomed detail/macro crops covering a few inches -- so those textures
render 2-3x too coarse at physical scale (verified on 000100-0051-F).
scripts/scale_audit.py (+ scale_audit_lib.py) downloads each gallery (throttled,
local-only, gitignored), detects the whole-sheet studio shot, measures it, and
classifies the current pick. The whole-sheet photo is a FIXED studio sample (aspect
1.326, p10-p90 1.318-1.331 across 361 products); its absolute long side is not
pixel-recoverable, so SAMPLE_LONG_IN=10.0in is a documented, globally-retunable
assumption -- every relative correction is independent of it. The detail->whole-sheet
bridge does not hold (SIFT/NCC/FFT all fail), so macro footprints are corrected by
re-pick, not point-estimate.
Registry (Bullseye rows only; all other rows byte-identical):
- 183 known-wrong ~10in stamps on detail/macro picks -> real_world_{w,h}_in = null
- 10 whole-sheet heights made aspect-consistent (square 10x10 stamp fix)
- 198 needs_repick:true flags (per-product targets in the sidecar)
Iridized (keys off iridized flag): 14 reflection-side picks + 91 transmission
re-picks flagged (backlit preview needs the white/transmission side; never crop
across a split backdrop seam).
- docs/library-picker-rebuild/scale_audit.json per-product sidecar (method+confidence)
- docs/library-picker-rebuild/scale_report.md findings, calibration, limitations
- docs/library-picker-rebuild/scale_boards/ ~35 examples incl. failures
- GlassLibraryDialog.tsx: null-safe scale (fallback + "scale TBD")
- build_swatch_library.py: preferred_gallery_image() pick preference, gated
(SCALE_AWARE_REPICK) pending the image-hosting re-pick rebuild
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…mantics
Lead-requested calibration checks, both negative for a cleaner absolute anchor:
- Rotation ruled out: minAreaRect rectified aspect 1.327 == axis-aligned bbox,
median tilt ~0deg across 361 sheets -- the sample truly has ~1.327 aspect, not a
17x20 (1.176) sheet at a studio tilt.
- Reeded-rib physical anchor: 5/6 reeded whole-sheets converge on ~80-83 ribs across
the full sheet (one physical roller), but ribs->inches is not closable -- Bullseye
publishes no rib pitch and the 2x2in Color Sample photos are unusable (generic
multi-sample stock _02, sub-2in full-bleed macro _01). SAMPLE_LONG_IN=10.0in stays
a documented assumption.
Also: state registry field semantics explicitly (real_world_{w,h}_in = the IMAGE
footprint, not the cart sale size -- the exact conflation that caused the bug) in
scale_report.md and the sidecar meta; add checklist footnotes (re-pick/image-hosting
coupling, calibration retune, frontend typecheck deferred to final review). No
registry data change (audit is idempotent).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…on item Lead-requested closeout notes (no data change; audit idempotent): - Candidate sample identity (UNVERIFIED): confirmed 1.327 aspect ~= 4:3 within rolled-edge slop -> possibly a metric 40x30cm studio blank (15.75x11.8in). If so SAMPLE_LONG_IN ~= 15.75 (1.57x rescale of every Bullseye scale). Not switching the constant on speculation -- recorded with the implied reeded rib pitch under each hypothesis (10in -> ~3.1mm, 15.75in -> ~4.9mm) so one physical measurement adjudicates instantly. In scale_report.md + sidecar meta.sample_size_candidate. - Release checklist: added deferred "CTO tape-measure calibration" item (rib pitch of a physical reeded sheet, or a studio-sample size -> closes SAMPLE_LONG_IN). Co-Authored-By: Claude Fable 5 <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.
Draft release PR for the consolidated glass swatch library. Do not merge — for CTO review.
Release checklist
kiln_transformative;reactive:true(15 rows) +iridized:true(162 shipped rows) metadata added. Quarantine 150 total; library 1332 → 1182.needs_repickflags; iridescent transmission-shot + split-backdrop-seam rules folded in (14 reflection-side picks, 91 transmission re-picks). Absolute sample size is a documented, retunable assumption. Pick-preference implemented + gated pending image hosting. See section below.VITE_SWATCH_CDN_URL); this is also what unblocks activating the scale re-pick (SCALE_AWARE_REPICK) and clearing the 198needs_repickrows.Canonical checklist lives at
docs/library-picker-rebuild/RELEASE_CHECKLIST.md.What this branch ships (vs main)
The whole library stack — main has none of it: the registry data (now 1182 rows), the picker/VLM build pipeline, the WYSIWYG exclusion policy, the scale audit, and the frontend Glass Library dialog.
Policy layer (striker exclusions + metadata)
Two WYSIWYG exclusion categories (a cold-process artist never performs the kiln step that develops the named color):
unfired_strikerkiln_transformativePer-row reasons + breakdowns in
striker_quarantine.md/.json. Two kept-but-flagged metadata booleans:reactive:true(15 rows),iridized:true(162 shipped rows).Scale audit layer (commit 65d3feb)
Bullseye galleries share one photo set across cart sizes; the builder stamped the cart-size width (10in for
-1010) onto whichever gallery image was picked, but ~45% of picks are zoomed detail/macro crops covering a few inches — so those textures render 2-3x too coarse at physical scale (verified on 000100-0051-F, reproduced: SIFT_01→_03scale 0.31, 305 inliers)._02+ sub-2in macro_01). So the absolute long side is not pixel-recoverable —SAMPLE_LONG_IN=10.0inis a documented, globally-retunable assumption; every relative correction is independent of it. ← CTO calibration decision.real_world_{w,h}_in= the swatch IMAGE's footprint (inches/px the app needs), NOT the cart sale size — the exact conflation that caused the bug.null, 10 whole-sheet heights made aspect-consistent, 198needs_repick:true.iridized): 14 reflection-side picks + 91 transmission re-picks flagged (backlit preview needs the transmission/white side; never crop across a split backdrop seam).docs/library-picker-rebuild/scale_audit.json(per-product method+confidence sidecar),scale_report.md,scale_boards/(~35 examples incl. failures),scripts/scale_audit.py(+scale_audit_lib.py, idempotent).GlassLibraryDialog.tsxmade null-safe (fallback width + "scale TBD"). Gallery image cache is gitignored (no large binaries; boards downscaled to ~1.3MB total).preferred_gallery_image()inbuild_swatch_library.pyencodes the measured-better rule, gatedSCALE_AWARE_REPICK=Falseuntil image hosting lands (re-picking regenerates gitignoredcatalog_imagescrops — the exact gap that forced the library: exclude unfired strikers (pre-struck exception) + striker schema #141 revert).Known limitations (honest)
node_modules); the change is a minimal, null-safe type widening + fallback.Checklist footnotes
SCALE_AWARE_REPICK) + clearing the 198needs_repickrows is part of image hosting (re-picking regenerates gitignored crops).SAMPLE_LONG_IN=10.0inis an assumption; retune the single constant at final review if a physical reference lands.GlassLibraryDialog.tsxchange is deferred to final review (no node_modules in the audit worktree).🤖 Generated with Claude Code