← All releases · how each check lane last ran
What we test
Every automated check and every browser journey in the CROP storefront,
grouped by the part of the product it protects. Each entry is the sentence its author
wrote for it, so the list reads as behaviour rather than as code.
chore/ct-navconfig-stale-comment @ c2d4cefbc · generated 2026-08-28 11:03 UTC
✓passed just now
✗failing
−deliberately skipped
○listed here, run by CI against a live site
Checks passing11,446
Browser journeys551
Code exercised76.74%
Decision paths68.7%
What this release changes
Production today (main (production) @ 137e97ed2)
against the release candidate, measured by the same method on both sides.
Automated checks+517
Browser journeys−6
Behaviour groups+125
Code exercised+1.4pp
| Where it changed | Checks | Journeys | Code exercised |
| Diagrams & assemblies178 of these arrived by reorganisation — existing checks whose code changed address, not new ones |
+221 |
±0 |
−1.6 pp |
| Equipment & whole goods186 left by reorganisation — they now count under another area, none were deleted |
−149 |
±0 |
+1.8 pp |
| Google visibilityNew: robots.ts — noindexed-but-linked routes stay fetchable (#3887) · shippingForJsonLd eligibility across the real shapes · +19 more |
+109 |
+2 |
−0.4 pp |
| Shared building blocksNew: /value-your-trade (#3871) · /credit-app (#3871) · +14 more |
+67 |
−2 |
+1.5 pp |
| Catalogue & browsingNew: matchCarriedBrand · /equipment listing — /parts design parity (#3871) · +17 more |
+64 |
±0 |
−0.1 pp |
| Product pageNew: buildPdpMetaFields — CROP-front#3302 the <title> keeps both the PN and the brand under truncation · _pdp-route.tsx wiring · +6 more |
+11 |
−4 |
+2 pp |
| Cart & checkoutNew: failure classification · TrackPurchase · +8 more |
+36 |
−1 |
+6 pp |
| Our own safety netsNew: main-required-contexts.json tracks real ci.yml jobs · next.config.ts redirects() — apex migration map (#3871) · +6 more |
+40 |
±0 |
— |
| Search & autocompleteNew: /api/search-service/resolve-part — href carries the index verdict · mapSearchServicePartToCatalog — lookupOnly (#3827/#3854) · +3 more |
+24 |
−1 |
+0.8 pp |
| Platform plumbingNew: materialiseRewrittenStatus · misconfiguration alarm · +4 more |
+22 |
+1 |
+3.2 pp |
| Orders & fulfilmentNew: loadOwnedOrder · quote actions — authentication gate · +3 more |
+30 |
±0 |
+2.1 pp |
| Images & mediaNew: the optimizer fetches the media origin, not our own edge (#3847) · one file resolves to one URL however it was spelled (#3816) · +2 more |
+20 |
−1 |
±0 pp |
| Internal admin toolsNew: payload handling · auth · +1 more |
+18 |
±0 |
+1.8 pp |
| Shipping & deliveryNew: deriveShippingPath (PG-only, front#598 / ct-3184) |
+2 |
±0 |
−0.1 pp |
| Sign-in & account |
+2 |
±0 |
+0.1 pp |
By part of the product
Automated checks2,137
Browser journeys84
Code exercised82.2%
What we check automatically333 groups
✓LOCAL_BRAND_TYPE_IMAGE_* — every alias/rule target exists on diskEquipment data81
- ✓/new-holland/equipment-types/harvesters.webp exists under public/
- ✓/kuhn/equipment-types/tillage.webp exists under public/
- ✓/kuhn/equipment-types/plows.webp exists under public/
- ✓/kuhn/equipment-types/seeding.webp exists under public/
- ✓/kuhn/equipment-types/spraying.webp exists under public/
- ✓/kuhn/equipment-types/fertilization.webp exists under public/
- ✓/kuhn/equipment-types/spreaders.webp exists under public/
- ✓/kuhn/equipment-types/balers.webp exists under public/
- ✓/kuhn/equipment-types/bale-wrappers.webp exists under public/
- ✓/kuhn/equipment-types/forage-harvesters.webp exists under public/
- ✓/kuhn/equipment-types/hay-forage.webp exists under public/
- ✓/kuhn/equipment-types/feed-mixers.webp exists under public/
- ✓/kuhn/equipment-types/shredders.webp exists under public/
- ✓/kuhn/equipment-types/landscape-maintenance.webp exists under public/
- ✓/mchale/equipment-types/fusion.webp exists under public/
- ✓/mchale/equipment-types/fixed-chamber-round-balers.webp exists under public/
- ✓/mchale/equipment-types/variable-chamber-round-balers.webp exists under public/
- ✓/mchale/equipment-types/round-bale-wrappers.webp exists under public/
- ✓/mchale/equipment-types/square-bale-wrappers.webp exists under public/
- ✓/mchale/equipment-types/handling-equipment.webp exists under public/
- ✓/mchale/equipment-types/disc-mowers.webp exists under public/
- ✓/mchale/equipment-types/accessories.webp exists under public/
- ✓/mchale/equipment-types/rake-range.webp exists under public/
- ✓/mchale/equipment-types/propel-tedders.webp exists under public/
- ✓/mchale/equipment-types/straw-blower-bale-feeder.webp exists under public/
- ✓/agco/equipment-types/tractors.webp exists under public/
- ✓/agco/equipment-types/hay-equipment.webp exists under public/
- ✓/agco/equipment-types/harvesting.webp exists under public/
- ✓/agco/equipment-types/seeding.webp exists under public/
- ✓/agco/equipment-types/applicators.webp exists under public/
- ✓/agco/equipment-types/grounds-care-equipment.webp exists under public/
- ✓/agco/equipment-types/tillage.webp exists under public/
- ✓/agco/equipment-types/material-handling.webp exists under public/
- ✓/marcrest/equipment-types/bale-baron.webp exists under public/
- ✓/marcrest/equipment-types/bale-handling.webp exists under public/
- ✓/marcrest/equipment-types/power-linx.webp exists under public/
- ✓/marcrest/equipment-types/baler.webp exists under public/
- ✓/kress/equipment-types/attachments-accessories.webp exists under public/
- ✓/kress/equipment-types/battery-tools.webp exists under public/
- ✓/kress/equipment-types/commercial-battery-tools.webp exists under public/
- ✓/kress/equipment-types/power-stations-cabinets.webp exists under public/
- ✓/kress/equipment-types/robotic-mowers.webp exists under public/
- ✓/ferris/equipment-types/front-mount.webp exists under public/
- ✓/ferris/equipment-types/attachments.webp exists under public/
- ✓/ferris/equipment-types/walk-behind.webp exists under public/
- ✓/ferris/equipment-types/zero-turn.webp exists under public/
- ✓/ferris/equipment-types/trim-mower.webp exists under public/
- ✓/ferris/equipment-types/spreader-sprayer.webp exists under public/
- ✓/ferris/equipment-types/blowers.webp exists under public/
- ✓/ferris/equipment-types/standby-generator.webp exists under public/
- ✓/ferris/equipment-types/grass-collection.webp exists under public/
- ✓/ferris/equipment-types/snow-blade.webp exists under public/
- ✓/ferris/equipment-types/sulky.webp exists under public/
- ✓/ferris/equipment-types/service-jack.webp exists under public/
- ✓/ferris/equipment-types/mulch-kit.webp exists under public/
- ✓/ferris/equipment-types/wheel-tire.webp exists under public/
- ✓/landoll/equipment-types/tillage.webp exists under public/
- ✓/landoll/equipment-types/harrow-and-packers.webp exists under public/
- ✓/landoll/equipment-types/grain-drill.webp exists under public/
- ✓/brillion/equipment-types/harrow-and-packers.webp exists under public/
- ✓/brillion/equipment-types/tillage.webp exists under public/
- ✓/ventrac/equipment-types/tough-cut-mower.webp exists under public/
- ✓/ventrac/equipment-types/flail-mower.webp exists under public/
- ✓/ventrac/equipment-types/boom-mower.webp exists under public/
- ✓/ventrac/equipment-types/snow-blower.webp exists under public/
- ✓/ventrac/equipment-types/snow-removal.webp exists under public/
- ✓/ventrac/equipment-types/broom.webp exists under public/
- ✓/ventrac/equipment-types/brush-cutter.webp exists under public/
- ✓/ventrac/equipment-types/turf-mowers.webp exists under public/
- ✓/ventrac/equipment-types/aerator.webp exists under public/
- ✓/ventrac/equipment-types/stump-grinder.webp exists under public/
- ✓/ventrac/equipment-types/trencher.webp exists under public/
- ✓/ventrac/equipment-types/power-rake.webp exists under public/
- ✓/ventrac/equipment-types/tiller.webp exists under public/
- ✓/ventrac/equipment-types/turbine-blower.webp exists under public/
- ✓/ventrac/equipment-types/edger.webp exists under public/
- ✓/ventrac/equipment-types/generator.webp exists under public/
- ✓/ventrac/equipment-types/weedbine.webp exists under public/
- ✓/ventrac/equipment-types/spreader.webp exists under public/
- ✓/ventrac/equipment-types/loader.webp exists under public/
- ✓/ventrac/equipment-types/tractor.webp exists under public/
✓getBrandTypeImageSrcEquipment data57
- ✓returns the brand path when the brand has an allowlist entry for the slug
- ✓falls back to the global map when the brand has equipmentImageKeyPrefix but no allowlist hit
- ✓serves the repo-local NH equipment-type cutouts we ship in public/
- ✓falls back to the global map when an empty-allowlist brand has no local tile
- ✓prefers a repo-local brand cutout over the bucket + global map
- ✓serves the NH flagship-combine cutout for the harvesters tile
- ✓resolves Landoll live equipment-types to their shipped local tiles (#2661)
- ✓serves the repo-local Brillion category cutout for harrow-and-packers (#2661)
- ✓serves the repo-local Brillion category cutout for tillage (#2661)
- ✓serves the repo-local Brillion category cutout for HARROW AND PACKERS (#2661)
- ✓serves the repo-local Brillion category cutout for TILLAGE (#2661)
- ✓never lets Brillion and Landoll borrow each other's tillage tile (#2644)
- ✓never lets Brillion and Landoll borrow each other's harrow-and-packers tile (#2644)
- ✓resolves McHale Our-Range categoryIds to their shipped local cutouts (#2571)
- ✓binds the three Kuhn labels whose live slug diverged from the authored key (#2658)
- ✓suppresses the global fallback for an adapter brand (no image program) with no local cutout
- ✓serves the repo-local Marcrest category cutout for bale-baron
- ✓serves the repo-local Marcrest category cutout for bale-handling
- ✓serves the repo-local Marcrest category cutout for power-linx
- ✓serves the repo-local Marcrest category cutout for baler
- ✓serves the repo-local Kress category tile for attachments-accessories (#2531/#2550)
- ✓serves the repo-local Kress category tile for battery-tools (#2531/#2550)
- ✓serves the repo-local Kress category tile for commercial-battery-tools (#2531/#2550)
- ✓serves the repo-local Kress category tile for power-stations-cabinets (#2531/#2550)
- ✓serves the repo-local Kress category tile for robotic-mowers (#2531/#2550)
- ✓serves the repo-local AGCO Browse-by-Type cutout for tractors (#2642)
- ✓serves the repo-local AGCO Browse-by-Type cutout for hay-equipment (#2642)
- ✓serves the repo-local AGCO Browse-by-Type cutout for harvesting (#2642)
- ✓serves the repo-local AGCO Browse-by-Type cutout for seeding (#2642)
- ✓serves the repo-local AGCO Browse-by-Type cutout for applicators (#2642)
- ✓serves the repo-local AGCO Browse-by-Type cutout for grounds-care-equipment (#2642)
- ✓serves the repo-local AGCO Browse-by-Type cutout for tillage (#2642)
- ✓serves the repo-local AGCO Browse-by-Type cutout for material-handling (#2642)
- ✓suppresses the global NH art on AGCO's unbound category forage (#2642)
- ✓suppresses the global NH art on AGCO's unbound category feeding (#2642)
- ✓suppresses the global NH art on AGCO's unbound category miscellaneous (#2642)
- ✓suppresses the global NH art on AGCO's unbound category special-application (#2642)
- ✓binds AGCO Tillage to AGCO's own cutout, never the global NH plough (#2660)
- ✓falls back to the global map when brandSlug is undefined
- ✓falls back to the global map when the brand slug is not in the registry
- ✓returns null when neither the brand path nor the global map has the type slug
- ✓normalizes brandSlug to lowercase before registry and manifest lookup
- ✓parity invariant — getBrandTypeImageSrc(undefined, tractors) === getTypeImageSrc(undefined)
- ✓parity invariant — getBrandTypeImageSrc(undefined, tillage) === getTypeImageSrc(undefined)
- ✓parity invariant — getBrandTypeImageSrc(undefined, loaders) === getTypeImageSrc(undefined)
- ✓parity invariant — getBrandTypeImageSrc(undefined, commercial-mowers) === getTypeImageSrc(undefined)
- ✓parity invariant — getBrandTypeImageSrc(undefined, harvesters) === getTypeImageSrc(undefined)
- ✓parity invariant — getBrandTypeImageSrc(undefined, forage) === getTypeImageSrc(undefined)
- ✓parity invariant — getBrandTypeImageSrc(undefined, construction) === getTypeImageSrc(undefined)
- ✓parity invariant — getBrandTypeImageSrc(undefined, mowers) === getTypeImageSrc(undefined)
- ✓parity invariant — getBrandTypeImageSrc(undefined, balers) === getTypeImageSrc(undefined)
- ✓parity invariant — getBrandTypeImageSrc(undefined, hay-tools) === getTypeImageSrc(undefined)
- ✓parity invariant — getBrandTypeImageSrc(undefined, planting) === getTypeImageSrc(undefined)
- ✓parity invariant — getBrandTypeImageSrc(undefined, sprayers) === getTypeImageSrc(undefined)
- ✓parity invariant — getBrandTypeImageSrc(undefined, made-up-slug) === getTypeImageSrc(undefined)
- ✓parity invariant — getBrandTypeImageSrc(undefined, does-not-exist) === getTypeImageSrc(undefined)
- ✓composes the brand path from registry equipmentImageKeyPrefix, not a hardcoded literal
✓handleBrandRoutingRequest routing43
- ✓renders the unified hub for an available brand — no diagrams 308 (ct-2047)
- ✓rewrites unknown brand to /brand-not-found with 404 + noindex
- ✓tolerates a trailing slash on the brand leaf
- ✓returns null for the bare /parts/brand hub (legacy-brand-hub-redirect handles it)
- ✓returns null when both brand and type resolve
- ✓rewrites unknown brand to /brand-not-found with 404 (no hono probe)
- ✓rewrites known brand + unknown type to /brand-not-found with 404
- ✓accepts a CE sub-category slug WITHOUT a hono probe
- ✓still 404s an unknown CE type via the hono probe (fallthrough preserved)
- ✓accepts a backend CE equipment type via the hono probe (no regression)
- ✓rewrites to /brand-not-found when hono returns 404 for a locally-known brand
- ✓falls through (returns null) on transient hono 5xx so the brand hub still renders
- ✓falls through (returns null) on network errors so the brand hub still renders
- ✓caches the type-list probe within the TTL window (single network call across requests)
- ✓returns null and skips the probe when SEARCH_SERVICE_URL is unset (fail-open env-misconfig)
- ✓returns null when both brand and type resolve
- ✓rewrites a known brand + unknown type to /brand-not-found with 404
- ✓rewrites an unknown brand to /brand-not-found with 404 (no hono probe)
- ✓leaves the NH Construction division alone, resolved sub-category or not
- ✓falls through when the type probe errors
- ✓ignores the bare diagrams tab
- ✓returns null for a valid categoryId, probing /categories (NOT equipment-types)
- ✓accepts a percent-encoded categoryId with spaces (MCH/VNT/MAR bug fix)
- ✓accepts the readable name-slug from the label, plus the raw id (#2325)
- ✓rewrites an unknown categoryId to /brand-not-found with 404
- ✓falls through (null) on a transient categories 5xx so the page still renders
- ✓308-redirects to the brand hub when the type segment is absent (#986)
- ✓308-redirects with a trailing slash too (#986)
- ✓renders the bare available brand hub (no diagrams 308)
- ✓does NOT redirect the /type leaf (it must keep rendering)
- ✓does NOT 308 a config-known but unavailable brand (no diagrams landing)
- ✓returns null for `/parts/{id}` leaves (handled by supersession-redirect)
- ✓returns null for `/parts` listing
- ✓returns null for `/equipment/...` paths (handled by model-routing)
- ✓returns null for deeper nested brand-paths the handler doesn't own
- ✓retries once on a 429 then resolves with the type list
- ✓retries exactly once then fails open (null) when both attempts error
- ✓does NOT retry on a definitive 404 (real not-found is a single probe)
- ✓does NOT retry when the first attempt already succeeds
- ✓emits a fail-open breadcrumb tagged 'brand-types' after the retry errors
- ✓retries once on a transient 503 then resolves the categories
- ✓retries exactly once then fails open (null) on persistent transient errors
- ✓emits a fail-open breadcrumb tagged 'brand-categories' after the retry errors
✓legacy accessors delegate to the registry (round-trip equivalence)Equipment data39
- ✓humaniseBrand(nhl) === New Holland
- ✓humaniseBrand(new-holland) === New Holland
- ✓humaniseBrand(new-holland-agriculture) === New Holland
- ✓humaniseBrand(frr) === Ferris
- ✓humaniseBrand(ferris) === Ferris
- ✓humaniseBrand(vnt) === Ventrac
- ✓humaniseBrand(ventrac) === Ventrac
- ✓humaniseBrand(mch) === McHale
- ✓humaniseBrand(mchale) === McHale
- ✓humaniseBrand(mar) === Marcrest
- ✓humaniseBrand(marcrest) === Marcrest
- ✓humaniseBrand(kuh) === Kuhn
- ✓humaniseBrand(kuhn) === Kuhn
- ✓humaniseBrand(kre) === Kress
- ✓humaniseBrand(kress) === Kress
- ✓getVendorDisplayName(NHL) === New Holland
- ✓getVendorDisplayName(FER) === Ferris
- ✓getVendorDisplayName(VNT) === Ventrac
- ✓getVendorDisplayName(MCH) === McHale
- ✓getVendorDisplayName(MAR) === Marcrest
- ✓getVendorDisplayName(KUH) === Kuhn
- ✓getVendorDisplayName(KRE) === Kress
- ✓does not absorb CNH into New Holland
- ✓getBrandBranding(new-holland).accent === #003f7d
- ✓getBrandBranding(new-holland-agriculture).accent === #003f7d
- ✓getBrandBranding(newhollandagriculture).accent === #003f7d
- ✓getBrandBranding(ferris).accent === #9e2432
- ✓getBrandBranding(ventrac).accent === #b50938
- ✓getBrandBranding(mchale).accent === #007d61
- ✓getBrandBranding(marcrest).accent === #414042
- ✓getBrandBranding(kuhn).accent === #e42317
- ✓getBrandBranding(kress).accent === #8d100c
- ✓formatProviderLabel(new-holland) === New Holland
- ✓formatProviderLabel(ferris) === Ferris
- ✓formatProviderLabel(ventrac) === Ventrac
- ✓formatProviderLabel(mchale) === McHale
- ✓formatProviderLabel(marcrest) === Marcrest
- ✓formatProviderLabel(kuhn) === Kuhn
- ✓formatProviderLabel(kress) === Kress
✓shouldNoIndexListingGoogle visibility35
- ✓main listing → index
- ✓search query → noindex
- ✓single category → index
- ✓single manufacturer → index
- ✓multiple manufacturers → noindex
- ✓category + manufacturer → noindex (multi-primary)
- ✓sortBy non-default → noindex (secondary filter)
- ✓category + availability → noindex (has secondary)
- ✓category + pagination → index (page is not secondary)
- ✓base pagination → index
- ✓page 1 → index
- ✓page at the cutoff (5) → still index
- ✓first page past the cutoff (6) → noindex
- ✓deep tail (page 100) → noindex
- ✓applies to a filtered listing too
- ✓priceMin filter → noindex
- ✓inStock filter → noindex
- ✓shipsSameDay filter → noindex
- ✓hasReviews filter → noindex
- ✓empty manufacturer strings → index (treated as no manufacturer)
- ✓category + invalid sortBy=newest in URL → noindex
- ✓category + valid sortBy=price_asc in URL → noindex (regression guard)
- ✓category + availability key in URL (any value) → noindex
- ✓category + priceMin key in URL → noindex
- ✓category + shipsSameDay key in URL → noindex
- ✓category + hasReviews key in URL → noindex
- ✓view key in URL → noindex, and the cross-URL canonical is dropped
- ✓pageSize key in URL → noindex (same display axis)
- ✓category alone in URL (no extras) → index
- ✓manufacturer alone in URL (no extras) → index
- ✓bare /parts (empty raw params) → index
- ✓category + page in URL → index (page is canonical)
- ✓manufacturer + invalid sortBy=newest in URL → noindex
- ✓unknown URL key (e.g. utm_source) → does NOT noindex (analytics ignored)
- ✓category + q (search) in URL → noindex (search forces noindex)
✓CatalogPaginationInterface pieces30
- ✓renders nothing when totalPages is 0
- ✓renders nothing when totalPages is 1
- ✓renders all pages when total fits the window (5 pages)
- ✓current page at start of long list — shows [1] 2 3 … last
- ✓current page in middle — shows 1 … N-1 [N] N+1 … last
- ✓current page at end of long list — shows 1 … N-2 N-1 [N]
- ✓only marks the current page
- ✓Previous is aria-disabled on page 1
- ✓Next is aria-disabled on the last page
- ✓Previous is enabled past page 1
- ✓fires onPageChange(page) when a numbered page is clicked
- ✓fires onPageChange(currentPage+1) when Next is clicked
- ✓does NOT fire onPageChange when clicking Previous on page 1
- ✓does NOT fire onPageChange when disabled
- ✓renders anchors with hrefs built from pathname + page param
- ✓preserves extra query params on every page (assembly grid chapter filter)
- ✓preserves explicit empty-value query params (?chapter= = all chapters)
- ✓honours custom pageParam name
- ✓urlencodes special characters in query values
- ✓renders crawlable hrefs AND fires callback on plain click
- ✓Next link in hybrid mode carries href AND fires callback
- ✓modifier-key click does NOT run callback (lets browser open in new tab)
- ✓disabled hybrid does not fire callback even with valid href
- ✓hides numbered buttons when totalPages exceeds softThreshold
- ✓wraps in a navigation landmark with aria-label
- ✓renders summary line when pageSize + total provided
- ✓does not render summary line when pageSize/total missing
- ✓renders a Page X of Y label that is hidden ≥sm
- ✓respects siblingCount=2 to show ±2 around current
- ✓nav landmark contains both Prev and Next links
✓ActiveFiltersBarParts pages27
- ✓renders nothing when no active filters
- ✓renders manufacturer chip with resolved name
- ✓renders manufacturer chip with code if name not found
- ✓renders manufacturer chip when URL carries the slug form
- ✓renders category chip with name from facets
- ✓renders priceBucket chip for priced
- ✓renders priceBucket chip for contact
- ✓renders price range chip with min and max
- ✓renders price range chip with min only
- ✓renders price range chip with max only
- ✓renders hasImage chip
- ✓renders availability chip for in_stock
- ✓does not render a chip for the retired 'available' value (off-canon)
- ✓#2804 — renders availability chip for out_of_stock
- ✓#2804 — clearing the availability chip also retires the legacy inStock flag
- ✓renders shipsSameDay chip
- ✓clears shipsSameDay chip on remove
- ✓renders equipment model chip with vendor code
- ✓renders multiple equipment model chips
- ✓does not render search query as a filter chip
- ✓renders sort chip for name_asc
- ✓renders sort chip for pn_desc
- ✓renders Clear all button when filters active
- ✓calls clearAll when Clear all clicked
- ✓calls updateFilters when chip cleared
- ✓removing one of two manufacturer chips keeps the other
- ✓renders multiple chips when multiple filters active
✓buildListingCanonicalGoogle visibility26
- ✓main listing → /parts
- ✓search query → /parts
- ✓categoryId filter → preserves categoryId
- ✓categoryPath filter → preserves categoryPath
- ✓switcher brand (New Holland), any spelling → one brand-catalog path
- ✓multiple manufacturers → keeps first only (switcher first → its path)
- ✓non-switcher carried brand → keeps the ?manufacturer= vendor-code listing
- ✓unknown manufacturer falls through unchanged (no silent rewrite)
- ✓category + manufacturer → keeps category only
- ✓category + pagination → self-referencing canonical
- ✓base pagination → includes page
- ✓search + pagination → /parts (search overrides)
- ✓sortBy only → /parts (secondary stripped)
- ✓category + secondary → keeps category, strips secondary
- ✓search + category → /parts (search overrides)
- ✓empty manufacturer strings → treated as no manufacturer
- ✓explicit page=1 → omits page from canonical
- ✓categoryId with special chars → properly encoded
- ✓categoryPath + categoryId both set → categoryPath wins
- ✓non-switcher manufacturer + pagination → includes page, vendor code
- ✓switcher brand + pagination → brand-catalog path, page dropped
- ✓non-switcher manufacturer + secondary → strips page and secondary, vendor code
- ✓hasImage only → /parts (secondary filter)
- ✓shipsSameDay only → /parts (secondary filter stripped)
- ✓hasReviews only → /parts (secondary filter stripped)
- ✓category + secondary + pagination → strips page (secondary present)
✓catalogSearchParamsCache.parseCatalogue data26
- ✓returns defaults for empty params
- ✓parses page number
- ✓parses manufacturer as array
- ✓parses comma-separated manufacturers
- ✓parses categoryId
- ✓parses priceBucket
- ✓returns null for invalid priceBucket
- ✓parses boolean params
- ✓parses availability
- ✓returns null for invalid availability
- ✓returns null for the retired 'available' value (JD-2026-07-15)
- ✓parses price range
- ✓returns null for invalid price
- ✓parses sortBy
- ✓accepts sortBy=revenue (CT-674 T6)
- ✓defaults invalid sortBy to relevance
- ✓parses search query via q param
- ✓parses PIT params
- ✓preserves equipment params
- ✓parses comma-separated equipmentModelKey
- ✓parses the Browse-by-Type equipmentType slug (#2316)
- ✓does not recognise the legacy `equipment` key
- ✓defaults pageSize to 40
- ✓parses each allowed pageSize preset
- ✓falls back to default for out-of-range pageSize
- ✓falls back to default for non-numeric pageSize
✓<BrandHubTemplate>Brand pages26
- ✓wraps its hero in the page-SEO edit frame (staff can propose a better title + meta)
- ✓seeds an empty SEO description when the brand ships no intro
- ✓renders exactly one h1 carrying the brand heading
- ✓keeps the existing breadcrumb structure (Home / Brands / Name)
- ✓renders one branded hero banner — the logo lockup over the cover photo (NH-Construction pattern)
- ✓never renders parts-count or category-count copy (no counters on the hub)
- ✓renders the Shop {name} parts CTA and no diagrams CTA (#2832)
- ✓keeps the CTA on /parts?manufacturer for a non-brand-catalog brand (CNH)
- ✓routes wave-2 catalog vendors to the global catalog pre-filtered (front#1850)
- ✓renders an equipment-type card per live type, linking the Parts Store type route
- ✓renders every equipment-type card with the glass surface (matches the prototype .eq-card)
- ✓forwards brandSlug to every equipment-type card (per-brand image opt-in)
- ✓funnels the diagrams CTA into the canonical Explorer, not the demoted /parts-diagrams fork
- ✓renders the single all-models inlink to /parts-diagrams/models (#1195)
- ✓does NOT embed per-model parts-diagrams anchors inline (kept light, #1195)
- ✓omits the rich-only extras slot in the thin density
- ✓renders the rich-only extras slot when supplied — same skeleton, MORE sections
- ✓passes authored type subtitles when supplied (rich-density editorial content)
- ✓omits subtitles entirely when none are supplied (thin density)
- ✓never renders the Figma placeholder count on any brand
- ✓never renders the serial-search widget — for any brand, including New Holland
- ✓keeps the hero banner flush — no negative top margins anywhere on the hub
- ✓renders the vendor-pill switcher on the hub with the active brand marked
- ✓links sibling brands in the switcher to their own crawlable SSR hub
- ✓keeps exactly one brand mark in the page body — the switcher's are navigation
- ✓stays the All-categories surface for a type-less brand — no first-type default
✓BRAND_EDITORIAL — carried-brand intro copyEquipment data25
- ✓covers exactly the carried brands
- ✓new-holland-agriculture intro is non-empty and under 600 chars
- ✓ferris intro is non-empty and under 600 chars
- ✓ventrac intro is non-empty and under 600 chars
- ✓mchale intro is non-empty and under 600 chars
- ✓marcrest intro is non-empty and under 600 chars
- ✓kuhn intro is non-empty and under 600 chars
- ✓new-holland-agriculture intro has no carriage returns / placeholder count
- ✓ferris intro has no carriage returns / placeholder count
- ✓ventrac intro has no carriage returns / placeholder count
- ✓mchale intro has no carriage returns / placeholder count
- ✓marcrest intro has no carriage returns / placeholder count
- ✓kuhn intro has no carriage returns / placeholder count
- ✓new-holland-agriculture intro opens with the brand name (real designer copy)
- ✓ferris intro opens with the brand name (real designer copy)
- ✓ventrac intro opens with the brand name (real designer copy)
- ✓mchale intro opens with the brand name (real designer copy)
- ✓marcrest intro opens with the brand name (real designer copy)
- ✓kuhn intro opens with the brand name (real designer copy)
- ✓new-holland-agriculture intro ends with a complete sentence (no truncated clause)
- ✓ferris intro ends with a complete sentence (no truncated clause)
- ✓ventrac intro ends with a complete sentence (no truncated clause)
- ✓mchale intro ends with a complete sentence (no truncated clause)
- ✓marcrest intro ends with a complete sentence (no truncated clause)
- ✓kuhn intro ends with a complete sentence (no truncated clause)
✓TypeFirstDiagramsView — unified Brand Explorer (#2159)Diagram pages25
- ✓the bare co-located tab is the all-categories GRID, with no type preselected (#3224)
- ✓derives the rail with the Part tab's derivation, so the two tabs hold the same tiles
- ✓still resolves the CE construction deep link, which has no rail tile
- ✓drives the rail with the 'query' variant so 'All categories' clears in place (#2319)
- ✓the noindex ?category= drill omits the /equipment/models inlink and drills the chosen type
- ✓renders no Part/Diagram toggle of its own (new-holland-agriculture)
- ✓renders no Part/Diagram toggle of its own (kuhn)
- ✓leads with the brand breadcrumb and is full width — no max-w-page cap (#2204)
- ✓renders the Vendors switcher above the hero, active on this brand, linking siblings in place (#2250)
- ✓renders the Vendors switcher even when the brand serves no taxonomy yet (#2250)
- ✓marks the New Holland Construction pill active on the construction category (#2204)
- ✓keeps the Agriculture pill active on a non-construction category (#2204)
- ✓swaps the rail to the 6 CE sub-categories with in-hub /type/ PATH links when division-hosted
- ✓a valid CE sub scopes the construction grid to that sub and rings its tile (#2367)
- ✓an unknown CE sub keeps the full construction grid and rings nothing (#2367)
- ✓the standalone construction view (no storeHrefs) ignores ?sub= — not regressed
- ✓keeps the standalone construction view on its AG-type rail, never the CE subs
- ✓construction restamps subLine onto the NH subcategory so the Explorer sections by subcategory
- ✓a series URL yields STRICTLY FEWER models than the unfiltered type
- ✓two different series produce DIFFERENT model sets
- ✓an unknown ?series= falls back to the full type (no 404, no empty grid)
- ✓array-valued ?series= reads the first value (firstParam)
- ✓still paints the grid when the injected type has models
- ✓keeps the empty answer for a type the shopper reached by path
- ✓offers the division's own CE sub-categories, not the parent's AG types
✓FilterCategoryNavProduct grid23
- ✓renders all root categories without per-bucket counts
- ✓sorts root categories by count descending
- ✓highlights 'All categories' when no category selected
- ✓calls onChange(null) when clicking 'All categories'
- ✓calls onChange with category id on click
- ✓highlights selected root category in flat mode
- ✓does not highlight 'All categories' when a category is selected
- ✓shows drill-down when root category is selected
- ✓shows drill-down when sub-category is selected
- ✓highlights selected sub-category with brand pill
- ✓parent is always font-semibold in drill-down
- ✓sorts sub-categories by count descending
- ✓calls onChange(null) when clicking back button
- ✓calls onChange with parent id when clicking parent name
- ✓calls onChange with sub-category id when clicking sub-category
- ✓renders all categories as root when level is undefined
- ✓uses name as id fallback when id is undefined
- ✓shows drill-down with no children when flat root category is selected
- ✓renders only 'All categories' when categories is empty
- ✓filters out categories with count 0
- ✓disables all buttons when disabled prop is true
- ✓disables all buttons in drill-down view when disabled
- ✓renders no per-bucket count for any category magnitude
✓BRAND_REGISTRY — carried-brand source of truthEquipment data22
- ✓contains exactly the carried catalog brands (excluding division projections)
- ✓new-holland-agriculture record preserves slug / vendorCode / displayName / flags
- ✓ferris record preserves slug / vendorCode / displayName / flags
- ✓ventrac record preserves slug / vendorCode / displayName / flags
- ✓mchale record preserves slug / vendorCode / displayName / flags
- ✓marcrest record preserves slug / vendorCode / displayName / flags
- ✓kuhn record preserves slug / vendorCode / displayName / flags
- ✓kress record preserves slug / vendorCode / displayName / flags
- ✓landoll record preserves slug / vendorCode / displayName / flags
- ✓brillion record preserves slug / vendorCode / displayName / flags
- ✓agco record preserves slug / vendorCode / displayName / flags
- ✓new-holland-agriculture record preserves branding (accent / logo / aspectRatio)
- ✓ferris record preserves branding (accent / logo / aspectRatio)
- ✓ventrac record preserves branding (accent / logo / aspectRatio)
- ✓mchale record preserves branding (accent / logo / aspectRatio)
- ✓marcrest record preserves branding (accent / logo / aspectRatio)
- ✓kuhn record preserves branding (accent / logo / aspectRatio)
- ✓kress record preserves branding (accent / logo / aspectRatio)
- ✓landoll record preserves branding (accent / logo / aspectRatio)
- ✓brillion record preserves branding (accent / logo / aspectRatio)
- ✓agco record preserves branding (accent / logo / aspectRatio)
- ✓reverse-resolves every carried brand by its registry vendorCode
✓groupEquipmentBucketsProduct grid22
- ✓groups buckets by brand code
- ✓sorts equipment brands by total docCount descending, BNS last
- ✓sorts models within brand by docCount descending
- ✓marks BNS as engine brand
- ✓computes correct totalDocCount per brand
- ✓resolves brand display name via getVendorDisplayName
- ✓creates correct modelKey format
- ✓filters by manufacturer selection
- ✓returns empty when filterBrands matches no equipment brand
- ✓filters by search query on model name
- ✓filters by search query on brand name
- ✓search is case-insensitive
- ✓returns empty array for search with no match
- ✓handles empty buckets
- ✓handles null filterBrands
- ✓handles empty searchQuery
- ✓applies filterBrands then searchQuery — combined filtering
- ✓returns empty when filterBrands matches but searchQuery does not
- ✓matches raw model code without spaces against formatted name
- ✓matches query with spaces against formatted model name
- ✓matches raw code against multi-segment formatted name
- ✓matches by brand code
✓brand [slug] page — metadataBrand pages20
- ✓New Holland serves the indexable Part catalog here: plain title, self path canonical, inherits index (#2367 Phase 1)
- ✓page 6 is noindex,follow with its own canonical — noindex past the depth bound
- ✓page 1000 is noindex,follow with its own canonical — the page the paginator links as last, which answers 500 on prod
- ✓page 5 is the last indexable one and keeps the brand-page title order
- ✓emits robots: { index: false, follow: false } for non-NH brand mchale
- ✓emits robots: { index: false, follow: false } for non-NH brand ventrac
- ✓emits robots: { index: false, follow: false } for non-NH brand agco
- ✓emits robots: { index: false, follow: false } for non-NH brand hotsy
- ✓emits robots: { index: false, follow: false } for non-NH brand briggs-stratton
- ✓emits robots: { index: false, follow: false } for non-NH brand club-car
- ✓emits robots: { index: false, follow: false } for non-NH brand kawasaki
- ✓emits robots: { index: false, follow: false } for non-NH brand great-plains
- ✓emits robots: { index: false, follow: false } for non-NH brand harvest-tec
- ✓emits robots: { index: false, follow: false } for non-NH brand ag-bag
- ✓emits robots: { index: false, follow: false } for non-NH brand dion-ag
- ✓emits robots: { index: false, follow: false } for non-NH brand amco
- ✓emits robots: { index: false, follow: false } for non-NH brand hla
- ✓emits robots: { index: false, follow: false } for non-NH brand ez-trail
- ✓non-seo-indexed brand (mchale) gets noindex,nofollow via the config gate
- ✓calls notFound() for an unknown slug instead of returning a partial Metadata
✓adaptBrandBomPart (BrandAssemblyBomPart -> BomPart)Assembly views19
- ✓maps the shared identity fields straight across
- ✓preserves publishStatus and list price
- ✓renders a null qty as a dash so the shared Qty cell never shows null
- ✓keeps a present qty string verbatim
- ✓qty 2.00 normalizes to 2 (strips trailing all-zero fraction only)
- ✓qty 12.00 normalizes to 12 (strips trailing all-zero fraction only)
- ✓qty 2.50 normalizes to 2.50 (strips trailing all-zero fraction only)
- ✓qty 0.75 normalizes to 0.75 (strips trailing all-zero fraction only)
- ✓qty 2 normalizes to 2 (strips trailing all-zero fraction only)
- ✓passes currentReplacementPn through when present
- ✓leaves currentReplacementPn undefined when the source omits it
- ✓threads a non-null pdpHref through to the shared BomPart
- ✓threads a null pdpHref through (row with no resolvable PDP renders plain text)
- ✓leaves price undefined (not a 0-priced row) when Ferris sends no price
- ✓fills the CNH-only required fields with inert defaults (no kit/reman/availability)
- ✓maps a list of parts preserving order
- ✓forwards a populated imageUrl to the shared BomPart
- ✓treats a null imageUrl as absent (no empty src on the thumbnail)
- ✓collapses a null description to an empty string, not a placeholder glyph
✓<ModelCard>Brand pages19
- ✓links to href and renders the model name and mono code
- ✓renders a pluralized diagram count pill
- ✓renders the singular form for exactly one diagram
- ✓renders a zero-count pill for models with no diagrams
- ✓exposes a data-search attribute from searchKey for client filtering
- ✓omits the data-search attribute when no searchKey is given
- ✓forwards a custom className to the root link
- ✓provides a descriptive aria-label combining name and diagram count
- ✓defaults to the oem-accented variant
- ✓variant='neutral' swaps the oem pill + hover border for muted tokens (bulk grid)
- ✓renders the icon placeholder when no imageUrl is provided
- ✓renders the icon placeholder for an explicit null imageUrl
- ✓renders the icon placeholder for an empty imageUrl
- ✓renders the preview image when imageUrl is set, with explicit width/height for CLS
- ✓hides the decorative preview image from assistive tech (link carries the name)
- ✓eager-loads the image when priority is set so it qualifies as an LCP candidate
- ✓lazy-loads the image by default so below-the-fold cards do not block LCP
- ✓renders a brand-aware placeholder (no Layers icon) when brandName is set and no image
- ✓keeps the generic Layers icon when no brandName is given (parts-diagrams callers)
✓buildPaginationNeighborPathsGoogle visibility19
- ✓page 1 of 5 → no prev, next is /parts?page=2
- ✓page 2 of 5 → prev is /parts (page 1 omits param), next is /parts?page=3
- ✓bare browse /parts?page=2 stays indexable and keeps rel=prev (#2223 regression)
- ✓middle page → prev and next both populated
- ✓last page → prev populated, next is null
- ✓single-page result → no prev or next emitted
- ✓zero-totalPages (degraded backend) → both null
- ✓category filter preserved across pagination links
- ✓category filter, page 2 → prev drops the page param (page 1)
- ✓#2767 — switcher brand (New Holland) emits NO neighbours (canonical is /parts/brand/…)
- ✓non-switcher brand keeps neighbours in the query namespace, as vendor code
- ✓#2767 — canonical namespace and rel=next namespace always agree
- ✓#2766/#3040 — rel=next never points past the published cap
- ✓#3040 — the last INDEXABLE page still emits a next into the noindex tail
- ✓search query → no prev/next (noindex page should not signal pagination)
- ✓multi-manufacturer combo → no prev/next (noindex)
- ✓category + manufacturer combo → no prev/next (multi-primary noindex)
- ✓secondary filter active → no prev/next (noindex)
- ✓invalid sortBy=newest in URL → no prev/next (noindex)
✓/brands (two-tier directory)Site pages18
- ✓renders the dark hero h1 and the contact card
- ✓opens the brand grid with a "Choose your brand" lead-in (#1831)
- ✓deep-links each resolvable brand tile to its flagship type listing
- ✓routes the ferris tile to its flagship type listing (ct-2204)
- ✓routes the ventrac tile to its flagship type listing (ct-2204)
- ✓routes the mchale tile to its flagship type listing (ct-2204)
- ✓routes the marcrest tile to its flagship type listing (ct-2204)
- ✓routes the kuhn tile to its flagship type listing (ct-2204)
- ✓keeps NH Construction on its CE hub and fails soft to the hub for unresolved brands
- ✓surfaces the /new holland/i brand name
- ✓surfaces the /ferris/i brand name
- ✓surfaces the /ventrac/i brand name
- ✓surfaces the /mchale/i brand name
- ✓renders all six carried tiles as flagship cards with their cover photos
- ✓uses the distinct New Holland Construction lockup on the construction tile
- ✓no longer renders the Diagrams / Parts store journey chips on tiles (John, #2053)
- ✓never renders a parts count line on any tile
- ✓carries brand-neutral metadata, not a New-Holland-only title
✓FilterDrawerProduct grid18
- ✓renders title, sections, and live total in footer
- ✓hides the Brand section when the brand axis is unsupported (brand-scoped listing)
- ✓JD-2026-07-15 — mobile availability is a 2-status radio (All + In Stock + Out of Stock)
- ✓#2793 — hides Availability/ShipsSameDay/Price sections when their axes are unsupported
- ✓#2793 — renders Availability/ShipsSameDay/Price when axes are supported (default)
- ✓opens/closes via the open prop (onOpenChange called by X)
- ✓toggles a brand in local state without leaking before Apply
- ✓on Apply diffs and closes the drawer
- ✓picking a brand-catalog vendor drops an active CNH brand (exclusive) on Apply
- ✓Clear calls onClear and does not close the drawer
- ✓reflects total prop updates in the apply CTA
- ✓Apply with no changes emits an empty diff
- ✓the In stock radio maps to availability=in_stock, not the legacy flag (#2223)
- ✓the Out of Stock radio emits availability=out_of_stock
- ✓the Ships same day toggle emits shipsSameDay=true
- ✓selecting All clears an active availability=in_stock
- ✓reflects an active availability=in_stock as the checked radio
- ✓#2804(c) — folds a legacy inStock=true bookmark into the In Stock radio
✓MediaPlaceholderProduct grid18
- ✓renders the sm placeholder with the mono OEM code and PN tag
- ✓omits the PN tag at sm when partNumber is missing
- ✓falls back to OEM when no manufacturer code is supplied at sm
- ✓renders the md placeholder with a brand-wordmark slot and PN tag
- ✓omits the PN tag at md when showPartNumber is false
- ✓renders the mono-code fallback at md when no manufacturerCode is supplied
- ✓renders the accent text tier when a manufacturerCode has no logo asset
- ✓stamps data-brand and tints the sm code with the brand accent
- ✓stamps data-brand on md and hero tiers
- ✓renders the hero placeholder with CT badge and honest copy
- ✓drops role=img and hides an empty-alt part placeholder from the a11y tree
- ✓keeps a labelled role=img when alt is non-empty
- ✓renders Package icon and label
- ✓hides labels at size=sm by default
- ✓shows labels at size=sm when showLabel is forced
- ✓renders ImageOff icon and label
- ✓applies caller-provided className
- ✓renders the branded wordmark placeholder when a manufacturer code is given
✓brand hub scope B — editorial config (#1703)Equipment data17
- ✓registers every carried brand hub
- ✓Kuhn uses live-only equipment cards (no authored overlay) with a dealer story (ct-2003)
- ✓Ventrac uses live-only equipment cards (authored folds were non-round-trippable)
- ✓ferris has a dealer story
- ✓ventrac has a dealer story
- ✓marcrest has a dealer story
- ✓marcrest uses authored-fallback equipment cards
- ✓Ferris keeps authored-fallback mode and maintenance categories
- ✓Ferris rotates the shared carousel across real cover photos on disk within LCP budget (#2554)
- ✓Kress rotates the shared carousel across real cover photos on disk within LCP budget (#2554)
- ✓McHale rotates the shared carousel across real cover photos on disk within LCP budget (#2554)
- ✓NH remains rich density with maintenance categories
- ✓NH (Agriculture) hub rotates the shared carousel from one slide source (#1936)
- ✓no brand config carries a featured rail (#1737 — hub minimalism)
- ✓Marcrest skeleton has three authored equipment cards (bale equipment, not grain carts)
- ✓McHale is live-only rich density — the hub grid tracks the live categoryIds (#2571)
- ✓McHale live-only: the hub grid is the live category list verbatim (#2571)
✓TypeDiagramsViewBrand pages17
- ✓renders one flat grid flagship-first and reports the scope total
- ✓mounts every model into one flat grid so search scans the whole type (#2340)
- ✓scopes the grid to the active ?series= and marks that series open in the rail (#2134)
- ✓links CNH model cards straight to the diagrams grid, not the detail page
- ✓links brand-catalog model cards into the diagrams journey by encoded modelCode
- ✓shows the family photo for a covered NH model and the type-category photo for an uncovered one (#2698)
- ✓shows the brand category card for McHale models on a type that ships a card
- ✓renders the left equipment-type rail: siblings link to their type page, 'All' returns to the unfiltered diagrams landing (#2134)
- ✓query variant: 'All categories' clears in place to the bare diagrams landing, not the hub (#2247)
- ✓discloses a brand-catalog category's series in the sidebar when the data carries sub-lines (#2159)
- ✓keeps a single ? when a series filter rides the in-place type link (#2159)
- ✓renders the Browse by Type tile row linking each sibling type page (#2134)
- ✓renders photoless authored-taxonomy tiles via allowPlaceholders and rings activeRailSlug (#2367/#2441)
- ✓omits Browse by Type when there is a single equipment type (nothing to switch to)
- ✓omits the rail when no equipment types are passed (legacy layout)
- ✓renders the tail past the first page as lite cards — no <img>, deferred URL, filter intact (#3160)
- ✓drops a schematic imageUrl and shows the McHale cutout, not the line drawing (#2067)
✓BrandAssemblyView (front#1429 Group B — shared stack, burned-in + Ferris caps)Diagram pages16
- ✓renders the shared SchematicViewer with zoom controls (gains zoom/pan)
- ✓burned-in: renders NO <text> callout labels (ARI numbers printed in image)
- ✓renders every BOM part through the shared table
- ✓Ferris caps: availability column present (#2830), branded PDP link, cart enabled
- ✓call_for_pricing row: price cell is the neutral dash — no tel CTA, no stock status (#2960)
- ✓clicking a hotspot highlights every BOM row sharing that ref
- ✓clicking a hotspot highlights every BOM row sharing that ref
- ✓links each BOM PN to its branded CT-KUH PDP (collision-safe, never bare PN)
- ✓burned-in: renders NO <text> callout labels (Kuhn numbers printed in image)
- ✓dedupes duplicate callout refs (CROP-hub position_order drift, like Marcrest)
- ✓dedupes duplicate callout refs for Marcrest only (#1853)
- ✓floored brand: each BOM row's availability, named row by row
- ✓no floor (undefined): availability stays the '-' placeholder, never In Stock
- ✓floor drives the chip only: a no-price row's price cell is the neutral dash (#2960)
- ✓priced rows read green 'In Stock' and NEVER 'Available to Order' (even with the relabel flag ON)
- ✓holds for Ferris and Ventrac (same in_stock floor, no per-brand fork)
✓<DiagramGroupSection>Diagram pages16
- ✓renders a section with the jump-target id 'g-<id>'
- ✓carries the data-group-section marker the filter walk targets
- ✓renders the group title
- ✓summarizes model and diagram counts when showCounts is true (default)
- ✓pluralizes a single model and a single diagram when counts are visible
- ✓hides the counts summary when showCounts=false (v3 layout — counts move to sidebar)
- ✓renders the model-grid children
- ✓is expanded by default (no data-collapsed attribute)
- ✓starts collapsed when defaultCollapsed is set
- ✓toggles data-collapsed when the header button is clicked
- ✓exposes expanded state to assistive tech via aria-expanded
- ✓syncs aria-expanded when data-collapsed is removed externally (jump/filter expand)
- ✓syncs aria-expanded when data-collapsed is added externally
- ✓suppresses the header but keeps the anchored grid + cards when hideHeader is set (#2105)
- ✓forces a hidden-header section open even when defaultCollapsed is set
- ✓ties the header to the grid region via aria-controls
✓/parts-diagrams/[brand]/[modelCode]/[assemblyCode] (front#1494)Diagram pages16
- ✓fetches the assembly, chapters and model assemblies for the brand + model
- ✓mounts the CNH chapter sidebar (AssemblyPageLayout) on the page
- ✓renders model-scoped prev/next AssemblyNav hrefs
- ✓renders the Brand > Model > Chapter > Assembly breadcrumb
- ✓renders the model header subtitle as '{chapter} · {n} parts'
- ✓renders the assembly BOM through the shared stack
- ✓404s when the brand is not a brand-routes brand
- ✓404s defensively when the modelCode segment is the literal 'assemblies'
- ✓404s when the assembly is not a member of the model's assembly list
- ✓404s when the model does not exist (assemblies fetch 4xx degrades to [])
- ✓404s when the model exists but has an empty assembly list
- ✓re-throws (does NOT 404) when the model-assemblies fetch fails transiently
- ✓404s when the assembly detail is unresolved (genuine 404 from hono)
- ✓emits a model-scoped canonical URL in metadata
- ✓resolves to a titled noindex page when the assembly fetch throws a 500
- ✓still 404s from generateMetadata when the assembly genuinely does not exist
✓<BrandIdentityCard>Brand pages15
- ✓renders the heading as the single h1
- ✓renders the brand lockup with the brand name
- ✓renders the subline node when provided
- ✓renders the intro paragraph when provided
- ✓renders the actions slot when provided
- ✓renders the aside slot when provided
- ✓renders the division when provided
- ✓forwards a logo override to the brand lockup (#1900)
- ✓renders cleanly with no subline, intro, actions, or aside
- ✓passes through a custom className on the root element
- ✓uses the prototype frosted-glass surface in the no-cover variant
- ✓uses the opaque cover surface (not glass) when a cover is present
- ✓lays the vendor cover photo over the top of the card when coverSrc is set
- ✓renders no cover markup when coverSrc is absent
- ✓keeps the heading as the single h1 with a cover present
✓FilterCheckboxGroupProduct grid15
- ✓renders all options
- ✓calls onChange with name and checked state
- ✓renders colored dot indicator
- ✓disables all checkboxes when disabled prop is true
- ✓does not call onChange when disabled
- ✓renders empty list when no options
- ✓renders option without dot when dot is not specified
- ✓renders a facet count when the option carries one
- ✓groups the thousands separator on a large count
- ✓renders a zero count rather than hiding it
- ✓renders no count element when the option has none
- ✓disables an option that would return nothing, and says why
- ✓leaves the option enabled when the count is unknown — fail open
- ✓never disables an option that is already on — the user must be able to undo it
- ✓the group-level disabled still wins over every option
✓FilterPriceRangeProduct grid15
- ✓renders min and max inputs
- ✓fires onMinChange on input
- ✓fires onMaxChange on input
- ✓hides clear button when showClear is false
- ✓shows clear button when showClear is true
- ✓calls onClear when clear button clicked
- ✓disables inputs when disabled prop is true
- ✓fires onMinBlur when min input loses focus
- ✓fires onMaxBlur when max input loses focus
- ✓displays provided min/max values
- ✓uses decimal inputMode for mobile keyboards
- ✓disables clear button when disabled
- ✓commits the min bound when Enter is pressed
- ✓commits the max bound when Enter is pressed
- ✓leaves the field alone for any other key
✓computeActiveFiltersCountCatalogue data15
- ✓returns 0 for default filters
- ✓counts manufacturer
- ✓counts categoryId
- ✓counts priceBucket
- ✓counts price range (priceMin or priceMax) as 1 filter
- ✓counts hasImage
- ✓counts availability
- ✓counts shipsSameDay
- ✓counts equipmentModelKey
- ✓does not count empty equipmentModelKey array
- ✓does not count sortBy (not a filter dimension)
- ✓does not count search (not a filter dimension)
- ✓counts all active filters together
- ✓does not count empty string manufacturer
- ✓does not count null priceBucket
✓<BrandScopePlate>Product grid14
- ✓renders the plate visual for known slug new-holland
- ✓renders the plate visual for known slug ventrac
- ✓renders the plate visual for known slug mchale
- ✓renders the plate visual for known slug case-ih
- ✓renders the plate visual for known slug bush-hog
- ✓falls back to a mono-3-letter pill when the slug has no logo asset
- ✓renders an <img> with the brand asset when one exists
- ✓calls onClearScope when the clear button is tapped
- ✓sets --cta as an inline style on the wrapper (not :root), keeping the override scoped
- ✓does not render the plate visual when slug is empty, but still renders children + wrapper
- ✓renders children verbatim inside the wrapper so the --cta override scopes them
- ✓renders the lineup tags and a '+ N more' badge when lineupTags overflow
- ✓includes the inStock count in the subline when provided
- ✓hides the plate visual on lg+ via lg:hidden
✓<PartCard>Brand pages14
- ✓links to href and renders the title
- ✓renders the part image with the given alt when imageUrl is provided
- ✓shows a No image placeholder when imageUrl is absent
- ✓renders the price label when provided
- ✓shows Out of Stock when no priceLabel is given (#2114)
- ✓shows Out of Stock when callForPricing is true even if a priceLabel exists (#2114)
- ✓renders a top-seller badge when topSeller is true
- ✓omits the top-seller badge by default
- ✓renders the brand name when provided
- ✓renders the model label when provided and no brand name
- ✓clamps long titles to two lines with a stable min-height
- ✓forwards a custom className to the root link
- ✓uses a glass surface when surface=glass (opt-in for the brand hub)
- ✓defaults to the flat card surface (schematic viewer + catalog unchanged)
✓brand-hub (front#1433, front#1617)Catalogue data13
- ✓carried brand new-holland-agriculture is still registered as carried
- ✓carried brand ferris is still registered as carried
- ✓carried brand ventrac is still registered as carried
- ✓carried brand mchale is still registered as carried
- ✓carried brand marcrest is still registered as carried
- ✓brand new-holland-agriculture has a shoppable parts listing
- ✓brand ferris has a shoppable parts listing
- ✓brand ventrac has a shoppable parts listing
- ✓brand mchale has a shoppable parts listing
- ✓brand marcrest has a shoppable parts listing
- ✓a slug outside the brand registry has NO parts store
- ✓non-carried slug kawasaki is not registered as carried
- ✓non-carried slug definitely-not-a-brand is not registered as carried
✓handleVanityBrandRedirectRequest routing13
- ✓redirects a bare switcher-brand slug to its moved top-level hub (#2367)
- ✓#2367 — vanity routes straight to the moved hub in a single hop
- ✓redirects a no-dash alias to the moved top-level hub (#2367)
- ✓redirects an adapter carried-brand slug to its moved top-level hub (#2367)
- ✓redirects /kuhn to its moved top-level hub (#2367)
- ✓redirects the NH Construction division to its moved hub too (#2367)
- ✓redirects briggs alias to briggs-stratton
- ✓is case-insensitive on the segment
- ✓tolerates a trailing slash
- ✓returns null for multi-segment paths
- ✓returns null for unknown slugs
- ✓returns null for reserved top-level routes
- ✓returns null for root and empty paths
✓CatalogChipRowProduct grid12
- ✓renders primary actions: Filter, In stock, view toggle, Sort
- ✓shows filter count badge when activeFiltersCount > 0
- ✓hides filter count badge when activeFiltersCount is 0
- ✓calls onOpenFilters when Filter pressed
- ✓calls onOpenSort when Sort chip pressed
- ✓flips in-stock when its chip is pressed
- ✓reflects in-stock active state via aria-pressed
- ✓renders active filter chips and removes them on click
- ✓renders the result count
- ✓keeps the count outside the horizontal scroller so it stays visible
- ✓renders exactly one sort control
- ✓forwards view-toggle activation to onViewChange
✓brand-page cover banner — coverImageSrc (#1529)Equipment data12
- ✓new-holland-agriculture exposes coverImageSrc from the bucket key new-holland/cover.jpg
- ✓ferris exposes coverImageSrc from the bucket key ferris/cover.jpg
- ✓ventrac exposes coverImageSrc from the bucket key ventrac/cover.jpg
- ✓mchale exposes coverImageSrc from the bucket key mchale/cover.jpg
- ✓marcrest exposes coverImageSrc from the bucket key marcrest/cover.jpg
- ✓kress exposes coverImageSrc from the bucket key kress/cover.jpg
- ✓brillion exposes coverImageSrc from the bucket key brillion/cover.jpg
- ✓agco exposes coverImageSrc from the bucket key agco/cover.jpg
- ✓landoll exposes coverImageSrc from the bucket key landoll/cover.jpg
- ✓every carried brand authors a cover — none falls back to the bare gradient (#2661)
- ✓every cover's in-repo source asset exists on disk (upload origin)
- ✓keeps coverImageSrc optional on the type
✓brand-type-image-manifest — asset existenceEquipment data12
- ✓new-holland-agriculture/balers resolves to a real file under public/
- ✓mchale/balers resolves to a real file under public/
- ✓mchale/mowers resolves to a real file under public/
- ✓mchale/wrappers resolves to a real file under public/
- ✓mchale/bale-handlers resolves to a real file under public/
- ✓mchale/accessories resolves to a real file under public/
- ✓new-holland-agriculture/balers is under the 300 KB LCP weight budget
- ✓mchale/balers is under the 300 KB LCP weight budget
- ✓mchale/mowers is under the 300 KB LCP weight budget
- ✓mchale/wrappers is under the 300 KB LCP weight budget
- ✓mchale/bale-handlers is under the 300 KB LCP weight budget
- ✓mchale/accessories is under the 300 KB LCP weight budget
✓handleLegacyBrandHubRedirectRequest routing12
- ✓redirects the old /parts/brand hub to /brands
- ✓redirects /parts/brand/ (trailing slash) to /brands
- ✓redirects the singular /brand alias to /brands
- ✓redirects the /manufacturers alias to /brands
- ✓redirects common variant /parts/brands to /brands
- ✓redirects common variant /parts-brand to /brands
- ✓redirects common variant /parts-brands to /brands
- ✓redirects common variant /manufacturer to /brands
- ✓redirects uppercase variants (single-hop for /PARTS/BRAND)
- ✓returns null for the canonical /brands target
- ✓returns null for per-brand hub URLs
- ✓returns null for unrelated paths
✓New Holland AG tiles — 0 icon fallbacksEquipment data12
- ✓declares the eleven AG equipment-type tiles
- ✓tractors (Tractors) resolves a real tile photo, not the icon fallback
- ✓tillage (Tillage) resolves a real tile photo, not the icon fallback
- ✓loaders (Loaders & Handlers) resolves a real tile photo, not the icon fallback
- ✓commercial-mowers (Lawn & Garden Mowers) resolves a real tile photo, not the icon fallback
- ✓harvesters (Combines & Harvesters) resolves a real tile photo, not the icon fallback
- ✓forage (Forage Equipment) resolves a real tile photo, not the icon fallback
- ✓mowers (Mowers) resolves a real tile photo, not the icon fallback
- ✓balers (Balers) resolves a real tile photo, not the icon fallback
- ✓hay-tools (Hay Tools) resolves a real tile photo, not the icon fallback
- ✓planting (Planting & Seeding) resolves a real tile photo, not the icon fallback
- ✓sprayers (Sprayers) resolves a real tile photo, not the icon fallback
✓resolvePartsDiagramsBrand (front#1398, ct-2065)Catalogue data11
- ✓resolves New Holland to the type-first view via the equipment-type-diagrams capability (not a slug literal)
- ✓resolves NH alias newholland through the same type-first decision onto the canonical slug
- ✓resolves NH alias new-holland through the same type-first decision onto the canonical slug
- ✓resolves Ferris to the brand-routes view carrying the vendor code
- ✓resolves ventrac to the brand-routes view carrying VNT
- ✓resolves mchale to the brand-routes view carrying MCH
- ✓resolves marcrest to the brand-routes view carrying MAR
- ✓resolves kuhn to the brand-routes view carrying KUH
- ✓404s an unknown brand slug
- ✓404s a config-known but non-available brand (briggs-stratton)
- ✓404s an empty / whitespace brand param
✓FilterEquipmentFitment — renderingProduct grid11
- ✓renders brand headers grouped by brand
- ✓renders BNS under Engines divider
- ✓renders model names within brand groups
- ✓renders 'All models' checkbox checked when no keys selected
- ✓renders 'All models' unchecked when keys are selected
- ✓shows 'Show more' button when brand has more than 5 models
- ✓shows 'No models found' when manufacturer filter yields no equipment brands
- ✓narrows to matching brands when manufacturer filter is set
- ✓disables all checkboxes when disabled prop is true
- ✓renders search input
- ✓renders no per-model part counts (no-counters rule)
✓BrandCarouselHero (#1848 / ct-2163)Brand pages10
- ✓renders the brand identity: lockup mark, single h1, and subline
- ✓rotates a photo per slide as the cover
- ✓exposes the rotating region as an accessibly-named carousel
- ✓carries no in-hero action buttons (return lives in the breadcrumbs + brand strip)
- ✓renders one position dot per slide, first current
- ✓starts autoplay when the client allows motion
- ✓skips play()/stop() until Embla initialises (emblaApi undefined) — #2853 crash guard
- ✓never autoplays under prefers-reduced-motion (identity + nav still render)
- ✓renders the lede paragraph between the heading and the counts
- ✓paints a static fallback (no carousel chrome, no autoplay) with no slides
✓resolveTireBrandCatalogue data10
- ✓resolves brand name from specifications.Brand
- ✓returns correct GCP logo URL for known brand
- ✓returns null logoUrl for unknown brand
- ✓falls back to manufacturer.name when Brand is missing
- ✓falls back to manufacturer.name when Brand is not a string
- ✓trims whitespace from Brand value
- ✓falls back when Brand is empty string
- ✓falls back when Brand is whitespace-only
- ✓returns "Unknown" when no brand or manufacturer
- ✓handles missing specifications entirely
✓FilterRadioGroupProduct grid10
- ✓renders all options
- ✓calls onChange with selected value
- ✓displays count badge
- ✓deselects active item when allowDeselect is true
- ✓does not deselect when allowDeselect is false
- ✓applies active styling to selected option
- ✓renders with radiogroup role
- ✓renders radio buttons with correct aria-checked
- ✓navigates with arrow keys
- ✓wraps around from last to first on ArrowDown
✓/parts/brand/[slug]/diagrams — co-located Diagram tab (#2367)Brand pages10
- ✓renders a model-group brand (McHale) through the shared body, header-suppressed, switcher wired to the hub
- ✓renders the model-group body for ferris (uniform across the adapter cohort)
- ✓renders the model-group body for ventrac (uniform across the adapter cohort)
- ✓renders the model-group body for marcrest (uniform across the adapter cohort)
- ✓renders the model-group body for kuhn (uniform across the adapter cohort)
- ✓renders the model-group body for agco (uniform across the adapter cohort)
- ✓routes New Holland to the type-first body, header-suppressed, switcher wired to the hub
- ✓resolves the legacy new-holland alias onto the canonical AG surface (outputs stay canonical)
- ✓hosts the NH Construction division on the parent type-first body, scoped to construction
- ✓404s an unknown brand
✓buildSeriesGroupsBrand pages10
- ✓groups by subLine, humanizes labels, and trails the blank-subLine Other bucket
- ✓folds a one-off sub_line (single model) into Other, keeping it reachable
- ✓humanizes labels: title-cases families, keeps short codes uppercase
- ✓treats whitespace-only subLine as Other
- ✓preserves the backend model order within a group (no client re-sort)
- ✓orders series by backend appearance (flagship-first), not by model count
- ✓sums diagramCount (assemblyCount) per section
- ✓expands the first group and collapses groups once the initial paint budget is filled
- ✓keeps every group expanded when the total fits in the paint budget
- ✓returns nothing for an empty model list
✓<TypePageBrowseRail> photo gating (#2441)Brand pages10
- ✓drops photoless types by default (diagrams photo-curation), hiding the rail when <2 remain
- ✓with allowPlaceholders, renders every type with the branded placeholder (photoless carried brands)
- ✓pluralizes the model-count line by count (1 model vs 2 models)
- ✓omits the model-count line for 0-count curated tiles (Landoll pre-data, #2682)
- ✓co-located hub base → `/parts/brand/{slug}/diagrams/type/{slug}` path
- ✓standalone landing base → `?category=` query, unchanged
- ✓a tile's own href (NHC `?sub=`) wins over the variant resolver
- ✓renders the real photo (not the placeholder) for a type that has a cutout asset
- ✓does not wrap any tile image in the edit frame by default (customer/SSR unchanged)
- ✓wraps each tile image in the edit frame with the per-brand+type category context when enabled
✓<ProductTile>Product grid9
- ✓links the PDP from the title alone, with nothing nested in the anchor (#3556)
- ✓falls back to the raw PN path when manufacturer code is missing (#1117)
- ✓renders the favorite button with a 44px tap target above the link layer
- ✓renders price, PN and stock state
- ✓renders real Clinton qty when clintonOnHand is present
- ✓shows no price or quote placeholder when price is missing (#1863)
- ✓renders Out of Stock when not on Clinton's shelf and no in-stock signal
- ✓renders In Stock for a guaranteed in_stock part off Clinton's shelf (#2518)
- ✓falls back to the branded placeholder when the tile image fails
✓<BrandIdentificationCard>Brand pages9
- ✓renders nothing when no image is provided (regression guard — no empty frame)
- ✓renders the 'How to identify your {brand}' title interpolated with the brand name
- ✓renders the plate image with the provided alt text
- ✓falls back to a descriptive default alt built from the brand name
- ✓renders the caption when provided
- ✓omits the caption paragraph when none is provided
- ✓uses the shared frosted-glass surface tokens
- ✓passes through a custom className on the root element
- ✓exposes the block as a labelled region landmark
✓<BrandLockup>Brand pages9
- ✓renders the brand logo image when an asset exists for the slug
- ✓renders an override logo when logoSrc is provided (NH Construction)
- ✓renders a monogram + wordmark fallback when no logo asset exists
- ✓derives the monogram from the first two alphabetic characters of the name
- ✓renders the division as a small tag when provided
- ✓omits the division tag when not provided
- ✓drops the framed white box around the logo when frameless is set
- ✓logoMaxWidth raises BrandInlineLogo's default 100px width clamp (wide wordmarks)
- ✓passes through a custom className on the root element
✓<HubNavFork>Brand pages9
- ✓renders the shop card with the correct href and accessible name
- ✓renders nothing when the brand has no shoppable listing
- ✓carries no diagrams CTA (#2832 — retired in favour of the Equipment Types grid)
- ✓injects the brand name into the shop descriptor
- ✓emits no parts-count copy (brand-hub hard rule)
- ✓carries GA4 telemetry attributes, honoring a custom ga4Source
- ✓defaults the GA4 source to brand-hub
- ✓renders no heading element so the page's single h1 stays in the identity card
- ✓labels the fork as a navigation landmark
✓usesEquipmentTypeDiagramsEquipment data9
- ✓returns true for New Holland (carried, search MV, no brand-routes adapter)
- ✓normalizes legacy short codes and casing for New Holland
- ✓returns false for the brand-routes adapter vendor FER
- ✓returns false for the brand-routes adapter vendor MCH
- ✓returns false for the brand-routes adapter vendor VNT
- ✓returns false for the brand-routes adapter vendor MAR
- ✓returns false for the brand-routes adapter vendor KUH
- ✓returns false for an unknown / non-carried vendor
- ✓returns false for an empty / nullish code
✓brand-type-image-manifest — bidirectional registry integrityEquipment data9
- ✓manifest key new-holland-agriculture has a registry record with equipmentImageKeyPrefix
- ✓manifest key ferris has a registry record with equipmentImageKeyPrefix
- ✓manifest key ventrac has a registry record with equipmentImageKeyPrefix
- ✓manifest key mchale has a registry record with equipmentImageKeyPrefix
- ✓registry slug new-holland-agriculture with equipmentImageKeyPrefix has a manifest key
- ✓registry slug ferris with equipmentImageKeyPrefix has a manifest key
- ✓registry slug ventrac with equipmentImageKeyPrefix has a manifest key
- ✓registry slug mchale with equipmentImageKeyPrefix has a manifest key
- ✓does NOT include Marcrest (which has no equipmentImageKeyPrefix)
✓getBrandSurfaceCopyGoogle visibility9
- ✓names the brand in every field
- ✓falls back cleanly for a brand with no seed (name-only, no fabricated lines)
- ✓is a stable resolver for an unknown slug (humanized, no throw)
- ✓produces a description unique across brands: intro
- ✓produces a description unique across brands: partDescription
- ✓produces a description unique across brands: diagramsTitle
- ✓produces a description unique across brands: diagramsDescription
- ✓getBrandTypeIntro names the brand, lowercased type, and type-specific parts
- ✓keeps meta descriptions within a sane SERP length
✓postBrandMediaAdmin logic9
- ✓POSTs multipart form data with the admin token header and returns cdnUrl
- ✓sends the type slug under the 'slug' field (not 'code') for kind=type
- ✓omits optional provenance fields when not provided
- ✓returns an error on a non-2xx response (never throws)
- ✓falls back to a status message when the error body has no error field
- ✓returns an error when the 2xx response is missing cdnUrl
- ✓returns an error on a network failure (never throws)
- ✓reports unconfigured when the base URL is unset (no fetch)
- ✓reports unconfigured when the token is unset (no fetch)
✓<ProductCardCozy>Product grid8
- ✓links the PDP from the title alone, with nothing nested in the anchor (#3556)
- ✓falls back to the raw PN path when manufacturer code is missing (#1117)
- ✓renders title, PN, fits summary, status copy and price
- ✓renders real Clinton qty when clintonOnHand is present
- ✓hides fits row when fitmentCount is missing or 0
- ✓renders Out of Stock with no shelf and no in-stock signal
- ✓shows no price or quote CTA when price is missing (#1863)
- ✓falls back to the branded placeholder when the thumbnail image fails
✓<ProductRow>Product grid8
- ✓links the PDP from the title alone, with nothing nested in the anchor (#3556)
- ✓falls back to the raw PN path when manufacturer code is missing (#1117)
- ✓renders title, PN, fits count, Clinton stock state and formatted price
- ✓renders real Clinton qty when clintonOnHand is present
- ✓shows no price or quote CTA when price is missing (#1863)
- ✓hides fits meta when fitmentCount is 0 or missing
- ✓renders Out of Stock with no shelf and no in-stock signal
- ✓falls back to the branded placeholder when the thumbnail image fails
✓capabilitiesForVendorCode (front#1433)Assembly views8
- ✓resolves NH to the full-feature preset
- ✓resolves the ARI-sourced brand FER to its preset
- ✓resolves the ARI-sourced brand VNT to its preset
- ✓resolves the ARI-sourced brand MCH to its preset
- ✓resolves the ARI-sourced brand MAR to its preset
- ✓resolves the ARI-sourced brand KUH to its preset
- ✓is case-insensitive on the vendor code
- ✓falls back to the safe ARI degraded preset for an unknown brand code
✓<GroupJumpSelect>Brand pages8
- ✓renders an option per group with label and count
- ✓calls onJump with the selected group id on change
- ✓reflects the active group as the selected value
- ✓shows a disabled placeholder so the first group is selectable before any scroll
- ✓never calls onJump with the placeholder value
- ✓is labelled for assistive tech
- ✓has a touch-friendly min height (>= 44px target)
- ✓applies className to the root element that contains the chevron and the select
✓<GroupNav>Brand pages8
- ✓renders the 'Product groups' header
- ✓renders one button per group with its label and count
- ✓calls onJump with the group id when a group is clicked
- ✓marks the active group with aria-current=true
- ✓renders no active group when activeId is null
- ✓applies a passthrough className
- ✓scrolls the active group into view when activeId changes (front#1616)
- ✓renders a max-height scrollable group list (front#1616)
✓localStorage-backed storeAdmin logic8
- ✓round-trips a toggle: write persists and reads back
- ✓toggling one switch to Users only produces the users-only status
- ✓toggling to SEO only produces the seo-only status
- ✓both switches on produces fully-on
- ✓both switches off produces off
- ✓resetOverrides clears every saved override
- ✓ignores an unknown slug (no-op)
- ✓notifies subscribers on change
✓getBrandEditorialEquipment data8
- ✓returns the intro for carried brand new-holland-agriculture
- ✓returns the intro for carried brand ferris
- ✓returns the intro for carried brand ventrac
- ✓returns the intro for carried brand mchale
- ✓returns the intro for carried brand marcrest
- ✓returns the intro for carried brand kuhn
- ✓is case-insensitive on the slug
- ✓returns undefined for an unknown or not-yet-carried brand
✓brandFallbackImageUrlGoogle visibility8
- ✓returns the prebuilt per-brand OG PNG for a known brand slug
- ✓canonicalises an alias slug to the prebuilt brand asset
- ✓resolves a vendor code to the prebuilt brand asset
- ✓falls back to the site-wide OG image for an unknown vendor code
- ✓is case-insensitive on the slug
- ✓falls back to the site-wide OG image for an unknown brand slug
- ✓falls back to the site-wide OG image when the slug is undefined
- ✓never returns the legacy shared part placeholder
✓NH Construction brand-hub config (ct-2163)Equipment data8
- ✓registers under the construction brand slug at rich density
- ✓is resolvable through the shared hub-config registry by its slug
- ✓renders the construction categories as the Equipment-Types cards
- ✓every card slug maps to a construction sub-category, photo matches (single source)
- ✓offers a maintenance grid and a dealer story for brand-hub parity
- ✓buckets the launch-carried lines by equipment type (#1507 narrowing)
- ✓carries a metaDescription + intro for the CE landing copy
- ✓hero slides + logo + cover + card source photos exist on disk within the LCP budget
✓/parts/brand/[slug]/diagrams/type/[typeSlug] — type-scoped co-located surface (#2367)Brand pages8
- ✓feeds the path type into the New Holland type-first body as equipmentType
- ✓resolves the legacy new-holland alias onto the canonical AG surface (outputs stay canonical)
- ✓feeds the path type into a model-group body via its `category` drill key
- ✓keeps `?series=` as a query sub-state layered on top of the path type
- ✓hosts the NH Construction division scoped to construction, mapping a CE sub path → ?sub=
- ✓NHC: an unknown path type falls back to bare construction — no bogus sub, no 404
- ✓feeds the path type into AGCO's model-group body too (models taxonomy, no hotspots — not a 404)
- ✓is noindex,follow with its canonical pinned to the bare diagrams tab (no new indexable URL, #2714)
✓TypeHubJsonLdBrand pages8
- ✓emits BreadcrumbList JSON-LD when models[] is empty
- ✓Brands crumb points at /brands, not the redirecting /parts/brand
- ✓mirrors the visible trail: Home / Brands / brand / type
- ✓emits BreadcrumbList + ItemList when models[] non-empty
- ✓caps ItemList at top-50 even when given more models
- ✓ItemList is sorted alphabetically by displayName (deterministic)
- ✓ItemList sort uses numeric collation (T6 < T7 < T10, not T1 < T10 < T2)
- ✓emits items below the cap when fewer than 50 models
✓brand capability presets (front#1429 Group B / front#1433)Assembly views7
- ✓NH preset is the full-feature set
- ✓Ferris preset matches the catalog-vendor shell with pdpLinks ON
- ✓Ventrac preset matches the catalog-vendor shell with pdpLinks ON (Wave-2)
- ✓McHale preset matches the catalog-vendor shell with pdpLinks ON (Wave-2)
- ✓Marcrest preset matches the catalog-vendor shell with cart ON (hub#136 pricing sign-off, front#1538)
- ✓Kuhn preset matches the catalog-vendor shell with pdpLinks ON (ct-2003)
- ✓every catalog-vendor preset enables pdpLinks (FER + VNT + MCH + MAR + KUH)
✓filterPartsByQueryDiagram viewer7
- ✓returns the input array unchanged when query is empty
- ✓matches a partNumber substring case-insensitively
- ✓matches a description substring case-insensitively
- ✓matches against either field (OR semantics)
- ✓returns an empty array when nothing matches
- ✓trims surrounding whitespace from the query
- ✓treats a null/undefined description as a non-match (no crash)
✓<BrandTile>Brand pages7
- ✓renders the whole tile as a single link to href
- ✓conveys the brand name and the division qualifier
- ✓renders the logo-only small tile with no journey chips (#2053)
- ✓renders the cover photo in the flagship variant when photoSrc is provided
- ✓clips the flagship photo diagonally and layers the darken + fade treatment
- ✓does not render a photo when photoSrc is absent (small logo variant)
- ✓passes through a custom className
✓BrandViewToggleBrand pages7
- ✓links Diagram view to the diagrams landing and Part view to the pre-filtered catalog
- ✓marks the active mode with aria-current
- ✓marks Diagram view active and Part view inactive when active="diagrams"
- ✓deep-links Diagram view to diagramsHref when provided (#2246)
- ✓emits no aria-current on either leg when markCurrent={false} (type hub) (#2204)
- ✓still highlights the active leg visually when markCurrent={false}
- ✓clears the 44px touch target below sm on both legs
✓<PromoContactCard>Brand pages7
- ✓renders the title and body
- ✓renders hours when provided
- ✓renders the phone as a tel: link
- ✓omits the phone link when no phone is given
- ✓renders the masked photo when photoSrc is provided
- ✓renders no photo element when photoSrc is omitted
- ✓applies a passthrough className
✓BRAND_NAV_ITEMS — header brand destinationsCatalogue & browsing7
- ✓is a plain constant — every href resolved, no promises
- ✓covers every carried brand, each pointing at its own hub
- ✓keeps the New Holland Construction division on its dedicated CE hub
- ✓places the Construction division immediately after New Holland
- ✓orders brands by the same canonical priority the strips use (#3864)
- ✓advertises exactly one URL per destination
- ✓exposes the canonical /brands directory as the trailing 'all brands' link
✓brand-page asset fields — equipmentImageKeyPrefix (#1526)Equipment data7
- ✓new-holland-agriculture exposes equipmentImageKeyPrefix new-holland
- ✓ferris exposes equipmentImageKeyPrefix ferris
- ✓ventrac exposes equipmentImageKeyPrefix ventrac
- ✓mchale exposes equipmentImageKeyPrefix mchale
- ✓stores the prefix as a clean bucket key (no leading/trailing slash)
- ✓leaves marcrest without an equipmentImageKeyPrefix (no per-type cards)
- ✓keeps the field optional on the type (records without it still valid)
✓formatBrandedSkuBusiness rules7
- ✓formats CT-{BRAND}-{PN} for happy path
- ✓upper-cases brand code
- ✓emits FER for the temporary FRR read alias
- ✓falls back to XXX when brand code is null
- ✓falls back to XXX when brand code is empty string
- ✓returns null when partNumber is missing
- ✓trims whitespace from partNumber
✓parseBrandedSkuBusiness rules7
- ✓parses CT-{BRAND}-{PN} format
- ✓returns null for non-branded inputs
- ✓preserves PN with hyphens
- ✓normalizes a legacy Ferris URL to the FER identity
- ✓parses lowercase input and normalizes the brand code to uppercase
- ✓parses mixed-case input and normalizes the brand code to uppercase
- ✓dispatches case variants to the same brand code (collision fence holds)
✓<FilterBrandGroup>Product grid7
- ✓renders CNH brand checkboxes from the manufacturers facet
- ✓emits the next selected array when a brand is toggled on
- ✓replaces the active brand (single-select — #2750)
- ✓clears the selection when the active brand is toggled off
- ✓renders nothing when there are no MV brand facets (front#2840)
- ✓does not offer brand-catalog vendors that the MV facets don't carry (front#2840)
- ✓collapses a long brand list behind Show more
✓/parts-diagrams/[brand]/assemblies/[assemblyCode] (front#1398)Diagram pages7
- ✓renders the ARI schematic image, callouts, and BOM rows via the shared stack
- ✓constrains the page to viewport height so the BOM scrolls in its panel (front#1509)
- ✓emits BreadcrumbList + ItemList JSON-LD (no Product), front#1429 A5
- ✓shows chapterName in the breadcrumb between the brand and the assembly (A6)
- ✓omits the chapter rung when chapterName is null (A6 graceful absence)
- ✓404s when the brand is not a brand-routes brand
- ✓filters the 99999999 sentinel row before it reaches the BOM or JSON-LD (front#2913)
✓<BrandHubTemplate> — New Holland Construction division (ct-2163)Brand pages7
- ✓uses the rotating carousel hero (not the still identity card) when slides are supplied
- ✓carries the division shop CTA and no diagrams fork (#2832)
- ✓renders the six CE category cards, each drilling into its own diagrams sub-category path
- ✓relocates the intro to the page bottom under the carousel hero
- ✓renders the supplied crawl index (All {brand} models → diagrams)
- ✓omits the vendor switcher on a division sub-hub (not a top-level carried brand)
- ✓shows no parts-count numbers anywhere on the division hub (brand-hub hard rule)
✓<PartsFiltersSidebar> — #2804 availability radio (3-way + counts)Parts pages7
- ✓renders only All + the two customer statuses (never 'Available to order')
- ✓(b) folds low_stock into the in_stock count (S1-A: In stock ⊇ low_stock)
- ✓never offers 'Available to order' even when the facet reports it (off-canon)
- ✓omits a status the facet has none of (metadata-driven — no phantom filter)
- ✓(b) shows no counts when the availability facet is absent (adapter brands)
- ✓(b) suppresses counts while an availability filter is active (intersection collapse)
- ✓(e) labels the contact-for-pricing checkbox 'Contact for quote', not 'Out of Stock'
✓brand [slug]/type [typeSlug] page — metadata robotsBrand pages7
- ✓does not set noindex for New Holland (NH stays indexable)
- ✓emits robots: { index: false, follow: false } for non-NH brand mchale (mirrors brand hub)
- ✓emits robots: { index: false, follow: false } for non-NH brand ventrac (mirrors brand hub)
- ✓emits robots: { index: false, follow: false } for non-NH brand hotsy (mirrors brand hub)
- ✓non-seo-indexed brand (mchale) gets noindex,nofollow via the config gate
- ✓delegates the robots decision to robotsForBrand(config.slug)
- ✓non-seo-indexed brand (mchale) + indexing off → robots omitted (layout wins)
✓humaniseBrandBusiness rules6
- ✓expands short brand codes to display names
- ✓expands hyphenated slugs to display names
- ✓expands the canonical Ferris code and slug
- ✓is idempotent on already-humanised values
- ✓title-cases unknown codes instead of returning lowercase
- ✓returns a safe fallback for empty/null input
✓CatalogBreadcrumbsProduct grid6
- ✓renders Home link and current page
- ✓renders Home as a link
- ✓renders category name as a non-link crumb when no vendor is shown
- ✓renders category as a link only when both vendor and categoryId are present
- ✓uses raw categoryId (not display name) in the URL so the filter round-trips
- ✓applies mobile truncate classes and title tooltip for long category names
✓deriveCatalogReconciledAvailabilityProduct grid6
- ✓flags clintonInStock=true on the reconciled value (badge handles elevation)
- ✓returns in_stock when inventory.availability is 'in_stock'
- ✓maps 'available' to vendor_direct per reconcile.ts canonical mapping
- ✓returns in_stock_limited when inventory.availability is 'low_stock'
- ✓returns unknown when no inventory signal but part has price
- ✓reads out of stock when the part has no price, whatever its stock signals say
✓SortSheetProduct grid6
- ✓renders one radio per option inside a radiogroup
- ✓uses native radio inputs rather than ARIA-roled buttons
- ✓marks the active option checked
- ✓calls onChange then closes when an option is selected
- ✓still closes when the already-active option is re-picked
- ✓closes via the X button
✓useCatalogViewProduct grid6
- ✓defaults to 'cards' when URL and localStorage are empty
- ✓URL wins over localStorage when both have a value
- ✓applies the remembered view WITHOUT writing it to the URL (#3588)
- ✓setView writes to localStorage immediately and pushes the view to the URL
- ✓ignores invalid localStorage values
- ✓does NOT seed the URL when the stored view equals the default (front#1331 no-flash)
✓ViewToggleProduct grid6
- ✓renders three buttons inside a labelled group
- ✓groups the buttons in a native fieldset named by a visually hidden legend
- ✓reflects active value via aria-pressed
- ✓calls onChange with the clicked value
- ✓keeps buttons in tab order (no tabIndex override)
- ✓activates via keyboard (Enter on focused button)
✓BrandBreadcrumb (front#1440)Assembly views6
- ✓renders every crumb label in order
- ✓renders crumbs with an href as links and the final crumb as the current page
- ✓renders a non-final crumb without an href as plain text (no link)
- ✓renders nothing for an empty crumb list
- ✓does not apply on-dark styling by default
- ✓applies on-dark (white) styling when onDark is set, for use over a hero
✓brand hero boxBrand pages6
- ✓gives both heroes the same body box, so the banner does not resize between brands
- ✓gives both heroes the same h1 scale
- ✓clamps the lede so intro length cannot change the box
- ✓keeps the full lede in the DOM — the clamp is CSS, so crawlers still read it
- ✓does not floor the coverless identity card — the diagrams surfaces hug their copy
- ✓exports a lede contract that carries the clamp
✓<BrandThemeScope>Brand pages6
- ✓renders its children
- ✓sets --oem from the registry accent for a known slug
- ✓falls back to the brand-default accent for an unknown slug
- ✓prefers an explicit accent override over the registry lookup
- ✓passes through className
- ✓works with no slug when given an explicit accent
✓<DarkHero>Brand pages6
- ✓renders the title and lede when provided
- ✓renders the photo with its alt text in the photo variant
- ✓does not render an image element in the gradient variant
- ✓renders children (e.g. a breadcrumb) inside the hero
- ✓applies a custom heightClass and className
- ✓renders the lede only when provided
✓ViewSwitchLinkBrand pages6
- ✓renders a Next Link typed view-switch
- ✓forwards GA4 data attributes
- ✓does not guard generic view-switch navigations
- ✓cancels an already-current leg before the router can refetch it
- ✓preserves document height only for an opted-in streamed route
- ✓does not let a late source ready effect clear the destination guard
✓formatDocumentDisplayNameBusiness rules6
- ✓prefers model_number
- ✓falls back to clean filename
- ✓skips Unknown filename
- ✓falls back to provider + short ID
- ✓falls back to provider only
- ✓returns Document as last resort
✓formatDocumentSubtitleBusiness rules6
- ✓shows provider label
- ✓shows provider and page count
- ✓shows filename hint when model_number differs
- ✓skips filename hint when it matches model_number
- ✓skips Unknown filename
- ✓returns empty string for no data
✓resolveBrandSlugCatalogue data6
- ✓returns the mapped slug for known codes
- ✓resolves the canonical Ferris (FER) and Ventrac (VNT) codes
- ✓normalises mixed-case codes before mapping
- ✓falls back to lowercase code for unmapped values
- ✓returns an empty string for null or undefined
- ✓returns an empty string for an empty input
✓resolveEffectiveSortBy (CT-674 T6)Catalogue data6
- ✓defaults to data_quality when category is set and URL has no sortBy (#2124)
- ✓preserves explicit sortBy from URL even when category is set
- ✓defaults to data_quality for the bare /parts landing (no category, no search) — #2124
- ✓preserves explicit relevance when category is set
- ✓ignores category-default when a search query is active (Hono ignores sortBy in search mode)
- ✓still honours an explicit URL sortBy even with a search query
✓product-image morph key (#2458)Catalogue data6
- ✓keys on the branded SKU — identical to the card detailHref segment
- ✓falls back to the bare part number when the brand code is missing (proxy 308s it)
- ✓trims the part number exactly like the card href builder
- ✓PDP side derives the same name from the lowercase route param
- ✓PDP side agrees with the grid whatever casing the route id arrives in
- ✓canonicalises the vendor code, so an FRR grid row pairs with its FER URL
✓analyzeUniquenessCatalogue data6
- ✓flags a cluster of near-duplicate frames
- ✓reports near-zero similarity for a fully distinct set
- ✓returns the empty report for no input
- ✓has no neighbour, pair, or cluster for a single item
- ✓treats a pair exactly at dupThreshold as a duplicate (>= boundary)
- ✓unions a whole family of shared-frame parts into one cluster
✓matchesRefineQueryBusiness rules6
- ✓returns true when query is empty or whitespace
- ✓matches case-insensitively across fields
- ✓returns false when no field matches
- ✓tolerates null / undefined fields
- ✓does not interpret regex metacharacters
- ✓supports substring phrases (contiguous)
✓toOemPartNumber (#1584 — eParts keys on the bare OEM PN)Business rules6
- ✓returns a bare PN unchanged (idempotent)
- ✓strips the CT-{BRAND}- prefix
- ✓strips a -PK{N} pack-alias suffix
- ✓is case-insensitive on the prefix while preserving PN case
- ✓preserves hyphenated OEM PNs that are not pack aliases
- ✓returns empty string for null/undefined/blank
✓appendPageSuffixToMetadata (front#940)Google visibility6
- ✓page 1 → returns input unchanged (canonical landing)
- ✓page 2 → appends Page 2 suffix to title and description
- ✓page 10 → appends Page 10 suffix
- ✓page 0 / page 1 / negative → returns input unchanged
- ✓non-finite page → returns input unchanged (defensive)
- ✓works for filter-scoped titles (Results for query)
✓OgBrandTemplateGoogle visibility6
- ✓returns a div React element
- ✓includes the brand name in the rendered tree
- ✓renders the logo when logoUrl is provided
- ✓picks white text on a dark accent (luminance < 0.55)
- ✓picks dark text on a light accent (luminance > 0.55)
- ✓omits the logo img when logoUrl is not provided
✓/api/equipment/brandsAPI endpoints6
- ✓returns only `available: true` configs and reads modelCount from the hub route
- ✓falls back to the adapter route when the hub route 404s (front#2446)
- ✓sums group model counts when the adapter route omits pagination
- ✓falls back to modelCount=0 when both hub and adapter routes are non-2xx
- ✓falls back to modelCount=0 when both routes reject (network / timeout)
- ✓does not touch the database (no pg client import side-effect)
✓<BrandDiagramsTypeSelection> (#2428)Diagram pages6
- ✓offers every type for selection, none pre-active, each linking via ?category=
- ✓keeps exactly one crawlable, trailing-slash-free /parts-diagrams/models inlink
- ✓renders the standalone landing chrome (breadcrumb + identity banner)
- ✓suppresses its own chrome in the co-located hub but still renders the selection grid
- ✓gives the co-located schema the hub trail, last rung unlinked
- ✓leaves the standalone landing on its own schema chain
✓adaptBrandModelAssembly (front#1494)Diagram pages6
- ✓maps the assembly identity fields straight across
- ✓derives hasCallouts from a positive calloutCount
- ✓uses the brand chapterName verbatim, falling back to an empty string when null
- ✓passes through the real schematicUrl from hono; falls back to hasSchematic when status is null
- ✓passes a real listing schematicUrl straight through instead of the sentinel
- ✓leaves slug null and assemblyId empty so hrefs fall back to assemblyCode
✓normalizeBrandGroups — duplicate-spelling mergeDiagram pages6
- ✓merges the four Attachment & Accessories spellings into one group
- ✓keeps the dominant (most-models) spelling as the display label
- ✓merges hyphen / spacing / case variants of walk-behind
- ✓merges singular/plural and hyphen variants of Zero Turn Mower - Commercial
- ✓merges Grass Collector and Grass Collectors
- ✓merges Spreader Sprayer and Spreader Sprayers
✓brand [slug] page — catalog data fetches (#2367)Brand pages6
- ✓ferris renders the shoppable Part catalog via the adapter feed (not the search MV)
- ✓new-holland renders the catalog via the search MV (not the adapter feed)
- ✓agco (adapter brand, no search-MV rows) sources from the adapter feed, not the search MV
- ✓a 4xx from the adapter feed renders an inline (cacheable) error — does not rethrow
- ✓a transient adapter-feed failure renders ServiceUnavailable, not the error boundary
- ✓a non-search error still throws so a real bug reaches the error boundary
✓FilterEquipmentFitment — selectionProduct grid6
- ✓calls onClear when clicking 'All models' while models are selected
- ✓does not call onClear when clicking 'All models' when already all selected
- ✓calls onSelect with added key when clicking unchecked model
- ✓calls onSelect with remaining keys when deselecting one of multiple
- ✓calls onClear when deselecting the last model
- ✓expands brand when clicking 'Show more'
✓FilterEquipmentFitment — searchProduct grid6
- ✓filters models by search query after debounce
- ✓shows 'No models found' when search matches nothing
- ✓clears search when clicking clear button
- ✓matches raw model code without spaces against formatted name
- ✓filters by brand name search
- ✓shows all models when search is cleared after filtering
✓buildBrandTypeCanonicalBrand pages6
- ✓returns the bare brand × type path
- ✓ignores trailing slugs that look like query strings
- ✓page N > 1 → self-referential ?page= canonical
- ✓page 1, an omitted page and a non-numeric page all keep the bare path
- ✓preserves URL-safe slug characters verbatim
- ✓percent-encodes free-form brand-catalog categoryIds
✓<TypePageBrandStrip> — Vendors switcherBrand pages6
- ✓renders a New Holland Construction pill that deep-links into the construction diagrams
- ✓renders nothing when the sibling-brand-links capability is off
- ✓marks the active brand inside the shared one-row rail
- ✓logo pills convey the name through the logo alt only — no duplicated visible name
- ✓marks every carried brand — the hub no longer opts out of logos (#3864)
- ✓orders brands by the canonical display priority — New Holland leads, McHale next (#2441)
✓TypePageCategoryTreeBrand pages6
- ✓renders a clipped, independently scrollable rail (flex child of the sidebar's sticky column)
- ✓pins 'All categories' outside the scroll viewport so a long list can't overrun it (#2254)
- ✓marks 'All categories' current when no type is filtering, and no type row with it
- ✓hands 'All categories' back to the type row once a type filters
- ✓keeps the active type inside the scroll viewport so the rail can bring it into view
- ✓renders row counts in the muted token, never opacity-dimmed below AA contrast
✓BrandPromoCard (group editing)Interface pieces5
- ✓shows the served preview at the seeded factor (list x factor)
- ✓nudging a brand's promo down updates that brand's served preview (all-McHale sale)
- ✓leaves other brands' previews untouched when one brand changes
- ✓exposes a global default and no wholesale/net/cost fields
- ✓keeps applying a promo backend-gated (Apply disabled)
✓DeferredCardMountProduct grid5
- ✓renders a linked placeholder with title + part number + price before intersecting
- ✓omits the price row on an unpriced part, like the card it stands in for
- ✓mounts the interactive ProductCard once the cell intersects
- ✓renders a held row's /lookup twin with no href in the markup (#3843)
- ✓keeps the placeholder when the cell never intersects
✓<PartMedia> placeholder fallbackProduct grid5
- ✓falls back to the branded part placeholder (PN + brand) when an advertised image 404s
- ✓renders the branded part placeholder when the part has no usable image
- ✓renders the lone diagram as the fallback image, labelled as a parts diagram
- ✓prefers a real photo over a diagram and does not label it a diagram
- ✓keeps the kit placeholder for kit parts
✓formatFitsCellProduct grid5
- ✓returns em-dash when count is null/undefined
- ✓returns em-dash when count is 0
- ✓singularises 'model' when count is 1
- ✓pluralises 'models' for counts >1
- ✓locale-formats large counts with thousands separators
✓shouldShowBrandToggleProduct grid5
- ✓shows for a single selected diagrams-capable brand
- ✓hides when no brand is selected
- ✓hides when multiple brands are selected
- ✓hides when one is selected but it did not resolve to an active brand
- ✓hides when the single brand has no diagrams landing
✓bomPartToCartItem — brand-qualified cart identityAssembly views5
- ✓stamps productId + sku as CT-{BRAND}-{PN} when brand is known
- ✓keeps the same raw PN distinct across brands (Ferris vs CNH collision)
- ✓uses the effective replacement PN, not the original, when supersession routes the row
- ✓falls back to the raw effective PN line (no sku) when brandCode is genuinely absent
- ✓falls back to the raw line when brandCode is empty string (defence-in-depth)
✓buildDirectoryTilesBrand pages5
- ✓splits New Holland into Agriculture + Construction tiles, both with photos
- ✓wires each carried brand's registry cover photo onto its tile
- ✓wires Kuhn's authored cover onto its tile (#2554 — Kuhn Group baler press photo)
- ✓lights up Landoll's tile from its authored registry cover (#2661)
- ✓orders cards so cover-photo tiles lead and placeholder tiles trail
✓renderTailCardsBrand pages5
- ✓emits one data-density-card <a> per model with the filter/sort/link contract, no <img>
- ✓HTML-escapes model text so an ampersand or quote can't break the markup
- ✓degrades a zero-assembly brand-catalog model to Shop parts, no diagram link
- ✓renders nothing for an empty tail
- ✓keeps every inner style in CSS: one class attribute, no inline svg
✓providerToBrandCodeBusiness rules5
- ✓maps known provider slugs
- ✓maps MongoDB-format provider slugs
- ✓is case-insensitive
- ✓returns null for unknown providers
- ✓round-trips with brandCodeToProvider
✓toggleBrandSelection (single-select radio — #2750)Catalogue data5
- ✓selects a brand when none is active
- ✓replaces the previous selection instead of unioning
- ✓replaces a legacy multi-value selection with the single pick
- ✓clears when the active brand is re-picked
- ✓does not mutate the input array
✓rankVisibleParts (front#1957)Catalogue data5
- ✓returns the server order untouched when the sort is explicit (switcher works)
- ✓leads with CT-photo parts on the default browse view
- ✓does NOT boost CT parts in search mode (relevance owns that order)
- ✓keeps the in-stock/price/image tier as the within-CT-cluster order
- ✓leaves non-CT ordering on the 7-tier score (boost is a no-op for them)
✓soft-countsCatalogue data5
- ✓returns false for counts below the threshold
- ✓returns true at and above the threshold
- ✓returns false for null and undefined
- ✓returns false for any count when activeNarrow is set
- ✓ignores activeNarrow:false (default behaviour)
✓seedBrandCapabilityFlagsEquipment data5
- ✓marks a carried brand-routes vendor as adapter + models + hotspots + carried
- ✓marks New Holland (search MV) carried but NOT a brand-routes adapter vendor
- ✓normalizes legacy short codes and casing
- ✓returns all-false for an unknown / non-carried vendor
- ✓marks AGCO (adapter, models taxonomy, no hotspots live) carried + adapter + models seeded (ct-2434)
✓normalizeBrandCapabilityFlagsEquipment data5
- ✓falls back to the seed when the row is missing
- ✓reads camelCase flags from the summary row, overriding the seed
- ✓reads snake_case flags (is_carried, has_models) emitted by the PG-backed summary
- ✓ignores non-boolean flag values and keeps the seed
- ✓can flip an unseeded brand carried via the summary flag (data, not code)
✓brandMarketingPrefixEquipment data5
- ✓maps New Holland Agriculture to the ag prefix
- ✓maps New Holland Construction to the ce prefix
- ✓maps own-slug brands to themselves
- ✓is case-insensitive
- ✓returns null for out-of-scope / unmapped brands
✓buildBrandMarketingCoverSlidesEquipment data5
- ✓builds carousel slides against the CDN contract for a mapped brand
- ✓returns [] for an unmapped brand (no marketing media this pass)
- ✓returns [] when no cover models are supplied (inert until seeded)
- ✓drops ineligible entries (schematic/logo) via the guard
- ✓caps the slide count to keep the LCP track short
✓getBrandSpecificModelImageSrcEquipment data5
- ✓returns the curated cutout for a mapped McHale model code
- ✓is case-insensitive on both brand slug and model code
- ✓returns null for an unmapped model code on a mapped brand
- ✓returns null for an unmapped brand
- ✓returns null when brand slug or model code is missing
✓division-brand-typesEquipment data5
- ✓flags a sibling division-brand slug
- ✓does not flag a real equipment-type slug
- ✓drops a division-brand slug from a parent brand's type list
- ✓keeps every entry when none collide with a brand slug
- ✓preserves the input order of surviving entries
✓findManufacturerSummary (front#832)Business rules5
- ✓finds by vendor code
- ✓finds by slug — the case that drove the bug
- ✓returns the same summary for slug and code forms
- ✓matches case-insensitively for both forms
- ✓returns undefined for unknown input
✓toManufacturerSlugParam (#2217)Business rules5
- ✓maps carried vendor codes to canonical registry slugs
- ✓resolves legacy alias codes through the registry
- ✓passes canonical slugs through unchanged
- ✓falls back to facet summaries for non-registry brands
- ✓leaves unknown values untouched (0-result behaviour preserved)
✓matchCarriedBrandInventory data5
- ✓matches a spaced display name from the inventory feed
- ✓matches a single-word make regardless of case
- ✓returns undefined for makes we do not carry
- ✓returns undefined for empty input
- ✓never resolves a make to an unavailable brand record
✓shouldIndexListing (#2367 Phase 2 gate)Google visibility5
- ✓indexes a shallow + rich listing (≤3 facets AND ≥10 results)
- ✓noindexes one result below the richness floor (boundary)
- ✓noindexes one facet past the depth ceiling (boundary)
- ✓requires BOTH — deep-but-rich and shallow-but-thin each fail
- ✓honors explicit threshold overrides
✓/equipment listing — /parts design parity (#3871)Equipment pages5
- ✓gives the page exactly one h1, and it is the hero's
- ✓keeps the /attachments cross-link — the hero lede is its only inbound link
- ✓counts in the hero subline and the toolbar, and puts search in the toolbar
- ✓stamps the card the way a parts card is stamped, without repeating the make
- ✓offers no favorite, no cart and no stock wording — whole goods are inquiry-only
✓PartsCatalogClient — BreadcrumbList JSON-LD (#3292)Parts pages5
- ✓emits exactly one trail on the bare landing, Home absolute and leaf bare
- ✓emits the vendor trail on a manufacturer-filtered listing
- ✓emits the trail on a searched listing
- ✓emits the trail past page 1
- ✓carries the category crumb, and only the leaf lacks an item URL
✓FilterSidebarHeaderProduct grid5
- ✓renders Filters label
- ✓hides Clear all button when no active filters
- ✓shows Clear all button when filters are active
- ✓calls onClear when Clear all is clicked
- ✓disables Clear all button when disabled prop is true
✓NH equipment cards — AG/CE division partition (#1507)Equipment data5
- ✓every card carries a division tag
- ✓partitions the 12 authored cards into 11 AG + 1 CE with no overlap
- ✓tags only the construction slug as CE
- ✓points the CE hub at the relocated first-class brand-division hub (ct-2163 / #2367)
- ✓filterNhAgEquipmentTypes drops CE slugs from live API lists
✓NH construction model imagery (#1938)Equipment data5
- ✓every sub-category is served from the bucket and its source asset exists on disk
- ✓resolves a model to its sub-category by product line (bare model number)
- ✓resolves to the wrong/no line if fed a brand-prefixed displayName (contract: pass modelNumber)
- ✓returns undefined / null for a line that maps to no sub-category
- ✓maps a model to its representative category photo + label
✓resolveBrandHubTypesEquipment data5
- ✓NH always renders 11 AG-authored cards even when live types are empty (#1507)
- ✓Ferris prefers live categories when present
- ✓Ferris falls back to authored cards when live is empty
- ✓Ventrac is live-only: empty live types render nothing (no 404-ing authored fallback)
- ✓Ventrac passes live categories through unchanged
✓<BrandDiagramsHeader>Diagram pages5
- ✓renders the shared breadcrumb ending in the brand name
- ✓renders one h1 of `{name} Parts Diagrams`
- ✓passes the cover, subline, and aside through to the identity banner
- ✓renders the cross-brand Vendors switcher for a fallback brand (kress), active on it
- ✓renders no Part/Diagram toggle (its one placement is the hub's toggle row)
✓brandGroupsToTypeModels (#2534 per-model image threading)Diagram pages5
- ✓threads a real per-model imageUrl through the group flatten
- ✓carries the group label onto subLine and falls slug/modelNumber back to modelCode
- ✓flattens every model across every group, preserving order
- ✓does not surface a schematic backend imageUrl as the model card photo
- ✓falls the card to the branded cutout when a model carries no imageUrl
✓ModelGroupDiagramsView — bare landing (#2656/#3224)Diagram pages5
- ✓the bare co-located tab is the all-categories GRID, with no category preselected
- ✓renders the DISABLED Browse-by-Type placeholder above the flat grid for a no-categories brand (#2367)
- ✓#3129 — starts the categories fetch concurrently, not serially after flags resolves
- ✓an explicit `?category=` opens that type, rail switching in place inside the hub
- ✓keeps the empty answer for a category the shopper asked for
✓brandFilteredBreadcrumbs — PDP brand crumb destination (#2685)Parts pages5
- ✓links the /parts/brand/{slug} hub for a carried brand, resolving vendor code → slug
- ✓resolves a lowercase code carried on `slug` (the shape the search layer emits)
- ✓routes a division part (NHC shares NHL) to its primary (AG) hub, matching the shown name
- ✓keeps the faceted `?manufacturer=` fallback for a non-carried OEM (no hub)
- ✓leaves the trail untouched when the manufacturer is unknown
✓capPerGroupDiagram pages5
- ✓keeps the flat total at or under the cap
- ✓represents every group instead of filling up from the largest
- ✓returns a small brand whole
- ✓takes each group's leading (flagship-first) models, in rail order
- ✓has no groups to cap
✓brand hub — authored equipment types (#1703 scope B)Brand pages5
- ✓renders live Equipment Types for ventrac (live-only — no authored fallback)
- ✓renders dealer story block for mchale
- ✓renders Equipment Types for marcrest when API returns no types
- ✓renders Ferris maintenance grid and dealer story when categories API is empty
- ✓renders the dealer story on ventrac
✓moved hub /brand/[slug] — New Holland (#2367)Brand pages5
- ✓keeps the authored NH hub title + description, stays indexable, /brand canonical
- ✓loads NH equipment types from the vocabulary endpoint and fetches no parts
- ✓serves the moved hub for an adapter primary brand (ferris)
- ✓serves the moved hub for the NH Construction division (#2367)
- ✓calls notFound() for a non-carried slug (no moved hub)
✓EquipmentPartsTable — branded cart identityDiagram pages5
- ✓stamps CT-{BRAND}-{PN} productId + branded sku for a Ferris row
- ✓keeps a Ferris add and a CNH add distinct for the same raw PN
- ✓links the part row to the server-stamped pdpHref verbatim
- ✓renders a held row (pdpHref null) as plain text but keeps Add-to-cart (#3854)
- ✓falls back to the legacy brandCode::pn productId with no sku when brandCode is empty
✓global brand-assembly generateMetadataDiagram pages5
- ✓builds the canonical, title and OG block from the assembly
- ✓does not put a CNH placeholder schematic on the OG card
- ✓404s rather than emitting metadata for a missing assembly
- ✓resolves to a titled noindex page when the assembly fetch throws a 500
- ✓emits a minimal title for a brand that has no brand-routes surface
✓BrandHubJsonLdBrand pages5
- ✓emits BreadcrumbList JSON-LD when types[] is empty
- ✓emits BreadcrumbList + ItemList when types[] non-empty
- ✓percent-encodes free-form categoryId slugs in ItemList URLs
- ✓Brands crumb points at /brands, not the redirecting /parts/brand
- ✓mirrors the visible trail: Home / Brands / brand
✓NH brand landing — featured-tile query allowlist (#846)Brand pages5
- ✓has at least one featured-part tile (design contract)
- ✓every featured-part tile uses a /parts?manufacturer=NHL&q=... href
- ✓every tile's decoded q value is on the verified-non-empty allowlist
- ✓every allowlist entry is used by at least one tile (no dead entries)
- ✓never re-introduces the known-dead / near-dead queries from #846
✓buildColocatedSwitcher — the toggle row's destinations (#2412/#2918)Brand pages5
- ✓type-first brand: the Part leg is the canonical type-scoped Part hub
- ✓filter-capable adapter (MCH): the Part leg keeps the type — its diagrams slug IS its Part category slug (#2656/#2918)
- ✓non-filter adapter (Brillion): the Part leg falls back to the bare catalog — its Part /type/{slug} has no ?categoryId= support
- ✓NH Construction division: the Part leg carries the active CE sub-category to its own /type/{sub} listing (#2952)
- ✓NH Construction division: an unresolved CE sub falls back to the bare catalog — no 404 Part link (#2952)
✓extractBrandDiagram pages5
- ✓extracts the brand prefix before the model number
- ✓falls back to the first whitespace token when model number is absent
- ✓humanises short-code prefix Nhl → New Holland
- ✓humanises short-code prefix Cih → Case IH
- ✓leaves already-humanised brand unchanged
✓<PartsFiltersSidebar> — #2577 unsupported filter-axis hidingParts pages5
- ✓renders Availability and Pricing when supportedFilterAxes is omitted (search MV — /parts, NH)
- ✓removes the Availability control from the DOM for a brand whose caps can't honor it (MCH)
- ✓removes the Pricing control from the DOM for a brand whose caps can't honor it (MAR/KUH)
- ✓removes both axes when neither is supported (KUH — no stock, no price)
- ✓keeps both axes when both are supported (an adapter brand that honors both)
✓brand-type hub generateMetadata — #1329Brand pages5
- ✓transient 503 → re-throws (to error boundary), NOT notFound()
- ✓transient timeout → re-throws, NOT notFound()
- ✓genuine 4xx fetch failure → empty types → type not found → notFound()
- ✓type genuinely absent from a healthy 200 response → notFound()
- ✓type present in a healthy 200 response → renders metadata (no notFound)
✓fetchTypeModels — brand-catalog drill-down (#2349)Brand pages5
- ✓transient 503 → re-throws (to error boundary), NOT empty models
- ✓transient 429 rate-limit → re-throws, NOT empty models
- ✓transient timeout → re-throws, NOT empty models
- ✓genuine 4xx → degrades to empty models (deterministic, cacheable)
- ✓healthy 200 → maps models through
✓TypeHeroRegionBrand pages5
- ✓renders the rotating identity banner when heroSlides are configured
- ✓still renders the dark banner (static fallback) when there are no slides
- ✓passes the resolver description as the hero lede
- ✓reads out model and series counts
- ✓drops the series clause when there is one or no series (catalog brand)
✓TypePageToolbarBrand pages5
- ✓is one row — no quick-nav strip under the search (#3861)
- ✓carries search, the density segment and the count readout
- ✓switches the readout to matches while searching and announces it politely
- ✓hides the density segment when the caller opts out
- ✓matches the Part store toolbar: same shell, same single row (#2367)
✓BrandWordmarkProduct grid4
- ✓renders the registry logo asset for a carried brand (NHL)
- ✓renders the accent text-wordmark tier for a known brand without a logo asset
- ✓resolves the brand from the code alone when no slug is supplied
- ✓falls back to OEM when no slug and no code resolve
✓CatalogToolbarProduct grid4
- ✓renders the caller's controls in ONE row and adds no second row
- ✓keeps the catalog-toolbar view-transition hook class
- ✓merges the caller's className onto the shell instead of replacing it
- ✓emits data-testid only when a testId is given
✓PartsListTable — Fits columnProduct grid4
- ✓renders count from explicit fitmentCount (e.g. 47 models)
- ✓falls back to equipmentFitment.length when fitmentCount missing
- ✓renders '—' with unknown flag when neither field is on the wire
- ✓renders '—' (not unknown) when fitmentCount is explicitly 0
✓ProductCard — branded placeholder for no-image state (CT-829)Product grid4
- ✓renders the brand-wordmark MediaPlaceholder when image.url is null
- ✓passes partNumber and manufacturerCode to the default placeholder fallback
- ✓does NOT render the legacy crosshair SVG fallback when image.url is null
- ✓uses the caller-provided fallback when image.fallback is set, overriding the branded default
✓<ProductListing>Product grid4
- ✓renders nothing when parts is empty
- ✓dispatches to ProductRow for view=counter
- ✓dispatches to ProductCardCozy for view=cards
- ✓dispatches to ProductTile for view=grid
✓<ProductListing> — mobile mount cap (front#1331)Product grid4
- ✓mounts only the eager count of cards on first paint; defers the rest
- ✓mounts a deferred card once it intersects the viewport
- ✓renders every card eagerly when there are fewer than the eager count
- ✓applies the same cap in grid view
✓SortMenuProduct grid4
- ✓renders an accessible Sort trigger
- ✓shows no active badge when the default (first) option is selected
- ✓marks a non-default sort with the active badge
- ✓disables the trigger when disabled
✓calloutMarkerShape (front#1512)Assembly views4
- ✓McHale uses ellipse markers (match the printed circular balloons)
- ✓NH / Ferris / Ventrac / Marcrest / Kuhn keep rectangular markers
- ✓resolves McHale's ellipse markers through capabilitiesForVendorCode
- ✓the unknown-brand fallback keeps rectangular markers (degrade closed)
✓isPlaceholderBomPart (front#2913 junk-row guard)Assembly views4
- ✓flags the 99999999 sentinel row
- ✓tolerates surrounding whitespace on the sentinel
- ✓keeps a real part (does not over-filter a similar-looking number)
- ✓drops only the placeholder when a BOM is filtered (mirrors the explorer)
✓formatProviderLabelBusiness rules4
- ✓returns known brand labels
- ✓handles case-insensitive lookup
- ✓falls back to word capitalization for unknown providers
- ✓resolves AGCO to its registry display name (carried brand, ct-2434)
✓normalizeProvidersBusiness rules4
- ✓deduplicates case variants
- ✓sorts alphabetically
- ✓returns lowercase canonical forms
- ✓handles empty array
✓deriveStatusAdmin logic4
- ✓both switches on -> fully-on
- ✓users only -> users-only
- ✓seo only -> seo-only
- ✓neither switch -> off
✓resolveBrandDataSource (ct-2163)Catalogue data4
- ✓projects the NH Construction division onto (new-holland-agriculture, construction)
- ✓resolves a normal brand to itself with no type scope
- ✓resolves an unknown slug to itself (no projection, no throw)
- ✓omits typeScope entirely when absent (exactOptionalPropertyTypes-safe)
✓brandLandingHref — hub-as-entry (ct-2047 / #2367)Catalogue data4
- ✓lands every carried primary brand on its moved top-level hub
- ✓moves the NH Construction division hub too despite available:false (#2367)
- ✓keeps a non-carried slug off the moved hub
- ✓never returns a bare /parts-diagrams/* landing
✓toCategorySlug (#2325 readable brand-type slugs)Catalogue data4
- ✓turns the category label into a readable lowercase-kebab slug
- ✓never emits a bare numeric or opaque-code slug for a real label
- ✓keeps Outfront distinct from the base Zero-Turn (the #2217 canon would merge these)
- ✓produces a unique slug for every real Ferris category
✓resolveCategorySlug (#2325 round-trip)Catalogue data4
- ✓round-trips: toCategorySlug(label) resolves back to that category
- ✓still resolves the raw categoryId (back-compat for old links → 308 heal)
- ✓returns undefined for an unknown slug (→ caller 404s)
- ✓prefers the readable-slug match over a raw-id collision deterministically
✓resolveBrowseSortFallback (#2124 — hono best-data ladder gap)Catalogue data4
- ✓bare browse data_quality → popular (pre-#2124 landing default)
- ✓category browse data_quality → revenue (pre-#2124 category default)
- ✓returns null for every non-data_quality sort (nothing to fall back from)
- ✓returns null for an undefined sort
✓fetchCatalogJsonCatalogue data4
- ✓returns the decoded body and sends the admin token
- ✓degrades to null on a non-2xx, naming the caller and its context
- ✓degrades to null on a transport failure rather than throwing into the render
- ✓degrades to null when a 200 body is not JSON
✓SORT_LABELS (CT-674 T6)Catalogue data4
- ✓provides a non-empty label for every SortByOption value
- ✓labels the best-data-first browse default Recommended (#2124)
- ✓uses the agreed-on Top sellers label for revenue
- ✓formats price labels human-readably
✓isMarketingHeroEligibleEquipment data4
- ✓accepts a normal product render URL
- ✓trusts a missing source URL (curated keeper set)
- ✓rejects schematics / line drawings
- ✓rejects logos, screenshots and brand chrome
✓New Holland Construction division projection (ct-2163)Equipment data4
- ✓registers the division record: shares NHL, indexed, not available
- ✓declares its projection onto (new-holland-agriculture, construction)
- ✓is excluded from the vendorCode round-trip so NHL keeps resolving the AG parent
- ✓carries the distinct Construction lockup + a static cover fallback
✓NH_TYPE_TILE_IMAGES — asset existenceEquipment data4
- ✓tractors resolves to a real file under public/
- ✓mowers resolves to a real file under public/
- ✓hay-tools resolves to a real file under public/
- ✓loaders resolves to a real file under public/
✓formatBrandedSkuForKnownBrandBusiness rules4
- ✓brands only when the manufacturer code is genuinely known
- ✓returns null for a missing or blank code (never mints CT-XXX-)
- ✓matches formatBrandedSku for a valid (real-code) input
- ✓still returns null when the part number is missing even with a real code
✓partUrl — THE /parts/ address ruleBusiness rules4
- ✓lowercases the slug
- ✓is idempotent — an already-canonical slug comes back unchanged
- ✓lowercases BEFORE encoding, so a slash PN keeps its uppercase %2F escape
- ✓never emits an uppercase character, whatever the input carries
✓partPath — the emitter every crawl-visible surface routes throughBusiness rules4
- ✓lowercases the backend's UPPERCASE canonical verdict
- ✓lowercases a locally synthesised slug too
- ✓lowercases the bare-PN fallback when no code is known
- ✓agrees with buildBrandedPartPath and canonicalSkuPath on one part
✓the SKU half of the fork stays uppercaseBusiness rules4
- ✓formatBrandedSku still emits an uppercase branded SKU
- ✓canonicalBrandedSku still returns the backend verdict verbatim
- ✓toOemPartNumber still preserves the PN's own case
- ✓repriceSku still keeps the branded prefix as the batch key
✓#2217 manufacturer slug grammar — lossless round-tripGoogle visibility4
- ✓every vendor code maps to a grammar-valid human-readable slug
- ✓serialize(code) -> slug -> parse(slug) === code (lossless)
- ✓accepts every spelling and collapses to one vendor code
- ✓leaves an unknown value untouched (no silent rewrite to a wrong brand)
✓titleCaseFromSlugGoogle visibility4
- ✓title-cases a single word
- ✓splits hyphens into spaces and title-cases each word
- ✓handles multi-word slugs
- ✓returns empty for empty input
✓composeBrandNameShared helpers4
- ✓prefixes the vendor when the name does not already lead with it
- ✓does not double the vendor when the name already leads with it
- ✓matches case-insensitively on a word boundary
- ✓returns the name when the vendor is empty
✓hero brand ticker (#1812, retargeted #2736)Home page4
- ✓every chip href targets its brand's catalog (/parts/brand/{slug})
- ✓the brand set equals the carried registry set
- ✓New Holland leads the ticker
- ✓exposes an accent color for each brand (drives the hover tint)
✓prepareCatalogListing — exact part-number match (#130270 → 13.0270)Parts pages4
- ✓matches on the backend's pnNorm, not just the printed part number
- ✓falls back to normalizing the part number when pnNorm is absent
- ✓encodes a slash-bearing slug instead of re-segmenting the path into a 404
- ✓renders the grid instead of guessing when two rows tie
✓FilterChipProduct grid4
- ✓renders label text
- ✓calls onClear when clicked
- ✓has accessible label for removal
- ✓renders the close indicator
✓buildTypeHeroSlidesEquipment data4
- ✓returns curated rotating slides when configured (NH Tractors)
- ✓falls back to the brand type cutout when no curated carousel exists (McHale Balers)
- ✓returns null when neither curated slides nor a type cutout exist
- ✓prefers curated slides over a supplied cutout
✓buildCrawlSections (#1507 launch narrowing → grouped crawl index)Equipment data4
- ✓groups live models by section, drops off-line models, uses bare labels
- ✓dedups a model that hono repeats across cursor pages (one anchor per slug)
- ✓keys + labels each section by its authored label (stable React key)
- ✓returns an empty section (not a missing one) when no model matches its lines
✓brand-hub equipment-card live-slug drift guardEquipment data4
- ✓mchale: authored category cards are live categoryIds (no 404-ing hub links)
- ✓ferris: authored category cards are live categoryIds (no 404-ing hub links)
- ✓ventrac: authored category cards are live categoryIds (no 404-ing hub links)
- ✓drift-checked at least one authored card overall
✓NH construction sub-categories (#1938)Equipment data4
- ✓declares the six equipment sub-categories the hub cards link to
- ✓resolves a known slug and rejects unknown / nullish slugs
- ✓narrows the construction set to a sub-category's product lines
- ✓matches the numeric Ford heritage tail for tractor-loaders only
✓BrandListingJsonLdDiagram pages4
- ✓emits exactly one BreadcrumbList JSON-LD with three positional rungs
- ✓points the parent rung at the cross-brand /brands entry
- ✓omits item URL on the leaf (current page) crumb
- ✓escapes attacker-shaped brand names via JsonLdScript (front#1440)
✓groupNhDrilldownModelsDiagram pages4
- ✓groups AG models by subLine, preserving first-seen order
- ✓buckets AG models with empty subLine under 'Other Models'
- ✓groups construction models by NH construction subcategory
- ✓returns [] for empty input
✓normalizeBrandGroups — does not over-merge distinct conceptsDiagram pages4
- ✓keeps Commercial vs Consumer separate
- ✓keeps Mower vs Rider separate
- ✓keeps the standalone Attachment group distinct from Attachment & Accessories
- ✓does not strip the trailing s from words ending in ss (Grass stays Grass)
✓normalizeBrandGroups — ordering and integrityDiagram pages4
- ✓sorts merged groups by model count descending
- ✓dedupes models by modelCode when a code appears under two spellings
- ✓returns an empty array unchanged
- ✓collapses the full 38-group Ferris shape to a deduplicated, smaller set
✓generic brand hub — all-models inlink (#1195)Brand pages4
- ✓renders exactly one crawlable link to /parts-diagrams/models
- ✓does NOT embed per-model parts-diagrams anchors inline (hub kept light)
- ✓renders no diagrams CTA on the hub (#2832 — the nav fork's card is retired)
- ✓renders exactly one h1 and never a parts counter or the placeholder
✓brandSurfaceHeadingBrand pages4
- ✓names the hub after the brand
- ✓names the Diagram view after what it actually lists
- ✓gives the two indexable brand surfaces different headings
- ✓lets a type scope name itself on either view
✓fetchBrandHubTypesBrand pages4
- ✓returns no types (flat path) when hasModels is false, never hitting the taxonomy fetch
- ✓returns no types when the brand is not carried (isCarried false)
- ✓fetches the equipment-type taxonomy when hasModels + isCarried are on
- ✓short-circuits a division-brand (NH Construction) to no types — no live fetch (ct-2163)
✓equipment-type parity — New Holland type-first (ct-2097)Brand pages4
- ✓mounts the shared Explorer for ?category=tractors
- ✓mounts the shared Explorer for ?category=combines
- ✓mounts the shared Explorer for ?category=loaders-handlers
- ✓mounts the shared Explorer for ?category=riding-mowers
✓isMultiBrandResponseDiagram pages4
- ✓returns true when Hono returned brand=null
- ✓returns false when single-brand response and one variant
- ✓returns false when all displayNames share the same brand prefix
- ✓returns true defensively when displayName brand prefixes disagree
✓VariantsClientViewDiagram pages4
- ✓renders chips for each distinct brand and defaults to the entry brand
- ✓filters table when a different brand chip is selected
- ✓invokes onBrandChange callback with the new brand
- ✓falls back to the first available brand when initialBrand is missing
✓fetchTypeModels — CNH all-models walk (#2349)Brand pages4
- ✓transient 503 → re-throws (to error boundary), NOT empty models
- ✓transient timeout → re-throws, NOT empty models
- ✓genuine 4xx → degrades to empty models (deterministic, cacheable)
- ✓healthy 200 → returns the model list
✓brand [slug]/type [typeSlug] page — non-exact slug 404s (heal is in next.config)Brand pages4
- ✓brand-catalog: a case-variant categoryId 404s and never redirects in-render
- ✓CNH: a case-variant equipment-type slug 404s and never redirects in-render
- ✓a genuinely unknown type 404s
- ✓an exact match resolves without redirecting
✓<BrandStripRail>Brand pages4
- ✓keeps ordinary brand links in a single horizontal navigation rail
- ✓shows desktop paging controls only for overflow and scrolls by most of the viewport
- ✓reveals an offscreen active brand without animation after a route switch
- ✓respects reduced-motion when a paging arrow is used
✓applyView (flat-grid windowing)Brand pages4
- ✓windows to the requested page and orders cards within it
- ✓filters by search before windowing and reports the match count
- ✓sorts by most diagrams via the visible order, leaving the DOM in place
- ✓clamps an out-of-range page and reports zero matches for a miss
✓BRAND_MAP logo marksBusiness rules3
- ✓every mark carries the ratio the layout reserves its box from
- ✓has marks to check, so the assertion above is not vacuous
- ✓states a plausible ratio for every mark
✓<BrowseByEquipmentHint>Product grid3
- ✓renders an inline link to /parts-diagrams by default
- ✓renders the block variant with descriptive copy
- ✓each variant carries a stable analytics marker for GA4
✓CatalogBrandBannerProduct grid3
- ✓renders the CT watermark as a masked solid colour, never as an <img>
- ✓hides the decorative layer on phones (kept out of the mobile LCP path)
- ✓renders selected brand logos as masked silhouettes (no <img>)
✓catalog price display (search payload → card)Product grid3
- ✓renders the price on the card when the search payload carries price.list
- ✓shows no price or quote CTA when the payload omits price (#1863)
- ✓keeps the leak guard: wholesale/net tiers never reach the card, list does
✓ProductCard — the card's only link is its title (#3556)Product grid3
- ✓nests no interactive content inside the anchor
- ✓puts exactly one link in the card, inside the h3, named by brand + title
- ✓paints the click area back over the card with the ::after overlay
✓ProductCard — held row navigates client-side only (#3843)Product grid3
- ✓emits no href — the /lookup URL never enters the markup
- ✓router.pushes to the /lookup twin on click
- ✓activates on Enter, not Space (nonstandard on role=link)
✓<ProductListing> list semanticsProduct grid3
- ✓renders counter as a ul of li
- ✓renders grid as a ul of li
- ✓renders cards as a ul of li
✓shouldShowBrandToggle with the carried-brand setProduct grid3
- ✓includes a non-New-Holland carried brand (Ferris)
- ✓shows for a non-New-Holland carried brand when exactly one is selected
- ✓hides for a carried brand when more than one brand is selected
✓SortDropdownProduct grid3
- ✓renders without errors
- ✓renders with aria-label for accessibility
- ✓renders as disabled when disabled prop is true
✓<BrandIdentificationHelp>Brand pages3
- ✓renders nothing when the brand has no identification image (Ferris today)
- ✓renders nothing when the brand is unknown
- ✓renders the card with the registry image / alt / caption when present
✓logoSrc overrides publish on our own host (#3804)Brand pages3
- ✓moves a raw bucket override onto our own media origin
- ✓hands a /public path to the optimizer as itself
- ✓leaves a vector mark unoptimized (#3452)
✓directoryBrandListCopyBrand pages3
- ✓reads as a sentence, with the Oxford conjunction before the last brand
- ✓names each brand once — the NH AG/CE split must not double up
- ✓degrades to a bare name for a single brand, and to empty for none
✓buildBrandDirectorySchemaBrand pages3
- ✓emits a CollectionPage holding one Brand node per carried brand
- ✓absolutises every URL — a relative one in JSON-LD resolves against the wrong base
- ✓omits `logo` rather than emitting an empty one when a brand has no mark
✓resolveBrandCardPhotoBrand pages3
- ✓returns the authored registry cover when present, even if marketing media exists
- ✓falls back to the first marketing-media hero when there is no authored cover
- ✓returns undefined when neither rung yields an asset (graceful placeholder)
✓brandCodeToProviderBusiness rules3
- ✓maps known brand codes
- ✓is case-insensitive
- ✓returns null for unknown codes
✓brandCodeToProvider accepts DB vendorCodesBusiness rules3
- ✓maps KNZ (DB vendorCode) to kinze
- ✓maps HVT (DB vendorCode) to harvesttec
- ✓maps KIN (internal code) to kinze
✓providerToVendorCodeBusiness rules3
- ✓returns DB vendorCodes for active catalog vendors
- ✓returns null for inventory-only providers
- ✓returns null for unknown providers
✓brandCategoriesToTypes (#2656 Parts⇄Diagrams rail parity)Catalogue data3
- ✓maps categories one-to-one, preserving order, labels and counts
- ✓emits the readable name-slug, never the raw categoryId
- ✓every rail slug resolves back to its category (the drill-down round-trip)
✓catalogServiceHeadersCatalogue data3
- ✓adds the admin token when the environment has one
- ✓omits the header entirely when unset — dev and preview have no secret
- ✓does not mutate the caller's base headers
✓shingles + jaccardCatalogue data3
- ✓scores two slot-filled sentences off one frame as near-identical
- ✓scores genuinely different copy as low similarity
- ✓is symmetric and self-identical
✓marketingMediaUrlEquipment data3
- ✓composes the contract delivery URL
- ✓uses the ag/ce prefix for New Holland divisions
- ✓strips a leading dot from the extension
✓getAppliedModelImageEquipment data3
- ✓normalizes a bare-path entry to { src } with no confidence
- ✓returns the { src, confidence } record for a scored entry (case-insensitive)
- ✓returns null for an unmapped code or missing args
✓brandRailTypesFromEquipmentTypesEquipment data3
- ✓drops NH's CE construction type (it 308s to the CE brand hub)
- ✓drops a sibling manufacturer slug leaking into a parent brand's list (#2251)
- ✓treats a missing list as empty (a taxonomy blip never throws at the rail)
✓Marcrest parity — activated as a carried navigable-noindex brandEquipment data3
- ✓is present in the registry as available:true / seoIndexed:false (navigable, noindex)
- ✓resolves a display name and branding (display maps still cover it)
- ✓IS carried — included in the carried/available derivation
✓brand identification helper — identificationImageSrcEquipment data3
- ✓leaves ferris without an identification image today (block stays hidden)
- ✓leaves every carried brand without an identification image (none authored yet)
- ✓keeps the identification fields optional on the type
✓repriceSkuBusiness rules3
- ✓keeps the brand prefix so a brand line resolves to its own schema, not the CNH bucket
- ✓strips the -PK{N} pack-alias suffix but keeps the brand prefix
- ✓falls back to the bare partNumber when no sku (CNH line)
✓buildBrandedPartPath (#823)Business rules3
- ✓builds the branded /parts/ct-{BRAND}-{PN} path when a code is known
- ✓falls back to the bare /parts/{PN} path when brand code is missing (no synthetic XXX)
- ✓percent-encodes slashes in the PN (branded and bare)
✓canonicalSkuPath (#3650)Business rules3
- ✓percent-encodes the slug so a slash PN keeps its own single-segment URL
- ✓leaves space PNs on their existing %20 form
- ✓returns null for an absent or empty verdict so callers keep their fallback
✓per-type copy (#2554)Google visibility3
- ✓gives different equipment types different part vocabulary
- ✓falls back to a generic non-empty vocab for an unknown type
- ✓produces a unique, SERP-length meta description per type
✓robotsForListingDepth (#2367 Phase 2 gate)Google visibility3
- ✓dark default — flag off ⇒ undefined even for the thinnest listing
- ✓armed — noindexes the thin or deep listing, leaves a rich shallow one to inherit
- ✓armed but indexing globally off ⇒ undefined (gate never overrides the master switch)
✓catalog-view-storeApp state3
- ✓defaults bomCompact to false (unwrap-by-default per CT-674)
- ✓toggleBomCompact flips the value
- ✓setBomCompact sets an explicit value
✓resolveCategoryIdToTypeSlug — legacy categoryId → /type/ slug (ADR-0003)Parts pages3
- ✓maps a known categoryId to the SAME name-slug the rail links to
- ✓returns null for an unknown/stale id (param dropped, never mis-filtered)
- ✓returns null when the taxonomy fetch fails (fail-soft, no redirect)
✓fetchCatalogData — facets ride their own budgetParts pages3
- ✓degrades facets to null when the bucket walk outruns FACET_BUDGET_MS, keeping the grid
- ✓returns real facets when the walk resolves in time
- ✓still throws the page-data budget error when SEARCH itself outruns it
✓PartsCatalogClient — client-filtered zero results (#2816)Parts pages3
- ✓shows the empty state when a client-side facet filters every part out
- ✓offers the culprit facet as a removable chip
- ✓renders the grid when the facet is off
✓useCatalogNavigation.selectCategoryCatalogue data3
- ✓mints a clean ?categoryId= URL from a sorted/paged/filtered one (#3588)
- ✓keeps filters picked in the same act, drops ones merely already in the URL
- ✓still merges for a non-category filter change — reset is opt-in
✓getTypeHeroSlidesEquipment data3
- ✓returns curated, well-formed slides for New Holland tractors
- ✓returns the F5-560 banner for McHale Fixed Chamber Round Balers (#2575)
- ✓returns null for an unconfigured brand × type
✓resolveTypeHubCapabilitiesEquipment data3
- ✓gives CNH the full profile (equipment links, ItemList)
- ✓drops equipment/ItemList for a brand-catalog vendor
- ✓tracks hero presence and never assumes a family mapping
✓buildBrandItemListSchema (front#1429 A5)Diagram pages3
- ✓emits an ItemList of BOM part numbers (no Product / price)
- ✓names a null-description row by its part number alone
- ✓emits an empty ItemList shell for zero parts
✓resolveTargetAssemblyCode — assembly (deep route) membership guardDiagram pages3
- ✓returns the assemblyCode when it is a member of the model
- ✓returns null (→ caller 404s) when the assemblyCode is not a member
- ✓returns null for a model with no assemblies
✓brandAssemblyCanonical — model-scoped shapeDiagram pages3
- ✓builds /parts-diagrams/{slug}/{model}/{assembly}
- ✓URL-encodes the model and assembly segments
- ✓does not encode the slug (already a clean lowercase slug)
✓buildBrandCanonical (#2774)Brand pages3
- ✓page 1 (default) → the bare brand path
- ✓page N > 1 → self-referential ?page= canonical
- ✓non-finite page falls back to the bare path
✓featured-parts rail removed (#1737)Brand pages3
- ✓never renders the rail or its heading on a thin brand
- ✓never renders any rail on the NH branch
- ✓fetches no parts preview at all — types are the hub's only data dependency
✓no counters on the hubBrand pages3
- ✓never renders a parts counter
- ✓consults the brands summary for capability flags, not a counter (ct-2036)
- ✓rethrows a transient 5xx from the types fetch so the runtime error boundary fires
✓resolveDiagramsHref — the switcher's Diagram-tab destination (#2952)Brand pages3
- ✓division (NH Construction) carries the active CE sub-category as a path
- ✓division with no active type → the bare co-located diagrams tab
- ✓type-first brand carries the active type as a path (unchanged by the fix)
✓BrandFlagsTableAccount pages3
- ✓renders one row per registry brand, seeded from the registry
- ✓keeps every switch disabled — there is no write path yet
- ✓labels each brand with the state its two flags add up to
✓fetchBrandHubCrawlSectionsBrand pages3
- ✓returns null for a brand whose hub declares no crawl sections (ferris)
- ✓projects the division onto (new-holland-agriculture, construction) and buckets the models
- ✓returns null when the projected model fetch fails (hub renders without the index)
✓<HubContactCallout>Brand pages3
- ✓renders the contact body copy
- ✓renders the phone as a tel: link with the dealer label
- ✓applies a passthrough className
✓NH brand landing — equipment-type cardsBrand pages3
- ✓has the documented 12 equipment-type cards (John's SEO spec)
- ✓partitions authored cards into 11 AG + 1 CE (#1507)
- ✓every equipment-type card has a non-empty slug + label
✓VariantsYearFilterDiagram pages3
- ✓narrows to overlapping variants on selection, keeps no-year variants as safe fallback, restores on 'all'
- ✓emits the parsed year or null via onYearChange
- ✓hides the year selector when no variant exposes year data
✓<PartsFiltersSidebar> — #2691 empty Categories hidingParts pages3
- ✓hides Categories when facets.categories is empty (adapter brands — no listFacets backend)
- ✓hides Categories when facets.categories is explicitly an empty array
- ✓renders Categories with real options (search MV — /parts, NH)
✓diagramsTypeNavHrefBrand pages3
- ✓navigates a top-level type as a PATH on the co-located hub base
- ✓keeps the standalone landing on the `?category=` query alias (indexed canonical)
- ✓percent-encodes free-form brand-catalog category slugs on both bases
✓brandTypeExplorerHrefBrand pages3
- ✓the `query` variant emits the co-located PATH form off a `/parts/brand/.../diagrams` base
- ✓the `query` variant defaults its base to the co-located diagrams tab (#2714)
- ✓the `brand-type` variant stays the canonical Part hub path, base-agnostic
✓brand-type opengraph-image generateStaticParams (front#1001)Brand pages3
- ✓throws when every brand-type fetch rejects (fail-loud guard)
- ✓returns the surviving entries when only some brand fetches fail
- ✓returns all combos when every brand fetch succeeds
✓brand-catalog type hub — readable NAME-slug canonical (#2325)Brand pages3
- ✓canonical is the per-category NAME slug, NOT the cross-brand canon slug
- ✓keeps Outfront a DISTINCT hub instead of merging it into base Zero-Turn
- ✓raw categoryId still resolves, consolidating onto the name-slug canonical
✓resolveNhConstructionSubcategory (ct-2580 — CE sub-category → Part-view model-key scope)Brand pages3
- ✓scopes a sub-category to its models' NHL::{modelNumber} fitment keys (not a diagrams bounce)
- ✓returns null for a slug that maps to no CE sub-category (a genuine 404)
- ✓caps the fitment sample at 14 to stay under the browse COUNT budget (hub#262 lifts it)
✓<RailArrow>Brand pages3
- ✓uses the given label as its accessible name and fires onClick
- ✓disables the button when disabled is true
- ✓lets a caller's className win over the base position/focus classes (last-wins merge)
✓buildSiblingDiagramsHrefs (diagrams-surface vendor switcher)Brand pages3
- ✓maps every carried brand to its Diagram-view base, never the brand-hub Part page
- ✓co-locates model-group brands' sibling pills onto the hub Diagram tab (#2367)
- ✓scopes New Holland Construction to the NH landing's construction category
✓scrollActiveCategoryIntoViewBrand pages3
- ✓leaves the scroll position alone when the active row is already in view
- ✓centres an active row below the fold inside the viewport (page never moves)
- ✓clamps to the top so a near-top active row never scrolls negative
✓applyView — lite tail image materialization (#3160)Brand pages3
- ✓injects the deferred cover photo (+ Photo badge) when a card is revealed, once
- ✓uses object-contain and no Photo badge for a cutout
- ✓materializes only revealed cards — an off-page card stays image-free
✓logo marks publish on our own host (#3797)Business rules2
- ✓moves a registry logo and a BRAND_MAP logo onto /img
- ✓leaves a /public logo and a brand with no logo untouched
✓<CardPrice> (#3558)Product grid2
- ✓announces the price with a label, without showing one
- ✓renders nothing without a price
✓catalogue row availability for a shelf part with no price (#3543)Product grid2
- ✓reads Out of Stock and shows no in-stock dot
- ✓leaves a priced shelf part reading its Clinton count
✓catalogue card badge for a shelf part with no price (#3543)Product grid2
- ✓shows no Clinton stock line
- ✓keeps the Clinton stock line for a priced shelf part
✓CatalogEmptyStateProduct grid2
- ✓renders the Sprint 14 EmptyState slate when no filters are active
- ✓renders the filter-removal description when chips are active
✓CatalogSkeletonProduct grid2
- ✓renders with children
- ✓renders the filter aside, and no second <main> (#3358)
✓listing product-image alt (#1328)Product grid2
- ✓partCardProps mirrors the heading title into the image + carousel alt for an enriched row
- ✓ProductTile renders a non-empty product-image alt equal to the heading title
✓PartsListTable — branded cart identityProduct grid2
- ✓stamps productId AND sku as CT-{BRAND}-{PN} on add
- ✓uses a distinct branded sku for the same PN under a different brand
✓PartsListTable — qty stepper caps to real stock (#2258)Product grid2
- ✓snaps a typed 99 down to the part's order ceiling
- ✓keeps the familiar 99 range when no ceiling signal is present
✓PartsListTable — a held row's twin URL never reaches the markupProduct grid2
- ✓renders no /lookup URL for a lookupOnly row, but keeps it navigable
- ✓still emits a real href for an indexable row
✓ProductCard — image edit affordance (admin-layer M3)Product grid2
- ✓renders the image region byte-identically and NO admin chrome when the gate is off (editContext, customer default)
- ✓omitting editContext leaves the card DOM unchanged (default customer path)
✓SchematicViewer — branded missing-schematic placeholderAssembly views2
- ✓renders the OEM wordmark on the dot-grid when a brand code is supplied
- ✓falls back to the neutral icon when no brand code is supplied
✓<DirectoryTileGrid>Brand pages2
- ✓loads the first row's cover photos eagerly and leaves the rest lazy
- ✓renders a <ul> whose every child is an <li>, trailing cell included (#3571)
✓<ExplorerModelCard> — no-diagram brand degradationBrand pages2
- ✓shops the brand parts catalog (no empty diagram link) for a zero-assembly catalog model
- ✓keeps the diagram drill-down for a catalog model that DOES carry assemblies
✓<ModelMediaWell> (#2698 model-hero category-image fallback)Brand pages2
- ✓renders the type-level category illustration, object-contain, for a hero-less model whose type resolves one
- ✓still renders the branded placeholder for a genuinely unmapped type (no regression)
✓view-switch document guard fallback watchdogBrand pages2
- ✓releases and announces settled even after a stale generation bump
- ✓still clears on the ordinary same-generation timeout
✓brandCodeToProvider uses MongoDB-format slugsBusiness rules2
- ✓maps BNS to briggs_stratton (underscore, matching MongoDB)
- ✓maps HAR to harvesttec (no separator, matching MongoDB)
✓BRAND_VISIBILITY_BRANDSAdmin logic2
- ✓excludes division projections (shared vendorCode)
- ✓covers the carried cohort the console manages
✓buildBrandRowsAdmin logic2
- ✓seeds each row from the registry when there are no overrides
- ✓applies a partial override on top of the seed
✓isDivisionBrand (ct-2163)Catalogue data2
- ✓is true only for a division-brand slug
- ✓is false for primary brands and unknown slugs
✓brandHasDiagramsSurface — capability gate (#2367)Catalogue data2
- ✓is true for type-first (NH) and every model-group adapter brand WITH a taxonomy
- ✓is false for an unknown slug (no registry record → no vendor code)
✓brandDiagramsBasePath — co-located for every diagrams-bearing brand (#2367)Catalogue data2
- ✓co-locates type-first (NH) diagrams under the catalog path
- ✓co-locates model-group adapter brands' diagrams under the catalog path
✓BRAND_SLUG_BY_CODECatalogue data2
- ✓maps known manufacturer codes to folder slugs
- ✓maps the canonical Ferris (FER) and Ventrac (VNT) codes
✓brandMarketingCoverSlides (seed-driven)Equipment data2
- ✓returns curated, CDN-contract slides for a seeded brand
- ✓stays inert for a carried-but-unseeded brand and non-carried brands
✓brandRailTypesFromCategoriesEquipment data2
- ✓drops a malformed category row carrying no categoryId
- ✓keys the tile by the readable name-slug, not the raw categoryId
✓carriedPartsHrefInventory data2
- ✓links a carried make into the catalogue by vendor code
- ✓yields no link for a make we do not carry
✓held-brand listing agrees with its /parts/brand twin (#3840)Google visibility2
- ✓noindexes ?manufacturer=<held brand>
- ✓leaves an indexed brand alone
✓moved hub /brand/[slug] — routing gate (#2367)Site pages2
- ✓renders the moved hub for a carried primary brand
- ✓404s the moved hub for a non-carried slug
✓prepareCatalogListingForAdapter — Per-page preset forwarding (#2833)Parts pages2
- ✓forwards the selected browse preset (?pageSize=80) to the adapter feed
- ✓keeps search mode at the fixed catalog page size (a stray ?pageSize= must not widen it)
✓prepareCatalogListing — a sole exact match never routes through /lookupParts pages2
- ✓sends an INDEXABLE sole match to its own /parts canonical
- ✓keeps the grid for a HELD sole match instead of redirecting at all
✓PartsCatalogClient — pagination hrefs carry canonical params onlyParts pages2
- ✓drops display + sort params, keeps the search query
- ✓keeps the manufacturer + category axes
✓hasTypeHeroVisualEquipment data2
- ✓is true when slides are present
- ✓is false for null or empty slides
✓buildBrandBreadcrumbSchema (front#1429 A5)Diagram pages2
- ✓emits Home > Parts Diagrams > {brand} > assembly with positions 1..N
- ✓inserts the chapterName between brand and assembly when present
✓<EmptyBrandDiagrams>Diagram pages2
- ✓interpolates the brand display name into the empty-state copy
- ✓renders as a non-error informational block (no heading, no alert role)
✓<EquipmentDiagramModelCard>Diagram pages2
- ✓links to the canonical /parts-diagrams/model/{slug}/parts-diagrams URL
- ✓emits a lowercased data-search haystack starting with the model code
✓brandGlobalAssemblyCanonical — no-model fallback shapeDiagram pages2
- ✓builds /parts-diagrams/{slug}/assemblies/{assembly}
- ✓URL-encodes the assembly segment
✓brandModelDiagramsCanonical — model grid shapeDiagram pages2
- ✓builds /parts-diagrams/{slug}/{model}
- ✓URL-encodes the model segment
✓/parts/brand/[slug]/not-found generateMetadataBrand pages2
- ✓post-flip (IS_INDEXING_ENABLED=true) emits NOINDEX_NOFOLLOW_ROBOTS
- ✓pre-flip (IS_INDEXING_ENABLED=false) omits robots so layout's noindex,nofollow is inherited
✓<PartsFiltersSidebar> — brand-scoped surface hides the Brand filterParts pages2
- ✓renders the Brand filter on the global listing (axes omitted)
- ✓removes the Brand filter on a brand-scoped surface (manufacturer forced by the path)
✓<PartsFiltersSidebar> — #2793 ships-same-day axis gatingParts pages2
- ✓renders the ships-same-day toggle when the axis is supported (search MV — omitted)
- ✓hides only the ships-same-day toggle when its axis is off but availability stays on
✓EquipmentBrandPickerDiagram pages2
- ✓links each candidate to its own ?brand=-scoped equipment URL
- ✓renders one link per candidate
✓/parts/brand/[slug]/type/[typeSlug]/not-found generateMetadataBrand pages2
- ✓post-flip (IS_INDEXING_ENABLED=true) emits NOINDEX_NOFOLLOW_ROBOTS
- ✓pre-flip (IS_INDEXING_ENABLED=false) omits robots so layout's noindex,nofollow is inherited
✓<BrandTypeExplorerBody>Brand pages2
- ✓renders the grid and no Part/Diagram toggle
- ✓renders the empty state (not the grid) when the catalog is empty
✓TypePageFiltersSidebarBrand pages2
- ✓previews live facet counts derived from the page models
- ✓renders the inert scaffold without opacity-dimmed text (AA contrast)
✓CatalogResultsGridProduct grid1
- ✓packs 180px tracks for compact and 280px for roomier modes
✓ViewModeSwitchProduct grid1
- ✓presses the active mode and declares no tab roles (#3570)
✓PageSizeToggleProduct grid1
- ✓presses the active page size and declares no tab roles (#3570)
✓PartsListTable — canonical PDP links (#3193)Product grid1
- ✓links every row to the branded canonical, one shape per row
✓ProductCard — compact placeholder + brand pill (CT-2078)Product grid1
- ✓suppresses the placeholder PN chip on compact so it does not stack under the brand pill
✓<BrandViewToggleRow>Brand pages1
- ✓renders exactly one toggle, in the page gutter, and forwards its destinations
✓distinctDirectoryBrandsBrand pages1
- ✓collapses the New Holland AG/CE split back to one brand entry
✓<ViewSwitchBoundary> — scoped to the view-switch transitionBrand pages1
- ✓defaults every untyped navigation to no animation, opting in only on view-switch
✓statusLabelAdmin logic1
- ✓maps every status to its human label
✓seedFlagsForAdmin logic1
- ✓maps registry available -> users and seoIndexed -> SEO
✓fullyOnCountAdmin logic1
- ✓counts only rows with both switches on
✓maskValuesCatalogue data1
- ✓collapses part numbers and dimensions to one token but keeps model names
✓brandHasMarketingMediaEquipment data1
✓BRAND_TYPE_IMAGE_MANIFESTEquipment data1
✓/attachments — the same client over a pre-filtered sliceEquipment pages1
- ✓owns its heading and counts attachments, not machines
✓PartsCatalogClient — did-you-mean banner live region (#811)Parts pages1
- ✓announces the correction from an <output> that stays a flex row
✓clearedCatalogParamsCatalogue data1
- ✓covers every catalog parser key
✓cachedGetBrandAssembly (front#2913 shared placeholder guard)Diagram pages1
- ✓drops the 99999999 sentinel row and keeps a real part
✓NhJsonLdBrand pages1
- ✓mirrors the visible trail: Home / Brands / New Holland
✓/parts/brand/[slug]/diagrams — generateMetadata (#2714)Brand pages1
- ✓self-canonicals the bare tab and does not hardcode noindex (per-brand gate governs)
✓brand-catalog type hub — readable canonical (front#2217)Brand pages1
- ✓resolves both the raw id and the readable slug, consolidating onto the readable canonical
✓TypeModelsEmptyStateBrand pages1
- ✓names the brand + type and routes the visitor to the diagrams funnel
What we walk through in a real browser27 journeys
○Go-live per-brand content-consistency gate (front#2930)Browser journey6
- ○New Holland (Ag) — content contract holds on a live sampled PDP
- ○Kuhn — content contract holds on a live sampled PDP
- ○Ventrac — content contract holds on a live sampled PDP
- ○Ferris — content contract holds on a live sampled PDP
- ○McHale — content contract holds on a live sampled PDP
- ○Marcrest — content contract holds on a live sampled PDP
○McHale PDP (CT-MCH-ALA00005)Browser journey5
- ○renders 200 with the part title
- ○shows a price, exactly one availability badge, and the buy CTA
- ○states a dispatch expectation with no channel wording
- ○Product JSON-LD rides the index gate: priced Offer on /parts, none on /lookup
- ○streams the lower half into the page (Buyers & extras present)
○Ventrac PDP (CT-VNT-00.0204)Browser journey5
- ○renders 200 with the part title
- ○shows a price, exactly one availability badge, and the buy CTA
- ○states a dispatch expectation with no channel wording
- ○Product JSON-LD rides the index gate: priced Offer on /parts, none on /lookup
- ○streams the lower half into the page (Buyers & extras present)
○Ferris PDP (CT-FER-1650347SM)Browser journey5
- ○renders 200 with the part title
- ○shows a price, exactly one availability badge, and the buy CTA
- ○states a dispatch expectation with no channel wording
- ○Product JSON-LD rides the index gate: priced Offer on /parts, none on /lookup
- ○streams the lower half into the page (Buyers & extras present)
○Kuhn PDP (CT-KUH-40120050)Browser journey5
- ○renders 200 with the part title
- ○shows a price, exactly one availability badge, and the buy CTA
- ○states a dispatch expectation with no channel wording
- ○Product JSON-LD rides the index gate: priced Offer on /parts, none on /lookup
- ○streams the lower half into the page (Buyers & extras present)
○sub-fetch surface probes (front#3009 / #3023)Browser journey5
- ○McHale CT-MCH-ALA00005: /similar responds 200, not the 404 storm
- ○Ventrac CT-VNT-00.0204: /similar responds 200, not the 404 storm
- ○Ferris CT-FER-1650347SM: /similar responds 200, not the 404 storm
- ○Kuhn CT-KUH-40120050: /similar responds 200, not the 404 storm
- ○CNH control: bare-PN /similar responds 200 (outage discriminator)
○Brand × equipment-type hubBrowser journey5
- ○brand hub surfaces the Equipment Types block
- ○type hub renders H1 and links onward to a real part
- ○type hub model filter narrows the list and clears
- ○unknown type slug for a known brand renders not-found (HTTP 404 on Vercel edge)
- ○unknown brand slug renders not-found (HTTP 404 on Vercel edge)
○Brand Part ⇄ Diagram content coherenceBrowser journey5
- ○both tabs agree the brand has content
- ○repeated flips never empty either grid
- ○a category drill and the flips around it keep both surfaces populated
- ○changing brand mid-flip lands on the new brand's own populated grid
- ○the outgoing view stays hidden after the switch instead of showing through
○Ferris diagrams journeyBrowser journey3
- ○Ferris tile on /brands leads into the brand @smoke
- ○Ferris landing renders model groups (or skips if backend not wired)
- ○Ferris model card → diagram grid → assembly viewer (ct-1891 — ARI schematic + hotspot + BOM + noindex)
○Ventrac diagrams journeyBrowser journey3
- ○Ventrac tile on /brands leads into the brand @smoke
- ○Ventrac landing renders model groups (or skips if backend not wired)
- ○Ventrac model card → diagram grid → assembly viewer (ct-1891 — ARI schematic + hotspot + BOM + noindex)
○McHale diagrams journeyBrowser journey3
- ○McHale tile on /brands leads into the brand @smoke
- ○McHale landing renders model groups (or skips if backend not wired)
- ○McHale model card → diagram grid → assembly viewer (ct-1891 — ARI schematic + hotspot + BOM + noindex)
○Marcrest diagrams journeyBrowser journey3
- ○Marcrest tile on /brands leads into the brand @smoke
- ○Marcrest landing renders model groups (or skips if backend not wired)
- ○Marcrest model card → diagram grid → assembly viewer (ct-1891 — ARI schematic + hotspot + BOM + noindex)
○Kuhn diagrams journeyBrowser journey3
- ○Kuhn tile on /brands leads into the brand @smoke
- ○Kuhn landing renders model groups (or skips if backend not wired)
- ○Kuhn model card → diagram grid → assembly viewer (ct-1891 — ARI schematic + hotspot + BOM + noindex)
○New Holland — diagrams-first landing + view toggle (ct-1808)Browser journey3
- ○landing renders with the 'Brand view' toggle group and Diagrams tab active
- ○clicking the Part-view leg navigates to the brand catalog
- ○brand hub URL renders in place — no diagrams 308 (ct-2047)
○Ferris diagrams — live model filterBrowser journey3
- ○typing a model term narrows the visible group sections
- ○clearing the filter restores all group sections
- ○nonsense query shows empty state with a clear button
○compact tractor parts-diagrams listing — soft-503 regressionBrowser journey3
- ○new-holland-boomer-40-compact-w-cab-tier-4b-na renders chapters, not ServiceUnavailable
- ○new-holland-workmaster-95 renders chapters, not ServiceUnavailable
- ○noindex meta is emitted when ServiceUnavailable renders
○Multi-brand PN search attribution (#1910) @smokeBrowser journey3
- ○search API returns each colliding brand as its own branded row
- ○each brand renders its own card with the correct branded link + label
- ○clicking each result lands on the correct-brand PDP — no wrong-brand landing
○kuhn — parts vs diagrams type navigation (ct-2781)Browser journey2
- ○kuhn type page stays in the parts context with a filtered parts grid
- ○kuhn diagrams type page renders the model grid
○marcrest — parts vs diagrams type navigation (ct-2781)Browser journey2
- ○marcrest type page stays in the parts context with a filtered parts grid
- ○marcrest diagrams type page renders the model grid
○kress — parts vs diagrams type navigation (ct-2781)Browser journey2
- ○kress type page stays in the parts context with a filtered parts grid
- ○kress diagrams type page renders the model grid
○agco — parts vs diagrams type navigation (ct-2781)Browser journey2
- ○agco type page stays in the parts context with a filtered parts grid
- ○agco diagrams type page renders the model grid
○landoll — parts vs diagrams type navigation (ct-2781)Browser journey2
- ○landoll type page stays in the parts context with a filtered parts grid
- ○landoll diagrams type page renders the model grid
○alias slug forms also resolve to NHLBrowser journey2
- ○?manufacturer=newholland resolves
- ○?manufacturer=new-holland resolves
○Brand-catalog type grid (equipment-types axis)Browser journey1
- ○McHale type page renders a populated model grid matching the count readout
○Ferris legacy SKU (CT-FRR-*)Browser journey1
- ○308-redirects onto the canonical CT-FER PDP, which renders
○New Holland catalog — model-card media-well render contractBrowser journey1
- ○every tractor model card renders a decoded photo or an explicit placeholder
○front#832 — manufacturer slug vs code parityBrowser journey1
- ○both ?manufacturer=new-holland-agriculture and ?manufacturer=NHL render a non-empty listing with NHL parts
Automated checks748
Browser journeys89
Code exercised92.8%
What we check automatically113 groups
✓handlePartsRoutingRequest routing99
- ✓returns a single 308 to the BRANDED replacement canonical for superseded_redirect parts (#823)
- ✓falls back to the bare replacement PN when the part carries no manufacturer.code (#823)
- ✓rewrites unknown PNs to /parts-not-found with 404 + noindex
- ✓404s a dont_list part with neither a price nor an image
- ✓404s every no_cnh_data part, priced or not
- ✓lets a priced dont_list part through to the page
- ✓lets an imaged dont_list part through to the page
- ✓404s a withdrawn part rather than 308ing its signal to a live replacement
- ✓fails open on a probe error — a search blip never 404s a live PDP
- ✓returns null (falls through to normal rendering) for regular sellable parts
- ✓returns null when superseded_redirect lacks a finalReplacementPn
- ✓returns null when finalReplacementPn equals the current PN (self-loop guard)
- ✓fails open (null) when Hono is unreachable — we never 500 the site on upstream errors
- ✓fails open on upstream 5xx and doesn't cache the failure
- ✓retries once on a transient throttle (429), then 308s
- ✓retries exactly once then fails open (null) when both attempts error
- ✓does NOT retry on a definitive 404 (real not-found is a single probe)
- ✓does NOT retry when the first attempt already succeeds
- ✓caches successful probes so repeated requests hit Hono once
- ✓returns null when SEARCH_SERVICE_URL is missing (misconfigured env — fail open)
- ✓redirects legacy CT-FRR URLs to CT-FER without a Search probe
- ✓routes ct-fer-0020x3ma to the brand adapter, never to /api/parts/
- ✓routes ct-vnt-49001 to the brand adapter, never to /api/parts/
- ✓routes ct-kuh-k5012340 to the brand adapter, never to /api/parts/
- ✓still 404s a lowercase brand SKU the adapter does not have
- ✓fails open (null) for CT-FER-0020X3MA WITHOUT probing the CNH /api/parts path
- ✓fails open (null) for CT-VNT-49001 WITHOUT probing the CNH /api/parts path
- ✓fails open (null) for CT-MCH-CST00094 WITHOUT probing the CNH /api/parts path
- ✓fails open (null) for CT-MAR-100-0210 WITHOUT probing the CNH /api/parts path
- ✓fails open (null) for CT-KUH-K5012340 WITHOUT probing the CNH /api/parts path
- ✓404s a dont_list brand part with neither price nor image
- ✓keeps a priced dont_list brand part reachable
- ✓keeps an imaged dont_list brand part reachable
- ✓keeps a sellable brand part reachable
- ✓404s a PN the adapter does not have (front#3743)
- ✓404s a missing PN for every brand-catalog vendor: FER
- ✓404s a missing PN for every brand-catalog vendor: KUH
- ✓404s a missing PN for every brand-catalog vendor: MCH
- ✓404s a missing PN for every brand-catalog vendor: VNT
- ✓404s a missing PN for every brand-catalog vendor: AGC
- ✓404s a missing PN for every brand-catalog vendor: MAR
- ✓404s a missing PN for every brand-catalog vendor: KRE
- ✓fails open on a transient adapter error
- ✓still probes a RAW (non-branded) PN through the CNH path — the fence is SKU-form-only
- ✓404s CT-KUHN-80450320 instead of 308ing it onto the New Holland part
- ✓404s CT-ZZZ-80450320 instead of 308ing it onto the New Holland part
- ✓404s CT-QQQQ-80450320 instead of 308ing it onto the New Holland part
- ✓404s CT-BRIGGS-5103868 — unparseable means unresolvable, not "no brand typed"
- ✓404s CT-AG_BAG-AA1541231 — unparseable means unresolvable, not "no brand typed"
- ✓404s CT-TEXTRON-651489 — unparseable means unresolvable, not "no brand typed"
- ✓404s CT-UTICA_MACK-6759 — unparseable means unresolvable, not "no brand typed"
- ✓404s CT-MIDWAY_BEARINGS-UCFL209-28 — unparseable means unresolvable, not "no brand typed"
- ✓404s CT-TUBELINE-35785 — unparseable means unresolvable, not "no brand typed"
- ✓404s CT-BLUE_DIAMOND_ATT-203720 — unparseable means unresolvable, not "no brand typed"
- ✓404s an unparseable code even when the part carries no manufacturer.code
- ✓404s a superseded part typed with an unregistered brand code
- ✓keeps the registered NH short form 308ing to the NHL canonical
- ✓keeps CT-FIA- 308ing onto the carrying vendor's slug (#801)
- ✓keeps CT-FRD- 308ing onto the carrying vendor's slug (#801)
- ✓keeps CT-VRS- 308ing onto the carrying vendor's slug (#801)
- ✓keeps CT-HES- 308ing onto the carrying vendor's slug (#801)
- ✓keeps CT-CTY- 308ing onto the carrying vendor's slug (#801)
- ✓keeps CT-LAV- 308ing onto the carrying vendor's slug (#801)
- ✓keeps CT-FDB- 308ing onto the carrying vendor's slug (#801)
- ✓keeps CT-GEH- 308ing onto the carrying vendor's slug (#801)
- ✓covers every heritage code that has a display name
- ✓still 308s when the part carries no manufacturer.code — nothing to contradict
- ✓returns 308 to /parts/ct-{BRAND}-{PN} for raw PN with manufacturer.code
- ✓308s an uppercase branded SKU to the lowercase canonical (#2859)
- ✓heals a mixed-case branded SKU in one hop
- ✓does not bounce the canonical form back — feeding the Location in returns null
- ✓returns null when the request already arrived on the branded form
- ✓returns null when the part has no manufacturer.code (legacy/imported row)
- ✓preserves searchParams (?asm=, ?ref=, ?replaced_from=) on the 308
- ✓supersession 308 emits the branded replacement directly — no raw→branded second hop (#823)
- ✓encodes special characters in the branded slug
- ✓never 308s a blank manufacturer code onto a synthetic CT-XXX- slug (#1594)
- ✓keeps the backend canonical when the manufacturer code is blank
- ✓404s a withdrawn CE part instead of 308ing it to its NHC canonical
- ✓308s a bare CE part number straight to its NHC canonical, one hop
- ✓keeps an unregistered SKU-shaped code failing closed (CT-KUHN-)
- ✓heals an already-crawled CT-NHL- CE URL forward instead of 404ing it
- ✓returns null once the request is already on the NHC canonical
- ✓falls back to the request identity when the payload carries no seo block
- ✓falls back when canonicalSku is present but empty
- ✓keeps the supersession target on the request identity, not this row's canonical
- ✓308s to the branded SKU when exactly one brand catalogue owns the PN
- ✓keeps the 404 when two brands own the same PN — a bare URL cannot disambiguate
- ✓ignores prefix and fuzzy neighbours — only a byte-equal PN counts
- ✓keeps the 404 when the sole owner is CNH — the parts probe already said no
- ✓keeps today's 404 when search itself is unreachable — never a 500
- ✓never spends a search call on a title slug
- ✓308s a lettered bare PN, which no longer looks uppercase to the gate
- ✓308s a hyphenated PN that reads like a title phrase, via the probe not the gate
- ✓does not re-probe a branded SKU that 404s — a dead branded URL stays dead
- ✓404s a brand-held SKU from the URL alone, before any probe (#3809)
- ✓404s a registry-held part
- ✓still 308s a superseded PN whose own verdict is held
- ✓leaves an index-eligible part on the page pipeline
✓GET /sitemap/[id].xmlSite pages62
- ✓shard 0: emits static + brand + equipment URLs, no boundary/parts call
- ✓shard 0: drops model + parts-diagrams locs when the equipment tree is noindexed
- ✓shard 0: the NH Construction division never emits a ?manufacturer= listing loc
- ✓shard 0: brand allowlist derives from config — a seoIndexed:false brand is excluded
- ✓shard 0: a brand added to SEO_INDEXED_BRAND_SLUGS surfaces in the sitemap
- ✓shard 0: advertises no URL from the retired cross-brand hub layer
- ✓shard 0: drops the redirecting /type/construction brand-type URL, keeps the rest
- ✓shard 0: includes /about and /faq static pages (front#1119 coverage)
- ✓shard 0: advertises the 10 migrated dealership pages, not the noindex showcase (#3871)
- ✓shard 0: includes the /parts-diagrams/models crawlable index hub (#1195)
- ✓shard 0: excludes the known noindex equipment sentinel from sitemap
- ✓shard 1 (parts): emits up to 10x5K branded canonical URLs
- ✓shard 1 (parts): dispatches 10 keyset batches; batch 0 has no cursor, rest seed from boundaries
- ✓shard 2 (parts): keyset cursors start at P50000 ((sitemapId-1)*50K)
- ✓assembly shard (id > partSitemapCount): routes to assemblies endpoint with keyset cursors
- ✓#3730 — emits SITE_URL as the host, never the origin the backend baked in
- ✓404s + no-store for an assembly-shard id and never fetches assemblies
- ✓still serves a PDP shard 200 with branded canonical URLs
- ✓shard 0 still advertises model + per-model diagram-index pages (not the cross-product)
- ✓returns 404 + no-store for shard id past total (front#936)
- ✓returns 404 + no-store for in-range shard that yields zero URLs (front#936)
- ✓returns 503 + no-store when every batch rejects on an in-range shard (transient, front#1119)
- ✓shard 0: brand-type all-reject → 503 + no-store, still captures the Sentry warning (#2856)
- ✓shard 0: ONE rejected brand-type fetch → 503 + no-store, never a partial 200 (#2856)
- ✓shard 0: brand-type partial success does NOT capture Sentry (only total-fail does)
- ✓shard 0: degraded upstreams → 503 + no-store, never a 24h-cached truncated map (#2856)
- ✓shard 0: healthy upstreams with zero models still serve 200 + 24h cache (#2856)
- ✓returns 503 no-store when BOTH boundary fetches reject (avoids 24h-cached empty urlset)
- ✓503 no-store when ONLY parts boundaries reject — no misrouting to assembly content
- ✓ONLY assemblies boundaries reject: parts shard 200, assembly shard 503 (not 404)
- ✓503s when hono boundaries batchSize != route SITEMAP_BATCH_SIZE (tripwire, front#1119)
- ✓404s when ENABLE_INDEXING is off
- ✓404s for non-numeric shard id
- ✓404s for negative shard id
- ✓falls back to raw PN loc when manufacturerCode is absent on a row
- ✓one rejected batch → 503 + no-store, never a 24h-cached partial shard (#2856)
- ✓all FETCHED batches rejecting on a tail shard → 503, not a false 'partial' 200 (#2856)
- ✓fires Sentry.captureMessage with shard/batch context on each rejected parts batch (front#1044)
- ✓fires ONE Sentry warning at shard-summary level on a degraded parts shard (#2856)
- ✓fires Sentry captures with shard/batch context on rejected assembly batches (front#1044)
- ✓fires NO warning when all batches succeed (front#1044)
- ✓503s (not 404) when ALL batches fail; one 503 warning, 10 error captures (front#1119/#1044)
- ✓parts shard: passes skipCount=true on every keyset batch
- ✓assembly shard: passes skipCount=true on every keyset batch
- ✓parts: a row WITH priceUpdatedAt emits <lastmod> equal to that value
- ✓parts: a row WITHOUT priceUpdatedAt emits NO <lastmod>
- ✓parts: a row with priceUpdatedAt === null emits NO <lastmod>
- ✓parts: two renders of the same fixed row produce identical lastmod (stable, no now())
- ✓assemblies: emit NO <lastmod> (no updated_at column upstream)
- ✓models (shard 0): a model WITH contentUpdatedAt emits <lastmod> on its equipment + parts-diagrams URLs
- ✓shard 0: static/listing/hub/taxonomy URLs emit NO <lastmod>, models keep theirs (#2857)
- ✓models (shard 0): a model with contentUpdatedAt null or absent emits NO <lastmod> (never a faked now())
- ✓drops rows whose backend seo.indexEligible is false, keeps the eligible ones
- ✓uses the backend canonical SKU for the loc, overriding local synthesis
- ✓emits the same URL the catalog anchor emits for that CE part
- ✓percent-encodes a slash in the backend canonical SKU (#3650)
- ✓keeps a row and falls back to buildBrandedPartPath when seo is absent (prod Hono)
- ✓strict mode fails closed without registry state and accepts eligible/grace only
- ✓drops rows for brand-catalog vendors even when seo.indexEligible is true
- ✓still applies the brand-catalog gate in strict mode
- ✓emits no uppercase character in any <loc> of a parts shard
- ✓emits no uppercase character in any <loc> of shard 0 (hubs, brands, static)
✓GET /feed/google/[id].xmlGoogle feed61
- ✓lowercases every item <link> while leaving every <g:id> untouched
- ✓emits valid Google RSS 2.0 XML with xmlns:g and at least one <item>
- ✓uses the registry canonical SKU when enriching merchant rows
- ✓omits g:identifier_exists when GTIN is absent but brand+MPN are present (#1338)
- ✓drops a GTIN Google would disapprove — bad check digit
- ✓drops a GTIN Google would disapprove — wrong length
- ✓drops a GTIN Google would disapprove — non-numeric
- ✓emits g:identifier_exists=false only when BOTH GTIN and brand are absent (#1338)
- ✓EXCLUDES rows with the Clinton placeholder image (Google disapproves)
- ✓EXCLUDES rows with no images (defensive)
- ✓EXCLUDES rows with NULL availability (orderability bucket absent)
- ✓feeds a shelf-stocked part as in_stock, whatever the upstream status says (#3546)
- ✓EXCLUDES rows with null OR zero price
- ✓EXCLUDES commerce-disabled rows (no_cnh_data / dont_list)
- ✓EXCLUDES quote-only rows even when they carry a price (call_for_pricing)
- ✓omits g:brand when manufacturer is absent (eligibility otherwise OK)
- ✓CDATA-wraps titles and descriptions (XML-sensitive characters survive)
- ✓404s when IS_INDEXING_ENABLED is off
- ✓404s for non-numeric shard id
- ✓404s for negative shard id
- ✓returns 503 + no-store when image boundaries fetch fails (fail-closed)
- ✓returns 503 + no-store when boundaries batchSize drifts from FEED_PARTS_PER_SHARD
- ✓returns 503 when sitemap fetch fails (retryable, not a misrouted empty 200)
- ✓returns 404 + no-store for an out-of-range shard id
- ✓survives one rejected enrichment batch — other batches still ship + Sentry partial-ship warning fires
- ✓renders a valid empty <channel> when every enrichment batch rejects (full-shard outage)
- ✓renders a valid empty <channel> when the shard's sitemap fetch returns zero rows
- ✓availability mapping covers every Google-feed enum (low_stock -> in_stock, etc.)
- ✓uses keyset cursor for shard > 0 (no deep OFFSET)
- ✓shard 0 omits searchAfter so the backend reads from the top
- ✓ships the item and no <g:shipping> for a DIS-stocked priced part (was flat-rate-eligible)
- ✓ships the item and no <g:shipping> for a CNH-overnight part (was flat-rate-eligible)
- ✓ships the item and no <g:shipping> for a freight part (always elided)
- ✓ships the item and no <g:shipping> for a hazmat part (always elided)
- ✓ships the item and no <g:shipping> for an unknown-shipping-path part (always elided)
- ✓takes g:id and link from the row's canonical SKU, not the enriched brand code
- ✓percent-encodes a slash in the canonical SKU (#3650)
- ✓falls back to local synthesis when the row's canonical SKU is empty
- ✓prefers the row's >=500x500 image over the enriched catalogue thumbnail
- ✓still drops a row whose image is the placeholder, whichever source it came from
- ✓keeps the item when the row's imageUrl is an empty string (#3650)
- ✓still joins the bare-PN row when the enriched sku is an empty string (#3650)
- ✓falls back to USD when the enriched currency is an empty string (#3650)
- ✓falls back to the id when the enriched partNumber is an empty string (#3650)
- ✓percent-encodes a '#' in the image URL, and the host move keeps it (#3650, #3798)
- ✓parses clean with hostile title and description content
- ✓still parses when the shard is empty
- ✓passes a normal title through untouched, with no PDP-style ellipsis
- ✓cuts an over-long title to 150 on a word boundary
- ✓never leaves a replacement character where it cut a surrogate pair
- ✓falls back to the part number when the title is whitespace only
- ✓keeps a real enriched description
- ✓composes one when the enriched description is just the title again
- ✓appends the fitment summary and drops the part type
- ✓composes rather than publish a brand description that is the title in caps
- ✓drops the summary's count rather than contradict the one in the title
- ✓emits no ALL-CAPS segment even when the part has no fitment
- ✓never composes a double period from a segment that ends in one
- ✓maps a known ngpc_category to its Motor Vehicle Parts leaf
- ✓falls back to Vehicle Parts & Accessories for a category with no honest leaf
- ✓omits g:product_type entirely when there is nothing but the root segment
✓nav-configGoogle visibility22
- ✓is the single Diagrams & Parts Store entry → NH-AG hub (front#2778 merged, front#2894 repointed)
- ✓does NOT advertise /brands or /equipment as a primary header nav entry (front#842)
- ✓every slug corresponds to a key in MANUFACTURER_CONFIGS
- ✓every href points at either the unified hub or a typed type-hub (ct-2047 / #2367)
- ✓has a curated short list (≤ 8 entries) so the footer stays readable
- ✓every href points at a /parts-diagrams/model/{slug} hub with a non-empty slug
- ✓every entry has a non-empty label
- ✓has a curated short list (3–8 entries) so the footer section stays balanced
- ✓rejects fake-looking T-series labels with 3+ bare digits and no dot (front#620 regression guard)
- ✓uses absolute same-origin paths
- ✓every entry has a non-empty human label and a unique href across both lists
- ✓links the migrated /service page from DEALERSHIP_LINKS
- ✓links the migrated /schedule-service page from DEALERSHIP_LINKS
- ✓links the migrated /schedule-demo page from DEALERSHIP_LINKS
- ✓links the migrated /value-your-trade page from DEALERSHIP_LINKS
- ✓links the migrated /employment page from DEALERSHIP_LINKS
- ✓links the migrated /credit-app page from DEALERSHIP_LINKS
- ✓links the migrated /staff page from DEALERSHIP_LINKS
- ✓links the migrated /testimonials page from DEALERSHIP_LINKS
- ✓links the migrated /map-hours page from DEALERSHIP_LINKS
- ✓links the migrated /email-insider page from DEALERSHIP_LINKS
- ✓keeps Help & Support to the six store links, in order (#3871 split)
✓PartsCatalogPage — generateMetadata (front#940 / front#2802)Parts pages21
- ✓?q=oil → noindex,follow, canonical dropped
- ✓?q=oil&manufacturer=new-holland → noindex,follow, canonical dropped
- ✓multi-manufacturer combo → noindex,follow, canonical dropped
- ✓multi-primary (?manufacturer=X&categoryId=Y) → noindex,follow, canonical dropped
- ✓sortBy secondary filter → noindex,follow, canonical dropped
- ✓category + secondary (availability) → noindex,follow, canonical dropped
- ✓?shipsSameDay=true secondary filter → noindex,follow, canonical dropped
- ✓raw-URL out-of-enum sortBy (#888 D3) still fires the raw-key guard → noindex,follow
- ✓NH Construction (?manufacturer=new-holland-construction) titles with the brand name, not the raw code
- ✓NH Construction (?manufacturer=NHC) titles with the brand name, not the raw code
- ✓single manufacturer slug vs vendor code → identical canonical, NO robots override
- ✓bare /parts (page 1) → canonical to /parts, NO robots override
- ✓?page=2 → self-canonical, indexable (pagination is not a secondary filter)
- ✓bare /parts (page 1 default) → 'Parts Store' title
- ✓?page=1 (explicit) → 'Parts Store' (page suffix omitted)
- ✓?page=2 → 'Parts Store — Page 2'
- ✓?page=10 → 'Parts Store — Page 10' (distinct from page 2), noindex tail
- ✓?page=5 (the last indexable page) keeps its self-canonical
- ✓?page=2 vs ?page=10 → titles are distinct (GSC duplicate guard)
- ✓?categoryId=FILTERS&page=2 → category title with Page 2 suffix
- ✓?page=3 → openGraph.title also carries Page 3 suffix
✓handleQueryStripRedirectRequest routing21
- ✓301-strips ?asm on a part-detail leaf
- ✓301-strips ?asmCode on a part-detail leaf
- ✓301-strips ?model on a part-detail leaf
- ✓301-strips ?modelSlug on a part-detail leaf
- ✓301-strips ?ref on a part-detail leaf
- ✓301-strips ?brand on a part-detail leaf
- ✓strips ALL legacy keys present in one hop
- ✓strips repeated occurrences of a key (?asm=1&asm=2)
- ✓301-strips ?asm on /parts-diagrams/model/{slug}/parts-diagrams/{code}
- ✓keeps replaced_from when stripping asm
- ✓keeps utm_* and gclid when stripping model
- ✓does not redirect a clean part leaf with no params
- ✓does not redirect when only replaced_from is present
- ✓does not redirect when only benign params are present
- ✓leaves ?highlight= to the robots rule (no redirect)
- ✓does NOT redirect when a strip key co-occurs with highlight (robots owns it)
- ✓ignores the /parts listing root
- ✓ignores reserved leaves /parts/brand and /parts/category
- ✓ignores a filtered brand listing /parts/brand/{slug}
- ✓ignores the parts-diagrams listing (no assembly code)
- ✓ignores unrelated paths
✓GET /sitemap-images/[id].xmlSite pages19
- ✓emits valid XML with image: namespace and branded SKU loc (CROP-front#916)
- ✓drops brand-catalog vendor rows so the image shard never submits a noindex PDP (#2373)
- ✓percent-encodes a slash in the backend canonical SKU loc (#3650)
- ✓falls back to raw PN loc when manufacturerCode is missing
- ✓dispatches batches via KEYSET cursors seeded from image boundaries (front#1107)
- ✓omits searchAfter for the first page (shard 0, batch 0) but seeds it for later batches
- ✓skips rows with null imageUrl (defensive even with withImageOnly)
- ✓XML-escapes ampersands in imageUrl query strings to keep Search Console valid
- ✓one rejected batch → 503 + no-store, never a 24h-cached partial shard (#2856)
- ✓shard 0 with ALL batches rejecting → 503 + no-store, never an empty cached 200 (#2856)
- ✓fires Sentry error per rejected batch + ONE 503 warning on a degraded shard (#2856)
- ✓shard > 0 with ALL batches failing → 503 (not 404) + 10 error captures (#2856)
- ✓404s when ENABLE_INDEXING is off
- ✓404s for non-numeric shard id
- ✓shard 0 stays 200 with empty <urlset> even when every batch returns zero rows
- ✓returns 404 + no-store for shard > 0 when every batch returns zero rows (front#936)
- ✓404 is reserved for proven out-of-range — an all-reject shard > 0 is 503 (#2856)
- ✓returns 503 + no-store when image boundaries fetch fails (front#1107 fail-closed)
- ✓skips batches past the image tail (null cursor) instead of fetching them
✓detectSoft404Request routing18
- ✓detects "Unable to load this equipment model" in a 200 HTML body
- ✓detects "Equipment Not Found" in a 200 HTML body
- ✓detects "ServiceUnavailable" in a 200 HTML body
- ✓detects "Service Unavailable" in a 200 HTML body
- ✓detects "Part Not Found" in a 200 HTML body
- ✓detects "Brand Not Found" in a 200 HTML body
- ✓detects "Page not found" in a 200 HTML body
- ✓detects "__next_error__" in a 200 HTML body
- ✓detects the Next error-boundary marker on an otherwise unrecognisable 200
- ✓prefers recognisable not-found copy over the error marker
- ✓returns null for a clean 200 HTML page
- ✓returns null when the status is not 200
- ✓returns null for non-HTML responses even with a matching substring
- ✓only inspects the first MAX_INSPECT_BYTES of the body
- ✓detects a substring sitting just inside the byte window
- ✓ignores soft-404 substrings that sit inside a <script> block
- ✓ignores soft-404 substrings that sit inside a <template> block
- ✓still detects a substring rendered in the main DOM alongside a script-block copy
✓variantTitleQualifier (#3649)Google visibility14
- ✓gives every W60C variant a distinct title within the SERP budget
- ✓gives every POWERSTAR-90 variant a distinct title within the SERP budget
- ✓gives every 2185 variant a distinct title within the SERP budget
- ✓never opens the W60C qualifier with an ellipsis
- ✓never opens the POWERSTAR-90 qualifier with an ellipsis
- ✓never opens the 2185 qualifier with an ellipsis
- ✓drops the prefix and suffix the family shares, keeping the differing words
- ✓keeps the head token that differs when the family shares no affix
- ✓falls back to tail-first when head-first would collide with a sibling
- ✓degrades to head-first truncation when the sibling lookup returned nothing
- ✓stays empty when displayName already carries the config
- ✓keeps a duplicate PG row's whole config rather than emptying its qualifier
- ✓keeps a config that already fits the budget whole
- ✓never reduces a sibling to punctuation
✓handleChapterRedirectRequest routing13
- ✓308s a single-assembly chapter straight to the schematic
- ✓drops chapter/page and keeps highlight, utm_* and gclid
- ✓falls back to the assembly code when the row has no slug
- ✓passes the chapter through to Hono url-encoded
- ✓renders the grid for a multi-assembly chapter
- ✓trusts the rows over the count when total=1 but the page is empty
- ✓renders the grid for an empty chapter
- ✓ignores the bare `?chapter=` all-chapters selection
- ✓ignores the landing page and the assembly-detail leaf
- ✓fails open after the retry and leaves a breadcrumb
- ✓recovers when the retry succeeds
- ✓falls through on an unknown model without caching the miss as a redirect
- ✓caches per slug+chapter, not per slug
✓inspectForSoft404Request routing13
- ✓returns null without fetching for non-inspected paths
- ✓returns null for its own subrequest to avoid a fetch loop
- ✓returns null without fetching for a non-crawler user-agent
- ✓tags the subrequest with the loop-guard header
- ✓detects and reports a soft-404, re-emitting the original body
- ✓re-emits a clean page without reporting
- ✓re-emits a non-200 via a mutable copy, without reading the body (front#1474)
- ✓marks a 500 subrequest service-unavailable for the crawler (front#3511)
- ✓marks a 502 subrequest service-unavailable for the crawler (front#3511)
- ✓marks a 503 subrequest service-unavailable for the crawler (front#3511)
- ✓re-emits a 200 non-HTML via a mutable copy, without reading the body
- ✓strips content-encoding/content-length from the re-emitted response
- ✓fails open: returns null when the subrequest fetch throws
✓resolveShardRequestGoogle visibility12
- ✓answers 404 for every shard while indexing is off, before parsing anything
- ✓reads 0 as shard 0
- ✓reads 7 as shard 7
- ✓reads 0.xml as shard 0
- ✓reads 12.xml as shard 12
- ✓answers 404 for '-1' rather than guessing a shard
- ✓answers 404 for 'abc' rather than guessing a shard
- ✓answers 404 for '' rather than guessing a shard
- ✓answers 404 for ' ' rather than guessing a shard
- ✓answers 404 for 'xml' rather than guessing a shard
- ✓resolves '1.5.xml' to shard 1, stopping at the first non-digit
- ✓resolves '1e3' to shard 1, stopping at the first non-digit
✓robots.ts — noindexed-but-linked routes stay fetchable (#3887)Site pages10
- ✓/sign-in is not blocked in production
- ✓/sign-in?redirect_url=%2Faccount is not blocked in production
- ✓/sign-in/factor-one is not blocked in production
- ✓/sign-up is not blocked in production
- ✓/sign-up?redirect_url=%2Fcart is not blocked in production
- ✓/lookup/CT-NHL-87035448 is not blocked in production
- ✓/account/orders is still blocked
- ✓/checkout/shipping is still blocked
- ✓/api/parts is still blocked
- ✓/parts/x?highlight=3 is still blocked
✓GET /sitemap-index.xmlSite pages10
- ✓derives all three counts from /boundaries totals (parts, assemblies, image-only)
- ✓emits N+1 parametric shards (minus BROKEN_PARAMETRIC_SHARDS) + M image shards (regression: front#888, prune: front#985)
- ✓advertises shards 10 & 11 — BROKEN_PARAMETRIC_SHARDS cleared (front#1119)
- ✓returns 503 when BOTH parametric calls reject (avoids 24h-cached single-shard regression)
- ✓503 no-store when ONLY assemblies rejects — never caches a parts-only index (front#1119)
- ✓503 no-store when ONLY parts rejects — never caches an assemblies-only index (front#1119)
- ✓fail-open: image rejection ships core index 200 but no-store (not pinned, front#1119)
- ✓advertises shard 0 + PDP shards + image shards but NO assembly shards
- ✓serves a PDP-only index 200 when the assemblies feed rejects (no longer core)
- ✓still 503s when the parts feed rejects (parts is the only core feed under the flag)
✓CollectionJsonLd (schema wiring, CROP-front#888)Parts pages10
- ✓drops an index-held row — its PDP 404s, so a ListItem would point at one (#3827)
- ✓emits the branded canonical the cards link (#3193), not a second URL shape
- ✓drops a row with an empty part number (#2764 — no placeholder /parts/ entity)
- ✓nests a Product carrying the Offer for a priced row (#3571)
- ✓emits NO offers key at all for an unpriced or call-for-pricing row (#3571)
- ✓gives every offered Product an image — own photo, else the brand OG (#3622)
- ✓drops the Offer for a priced row whose brand has no image at all (#3622)
- ✓counts the capped list it emits, not the page it was handed (#3622)
- ✓keeps the Offer but omits availability when the bucket is unknown (#3571)
- ✓falls back to raw /parts/{PN} when manufacturer.code is absent
✓#2938 — schema.org availability agrees with the Google feed for EVERY statusGoogle visibility9
- ✓agree for in_stock
- ✓agree for low_stock
- ✓agree for backorder
- ✓agree for preorder
- ✓agree for out_of_stock
- ✓agree for available
- ✓agree for null
- ✓agree for undefined
- ✓displayStateToSchemaAvailability emits ONLY the binary vocabulary
✓shippingForJsonLd (CROP-front#1222)Google visibility9
- ✓emits OfferShippingDetails for a DIS-stocked priced part
- ✓emits CNH-overnight handling/transit windows summing to 5 days
- ✓emits DFS-ground handling/transit windows summing to 6 days
- ✓returns undefined for a freight (truck-required) part
- ✓returns undefined for a hazmat part
- ✓returns undefined for a heavy-blocklist PN even when PG `requiresTruck` is unset
- ✓returns undefined for an unpriced part
- ✓returns undefined for an unknown-shipping-path part (missing PG signals)
- ✓hostile case — engine returns conditional/variable rate per customer: both helpers elide
✓shippingForJsonLd eligibility across the real shapesGoogle visibility9
- ✓emits shipping markup — DIS-stocked priced
- ✓emits shipping markup — CNH-overnight priced
- ✓emits shipping markup — DFS-ground priced
- ✓elides shipping markup — freight
- ✓elides shipping markup — hazmat
- ✓elides shipping markup — unpriced
- ✓elides shipping markup — unknown path
- ✓elides shipping markup — in_stock but freight (path falls to unknown)
- ✓elides shipping markup — heavy-blocklist PN with no PG shipping flag (CROP-front#1244)
✓IS_INDEXING_ENABLED — fail-closed truth table (#2862)Google visibility8
- ✓the ONE open cell: flag + prod app-env + canonical prod origin
- ✓flag off on the prod host → closed (the rollback lever still works)
- ✓flag mistakenly true on a non-prod app-env → closed, whatever the origin
- ✓flag mistakenly true with no site URL at all → closed
- ✓only the exact literal opens the flag — a typo stays closed on prod
- ✓a prod build with NO NEXT_PUBLIC_SITE_URL fails the build (no dev-origin fallback)
- ✓a prod build pointed at a non-canonical origin fails the build
- ✓SITE_URL keeps the dev fallback off prod (non-prod builds still boot)
✓private route groups carry noindex,nofollowGoogle visibility8
- ✓NOINDEX_NOFOLLOW_ROBOTS is actually noindex,nofollow for every agent
- ✓NOINDEX_FOLLOW_ROBOTS is noindex but still followable for every agent
- ✓app/account declares NOINDEX_NOFOLLOW_ROBOTS on its group layout
- ✓no route under app/account overrides the inherited robots
- ✓app/checkout declares NOINDEX_NOFOLLOW_ROBOTS on its group layout
- ✓no route under app/checkout overrides the inherited robots
- ✓app/(auth) declares NOINDEX_FOLLOW_ROBOTS on its group layout
- ✓no route under app/(auth) overrides the inherited robots
✓robots.ts — interlink param revert (#1311 Option A, #1326)Site pages7
- ✓does NOT block the reverted assembly-context / supersession params
- ✓still blocks the diagram-row highlight dup in production
- ✓keeps the path-based Disallows intact in production
- ✓never blocks the Next.js asset tree — Googlebot must fetch CSS/JS (#2855)
- ✓has no duplicate Disallow entries
- ✓keeps clean canonical paths crawlable (no over-block) in production
- ✓does NOT add param rules when indexing is disabled (dev)
✓toCrawlerErrorResponse (#1734)Request routing7
- ✓converts not-found chrome to a real 404 with no-store + noindex
- ✓converts "ServiceUnavailable" chrome to a real 503 with Retry-After
- ✓converts "Service Unavailable" chrome to a real 503 with Retry-After
- ✓converts "__next_error__" chrome to a real 503 with Retry-After
- ✓neutralises CDN-Cache-Control so a transient error is never CDN-cached
- ✓neutralises Vercel-CDN-Cache-Control so a transient error is never CDN-cached
- ✓strips the internal detection marker before the response leaves the edge
✓buildBomProductIdentity (BOM Product name/description cleanup, CT-1315)Google visibility7
- ✓strips the duplicated trailing PN and moves the fitment clause to description
- ✓handles a leading duplicated PN form too (PN at front of displayTitle)
- ✓does not double-prepend the brand when the type already names it
- ✓omits brand prefix when modelBrand is null
- ✓falls back to [brand] PN when displayTitle is empty or only the PN
- ✓emits no description when there is no fitment clause
- ✓never duplicates the PN in name regardless of input shape
✓#3777 /parts/ robots cutSite pages6
- ✓is inert while the flag is off — /parts/ stays crawlable
- ✓disallows /parts/ and allows every eligible SKU when on
- ✓keeps the brand listing subtree crawlable (#3806)
- ✓FAILS OPEN when the eligible list is empty — never a blanket /parts/ block
- ✓fails open when the upstream fetch fails
- ✓keeps the pre-existing path blocks intact
✓IS_INDEXING_ENABLED — audit unlock (front#3724)Google visibility6
- ✓opens the dev origin when ENABLE_INDEXING and SEO_AUDIT_UNLOCK are both true
- ✓stays closed on the dev origin without the unlock (#2862 unchanged)
- ✓stays closed when the unlock is set but ENABLE_INDEXING is not
- ✓refuses a *.vercel.app preview even with both flags set
- ✓refuses localhost even with both flags set
- ✓still opens prod through the #2862 triple, unlock absent
✓SiteJsonLdHome page6
- ✓advertises the same opening hours the site tells customers
- ✓emits the Organization (LocalBusiness) schema
- ✓attaches image + priceRange to LocalBusiness (RRT Local businesses)
- ✓emits the WebSite schema with SearchAction
- ✓does NOT emit a SiteNavigationElement schema
- ✓attaches hasMerchantReturnPolicy to the Organization
✓handleSitemapAliasRequest routing6
- ✓serves /sitemap.xml from the index WITHOUT a redirect
- ✓rewrites the trailing-slash variant
- ✓rewrites the uppercase variant
- ✓does NOT touch the canonical /sitemap-index.xml (avoid a rewrite loop)
- ✓does NOT touch sitemap shards under /sitemap/{n}.xml
- ✓does NOT touch unrelated paths
✓stripScriptAndTemplateBlocksRequest routing6
- ✓removes <script> blocks including their contents
- ✓removes <template> blocks including their contents
- ✓handles multiple sibling script blocks
- ✓is non-greedy across adjacent blocks
- ✓preserves content with no script or template blocks
- ✓is case-insensitive on the tag name
✓buildPartPath (DISPLAY-code rule)Google visibility6
- ✓brands a brand-catalog vendor code — its bare PN hits the CNH collision bucket
- ✓emits the bare PN for a search-MV code (#2764 — the badge may not be the carrier)
- ✓emits the bare PN for an OEM badge code the edge has to resolve
- ✓emits the bare PN when no code is carried at all
- ✓percent-encodes a slash in the PN, branded or bare (a raw / re-segments the path)
- ✓degrades to a bare `/parts/` for an empty PN rather than minting a branded slug
✓mustWithhold — fails OPEN (#3792/#3809)Google visibility6
- ✓withholds an explicitly rejected row
- ✓serves a row with no verdict — a missing verdict must never manufacture a 404
- ✓withholds every brand-held SKU, with or without a payload
- ✓serves CNH SKUs, bare PNs and garbage on the brand rule alone
- ✓is false with the flag off, whatever either rule says — the flag is the rollback
- ✓is NOT the negation of mayAdvertise — the asymmetry is the point
✓isTitleSlugGoogle visibility6
- ✓accepts a real title slug: 3+ segments led by a word
- ✓rejects a branded SKU in EITHER casing — it has 3 segments too
- ✓rejects a bare part number, lettered or not, in either casing
- ✓holds two segments out on purpose
- ✓rejects a leading segment that is not an alphabetic word
- ✓cannot tell a hyphen-heavy part number from a phrase, and that is bounded
✓surface <title> uniqueness (#2528)Google visibility6
- ✓'New Holland': hub, brand catalog, brand x type, and equipment titles are mutually distinct
- ✓'Ventrac': hub, brand catalog, brand x type, and equipment titles are mutually distinct
- ✓'Ferris': hub, brand catalog, brand x type, and equipment titles are mutually distinct
- ✓'Kuhn': hub, brand catalog, brand x type, and equipment titles are mutually distinct
- ✓'McHale': hub, brand catalog, brand x type, and equipment titles are mutually distinct
- ✓longest division catalog title fits the SERP window at max pagination
✓robotsForDiagram (#2372)Google visibility5
- ✓flip off (default) → undefined for any family (no-op, prior behaviour wins)
- ✓flip on + no pilot scope → NOINDEX_FOLLOW_ROBOTS for the whole cross-product
- ✓emits noindex,follow (follow keeps link equity to PDPs — never nofollow)
- ✓flip on + pilot scope → noindex only for listed families; others stay indexable
- ✓indexing off → undefined even with the flip on (layout's global noindex governs)
✓catalogPartHref (CATALOG row — the code IS the carrying vendor)Google visibility5
- ✓brands a search-MV code, unlike buildPartPath (#3193 — no second URL shape)
- ✓brands a brand-catalog vendor code
- ✓falls back to the bare PN rather than a synthetic CT-XXX- slug
- ✓percent-encodes a slash inside the branded slug
- ✓degrades to `/parts/` for an empty or absent PN
✓isGrowingCoverageModelGoogle visibility5
- ✓is true when the page is parts-thin AND has no publishable BOM parts
- ✓is false when parts-thin but the model has publishable parts
- ✓is false for a fully-covered (non-thin) model regardless of the parts signal
- ✓mirrors the equipment page robots gate exactly
- ✓page-side count mapping: totalParts > 0 reproduces the legacy totalParts === 0 gate
✓mapAvailabilityToSchema (PDP JSON-LD parity)Google visibility5
- ✓maps in_stock to schema.org/InStock
- ✓maps low_stock to InStock (binary #1634/#2938 — never LimitedAvailability)
- ✓maps available to InStock
- ✓maps backorder to OutOfStock (ruleset #1840), plus preorder / out_of_stock
- ✓returns undefined for NULL (caller drops the row / omits the field)
✓collectShardBatchesGoogle visibility5
- ✓seeds each batch from its own boundary cursor, first page from the top
- ✓keeps keyset order — batch 2's rows follow batch 1's, however they land
- ✓skips batches past the end of the dataset without fetching them
- ✓reports a rejected batch instead of throwing, and keeps the rest of the shard
- ✓counts every failure — a fully rejected shard reports all of them
✓truncateTitleWithSuffixGoogle visibility5
- ✓joins head + suffix unchanged when the combined length fits
- ✓truncates the head but keeps the suffix intact when combined overflows
- ✓never drops the differentiating suffix even when the head is huge
- ✓stays in budget when the suffix alone exhausts it (never over-length)
- ✓caps against the rendered budget when the caller passes it (absolute titles)
✓BinLookupView — clinton_localAccount pages5
- ✓renders bin location, qty, vendor, description, state badge, and cost
- ✓hides the cost block when avgCost and dealerNet are both null
- ✓shows bin location as '—' when binLocation is null
- ✓shows the stale warning when stale=true
- ✓renders multiple vendor rows when the PN has a composite-PK collision
✓BinLookupView — CNH fallback statesAccount pages5
- ✓renders cnh_depot with channel hint, lead time, and orderability badge
- ✓renders vendor_direct with special-order copy
- ✓renders unavailable with Contact CNH copy and RED orderability badge
- ✓renders no orderability badge when cnhSignals is null (degraded mode)
- ✓renders fallback card + locally-tracked rows when shelf is empty but Clinton tracks the PN
✓buildOgUrlGoogle visibility4
- ✓prefixes METADATA_BASE_URL onto an absolute path
- ✓passes through absolute URLs unchanged
- ✓resolves '/' or '' to the bare METADATA_BASE_URL
- ✓prepends a leading slash when missing
✓robotsForBrand (front#1397)Google visibility4
- ✓indexing on + seo-indexed brand (new-holland) → undefined (stays indexable)
- ✓indexing on + registry brand not seo-indexed (mchale/ventrac) → NOINDEX_NOFOLLOW_ROBOTS
- ✓indexing on + brand not in the registry → undefined (legacy brands stay indexable)
- ✓indexing off → undefined for any brand (layout's global noindex governs)
✓catalogPartHref prefers the backend canonical (#3193 / #3648)Google visibility4
- ✓emits the CE-division SKU, not CT-NHL- synthesized off the request-side code
- ✓agrees with the sitemap <loc> for that same CE part
- ✓treats an empty canonicalSku as no verdict and falls back to synthesis
- ✓encodes the backend SKU — it arrives unencoded and a raw / is a hard 404 (#3650)
✓catalogPartHref — lookupOnly (#3827 / #3834)Google visibility4
- ✓sends an index-held row to its /lookup twin, same slug
- ✓swaps only the leading segment — an encoded slug survives intact
- ✓still yields NO structured-data URL — /lookup is noindex
- ✓leaves browse rows on the canonical /parts path
✓googleProductCategoryGoogle visibility4
- ✓maps a category to its Motor Vehicle Parts leaf
- ✓never returns the taxonomy root
- ✓falls back for a category with no honest leaf, and for no category at all
- ✓normalises case and internal whitespace
✓mayAdvertise — fails CLOSED (#3777)Google visibility4
- ✓strict mode advertises only a positively vouched row
- ✓legacy/shadow keep the old reading: only an explicit rejection drops the URL
- ✓never advertises a brand-held SKU, in any mode and however good the verdict
- ✓is independent of the 404 flag — the sitemap is mode-driven, not flag-driven
✓the verdict is casing-blind (the URL is lowercase, the SKU is not)Google visibility4
- ✓reads a brand hold off a lowercase path SKU
- ✓gives both casings of one SKU the same mayAdvertise verdict
- ✓gives both casings of one SKU the same mustWithhold verdict
- ✓stamps the hold off a lowercase canonicalSku
✓buildBreadcrumbSchemaGoogle visibility4
- ✓emits a BreadcrumbList with positional ListItems; the leaf carries no item URL
- ✓drops a mid-trail crumb that carries no item, and renumbers over the gap
- ✓keeps an item-less leaf — that is the one place the property is waived
- ✓carries a malicious crumb name straight into the schema (escaping is the emit step)
✓displayStateToSchemaAvailability (BOM-row DisplayState parity, CT-1315)Google visibility4
- ✓maps every in-stock-family state to InStock (mirrors the 'In Stock' chip)
- ✓maps pre_launch to PreOrder
- ✓maps backorder AND discontinued to OutOfStock (binary #1634/#2938 — never Discontinued)
- ✓returns undefined for unknown / null / undefined (caller elides the field)
✓reconciledOfferAvailability (#3546 — feed reads the same shelf signals as the PDP)Google visibility4
- ✓elevates on the shelf COUNT alone, with no clintonInStock flag
- ✓elevates on the clintonInStock flag alone
- ✓leaves a part with nothing on the shelf on its upstream answer
- ✓reads out_of_stock for an unpriced shelf part
✓primaryImageUrl + isPlaceholderImageGoogle visibility4
- ✓returns the first real image URL when present
- ✓falls back to media.primaryImage when images[] is empty
- ✓falls back to the Clinton placeholder when no media
- ✓isPlaceholderImage flags the placeholder URL exactly
✓toBuildLogoSrc (#1491 — OG logos must not fetch from deployed envs)Google visibility4
- ✓inlines a local /public path as a base64 data URL read from disk
- ✓uses image/png mime for .png assets
- ✓falls back to a SITE_URL-prefixed URL when the file is not on disk
- ✓passes through other absolute URLs unchanged
✓runWithConcurrencyGoogle visibility4
- ✓never runs more than `limit` tasks at once
- ✓defaults to the upstream instance count
- ✓settles every task and keeps each one's slot despite completion order
- ✓records a rejection instead of throwing, so one bad task cannot abort the fan-out
✓slugifyGoogle visibility4
- ✓lowercases and replaces non-alphanumeric runs with hyphens
- ✓strips leading and trailing hyphens
- ✓preserves digits inside tokens
- ✓returns empty string for punctuation-only input
✓buildPartUrl (helper, manufacturerCode-only)Parts pages4
- ✓uses part number directly when manufacturerCode is omitted
- ✓emits the BARE PN for a search-MV code (#2764 — badge may not be the carrier)
- ✓brands a brand-catalog vendor's code (its PN collides with the CNH bucket)
- ✓encodes special characters in part number
✓app/layout.tsx robots meta wiring (#2530)Site pages3
- ✓gates the metadata robots on IS_INDEXING_ENABLED
- ✓indexing on → index,follow for both generic bots and googleBot
- ✓indexing off → noindex,nofollow (dev/stage never leak into the index)
✓extractCanonicalGoogle visibility3
- ✓extracts href from a well-formed canonical link
- ✓accepts single quotes and extra whitespace
- ✓returns null when no canonical link is present
✓parseRobotsDisallowGoogle visibility3
- ✓returns Disallow paths from the User-agent: * block only
- ✓ignores Disallow entries under specific-UA blocks when no wildcard block exists
- ✓returns [] for empty input
✓robotsMatchesGoogle visibility3
- ✓does not treat a trailing-slash pattern as a prefix of the bare path (#3887)
- ✓expands `*` and matches a query rule `startsWith` would miss
- ✓anchors a trailing `$`
✓parseSitemapUrlsGoogle visibility3
- ✓extracts <loc> URLs from a sitemap index
- ✓extracts <loc> URLs from a leaf sitemap urlset
- ✓returns [] when no <loc> tags are present
✓<PageBreadcrumb>Home page3
- ✓renders Home > {label} with the leaf unlinked and marked current
- ✓omits item on the leaf and never emits a bare siteUrl trailing slash
- ✓emits exactly one nav and one JSON-LD script
✓PartsCatalogPage — generateMetadata with indexing OFF (front#2802)Parts pages3
- ✓filtered ?q=oil → no robots override, canonical kept (no dev change)
- ✓filtered ?sortBy=price_asc → no robots override, canonical kept
- ✓bare /parts → no robots override, canonical present
✓LookupNavInterface pieces3
- ✓renders a keyboard-reachable link that carries NO href
- ✓navigates on click and on Enter, but not on Space
- ✓lets the caller's handler cancel the navigation
✓shouldInspectPathRequest routing3
- ✓matches the inspected route prefixes
- ✓matches the listing-root exact paths (front#939 follow-up — cacheable Cache-Control wrap)
- ✓skips unrelated routes
✓reportSoft404Request routing3
- ✓emits a structured console.error line
- ✓falls back to 'unknown' when the user-agent is absent
- ✓sends a Sentry event tagged soft-404-edge-detected
✓productTypeGoogle visibility3
- ✓joins category and part type under the Parts root
- ✓drops missing segments rather than emitting an empty one
- ✓returns null when only the root would remain
✓isBrandHeldSkuGoogle visibility3
- ✓holds brand-catalog vendors
- ✓does not hold CNH parts
- ✓does not hold an unparseable or missing sku
✓the registry rules are not each other's negationGoogle visibility3
- ✓an absent verdict is neither a vouch nor a rejection
- ✓vouches only for a published state
- ✓rejects on the flag alone, whatever the reason (#3809)
✓fetchIndexablePartPaths — Allow: list forms (#3806)Google visibility3
- ✓emits the branded canonical AND the bare-PN alias, both $-anchored
- ✓keeps a brand-held path out of the list in either form
- ✓still drops a registry-held part entirely
✓escapeJsonLdGoogle visibility3
- ✓neutralizes a </script> injection vector in a serialized string
- ✓escapes U+2028 / U+2029 line separators that break inline JSON
- ✓escapes ampersands
✓feedEligibleRowsGoogle visibility3
- ✓drops brand-held rows and any row the backend calls ineligible
- ✓keeps an NHL row whose registry verdict the merchant projection does not carry
- ✓keeps every row when the flag is off — prod today, every PDP resolves
✓mapAvailabilityToGoogleFeedGoogle visibility3
- ✓collapses in_stock / low_stock / available to in_stock
- ✓maps backorder to out_of_stock (ruleset #1840) and drops preorder
- ✓returns undefined for NULL (feed caller MUST drop the row)
✓priceValueOrNull + priceCurrencyGoogle visibility3
- ✓returns the list price value when > 0
- ✓returns null for zero / negative / missing price (feed caller drops the row)
- ✓defaults currency to USD when missing
✓cursorForRowGoogle visibility3
- ✓returns undefined for row 0 so the first page reads from the top
- ✓returns the cursor AT the row for a mid-dataset batch
- ✓returns null past the end so the caller skips the fetch
✓truncateTitleAtWordBoundaryGoogle visibility3
- ✓returns a title at or under the cap unchanged
- ✓truncates an overflowing title at a word boundary with an ellipsis
- ✓hard-cuts when the first word alone overflows the target
✓variantQualifier (#3105)Google visibility3
- ✓returns the config from modelName that displayName drops
- ✓is empty when displayName already carries the model config (single-variant)
- ✓is empty when modelName is missing
✓BinLookupView — initial renderAccount pages3
- ✓renders the search input and a disabled submit button on empty input
- ✓enables the submit button once the input is non-empty
- ✓shows no result area before any search is submitted
✓IS_INDEXING_ENABLED — strict env parsing (#2530)Site pages2
- ✓ENABLE_INDEXING="true" → enabled (the prod flip)
- ✓any other value stays disabled — the gate only opens on the exact literal
✓HomePage — metadata canonical (#1117)Site pages2
- ✓sets an explicit self-canonical (does not rely on the removed layout default)
- ✓canonical is the site root, not a relative './' parent-dir value
✓robots.ts — non-prod global crawl block (#1497)Site pages2
- ✓emits a global Disallow: / when indexing is disabled
- ✓keeps prod crawlable (allow /, not a global block) when indexing is enabled
✓robots.ts — /parts filter params stay crawlable (#2217)Site pages2
- ✓never blocks the /parts filter params in production
- ✓blocks no query-string params other than the highlight diagram-row dup
✓robots.ts — per-request freshness contract (cacheComponents)Site pages2
- ✓calls connection() on every invocation, both branches
- ✓source: calls connection() and does NOT reintroduce the removed force-dynamic export
✓GET /sitemap-index.xml — per-request freshness contract (cacheComponents)Site pages2
- ✓calls connection() on every request
- ✓source: calls connection() and does NOT reintroduce the removed force-dynamic export
✓isCrawlerUserAgentRequest routing2
- ✓matches search-engine crawlers — including real Googlebot
- ✓rejects real-user browsers and an absent user-agent
✓buildPartUrlGoogle visibility2
- ✓is buildPartPath under SITE_URL — same rule, absolute
- ✓carries the bare-PN rule through for a search-MV code
✓hasPartNumberGoogle visibility2
- ✓is true only for a non-blank part number
- ✓is false for blank, null and absent — those rows have no PDP
✓stampIndexHeldGoogle visibility2
- ✓stamps the withheld rows and leaves the rest identical
- ✓falls back to partNumber when the row carries no canonicalSku
✓buildItemListSchemaGoogle visibility2
- ✓emits an ItemList with name/url/numberOfItems and positional elements
- ✓uses a provided total for numberOfItems so a capped list keeps the true count
✓published /img logo paths (#3797)Google visibility2
- ✓resolves a /img logo back to the GCS upstream, not to SITE_URL
- ✓still reads a real /public path from disk
✓no caller can produce a media-host logo src (#3870)Google visibility2
- ✓enumerates every brand and finds only /img and /public paths
- ✓resolves each of them without falling through to the raw src
✓xmlEscapeGoogle visibility2
- ✓entity-encodes every XML special character
- ✓escapes the ampersand first so entities are not double-encoded
✓captureBatchFailureGoogle visibility2
- ✓tags with kind when the surface has more than one feed
- ✓omits the kind tag entirely when the caller has one feed
✓fail-closed responsesGoogle visibility2
- ✓serves 503 + no-store so the next crawl retries instead of hitting a pinned edge
- ✓serves 404 + no-store for an out-of-range shard (front#936)
✓partPathsFromSitemapXml (#3827)Google visibility2
- ✓keeps PDP paths and strips the origin
- ✓returns nothing for a shard with no product URLs
✓rendered budget (#3081)Google visibility2
- ✓leaves exactly the site suffix between the plain and rendered budgets
- ✓keeps a maximally-truncated plain title inside the rendered budget
✓admin-widget-copy-seo-mount-invariant.regressionAdmin logic2
- ✓the copy mount files a byte-identical text issue vs the canonical builder
- ✓the seo mount files a byte-identical seo issue vs the canonical builder
✓GET /sitemap-images/[id].xml — per-request freshness contract (cacheComponents)Site pages2
- ✓calls connection() on every request
- ✓source: calls connection() and does NOT reintroduce the removed force-dynamic/revalidate exports
✓GET /sitemap/[id] — per-request freshness contract (cacheComponents)Site pages2
- ✓calls connection() on every request
- ✓source: calls connection() and does NOT reintroduce the removed force-dynamic/revalidate exports
✓BinLookupView — error and configuration statesAccount pages2
- ✓shows 'not configured' message when the route reports configured=false
- ✓shows 'no data' message when the route returns 204 (non-staff path)
✓GET /feed/google/[id].xml — per-request freshness contract (cacheComponents)Google feed2
- ✓calls connection() on every request
- ✓source: the shared route factory calls connection(), and no route re-adds force-dynamic
✓HomePage — openGraph base tags (#3030)Site pages1
- ✓spreads OG_BASE so og:site_name + og:locale + type are present
✓/lookup/ stays crawlable so its noindex can be honouredSite pages1
- ✓does NOT Disallow /lookup/ when indexing is on
✓seedFromTodayGoogle visibility1
- ✓returns a positive integer encoding YYYYMMDD
✓OG_BASEGoogle visibility1
- ✓carries type, locale, siteName but DOES NOT include url (intentional — callers thread url)
✓DEFAULT_OG_IMAGE_URLGoogle visibility1
- ✓points at the root /opengraph-image route (1200×630 PNG)
✓held-brand listing carries nofollow (#3843)Parts pages1
- ✓?manufacturer=<held brand> → noindex,nofollow
✓isLookupHrefInterface pieces1
- ✓matches only /lookup/ targets
✓catalogPartUrlGoogle visibility1
- ✓is catalogPartHref under SITE_URL — ItemList JSON-LD needs absolute URLs
✓indexablePartPath — the sitemap/canonical form stays a real URLGoogle visibility1
- ✓never carries the robots `$` anchor (#3843)
✓JSON-LD single-emitter guard (front#1667)Google visibility1
- ✓emits the application/ld+json MIME only via <JsonLdScript>
✓serializeJsonLdGoogle visibility1
- ✓stringifies then escapes in one step (the dangerouslySetInnerHTML payload)
✓classifyBatchErrorGoogle visibility1
- ✓separates the upstream failure modes on-call triages by
✓BinLookupView — fetch URLAccount pages1
- ✓calls the staff-inventory route with the URL-encoded part number
What we walk through in a real browser17 journeys
○SEO smokeBrowser journey32
- ○robots.txt shape (indexing=false)
- ○/parts/brand/{slug}/diagrams returns the same status to bots and humans (#1474)
- ○sitemap-index.xml 404s when indexing is disabled
- ○sitemap-images/0.xml 404s when indexing is disabled
- ○home / meta robots (indexing=false)
- ○home / emits LocalBusiness + WebSite JSON-LD
- ○PDP /parts/87708024 canonical + meta robots
- ○a PDP advertised in the sitemap is indexable
- ○PDP /parts/ct-nhl-47126655 streams below-the-fold sections into the SSR HTML (CT-1882)
- ○PDP /parts/ct-nhl-47126655 renders its body without JavaScript (#3176)
- ○brand catalog /parts/brand/new-holland-agriculture renders its body without JavaScript (#3176)
- ○brand type hub /parts/brand/new-holland-agriculture/type/tractors renders its body without JavaScript (#3176)
- ○parts listing /parts renders its body without JavaScript (#3176)
- ○brand diagrams /parts/brand/new-holland-agriculture/diagrams renders its body without JavaScript (#3176)
- ○equipment /parts-diagrams/model/county-1124 renders its body without JavaScript (#3176)
- ○return policy /return-policy renders its body without JavaScript (#3176)
- ○/parts ItemList JSON-LD matches the rendered listing @smoke (#3622)
- ○an unknown diagram model 404s instead of soft-200ing (#3176)
- ○NH PDP /parts/ct-nhl-47126655 emits og:image/title/type in raw SSR HTML (OG · media)
- ○NH brand catalog /parts/brand/new-holland-agriculture emits og:image/title/type in raw SSR HTML (OG · media)
- ○equipment /parts-diagrams/model/county-1124 canonical + meta robots
- ○brand hub /parts/brand/new-holland-agriculture canonical + site JSON-LD
- ○brand × type /parts/brand/new-holland-agriculture/type/tractors canonical + JSON-LD
- ○vanity /new-holland-agriculture 301-redirects to its unified hub
- ○assembly BOM /parts-diagrams/model/county-1124/parts-diagrams/012-linkage-power-steering-w-cooler-68-12-70 emits ItemList JSON-LD
- ○/parts canonical + indexable on bare listing (indexing=false)
- ○/parts?q=bearings — noindex,follow + NO canonical when indexing on, canonical kept when off (front#2802, indexing=false)
- ○/parts?page=2 self-canonical + crawlable anchors (CT-674 #165)
- ○/parts?page=2 head includes rel=prev (CT-674 #165)
- ○/parts (page 1) head includes rel=next (CT-674 #165)
- ○assembly canonical is a stable absolute URL (fixed-point check)
- ○growing-coverage equipment /parts-diagrams/model/ford-19-86 carries noindex AND is absent from sitemap shard 0
○Deployed streamed-notFound edge 404 (#3572)Browser journey10
- ○unknown moved brand hub is a real 404 for Googlebot
- ○unknown moved brand hub is a real 404 for a browser
- ○type-first brand model is a real 404 for Googlebot
- ○type-first brand model is a real 404 for a browser
- ○unknown diagram model is a real 404 for Googlebot
- ○unknown diagram model is a real 404 for a browser
- ○unknown diagram assembly is a real 404 for Googlebot
- ○unknown diagram assembly is a real 404 for a browser
- ○the not-found body is in the raw HTML, no JavaScript required
- ○a real brand hub and a real diagram model still serve 200
○meta robots quality (CT-888)Browser journey9
- ○/ robots tags are consistent (noindex)
- ○/parts robots tags are consistent (noindex)
- ○/parts/brand/new-holland-agriculture robots tags are consistent (noindex)
- ○/parts/brand/__invalid_brand_for_robots_test__ robots tags are consistent (noindex)
- ○/parts/brand/new-holland-agriculture/type/__invalid_type_for_robots_test__ robots tags are consistent (noindex)
- ○/parts?q=oil robots tags are consistent (noindex)
- ○/parts-diagrams/model/__invalid_slug_for_robots_test__/variants robots tags are consistent (noindex)
- ○/parts-not-found robots tags are consistent (noindex)
- ○/equipment-not-found robots tags are consistent (noindex)
○Slug stability smoke (per-PR) @smokeBrowser journey8
- ○at least one sellable canary still renders a PDP
- ○PDP /parts/87708024 canonical chain stable
- ○PDP /parts/86546609 canonical chain stable
- ○PDP /parts/47622189 canonical chain stable
- ○PDP /parts/84496951 canonical chain stable
- ○PDP /parts/6559669 canonical chain stable
- ○the advertised URL is lowercase, self-canonical and one hop from uppercase
- ○superseded canary 308 chain strips replaced_from from canonical
○not-found surfaces carry no breadcrumb (#3468)Browser journey6
- ○/parts-not-found emits no BreadcrumbList and renders no breadcrumb nav
- ○/parts/{invalid-pn} body 404 emits no BreadcrumbList and renders no breadcrumb nav
- ○/parts/brand/{invalid-brand} (segment-level not-found) emits no BreadcrumbList and renders no breadcrumb nav
- ○/parts/brand/new-holland-agriculture/type/{invalid-type} emits no BreadcrumbList and renders no breadcrumb nav
- ○/equipment-not-found emits no BreadcrumbList and renders no breadcrumb nav
- ○root /{unknown} emits no BreadcrumbList and renders no breadcrumb nav
○PDP — superseded_redirect 308 + replaced-from bannerBrowser journey4
- ○obsolete PN redirects to replacement and shows green banner
- ○direct navigation to the replacement PN does NOT show the banner
- ○regular sellable part — no redirect, no banner
- ○canonical tag on target PDP strips the replaced_from query param
○Deployed type page — edge 404 (#2349 / front#882)Browser journey4
- ○genuine McHale type miss returns a real HTTP 404 (not a soft-404 200)
- ○genuine New Holland type miss returns a real HTTP 404 (cross-brand)
- ○a valid type page serves HTTP 200
- ○no sticky false-404: a valid type still 200s after a genuine miss
○Slug navigation — equipment URLsBrowser journey3
- ○equipment detail page via slug → HTTP 200
- ○equipment assemblies page via slug → HTTP 200
- ○equipment browse page → HTTP 200, all card links are numeric-id unit pages
○Slug navigation — fallback redirect chainBrowser journey3
- ○legacy /parts/{modelCode}/assemblies → 308 → /parts-diagrams/model/{slug}/parts-diagrams
- ○invalid equipment slug → not-found body (HTTP 404 on Vercel edge)
- ○invalid equipment slug assemblies sub-route → not-found body (HTTP 404 on Vercel edge)
○Slug navigation — no dead links on key pagesBrowser journey2
- ○equipment browse: all card links resolve (no 404)
- ○PDP page: fitment and assembly links resolve (no 404)
○Slug stability — equipment slug stability (Block 3)Browser journey2
- ○100 sampled model slugs render 200 with canonical = /parts-diagrams/model/{slug}
- ○denormalized equipment slug variants 308-redirect to the canonical
○sitemap shard health (front#985)Browser journey1
- ○every advertised /sitemap shard returns HTTP 200 + valid <urlset> with ≥1 <url>
○Slug navigation — PDP fitment linksBrowser journey1
- ○PDP fitment models have slug-based /parts-diagrams/model/ hrefs
○Slug stability — part URL immutability (Block 1)Browser journey1
- ○100 sampled PNs render 200 with canonical = /parts/{encodeURIComponent(PN)}
○Slug stability — PDP guard response codes (Block 2)Browser journey1
- ○superseded canary redirects to replacement and strips replaced_from from canonical
○Slug stability — sitemap ↔ robots parity (Block 4)Browser journey1
- ○sitemap sample + robots conformance (indexing=false)
○a degraded listing page reaches a crawler as 503, never 500 (#3511) @smokeBrowser journey1
- ○a deep listing page never answers 500 to a crawler
Automated checks1,209
Browser journeys35
Code exercised80%
What we check automatically239 groups
✓handlePartsDiagramsGoneRequest routing36
- ✓410s the retired surface /parts-diagrams/categories
- ✓410s the retired surface /parts-diagrams/categories/
- ✓410s the retired surface /parts-diagrams/category
- ✓410s the retired surface /parts-diagrams/category/hay-forage
- ✓410s the retired surface /parts-diagrams/type
- ✓410s the retired surface /parts-diagrams/type/tractors
- ✓410s the retired surface /parts-diagrams/ferris
- ✓410s the retired surface /parts-diagrams/new-holland-agriculture
- ✓410s the retired surface /parts-diagrams/new-holland
- ✓410s the retired surface /parts-diagrams/new-holland-construction
- ✓410s the retired surface /parts-diagrams/agco
- ✓410s the retired surface /parts-diagrams/categoriesXYZ
- ✓410s the retired surface /parts-diagrams/typeform
- ✓410s the retired surface /parts/diagrams
- ✓410s the retired surface /parts/diagrams/
- ✓410s the legacy artifact route /parts-schematics
- ✓410s the legacy artifact route /parts-schematics/
- ✓410s the legacy artifact route /parts-schematics/kuhn/anything
- ✓falls through (null) for the live surface /parts-diagrams/ferris/is600z
- ✓falls through (null) for the live surface /parts-diagrams/ferris/is600z/ABC123
- ✓falls through (null) for the live surface /parts-diagrams/ferris/assemblies/ABC123
- ✓falls through (null) for the live surface /parts-diagrams/new-holland-agriculture/T7-270/05-100-04
- ✓falls through (null) for the live surface /parts-diagrams/ferris/1000ZK21%2F48
- ✓falls through (null) for the live surface /parts-diagrams/model/ford-5610/parts-diagrams
- ✓falls through (null) for the live surface /parts-diagrams/model/ford-5610/parts-diagrams/03d02-power-steering
- ✓falls through (null) for the live surface /parts/brand/ferris/diagrams
- ✓falls through (null) for the live surface /parts/brand/new-holland-agriculture/diagrams/type/tractors
- ✓falls through (null) for the live surface /parts/diagrams-guide
- ✓falls through (null) for the live surface /parts
- ✓falls through (null) for the live surface /brands
- ✓falls through (null) for the live surface /parts-diagrams
- ✓falls through (null) for the live surface /parts-diagrams/
- ✓falls through (null) for the live surface /parts-diagrams/model
- ✓falls through (null) for the live surface /parts-diagrams/models
- ✓does not gate the hub root behind a query param either
- ✓is the only parts-diagrams handler left in the proxy chain
✓AllPartsSheetAssembly views25
- ✓renders the trigger button and prefetches the BOM on mount (warm cache before open)
- ✓does NOT prefetch the BOM in searchOnlyMode (no chapters prop)
- ✓loads parts on open and renders the BOM rows
- ✓does not render a Qty column — the v2 directory endpoint has no per-row qty
- ✓renders the derived schematic thumbnail for each BOM row's diagram
- ✓renders a schematic MediaPlaceholder for a diagram-less BOM row (parity with the Part # column)
- ✓enlarges the schematic preview to 480px on hover (larger than the 240px part-photo preview)
- ✓filters loaded parts by client-side substring for short queries
- ✓renders the empty-results banner when server-side search returns nothing
- ✓surfaces the Retry banner on directory-fetch failure and recovers on click
- ✓sorts by price ascending with null prices at the end
- ✓sorts by price descending with null prices still at the end
- ✓breaks price ties deterministically by partNumber
- ✓applies sort after filter so search results stay correctly ordered
- ✓in searchOnlyMode (no chapters prop) skips the BOM load entirely and shows the search-only prompt
- ✓seeds the search box and runs the diagram lookup on open
- ✓auto-opens and seeds the search box from #all-parts=<query>
- ✓auto-opens without seeding for a bare #all-parts
- ✓brand-qualifies the part-assemblies lookup for a McHale model
- ✓renders the default description line interpolating modelDisplayName when dialogTitle is omitted
- ✓renders dialogTitle verbatim (no modelDisplayName prefix) when the prop is provided
- ✓mounts only SHEET_EAGER_COUNT <tr> on first paint after the BOM loads
- ✓mounts a deferred row when its placeholder intersects the viewport
- ✓mounts every row eagerly when the BOM has fewer than SHEET_EAGER_COUNT
- ✓preserves per-occurrence schematicUrl + diagram href for both eager and deferred rows
✓<DiagramPartsRail>Diagram viewer19
- ✓renders all parts and the count summary
- ✓marks the active row when its ref is in selectedRefs
- ✓fires onToggleRef when the row body is tapped
- ✓uses the inverse aria-label on an already-active row
- ✓exposes the price label inside the row (no separate add button rendered)
- ✓renders price when present and omits price label otherwise (#1863)
- ✓opens the drawer to the full snap point on first selection
- ✓renders the availability dot label when getAvailability returns a status
- ✓does NOT mount the drawer (no body portal) at desktop width
- ✓gates the PORTALED content with lg:hidden (not just the wrapper)
- ✓scrolls the newly-activated row into view
- ✓does not scroll when a row is deactivated
- ✓scrolls again when the same row is re-activated after a deselect
- ✓scrolls only the newly-activated row when another row stays active
- ✓renders the search input inside the rail header
- ✓filters rows by partNumber or description
- ✓renders a 'no matches' empty state when the query yields nothing
- ✓updates the summary count to the filtered length while a query is active
- ✓forwards onToggleRef when a filtered row is tapped (preserves callout wiring)
✓handleAssemblyRoutingRequest routing17
- ✓returns 308 when URL uses a legacy UUID and Hono returns a different slug
- ✓preserves search params on the redirect target
- ✓returns null when URL is already canonical (no loop)
- ✓returns null when slug is null (unmigrated row, graceful degrade)
- ✓rewrites to /assembly-not-found with 404 + noindex when Hono returns 404 (front#888 I4)
- ✓caches Hono 404 — repeated probes of the same unknown code skip the fetch
- ✓returns null on Hono 429 (fail-open — rate limit must not 404 valid assemblies)
- ✓returns null on Hono 5xx (fail-open — never 500 the site)
- ✓returns null when Hono is unreachable (fetch throws)
- ✓caches ok probes — second call for same id does not re-fetch
- ✓does not cache transient errors (5xx) — next call re-probes
- ✓returns null when SEARCH_SERVICE_URL is unset (fail-open on misconfig)
- ✓retries once on a 429 then 308s when the retry succeeds
- ✓retries exactly once then fails open (null) when both attempts error
- ✓does NOT retry on a definitive 404 (real not-found is a single probe)
- ✓does NOT retry when the first attempt already succeeds
- ✓emits a fail-open breadcrumb tagged 'assembly' after the retry errors
✓resolveDetailDiagram pages16
- ✓returns full detail + partsThin=false when detail has sections and parts
- ✓returns detail + partsThin=true when Catalog has empty sections and Hono has no chapters
- ✓prefers Hono synth when Catalog row has zero parts but Hono has chapters (front#819)
- ✓preserves Catalog detail untouched when totalParts > 0 (front#819 regression guard)
- ✓synthesises from chapters + partsThin=true when detail is null but chapters exist
- ✓synthesised detail carries real counts from chapters + BOM directory (front#809)
- ✓returns null (genuine 404) when both upstreams miss
- ✓returns null when detail is null and chapters have zero chapterCount
- ✓throws SearchServiceDownError instead of 404ing when chapters failed transiently (#2965)
- ✓still returns null when chapters resolved cleanly with no coverage (genuine 404 preserved)
- ✓renders a Catalog-covered model even when chapters failed transiently (no over-throw)
- ✓returns null when chapters.model.subLine='ATTACHMENT' even with full catalog detail
- ✓returns null when chapters.model.subLine='ATTACHMENT' even with hono-only thin fallback
- ✓matches subLine case-insensitively and trim-tolerantly
- ✓does NOT filter when subLine is a real model class (e.g. BALE WAGON)
- ✓forwards specs when present
✓buildEquipmentSpecRowsDiagram pages15
- ✓returns [] for null specs
- ✓returns [] when every field is null (no row pollution)
- ✓emits production years, classification, engine, transmission, weight in canonical order
- ✓formats PTO with type in parens when both present
- ✓formats hitch with category + lift when both present
- ✓falls back to category-only when hitch lift missing
- ✓emits front + rear tires on separate rows
- ✓formats fuel tank with gal suffix
- ✓falls back to raw value when weight is non-numeric
- ✓emits Built In in the identity group
- ✓shows Manufacturer only for a true rebadge, not when it echoes the brand
- ✓emits Steering and composes Electrical from voltage + charging
- ✓composes Electrical from a single side when the other is missing
- ✓surfaces discrete displacement/cylinders when engineMaker is terse
- ✓suppresses displacement/cylinders already bundled in the engine line
✓buildDiagramIndexSummaryAssembly views14
- ✓returns empty content when there are no chapters
- ✓sums per-chapter and grand totals from assembly part counts
- ✓includes catalogued-part counts and a largest-systems sentence
- ✓does not double the vendor in the era sentence
- ✓adds an era sentence only when production years exist
- ✓normalizes glued/asymmetric hyphen separators in chapter labels
- ✓excludes catch-all buckets from the most-documented-systems sentence
- ✓normalizes Knotter -Wrapper → Knotter & Wrapper
- ✓normalizes Sheet Metal-Decals → Sheet Metal & Decals
- ✓normalizes Power Take Off → Power Take Off
- ✓normalizes Electrical Systems → Electrical Systems
- ✓normalizes 3-Point Hitch → 3-Point Hitch
- ✓drops the count recap and CTA when catalog `about` already covers them
- ✓omits the parts clause when no part counts are known
✓generateBomItemListSchemaDiagram pages14
- ✓emits empty ItemList shell for empty BOM (CT-433)
- ✓emits one ListItem per row at position 1..N
- ✓caps itemListElement at 50 but keeps numberOfItems at the true total
- ✓Product.url uses the branded canonical via buildPartUrl + modelBrand
- ✓Product.url falls back to raw /parts/{PN} when modelBrand is unknown
- ✓Product.url + Offer.url prefer the backend canonical SKU over local synthesis
- ✓Product.url percent-encodes a slash in the backend canonical SKU (#3650)
- ✓Product.url falls back to buildPartUrl when the canonical SKU is empty
- ✓replaces CNH placeholder URLs with the brand fallback and keeps real images
- ✓applies brand when modelBrand present, omits when null
- ✓flags obsolete parts via additionalProperty
- ✓filters dont_list parts out of itemListElement and numberOfItems (front#205)
- ✓emits empty ItemList shell when every part is dont_list (CT-433, was front#205 null)
- ✓schema is JSON-serializable round-trip
✓BomTable filter — tokenized P0 (#623)Assembly views13
- ✓matches space query against hyphenated description (hose water → HOSE-WATER PUMP)
- ✓matches hyphen query against space-separated description (hose-water → HOSE WATER PUMP)
- ✓matches a token nested inside a hyphenated PN (8751 → ABC-8751-X)
- ✓requires AND across the joined per-row corpus (engine in description, bolt in applicability)
- ✓highlights every occurrence of every token (hose water in HOSE-WATER PUMP HOSE)
- ✓paste keeps whitespace verbatim for multi-token query (hose water)
- ✓paste collapses whitespace for hyphenated PN-shaped content ( ABC-1234\n → ABC-1234)
- ✓matches a phrase against applicability.raw_text (no longer serviced)
- ✓matches against modern kitParts[].partNumber even when legacy kitPartNumbers is empty
- ✓preserves currentReplacementPn in the corpus (regression guard for issue spec drift)
- ✓returns all rows for whitespace-only filter (no false-empty)
- ✓highlights the matched token inside applicability.raw_text render
- ✓highlights the matched token inside currentReplacementPn link render
✓generateEquipmentSchemaDiagram pages13
- ✓emits a CollectionPage with no Product-family fields (#3070)
- ✓produces valid JSON when serialized (#3070 round-trip guard)
- ✓uses cover image as first image when available
- ✓falls back to images array when cover image is null
- ✓omits image when no images available
- ✓includes part count in description
- ✓singularizes counts of 1 in description (#2940)
- ✓uses thin-catalog description when totalParts is zero (CT-674 T-B6)
- ✓uses slug-based canonical URL (CT-674)
- ✓does not double the brand when the model already leads with the vendor
- ✓prepends the vendor when the model does not already name it
- ✓de-dup is case-insensitive
- ✓only de-dups on a word boundary (does not strip a substring match)
✓computeHitTargetPaddingsAssembly views12
- ✓gives a single isolated callout the full desired padding on both axes
- ✓keeps full padding for two far-apart callouts
- ✓clamps two adjacent callouts to at most half the gap, and they do not overlap
- ✓keeps asymmetric pads disjoint in an L-shape (third neighbor tightens one side only)
- ✓gives zero padding to two callouts whose visible boxes already overlap
- ✓handles a degenerate zero-size rect without producing NaN
- ✓never returns a negative padding
- ✓returns one padding entry per callout in input order
- ✓loads 43 callouts
- ✓PROPERTY: no two expanded hit rects overlap unless their visible boxes already overlap
- ✓PROPERTY: each visible box center lies inside its own expanded hit rect
- ✓REGRESSION: the OLD uniform-160 expansion DOES produce overlapping pairs on this fixture
✓getProductTypeHrefAssembly views12
- ✓returns the /parts/brand/{slug}/type/{equipmentType} URL when brandCode + equipmentType resolve
- ✓returns null when brandCode is missing
- ✓returns null when equipmentType is missing
- ✓returns null when brandCode is unknown (not in manufacturer-config)
- ✓returns null for heritage brand codes not yet in manufacturer-config (Ford, Fiat) — safe no-link fallback
- ✓lowercases a display-case equipmentType when no whitelist is supplied
- ✓kebab-cases a multi-word equipmentType (Hay Tools → hay-tools)
- ✓returns null when equipmentType is empty after slugification (no valid path segment)
- ✓canonicalizes a singular display-case equipmentType to the brand's routable slug (#2323)
- ✓returns the link when the slugified equipmentType is exactly on the whitelist
- ✓returns null when the equipmentType matches no whitelist slug — avoids a soft-404
- ✓returns null when the whitelist is present but empty (taxonomy fetch failed) — safe text fallback
✓<TypeHero>Diagram pages12
- ✓renders exactly one h1 with the brand-qualified heading
- ✓renders its breadcrumb by default
- ✓suppresses its breadcrumb when showBreadcrumb is false (avoids the duplicate trail)
- ✓renders the BrandLockup logo
- ✓subtitle shows only the total when no line filter is active
- ✓subtitle shows filtered/total and the line label when a line is active
- ✓renders 4-level breadcrumb with root + brand landing links
- ✓inserts a parent crumb as a back-link before the current page (#1938)
- ✓renders cleanly with zero total models
- ✓renders the class-of-equipment cover photo when coverSrc is supplied (#1742)
- ✓omits the cover banner when coverSrc is undefined (graceful fallback)
- ✓does not render the pre-v2 per-category icon container (regression guard)
✓generateMetadata — diagram-chapter robots (front#795)Diagram pages12
- ✓chapter view (non-empty) + indexing on → noindex,follow
- ✓chapter view + indexing off → no page-level robots (layout wins)
- ✓landing page (no chapter param) + non-empty → indexable
- ✓landing page (no chapter param) + empty catalogue → noindex,follow
- ✓single-assembly chapter still emits metadata + noindex,follow
- ✓paginated view (?page=2) → noindex,follow
- ✓deep paginated view (?page=101) → noindex,follow
- ✓?page=1 is the landing — robots unchanged (indexable)
- ✓no page param leaves robots unchanged (indexable)
- ✓garbage ?page= falls back to page 1 and stays indexable
- ✓paginated view + indexing off → no page-level robots (layout wins)
- ✓empty chapter view still noindex,follow (regression guard for #640 path)
✓ChapterRowAssembly views11
- ✓renders chapter name, count, and a link to the grid with the chapter filter
- ✓URL-encodes chapter names that contain spaces or special characters
- ✓omits the assembly count when the chapter has zero assemblies
- ✓marks the link as aria-current='page' when the chapter is the active grid filter
- ✓does not set aria-current when the chapter is not active
- ✓sets aria-disabled on the link for chapters with no real schematics
- ✓clicking the chevron button calls onOpenChange with true
- ✓the chevron button's aria-label reflects the open state
- ✓invokes triggerRef with the Link element on mount
- ✓variant=thumbnails surfaces a thumbnail image in the expanded list
- ✓default variant renders the existing text rows (regression pin)
✓<TypeCard>Diagram pages11
- ✓renders the supplied href with descriptive aria-label
- ✓renders the type label as a heading; brand + count live only in aria-label
- ✓omits the count from the aria-label when modelCount is 0 (missing-slug fallback)
- ✓uses the singular noun in the aria-label for a single-model type (1 model, not 1 models)
- ✓renders the Figma WebP thumbnail for mapped slugs
- ✓falls back to the Lucide icon when slug has no image mapping
- ✓grid encodes special characters in category slug hrefs
- ✓renders the optional subtitle when provided (used on /equipment + NH landing)
- ✓links to the Parts Store target when /equipment supplies that href
- ✓uses imageSlug override to look up the thumbnail WebP
- ✓emits the configured ga4Source on the link
✓buildEquipmentOverviewDiagram pages11
- ✓returns no prose for a fully sparse model (data-gated, no filler)
- ✓emits an era sentence only when production years exist
- ✓does not double the vendor when displayName already leads with it
- ✓includes manufacturer only when it names a distinct maker
- ✓composes a powertrain sentence from engine + transmission + drive
- ✓composes a capability sentence from weight, PTO and hitch
- ✓emits a serial-number paragraph and serialYears only when entries exist
- ✓emits a coverage paragraph only when the model has catalogued parts
- ✓adds a closing support line only when other prose exists
- ✓surfaces mechanical facts as bullet strings
- ✓produces a substantial unique-word count for a richly-specced model
✓EquipmentAssemblyDetailPage — fetch degradation (#1329)Diagram pages11
- ✓404s on a genuine 4xx from the assembly detail
- ✓re-throws an assembly-detail 503 rather than caching a 404
- ✓re-throws a chapters 503
- ✓re-throws an assembly-detail 429 rather than caching a 404
- ✓re-throws a chapters 429
- ✓re-throws an assembly-detail timeout rather than caching a 404
- ✓re-throws a chapters timeout
- ✓re-throws an assembly-detail network rather than caching a 404
- ✓re-throws a chapters network
- ✓renders without the sidebar layout when chapters degrade on a 4xx
- ✓still renders when the chapter-assemblies fan-out fails entirely
✓BomTable Ferris capabilities (front#1429 Group B)Assembly views10
- ✓renders the Availability column header for every brand (#2830 unified columns)
- ✓renders a per-row availability cell for every brand (#2830 — '-' placeholder when no data)
- ✓renders per-row add-to-cart checkboxes when cart=true and onToggleRow is wired
- ✓renders an enabled add-to-cart button on a priced sellable row
- ✓disables the add-to-cart button on an unpriced row (isBomRowOrderable gate)
- ✓renders the part number as a branded PDP link when buildPartHref is supplied
- ✓renders the part number as plain text (no PDP link) when capability disables pdpLinks
- ✓priced row shows the formatted price
- ✓a call_for_pricing row's price cell is the neutral dash, no tel CTA and no stock status (#2960)
- ✓an unpriced non-call row also renders the dash, never a stock status in the price column (#2960)
✓BomTable filterAssembly views10
- ✓renders all parts initially
- ✓filters rows by part number substring
- ✓matches case-insensitively
- ✓matches on description substring, not just part number
- ✓ignores leading/trailing whitespace in typed value
- ✓clears filter via the X button
- ✓clears filter via Escape
- ✓shows empty state with query and a Clear filter button when no matches
- ✓wraps the matched substring with <mark> in the matching row
- ✓normalizes pasted clipboard text (strips whitespace/newlines)
✓<CalloutPin>Diagram viewer10
- ✓renders the ref badge and display name
- ✓positions the card via inline left/top
- ✓renders the leader-arrow SVG with a polyline from callout to card edge
- ✓shows the formatted price when one is provided
- ✓shows no price label when price is missing (#1863)
- ✓renders the Add-to-order button only when onAdd and price are provided
- ✓renders the 'Open part' link only when partNumber is provided
- ✓deep-links to the brand-qualified pdpHref when provided (not the bare PN)
- ✓renders no 'Open part' link when pdpHref is explicitly null (branded, no PDP)
- ✓shows the part number in the header when provided
✓recent-diagrams-storeApp state10
- ✓pushes a new diagram to the front of the list
- ✓dedupes by assemblyCode and bumps the existing entry to the front
- ✓caps persisted history at 8 entries (oldest dropped)
- ✓uses Date.now() when viewedAt is omitted
- ✓preserves all metadata on persisted entries
- ✓wipes all items
- ✓toggles the hydration flag
- ✓returns at most the first 6 items
- ✓returns all items when fewer than the preview limit are stored
- ✓returns the total persisted count, not the preview-trimmed slice
✓admin diagram edit widgetAdmin editing9
- ✓offers the flag-diagram trigger for an admin with the toggle on
- ✓opens a prefilled kind=diagram issue (schematic exception) on a wrong-diagram flag
- ✓adds a pasted URL as a selectable tile and files it as the proposed schematic
- ✓shows an inline error and no tile for an invalid pasted URL
- ✓renders NO trigger in prod even for an admin with the toggle on
- ✓renders the trigger for staff
- ✓renders NO trigger for a customer
- ✓renders NO trigger when the toggle is off
- ✓renders NO trigger for an anonymous visitor
✓ChapterAssemblyList — thumbnail variantAssembly views9
- ✓variant defaults to text: regression pin on the existing render path
- ✓renders a thumbnail image for assemblies with a real schematicUrl
- ✓falls back to MediaPlaceholder when schematicUrl is missing
- ✓falls back to MediaPlaceholder for CNH placeholder URLs
- ✓schematic-less thumbnail renders the branded wordmark when a brand code is supplied
- ✓each row routes to its assembly URL via slug
- ✓active assembly row carries aria-current=page
- ✓filter narrows the visible thumbnail rows
- ✓filter with no matches shows 'No matching parts diagrams' in thumbnail mode
✓EquipmentBreadcrumb renderingAssembly views9
- ✓renders the productType crumb as a link when brand + equipmentType resolve
- ✓leaves productLine (division) as plain text — it has no canonical page yet (#184 / #189)
- ✓links the subLine (series) crumb to the type hub's series drill (#2323)
- ✓falls back to plain text for productType when brandCode is missing (graceful degradation)
- ✓still renders the Home and displayName crumbs
- ✓renders trailing crumbs with links when href is provided, plain text for the last one
- ✓renders safely when model is null (e.g. lookup failure)
- ✓renders leadingCrumb link between Home and the product hierarchy (front#336)
- ✓omits the leading crumb slot when the prop is not passed
✓SchematicViewer markerShape (front#1512)Assembly views9
- ✓defaults to rect markers — no <ellipse> visible elements
- ✓renders <ellipse> visible markers when markerShape='ellipse'
- ✓ellipse geometry is the bbox-inscribed ellipse (centre + rx/ry)
- ✓ellipse keeps the same role / tabindex / aria-pressed as the rect marker
- ✓the invisible hit rect stays a <rect> even with ellipse markers (hit geometry unchanged)
- ✓clicking the ellipse marker fires onCalloutClick with the ref
- ✓keyboard Enter on the ellipse marker fires onCalloutClick
- ✓ellipse markers still print the overlay label (<text>) in overlay mode
- ✓the inline hover-sync + pulse CSS rules also target ellipse markers
✓<DiagramBreadcrumb>Diagram viewer9
- ✓renders nothing when given an empty array
- ✓renders each crumb label inside an ordered list
- ✓wraps non-final crumbs with an href in an anchor
- ✓does NOT render the last crumb as a link even when an href is provided
- ✓only sets aria-current=page on the final crumb
- ✓renders non-final crumbs without an href as plain text (no anchor)
- ✓renders a ChevronRight separator between crumbs but not after the last one
- ✓uses an overflow-x-auto scrollable nav without flex-wrap
- ✓exposes the navigation landmark with an accessible name
✓computePinPlacementBusiness rules9
- ✓places the card to the right of a centred callout
- ✓flips to the left of a near-right-edge callout
- ✓clamps vertically when the callout is near the top edge
- ✓clamps vertically when the callout is near the bottom edge
- ✓clamps the card left coordinate when both flips overflow
- ✓targets the LEFT edge midpoint when the card sits to the right of the callout
- ✓targets the RIGHT edge midpoint after a horizontal flip
- ✓targets the BOTTOM edge midpoint when the callout sits well below a top-clamped card
- ✓returns finite numbers for degenerate zero-size containers
✓getChapterVisualBusiness rules9
- ✓picks an engine icon for engine-keyword chapters
- ✓picks a hydraulic icon for hydraulic-keyword chapters
- ✓picks a transmission icon for transmission-keyword chapters
- ✓picks an electrical icon for electrical-keyword chapters
- ✓falls back to Cog when no keyword matches
- ✓returns a stable visual for identical name + index pairs
- ✓cycles colors through the five-token palette
- ✓handles negative indices via modulo wrap
- ✓returns a token-only colorClass (no inline hex)
✓<TypeSidebar>Diagram pages9
- ✓renders All + every category, linking to {basePath}?category=<slug>
- ✓brand-type variant links to /parts/brand/{slug}/type/{type}, All → brand hub (#2134/#2159)
- ✓nests the active category's series as ?series= child links (#2134)
- ✓suppresses series children when the category has a single (lone) series
- ✓marks the active category with aria-current=page
- ✓marks All as active when no category is selected
- ✓active row uses the --brand (Clinton blue) token, not --primary (indigo)
- ✓rows carry the v2 focus-visible ring token
- ✓encodes special characters in category slug hrefs
✓resolveSlugParam — front#243 5xx-vs-404 discriminationDiagram pages9
- ✓returns a model outcome on a clean 200
- ✓returns an ambiguous outcome when the slug collides across brands (no brand hint)
- ✓returns null on a deterministic 404 (slug genuinely unknown)
- ✓throws SearchServiceDownError on 5xx so the page renders ServiceUnavailable, not 404
- ✓throws SearchServiceDownError on a network/timeout (cold Cloud Run instance)
- ✓throws SearchServiceDownError on a connection failure
- ✓wraps unknown Error subclasses (TypeError, Zod, etc) as SearchServiceDownError (#663)
- ✓wraps generic Error instances as SearchServiceDownError (#663)
- ✓wraps non-Error throws (string, object) as SearchServiceDownError (#663)
✓generateBreadcrumbSchemaDiagram pages9
- ✓produces a 4-item BreadcrumbList starting at Home
- ✓non-terminal items have item URLs and the model leaf has none
- ✓points the vendor crumb at the unified hub for NH (no ?vendor= param)
- ✓points the vendor crumb at the moved hub for the search-catalog brand FER
- ✓points the vendor crumb at the moved hub for the carried brand MCH
- ✓points the vendor crumb at the moved hub for the carried brand VNT
- ✓drops the hubless vendor crumb from the schema for a non-available brand
- ✓drops the hubless vendor crumb from the schema for an unrecognised brand code
- ✓uses the formatted model name for the leaf crumb
✓EquipmentVariantsPageDiagram pages9
- ✓redirects to canonical when slug differs
- ✓notFound when slug genuinely 404s
- ✓renders ServiceUnavailable (NOT notFound) on a transient resolve failure (#1329)
- ✓renders ServiceUnavailable on a network/timeout resolve failure (#1329)
- ✓notFound when variantCount is 0
- ✓redirects to lone variant when variantCount is 1
- ✓renders the variants UI when variantCount > 1
- ✓emits Sentry breadcrumb on successful render with the entry context
- ✓uses 'multi' brand sentinel in breadcrumb on multi-brand collisions
✓generateMetadata — thin assembly robotsDiagram pages9
- ✓case 0: thin + IS_INDEXING_ENABLED=false → no page-level robots (layout wins)
- ✓case A: thin (no image, no BOM) + indexing on → noindex,follow
- ✓case B: CNH placeholder schematic + no BOM → noindex,follow
- ✓case C: BOM-only (no image but partCount > 0) → indexable
- ✓case D: image-only (real schematic but no BOM) → indexable
- ✓case E: rich (real image + parts) → indexable
- ✓case F: invalid assemblyCode format → notFound() triggers proper 404 (front#612)
- ✓case G: getAssemblyDetail throws a transient → re-throws (NOT a cached 404) (#1329)
- ✓case H: getAssemblyDetail returns null/empty → notFound() (front#612)
✓generateBomItemListSchema — offers (CT-1315)Diagram pages9
- ✓emits an Offer with all required fields when a positive price exists
- ✓renders an unpriced row as a plain ListItem (no nested Product)
- ✓renders a zero-priced row as a plain ListItem (Merchant-listing requires price > 0)
- ✓keeps positions contiguous across mixed priced/unpriced rows (#3027)
- ✓emits an Offer WITHOUT availability when the DisplayState is unknown/absent
- ✓maps backorder and discontinued DisplayStates to schema availability
- ✓works without an availabilityByPn argument (backward-compatible call)
- ✓offer url matches the Product url (branded canonical)
- ✓keeps schema JSON-serializable with offers present
✓generateBomItemListSchema — availability ↔ visible chip alignment (#2908 / #1634)Diagram pages9
- ✓in_stock row emits InStock — source=live, flag=true (binary, flag-independent)
- ✓in_stock row emits InStock — source=snapshot, flag=true (binary, flag-independent)
- ✓in_stock row emits InStock — source=floor, flag=true (binary, flag-independent)
- ✓in_stock row emits InStock — source=none, flag=true (binary, flag-independent)
- ✓in_stock row emits InStock — source=live, flag=false (binary, flag-independent)
- ✓in_stock row emits InStock — source=snapshot, flag=false (binary, flag-independent)
- ✓in_stock row emits InStock — source=floor, flag=false (binary, flag-independent)
- ✓in_stock row emits InStock — source=none, flag=false (binary, flag-independent)
- ✓keeps InStock for a floor-sourced vendor_direct row regardless of the flag
✓isBomRowOrderableAssembly views8
- ✓blocks the dont_list incident part regardless of display state
- ✓blocks no_cnh_data (commerce disabled)
- ✓blocks a purchasable:false priced row (explicit brand-catalog flag)
- ✓blocks call_us availability buckets (discontinued / backorder) even when sellable
- ✓blocks obsolete rows and rows without a price
- ✓blocks a price wrapper carrying no list value
- ✓allows a sellable, in-stock, priced row
- ✓allows when display state is unknown/missing (unclear → defer, still priced+sellable)
✓BomTable pricing (list-only, CT-674)Assembly views8
- ✓shows list price when available
- ✓shows the neutral dash when list is missing even if a stray `net` value is present at runtime (#2960)
- ✓shows replacement price + 'via {pn}' hint when fromReplacement is true
- ✓does NOT show 'via' hint when price is the row's own (no fromReplacement)
- ✓uses finalReplacementPn for the 'via {pn}' hint when set
- ✓falls back to currentReplacementPn when finalReplacementPn is null (legacy hono)
- ✓cart-add swaps to finalReplacementPn (terminal) for superseded rows
- ✓cart-add uses original PN when price is the row's own (no supersession)
✓BomTable availability chip (front#409-B)Assembly views8
- ✓renders CustomerAvailabilityBadge per row when displayState is provided
- ✓folds an unknown-availability orderable row to 'In Stock'
- ✓folds an unknown-availability commerce-disabled row to 'Out of Stock'
- ✓renders empty placeholder when no displayState is available for the part
- ✓Add-all-in-stock CTA counts only resolved in_stock-family rows
- ✓Add-all-in-stock excludes dont_list rows even in an in-stock display state
- ✓CTA hidden when no parts resolve to in_stock
- ✓falls back gracefully when availabilityByPn is undefined (rollout / older callers)
✓BomTable scroll-to-row on diagram selection (#1374)Assembly views8
- ✓scrolls to the row whose hotspot was clicked (selectedRefs + scrollToRef)
- ✓does not scroll when a selection is toggled OFF
- ✓scrolls to the NEWEST selection even when an earlier row stays selected
- ✓still scrolls to the URL ?highlight= row on mount (deep link, no scrollToRef)
- ✓scrolls only the FIRST row of a multi-PN callout (no per-row scroll storm)
- ✓scrolls again when the same ref is re-selected after a deselect
- ✓click-driven scrollToRef wins over the URL ?highlight= deep link
- ✓survives the scroll target being filtered out, then re-anchors when it returns
✓calloutsFitImageSpaceAssembly views8
- ✓is true when every callout sits inside the declared space
- ✓is false when callouts exceed the declared space (Kuhn feed shape)
- ✓tolerates a couple of pixels of edge overflow
- ✓fits when out-of-space callouts stay under the 10% cap (1 of 20)
- ✓is suppressed once out-of-space callouts clear the 10% cap (3 of 20)
- ✓keeps dimension-less feeds (space resolved at runtime)
- ✓keeps the overlay when there are no callouts to validate
- ✓is false for missing callout data
✓ModelSpecsHeaderAssembly views8
- ✓links the title to the model detail page when modelHref is given
- ✓renders the title as a plain heading when no modelHref is given
- ✓carries the variant config in the H1 so siblings differ
- ✓pins the qualifier heading and the suppressed modelName paragraph
- ✓pins the modelName paragraph when it differs and yields no qualifier
- ✓pins no modelName paragraph when modelName equals displayName
- ✓pins the Parts Diagrams fallback for a missing model
- ✓leaves the H1 alone when displayName already carries the config
✓useAllBomPartsAssembly views8
- ✓skips the fetch entirely while `enabled` is false
- ✓skips the fetch when chapters is empty even with `enabled: true`
- ✓hits the v2 single-call directory route exactly once and exposes flattened parts
- ✓emits one FlatPart per (part, diagram) pair so multi-diagram parts stay browsable
- ✓surfaces upstream failure via `isError` so the dialog can show its retry banner
- ✓`refetch` re-runs the loader so the dialog's Retry button recovers from a transient failure
- ✓shares queryKey + queryFn between the hook and a page-mount prefetch (warm cache, one fetch)
- ✓dedupes through queryKey across identical-content chapter prop arrays
✓<AssemblyTree>Diagram viewer8
- ✓renders one collapsible row per chapter with its display name and diagram count
- ✓starts the active chapter expanded so its rows are visible
- ✓expands a chapter on trigger click and reveals its assembly rows
- ✓builds the row href from baseUrl + slug, falling back to assemblyCode
- ✓renders the chapter icon tile with a token-class background per chapter
- ✓exposes a min-h-11 tap target on every chapter trigger
- ✓renders a part-count badge only when partCount > 0
- ✓is hidden above lg via lg:hidden
✓resolveLineAndPageDiagram pages8
- ✓accepts valid line + page
- ✓accepts null line (user cleared the filter)
- ✓redirects when line is not in the derived set
- ✓redirects when page is greater than totalPages
- ✓redirects when page is zero or negative
- ✓does not redirect when totalPages is 0 and page is 1 — empty state is a valid render
- ✓preserves line when stripping out-of-range page
- ✓preserves an active sub in redirect targets (#1938)
✓redirectIfLegacyAssemblyCodeDiagram pages8
- ✓no-op when URL code already matches canonical slug
- ✓308-redirects when URL is a legacy uppercase UUID
- ✓308-redirects when URL is a legacy dotted code
- ✓no-op when assembly.slug is null (unmigrated row — graceful)
- ✓preserves ?highlight query on the redirect target
- ✓encodes a highlight value containing URL-reserved characters
- ✓no-op on self-loop (URL code equals slug equals the canonical form)
- ✓builds target URL via equipmentAssemblyDetailUrl (same path shape as canonical)
✓buildEquipmentBreadcrumbSchema (#2864 — unique, progressive, parity)Assembly views7
- ✓emits unique breadcrumb item URLs on the list page
- ✓positions are 1..n and the leaf carries no item on the list page
- ✓is at parity with the visible breadcrumb hrefs on the list page
- ✓emits unique breadcrumb item URLs on the assembly page
- ✓positions are 1..n and the leaf carries no item on the assembly page
- ✓is at parity with the visible breadcrumb hrefs on the assembly page
- ✓Home resolves to the bare origin, not origin + '/'
✓sortAssembliesAssembly views7
- ✓pins PICTORIAL OVERVIEW first above callouts
- ✓pins GENERAL PICTORIAL INDEX first
- ✓does NOT treat 'INDEX VALVE' as pictorial
- ✓does NOT treat 'BRAKE OVERVIEW' as pictorial (regex too broad guard)
- ✓DIA KIT last even when no_image assembly present
- ✓full tier order: pictorial > callouts > image > no_image > DIA
- ✓sorts alphabetically within same tier
✓<EquipmentPlate>Diagram viewer7
- ✓renders the brand eyebrow, display name, meta line and counts
- ✓renders the brand logo image when one is configured
- ✓falls back to a mono-3-letter pill when no logo asset exists for the brand
- ✓falls back to equipmentType + productLine when specs are missing
- ✓omits the meta line when no spec or model classification is available
- ✓uses 'Parts diagrams' as a heading fallback when model is null
- ✓never renders a serial-number field
✓<MobileDiagramHeader>Diagram viewer7
- ✓renders the title and an optional subline
- ✓calls router.back() when the back button is tapped without a custom handler
- ✓prefers a custom onBack over router.back()
- ✓fires onSave when the save button is tapped
- ✓reflects the saved state in aria-pressed and the label
- ✓does not render the empty kebab placeholder on either screen (Phase 1)
- ✓sticks to the top of the viewport with the correct z-index and chrome
✓<MobileDiagramView>Diagram viewer7
- ✓renders the header, breadcrumb, diagram, and rail without crashing
- ✓composes the subline from model display name and chapter
- ✓does NOT render the diagram branch when the assembly has no callouts
- ✓falls back to the plain schematic image when callouts overflow the declared image space (Kuhn feed)
- ✓hides the CalloutPin when no selection is active
- ✓hides the CalloutPin when more than one ref is selected
- ✓renders the rail with the supplied parts
✓<RecentlyViewedRail>Diagram viewer7
- ✓renders nothing when the store is empty
- ✓renders one card per persisted recent diagram
- ✓links each card to /parts-diagrams/model/{modelSlug}/parts-diagrams/{assemblyCode}
- ✓uses a single Link per card so there is one tab-stop per item
- ✓cycles the chapter-icon token color by index position
- ✓is hidden on lg breakpoints via lg:hidden
- ✓renders the chapter eyebrow per card and 'See all' header link
✓suppressOverRepeatedDiagramsBusiness rules7
- ✓drops a diagram shared by more parts than the threshold
- ✓keeps a diagram shared by at most the threshold count
- ✓strips only the over-repeated diagram, never a real photo on the same part
- ✓recomputes a primaryImage that pointed at the suppressed diagram
- ✓counts distinct parts, not occurrences — a doubled diagram on one part counts once
- ✓leaves unique diagrams (different URLs) alone
- ✓is a no-op on an empty set
✓/parts-diagrams — resolveCategoriesDiagram pages7
- ✓returns one card per seed when every preferred slug is live
- ✓matches the first preferred slug when present in the available set
- ✓falls back to the second candidate when the first is absent
- ✓drops the seed when none of its candidates match (was: dead-link fallback)
- ✓constructs brand-scoped hrefs pointing at /parts/brand/new-holland-agriculture/type/<slug>
- ✓every non-construction resolved href starts with /parts/brand/new-holland-agriculture/type/
- ✓points a construction-matched card straight at the NHC hub, not the 308ing AG type path (#2768)
✓<TypeCard> brand-aware image sourceDiagram pages7
- ✓renders the brand-specific photo when the brand has an allowlist hit
- ✓falls back to the global category WebP when the brand has no photo for the slug
- ✓respects imageSlug as the typeSlug input — brand path wins on override slug
- ✓respects imageSlug as the sole typeSlug input — global path on override miss
- ✓suppresses the global NH art for Marcrest (no image program), falling to the icon
- ✓preserves next/image intrinsic dimensions on the brand path (R4 / no CLS)
- ✓falls back to the Lucide icon when both brand and global paths miss
✓resolveCategoryDiagram pages7
- ✓returns root when no category or line is set
- ✓redirects to the brand landing when a line is set without a category (bare ?line=)
- ✓redirects to the brand landing when the category slug is unknown
- ✓redirects to the brand landing when both category and line are unknown
- ✓returns the matched category when the slug is valid
- ✓is case-sensitive on slug matching (by design — URLs are literal)
- ✓strips a bare ?sub= without a category (#1938)
✓parseAllPartsHashAssembly views7
- ✓ignores a hash that is not ours
- ✓opens the sheet unfiltered for a bare #all-parts
- ✓seeds the search box from #all-parts=<query>
- ✓decodes a percent-encoded multi-word query
- ✓opens unfiltered rather than throwing on broken percent-encoding
- ✓treats an empty query as no query
- ✓keeps a query containing its own '=' intact
✓buildThinDetailFromChaptersDiagram pages7
- ✓humanises lowercase brand codes to display names
- ✓humanises case-ih slug
- ✓falls back to brandCode when chapter model has no brand
- ✓empties sections/images and marks origin as hono-fallback
- ✓surfaces real totalSections from chapterCount (front#809)
- ✓surfaces real totalParts from the BOM directory partCount (front#809)
- ✓keeps totalParts at 0 when the BOM directory is unavailable (honest fallback)
✓buildMechanicalFactsDiagram pages7
- ✓returns [] for null/undefined specs or empty details
- ✓passes through a string array and collapses source whitespace
- ✓humanizes object-shaped details into 'Key: value' bullets
- ✓drops exact duplicates case-insensitively
- ✓suppresses facts already conveyed by Steering / Drive rows
- ✓keeps drive/steering facts when no discrete row carries them
- ✓ignores non-primitive array entries (no [object Object])
✓EquipmentAssembliesPage — slug-shape soft-404 fixturesDiagram pages7
- ✓renders real chapters for short slug (new-holland-workmaster-60)
- ✓renders real chapters for compound slug (new-holland-t6155-autocommand-stage-v)
- ✓renders real chapters for long compound slug (new-holland-t5110-autocommand-stage-v-nafta-my23)
- ✓renders real chapters for CR-class slug (new-holland-cr790-e5)
- ✓renders real chapters for brand-only short pattern (new-holland-boomer-45d)
- ✓covers at least 5 distinct slug shapes
- ✓surfaces Service Unavailable (not a chapter grid) when getChapters fails
✓generateMetadata — diagram cross-product noindex gate (#2372)Diagram pages7
- ✓flip off → rich NH diagram stays indexable (no page-level robots)
- ✓flip on + rich (partCount >= DIAGRAM_INDEX_MIN_PARTS) → stays indexable (#2367 Phase 4)
- ✓flip on + rich + isSharedDiagram → noindex,follow (sharedness beats richness)
- ✓flip off + rich + isSharedDiagram → indexable (gate stays dark pre-flip)
- ✓flip on + rich + isSharedDiagram=false → stays indexable (unshared rich subset)
- ✓flip on → canonical stays self-referential + page still renders (200, crawlable)
- ✓flip on + indexing off → layout's global noindex governs (no page-level robots)
✓EquipmentAssemblyDetailPage — resolved page wiringDiagram pages7
- ✓wraps the interactive view in the chapter layout and scopes search to the model
- ✓drops the search scope when the model has no brandCode/modelNumber pair
- ✓links the chapter crumb only when the chapter holds more than one assembly
- ✓shows the copyable CNH section code only when the assembly has one
- ✓renders the chapter name and part count under the heading
- ✓passes the BOM through the availability enrichment before rendering it
- ✓locates the current assembly within its chapter for prev/next nav
✓assembly-context-storage (front#1311)Assembly views6
- ✓round-trips a written context for the matching part number
- ✓returns null for a different part number (stale-context guard)
- ✓preserves a context with no ref (kit / replacement links)
- ✓returns null when nothing was written
- ✓returns null on a partial record missing a required field
- ✓returns null and does not throw on malformed JSON
✓AssemblyInteractiveView → BomTable scroll wiring (#1374)Assembly views6
- ✓clicking a diagram hotspot scrolls the BOM to that part's row
- ✓clicking the same hotspot again (deselect) does not move the list
- ✓re-selecting the same hotspot after a deselect scrolls again
- ✓the newest hotspot click wins while earlier selections stay active
- ✓URL ?highlight= deep link scrolls on mount with no clicks (AllPartsSheet contract)
- ✓clicking a BOM ref cell re-centers its row (parity with pre-#713 behavior)
✓AssemblyView — mobile "Browse Diagrams" triggerAssembly views6
- ✓renders the Browse Diagrams trigger when chapters are passed
- ✓omits the trigger when no chapters are passed (brand wrappers stay opted out)
- ✓omits the trigger when chapters is an empty list (chaptersData failed upstream)
- ✓trigger renders before MobileDiagramView in document order at <lg
- ✓trigger wrapper carries lg:hidden so desktop layout is untouched
- ✓variant flows from AssemblyView through MobileChapterDrawer to the trigger label
✓computeAssemblyNeighbors (CT-674 / #204)Assembly views6
- ✓returns next only when current is first
- ✓returns prev only when current is last
- ✓returns both when current is in the middle
- ✓returns both null and currentIdx=-1 when assemblyCode missing (silent-null guard)
- ✓handles single-assembly chapter (no neighbors)
- ✓handles empty list
✓handleLegacyAssemblyRedirectRequest routing6
- ✓308-redirects the bare /assemblies listing to /parts-diagrams
- ✓preserves the assembly code in the detail path
- ✓preserves the query string (e.g. ?highlight=5)
- ✓does NOT corrupt a slug that contains the literal 'assemblies'
- ✓handles a slug that is literally 'assemblies'
- ✓returns null for non-matching paths
✓buildPartsDiagramsUrlDiagram pages6
- ✓returns the bare base path when no params are set
- ✓omits page=1
- ✓keeps page>1
- ✓encodes special chars in category and line
- ✓drops falsy params
- ✓places sub after category and before line (#1938)
✓EquipmentOverviewDiagram pages6
- ✓renders prose, mechanical facts and serial table for a full-data model
- ✓renders nothing for a fully sparse model
- ✓renders the Hono about prose for a spec-less model (the ~94% gap)
- ✓leads the prose with the Hono about, then the specs-derived paragraphs
- ✓ignores a blank about and keeps the sparse-model thinness honest
- ✓renders byte-identical SSR HTML with and without the copy/seo edit context
✓VariantsTableDiagram pages6
- ✓renders one card per variant and sorts newest production start year DESC then model_code ASC
- ✓renders differentiator, production-year range, and pluralised parts-diagrams count
- ✓hides the production-year line when no year is parseable and formats single/large counts
- ✓marks the current variant with aria-current and a 'Currently viewing' badge
- ✓links each card to /parts-diagrams/model/<slug>, falling back to /parts when slug is missing
- ✓renders an empty-state message with a browse link when no variants are supplied
✓buildChapterHref — front#657 breadcrumb↔chapter-index guardDiagram pages6
- ✓emits a link for a multi-assembly chapter present in the index
- ✓returns undefined (no link, plain text) for a chapter ABSENT from the index
- ✓returns undefined for a single-assembly chapter (grid would redirect straight back)
- ✓returns undefined when the chapter index is missing entirely (fetch failed)
- ✓URL-encodes chapter keys with spaces and ampersands so the route reads them back intact
- ✓round-trips every linked chapter back to an index entry (breadcrumb↔index agree)
✓generateMetadata — #1329 transient must re-throw, 4xx still 404sDiagram pages6
- ✓getAssemblyDetail 503 → re-throws the SearchServiceApiError, not notFound()
- ✓getAssemblyDetail 429 → re-throws (rate-limit is transient)
- ✓getAssemblyDetail timeout → re-throws
- ✓getAssemblyDetail genuine 404 → notFound() (real 404 status)
- ✓chapters (non-essential) 503 → re-throws, not silently dropped to null
- ✓chapters genuine 404 → degrades to null, metadata still renders
✓generateBomItemListSchema — brand-fallback image for priced rows (#3122)Diagram pages6
- ✓uses the New Holland brand-fallback OG image for an imageless priced row
- ✓leaves a real, non-placeholder imageUrl unchanged (regression)
- ✓replaces a CNH placeholder imageUrl with the brand fallback, not the placeholder
- ✓omits image entirely for an imageless priced row with an unknown brand
- ✓omits image entirely for an imageless priced row with no modelBrand
- ✓leaves an unpriced row as a plain ListItem, untouched by the fallback
✓deriveMobileActiveRefAssembly views5
- ✓returns null when there is no selection and no URL highlight
- ✓returns the URL highlight when selection is empty
- ✓returns the most recently inserted ref when the selection has items
- ✓prefers the most recent toggle over the URL highlight when both exist
- ✓preserves the URL highlight after the user clears every selection
✓AssemblyView — degraded (brand) preset (front#1440)Assembly views5
- ✓renders the availability column for the degraded preset too (#2830 unified columns)
- ✓surfaces per-row cart checkboxes for the ARI preset (cart enabled)
- ✓renders the resizable desktop chrome (reset-layout control) for a brand
- ✓renders the empty-state card for a brand when a model-scoped baseUrl is present
- ✓does NOT render the empty-state card for a brand without a baseUrl (global route)
✓flattenDirectoryAssembly views5
- ✓emits one FlatPart per (part, diagram) pair and preserves diagram fields
- ✓derives schematicUrl per diagram so the dialog's diagram thumbnail renders
- ✓emits a single placeholder row for parts with zero diagrams
- ✓carries the server-stamped indexHeld onto every row the part produces
- ✓maps listPrice → price.list and carries availabilitySnapshot + finalReplacementPn through
✓BomTable display-only brand — cart:false keeps every column (#2830)Assembly views5
- ✓renders all 7 unified column headers (cart column present, not dropped)
- ✓renders NO row checkboxes (cart affordance gated off even with onToggleRow wired)
- ✓renders NO add-to-cart buttons
- ✓renders a quiet '—' cart placeholder cell in every row instead of the buy affordances
- ✓renders NO 'Add all in-stock' bulk bar (affordance suppressed for display-only)
✓KitBadge dont_list filtering (front#205)Assembly views5
- ✓renders single sellable kit sub-PN as a link
- ✓renders single dont_list kit sub-PN as plain text (no link)
- ✓renders dropdown trigger with full count even when some sub-PNs are dont_list
- ✓falls back to legacy kitPartNumbers (no kitParts) by linking every entry
- ✓renders empty kit (no sub-PNs) as a static badge with no link
✓BomTable sticky action cell opacity (CT-2073)Assembly views5
- ✓every sticky action cell carries the opaque .lg-bom-sticky-cell class (never bg-inherit)
- ✓marks a highlighted (deep-linked) row's sticky cell as highlighted
- ✓marks a selected (checkbox) row's sticky cell as tinted, not highlighted
- ✓marks a hovered row's sticky cell as tinted
- ✓lets the strong highlight win over the faint selection tint
✓DiagramIndexSummaryAssembly views5
- ✓renders intro prose and a chapter rollup table with totals
- ✓collapses the count table into a closed details while keeping it in the SSR HTML
- ✓leads the intro with the Hono diagrams about prose (front#2039)
- ✓ignores a blank about and renders the specs-derived intro unchanged
- ✓renders nothing when there are no chapters
✓matchesTokensAssembly views5
- ✓matches John's front#623 repro: space query against a hyphenated description
- ✓requires every token, not any
- ✓matches every row when the query is empty
- ✓matches on a substring, not only a whole word
- ✓finds a hyphenated part number typed without its hyphens
✓SchematicViewer calloutShape (front#1439)Assembly views5
- ✓defaults to rect callouts (no circles) — desktop byte-identical
- ✓renders circle callout shapes when calloutShape='circle'
- ✓circle callouts carry data-ref and reflect selection via data-active
- ✓circle callout fires onCalloutClick with the ref when clicked
- ✓circle callout shows the in-cart badge when its ref is carted
✓SchematicViewer discoverability hint (front#1493)Assembly views5
- ✓burned-in: renders a one-line hint above the diagram on first visit
- ✓burned-in: shows the pointer copy on pointer-capable devices
- ✓burned-in: shows the tap copy on touch devices
- ✓overlay: never renders the hint banner (CNH clean look)
- ✓burned-in: fades the hint after the first callout click but keeps the row (front#1523)
✓partAssembliesApiIdAssembly views5
- ✓sends the raw PN for CNH (search-MV) parts
- ✓sends the raw PN when the brand is unknown or absent
- ✓brands the SKU for McHale adapter parts so the lookup hits the adapter
- ✓brands the SKU for Ferris adapter parts
- ✓uppercases a lowercased adapter brand code
✓useZoomPan — double-tap-to-zoom (touch)Assembly views5
- ✓zooms to the tap point on a second tap within 300ms / 30px
- ✓resets to 1x on the second tap when current scale is past the threshold
- ✓does not double-tap when the second tap is more than 300ms later
- ✓does not double-tap when the second tap is more than 30px away
- ✓resets the double-tap tracker when a pinch (2-finger) starts
✓buildModelCompatibilityDiagram viewer5
- ✓lists compatible sibling variants, excluding the page's own model
- ✓dedupes variant labels and caps the named list with an overflow count
- ✓returns null when there are no variants
- ✓returns null when only the page's own model is a variant
- ✓falls back to the variant displayName when no description is present
✓adaptBrandCalloutDataForVendor (#1853)Business rules5
- ✓dedupes callouts for the hub-imported brands (MAR + KUH)
- ✓passes callouts through untouched for NH / ARI brands
- ✓drops non-numeric schematic dimensions — explicit null (Ventrac)
- ✓drops non-numeric schematic dimensions — absent keys (McHale)
- ✓keeps numeric schematic dimensions (Ferris)
✓migrateLegacyAssemblySidebarModeApp state5
- ✓ports legacy 'expanded' raw string into the store and clears the legacy key
- ✓ports legacy 'collapsed' raw string and clears the legacy key
- ✓does not overwrite an existing new-key envelope
- ✓ignores garbage value in the legacy key and clears it
- ✓is a no-op when neither key is set
✓<JsonLd>Diagram pages5
- ✓emits 3-item BreadcrumbList + CollectionPage at the co-located brand landing
- ✓uses the PATH-form type URL (not ?category=) for the category rung
- ✓keeps CollectionPage.url on the landing canonical even with an active category
- ✓never emits a retired /parts-diagrams/{brand} URL in either schema
- ✓pins the breadcrumb brand rung to buildBrandDiagramsLandingCanonical(slug)
✓<TypeCard> surface variantsDiagram pages5
- ✓defaults to the flat surface (bg-card, no glass tokens) so /parts-diagrams and /equipment stay unchanged
- ✓renders glass tokens when surface='glass' (brand hub opt-in)
- ✓treats surface='flat' identical to the default (no regression on explicit pass-through)
- ✓keeps the brand-aware hover lift on both surfaces (no fork of hover semantics)
- ✓composes surface with the other props (subtitle, href, ga4Source, imageSlug) without interference
✓diagramPageMetadataDiagram pages5
- ✓appends the site suffix to the OG title but not to the page title
- ✓omits the robots key entirely when none is supplied, so the layout's is inherited
- ✓passes a supplied robots directive through
- ✓falls back to the site OG image, alt-texted with the title
- ✓uses the supplied OG image when there is one
✓bomRowPdpHrefAssembly views5
- ✓prefers the backend canonical SKU so a CNH row skips the bare-PN double 308 (#2911)
- ✓percent-encodes the canonical SKU on the seo-preferred branch (#3650)
- ✓falls back to the buildPartHref closure when seo is absent (byte-identical to pre-#702)
- ✓falls back to raw /parts/{PN} when neither seo nor a closure is present
- ✓falls back when the canonical SKU is empty (never emits an empty href)
✓isBomRowLinkable — withdrawn cohort (front#3698)Assembly views5
- ✓does not link a no_cnh_data row: 200,731 BOM rows point at one and its PDP now 404s
- ✓does not link a no_cnh_data row even when it carries a price and an image
- ✓does not link a contentless dont_list row
- ✓still links a sellable row
- ✓fail-open: a row with no publishStatus stays linked
✓selectPopularPartsDiagram pages5
- ✓ranks by diagram frequency descending
- ✓breaks ties toward in-stock then priced parts
- ✓honors the limit
- ✓returns an empty array for empty input
- ✓does not mutate the input array
✓EquipmentPopularPartsDiagram pages5
- ✓renders PDP links with diagram frequency from a passed-in directory
- ✓fetches the directory when none is passed
- ✓renders nothing when there are no parts
- ✓renders nothing (non-fatal) when the directory fetch throws
- ✓drops a registry-held row so the band never advertises a 404 PDP (#3854)
✓VariantsAnalyticsDiagram pages5
- ✓fires variants_view on mount with current slug + count
- ✓emits brand=multi sentinel when entry brand is null
- ✓fires variant_clicked when a row link is clicked
- ✓fires variants_brand_filter when chip selection changes (multi-brand)
- ✓fires variants_year_filter when the year dropdown changes (single-brand)
✓EquipmentVariantsBannerDiagram pages5
- ✓renders an Alert when other variants exist
- ✓renders nothing when only the current variant exists
- ✓renders nothing when the variants endpoint fails
- ✓uses singular copy when exactly one other variant exists
- ✓does not pass brand filter when brand is the 'Equipment' fallback
✓generateMetadata — equipment-first title + description (#1098)Diagram pages5
- ✓leads with the assembly name + 'for <brand> <model>', code parenthetical
- ✓gives a shared diagram distinct titles under different host models
- ✓builds a unique fitment-rich description (no 'assembly with N parts' stub)
- ✓falls back to name + part count when the model is unresolved
- ✓does not duplicate the brand when displayName already includes it
✓EquipmentAssemblyDetailPage — guardsDiagram pages5
- ✓404s an assemblyCode that fails format validation, before any fetch
- ✓404s an ATTACHMENT-class sub-line even when the assembly resolved
- ✓404s when the assembly detail comes back empty
- ✓308s a legacy assembly code to the canonical slug, carrying ?highlight
- ✓does not redirect when the canonical slug already matches the URL
✓<AssemblyCard> href segment (#3647)Assembly views4
- ✓uses the assembly slug when it is present
- ✓falls back to the assemblyCode when the slug is null (brand-catalog vendor)
- ✓falls back to the assemblyCode when the slug field is absent entirely
- ✓falls back to the assemblyCode for an empty-string slug
✓AssemblyGrid pagination — RSC-safe descriptorAssembly views4
- ✓builds page-2 href with chapter filter preserved
- ✓preserves the explicit ?chapter= (all chapters) marker through pagination
- ✓omits chapter param when none selected
- ✓renders empty-state placeholder when there are no assemblies
✓toggleCalloutRef (#1374 hotspot click → BOM scroll anchor)Assembly views4
- ✓adding a ref returns it as the scroll anchor
- ✓removing a ref returns a null anchor — deselect must not scroll the list
- ✓anchors to the newest ref even when it sorts before existing selections
- ✓does not mutate the previous set
✓AssemblyView — CNH full preset (front#1440)Assembly views4
- ✓renders the resizable desktop layout with the BOM table and a cart column
- ✓links a CNH part number to its bare PDP path (edge 308s to the branded canonical) when assemblyContext is present
- ✓renders the branded wordmark placeholder when the schematic is missing but parts exist
- ✓renders the empty-state card when the assembly has no schematic and no parts
✓fetchBomDirectoryAssembly views4
- ✓calls the relative /api/models/:slug/bom-parts proxy (no direct hono URL)
- ✓throws on upstream non-2xx so TanStack Query surfaces isError
- ✓rejects a wire-shape drift (e.g. diagrams flattened to string[]) at the Zod gate
- ✓parses the live shape: no entry-level applicability, applicability on each diagram
✓BomTable unified stacked header for every brand (#2830)Assembly views4
- ✓NH renders the stacked header — no single-row variant
- ✓Ferris (brand) renders the stacked header — no single-row variant
- ✓the filter input is NOT flex-1 in the stacked header (own full-width row)
- ✓renders the results-count row OUTSIDE the scrollable table card (stacked layout)
✓getSubLineHrefAssembly views4
- ✓links the subLine (series) crumb to the hub's ?series= drill on the validated type base
- ✓resolves the series base off the canonicalized singular equipmentType (#2323 live repro)
- ✓returns null when the model has no subLine
- ✓returns null when the productType base does not resolve (no series without a routable type)
✓tokenizeAssembly views4
- ✓treats space, hyphen and slash as the same separator
- ✓collapses separator runs and trims the edges
- ✓lowercases so the corpus and the query meet in the same case
- ✓returns no tokens for an empty or separator-only query
✓resolveAssemblyNav (front#281 / front#295)Assembly views4
- ✓resolves neighbors for canonical UUID against UUID-keyed listing
- ✓resolves for pre-backfill rows with slug=null
- ✓fails-on-revert: slug-as-key against UUID listing fires Sentry at error
- ✓does not fire Sentry for an empty listing
✓getSidePanelDefaultPercentAssembly views4
- ✓returns 35 at 4K (>=3200)
- ✓returns 40 at QHD (2560..3199)
- ✓returns 50 below QHD (<2560)
- ✓preserves the original T-B11 thresholds (back-compat with assembly-interactive-view)
✓SchematicViewer onActiveCalloutPosition slot (front#1439)Assembly views4
- ✓emits null when no callout is selected
- ✓emits null when more than one callout is selected (rail disambiguates)
- ✓re-emits null when the active ref is cleared
- ✓does not throw when the slot is omitted (default callers)
✓SchematicViewer calloutLabelMode (front#1429 Group B)Assembly views4
- ✓defaults to overlay mode (NH) — draws a <text> label per callout
- ✓burned-in mode renders NO <text> — ARI numbers are printed in the image
- ✓burned-in mode keeps the clickable callout rects (data-ref intact)
- ✓burned-in mode keeps the accessible <title> on each callout
✓SchematicViewer CalloutOverlay hit-target expansionAssembly views4
- ✓renders one marker per duplicate ref (CNH legitimately repeats refs at each position)
- ✓renders an invisible expanded hit-rect for sub-minimum callouts
- ✓leaves large callouts byte-identical (hit-rect = visible rect dimensions)
- ✓the invisible hit-rect fires onCalloutClick when tapped
✓SchematicViewer resting outline — overlay mode (front#1493)Assembly views4
- ✓non-selected callouts rest transparent (CNH clean look)
- ✓keeps the hover/focus reveal classes so hover-sync still works
- ✓selected callout keeps its strong fill/stroke
- ✓callout groups carry cursor-pointer to override the pan grab cursor
✓SchematicViewer hover sync (front#1438) — active in BOTH modesAssembly views4
- ✓overlay: calls onCalloutHover with the ref on pointer enter and null on leave
- ✓burned-in: calls onCalloutHover with the ref on pointer enter and null on leave
- ✓overlay: marks the externally hovered callout as hover-active
- ✓burned-in: marks the externally hovered callout as hover-active
✓VendorLogoBadgeAssembly views4
- ✓renders the registry logo asset inside a circular badge for a carried brand (FER)
- ✓never renders the raw vendor code as visible text (regression for the glitch)
- ✓renders a neutral fallback badge when the vendor has no logo asset
- ✓renders a neutral fallback badge when no brand code is supplied
✓<AssemblyTree> — chapter mount capDiagram viewer4
- ✓mounts only CHAPTER_EAGER_COUNT chapter triggers on first paint when there is no active chapter
- ✓always mounts the active chapter eagerly even if it sits past the eager window
- ✓mounts one more chapter trigger after the observer fires
- ✓mounts every chapter eagerly when the count is below the eager window
✓<DiagramPartsRail> mount cap (front#1347)Diagram viewer4
- ✓mounts only RAIL_EAGER_COUNT rows on first paint; defers the rest
- ✓mounts a deferred row once it intersects the viewport
- ✓mounts every row eagerly when there are fewer than RAIL_EAGER_COUNT
- ✓preserves per-row ref + partNumber + price in eager and post-intersection rows
✓MobileDiagramView through the shared SchematicViewer (front#1439)Diagram viewer4
- ✓renders circle callouts via the shared viewer (not rect)
- ✓still renders the header, breadcrumb and parts rail
- ✓does NOT render callouts when the assembly has no callout data
- ✓FIX: a dimension-less feed renders circle callouts after the image loads
✓<MobileDiagramsShell>Diagram viewer4
- ✓composes equipment plate, search, tree, and the (silent) recent rail without crashing
- ✓renders the recently-viewed rail once the store has any items
- ✓hides the entire shell at lg breakpoint via lg:hidden on the wrapper
- ✓renders pass-through children inside the shell
✓patchBriggsSvgMarkup (#1853)Business rules4
- ✓fixes the Components-Engine viewBox typo and pins intrinsic size
- ✓returns null when the SVG is already standards-compliant
- ✓derives intrinsic size from the viewBox value when no dims are passed
- ✓still renames the typo when the viewBox value is unparseable
✓isPatchableSchematicSvgUrlBusiness rules4
- ✓accepts media-hosted https .svg schematics under a /schematics/ path
- ✓rejects a media-hosted .svg outside a /schematics/ path
- ✓rejects non-svg, other hosts, and non-https
- ✓exposes the host constant both consumers key off
✓/parts-diagrams — CATEGORY_SEEDSDiagram pages4
- ✓exposes exactly 9 Level-1 categories
- ✓has a displayName, subtitle, and at least one slug candidate per seed
- ✓includes the canonical 9 category names
- ✓subtitles surface farmer vocabulary called out in #700
✓resolveDiagramsJsonLdPropsDiagram pages4
- ✓hands the co-located tab its OWN visible ancestry, not this landing's
- ✓drops the auto-picked category — only a URL-explicit type is real hierarchy
- ✓leaves the standalone landing on its own Parts Diagrams chain
- ✓the override actually reaches the emitted schema
✓<TypeCardGrid>Diagram pages4
- ✓renders one card per type
- ✓shows empty-state copy when there are no types
- ✓threads brandSlug to each card so the co-located hub resolves repo-local brand tiles
- ✓keeps the standalone landing on the shared global tile when brandSlug is omitted (SEO stability)
✓resolveSub (#1938)Diagram pages4
- ✓returns sub: null when no sub is set
- ✓accepts a valid sub
- ✓strips an unknown sub back to the bare category
- ✓strips any sub when the category defines none (empty validSubSlugs)
✓/parts-diagrams/models — page bodyDiagram pages4
- ✓lists anchors for every model including an uncategorised one (county-1124)
- ✓disambiguates with a brand section heading, not a brand prefix per anchor
- ✓sections by brand rather than first letter (#3434)
- ✓renders a fail-soft empty state (no 500) when the slug fetch rejects
✓handleCopyListAssembly views4
- ✓writes a titled, aligned list the customer can paste into an email
- ✓leaves the price column blank for an unpriced part instead of printing a zero
- ✓confirms the copy with the part count
- ✓reports a denied clipboard rather than failing silently
✓handlePrintAssembly views4
- ✓renders one row per part with its chapter and price
- ✓escapes part data before it reaches the print document
- ✓opens the blob in a new tab
- ✓survives a popup blocker returning no window
✓comparePartsAssembly views4
- ✓keeps missing prices last in both directions
- ✓orders present prices by direction
- ✓breaks ties on partNumber so equal keys stay deterministic
- ✓sorts empty descriptions last ascending but first descending
✓/api/schematics/svg patch proxy (#2906)API endpoints4
- ✓patches the viewBox_supporto typo and serves image/svg+xml
- ✓passes a standards-compliant SVG through unchanged
- ✓rejects a missing or disallowed url with 400
- ✓redirects to the raw url when the upstream fetch fails
✓matchesBrandHintDiagram pages4
- ✓matches the canonical brand code case-insensitively (our internal links)
- ✓matches the brand slug form (hand-typed / federated URLs)
- ✓matches the display-name form
- ✓does not cross-match a different brand
✓pickDisambiguationMatchDiagram pages4
- ✓selects the matching candidate and mirrors a normal by-slug resolution
- ✓selects the other brand for its own code (real collision)
- ✓returns null when the brand hint is absent (caller shows the picker)
- ✓returns null when the hint matches no candidate (unknown synonym → picker)
✓equipment generateMetadata — growing-coverage robots (front#630)Diagram pages4
- ✓partsThin + totalParts=0 + indexing on → noindex,follow
- ✓partsThin + totalParts > 0 (Hono-fallback w/ BOM coverage) → indexable
- ✓not partsThin (full Catalog detail) → indexable regardless of count
- ✓growing-coverage page + indexing off → no page-level robots (layout wins)
✓equipment generateMetadata — per-brand seoIndexed gate (front#1397)Diagram pages4
- ✓registry brand not seo-indexed (McHale) + rich content + indexing on → noindex,follow (brand gate)
- ✓legacy brand not in the registry (Ford) + rich content + indexing on → indexable (no behavior change)
- ✓registry brand not seo-indexed + indexing off → no page-level robots (layout wins)
- ✓seo-indexed brand (new-holland) rich content + indexing on → indexable (byte-identical)
✓buildTitle — SERP title cap (#3081)Diagram pages4
- ✓caps a long vendor-folded title, keeping the descriptor intact
- ✓caps a long title and leads with the vendor when the name omits it
- ✓leaves an in-budget title unchanged (common case)
- ✓does not emit a leading space when the vendor is unknown
✓buildTitle — variant identity (#3105)Diagram pages4
- ✓distinguishes siblings that share a displayName
- ✓keeps the differing tail even when the config overflows the budget
- ✓adds nothing when the name already carries the model name
- ✓drops the qualifier rather than the model when the head fills the budget
✓generateMetadata (post-flip: IS_INDEXING_ENABLED=true)Diagram pages4
- ✓leaves robots unset for multi-variant pages — indexable per #1289/#2909
- ✓falls back to detail-page canonical when only 1 variant exists
- ✓returns 'Equipment Not Found' with NOINDEX_NOFOLLOW_ROBOTS for a genuine 404 slug
- ✓returns ServiceUnavailable metadata (NOT not-found) on a transient (#1329)
✓EquipmentSchematicActionsDiagram pages4
- ✓renders parts diagrams and catalog CTAs with correct hrefs and a11y labels
- ✓hides the Parts Catalog CTA when partsThin=true
- ✓hides the Parts Diagrams CTA when slug is empty
- ✓applies sectionIndex to --section-index CSS variable for animation stagger
✓generateMetadata — #3028 landing title/descriptionDiagram pages4
- ✓uses displayName + chapter count, no qualifier when the displayName is distinct
- ✓appends the variant config from modelName when displayName drops it
- ✓gives two same-displayName variants distinct titles and descriptions
- ✓caps an overlong landing title while keeping the chapter-count descriptor
✓generateMetadata — per-brand seoIndexed gate (front#1397)Diagram pages4
- ✓registry brand not seo-indexed (McHale) landing + indexing on → noindex,follow
- ✓registry brand not seo-indexed (McHale) landing + indexing off → no page-level robots (layout wins)
- ✓seo-indexed brand (new-holland) landing non-empty → indexable (byte-identical)
- ✓ENABLE_EQUIPMENT_TREE_NOINDEX → seo-indexed landing becomes noindex,follow
✓generateMetadata — Phase 4 partial-index richness gate (#2367)Diagram pages4
- ✓thin tail (partCount < MIN_PARTS) + flip on → noindex,follow (dup tail hidden)
- ✓thin tail (partCount < MIN_PARTS) + flip off → indexable (gate is dark)
- ✓at the MIN_PARTS boundary (partCount === MIN_PARTS) → indexable
- ✓canonical stays self-referential on thin tail (noindex,follow does not reroute)
✓buildBomPartHref (front#1195 + front#1311 / #2764 — clean crawl hop)Assembly views3
- ✓emits the bare PN for a CNH model code (#2764 — no query string, no badge)
- ✓emits the Ferris branded path (front#1429 — leak-safe diagram→PDP hop)
- ✓falls back to the raw PN path when the brand code is unknown
✓part-number → PDP resolution (relevance inversion guard)Assembly views3
- ✓resolves 21.48424 to a /parts/ PDP, not the assembly page
- ✓keeps the literal part number in the PDP path (no slugify of the PN)
- ✓always lands a /parts/ leaf even when the brand code is unknown
✓AssemblyView — desktop layout controls overlay the canvas (front#1511)Assembly views3
- ✓renders the three layout buttons INSIDE the schematic canvas card
- ✓the panel-controls overlay is desktop-only (hidden lg:flex)
- ✓a brand (resizable) page also overlays its layout controls on the canvas
✓schematicUrlForCodeAssembly views3
- ✓derives the canonical media.clintontractor.net schematic URL from an assembly code
- ✓returns null for an empty code so a diagram-less row renders no broken thumbnail
- ✓url-encodes codes so an exotic code can't break the URL
✓BomTable hover sync (front#1438)Assembly views3
- ✓calls onRowHover with the ref on row pointer-enter and null on leave
- ✓visually marks the externally hovered row
- ✓does not break when hover props are omitted (back-compat)
✓BomTable main-row link suppression for dont_list (front#205)Assembly views3
- ✓renders the main row PN as a Link when publishStatus is sellable
- ✓renders the main row PN as plain text (no Link) when publishStatus is dont_list
- ✓falls back to Link when publishStatus is undefined (legacy hono response)
✓ChapterAssemblyList — pre-grouped brand map (front#1494)Assembly views3
- ✓renders from the map and never calls the CNH lazy-fetch hook with a chapter
- ✓shows the empty message when the chapter has no pre-grouped assemblies
- ✓CNH regression pin: without the map, the lazy-fetch hook drives the chapter
✓DiagramsEmptyStateAssembly views3
- ✓links high-intent visitors to the model parts catalog and the parts desk (#633)
- ✓fires parts_diagrams_empty with reason=data_missing for a 0-chapter landing (#632)
- ✓tags a chapter view with reason=filtered when the backend had rows (#632)
✓<MobileChapterDrawer> triggerAssembly views3
- ✓shows generic "Chapters" label when no active chapter
- ✓shows "Chapters · {displayName}" when active chapter resolved
- ✓hidden on desktop (lg:hidden) via wrapper class
✓<MobileChapterDrawer> variant="thumbnails"Assembly views3
- ✓reads "Browse Diagrams" on the trigger and DrawerTitle
- ✓reads "Browse Diagrams · {chapter}" when an active chapter is set
- ✓renders thumbnail rows when chapterAssembliesByName is provided
✓SchematicViewer pulse-on-load (front#1493)Assembly views3
- ✓burned-in: applies the pulse class when reduced motion is NOT preferred
- ✓burned-in: omits the pulse class when reduced motion IS preferred
- ✓overlay: never pulses, even when reduced motion is NOT preferred
✓SchematicViewer dimension fallback (front#1433 — McHale)Assembly views3
- ✓dimensions present (Ventrac/NH/Ferris): overlay renders immediately with provided viewBox
- ✓dimensions absent (McHale): NO hotspot overlay until the image loads
- ✓dimensions absent: overlay appears using naturalWidth/Height after onLoad
✓SchematicViewer panelControls slot (front#1511)Assembly views3
- ✓renders nothing extra when no panelControls are passed (back-compat)
- ✓renders the panelControls slot INSIDE the white canvas card
- ✓the slot is bottom-right and desktop-only (hidden lg:flex), distinct from zoom controls
✓useViewportWidthAssembly views3
- ✓returns the current window.innerWidth after mount
- ✓updates when the window resizes
- ✓removes the resize listener on unmount
✓useZoomPan — pan bounds clamping (front#1438)Assembly views3
- ✓clamps a huge drag so panX saturates at the computed bound
- ✓allows pan up to the overflow half-extent when the image is larger than the container
- ✓clamps arrow-key panning so it cannot push the image off-screen
✓<AssemblyTree> — controlled open stateDiagram viewer3
- ✓opens the deep-linked chapter on mount
- ✓closes the previously open chapter when another opens (accordion)
- ✓closes the currently open chapter on a second click
✓<AssemblyTree> — assembly mount cap inside open chapterDiagram viewer3
- ✓mounts only ASSEMBLY_EAGER_COUNT rows on first paint inside the open chapter
- ✓mounts one more assembly link after the observer fires
- ✓mounts every assembly eagerly when the count is below the eager window
✓<DeferredListItem>Diagram viewer3
- ✓renders an empty <li data-deferred> with reserved minHeight before intersection
- ✓mounts children once the observer fires
- ✓mounts eagerly when IntersectionObserver is undefined
✓<MobileCategorySelect>Diagram pages3
- ✓renders a hidden-on-desktop select with All option + every category
- ✓adds a series sub-select when a brand-type category is active with ≥2 series (#2134)
- ✓omits the series sub-select for a single (lone) series
✓assemblyOgImageDiagram pages3
- ✓uses a real schematic
- ✓falls back to the site image when the backend served a CNH placeholder
- ✓falls back when the schematic is null or absent
✓#2209 multi-brand category federation — McHaleDiagram pages3
- ✓folds every live McHale category into the canon (none silently dropped)
- ✓surfaces McHale beside New Holland under the Hay & Forage (Baler) shelf
- ✓keeps non-baler McHale categories off the Hay & Forage zone where they do not belong
✓isBomRowLinkable — registry-held rows keep their place and lose their linkAssembly views3
- ✓a held row is not linkable
- ✓the stamp keeps every row — the BOM is not thinned, only unlinked
- ✓flag off: the same held row keeps its link, so the stamp is the only lever
✓admin-widget-diagram-mount-invariant.regressionAdmin logic3
- ✓pdp-gallery mount files a byte-identical diagram issue vs the grid tile
- ✓full-size-viewer mount files a byte-identical diagram issue vs the grid tile
- ✓the mounted issue equals the canonical buildDiagramIssueUrl output
✓isNonEquipmentSubLineDiagram pages3
- ✓returns true for exact ATTACHMENT
- ✓returns false for empty/missing subLine
- ✓returns false for real-equipment sub-lines
✓withPartLinksDiagram pages3
- ✓links catalog rows, drops brand-held and out-of-catalog rows (flag on)
- ✓keeps the brand-held link while the flag is off (PDP still answers 200)
- ✓passes null through
✓/api/models/:modelCode/bom-parts — index verdictAPI endpoints3
- ✓stamps indexHeld on a registry-rejected row and leaves a vouched one alone
- ✓leaves a row with no verdict unstamped — an absent verdict is not a hold
- ✓stamps nothing while the gate flag is off, so the rollback switch still works
✓normalizeBrandParamDiagram pages3
- ✓returns a trimmed string for a single value
- ✓takes the first entry of a repeated param
- ✓returns null for undefined, empty, or whitespace-only
✓EquipmentMediaGallery empty-state fallback (front#2769 follow-up)Diagram pages3
- ✓renders the resolved family/class photo when the model has no real images
- ✓falls through to the branded placeholder when the ladder also comes up empty
- ✓still shows the real cover image untouched when one exists
✓resolveAssemblyListRobots — equipment-tree noindex (#3594)Diagram pages3
- ✓flag off → the landing stays indexable
- ✓flag on → noindex,follow
- ✓flag on + indexing off → no page-level robots (layout wins)
✓generateMetadata — route-unique code in the description (#3197)Diagram pages3
- ✓separates two same-named assemblies whose assemblyId is blank
- ✓separates assemblies that share a CNH section code
- ✓keeps the description within the SERP budget
✓generateMetadata — per-brand seoIndexed gate (front#1397)Diagram pages3
- ✓registry brand not seo-indexed (McHale) + rich assembly + indexing on → noindex,follow
- ✓registry brand not seo-indexed (McHale) + indexing off → no page-level robots (layout wins)
- ✓seo-indexed brand (new-holland) rich assembly + indexing on → indexable (byte-identical)
✓generateMetadata — og:image fallback (#1118)Diagram pages3
- ✓uses the real schematic for og:image / twitter:image when present
- ✓falls back to DEFAULT_OG_IMAGE_URL when the schematic is missing
- ✓falls back to DEFAULT_OG_IMAGE_URL for a CNH placeholder schematic
✓generateBomItemListSchema — sku suppression for unresolved vendor (front#1475)Diagram pages3
- ✓omits the sku (no CT-XXX-) when the model brand has no vendor code
- ✓omits the sku when modelBrand is null
- ✓still emits the branded sku when the vendor code resolves
✓<AssemblyCard> schematic thumbnail (#2906)Assembly views2
- ✓routes a media SVG thumbnail through the patch proxy
- ✓leaves a raster schematic on its original url
✓AssemblyGrid card href (front#1195 — slug, not UUID)Assembly views2
- ✓links the canonical slug so the crawl hop lands a 200 (no UUID 308)
- ✓falls back to the UUID assemblyCode when slug is absent (pre-backfill rows)
✓bomRowKey (front#1128)Assembly views2
- ✓derives distinct keys for two PNs that share one callout ref
- ✓derives distinct keys for one PN referenced by two callouts (many-to-many)
✓toggleRowKey (front#1128 per-row selection)Assembly views2
- ✓toggling one row never affects a sibling sharing the same callout ref
- ✓does not mutate the previous set (returns a new Set)
✓AssemblyView — callout marker shape plumbing (front#1512)Assembly views2
- ✓McHale (ellipse capability) renders ellipse hotspot markers in the canvas
- ✓Ferris / NH (rect capability) keep rectangular hotspot markers
✓AssemblyView — single-design mobile branch (front#1440)Assembly views2
- ✓renders the MobileDiagramView for a brand preset (the audited single-design fix)
- ✓does not crash and omits the model crumb when model is null (brand data gap)
✓AssemblyView — layout slot (#3623)Assembly views2
- ✓emits only the desktop half in the desktop slot
- ✓emits only the mobile half — no second BOM — in the mobile slot
✓BomTable per-row pdpHref gate (front#1429)Assembly views2
- ✓links a Ferris row that carries a non-null pdpHref
- ✓renders a Ferris row with a null pdpHref as plain text (no PDP link)
✓BomTable supersession rendering (front#1495)Assembly views2
- ✓renders the newer-version PN as plain text when capability disables pdpLinks
- ✓CNH also renders the newer-version PN as plain text (#3854)
✓BomTable NH capabilities are the default (no behavior change)Assembly views2
- ✓renders the Availability column when capabilities default / NH
- ✓omitting capabilities behaves exactly like NH (Availability present)
✓BomTable per-row selection (front#1128)Assembly views2
- ✓toggling one PN's checkbox emits its row key, not the shared ref
- ✓checks only the selected row even when a sibling shares the callout ref
✓buildChapterItemListSchemaAssembly views2
- ✓returns null for an empty chapter list
- ✓builds an ItemList with one positioned element per chapter
✓<MobileChapterDrawer> open behaviourAssembly views2
- ✓opens DrawerContent on trigger click and exposes DrawerTitle for a11y
- ✓renders chapter rows inside the drawer once opened
✓<MobileChapterDrawer> auto-close on navigationAssembly views2
- ✓closes when pathname changes (chapter Link click → route transition)
- ✓closes when searchParams change (chapter query string change)
✓buildCorpusAssembly views2
- ✓drops null and undefined fields without leaving stray separators
- ✓returns an empty string when a row has no searchable text
✓SchematicViewer resting outline — burned-in mode (front#1493)Assembly views2
- ✓non-selected callouts keep the always-visible outline
- ✓selected callout keeps its strong fill/stroke
✓SchematicViewer optimizer bypass (front#1435 — DPR-1 callout alignment)Assembly views2
- ✓dimensions absent (McHale): renders the schematic image unoptimized so naturalWidth equals the true source size
- ✓dimensions present (NH/Ferris/Ventrac): keeps the optimized path unchanged
✓SchematicViewer canvas fills the panel (front#1523 F2)Assembly views2
- ✓the white canvas card no longer drops to auto height on lg (fills the panel)
- ✓the outer wrapper stays a flex column on lg (does not revert to block/auto)
✓SchematicViewer letterbox aspect box (front#1523 F2 invariant)Assembly views2
- ✓img and SVG overlay share one aspect-ratio box (img box == overlay box)
- ✓mobile (<lg) keeps the 60dvh letterbox path byte-identical
✓SchematicViewer hint row stability (front#1523 F3-left / F4)Assembly views2
- ✓burned-in: renders a persistent h-9 hint row above the diagram
- ✓burned-in: the hint row keeps its height after dismissal (text fades, row stays)
✓useZoomPan — orientation changeAssembly views2
- ✓re-fits the canvas and clears pan when orientation flips
- ✓does not re-fit on transient resizes that aren't orientation flips
✓<AssemblyTree> — deep-link scroll (front#1331)Diagram viewer2
- ✓scrolls the active chapter into view on landing
- ✓does not scroll when no chapter is active
✓dedupeCalloutsByRef (#1853)Business rules2
- ✓keeps the first hotspot per ref and drops later duplicates
- ✓is a no-op when refs are already unique
✓isPatchableSchematicSvgBusiness rules2
- ✓accepts media-hosted https .svg schematics
- ✓rejects non-svg, other hosts, and non-https
✓buildSchematicThumbnailSrcBusiness rules2
- ✓routes media SVGs through the patch proxy with the url encoded
- ✓passes raster schematics and non-media urls through untouched
✓/parts-diagrams — crawl-discoverability (#1195)Diagram pages2
- ✓links the type hubs AND one prominent link to /parts-diagrams/models
- ✓does NOT embed per-model parts-diagrams anchors inline (hub kept light)
✓<TypeCard> imageSrc override (#1900)Diagram pages2
- ✓renders the direct imageSrc and bypasses the manifest resolver
- ✓wins over brandSlug + imageSlug when all three are present
✓<TypeCard> edit prop (category vs global-category variants)Diagram pages2
- ✓the existing brand-scoped category variant leaves the customer DOM byte-identical (gate off)
- ✓the global cross-brand variant wraps the region byte-identically with no admin chrome (gate off)
✓no internal links to the retired diagrams directories (#2765, #3345)Diagram pages2
- ✓links no retired /parts-diagrams or /parts/diagrams URL — every one answers 410
- ✓matches retired shapes and spares the live surfaces
✓/parts-diagrams/models — metadataDiagram pages2
- ✓self-canonicals to /parts-diagrams/models and bypasses the layout title template
- ✓does not set a noindex robots override (page is indexable via layout default)
✓PartNumberCellAssembly views2
- ✓renders an anchor to the PDP when the row is linkable
- ✓renders the number as plain text — no anchor at all — when it is not
✓nullsLastAssembly views2
- ✓treats null, undefined and empty string as missing
- ✓ties when both are missing and defers when both are present
✓preset round-tripAssembly views2
- ✓maps every preset back to itself
- ✓reports no preset for a header-click state the dropdown cannot show
✓buildDiagramIssueUrlAdmin logic2
- ✓routes a wrong-diagram flag to the diagram-review label (kind=diagram)
- ✓routes a suggested replacement and carries the proposed schematic URL
✓breadcrumbEquipmentFetchFailureDiagram pages2
- ✓emits an error breadcrumb with the Error message extracted
- ✓stringifies a non-Error thrown value
✓chaptersUnavailableReasonDiagram pages2
- ✓reports transient failures (5xx / 429 / timeout / network)
- ✓returns undefined for a genuine 4xx so an unknown slug still 404s
✓/equipment/[slug]/not-found generateMetadataDiagram pages2
- ✓post-flip (IS_INDEXING_ENABLED=true) emits NOINDEX_NOFOLLOW_ROBOTS
- ✓pre-flip (IS_INDEXING_ENABLED=false) omits robots so layout's noindex,nofollow is inherited
✓equipment generateMetadata — equipment-tree noindex (#3594)Diagram pages2
- ✓flag on → noindex,follow even for a rich, seo-indexed model
- ✓flag on + indexing off → no page-level robots (layout wins)
✓equipment generateMetadata — soft-404 / ServiceUnavailable robots (front#983)Diagram pages2
- ✓SearchServiceDown + indexing on → noindex,nofollow (body renders ServiceUnavailable)
- ✓SearchServiceDown + indexing off → no page-level robots (layout wins)
✓RelatedEquipmentGridDiagram pages2
- ✓renders nothing when the backend returns zero siblings
- ✓renders equipment cards linking to sibling slugs with a11y labels
✓EquipmentAssembliesPage — diagram index summary enrichmentDiagram pages2
- ✓renders the summary prose and chapter ItemList exactly once
- ✓omits the summary when the model has no chapters
✓parseProductionYears / formatProductionYearsDiagram pages2
- ✓parses closed, open-ended ('present'), open-ended ('+'), and single-year windows
- ✓formats closed, open, single-year, and null windows
✓EquipmentDetail — variantsBanner slotDiagram pages2
- ✓renders the banner when variantsBanner is provided
- ✓does not render a banner when variantsBanner is null
✓generateMetadata — soft-404 / ServiceUnavailable robots (front#983)Diagram pages2
- ✓chapters fetch throws + indexing on → noindex,nofollow (covers ServiceUnavailable body)
- ✓chapters fetch throws + indexing off → no page-level robots (layout wins)
✓generateMetadata — variant title differentiator (#3649)Diagram pages2
- ✓gives all three configs a distinct title with no leading ellipsis
- ✓still titles the page when the variants lookup fails
✓page.tsx wiringDiagram pages2
- ✓page.tsx invokes redirectIfLegacyAssemblyCode after notFound guard
- ✓imports redirectIfLegacyAssemblyCode from ./_guards
✓generateMetadata — #3028 title cap + description code dedupeDiagram pages2
- ✓inlines the assembly code into the description (route-unique dedupe)
- ✓truncates an overlong title but always keeps the assembly code suffix
✓generateBomItemListSchema — name / description cleanup (CT-1315)Diagram pages2
- ✓strips fitment clause + duplicated trailing PN from name, moves fitment to description
- ✓emits no description when the row has no fitment clause
✓escapeJsonLdDiagram pages2
- ✓escapes </script> so the script tag cannot break out
- ✓escapes <, >, &, U+2028, U+2029
✓AssemblyGrid schematic runtime-error fallback (front#2769)Assembly views1
- ✓swaps to the MediaPlaceholder when a real schematicUrl fails to load
✓AssemblyView — resizable panel padding (#2830)Assembly views1
- ✓both resizable panel content wrappers use the same padding (p-2)
✓loadAllBomPartsAssembly views1
- ✓returns FlatPart[] derived from the directory response
✓BomTable analyticsAssembly views1
- ✓emits bom_view_toggle with the target mode when Unwrap button is clicked
✓/parts-diagrams — metadataDiagram pages1
- ✓uses title.absolute so the layout's '%s | CROP' template does not duplicate the suffix
✓handleEmailListAssembly views1
- ✓opens a mailto with the model in the subject and the list in the body
✓ZoomThumbAssembly views1
- ✓opens and closes the preview on focus, not hover alone
✓CatalogDiagramLinkAssembly views1
- ✓exposes the lazy diagram lookup as a real button
✓breadcrumbEquipmentNotFoundDiagram pages1
- ✓emits a warning breadcrumb carrying slug, reason, and route
✓isPartsDiagramsLandingEmptyDiagram pages1
- ✓null → false; chapterCount>0 → false; chapterCount===0 → true
✓isPartsDiagramsChapterEmptyDiagram pages1
- ✓null → false; populated → false; [] → true
✓generateMetadata (pre-flip: IS_INDEXING_ENABLED=false)Diagram pages1
- ✓multi-variant page omits robots so layout's noindex,nofollow is inherited
✓yearInWindowDiagram pages1
- ✓respects closed, open-ended, and missing windows
✓variantDifferentiatorDiagram pages1
- ✓strips year tokens, truncates at 40, and handles empty input
✓sortVariantsDiagram pages1
- ✓newest start year DESC, model_code ASC, no-year variants pushed to end
✓collectYearOptionsDiagram pages1
- ✓returns distinct years DESC across every variant's window, empty when none
What we walk through in a real browser17 journeys
○retired hub answers 410 Gone @smokeBrowser journey11
- ○410 on /parts-diagrams/categories @smoke
- ○410 on /parts-diagrams/category/hay-forage @smoke
- ○410 on /parts-diagrams/type/tractors @smoke
- ○410 on /parts-diagrams/ferris @smoke
- ○410 on /parts-diagrams/new-holland-agriculture @smoke
- ○410 on /parts-diagrams/new-holland @smoke
- ○410 on /parts-schematics @smoke
- ○410 on /parts/diagrams @smoke
- ○legacy ?category= serves the hub rather than redirecting @smoke
- ○the bare hub is live, not gone @smoke
- ○the live model-diagram viewer is NOT gone @smoke
○/parts/brand/new-holland-agriculture/diagrams (V2 type-first landing)Browser journey5
- ○landing shows the identity card + Browse-by-Type tiles linking to ?category=
- ○unified search: classifier-hint appears for PIN input
- ○?category= renders TypeHero + product-groups nav + grouped model sections (noindex)
- ○deep-state ?category=construction&sub=skid-steer-loaders lands on the sub + back restores
- ○?category=&line= still resolves and stays noindex (legacy param)
○T-B10 — assembly sidebar default rail + persistenceBrowser journey3
- ○sidebar renders as a slim rail by default (no chapter list visible)
- ○clicking the rail toggle expands the sidebar and persists across reload
- ○collapsed state persists when the user re-collapses the sidebar
○front#1311 — clean BOM→PDP links + sessionStorage contextBrowser journey2
- ○BOM part link is clean, and clicking it restores the assembly bar
- ○a direct PDP visit (no click) shows no assembly bar
○Parts ⇄ Diagrams cold first navigation @smokeBrowser journey2
- ○Parts → Diagrams keeps real chrome, scroll and document continuity
- ○Diagrams → Parts keeps real chrome, scroll and document continuity
○T-B11 — 1920×1080 baseline (regression vs T-B10)Browser journey1
- ○canvas claims the full viewport — no 1536 container cap
○T-B11 — 2560×1440 QHDBrowser journey1
- ○canvas ≥ 2200px, BOM price header inline
○T-B11 — 3440×1440 ultrawideBrowser journey1
- ○canvas ≥ 3000px, no horizontal scrollbar
○T-B11 — 3840×2160 4KBrowser journey1
- ○canvas ≥ 3000px, full BOM visible, no horizontal scrollbar
○T-B11 — 1280×800 regression (T-B10 add-to-cart still visible)Browser journey1
- ○BOM add-to-cart stays inside viewport, no horizontal page scroll
○T-B11 — mobile 375×667 (T-B10 behaviour preserved)Browser journey1
- ○mobile renders its own diagram view, no desktop rail, no horizontal scroll
○T-B10 — BOM add-to-cart visibility at 1280×800Browser journey1
- ○every BOM row's add-to-cart button is visible (not clipped horizontally)
○T-B10 — mobile: sidebar rail does not apply at <768pxBrowser journey1
- ○assembly detail page renders its own mobile view, no desktop rail
○Mobile parts-diagram interactionsBrowser journey1
- ○renders zoomable canvas + BOM rail + search filter on mobile
○brand diagrams surfaceBrowser journey1
- ○the brand tab renders the type grid and links the model viewer
○Parts ⇄ Diagrams warm Instant Navigation contractBrowser journey1
- ○both directions commit from the warmed router cache
○Brand selector rail @smokeBrowser journey1
- ○stays one row, contains page overflow, and keeps the active brand visible
Automated checks852
Browser journeys67
Code exercised77.7%
What we check automatically183 groups
✓manufacturer-configReference data52
- ✓resolves the canonical slug for New Holland (Agriculture)
- ✓resolves the legacy New Holland form new-holland to the canonical agriculture config
- ✓resolves the legacy New Holland form newholland to the canonical agriculture config
- ✓resolves the legacy New Holland form newhollandagriculture to the canonical agriculture config
- ✓resolves the legacy New Holland form NEW-HOLLAND to the canonical agriculture config
- ✓resolves Ferris to the FER vendor code, available but not seo-indexed
- ✓resolves ventrac to VNT, available but not seo-indexed
- ✓resolves mchale to MCH, available but not seo-indexed
- ✓resolves marcrest to MAR, available but not seo-indexed
- ✓resolves kuhn to KUH, available but not seo-indexed
- ✓resolves kress to KRE, available but not seo-indexed
- ✓resolves agco to AGC, available but not seo-indexed
- ✓resolves the vanity alias briggs to canonical slug briggs-stratton
- ✓resolves the vanity alias briggsandstratton to canonical slug briggs-stratton
- ✓resolves the vanity alias briggs-and-stratton to canonical slug briggs-stratton
- ✓resolves the vanity alias greatplains to canonical slug great-plains
- ✓resolves the vanity alias clubcar to canonical slug club-car
- ✓resolves the vanity alias agbag to canonical slug ag-bag
- ✓resolves the vanity alias dionag to canonical slug dion-ag
- ✓resolves the vanity alias harvesttec to canonical slug harvest-tec
- ✓resolves the vanity alias eztrail to canonical slug ez-trail
- ✓returns null for an unknown alias
- ✓contains the activated brands (+ landoll + brillion + agco)
- ✓contains the activated vendor codes (+ LDL + BRL + AGC)
- ✓matches the `available: true` flag on MANUFACTURER_CONFIGS
- ✓flags only the activated brands as available; every other config is falsy
- ✓derives SEO_INDEXED_BRAND_SLUGS to the two New Holland divisions
- ✓flags only the NH divisions with seoIndexed: true; every other config is falsy
- ✓matches the `seoIndexed: true` flag on MANUFACTURER_CONFIGS
- ✓maps the canonical New Holland agriculture slug to the NHL vendor code
- ✓still maps the retired new-holland slug to the NHL vendor code
- ✓maps the vendor code unchanged (case-insensitive)
- ✓resolves slug aliases through to the vendor code
- ✓resolves the legacy Ferris code FER to the canonical FER (ct-2204)
- ✓returns the same vendor code for slug and code forms
- ✓maps the NH Construction division slug to the virtual NHC code (#2750)
- ✓passes unknown input through unchanged (so it 0-results, not 404s)
- ✓handles empty / whitespace input safely
- ✓registers the construction config: NHL code, not available, seo-indexed
- ✓resolves NHL by vendor code to the Agriculture parent, never the division
- ✓resolves the legacy FER alias to the Ferris config (canonical FER)
- ✓still resolves the canonical FER code directly
- ✓returns null for a genuinely unknown code
- ✓new-holland-agriculture config matches its registry record
- ✓ferris config matches its registry record
- ✓ventrac config matches its registry record
- ✓mchale config matches its registry record
- ✓marcrest config matches its registry record
- ✓kuhn config matches its registry record
- ✓kress config matches its registry record
- ✓agco config matches its registry record
- ✓carries identity only — no store-specific keys creep back in (#3857)
✓not-found surfaces carry no breadcrumbSite pages21
- ✓/ (root boundary) emits no BreadcrumbList JSON-LD
- ✓/ (root boundary) renders no breadcrumb nav
- ✓/parts boundary emits no BreadcrumbList JSON-LD
- ✓/parts boundary renders no breadcrumb nav
- ✓/parts/[id] boundary emits no BreadcrumbList JSON-LD
- ✓/parts/[id] boundary renders no breadcrumb nav
- ✓/parts/brand/[slug] boundary emits no BreadcrumbList JSON-LD
- ✓/parts/brand/[slug] boundary renders no breadcrumb nav
- ✓/parts/brand/[slug]/type/[typeSlug] boundary emits no BreadcrumbList JSON-LD
- ✓/parts/brand/[slug]/type/[typeSlug] boundary renders no breadcrumb nav
- ✓/parts-diagrams/model/[slug] boundary emits no BreadcrumbList JSON-LD
- ✓/parts-diagrams/model/[slug] boundary renders no breadcrumb nav
- ✓/parts-not-found emits no BreadcrumbList JSON-LD
- ✓/parts-not-found renders no breadcrumb nav
- ✓/brand-not-found emits no BreadcrumbList JSON-LD
- ✓/brand-not-found renders no breadcrumb nav
- ✓/equipment-not-found emits no BreadcrumbList JSON-LD
- ✓/equipment-not-found renders no breadcrumb nav
- ✓/assembly-not-found emits no BreadcrumbList JSON-LD
- ✓/assembly-not-found renders no breadcrumb nav
- ✓still offers a way back — the catalog boundary keeps a /parts link
✓isJunkTemplateTitle (CROP-front#831 — hono junk-template detector)Shared helpers21
- ✓flags the upstream junk template for '47425516'
- ✓flags the upstream junk template for '47425851'
- ✓flags the upstream junk template for '47442202'
- ✓flags the upstream junk template for '47443463'
- ✓flags the upstream junk template for '47685843'
- ✓flags the upstream junk template for '84159488C'
- ✓flags the upstream junk template for '73344274'
- ✓flags the upstream junk template for 'HT7964635CDS'
- ✓does NOT flag the customer-readable fitment title for '731143012'
- ✓does NOT flag the customer-readable fitment title for '86564333'
- ✓does NOT flag the customer-readable fitment title for '102787A1'
- ✓does NOT flag the customer-readable fitment title for '90333701'
- ✓does NOT flag the customer-readable fitment title for '51475378'
- ✓does not flag a small-N fixed-shape title naming one model
- ✓does not flag the metadata-fallback title (`PN · Manufacturer`)
- ✓requires the tail segment to equal the part number
- ✓requires the middle segment to equal the manufacturer name
- ✓is case-insensitive on PN and manufacturer match
- ✓handles missing inputs gracefully
- ✓does not flag titles using a different separator
- ✓does not flag titles with extra segments
✓analytics.trackBusiness rules15
- ✓sends flat payload to gtag unchanged
- ✓flattens nested objects with underscore prefix
- ✓joins arrays into comma-separated strings
- ✓omits null and undefined values
- ✓truncates string values exceeding 100 chars
- ✓truncates joined array values exceeding 100 chars
- ✓passes booleans through
- ✓sends event without payload when none provided
- ✓sends original (unflattened) payload to Segment sink
- ✓logs to console.info in dev when no sinks available
- ✓drops array-of-objects keys with a dev warning (regression guard for GA4 items bug)
- ✓compile-time: rejects ecommerce literals + widened strings (type-only)
- ✓trackDynamic routes ecommerce names to trackEcommerce at runtime
- ✓trackDynamic flattens non-ecommerce events (same as track)
- ✓redirects ecommerce-named events to trackEcommerce at runtime (defense in depth)
✓retryBusiness rules15
- ✓returns false for AbortError
- ✓returns true for network errors
- ✓returns true for timeout errors
- ✓returns true for 5xx status codes
- ✓returns true for 429 (rate limit)
- ✓returns false for 4xx errors
- ✓returns false for random objects
- ✓returns result on first success
- ✓retries on failure and succeeds
- ✓throws after max retries
- ✓does not retry non-retryable errors
- ✓calls onRetry callback
- ✓respects abort signal before first attempt
- ✓respects abort signal during retry delay
- ✓uses custom shouldRetry function
✓useScrollSpyInterface behaviour13
- ✓returns null before any section intersects
- ✓returns the id of the intersecting section
- ✓observes one element per section id that exists in the DOM
- ✓uses the prototype rootMargin by default
- ✓honors a custom rootMargin override
- ✓disconnects the observer on unmount
- ✓keeps the last intersecting id when an entry leaves the viewport
- ✓picks the topmost section below the header when multiple sections intersect
- ✓ignores sections whose top is above the header when picking active
- ✓forces the last id when scrolled to page bottom even if it never intersects
- ✓does not force the last id on a short, non-scrollable page
- ✓re-evaluates on resize when nearing the page bottom
- ✓removes scroll/resize listeners on unmount
✓scrubWholesaleFieldsBusiness rules12
- ✓removes price-context leak keys at all nesting levels
- ✓scrubs arrays of objects
- ✓leaves primitives and non-leak keys untouched
- ✓preserves public dealer contact entity fields (equipment marketplace)
- ✓still strips dealer* price variants (dealerPrice, dealerCost, dealerList, dealerListPrice)
- ✓strips snake_case variants emitted by Python / Mongo / PG backends
- ✓keeps company-name strings that merely start with 'wholesale' (wholesaler, etc)
- ✓strips bare `net` when nested under a pricing-container parent (CT-674)
- ✓does NOT strip bare `net` / `dealer` at the root (no pricing context)
- ✓strips raw CNH availability signal keys (cnh_availability, cnh_orderability, cnh_orderability_raw)
- ✓redacts raw signal words embedded in string values
- ✓does not over-match substrings inside English words (reduce, Greyhound)
✓test-utils/factories (#1916)Shared building blocks11
- ✓makeSearchPart satisfies required Part fields
- ✓makeCatalogPart is distinct from makeSearchPart (catalog shape)
- ✓makeStaffPart adds staff-only publish fields
- ✓makeBomPart satisfies required BomPart fields
- ✓makeFavoritedProduct wraps catalog data for garage favorites
- ✓makeCartItem includes cart-store required fields
- ✓makeSearchResponse wires parts + pagination
- ✓makeUser threads Clerk role into publicMetadata
- ✓enumerates all 8 display states with getMatrixLabel SSoT badges
- ✓makeOrderabilityState in-stock tiers stay 'In Stock' regardless of confirmed (#2908 fixed-orderability line)
- ✓exposes CNH stock light enum for matrix cartesian tests
✓sentryBeforeSendBusiness rules10
- ✓scrubs request.data, extra, contexts, and breadcrumbs
- ✓redacts leak terms embedded in breadcrumb message strings
- ✓redacts raw CNH signal words in breadcrumb messages
- ✓redacts a Telegram bot token embedded in a breadcrumb fetch URL
- ✓redacts a Telegram bot token embedded in a breadcrumb message
- ✓redacts a Telegram bot token in exception.values[].value
- ✓handles an exception value of undefined without throwing and redacts the token entry
- ✓redacts a Telegram bot token in the top-level event.message
- ✓redacts a Telegram bot token in event.request.url
- ✓redacts both the token in exception value and a wholesale signal elsewhere, never returning null
✓checkout funnel eventsBusiness rules9
- ✓trackViewCart emits view_cart with computed value + items array of objects
- ✓trackViewCart no-ops on empty cart
- ✓trackBeginCheckout emits begin_checkout with funnel value
- ✓trackAddShippingInfo includes shipping_tier
- ✓trackAddPaymentInfo defaults payment_type to stripe_checkout
- ✓trackPurchase emits purchase with transaction_id, tax, shipping
- ✓trackPurchase is idempotent per transactionId via sessionStorage
- ✓trackPurchase no-ops without transactionId
- ✓trackPurchase still emits when sessionStorage throws (private mode)
✓<ConditionalFooter> route gateShared building blocks9
- ✓renders the footer on /
- ✓renders the footer on /parts
- ✓renders the footer on /parts/brand/new-holland-agriculture
- ✓hides the footer on /account
- ✓hides the footer on /account/garage
- ✓hides the footer on /sign-in
- ✓hides the footer on /sign-up
- ✓hides the footer on /forgot-password
- ✓hides the footer on /reset-password
✓addresses actionsBusiness rules9
- ✓listAddresses returns the empty list for a fresh user
- ✓listAddresses refuses unauthenticated calls
- ✓upsertAddress generates an id when none is supplied
- ✓upsertAddress preserves a supplied id
- ✓setDefaultAddress promotes the target address
- ✓deleteAddress removes the target
- ✓migrateAddressesFromLocal writes when server copy is empty
- ✓migrateAddressesFromLocal keeps server copy when both are populated
- ✓migrateAddressesFromLocal no-ops on empty local + empty server
✓instrumentation.ts — FE_OTEL_ENABLED gate (#1162)Shared building blocks8
- ✓flag unset (default): does NOT register @vercel/otel
- ✓flag unset: Sentry keeps owning OTel (skipOpenTelemetrySetup=false)
- ✓flag "false": treated as OFF — no @vercel/otel, Sentry owns OTel (coerce-boolean guard)
- ✓flag "TRUE" / "1": treated as OFF (strict === "true" only)
- ✓flag "true": registers @vercel/otel as crop-front and propagates to search-api only
- ✓flag "true": Sentry yields OTel setup (skipOpenTelemetrySetup=true)
- ✓flag ON: registers OTel on the edge runtime too
- ✓does NOT hardcode any exporter URL or auth token in source
✓useCameraScanInterface behaviour8
- ✓starts in idle state
- ✓flips isScanning when start() is called and a reader is attached
- ✓records lastDecoded when the decoder produces a result
- ✓ignores NotFoundException frames as part of normal scanning
- ✓captures permission_denied when getUserMedia is blocked
- ✓reports not_supported when mediaDevices.getUserMedia is absent
- ✓stops resets the decoder
- ✓reset clears lastDecoded so repeat scans can fire
✓markShippedActionServer actions8
- ✓returns validation failure for empty input
- ✓returns unauthenticated when no Clerk session
- ✓returns unauthorized when the caller is a customer
- ✓PATCHes the staff status endpoint with shipped + revalidates the detail path
- ✓forwards an optional tracking number in the body
- ✓returns backend_error when the payment service responds non-ok
- ✓surfaces the backend's own error message
- ✓falls back to the status code when the body carries no message
✓submitRefundRequestActionServer actions8
- ✓returns validation failure when amount is missing
- ✓returns unauthenticated when there is no Clerk session
- ✓returns unauthorized when the caller is a customer
- ✓returns order_not_found when the staff endpoint can't see the order
- ✓persists the request and emails the admin queue on the happy path
- ✓treats a duplicate submit as alreadyPending without re-emailing
- ✓swallows a Resend failure as non-fatal and still returns success
- ✓captures a Resend RETURNED error to Sentry but stays non-fatal (#1091)
✓addresses-repoReference data8
- ✓listUserAddresses returns [] when nothing stored
- ✓replaceUserAddresses writes then reads back the whole list (jsonb round-trip)
- ✓upsertUserAddress inserts a new row and persists it
- ✓upsertUserAddress replaces an existing row by id
- ✓setting isDefault on upsert clears default on other rows
- ✓deleteUserAddress removes the row and promotes a new default
- ✓deleteUserAddress on the only address leaves an empty list
- ✓setDefaultUserAddress flips the default to the requested id
✓getBusinessHoursStatusBusiness rules8
- ✓is closed before 7:30 AM on a weekday and reports today opening
- ✓is open at 10:00 AM on a weekday with closing time
- ✓is closed after 5:00 PM on a weekday and rolls to next day
- ✓Saturday morning is open with 12:00 PM close
- ✓Saturday afternoon is closed and rolls to Monday
- ✓Sunday is closed all day and rolls to Monday
- ✓exactly at open transition (7:30 AM Mon) flips to open
- ✓exactly at close transition (5:00 PM Mon) flips to closed
✓resend-adapterBusiness rules8
- ✓throws EmailAdapterNotConfiguredError when RESEND_API_KEY is empty
- ✓throws EmailSendFailedError preserving the upstream Resend error
- ✓returns the Resend id on a clean send
- ✓rejects a payload missing both html and text
- ✓forwards a text-only body without an html field
- ✓forwards bcc array to Resend SDK when set
- ✓omits bcc field entirely when not provided or empty
- ✓throws EmailSendFailedError when Resend returns { data: null, error: null }
✓assertNoWholesaleLeakBusiness rules8
- ✓returns silently on a clean retail payload
- ✓throws on dealer price key
- ✓throws on wholesale_price (snake_case)
- ✓throws on netPrice key
- ✓throws on nh_discount field
- ✓throws on nested net shape { net: { value: ... } } (CT-674 / front#148)
- ✓preserves benign 'dealer.name' / 'dealer_name' (public-contact field)
- ✓includes the matched substring on the thrown error
✓parseAddress — non-US blockingShared helpers8
- ✓rejects Canadian addresses with explicit error
- ✓rejects addresses containing a non-US country tag
- ✓accepts the New Mexico address 123 Main St, Springfield, New Mexico 12345
- ✓accepts the New Mexico address 123 Main St, Springfield, new mexico 12345
- ✓accepts the New Mexico address 123 Main St, Apt 4, Springfield, New Mexico 12345
- ✓accepts the New Mexico address 123 Main St, Albuquerque, NM 87101
- ✓accepts a US street named after a country
- ✓still rejects a genuine Mexican address
✓looksLikeFullAddressShared helpers8
- ✓returns true for a typical pasted full address
- ✓returns true when state is spelled out (Google Maps copy)
- ✓returns false for a bare street line (no ZIP)
- ✓returns false for input below the length threshold
- ✓returns false when ZIP is present but no state
- ✓accepts ZIP+4 format
- ✓returns false for an empty or whitespace-only string
- ✓trims surrounding whitespace before checking
✓isSafeImageUrlShared helpers8
- ✓allows https URLs
- ✓allows http URLs
- ✓allows data:image URLs
- ✓allows relative URLs
- ✓rejects javascript: URLs
- ✓rejects data:text/html URLs (XSS vector)
- ✓rejects empty string
- ✓rejects bare filenames
✓<StoreBrowseByType> (#2207 — store browse-by-type switcher)Parts pages8
- ✓renders one link per equipment type when a CNH brand has several
- ✓forwards the rail top-margin override (default mt-6; brand catalog passes mt-3)
- ✓renders nothing when the brand has fewer than two types (nothing to switch)
- ✓fails soft to nothing when the taxonomy fetch throws (never blocks the grid)
- ✓Landoll renders live category tiles linking the canonical type hub, not a bare-catalog bounce
- ✓NH Construction sub-category tiles link the Part path, never a /parts-diagrams bounce
- ✓CNH (search-MV) brand links the canonical PATH, never the ?equipmentType= query form
- ✓brand-catalog (adapter, non-MV) vendor links the canonical type hub by name-slug, never the empty ?manufacturer= listing
✓usePrintLabelInterface behaviour7
- ✓opens a cross-origin label in a tab — it can be shown but never fetched
- ✓reports a blocked popup as an error rather than failing silently
- ✓names the order in its toasts only when given one
- ✓prints a same-origin label through an off-screen frame, then revokes the blob
- ✓falls back to a tab when the fetch fails, and clears the printing state
- ✓aborts an in-flight print on unmount instead of leaking the frame
- ✓stays silent when a print is abandoned — an abort is our own doing
✓fetchFavoritedProducts — a discontinued part and an unreachable one are different answersServer actions7
- ✓returns the parts it could resolve
- ✓treats a 404 as a genuinely discontinued part and keeps succeeding
- ✓reports a failure when the search backend answers 500
- ✓reports a failure when the request never reaches the backend
- ✓one unreachable part poisons the answer even when its siblings resolved
- ✓a 404 alongside a reachable part is still a success
- ✓an empty saved list is a success with nothing in it, not a failure
✓buildPrefilledMessageSite pages7
- ✓returns an empty string when no known params are present
- ✓prefills subject + part number + brand when the DEAD-part CTA sent them
- ✓skips lines for missing fields
- ✓trims whitespace around values
- ✓prefills freight-quote context with items + zip + reason (heavy)
- ✓prefills freight-quote context with the below-threshold reason label
- ✓freight-quote without items still produces a usable preamble
✓/value-your-trade (#3871)Site pages7
- ✓renders exactly one h1 in the server shell
- ✓server-renders the dealer facts a visitor came for
- ✓points its CTA at the contact page with a prefill subject
- ✓carries no form and no off-site dealer links
- ✓links whole-goods inventory at /equipment, not the parts catalog (#3871)
- ✓keeps the title inside the 60-character SERP budget
- ✓makes no claim the harvested www source never made (#3871)
✓<Footer> — mobile-redesign 3-column structure (sprint 4)Shared building blocks7
- ✓renders the four nav columns (#3871 added Dealership)
- ✓Dealership column keeps store help and dealership pages apart (#3871)
- ✓Shop by Brand column points to /brands and drops the OEM placeholder note
- ✓Shop by Brand column links the model index (All models → /parts-diagrams/models) sitewide (#1211)
- ✓Visit Us column carries address, phone and 5 social tiles
- ✓WCAG 2.5.5 — all footer links carry a py-* class for >= 24px tap target (#527)
- ✓renders the bottom bar with the SINCE 1953 pill, copyright and legal links
✓<CountBadge>Shared building blocks7
- ✓renders nothing at zero or below
- ✓renders the raw count within range
- ✓shows exactly max at the boundary (no plus)
- ✓clamps a favorites count above 99 to '99+'
- ✓clamps a cart count above CART_BADGE_MAX to the max-plus label
- ✓applies the tone colour and stays decorative (aria-hidden)
- ✓maps the destructive tone to bg-destructive
✓favorites-repoReference data7
- ✓getUserFavorites returns [] when nothing stored
- ✓replaceUserFavorites writes then reads back the whole list (jsonb round-trip)
- ✓replaceUserFavorites preserves prior stock state across a client re-sync
- ✓recordFavoriteStockState stamps only the matching item
- ✓recordFavoriteStockState is a no-op when the item is absent
- ✓recordFavoriteStockState does not create a row for an unknown user
- ✓listAllFavoritesDocuments returns every user's items
✓getDualBuyBoxLayout — pack PN, clintonOnHand variantsBusiness rules7
- ✓clintonOnHand=0 → pack-only (no individual buy-box, can't fulfil from DIS)
- ✓clintonOnHand=3 → dual, individual cap = 3 (exact DIS count)
- ✓clintonOnHand=12.7 → dual, individual cap floors to 12 (whole units only)
- ✓clintonOnHand=undefined (no stock signal) → pack-only (no interim 99)
- ✓clintonOnHand=null (PG NULL explicit) → pack-only (no interim 99)
- ✓missing stock signal never produces individualCap (no 99 fallback)
- ✓DEFAULT_HIDE_INDIVIDUAL_WHEN_SIGNAL_MISSING defaults to true (overselling guard)
✓resolveStepperCap — non-pack singles stepper bound (#2258)Business rules7
- ✓caps to the exact ceiling when it is below the fallback (no 99 oversell)
- ✓uses large real stock counts instead of the old fallback ceiling
- ✓floors a fractional count so the bound stays a whole orderable qty
- ✓falls back to the familiar cap when stock is unknown
- ✓treats a non-positive or non-finite count as no signal (fallback, never 0)
- ✓the fallback is the long-standing singles range (99)
- ✓caps a part we do not stock ourselves at its depot ceiling (#3216)
✓escapeHtmlShared helpers7
- ✓returns an empty string for null and undefined
- ✓coerces numbers to strings without escaping safe digits
- ✓leaves ordinary text untouched
- ✓escapes the five OWASP HTML-content sinks
- ✓blocks the classic <script> XSS payload
- ✓blocks the attribute-break + img onerror payload used in real exploits
- ✓does not double-escape characters that are already entities
✓isSafeLinkUrlShared helpers7
- ✓allows https URLs
- ✓allows http URLs
- ✓rejects javascript: URLs
- ✓rejects data: URLs
- ✓rejects invalid URLs
- ✓rejects empty string
- ✓rejects ftp: protocol
✓authedFetch CANCELLED handling — pin per callerBusiness rules7
- ✓fetchUserOrders absorbs CANCELLED without logging
- ✓fetchOrderById absorbs CANCELLED without logging
- ✓fetchAdminUsers absorbs CANCELLED without logging
- ✓fetchAuditLog absorbs CANCELLED without logging
- ✓fetchStaffOrders absorbs CANCELLED without logging
- ✓fetchStaffOrderDetail absorbs CANCELLED without logging
- ✓fetchStaffInventory absorbs CANCELLED without logging
✓globals.css view-transition contractSite pages6
- ✓silences the root layer (plain navs stay instant)
- ✓animates only the view-switch typed transition
- ✓freezes the shared brand top and holds the browse rail
- ✓pins the sticky header only during a view-switch
- ✓holds document height and excludes product image morphs during the view switch
- ✓disables product-image morphs under reduced motion with the UNSPACED selector React actually serializes
✓/credit-app (#3871)Site pages6
- ✓renders exactly one h1 in the server shell
- ✓server-renders the dealer facts a visitor came for
- ✓links out to the finance partners with noopener, not a credit form
- ✓carries no Sandhills or off-site dealer links
- ✓makes no financing claim the dealer site does not make (#3871)
- ✓keeps the title inside the 60-character SERP budget
✓/employment (#3871)Site pages6
- ✓renders exactly one h1 in the server shell
- ✓server-renders the dealer facts a visitor came for
- ✓points its CTA at the contact page with a prefill subject
- ✓carries no form and no off-site dealer links
- ✓keeps the title inside the 60-character SERP budget
- ✓makes no claim the harvested www source never made (#3871)
✓/email-insider (#3871)Site pages6
- ✓renders exactly one h1 in the server shell
- ✓server-renders the dealer facts a visitor came for
- ✓makes no specific dollar-amount promise (#3871 scope decision)
- ✓points its CTA at the contact page with a prefill subject
- ✓carries no form and no off-site dealer links
- ✓keeps the title inside the 60-character SERP budget
✓PartsCatalogPage — pagination guards (front#936)Parts pages6
- ✓404s on ?page=-1 as a defensive backstop to the edge proxy guard
- ✓404s on ?page=-99 as a defensive backstop to the edge proxy guard
- ✓404s on ?page=0 as a defensive backstop to the edge proxy guard
- ✓404s when ?page exceeds pagination.totalPages reported by hono
- ✓404s on a zeroed {total:0,totalPages:0} response at page 9 (dead-guard regression)
- ✓does NOT 404 on page 1 of a genuinely empty result set
✓/schedule-demo (#3871)Site pages6
- ✓renders exactly one h1 in the server shell
- ✓server-renders the dealer facts a visitor came for
- ✓points its CTA at the contact page with a prefill subject
- ✓carries no form and no off-site dealer links
- ✓keeps the title inside the 60-character SERP budget
- ✓makes no claim the harvested www source never made (#3871)
✓/schedule-service (#3871)Site pages6
- ✓renders exactly one h1 in the server shell
- ✓server-renders the dealer facts a visitor came for
- ✓points its CTA at the contact page with a prefill subject
- ✓carries no form and no off-site dealer links
- ✓keeps the title inside the 60-character SERP budget
- ✓makes no claim the harvested www source never made (#3871)
✓/service (#3871)Site pages6
- ✓renders exactly one h1 in the server shell
- ✓server-renders the dealer facts a visitor came for
- ✓points its CTA at the contact page with a prefill subject
- ✓carries no form and no off-site dealer links
- ✓keeps the title inside the 60-character SERP budget
- ✓makes no claim the harvested www source never made (#3871)
✓createEmailDispatcherBusiness rules6
- ✓forwards the payload to the adapter untouched
- ✓swallows an unconfigured adapter without reporting it — dev has no key
- ✓reports a Resend rejection with the flow's own message and tags
- ✓reports an unexpected failure as-is, keeping the original error
- ✓never throws back into the action — the record is already persisted
- ✓keeps each flow's own identity
✓emailLocalGuessBusiness rules6
- ✓capitalises the first token of the local part
- ✓splits on common separators
- ✓lowercases the tail of the first token
- ✓returns undefined for empty / missing input
- ✓returns undefined when the local-part is missing
- ✓returns undefined when the @ is missing
✓verifyReviewTokenBusiness rules6
- ✓round-trips a freshly signed token
- ✓emits the body.sig shape with two base64url segments
- ✓rejects a tampered body
- ✓rejects a wrong secret
- ✓rejects an expired token but accepts up to the expiry second
- ✓rejects malformed tokens
✓formatCategoryNameShared helpers6
- ✓converts ALL_CAPS to title case
- ✓handles multi-word names with &
- ✓handles already title-cased input
- ✓handles lowercase input
- ✓handles single character
- ✓handles empty string
✓pickCardTitleShared helpers6
- ✓prefers short longTitle
- ✓falls through to title when longTitle exceeds the length ceiling
- ✓falls through to partNumber when both title fields exceed the ceiling
- ✓ignores empty/whitespace strings
- ✓returns empty string when nothing is usable
- ✓treats null fields like missing
✓pooledShared helpers6
- ✓returns empty array for empty tasks
- ✓runs all tasks and preserves order
- ✓respects concurrency limit
- ✓handles limit larger than task count
- ✓handles limit of 1 (sequential)
- ✓propagates errors
✓Resend call-shape pin (cross-cut, #1234)Business rules6
- ✓contact.ts — first send envelope (staff)
- ✓part-request.ts — first send envelope (staff)
- ✓refund-request.ts — first send envelope (admin)
- ✓return-request.ts — first send envelope (staff)
- ✓order-confirmation.ts — first send envelope (customer)
- ✓send-shipped.ts — first send envelope (customer)
✓root <Template> — static Instant Navigation shellSite pages5
- ✓returns route content without a global View Transition
- ✓contains no root URL read or global ViewTransition
- ✓app/parts/template.tsx keeps intentional motion scoped to ViewSwitchBoundary
- ✓app/parts-diagrams/template.tsx keeps intentional motion scoped to ViewSwitchBoundary
- ✓app/brand/template.tsx keeps intentional motion scoped to ViewSwitchBoundary
✓renderWithProviders — pin contract (#1914)Shared building blocks5
- ✓mounts a simple component into a queryable DOM
- ✓returns a queryClient that is the same instance the tree consumes
- ✓exposes a push spy through routerOverrides + returns it via pushMock
- ✓propagates dehydratedState so a prefilled query is hot on first render
- ✓setClerkMock({ role: staff }) makes auth.has() grant org:staff permissions
✓ContactTileHome page5
- ✓renders the label, value and sub inside a single link
- ✓leaves a same-tab link without target or rel — tel: and mailto: must not open a tab
- ✓opens an external link in a new tab with noopener noreferrer
- ✓hides the decorative icon chip from assistive tech
- ✓tints the chip only for the primary tile
✓/map-hours (#3871)Site pages5
- ✓renders exactly one h1 in the server shell
- ✓server-renders the dealer facts a visitor came for
- ✓links out to Google Maps for directions
- ✓carries no form and no off-site dealer links
- ✓keeps the title inside the 60-character SERP budget
✓/testimonials (#3871)Site pages5
- ✓renders exactly one h1 in the server shell
- ✓server-renders the dealer facts a visitor came for
- ✓drops the placeholder-attributed quote rather than publish it (#3871)
- ✓carries no form and no off-site dealer links
- ✓keeps the title inside the 60-character SERP budget
✓batchIdentityKey — collision fenceBusiness rules5
- ✓gives a colliding PN distinct keys per source schema (21.0081: public vs ventrac)
- ✓collapses every CNH-family form of one PN to a single key (no-regression)
- ✓upper-cases the PN and peels a periphery -PK alias to the same key
- ✓keys a lowercase URL slug to the same row as its uppercase SKU
- ✓returns null when there is no part number
✓CONTINENTAL_US_STATESBusiness rules5
- ✓excludes AK
- ✓excludes HI
- ✓includes NY, CA, TX, FL, DC
- ✓has exactly US_STATES.length minus NON_CONTINENTAL_STATE_CODES.length entries
- ✓preserves alphabetical ordering of source US_STATES
✓sendShippedEmailBusiness rules5
- ✓calls Resend with the shipped HTML body
- ✓skips silently when RESEND_API_KEY is not configured
- ✓captures to Sentry when Resend RETURNS an error, without throwing (#1091)
- ✓uses support@ as the replyTo and omits bcc when env empty (#1259)
- ✓sends from the Clinton Tractor Support display name on support@send (#1280)
✓resolvePackAliasOfferBusiness rules5
- ✓returns the hono payload verbatim when it is marked available
- ✓synthesizes the offer from packQty + unit price when hono has not shipped one
- ✓returns null for non-pack parts (packQty absent or 1)
- ✓returns null when the pack cannot be priced or identified
- ✓ignores an unavailable hono payload and falls through to synthesis
✓isSafeCheckoutUrlShared helpers5
- ✓allows https URLs
- ✓rejects http URLs (payment requires https)
- ✓rejects javascript: URLs
- ✓rejects invalid URLs
- ✓rejects empty string
✓always-stocked rotation state (#2314)Home page5
- ✓seeds the first visibleCount pool indices into the visible slots
- ✓clamps visible to the pool size when the pool is smaller
- ✓swaps one slot per tick, cycling the spare pool entries in order
- ✓never shows the same pool index in two slots at once
- ✓is a no-op when the pool has no spare parts to cycle in
✓PinnedHeroVideo — SSR + first paintHome page5
- ✓emits NO <video> element in the SSR HTML (no preload, no autoplay byte path)
- ✓does NOT mount <video> on mobile viewport
- ✓does NOT mount <video> with prefers-reduced-motion
- ✓does NOT mount <video> when navigator.connection.saveData is true
- ✓mounts <video> on desktop with no save-data / reduced preferences
✓lib/sentry wrapper — SDK delegation pins (#1243)Business rules5
- ✓captureException passes error + capture context through unchanged (PDP shape)
- ✓captureException works without context (single-arg shape)
- ✓captureMessage passes message + level/context through unchanged
- ✓addBreadcrumb passes the breadcrumb through unchanged (no_cnh_data shape)
- ✓namespace import shape exposes the same three functions
✓app/layout viewport exportSite pages4
- ✓does not set maximumScale (WCAG SC 1.4.4 / F67 — pinch-zoom must not be capped)
- ✓does not set userScalable to false (would also fail WCAG SC 1.4.4)
- ✓keeps device-width + initialScale 1 (responsive baseline)
- ✓keeps viewportFit "cover" so safe-area insets resolve on notched devices
✓CookieConsentBanner — mobile slim mode (CROP-front#922)Interface pieces4
- ✓renders 44×44 tap targets for both consent buttons on mobile
- ✓auto-dismisses to 'necessary' on first scroll on mobile
- ✓auto-dismisses to 'necessary' after 12s dwell on mobile
- ✓does NOT auto-dismiss on desktop (>=768px); explicit tap still required
✓Customer templates render the canonical logo at the top (#1280)Shared building blocks4
- ✓order-confirmation contains an <img> with the canonical logo src
- ✓order-shipped contains an <img> with the canonical logo src
- ✓backorder-update contains an <img> with the canonical logo src
- ✓refund-issued contains an <img> with the canonical logo src
✓RefundIssuedEmailShared building blocks4
- ✓renders a snapshot of the refund-issued email
- ✓formats the refund amount in the headline
- ✓includes the breakdown and the staff note when provided
- ✓omits the breakdown block when not provided
✓parseVinInterface behaviour4
- ✓returns null for empty or short input
- ✓matches a 17-character VIN inside a longer string
- ✓rejects strings containing I/O/Q which are not valid in real VINs
- ✓normalises whitespace before matching
✓useRailOverflowInterface behaviour4
- ✓reports no overflow for content that fits
- ✓flags overflow and start/end edges from scrollWidth vs clientWidth
- ✓re-measures on ResizeObserver callback and on scroll
- ✓invokes onMeasure with the element after every measurement, without re-subscribing on re-render
✓trackAddToCartBusiness rules4
- ✓emits GA4 add_to_cart with pack dimensions for pack-buy items
- ✓drops pack_qty from GA4 payload for singles, keeps is_pack_buy=false
- ✓rounds value to 2 decimals to avoid float noise
- ✓falls back to productId when partNumber absent (GA4 still gets an item_id)
✓submitContactFormAction (useActionState adapter)Server actions4
- ✓returns success when the underlying submitContactForm resolves to {success:true}
- ✓returns error state on validation failure (empty required fields)
- ✓returns error state on invalid email
- ✓forwards FormData fields to Resend (success path)
✓submitPartRequestActionServer actions4
- ✓creates a part_request AND a quote (dual write) for signed-in users
- ✓returns success even when the quotes dual-write throws
- ✓skips the quotes dual-write for anonymous visitors
- ✓captures a Resend RETURNED error to Sentry but stays success (#1091)
✓/faq shipping sectionSite pages4
- ✓keeps the shipping deep-link anchor emails point at
- ✓single-sources the free-shipping threshold from the eligibility constant
- ✓states the free-means-slower trade-off where the threshold is explained
- ✓answers the speed question plainly: cheapest service, overnight costs extra
✓fetchPartCoreParts pages4
- ✓returns the part when getCachedPartById succeeds
- ✓falls back to slug lookup when id lookup returns null
- ✓recovers via trailing-PN extraction when slug misses on SEO URL (CT-674 T21)
- ✓returns null when id, slug, and PN-recovery all miss — no fuzzy fallback
✓PartsCatalogPage — a transient failure is a 503 body, not the error boundaryParts pages4
- ✓renders ServiceUnavailable when the search fetch outruns the page budget
- ✓renders ServiceUnavailable for a 503 from the backend
- ✓still throws a non-search error so a real bug reaches the error boundary
- ✓keeps a deterministic 4xx on the inline (cacheable) path — #1284 unchanged
✓DeferredMountInterface pieces4
- ✓renders only a height-reserving placeholder before intersection
- ✓mounts children and clears data-deferred once the cell intersects
- ✓disconnects the observer after the one-shot mount
- ✓mounts children eagerly when IntersectionObserver is undefined
✓DeferredTableRowInterface pieces4
- ✓renders a placeholder <tr> with colSpan + reserved height before intersection
- ✓mounts the real <tr> and removes the placeholder once the cell intersects
- ✓disconnects the observer after the one-shot mount
- ✓mounts children eagerly when IntersectionObserver is undefined
✓<Header>Shared building blocks4
- ✓renders the mobile cart icon as a plain anchor (full nav, not soft nav)
- ✓has exactly one drawer opener, and it is the disclosure's summary
- ✓renders the brand + primary nav links directly, not behind an interaction
- ✓ships every nav disclosure closed
✓MobileCallButton — CROP-front#918Shared building blocks4
- ✓renders a tel: link to Clinton Tractor's main line
- ✓is hidden on >= md viewports via md:hidden so it stays phone-only
- ✓clears the shared <MobileBottomBar> on every route (bottom-[140px] vs ~99px bar height)
- ✓exposes a discoverable aria-label so screen readers announce the action
✓purchase-cta-labels (#1877)Business rules4
- ✓defines the canonical add-to-cart label
- ✓defines the canonical express-buy label
- ✓formats qty tooltips consistently
- ✓formats aria labels consistently
✓clampToServeablePages (#2766)Business rules4
- ✓clamps a nominal count past the cap to the serveable window
- ✓passes a count already inside the window through unchanged
- ✓collapses zero / negative / non-finite to 0 (the no-pagination signal)
- ✓truncates a fractional page count
✓refund-requests-repoReference data4
- ✓findPendingRefundRequest returns null when nothing pending
- ✓createRefundRequest returns an id and findPending then hits it
- ✓findPendingRefundRequest ignores already-decided rows for the same order
- ✓passes every column in the order the INSERT declares
✓isIntentRoutingEnabledBusiness rules4
- ✓returns true when the env var is unset (default on)
- ✓returns true when the env var is 'true'
- ✓returns false only for the literal string 'false'
- ✓treats arbitrary strings as enabled (fail-open)
✓useAtmosphericVideo (#1477)Business rules4
- ✓shows on desktop with motion allowed and no Save-Data
- ✓stays off on mobile viewports
- ✓stays off when prefers-reduced-motion is set
- ✓stays off on Save-Data connections
✓buildBfcacheReport — back/forward navigationsBusiness rules4
- ✓reports restored=true when notRestoredReasons is empty
- ✓reports restored=false with reasons[] when notRestoredReasons is populated
- ✓preserves WebLocks as a distinct reason (Clerk follow-up signal)
- ✓flattens multiple reasons in order
✓getDualBuyBoxLayout — pack/no-pack branchBusiness rules4
- ✓returns 'single' for packQty undefined (non-pack PN)
- ✓returns 'single' for packQty=1 (CNH stocked as singles)
- ✓returns 'single' for packQty=0 or negative (defensive)
- ✓returns 'single' for packQty=null (PG NULL passed through)
✓computePackPrice — synthesised pack price for fallback pathBusiness rules4
- ✓48054133 (knife blade): $5.22 × 25 = $130.50
- ✓rounds to cents (Stripe rejects fractional cents)
- ✓returns 0 for invalid unitPrice
- ✓falls back to unitPrice when packQty invalid
✓parseAddress — high-confidence comma pathShared helpers4
- ✓parses 'Street, City, ST ZIP' format
- ✓parses ZIP+4 in comma format
- ✓normalises full state name to 2-letter abbreviation
- ✓extracts apartment unit from street into separate field
✓decodeRouteParamShared helpers4
- ✓decodes a still-encoded segment
- ✓is idempotent — an already-decoded segment is unchanged
- ✓keeps the raw value for a part number carrying a literal %
- ✓survives a malformed escape without throwing
✓escapeRegExpShared helpers4
- ✓makes every metacharacter match itself
- ✓stops a metacharacter from matching something it should not
- ✓leaves an already-safe string untouched
- ✓escapes a hyphen-bearing model code as a literal
✓<WhatWeStock> — all carried brands gridHome page4
- ✓renders the heading and the All brands link to /brands
- ✓renders one catalog-hub link per carried brand (auto-grow invariant)
- ✓renders New Holland as ONE combined card with the division line
- ✓renders no per-brand parts counts (owner's no-counters rule)
✓<HowItWorks> — platform guide video (#2214)Home page4
- ✓renders the guide heading and a facade play control — no iframe until click
- ✓mounts the YouTube embed inline (playsinline) only after the user clicks play
- ✓sizes the 1280x720 facade thumbnail to its half-width slot, still eager
- ✓emits VideoObject structured data for the walkthrough (SEO, #2308)
✓Shop by category — tile-query allowlist (#841)Home page4
- ✓has exactly 12 tiles (design contract)
- ✓every tile query is on the verified-non-empty allowlist
- ✓every allowlist entry is used by at least one tile (no dead entries)
- ✓never re-introduces the three known-dead multi-word queries from #841
✓interleaveByBrand — multi-brand pool selection (#2314)Parts pages4
- ✓round-robins across brands so the pool leads brand-diverse
- ✓dedupes by part number, keeping the first brand's occurrence
- ✓respects the pool limit
- ✓ignores empty brand groups
✓MostPopularBand view-transition-name dedup (CROP-front#1130)Parts pages4
- ✓passes enableViewTransition: false for the current PDP part (SKU match)
- ✓matches on the SKU derivation, not the search-doc slug/id (#2458 key change)
- ✓keeps enableViewTransition: true when currentPartSku is not in the band
- ✓keeps enableViewTransition: true when currentPartSku is absent
✓<PartsBrowseHubs> (front#169 — crawlable /parts hub)Parts pages4
- ✓renders the primary hub links so /parts is no longer a crawl dead-end
- ✓renders one crawlable type-hub link per New Holland equipment type
- ✓emits no crawlable link for a type that 308s off this brand (#2768)
- ✓fails soft to the static hubs when the taxonomy fetch throws (no crash)
✓happy-dom getComputedStyle shimShared building blocks3
- ✓reports an unset transform as 'none', the way a browser does
- ✓survives the exact expression vaul's getTranslate evaluates
- ✓keeps ordinary computed-style reads working through the proxy
✓EmailLayout — logo URL pin (#1280)Shared building blocks3
- ✓exports the canonical prod CDN URL as LOGO_SRC
- ✓renders the canonical logo src — no NEXT_PUBLIC_SITE_URL fall-through to crop-dev.app
- ✓renders the canonical logo even when NEXT_PUBLIC_SITE_URL is set to a different host
✓BackorderUpdateEmailShared building blocks3
- ✓renders a snapshot of the backorder-update email
- ✓renders both the new ETA and the previous ETA
- ✓switches the headline when the new ETA is earlier than the previous
✓parseModelCodeInterface behaviour3
- ✓returns null for empty input
- ✓strips whitespace and hyphens
- ✓caps at 64 chars to keep upstream lookup queries bounded
✓useDebouncedValueInterface behaviour3
- ✓returns the initial value immediately
- ✓updates after the delay elapses
- ✓resets the timer when the value changes rapidly
✓useDebouncedCallbackInterface behaviour3
- ✓invokes the callback after the delay
- ✓cancel prevents a pending invocation
- ✓flush runs the callback immediately when a timer is pending
✓useFavoritesSyncInterface behaviour3
- ✓merges local and server favorites keeping the earliest addedAt per key
- ✓clears favorites when the user signs out
- ✓syncs merged favorites back when local had items the server lacked
✓useHydratedInterface behaviour3
- ✓renders without errors
- ✓accepts different value types
- ✓returns a value
✓useIsMobileInterface behaviour3
- ✓starts false then reflects matchMedia after mount
- ✓updates when the viewport media query changes
- ✓queries the mobile breakpoint media string
✓scrollToSectionInterface behaviour3
- ✓does nothing when the target element does not exist
- ✓smooth-scrolls to the section offset by the sticky header
- ✓jumps instantly when prefers-reduced-motion is set
✓pending input accounting (#3705)Shared building blocks3
- ✓counts a call while it runs and stops counting when it settles
- ✓stops counting a call that throws
- ✓take() reports the leak once, then reads zero
✓scrubSecretsFromStringBusiness rules3
- ✓redacts a Telegram bot token in an API URL
- ✓redacts the token anywhere in a free-text string
- ✓leaves token-free strings untouched (no over-match on 'bot'/'robot')
✓cn — custom text-px font sizes vs tailwind-mergeShared helpers3
- ✓keeps a text-px size and a text color together (size, then color)
- ✓keeps a text-px size and a text color together (color, then size)
- ✓still collapses two competing text-px sizes to the last
✓submitContactForm — Resend returned-error observability (#1091)Server actions3
- ✓returns {success:false} and captures when the STAFF send resolves an error
- ✓stays {success:true} but captures when only the CUSTOMER confirmation errors
- ✓returns {success:true} and does NOT capture when both sends are clean
✓PartsError — retry backoff (front#1331)Parts pages3
- ✓does not call reset synchronously and disables the button while retrying
- ✓calls reset once after the backoff delay elapses
- ✓ignores rapid repeated taps while a retry is pending (no reset storm)
✓/track metadata robots gating (#1118)Site pages3
- ✓flag OFF → noindex,follow (thin stub kept out of the index)
- ✓flag ON → no page-level robots (page is indexable)
- ✓canonical stays /track regardless of the flag
✓CTAuthorizedBadgeInterface pieces3
- ✓renders the CT mark and dealer copy
- ✓hides the decorative children from the accessible tree
- ✓merges caller-provided className
✓<ServiceUnavailableBeacon>Product features3
- ✓captures a warning event with slug, reasonCode, upstreamErrorMessage
- ✓falls back to 'unknown' for absent props
- ✓renders nothing
✓nav icon tokens (#2208)Shared building blocks3
- ✓pins the two role sizes the nav icon set is allowed to use
- ✓keeps the two roles distinct so the hierarchy stays readable
- ✓exposes each token as a single Tailwind size-* utility (no compound classes)
✓ABOUT_COPYBusiness rules3
- ✓is within the 100–150-word SEO target
- ✓includes required factual anchors (founding year, city, phone, email)
- ✓does not mention unsupported brands
✓parseBccListBusiness rules3
- ✓returns undefined for missing / empty input so callers skip the bcc key
- ✓returns a single-entry array for one address
- ✓splits, trims, and drops empties for comma-separated lists
✓clientEnv NEXT_PUBLIC_FEATURE_GUEST_TRACKBusiness rules3
- ✓a literal "false" parses to false (not coerced true)
- ✓only "true" enables it
- ✓unset / empty / any other value is OFF
✓partAvailabilityToLabel — saved parts stock labelBusiness rules3
- ✓orderable tiers → 'In Stock'
- ✓out_of_stock → 'Out of Stock'
- ✓unknown / absent values → undefined (no badge)
✓authedFetch — auth scheme compositionBusiness rules3
- ✓emits Authorization: Bearer <token> for the bearer scheme
- ✓emits X-Admin-Token for the adminToken scheme
- ✓forwards method + body + cache + other RequestInit fields untouched
✓buildBfcacheReport — fresh navigationsBusiness rules3
- ✓returns null for type=navigate (only back/forward is interesting)
- ✓returns null for type=reload
- ✓returns null for type=prerender
✓toPublicImagePathShared helpers3
- ✓moves a media URL onto the /img prefix, query string intact
- ✓maps our GCS buckets through the media proxy's own prefixes
- ✓passes through anything the /img rewrite does not serve
✓toPublicImagePath — object keys survive verbatim (#3798)Shared helpers3
- ✓keeps everything after a '#' in the key
- ✓does not re-encode a raw space
- ✓keeps a query string
✓isVectorImage — which lane a mark takes (#3452)Shared helpers3
- ✓is true for a vector, whatever shape the source arrives in
- ✓is false for every raster the optimizer will actually resize
- ✓reads the path, so a query string cannot decide the lane
✓pickPdpHeadingShared helpers3
- ✓prefers shortTitle
- ✓falls through to partNumber rather than leaking body text
- ✓returns 'Untitled part' as last resort
✓<ShopByCategory> — Popular categories rail (sprint 5)Home page3
- ✓renders the section heading and 12 category tiles linking into the Parts Store
- ✓marks the ?q= tiles rel=nofollow but leaves the clean All link followable
- ✓surfaces the canonical part-system categories from the design
✓<AlwaysStockedParts> — Top sellersHome page3
- ✓renders the section with the brand-diverse pool when the feed resolves
- ✓renders nothing when the popular-parts feed is unavailable (failure-isolated)
- ✓fills the full visible row from a single-brand pool — no shrink, no ragged tail (#2296)
✓MostPopularBand JSON-LD (CROP-front#888)Parts pages3
- ✓emits the absolute branded canonical the band's cards link (#3193)
- ✓falls back to absolute raw /parts/{PN} when manufacturer.code is empty
- ✓drops a row with a missing partNumber (no placeholder entity)
✓<PartsVendorsStrip> — /parts Vendors stripParts pages3
- ✓renders the carried-brand strip with no active pill when no brand is selected
- ✓links each carried pill to its clean-path brand page (#2398 — uniform URL, no param)
- ✓rings the active vendor's pill (parity with the diagrams header)
✓app/layout.tsx Instant Navigation boundariesSite pages2
- ✓prerenders a height-stable shell around the pathname-aware cutoff banner
- ✓keeps the crawlable footer as the pathname-aware footer fallback
✓root layout pins the theme to light (#3874)Site pages2
- ✓ThemeProvider carries forcedTheme="light"
- ✓does not follow the OS preference
✓ChatwootWidget start-new-chat buttonInterface pieces2
- ✓is hidden until the widget opens and hides again on close
- ✓resets the conversation and reopens the widget on click
✓useIsHydratedInterface behaviour2
- ✓renders without errors
- ✓returns a boolean
✓isValidLabelUrlInterface behaviour2
- ✓accepts the three schemes a label can arrive as
- ✓rejects anything else, including the schemes that could execute
✓trackViewItemBusiness rules2
- ✓emits GA4 view_item with an items[] array (not flat) so the Items report attributes it
- ✓falls back partNumber -> sku -> productId for item_id
✓scrubWholesaleFields stays lean (no secret pass on the gateway hot path)Business rules2
- ✓does not run the Telegram-token redaction (leaves a token-shaped string as-is)
- ✓still strips wholesale + CNH signals (unchanged behavior)
✓sentryBeforeSendTransactionBusiness rules2
- ✓redacts the bot token from the request URL and every span URL/description
- ✓returns a transaction with no spans unchanged
✓wholesale-patterns alignmentBusiness rules2
- ✓every documented family has working samples covered by both patterns
- ✓patterns preserve legitimate public contact / company-name fields
✓RouteErrorHome page2
- ✓falls back to the generic description and reports without a hint
- ✓uses the supplied description and forwards captureTags as Sentry tags
✓<ContactPage> shell (#3015)Site pages2
- ✓renders exactly one h1 in the server shell
- ✓renders the direct-contact tiles server-side
✓GET /llms.txtSite pages2
- ✓serves a text/plain llms.txt when indexing is enabled
- ✓404s when indexing is disabled (mirrors the sitemap-index gate)
✓/parts-not-found generateMetadataParts pages2
- ✓post-flip (IS_INDEXING_ENABLED=true) emits NOINDEX_NOFOLLOW_ROBOTS with googleBot shape
- ✓pre-flip (IS_INDEXING_ENABLED=false) omits robots so layout's noindex,nofollow is inherited
✓prepareCatalogListingForAdapter — pagination guards (#3040)Parts pages2
- ✓404s at page 2 when the adapter zeroes the total
- ✓does NOT 404 at page 1 of an empty brand catalog
✓BusinessHoursLiveInterface pieces2
- ✓renders open status with a green StatusDot
- ✓re-renders on interval tick if status changes
✓#3040 pagination policy constantsBusiness rules2
- ✓serves 100 listing pages (the measured render window) and indexes the first 5
- ✓keeps the noindex depth inside the published window
✓part-requests-repoReference data2
- ✓createPartRequest returns an id (dispatch hits PG)
- ✓issues a fresh id per request
✓stock-alerts-repoReference data2
- ✓first active alert returns a new id
- ✓duplicate active alert returns the 'existing' sentinel
✓buildShippedEmailPropsBusiness rules2
- ✓maps an Order into the React Email props
- ✓returns null when the order has no tracking number yet
✓authedFetch — AUTH_TOKEN_MISSING shortcutBusiness rules2
- ✓returns AUTH_TOKEN_MISSING when bearer is empty string
- ✓returns AUTH_TOKEN_MISSING when adminToken is empty string
✓authedFetch — TIMEOUT branch (fake timers)Business rules2
- ✓aborts the internal controller after timeoutMs and reports TIMEOUT
- ✓respects a caller-supplied timeoutMs
✓authedFetch — success + parseBusiness rules2
- ✓returns ok=true with raw response and undefined data when parse is omitted
- ✓returns ok=true with parsed data when parse is provided
✓authedFetch — external signal compositionBusiness rules2
- ✓aborts the underlying fetch and returns CANCELLED when external signal fires
- ✓returns CANCELLED when the external signal is already aborted before fetch
✓buildBfcacheReport — Safari (notRestoredReasons unsupported)Business rules2
- ✓reports restored=unknown when notRestoredReasons is undefined (Safari)
- ✓reports restored=unknown when notRestoredReasons is null
✓buildBfcacheReport — cc-policy correlation tagBusiness rules2
- ✓carries the cc-policy meta value verbatim
- ✓reports ccPolicy=unknown when meta tag is missing
✓buildBfcacheReport — restore latencyBusiness rules2
- ✓computes responseStart - startTime for Safari restore-latency signal
- ✓flags revalidation round-trips with non-zero latency
✓buildPackAliasSku — front#919 contractBusiness rules2
- ✓appends -PK{N} to the branded SKU
- ✓works for any pack size
✓buildPackLineProductId — cart row collision guardBusiness rules2
- ✓composes productId + packAliasSku so the pack line is distinct from singles
- ✓two pack lines for different PNs hash to different ids
✓refund reasons contractBusiness rules2
- ✓REFUND_REASONS is a real array of the canonical reasons
- ✓REASON_LABEL has a label for every reason
✓RefundRequestSheet import source (front#1069)Business rules2
- ✓imports REFUND_REASONS/REASON_LABEL from the plain reasons module
- ✓does NOT import REFUND_REASONS or REASON_LABEL from the use-server action file
✓reviewEmailHashBusiness rules2
- ✓is stable and case/whitespace-insensitive
- ✓never leaks the raw address
✓parseAddress — fallback strategiesShared helpers2
- ✓parses without comma between street and city when state+ZIP is unambiguous
- ✓returns success=false on input that cannot be parsed
✓gcsUrlFromPublicPath — the inverse Satori needs (#3797)Shared helpers2
- ✓round-trips every mapped bucket
- ✓is null for a path that is not a mapped /img bucket
✓<HeroSearch> — search heroHome page2
- ✓renders the H1 and mounts the one shared search component
- ✓renders the centered Or row with Parts Store + Parts Diagrams CTAs (#848)
✓fetchMultiBrandPopular — pool fill with today's single-brand feed (#2314, #2296)Parts pages2
- ✓fills the pool past the visible row from ONE brand's deeper popular list
- ✓round-robin interleaves once 2+ brands return parts (multi-brand path intact)
✓<PartsHomeHero>Parts pages2
- ✓renders the identity band — h1, lede and subline
- ✓carries no CTA link (#2832 — the diagrams button is retired)
✓one <main> per document (#3358)Site pages1
- ✓is rendered by app/layout.tsx and nowhere else
✓CookieConsentBanner — click-swallow guard during slide-in (CROP-front#2604)Interface pieces1
- ✓ignores pointer events until the slide-in settles, then accepts them
✓a reported leak cannot corrupt the next count (#3705)Shared building blocks1
- ✓a call that settles after its leak was reported does not go negative
✓renderWithProviders wires the counter to the real user object (#3705)Shared building blocks1
- ✓an in-flight user.type() is visible to the global afterEach
✓trackRemoveFromCartBusiness rules1
- ✓emits GA4 remove_from_cart with pack dimensions mirroring add_to_cart
✓trackPackInvariantViolationBusiness rules1
- ✓emits GA4 pack_invariant_violation with item + pack_qty
✓scrubSecretsDeepBusiness rules1
- ✓redacts tokens nested in objects and arrays
✓AccountMenu voice patchesShared building blocks1
- ✓does not render the legacy 'My …' labels
✓AccountMenu is non-modal (no page scroll-lock)Shared building blocks1
- ✓does not lock body scroll while the menu is open
✓useSyncHeaderHeight (#1624)Shared building blocks1
- ✓publishes measured header height to :root and clears on unmount
✓MSW vitest serverShared building blocks1
- ✓fails unhandled fetch when onUnhandledRequest is error
✓sendShippedEmail — BCC injection (#1259)Business rules1
- ✓BCCs the configured alias when env is set
✓authedFetch — HTTP_ERROR branchBusiness rules1
- ✓returns HTTP_ERROR with the upstream status and a synthesized message
✓authedFetch — NETWORK_ERROR branchBusiness rules1
- ✓returns NETWORK_ERROR with the thrown message when fetch rejects
✓toPublicImageUrlShared helpers1
- ✓absolutizes only what it rewrote — feeds must never emit a relative <image:loc>
✓typeTileHref (#2316)Parts pages1
- ✓renders the crawlable brand/type hub for every type, regardless of model count
✓typeFilterHref (#2316)Parts pages1
- ✓targets the in-place /parts equipment-type filter
What we walk through in a real browser19 journeys
○Static support/legal pages — render + findability (OBJ-08)Browser journey9
- ○/faq renders a main landmark and its H1
- ○/privacy-policy renders a main landmark and its H1
- ○/terms-of-service renders a main landmark and its H1
- ○/return-policy renders a main landmark and its H1
- ○/shipping-delivery renders a main landmark and its H1
- ○/payment-methods renders a main landmark and its H1
- ○/contact renders a main landmark and its H1
- ○/about renders a main landmark and its H1
- ○the footer links every support/legal page (findable from any page)
○CT-674 — equipment card navigation from search resultsBrowser journey5
- ○clicking an equipment card on the parts search page navigates to /parts-diagrams/model/{slug}/parts-diagrams
- ○direct visit to legacy /equipment/FRD::5610 URL redirects to clean slug assemblies page
- ○URL-encoded legacy /equipment/FRD%3A%3A5610 also redirects
- ○model-number search surfaces the equipment section with a slug-URL heading link
- ○autocomplete equipment suggestion lands on the assemblies page
○/ — home What we stock (all carried brands)Browser journey5
- ○renders the heading and links every carried brand to its hub
- ○New Holland renders exactly one combined card
- ○the All brands link routes to the /brands directory
- ○clicking a non-NH brand card navigates to its catalog
- ○mobile (375px) — every carried brand card is reachable
○McHale launch customer journey (#2107 / J2-T2)Browser journey5
- ○home serves and offers product search
- ○McHale brand hub is findable and lists its equipment types
- ○McHale diagram surface renders a populated model grid
- ○McHale model drills into the schematic/hotspot diagram viewer
- ○real McHale part → real add-to-cart → /checkout/review → session-create fires
○NH Agriculture hub (#1507) @smokeBrowser journey5
- ○bare /parts/brand/new-holland-agriculture renders the hub directly — no 308 (ct-2047)
- ○legacy /parts/brand/new-holland 308s to the canonical agriculture hub
- ○retired /parts-diagrams/{slug} landing answers 410 Gone (#3345)
- ○AG diagrams landing does not surface construction as an in-place tile (#2903)
- ○/parts/brand/new-holland-agriculture renders the Part catalog in place — no 308 onward (ct-2047)
○New Holland launch customer journey (go-live gate)Browser journey5
- ○home serves and offers product search
- ○NH brand hub is findable and lists its equipment types
- ○NH diagram surface renders a populated model grid
- ○NH model drills into the schematic/hotspot diagram viewer
- ○NH part PDP -> add to cart -> checkout review with pay CTA enabled
○CT-674 front#159 — publish-status PDP matrixBrowser journey5
- ○sellable (86546609) renders PDP with Add-to-Cart
- ○no_cnh_data (0145155) is withdrawn, not rendered
- ○dont_list (9624450) renders PDP with pending banner, no CTA (front#833)
- ○truly missing PN (CT-NHL-99999999) returns 404, not a soft-200
- ○superseded_redirect (13557934) 308s and shows replaced-from banner
○CT-674 — no generic CNH placeholder images leak to the UIBrowser journey4
- ○catalog listing never renders cnhiparts.widen.net images
- ○page renders cleanly when CNH requests are blocked at the network
- ○Ford 7710 (older equipment) — assembly grid shows CT placeholder for no-schematic rows
- ○/parts — no legacy crosshair-SVG placeholder is rendered (CT-829)
○NH AG vs Construction — responsive (#1908) @smokeBrowser journey4
- ○mobile 375px — AG surface does not show construction as an in-place tile
- ○mobile 375px — construction hub shows CE equipment types
- ○desktop 1280px — AG surface does not show construction as an in-place tile
- ○desktop 1280px — construction hub shows CE equipment types
○HTML byte budgetBrowser journey4
- ○@perf home (/) stays under 230KB
- ○@perf brand-hub (/parts/brand/new-holland-agriculture) stays under 230KB
- ○@perf pdp (/parts/47622189) stays under 450KB
- ○@perf brand-diagrams (/parts/brand/new-holland-agriculture/diagrams) stays under 3900KB
○CT-1824 — per-brand placeholder systemBrowser journey3
- ○/parts — no surface renders the legacy part-placeholder.svg
- ○/parts — placeholder tiles carry a per-brand identity
- ○brand listing placeholders inherit the brand (ferris)
○CT-674 — chapter click → filtered assembly gridBrowser journey2
- ○clicking a sidebar chapter navigates to /parts-diagrams?chapter=X with visible cards
- ○the chevron toggle on a chapter row is keyboard-accessible and independent of the link
○Desktop dual buy-box flow (#1055 → #954)Browser journey2
- ○PDP renders individual panel + pack-alias card side-by-side
- ○QtyStepper surfaces 'Only N available' hint when typed > cap; clamps on commit
○Mobile dual buy-box flow (#1055 → #954)Browser journey2
- ○PDP renders sticky bar + pack-alias card; adding pack produces a distinct cart line
- ○PDP renders individual stepper + cap is enforced when typed above max
○NH Construction hub (#1507) @smokeBrowser journey2
- ○the retired /type/construction URL 308-redirects to the division hub (ct-2163)
- ○construction hub shows CE sub-categories only
○checkout — Pickup Today is shelf-only @smokeBrowser journey2
- ○offers Pickup Today for a Clinton-shelf part (dis-stock)
- ○re-dates pickup for a ship-in part (3-5 business days, not on shelf)
○Footer — WCAG 2.5.5 tap targets (#527) @smokeBrowser journey1
- ○all footer links and buttons meet >= 24px minimum tap target on 390x844
○NH AG diagrams `?series=` filters the grid (#2759) @smokeBrowser journey1
- ○a real series URL renders strictly fewer, different models than the full type
○NH federated brand-switcher navigation (#2159/#2250)Browser journey1
- ○driving a sibling pill jumps to another brand's diagrams surface
Automated checks1,086
Browser journeys42
Code exercised71.3%
What we check automatically181 groups
✓search-service adaptersSearch backend42
- ✓maps a search-service part into a unified catalog part
- ✓ranks a source:'ct' photo first and promotes it to primaryImage over the API primaryImage
- ✓keeps a CT photo as primary even when the part also has dealer angles
- ✓#2227 — drops CNH widen.net placeholders from images and primaryImage
- ✓#2213 — renders a lone diagram as the card image when no photo exists
- ✓#2212 — sorts an explicit per-part imageUrl first and makes it the primary
- ✓#2212 — drops a CNH widen.net imageUrl and keeps the normal ladder
- ✓#2227 — a non-CNH row with only a CNH placeholder leaks no CNH url
- ✓front#1601 — threads publishStatus through to UnifiedCatalogPart
- ✓front#1601 — threads top-level availability through to UnifiedCatalogPart
- ✓front#1601 — omits publishStatus / availability when the backend omits them
- ✓creates fallback config when manufacturer is unknown
- ✓strips dealer, wholesale, and net (dealer cost) tiers injected by the backend
- ✓drops the price field when only wholesale tiers (incl. net) are present
- ✓omits the price field when the backend returns no price object
- ✓omits the price field when the backend returns an empty price object
- ✓threads hasKit=true through to UnifiedCatalogPart
- ✓threads hasKit=false through to UnifiedCatalogPart
- ✓omits hasKit when the backend does not provide it
- ✓threads hasCtPhoto=true through to UnifiedCatalogPart
- ✓omits hasCtPhoto when the backend sends false
- ✓omits hasCtPhoto when the backend does not provide it
- ✓threads clintonOnHand positive int through to UnifiedCatalogPart
- ✓threads clintonOnHand=0 (DIS empty signal) through unchanged
- ✓preserves clintonOnHand=null (PG NULL = explicit no-signal)
- ✓omits clintonOnHand when the backend does not surface it (undefined)
- ✓threads secondary vendor/CNH depot stock fields through to UnifiedCatalogPart
- ✓forwards maxOrderQty, including a null 'checked, no ceiling' signal
- ✓never invents maxOrderQty from a shelf count the backend didn't sum
- ✓drops own-host part images that don't reference the part's partNumber
- ✓keeps own-host part images whose URL matches the partNumber
- ✓does NOT touch off-host images (CDN, video thumbnails, 360° frames)
- ✓handles parts with missing images
- ✓passes longTitle through when present
- ✓omits longTitle when not present
- ✓maps manufacturer facets into catalog summaries
- ✓synthesizes a summary for a selected brand absent from the facet list (by vendor code)
- ✓synthesizes a summary when the selection uses the slug form
- ✓does not duplicate a selected brand already present (case-insensitive)
- ✓synthesizes the virtual NHC summary absent from the facet list (#2750)
- ✓ignores selections with no known manufacturer config
- ✓returns the original list unchanged when nothing is selected
✓decideSearchIntentSearch box40
- ✓routes equipment suggestion with slug to assemblies URL
- ✓bubbles equipment suggestion with null slug to hint-based fallback (front#522)
- ✓routes a federated brand model (brandSlug+modelCode, no slug) to parts-diagrams (search#627)
- ✓derives brandSlug from brandCode when the payload omits it (search#642 — live vocab-path emitter)
- ✓uses the payload brandSlug for a numeric federated modelCode (Kuhn 10652, search#627)
- ✓bubbles equipment suggestion with empty-string slug to hint-based fallback (front#522)
- ✓bubbles whitespace-only equipment slug to hint-based fallback (front#522)
- ✓routes part_number suggestion with id to PDP
- ✓prefers slug over id in part_number payload
- ✓routes part_match payload to PDP via partNumber
- ✓routes assembly suggestion to /parts?q=assemblyCode
- ✓decides from the part at rank 3, not the assembly at rank 0
- ✓leaves rank 0 in charge when no row is an exact part match
- ✓ignores a partNumberMissing row — it has no PN to be identical to
- ✓routes hint=equipment to /parts-diagrams/model/{query} for middleware redirect
- ✓amendment: bare 3-digit number with hint=null routes to equipment
- ✓amendment: bare 4-digit number '5610' with cold LRU routes to equipment (John's video bug)
- ✓amendment: bare 5-digit number routes to equipment
- ✓amendment does NOT trigger for 6+ digit numbers (those are part numbers → /parts?q)
- ✓amendment does NOT trigger for mixed alphanumeric
- ✓routes hint=parts to /parts?q (results page, not straight to a PDP)
- ✓generic phrase without cache routes to /parts?q
- ✓single-word without cache or hint routes to /parts?q
- ✓hint=semantic (compound) falls through to generic
- ✓"5610" → /parts-diagrams/model/5610 with cold LRU
- ✓"7710" → /parts-diagrams/model/7710 with cold LRU
- ✓"oil filter" → /parts?q (generic)
- ✓"hydraulic" → /parts?q (generic)
- ✓"Ford" → /parts?q (generic)
- ✓"engine" → /parts?q (generic)
- ✓"87802831" (hint=parts, cold LRU) → /parts?q tagged part_pdp
- ✓"73344274" (hint=parts, cold LRU) → /parts?q tagged part_pdp
- ✓part_match whose partNumber differs from a partial query bubbles to fallback
- ✓part_number suggestion still jumps to PDP when the query matches modulo separators
- ✓matches the bare `text` even when part_match.partNumber is the branded SKU (CT-1233 pin)
- ✓a family query that pins no single model bubbles to results ('boomer' → 5 Boomers)
- ✓an exact model query still jumps, even amid siblings ('boomer 55' → BOOMER-55 diagrams)
- ✓a multi-brand dropdown never silently picks one brand ('8n' → Ford 8N + NH Boomer-8N)
- ✓a federated family query bubbles to results ('fusion' → 5 McHale models)
- ✓falls back to the single top suggestion when no list is supplied (exact still jumps)
✓autocomplete regression — effectiveMode resolutionSearch box37
- ✓"LS160" → auto or equipment (New Holland LS160 skid steer)
- ✓"LS170" → auto or equipment (New Holland LS170 skid steer)
- ✓"LS190" → auto or equipment (New Holland LS190 skid steer)
- ✓"C232" → auto or equipment (New Holland C232 CTL)
- ✓"C238" → auto or equipment (New Holland C238 CTL)
- ✓"L328" → auto or equipment (New Holland L328 skid steer)
- ✓"L230" → auto or equipment (New Holland L230 skid steer)
- ✓"W80C" → auto or equipment (New Holland W80C wheel loader)
- ✓"T7230" → auto or equipment (New Holland T7230 tractor)
- ✓"T6070" → auto or equipment (New Holland T6070 tractor)
- ✓"TM190" → auto or equipment (New Holland TM190 tractor)
- ✓"TS115" → auto or equipment (New Holland TS115 tractor)
- ✓"E9NN6600AA" → parts (Ford OEM hydraulic pump)
- ✓"C7NN10849A" → parts (Ford OEM alternator)
- ✓"D8NN11000CE" → parts (Ford OEM starter)
- ✓"ABC-123" → parts (aftermarket part with dash)
- ✓"LT550_v2" → parts (part with underscore)
- ✓"P-123.45" → parts (part with dash and dot)
- ✓"878016" → parts (6-digit part number)
- ✓"87801641" → parts (NH 8-digit part number)
- ✓"84343157" → parts (NH 8-digit part number)
- ✓"7710" → auto (Ford 7710 tractor)
- ✓"5610" → auto (Ford 5610 tractor)
- ✓"8340" → auto (Ford 8340 tractor)
- ✓"580" → auto (Case 580 backhoe)
- ✓"NH LS160" → equipment (NH prefix + skid steer)
- ✓"NH L170" → equipment (NH prefix + skid steer)
- ✓"New Holland T6070" → equipment (full brand + tractor)
- ✓"Ford 7710" → equipment (Ford + numeric model)
- ✓"Ford TW35" → equipment (Ford + TW series)
- ✓"Case IH MX110" → equipment (Case IH + tractor)
- ✓"CNH T7270" → equipment (CNH + tractor)
- ✓semantic queries with prepositions → semantic → auto
- ✓single generic words → auto
- ✓brand alone without model → auto
- ✓explicit parts mode is not overridden
- ✓explicit equipment mode is not overridden
✓brand-routes clientSearch backend27
- ✓fetches the model groups for a vendor code
- ✓fetches the assemblies for a vendor code + model
- ✓fetches the chapter index for a vendor code + model (front#1494)
- ✓rejects a chapters response that fails schema validation (front#1494)
- ✓encodes model codes with URL-unsafe characters (spaces)
- ✓fetches an assembly detail (schematic + callouts + BOM) for a vendor code
- ✓accepts a BOM row with a null qty
- ✓parses a Brillion row with a null description and schematicStatus
- ✓parses a Ventrac callout block with explicit null image dimensions
- ✓parses a McHale callout block with the dimension keys omitted
- ✓surfaces a 404 from the brand routes as SearchServiceApiError(404)
- ✓throws SearchServiceTimeoutError when the request aborts
- ✓rejects responses that fail schema validation
- ✓fetches the equipment-type categories for a vendor code
- ✓fetches the models in one equipment type (drill-down) and encodes the typeId
- ✓encodes a typeId that contains a space
- ✓accepts a legacy categoryId-keyed drill-down response
- ✓rejects an equipment-type-models response that fails schema validation
- ✓fetches the per-brand summary array
- ✓parses an empty summary as an empty array
- ✓preserves additive hono fields on summary rows (looseObject)
- ✓rejects a summary row with a stringified partsCount (schema gate)
- ✓surfaces a 503 from the summary endpoint as SearchServiceApiError
- ✓bare listing appends no filter params
- ✓forwards inStock as `inStock=true` (the value hono accepts)
- ✓forwards price bounds as SNAKE_CASE `price_min`/`price_max`
- ✓omits inStock when the opt is false (no `inStock=false` sent)
✓classifySerialInputProduct features25
- ✓classifies a full CNH PIN
- ✓trims surrounding whitespace on a packed PIN
- ✓normalises to uppercase
- ✓rejects 16-char input (too short for PIN)
- ✓rejects 18-char input (too long for PIN)
- ✓rejects PIN with forbidden I/O/Q characters (VIN rule)
- ✓classifies 'LB75 03104485' as compound
- ✓classifies dotted model 'T7.270 ZFLE05123' as compound
- ✓collapses multiple spaces between model and serial
- ✓rejects compound with too-short serial (< 6 chars)
- ✓rejects compound when model part is too long (> 8 chars)
- ✓rejects two-word generic phrases with an all-letter second word
- ✓classifies 6-digit bare serial
- ✓classifies 12-digit bare serial
- ✓rejects 5-digit (too short, likely model number)
- ✓classifies CNH alphanumeric prefix serial 'ZGED01107' (T6.145)
- ✓classifies CNH mixed-prefix serial 'W3J001578' (WM25s)
- ✓classifies CNH 3-letter-prefix serial 'NKM479279' (L228)
- ✓classifies CNH 3-letter-prefix serial 'YMN205946' (RB450)
- ✓rejects part number ending in letter 'D7NN9002B' (PN, not serial)
- ✓returns null for empty string
- ✓returns null for whitespace only
- ✓returns null for plain model code (no serial)
- ✓returns null for part number like '87052423'
- ✓returns null for free-text 'new holland tractor'
✓search-service clientSearch backend23
- ✓serializes search params and returns the response body
- ✓getPartsBatch rejects responses missing required consumer fields (#1918)
- ✓includes PIT pagination parameters in search request
- ✓throws SearchServiceApiError on non-OK responses
- ✓propagates abort errors as SearchServiceTimeoutError
- ✓sets upstream.timeout=hono Sentry tag when AbortError fires (#1256)
- ✓does NOT set upstream.timeout tag for non-timeout errors (#1256)
- ✓supports other endpoints
- ✓retrieves a single part by id or slug
- ✓adapts backend parts with missing fields
- ✓adapts part from getPartById
- ✓forwards cursor via opts, URL-encodes the `|` tuple separator, and returns pre-rendered urls
- ✓forwards offset+limit for hono#161 direct-shard fetch
- ✓forwards skipCount=true when set; omits when false/undefined
- ✓forwards skipCount=true when set; omits when false/undefined
- ✓hits the parts boundaries path and returns total + batchSize + boundaries
- ✓hits the assemblies boundaries path for kind=assemblies
- ✓appends withImageOnly=true for kind=parts when set
- ✓ignores withImageOnly for kind=assemblies (parts-only filter)
- ✓pins the constant against silent edits in ./constants
- ✓does not abort a pending request before 14s under the default timeout
- ✓throws SearchServiceDegradedError when the 200 body carries meta.degraded
- ✓returns normally for a genuine 200 empty (no degraded flag)
✓classifyQueryLocallySearch box22
- ✓detects part numbers with separators (dashes, dots, underscores)
- ✓detects long (7+) bare alphanumeric as part numbers
- ✓classifies standalone 3-5 digit numbers as null (could be model numbers like Ford 7710)
- ✓classifies 6+ digit numbers as parts (part numbers, not model numbers)
- ✓treats short bare alphanumeric (3-6 chars) as ambiguous — could be model code
- ✓does not classify dotted CNH model shapes as parts
- ✓still classifies non-model dotted separators as parts
- ✓detects New Holland alpha-numeric models
- ✓detects Case IH models
- ✓does not classify non-CNH brands as equipment (no data in PG search_models)
- ✓detects Ford pure-numeric models (most common pattern)
- ✓detects Ford TW series including hyphenated variants
- ✓detects CNH models
- ✓does not match 'ford' inside other words
- ✓does not match 'case' inside other words
- ✓does not match 'nh' inside other words
- ✓does not detect Fordson word-based models (no numeric token)
- ✓brand alone without model returns null
- ✓'case' as common English word + number still matches equipment
- ✓detects queries with prepositions
- ✓returns null for single generic words
- ✓returns null for empty/whitespace
✓<UnifiedEquipmentSearch>Product features20
- ✓renders the combobox label and global placeholder (#1833)
- ✓accepts a category-scoped placeholder from the server page (#1833)
- ✓fetches model autocomplete for textual queries
- ✓shows a serial-hint virtual option when input matches a PIN shape
- ✓shows compound-hint copy for model + serial pastes
- ✓shows bare-serial hint for digit-only input
- ✓Enter on serial hint fires the serial lookup flow
- ✓Enter on a model suggestion routes to its parts-diagrams page
- ✓clicking a model suggestion routes through the transition
- ✓renders a brand-catalog (slug-less) suggestion and routes to its brand page
- ✓drops a suggestion that has neither a slug nor a brandSlug+modelCode
- ✓ArrowDown cycles through serial-hint then suggestions
- ✓Escape closes the dropdown
- ✓info popover trigger has an accessible label
- ✓CombinedListbox paints a row-level spinner + disables all options when navigatingIndex is set
- ✓CombinedListbox does NOT mark rows aria-busy when navigatingIndex is null
- ✓renders the listbox as an overlay (absolute), never in normal flow
- ✓resets the active option when the query changes (#2592)
- ✓stays focusable during a pending state — readOnly, not disabled (#2592)
- ✓data-ga4-kind reflects the classifier output
✓hasActiveFiltersSearch box20
- ✓returns false for null
- ✓returns false for undefined
- ✓returns false for empty params
- ✓returns false when only q is present
- ✓returns false when only cosmetic / transient keys are present
- ✓returns true for categoryId
- ✓returns true for categoryPath
- ✓returns true for manufacturer (single)
- ✓returns true for manufacturer (comma-separated array form)
- ✓returns true for equipmentModelKey
- ✓returns true for priceBucket
- ✓returns true for priceMin / priceMax
- ✓returns true for availability literal
- ✓returns true for semantic filters
- ✓hasImage=true counts as active
- ✓hasImage=false does NOT count as active (default-false boolean)
- ✓inStock=false does NOT count
- ✓returns true when at least one filter is present alongside cosmetic keys
- ✓returns false for empty-string values
- ✓returns false for whitespace-only values
✓AdaptiveBackoffControllerSearch backend18
- ✓starts in healthy state
- ✓provides healthy config initially
- ✓has empty stats initially
- ✓records single failure
- ✓transitions to recovering after 5 failures
- ✓transitions to degraded after 10 failures
- ✓resets consecutive recoveries on failure
- ✓records single recovery
- ✓transitions to recovering with 3+ recoveries
- ✓returns to healthy after degradation with sufficient recoveries
- ✓increments consecutive recoveries counter
- ✓transitions from healthy -> recovering -> degraded
- ✓transitions from degraded -> recovering -> healthy
- ✓logs state changes
- ✓counts events within window correctly
- ✓returns different configs for each state
- ✓resets to initial state
- ✓returns comprehensive statistics
✓getProductLineSearch backend16
- ✓BOOMER-40 → BOOMER
- ✓WORKMASTER 95 → WORKMASTER
- ✓POWERSTAR 75 → POWERSTAR
- ✓T6.145 → T-Series
- ✓T7.230 → T-Series
- ✓T8.380 → T-Series
- ✓T9.435 → T-Series
- ✓TS6.110 → TS-Series
- ✓TD5.110 → TD-Series
- ✓CR9.90 → CR
- ✓CX8050 → CX
- ✓WM25S → WM
- ✓→ Other
- ✓→ Other
- ✓320 Skid Steer → 320
- ✓handles null/undefined gracefully
✓part-adapter type guardsSearch backend15
- ✓returns true for valid PartSuggestionPayload
- ✓returns false for PartMatchPayload
- ✓returns false for EquipmentSuggestionPayload
- ✓returns false for null/undefined
- ✓returns true for valid PartMatchPayload
- ✓returns false for PartSuggestionPayload
- ✓returns false for null/undefined
- ✓returns true for valid QuerySuggestionPayload with manufacturer
- ✓returns true for payload with only category
- ✓returns false for PartMatchPayload
- ✓returns false for EquipmentSuggestionPayload
- ✓returns false for null/undefined
- ✓returns true for valid EquipmentSuggestionPayload
- ✓returns false for PartSuggestionPayload
- ✓returns false for null/undefined
✓<SuggestionPanel> query-mode affordancesProduct features14
- ✓marks the exact-PN suggestion row (presentational brand treatment)
- ✓does not mark any row when no suggestion exactly matches the query
- ✓hoists the exact match into a Top Hit hero and drops it from its group
- ✓hoists a leading equipment model as the Top Hit (brand-prefixed hero title)
- ✓renders a brand-prefixed equipment title, a single type subtitle, and a diagram count
- ✓labels the part-number and description sections by what matched (#2679)
- ✓wraps only image-bearing rows as a hover-preview trigger
- ✓contains overscroll on the scrolling command list
- ✓stamps the arrow-navigation state and keeps the footer honest about Enter
- ✓promises Open once a row is genuinely user-selected
- ✓promises Open in the empty-query state, where Enter activates the selected row
- ✓shows the serial affordance row and routes clicks through onSerialSubmit
- ✓hides the serial affordance row when the query has no serial shape
- ✓offers browse escapes and the dealer phone line in the no-results state
✓adaptBrandCatalogPart (front#1610)Search backend13
- ✓maps a sellable, priced detail to a valid Part with branded SKU and no availability
- ✓omits price for a call_for_pricing (unpriced) detail and leaves availability unset
- ✓omits the manufacturer slug when not provided
- ✓hydrates media from an in-house imageUrl so the PDP gallery renders it
- ✓forwards the Clinton on-hand signal: an in_stock wire row → availability 'in_stock' (#630/#2518)
- ✓forwards clintonInStock so an on-shelf brand part can promise same-day (#3205)
- ✓falls back to the empty-media state when imageUrl is null or blank
- ✓maps the full CT-first media.images[] gallery preserving order
- ✓wires view360 spin frames into media.view360 as the gcp shape
- ✓attaches view360 even when the part only has a single imageUrl
- ✓omits view360 when the frame array is absent or empty
- ✓carries the purchasable flag onto the Part
- ✓a purchasable:false sellable priced detail is NOT purchasable through the shared gate
✓crawl origin-cache guard (#2937)Search backend13
- ✓app/parts-diagrams/model/[slug]/fetch-model-detail.ts routes crawl fetches through a getCached* wrapper
- ✓app/parts-diagrams/model/[slug]/parts-diagrams/page.tsx routes crawl fetches through a getCached* wrapper
- ✓app/parts-diagrams/model/[slug]/parts-diagrams/[assemblyCode]/page.tsx routes crawl fetches through a getCached* wrapper
- ✓app/parts-diagrams/model/[slug]/variants/page.tsx routes crawl fetches through a getCached* wrapper
- ✓app/parts-diagrams/model/[slug]/_components/equipment-popular-parts.tsx routes crawl fetches through a getCached* wrapper
- ✓app/parts/[id]/page.tsx routes crawl fetches through a getCached* wrapper
- ✓app/parts/[id]/utils.ts routes crawl fetches through a getCached* wrapper
- ✓app/parts/[id]/fetch-fitment-specs.ts routes crawl fetches through a getCached* wrapper
- ✓app/parts/[id]/assemblies/page.tsx routes crawl fetches through a getCached* wrapper
- ✓app/parts/[id]/assemblies/[assemblyCode]/page.tsx routes crawl fetches through a getCached* wrapper
- ✓app/api/schematics/related/route.ts routes crawl fetches through a getCached* wrapper
- ✓app/api/search-service/models/[modelNumber]/variants/route.ts routes crawl fetches through a getCached* wrapper
- ✓cached-client.ts defines every wrapper as a "use cache" function
✓adaptBackendFacetsSearch backend13
- ✓transforms complete facets response
- ✓maps availability facets from backend
- ✓includes low_stock (limited availability) in availability facets
- ✓#2804 — passes the `available` (orderable, off-shelf) bucket through
- ✓filters out zero-count availability buckets
- ✓derives mediaHasImageCount from manufacturer withImage sub-aggregations
- ✓returns null mediaHasImageCount when manufacturers have no withImage data
- ✓carries the measured toggle counts, preferring them over the legacy derivation
- ✓leaves both counts null when the backend did not measure them
- ✓extracts contactForPricingCount from price buckets
- ✓returns null contactForPricingCount when no price facet
- ✓handles partial facets response
- ✓handles empty facets response
✓search-part consumer contract (#1918)Search backend13
- ✓parses a real captured /api/parts/batch response
- ✓accepts availability: null in batch response — regression #2012
- ✓accepts availability: null that hono really emits on the search path
- ✓accepts availability: null in similar-parts sameType array — regression #2012
- ✓accepts title: null that prod hono emits on the search path (#2223)
- ✓rejects a part missing manufacturer (silent-drop class #1897)
- ✓rejects search responses missing pagination
- ✓createRequest rejects invalid batch payloads at the boundary
- ✓parses a real captured /api/autocomplete legacy response
- ✓accepts the sections autocomplete shape
- ✓rejects an empty autocomplete object (no more all-optional theater)
- ✓rejects an autocomplete response carrying neither suggestions nor sections
- ✓allows extra hono fields on parts (loose consumer)
✓useSerialLookupProduct features12
- ✓starts in idle state
- ✓classifies invalid input without hitting the network
- ✓routes single-match to the resolved URL via router.push
- ✓auto-routes single-match when variantCount is 1
- ✓pauses on confirmation card when variantCount > 1
- ✓flows large variantCount values through the status
- ✓surfaces multi-match candidates without auto-routing
- ✓returns no_match when the backend can't resolve a recognized format
- ✓renders format_recognized_no_match with the backend reason
- ✓treats network failures as error
- ✓treats non-2xx responses as error
- ✓reset() returns to idle from any non-loading state
✓getRetryConfigSearch backend12
- ✓matches exact paths
- ✓matches health endpoint exactly
- ✓matches autocomplete endpoint exactly
- ✓matches sitemap endpoints exactly with cold-start retry config (CT-888 + front#1044)
- ✓matches /api/parts/:id pattern
- ✓does not match incorrect paths
- ✓returns default config for unconfigured endpoints
- ✓returns default config for completely unrelated paths
- ✓all retry configs have required properties
- ✓critical endpoints have more aggressive retry
- ✓latency-critical endpoints disable retry
- ✓filters endpoint retries no more than search
✓usePartSearchAssembly views12
- ✓asks the server nothing below the 3-character threshold
- ✓waits out the debounce before firing
- ✓fires both lookups in parallel and reports the results
- ✓skips the catalog half when the caller has no model context (PDP)
- ✓trims the query before sending it
- ✓collapses a burst of keystrokes into one request
- ✓aborts the in-flight pair when a new query settles
- ✓clears results and aborts when the box drops back below the threshold
- ✓surfaces a failed lookup as an error, not as an empty result set
- ✓treats an aborted request as a cancellation, not a failure
- ✓clears a previous error when a new query starts
- ✓aborts the last request on unmount
✓brand-taxonomy clientSearch backend11
- ✓fetches equipment types for a brand
- ✓encodes brand slug with URL-unsafe characters
- ✓fetches models for a brand × type with default limit
- ✓passes cursor and custom limit when provided
- ✓throws SearchServiceApiError on 5xx responses
- ✓throws SearchServiceTimeoutError when the request aborts
- ✓preserves subLine on each model when hono returns it
- ✓normalises missing subLine to empty string (pre-deploy backward compat)
- ✓rejects responses that fail schema validation
- ✓outlasts a rate-limit burst during the build
- ✓does not retry a 429 at runtime
✓resolveLegacySlugSearch backend11
- ✓returns clean slug when vocabulary resolves the model number
- ✓URL-encodes the model number when it contains special characters
- ✓caches the resolved slug and does not refetch within the TTL window
- ✓does NOT cache vocabulary misses — each call re-queries Hono (CT-674 T1)
- ✓recovers as soon as Hono starts returning the slug (no sticky null)
- ✓returns null when the vocabulary entry is missing a slug
- ✓returns null when Hono responds with a non-ok status
- ✓does not cache error responses so retries are possible later
- ✓returns null and swallows network errors (fail-closed — will not redirect)
- ✓returns null when the legacy key has no model number part
- ✓returns null when SEARCH_SERVICE_URL is not configured
✓buildSearchParamsSearch box11
- ✓returns just mode when params and seed are empty
- ✓includes only non-empty caller params
- ✓trims caller param values
- ✓preserves seed filters when caller passes only q
- ✓caller params override seed
- ✓drops pagination + transient state from seed
- ✓null seed behaves as no seed
- ✓preserves all known catalog filter keys
- ✓seed mode is overridden by argument mode
- ✓explicit null caller value deletes the key from seed (Greptile P1 fix)
- ✓undefined caller value preserves seed value
✓expandFarmerSynonymSearch backend10
- ✓returns the trimmed lowercase query as the first element
- ✓returns single empty string for empty / whitespace input
- ✓expands disbine / disc bine / disc-bine to discbine
- ✓expands haybine and hay bine (legacy NH brand) to discbine
- ✓expands disc mower conditioner / mower conditioner to discbine
- ✓expands swather / sp swather to windrower
- ✓expands rounder to round baler
- ✓does not expand canonical product names — preserves single-element list
- ✓does not expand unknown shorthand
- ✓substring match against canonical product name validates the expansion
✓proxySearchServiceSearch backend10
- ✓forwards the upstream body under the requested cache tier
- ✓passes an upstream status through by default
- ✓lets a caller remap the upstream status
- ✓answers 502 rather than serving a body the schema rejects
- ✓returns the parsed value when a schema is supplied
- ✓runs a transform over the validated body before answering
- ✓never reaches the transform when the schema rejects the body
- ✓answers 504 when the deadline passes before the upstream replies
- ✓answers 500 for a transport failure
- ✓answers 500 when the upstream sends a 200 that is not JSON
✓deriveEquipmentDisplayMode (CT-674)Product grid10
- ✓no search term → neither flag
- ✓not first page → hide equipment
- ✓no equipment matches → neither flag
- ✓zero parts + equipment matches → equipment-first
- ✓parts outnumbered by equipment ratio (John's 5610 case: 4p, 3e)
- ✓tiny parts count under absolute cap wins even without ratio
- ✓parts count at the cap (10) still triggers equipment-first
- ✓parts count just over the cap with single equipment → mixed
- ✓many parts plus many equipment → still mixed if ratio not satisfied and cap exceeded
- ✓parts count below 3× equipment is equipment-first regardless of cap
✓HeaderSearch — public-surface pin (CT-1233)Search box10
- ✓typing 'h7230' fires the autocomplete request with q+mode+format
- ✓Enter on a cached PN suggestion pushes /parts/ct-nhl-h7230
- ✓Enter on a cached assembly suggestion pushes the exploded-diagram URL (#2664)
- ✓isSearchPending stamps aria-busy='true' on the search input during the resolve branch
- ✓search input aria-controls resolves to a mounted CommandList when dropdown is closed
- ✓Cmd+K opens the command-menu panel (cmdk shortcut contract)
- ✓Recent searches persist across close+refocus via localStorage
- ✓does not mount the autocomplete engine before any user interaction (#2157)
- ✓mounts the engine once the input is focused (#2157)
- ✓keeps the panel closed on a bare focus with nothing to show (#2625)
✓suggestion helpersSearch box10
- ✓formats part counts with pluralisation
- ✓builds metadata text per suggestion type
- ✓resolves icons per suggestion type
- ✓parses highlight segments into structured fragments
- ✓formats equipment subtitle
- ✓strips a trailing ' · {equipmentType}' from the title, preserving <em> spans
- ✓leaves the title untouched when the type suffix is absent
- ✓brand-prefixes an equipment title (McHale FUSION 1) with the type dropped
- ✓does not double-prefix a title that already leads with the brand
- ✓formats diagram counts and assembly subtitles
✓useSearchActions — CT-906 search-pending stateSearch box10
- ✓starts with isSearchPending=false
- ✓handleSearch pushes the destination through the transition
- ✓navigate pushes the URL through the transition (Popular / Try / Image surfaces)
- ✓equipment suggestion taps push to the equipment URL
- ✓derives brandSlug from brandCode for a brand-catalog model that omits it (search#642 — the fusion 404)
- ✓flips isSearchPending=true while the resolve branch awaits the network
- ✓assembly suggestion taps push to the resolved diagram page
- ✓handleSearch routes a serial-shaped query to the serial-lookup flow, not /parts (#2625)
- ✓handleSearch still routes a pure-digit query to /parts (ambiguous with a bare serial)
- ✓assembly suggestion falls back to a text search when the model resolve fails
✓runAutoSearchBusiness rules9
- ✓produces one set per model with ranked, quality-gated candidates
- ✓drops unavailable images — only live candidates reach the set (W1)
- ✓re-searches with an AI query when a pass returns zero available images (W2)
- ✓stops at the empty-retry cap when every query stays empty (W2)
- ✓demotes a URL returned for more than one model to flag
- ✓skips already-collected models so a re-run resumes
- ✓STOPS the whole loop on an upstream 502/503 (not a per-model skip)
- ✓caps at RUN_BATCH_CAP and reports capped=true with more remaining
- ✓halts when the abort signal is already aborted
✓resolveSlugByModelCode (CT-674 / GH #89)Search backend9
- ✓resolves a model UUID to its slug via /api/models/{code}/chapters
- ✓caches the resolved slug and does not refetch within TTL
- ✓returns null when Hono returns non-ok
- ✓returns null when the chapters response has an empty slug
- ✓returns null when the chapters response has a null model
- ✓returns null on network errors (fail-closed)
- ✓does NOT cache negative results — retries on next call
- ✓returns null when SEARCH_SERVICE_URL is not configured
- ✓returns null for an empty model code without fetching
✓retrySearch backend9
- ✓returns result on first successful attempt
- ✓retries on 5xx errors up to maxAttempts
- ✓does not retry on 4xx errors
- ✓throws error after maxAttempts exhausted
- ✓respects abort signal
- ✓throws immediately if signal is already aborted
- ✓applies exponential backoff with default config
- ✓applies jitter to delay when enabled
- ✓uses custom retry config
✓peekAutocompleteCache (react-query layer)Search box9
- ✓returns null for queries shorter than MIN_QUERY_LENGTH
- ✓returns null when the cache has no matching entry
- ✓returns the top cached suggestion on a hit
- ✓respects the classifier-derived effective mode (parts hint routes to 'parts' key)
- ✓trims input before lookup so whitespace paste still finds the entry
- ✓returns null when the cached entry has no suggestions
- ✓is mode-scoped: forced mode does not read the 'auto' key
- ✓a forced (non-auto) mode carries straight through resolveEffectiveMode
- ✓__resetAutocompleteQueryCacheForTests clears prior seeds
✓pickTopHitProduct features8
- ✓returns null for an empty query
- ✓picks an exact part-number match, case-insensitively, in group order
- ✓does not hoist a partNumberMissing row (selecting it only runs a generic search)
- ✓prefers a part-number match over a leading equipment row
- ✓picks the leading equipment row when its text equals the query
- ✓picks the leading equipment row when its modelCode equals the query
- ✓does not pick equipment that only partially matches (nothing fuzzier in v1)
- ✓does not pick equipment that does not lead the results
✓paginateAssembliesSearch backend8
- ✓returns null when page 1 fetch fails
- ✓returns first page unchanged for a single-page chapter
- ✓returns an empty assemblies array for an empty chapter
- ✓concatenates all pages when totalPages <= MAX_CHAPTER_PAGES
- ✓caps at MAX_CHAPTER_PAGES and warns when chapter exceeds cap
- ✓does not emit Sentry when chapter is within cap
- ✓tolerates individual page failures and returns partial results
- ✓issues pages in parallel (not sequentially)
✓isPdpWithdrawn (front#3698)Search backend8
- ✓true for no_cnh_data regardless of content
- ✓true for dont_list with neither a price nor an image
- ✓false for dont_list carrying a price
- ✓false for dont_list carrying a primaryImage
- ✓false for dont_list carrying a gallery image
- ✓false for a dont_list BOM row carrying imageUrl (the BomPart shape)
- ✓false for every status outside the two cohorts
- ✓false for undefined / null / an unknown string (fail-open)
✓isCommerceDisabledSearch backend8
- ✓true for no_cnh_data
- ✓true for dont_list (front#833: replaces the prior 404 path)
- ✓false for sellable
- ✓false for call_for_pricing — quote-only is gated by isQuoteOnly, not the banner
- ✓false for superseded_sellable
- ✓false for undefined (fail-open)
- ✓false for null (view-model omits the field when missing)
- ✓false for an unknown string (fail-open)
✓deduplicateRequestSearch backend8
- ✓executes function when no cached request exists
- ✓reuses existing promise for concurrent requests
- ✓executes new request after previous completes
- ✓cleans up after request completes
- ✓handles request failures
- ✓deduplicates identical failing requests
- ✓handles multiple different concurrent requests
- ✓respects deduplication window
✓isRetryableErrorSearch backend8
- ✓returns true for timeout errors
- ✓returns true for 5xx server errors
- ✓returns false for 4xx client errors
- ✓retries during the production build
- ✓does NOT retry at runtime
- ✓does NOT retry when the phase is unset
- ✓returns false for connection errors (SearchServiceError)
- ✓returns false for other errors
✓<DiagramSearchInside>Diagram viewer7
- ✓shows nothing in the result list when the query is empty
- ✓filters results by case-insensitive displayName match
- ✓renders an empty state only when query is non-empty with no matches
- ✓preserves the chapter displayName as an eyebrow on each result row
- ✓navigates via router.push, preferring slug over assemblyCode
- ✓falls back to assemblyCode when slug is null
- ✓renders the input with at least a 44px (h-11) target height
✓ENDPOINT_RETRY_CONFIGSSearch backend7
- ✓defines configs for critical endpoints
- ✓disables retry for autocomplete endpoint
- ✓disables retry for health check
- ✓part details endpoint has fast recovery config
- ✓search endpoint has budget-capped config
- ✓filters endpoint has conservative config
- ✓sitemap endpoints have aggressive cold-start retry config (CT-888 + front#1044)
✓parseSearchParams — pageSize boundary (#1292)Search backend7
- ✓passes through pageSize=1 (min boundary)
- ✓passes through pageSize at MAX
- ✓passes through pageSize=MAX-1
- ✓throws SearchServiceApiError(400) when pageSize=MAX+1
- ✓throws SearchServiceApiError(400) for a very large pageSize (999999)
- ✓omits pageSize from query when value is invalid (non-integer)
- ✓omits pageSize when not provided
✓diagramMatchHrefAssembly views7
- ✓prefers the row's own model over the sheet's
- ✓falls back to the sheet's model when the row has no slug
- ✓falls back to the model key when neither side has a usable slug
- ✓rejects an all-digits slug as the feed artifact it is (#3029)
- ✓omits the highlight when the match carries no callout ref
- ✓encodes a ref that would otherwise break the query string
- ✓prefers the canonical assembly slug over the legacy code
✓buildImageQueryVariants — machine surfaces (default / model-card / model-list)Admin logic7
- ✓leads with typed noun + OEM-domain keyword, then typed noun, then broad
- ✓model-card / model-list use the same machine templates as the default
- ✓logo / hero fall through to the machine templates (whole-model surfaces)
- ✓resolves a vendor code (KUH) to the brand NAME + OEM domain in the query
- ✓falls back to 'official' when the brand has no OEM domain
- ✓de-duplicates identical variants
- ✓cycles deterministically over the variant list via modulo attempts
✓adaptManufacturerFacetsSearch backend7
- ✓transforms backend manufacturer facets to frontend format
- ✓handles unknown manufacturer codes with fallback
- ✓returns null for empty array
- ✓returns null for undefined input
- ✓resolves vendor codes via vendor-display-names
- ✓resolves CNH heritage make codes to full vendor names
- ✓preserves original code case from backend
✓AutoSearchPanel reviewInterface pieces6
- ✓keeps flag candidates visible (does not hide non-OEM rows)
- ✓Approve verifies then moves the chosen candidate into the replacement store
- ✓Approve on an unavailable AI check still stages the pick (human's call stands)
- ✓a 'wrong image' verdict BLOCKS the approve and flags the set; a second click overrides
- ✓Reject removes the set without writing a replacement
- ✓Approve defaults to the first candidate when none is explicitly chosen
✓rankScopedPartsAssembly views6
- ✓returns nothing for an empty query — orientation, not a dump
- ✓ranks an exact part-number prefix above a title contains-match
- ✓ranks an exact title match ('Arm') above a title-contains match ('Armrest')
- ✓only falls back to diagram/chapter text when no part-number or title token matches
- ✓ANDs multi-token queries — every token must match somewhere on the same part
- ✓excludes parts that don't match every token
✓isClientRequestError — cache-poison discriminatorSearch backend6
- ✓is true for 4xx validation errors (malformed request, safe to cache inline)
- ✓is FALSE for 429 — rate-limiting is transient, must not be cached
- ✓is FALSE for every 5xx, including the 503 SEARCH_DEGRADED contract
- ✓is FALSE for timeout, degraded, and base connection errors (all transient)
- ✓is FALSE for non-SearchService errors and non-errors
- ✓narrows the type so the 4xx branch can read .status/.code
✓retry metrics trackingSearch backend6
- ✓tracks retry attempts with endpoint metadata
- ✓tracks exhausted retries when all attempts fail
- ✓tracks timeout error type correctly
- ✓does not track when no metadata provided
- ✓does not track first attempt (only retries)
- ✓tracks exhausted for non-retryable errors after retry
✓buildSearchParams — count/filter parity across pages (#2223)Parts pages6
- ✓browse landing uses the same page size on page 1, 2 and 3
- ✓browse honors the user-selected Per-page preset on EVERY page
- ✓search results keep the fixed catalog page size
- ✓does NOT inject a page-1-only hasImage filter that hides parts on later pages
- ✓keeps the derived filter set identical across pages for a brand
- ✓keeps the derived filter set identical across pages for a category
✓enrichCatalogMatchesAssembly views6
- ✓stays null before the search has answered
- ✓fills a missing price from the BOM row with the same part number
- ✓fills a missing image from the BOM row
- ✓keeps the search endpoint's own price and image when it has them
- ✓leaves a hit with no BOM counterpart unpriced rather than guessing
- ✓cross-references by part number, not by position
✓mergeEquipmentBrowseSearch box6
- ✓returns suggestions unchanged when browse is empty
- ✓appends novel browse equipment whose model name starts with the query
- ✓deduplicates by modelKey
- ✓returns same reference when all browse items are duplicates
- ✓drops browse rows whose model name does not start with the query (#2625 substring noise)
- ✓prefix match is case-insensitive
✓adaptPriceFacetsSearch backend6
- ✓transforms backend price ranges with from and to
- ✓formats 'Under' labels for ranges without from
- ✓formats '+' labels for ranges without to
- ✓formats 'All' label for range without from or to
- ✓returns null for undefined input
- ✓returns empty array for empty ranges
✓normalizeFacetsSearch backend6
- ✓returns defaults for null input
- ✓returns defaults for undefined input
- ✓preserves provided array fields
- ✓forwards conditions field
- ✓forwards scalar fields
- ✓normalizes non-array values to defaults
✓mergeFacetsSearch backend6
- ✓returns search when filters is null
- ✓returns search when filters is undefined
- ✓prefers filters when both have data
- ✓falls back to search when filters arrays are empty
- ✓returns null for arrays when both are empty
- ✓forwards scalar fields with null fallback
✓<BrandScopeSearchField>Brand pages5
- ✓renders the input by label + placeholder, and never a view toggle
- ✓emits the raw input string through onChange
- ✓supports both controlled (value) and uncontrolled (defaultValue) inputs
- ✓forwards inputRef and renders the trailing slot
- ✓renders a quiet placeholder (no input, no toggle) in the loading field shell
✓isRoutableSerialShape (#2625 header-search routing gate)Product features5
- ✓is false for null
- ✓is true for a 17-char PIN
- ✓is true for a compound model+serial paste
- ✓is true for an alpha-prefixed bare serial (no part-number reading)
- ✓is false for a pure-digit bare serial (ambiguous with a part number)
✓<ScopedPartsPanel> ranked resultsProduct features5
- ✓ranks an exact title match above a contains match
- ✓shows the in-stock badge only for the in_stock part
- ✓offers a clear escape back to global search when nothing matches
- ✓caps ranked results at 8 with a link to see the rest
- ✓carries the typed query into the See-all deep link so the sheet opens pre-filtered
✓<SuggestionPanel> fetching affordanceProduct features5
- ✓shows the top bar and marks the list busy while refining, keeping stale rows
- ✓keeps the skeleton up and suppresses 'No results' while an empty first query is fetching
- ✓renders 'No results found.' only once the query settles empty
- ✓suppresses the top bar during a navigation, deferring to the nav overlay
- ✓holds the result-count announcement silent until a fetch settles
✓getBrandCapabilityFlagsSearch backend5
- ✓flips hasModels off from the summary, gating the equipment-type section by data
- ✓derives navigability from the PG is_carried flag (snake_case)
- ✓onboards a brand absent from every hardcoded list purely via summary flags
- ✓falls back to the seed for a flag the summary omits
- ✓falls back to the seed (not an error) when the summary fetch fails
✓getCachedRelatedModels — #1329 best-effort additive sectionSearch backend5
- ✓degrades a transient 503 to the empty shape (never throws → hub stays up)
- ✓degrades a transient timeout to the empty shape
- ✓degrades a network error to the empty shape
- ✓degrades a genuine 4xx to the empty shape
- ✓passes through a successful response unchanged
✓getCachedSearchResults — #2124 data_quality sort fallbackSearch backend5
- ✓retries bare browse with `popular` when hono 400s on data_quality
- ✓retries category browse with `revenue` (not popular)
- ✓does not retry when data_quality succeeds (no double fetch on dev hono)
- ✓re-throws a 4xx for any non-data_quality sort (nothing to fall back from)
- ✓re-throws a transient 5xx on data_quality instead of masking it as a sort issue
✓fallbackUnlessTransientAtRuntime — #1323 SSG hub guardSearch backend5
- ✓during `next build`, returns the fallback for ANY error (never fails the build)
- ✓at runtime, returns the fallback for a deterministic 4xx (stays a clean degrade)
- ✓at runtime, RE-THROWS every transient failure (5xx / 429 / timeout / degraded / unknown)
- ✓at runtime, re-throws the ORIGINAL error instance (boundary sees the real cause)
- ✓treats a non-build NEXT_PHASE (runtime server) as runtime, not build
✓fetchIpv4 — Agent reuse (#1263)Search backend5
- ✓constructs exactly one Agent across many calls
- ✓constructs one Agent under concurrent first-callers (no thundering herd)
- ✓passes the same dispatcher instance on every call
- ✓forwards init options without dropping caller-supplied fields
- ✓constructs the Agent with IPv4-only connect family and serverless socket posture (hono#558)
✓fetchVocabularyByNumbersSearch backend5
- ✓uses the Next data cache by default (revalidate 300)
- ✓bypasses the Next cache when noStore is set (CT-674 T1 retry path)
- ✓attaches an AbortSignal when timeoutMs is set
- ✓returns an empty map on 500 so the caller can decide to retry
- ✓returns an empty map when the abort fires (timeout)
✓getRequestKeySearch backend5
- ✓returns path when no params provided
- ✓returns path when params is empty object
- ✓generates key with params
- ✓sorts params consistently
- ✓handles params with different types
✓sanitizePartPricingSearch backend5
- ✓strips dealer, wholesale, net (dealer cost), and discountPercent
- ✓strips discountPercent even when no other wholesale tiers are present
- ✓drops `net` even when it is the only tier present (don't leak dealer cost)
- ✓strips arbitrary unknown tiers (e.g. nh_discount_code, costPrice)
- ✓returns undefined for empty or non-object input
✓buildSearchParams — inStock -> availability mapping (#2223, #2466)Parts pages5
- ✓derives availability=in_stock from a bare inStock=true
- ✓does not set availability when inStock is absent/false
- ✓an explicit availability wins and is not clobbered by inStock
- ✓drops the retired `available` bucket instead of threading it through
- ✓drops an out-of-enum availability value (nuqs literal → null)
✓<PartsHeroSearchInput>Product grid5
- ✓renders a plain search-parts input and no ⌘K hint (the chord is the header's)
- ✓keeps the clear button mounted but invisible when empty so the field never reflows (#2592)
- ✓fires onSearchChange after the 600ms debounce when typing
- ✓flushes the debounce synchronously on Enter
- ✓clears the input + emits an empty onSearchChange on Escape
✓searchCatalogPartsAssembly views5
- ✓sends the query, the model filter and the 50-row cap
- ✓maps a hit and leaves price for the BOM cross-reference to fill
- ✓falls back to `title` for description and to the first gallery image
- ✓returns no image rather than undefined when the payload carries no media
- ✓degrades to no hits on an error status, an unexpected shape, or a dead network
✓searchPartDiagramsAssembly views5
- ✓maps assemblies onto the searched part number
- ✓normalises an absent slug and schematic to null, not undefined
- ✓returns no matches on an error status or an unexpected shape
- ✓propagates a dead network instead of swallowing it
- ✓brand-qualifies the lookup id for an adapter brand (front#2755)
✓normalizeDidYouMeanSearch box5
- ✓wraps a bare corrected-query string
- ✓passes an already-shaped object through unchanged
- ✓returns null for a blank string
- ✓returns null for null/undefined
- ✓returns null for an object with no usable text
✓buildAutocompleteWireQuerySearch box5
- ✓strips joiners from a dashed PN-shaped query
- ✓strips dots and underscores too
- ✓keeps a branded SKU intact, stripping joiners only inside the PN (#3811)
- ✓leaves non-PN-shaped queries untouched
- ✓leaves dotted model shapes untouched (not classified as parts)
✓enhancePartWithMissingFieldsSearch backend5
- ✓uses backend-provided vendorCode when present
- ✓derives vendorCode from manufacturer code when missing
- ✓enhances manufacturer with navigation fields
- ✓uses backend-provided qualityScore when present
- ✓leaves qualityScore undefined when neither source available
✓McHale equipment-type canon (#2101)Search backend5
- ✓fails on the documented wrong-label wire fixture (Shear Grab + ghost model types)
- ✓regression gate: McHale browse-by-type wire must match agreed canon
- ✓passes when required types are present and forbidden labels are absent
- ✓accepts display variants Round Balers / Disc Mowers for required buckets
- ✓documents Rakes/Tedders as John-gated (not asserted until flag flips)
✓/api/admin-media/searchAPI endpoints5
- ✓returns 403 for non-admin (staff)
- ✓returns 503 for admin when Serper is not configured (no mock shelf)
- ✓returns 200 with mapped candidates when Serper returns items
- ✓returns 502 when Serper fails upstream (error, not a mock shelf)
- ✓returns 200 with an empty list when Serper genuinely has no images
✓/api/search-service/resolve-part — href carries the index verdictAPI endpoints5
- ✓sends a registry-held part to its /lookup twin, never to the 404
- ✓sends a vouched part to its canonical PDP
- ✓holds an adapter-brand row that carries no verdict at all (search#933)
- ✓falls back to the first candidate when none is an exact match
- ✓404s when nothing matches, so the caller falls back to the results page
✓AdminImageEditDialog — Search againAdmin editing4
- ✓renders the search control (re-runs the edited query)
- ✓shows the manufacturer-results label when an OEM candidate is present
- ✓shows the broadened-search label when no OEM candidate is present
- ✓shows a loading indicator while the shelf loads
✓AutoSearchEntry gateInterface pieces4
- ✓opens the dialog for an admin off-prod with the toggle on
- ✓stays inert for an admin while the toggle is off
- ✓stays inert for a customer
- ✓stays inert on prod even for an admin with the toggle on
✓AutoSearchPanel gateInterface pieces4
- ✓renders nothing for a customer even when opened
- ✓renders nothing on prod for an admin
- ✓stays closed until the dropdown opens it
- ✓opens with an empty state when the store is empty
✓classifySerialApiPathProduct features4
- ✓builds PIN query path
- ✓builds compound query path
- ✓builds bare-serial query path
- ✓returns null for null classification
✓resolveClassificationToUrlProduct features4
- ✓routes single match to /equipment/{slug}
- ✓routes multi match to disambiguation listing
- ✓returns null for no_match
- ✓returns null for format_recognized_no_match
✓searchEnginePropsProduct features4
- ✓submits the trimmed query, not whatever is in the input
- ✓searches for the recent term the user picked, not the current one
- ✓passes the hero empty-state through — it belongs to the page, not the shell
- ✓never carries `variant` — that is the one thing the two chromes disagree about
✓useRowPreviewOpenProduct features4
- ✓opens only after the dwell delay while the row stays active
- ✓closes immediately when selection moves off the row
- ✓never opens while arrowing past the row faster than the dwell
- ✓matches the active value case-insensitively (cmdk lowercases)
✓<SearchPill> layout stabilityProduct features4
- ✓keeps the clear-search slot mounted (invisible) while open with an empty query
- ✓reveals the same clear-search slot once a query exists — no remount
- ✓does not render the clear-search slot while closed (shortcut hint instead)
- ✓keeps the submit label mounted while pending — spinner overlays instead of replacing
✓<SuggestionPanel> render stabilityProduct features4
- ✓keeps stale results visible while the next fetch is loading (no shimmer swap)
- ✓shows the loading shimmer only before the first results arrive
- ✓reserves the shimmer footprint (min-h-60) for the whole query session
- ✓does not reserve query-session height in the empty-query (recent searches) state
✓useSearchShellState requestOpen something-to-show gate (#2625)Product features4
- ✓stays closed on focus with no query, no recents, no static content
- ✓opens once the query reaches MIN_QUERY_LENGTH
- ✓opens when recent searches exist
- ✓opens when the surface declares static empty-query content (hero)
✓useSearchShellState model scope-lock (All BOM Parts × Search)Product features4
- ✓locks onto a model from an OPEN panel: clears the query and refocuses the input
- ✓does NOT open the panel or clear the query when scope is set while closed (page auto-scope)
- ✓does not reset an already-typed query when the SAME model's scope changes shape
- ✓treats a locked scope as something to show for requestOpen, even with an empty query
✓checkImageLivenessBusiness rules4
- ✓resolves for a live, large-enough image
- ✓rejects on an error
- ✓rejects an image below the min width
- ✓rejects after the timeout when the image never loads
✓buildDiagramSearchIndexBusiness rules4
- ✓flattens chapters into one row per assembly with chapter displayName attached
- ✓skips chapters whose assemblies haven't been pre-fetched
- ✓falls back to assemblyCode when slug is null
- ✓falls back to assemblyCode for an EMPTY-STRING slug (#3647)
✓buildEquipmentSearchPlaceholderEquipment data4
- ✓returns a global placeholder without hardcoded model examples (#1833)
- ✓derives category copy from label + count (#1833 / #1811 compose)
- ✓formats large counts with locale grouping
- ✓defaults to global when called with no argument
✓useEquipmentSearchBusiness rules4
- ✓does not fire a request when query is shorter than minQueryLength
- ✓debounces the API call and surfaces results
- ✓clear() resets the query and results
- ✓surfaces fetch errors as `error`
✓mapSearchServicePartToCatalog — lookupOnly (#3827/#3854)Search backend4
- ✓holds an adapter-brand row that carries no registry verdict at all
- ✓does not hold a CNH row — NHL is not an adapter brand
- ✓holds a CNH row the registry rejects
- ✓holds nothing with the flag off — the flag is the whole rollback
✓brandCatalogPartDetailResponseSchema (#1852)Search backend4
- ✓accepts Clinton-stocked Ferris detail with in_stock availability and media gallery
- ✓accepts a detail carrying 360 spin frames (#1781)
- ✓still accepts legacy Ferris rows with null availability
- ✓accepts a detail that omits availability entirely
✓adaptBrandCatalogPartSummary (front#1610 hub listing)Search backend4
- ✓maps a priced summary into a valid card Part with branded SKU and no availability
- ✓omits price for an unpriced summary
- ✓hydrates media from imageUrl so the storefront card renders the photo
- ✓keeps the empty-media fallback when summary imageUrl is null/missing
✓parts-popular clientSearch backend4
- ✓fetches popular parts with default limit
- ✓encodes vendor + limit query string
- ✓propagates 4xx errors as SearchServiceApiError
- ✓returns the parsed wrapper shape (vendor null + total + took)
✓getProductLineDisplaySearch backend4
- ✓preserves Series labels
- ✓preserves short codes uppercase
- ✓title-cases longer words
- ✓passes Other through
✓isQuoteOnly (#3479)Search backend4
- ✓true for call_for_pricing
- ✓false for sellable — the axis must not swallow the ordinary case
- ✓false for the NO_COMMERCE members, which have their own axis
- ✓false for undefined / null / an unknown string (fail-open, same as its siblings)
✓resolveShortSlug (front#243)Search backend4
- ✓resolves single- and multi-variant short slugs (uppercases tail, hits /variants)
- ✓returns null without fetching when slug has no known brand prefix or env is unset
- ✓returns null on empty variants, non-ok status, or network failure
- ✓caches positive resolutions, does NOT cache negatives (recovers when hono warms)
✓hero-search href allowlist (#848, #2849)Home page4
- ✓every ALT_ACTIONS href targets /parts, the diagram surfaces, or a brand hub
- ✓every QUICK_CHIPS href targets /parts, the diagram surfaces, or a brand hub
- ✓the known dead targets from #848 can never re-enter the hero
- ✓hero exposes the Part Store + Parts Diagrams center CTAs
✓isSingleFederatedBrand — #2795 global /parts facade gateParts pages4
- ✓true for a single federated brand (adapter-served)
- ✓false for New Holland (search-MV path, not an adapter brand)
- ✓false for a multi-brand selection (no single-brand facade)
- ✓false when no manufacturer is selected (global grid)
✓EquipmentModelCard — non-carried brand has no Diagrams link (#3309)Product grid4
- ✓omits the Diagrams link entirely for a non-carried brand
- ✓emits no /parts-diagrams href at all for a non-carried brand
- ✓keeps a working View parts link so the card is not dead weight
- ✓never builds a double-slash diagrams path from an empty brandSlug
✓EquipmentSearchResults — show-all affordanceProduct grid4
- ✓compact banner fires onShowAll (e.g. switch to the Models tab) when provided
- ✓compact banner with no onShowAll expands the full list in place
- ✓expanded variant renders every model with no compact cap and no control
- ✓#3153 — browseHref makes 'Show all' a diagrams-page link, over onShowAll/expand
✓hasServerResultsAssembly views4
- ✓is false below the 3-character server-search threshold, even with hits
- ✓is true when either lookup returned rows
- ✓is false when the search ran and found nothing
- ✓is false before either lookup has answered
✓mergeBrandSuggestionsSearch box4
- ✓returns suggestions unchanged when brand is empty
- ✓appends novel brand rows of both types
- ✓appends nothing when every brand row is a full duplicate (stale-backend guard)
- ✓dedupes on type AND text, so a same-text row of a different type is still novel
✓SuggestionPanel — CT-906 loading overlaySearch box4
- ✓does NOT render the loading overlay when isSearchPending=false
- ✓renders the loading overlay when isSearchPending=true
- ✓stamps data-search-pending on the panel root
- ✓invokes onNavigate from the TrySearchingByGroup chip taps
✓buildImageQueryVariants — surface-directedAdmin logic4
- ✓part (pdp) leads with brand+title+partNumber and NEVER appends the equipment noun
- ✓category leads with the label + agricultural-equipment anchor (no OEM domain for Marcrest)
- ✓brand keys on the brand name only (from displayName)
- ✓global-category is cross-brand with no OEM domain bias
✓cached-client fail-open boundary (#3611)Search backend4
- ✓getCachedPopularParts resolves to null instead of throwing
- ✓getCachedPartAssemblies resolves to null instead of throwing
- ✓passes the payload straight through when the upstream succeeds
- ✓keeps the isolation inside the cached function, not at the call site
✓adaptCategoryFacetsSearch backend4
- ✓transforms backend category facets to frontend format
- ✓returns null for empty array
- ✓returns null for undefined input
- ✓preserves category name formatting
✓enhanceManufacturerSearch backend4
- ✓uses backend-provided fields when all are present
- ✓derives fields from code when missing
- ✓handles codes with special characters
- ✓partially derives missing fields when some are present
✓normalizeView360Search backend4
- ✓copies view360 from media to top-level when missing
- ✓copies view360 from top-level to media when missing
- ✓returns part unchanged when view360 in both locations
- ✓returns part unchanged when view360 missing from both
✓adaptBackendPartSearch backend4
- ✓applies all transformations in correct order
- ✓preserves publishStatus + finalReplacementPn for superseded_redirect parts
- ✓preserves replacedPartNumbers list for superseded_sellable parts
- ✓preserves baseline supersession fields on a sellable part
✓/api/admin-media/search — attempt cycles the template + busts the cacheAPI endpoints4
- ✓attempt=0 and attempt=1 issue DIFFERENT queries (cache miss)
- ✓re-issuing the SAME attempt hits the cache (no second upstream call)
- ✓attempt 3 reuses variant[0] but pages to page 1 (fresh results, not repeat)
- ✓threads surface -> a pdp part searches by part number, not the equipment noun
✓/api/search-service/autocompleteAPI endpoints4
- ✓returns 502 when the upstream search service errors
- ✓returns 502 on an unexpected (non-SearchServiceError) failure
- ✓passes a sections response straight through with a 200
- ✓short-circuits a too-short query without hitting the upstream
✓groupPartsByNumberAssembly views3
- ✓collapses (part, diagram) rows back to one entry per part with a diagrams array
- ✓gives a zero-diagram part (the loader's empty-assemblyCode placeholder row) an empty diagrams array
- ✓dedupes diagrams by code — a part callout listed twice on one diagram renders once
✓<FitsExactBadge> — serial-search UIProduct features3
- ✓renders the badge when classify resolves a single match and fitment contains the resolved model
- ✓renders nothing when classify resolves a single match but fitment does not contain the resolved model
- ✓renders nothing when no serial param is present (no fetches fired)
✓<ScopedPartsPanel> part rowsProduct features3
- ✓navigates straight to the diagram for a single-diagram part
- ✓expands a multi-diagram part inline instead of navigating away
- ✓renders the diagram code on each expanded child row so same-named diagrams stay distinguishable
✓<SearchPill> model scope-lock (All BOM Parts × Search)Product features3
- ✓renders the scope chip and swaps the placeholder to the scoped copy
- ✓calls onClearScope when the chip's remove button is clicked
- ✓shows no chip and the static placeholder when no scope is locked
✓buildPreviewCaptionProduct features3
- ✓falls back to the PN when a part row's highlight is an empty string
- ✓leads with the description and captions the PN beneath for a part row
- ✓uses the subtitle as the secondary line for non-part rows
✓<SuggestionRow> scope-to-model action (All BOM Parts × Search)Product features3
- ✓locks the scope store on click without triggering the row's own hand-off onSelect
- ✓does not render when the equipment payload has no slug (nothing to search)
- ✓falls back to the suggestion's text when the payload has no displayName
✓useSearchShellState close/reset behavior (#2625)Product features3
- ✓shows recent searches again on reopen after a submit
- ✓preserves the typed query across a dismissal and the next reopen
- ✓keeps focus in the input when the panel closes (APG combobox: Escape must not blur)
✓useDismissOnOutsideScroll (#2625 hero surface)Product features3
- ✓dismisses on a page scroll while enabled
- ✓lets scrolls inside the panel (the suggestion list) through
- ✓does not listen while disabled
✓buildAutoSearchQueryBusiness rules3
- ✓adds the equipment noun + OEM-domain keyword, no negatives, never `site:`
- ✓falls back to the per-brand default noun when no scope noun is given
- ✓prefixes the brand when the model name lacks it and folds in the noun
✓bomDirectoryResponseSchema — seo verdict (#3854)Search backend3
- ✓keeps the verdict, including the `state` the hold decision reads
- ✓drops a drifted verdict to undefined, keeps the model, and says so
- ✓does not invent a verdict when the backend sends none
✓filterByLineSearch backend3
- ✓returns all models when line is null/empty
- ✓narrows to matching line
- ✓returns empty for unknown line
✓filterByLines (#1938 allow-list)Search backend3
- ✓keeps models whose line is in the allow-list (multi-line sub-grouping)
- ✓keeps nothing for an empty allow-list (unlike filterByLine's optional narrow)
- ✓ignores allow-list entries with no matching models
✓resolveSlugByModelNumberSearch backend3
- ✓resolves a bare model number to its canonical slug
- ✓returns null for an empty string
- ✓shares its cache with resolveLegacySlug (same model number, one fetch)
✓resolveSearchApiUrlSearch backend3
- ✓uses SEARCH_SERVICE_URL
- ✓throws when SEARCH_SERVICE_URL not set
- ✓respects explicit baseUrl config over env
✓sanitizePartSearch backend3
- ✓strips wholesale fields from price block
- ✓drops the price field entirely when only wholesale tiers are present
- ✓returns the part unchanged when it has no price
✓buildSearchParams — indexableOnly rides browse, never search (#3809/search#934)Parts pages3
- ✓browse (no q) with the flag on requests registry-eligible rows only
- ✓a text search keeps finding held parts — no indexableOnly
- ✓flag off leaves every request byte-identical
✓SearchResultsSegmentsParts pages3
- ✓renders nothing when there is no real choice (< 2 segments)
- ✓renders every segment, with counts, and marks the active one pressed
- ✓fires onChange with the clicked segment id
✓EquipmentModelCard — actionsProduct grid3
- ✓renders exactly two links (Parts + Diagrams) and no bare button
- ✓points View parts at the flat model-scoped catalog, NOT the diagrams page
- ✓points Diagrams at the model's parts-diagrams hub (slug resolves alone)
✓EquipmentModelCard — federated brand routing (#2667)Product grid3
- ✓routes an empty-slug federated Diagrams link to /parts-diagrams/{brandSlug}/{modelCode}
- ✓still scopes View parts to the model for a federated row
- ✓derives the brand slug from brandCode when brandSlug is absent (Diagrams stays live)
✓EquipmentModelCard — titleProduct grid3
- ✓uses the bare model number as the title (brand prefix + 'Parts Diagram' suffix stripped)
- ✓keeps a model that carries no brand prefix intact (NHL T6.145 → 'T6.145')
- ✓falls back to the uppercased brandCode text chip for unknown vendors
✓EquipmentModelCard — contentProduct grid3
- ✓renders the equipment-type badge and the diagram count
- ✓singularises the diagram count when assemblyCount is 1
- ✓renders 'many diagrams' for soft counts at/above SOFT_COUNT_THRESHOLD (10K)
✓soleBrandCode (single-brand hoist decision)Product grid3
- ✓returns the shared code when every result is the same brand
- ✓returns undefined when brands differ (per-card logos stay)
- ✓returns undefined for an empty result set
✓heldPartNumbersAssembly views3
- ✓collects only the rows the route stamped
- ✓dedupes the repeated rows one part produces across its diagrams
- ✓leaves a part the BOM has no row for out — an absent verdict is not a hold
✓ensureNonEmptyQuery (empty-query floor)Admin logic3
- ✓combines brand + label
- ✓falls back to modelCode when brand + displayName are blank
- ✓never returns empty (modelCode is the last resort)
✓BRAND_OEM lookupsAdmin logic3
- ✓resolves OEM domains + noun by slug, code, and display name
- ✓returns empty domains + noun for unknown or domain-less brands
- ✓resolves a vendor code (KUH) to the same OEM entry as the slug (kuhn)
✓search directives — schematic guard is per-surfaceAdmin logic3
- ✓excludes schematic/manual terms on the photo surfaces
- ✓keeps photo surfaces on the photo medium
- ✓carries no text negatives on the diagram scope (a diagram is the goal)
✓adaptBackendPartsSearch backend3
- ✓applies transformation to all parts in array
- ✓handles empty array
- ✓preserves supersession fields across list mapping (CT-674 T-B2/T-B3)
✓<RowPreview>Product features2
- ✓renders the row bare (no card, no wrapper) when there is no thumbnail
- ✓mounts the portaled preview card once the dwell opens it (controlled HoverCard)
✓<ScopedPartsPanel> empty-query orientationProduct features2
- ✓hints at the total part count and offers chapter chips instead of a raw list
- ✓drills a picked chapter into its diagrams (not a flat part slice) and offers a way back
✓<ScopedPartsPanel> error / empty-BOM statesProduct features2
- ✓shows an empty-BOM state with an escape when the model has no parts
- ✓shows an error state with an escape when the BOM fails to load
✓<ScopedPartsPanel> variantProduct features2
- ✓shows the keyboard-hint footer for the default popover variant
- ✓hides the keyboard-hint footer for the overlay variant
✓header-search live regions are <output>Product features2
- ✓announces the did-you-mean banner from an <output> that stays a flex row
- ✓renders the deferred-chunk skeleton fallback as a block <output>
✓useSearchShellState Enter vs arrow navigation (#2625)Product features2
- ✓runs the generic search on Enter until the user arrow-navigates, then defers to cmdk
- ✓disarms arrow navigation on query change and on close
✓useSearchShellState Cmd+K routing (#2625)Product features2
- ✓opens the mobile overlay below lg instead of the hidden popover shell
- ✓toggles the popover shell at lg and above
✓rankAndTrimBusiness rules2
- ✓ranks OEM above aggregator above neutral, drops junk, and trims to 8
- ✓caps the result at 20 candidates (batch depth)
✓qualityForBusiness rules2
- ✓is good only when OEM AND unique AND live
- ✓flags OEM images that are cross-model, dead, or from an aggregator
✓prerender-safe clockSearch backend2
- ✓never reads Date.now, whatever it is asked to do
- ✓stamps the state-change log with epoch milliseconds, not process uptime
✓isBrandCatalogVendor (FER + VNT + MCH + MAR + KUH)Search backend2
- ✓is true for every brand-catalog vendor (FER, VNT, MCH, MAR, KUH) — case-insensitive
- ✓is false for CNH and unrelated brands, and for nullish input
✓supportsPartCategoryFilter (#2441 / ct-2781 — adapter type→filtered Part view routing)Search backend2
- ✓is true for every adapter brand whose parts carry a category signal (FER/MCH/VNT/MAR/KUH/KRE/AGC/LDL, CROP-search#658)
- ✓is false for non-adapter / unrelated / nullish input
✓supportsInStockFilter (#2517 — adapter stock-filter caps)Search backend2
- ✓is true only for FER (the sole adapter brand with a Clinton stock signal)
- ✓is false for every adapter brand without a stock signal (else the forward 400s)
✓supportsPriceRangeFilter (#2517 → #647 → #666 — adapter price-range caps)Search backend2
- ✓is true for AGC, MCH, and VNT (all back a price band on the adapter endpoint)
- ✓is false for every adapter brand without a price-range axis
✓groupByProductLineSearch backend2
- ✓groups models by derived line
- ✓uses modelNumber rather than brand-prefixed displayName
✓topProductLinesSearch backend2
- ✓sorts by count desc then alphabetical
- ✓respects limit
✓getInflightCountSearch backend2
- ✓returns 0 when no in-flight requests
- ✓tracks number of in-flight requests
✓buildSuggestionGroupsSearch backend2
- ✓routes assembly suggestions into their own 'Parts diagrams' group (#2664)
- ✓keeps genuine description suggestions in the descriptions group
✓EquipmentSearchResults — "Show all" honours the soft-count policyProduct grid2
- ✓omits the raw count at or above the soft-count threshold
- ✓formats a below-threshold count with thousands separators
✓junk detectionAdmin logic2
- ✓flags stock/marketplace/social sources
- ✓does not flag OEM or aggregator sources
✓adaptFiltersResponseSearch backend2
- ✓transforms filters endpoint response with facets and total
- ✓preserves total count
✓summarizeChaptersAssembly views1
- ✓counts distinct diagrams per chapter, largest first (ties broken A–Z)
✓listChapterDiagramsAssembly views1
- ✓lists a chapter's diagrams with part counts, largest first, ignoring other chapters
✓scopedPartsPanelPropsProduct features1
- ✓carries the narrowed scope the caller proved non-null
✓<ScopedPartsPanel> loadingProduct features1
- ✓shows a loading state before the model's BOM resolves
✓<ScopedPartsPanel> browse escapeProduct features1
- ✓always offers Browse all parts, even with results on screen
✓<SearchPill> aria-expanded syncProduct features1
- ✓reports the real open state instead of cmdk's hardcoded true
✓useSearchShellState focus-on-open (#921)Product features1
- ✓focuses the input once when opened and not again on later re-renders / keystrokes
✓markGenericAcrossModelsBusiness rules1
- ✓returns only URLs that appeared for more than one model
✓bomDirectoryResponseSchema — null cnhOrderability (#2969)Search backend1
- ✓parses a model whose call_for_pricing part has null cnhOrderability
✓SearchServiceDegradedErrorSearch backend1
- ✓extends SearchServiceError (so a generic catch still sees it) and is named
✓fetchIpv4 — transport failures do not retry dual-stack (#3609)Search backend1
- ✓propagates a connect failure instead of re-running it on global fetch
✓publish-status constantsSearch backend1
- ✓NO_COMMERCE_STATUSES contains no_cnh_data and dont_list (front#833 union)
✓clearInflightRequestsSearch backend1
- ✓clears all in-flight requests
✓prerender-safe clockSearch backend1
- ✓never reads Date.now while deduplicating
✓schema / type alignmentSearch backend1
- ✓partPricingSchema shape matches the PartPricing interface keys
✓sanitizePartsSearch backend1
- ✓sanitizes each part in an array
✓EquipmentSearchResults — card identityProduct grid1
- ✓keys cards by modelKey, so one modelCode shared across brands does not collide
✓features/search-bar — public barrel name snapshot (CT-1233)Search box1
- ✓re-exports exactly the documented public surface
✓domain rankingAdmin logic1
- ✓ranks OEM 0, aggregator 2, neutral 1 — matching brand-name sources too
What we walk through in a real browser8 journeys
○Parts Search FiltersBrowser journey13
- ○should display results count on catalog page
- ○should apply manufacturer filter via sidebar checkbox
- ○brand-catalog vendor pill navigates to its brand page — never a 0-result manufacturer combo @smoke
- ○sidebar Clear removes manufacturer + equipmentModelKey from the URL
- ○manufacturer filter narrows the grid below full-catalog total
- ○should apply availability filter and update results
- ○picking a category mints a clean ?categoryId= URL, whatever came before @smoke
- ○browsing a category defaults to Recommended, and an explicit pick writes sortBy
- ○clearing an explicit sort chip resets to context default, not relevance (CT-674 T6 follow-up)
- ○search mode does not apply revenue default (CT-674 T6 follow-up, search honesty)
- ○search mode: Top sellers sort surfaces highest-revenue match (CT-674 T23)
- ○should apply multiple filters together
- ○should clear all filters via active filters bar
○Search intent routing (CT-674 T2)Browser journey8
- ○amendment: cold-LRU paste of bare 4-digit model '5610' routes to /parts-diagrams/model/ (John's video bug)
- ○amendment: cold-LRU paste of bare 3-digit model '580' routes to /parts-diagrams/model/
- ○cold-LRU paste of 6-digit part number routes to /parts/{id} (PDP)
- ○generic phrase 'oil filter' routes to /parts?q= (Stage 3 fallback)
- ○single generic word 'hydraulic' routes to /parts?q=
- ○stage 1: warm-LRU equipment suggestion with slug routes directly to /parts-diagrams/model/{slug}/parts-diagrams
- ○@smoke stage 1: an exact part number outranks an assembly and lands on the part
- ○empty submit is a no-op
○Search Bar AutocompleteBrowser journey7
- ○should show suggestions when typing part number
- ○should navigate to part detail page when clicking part suggestion
- ○should navigate to equipment page when clicking equipment suggestion
- ○should navigate using keyboard in autocomplete
- ○should show equipment from browse when ES returns nothing
- ○clicking Search after typing 'oil filter' must not 404 on a modelKey URL (front#522)
- ○should clear search input when clicking clear button
○intent routing suppression when filters are activeBrowser journey4
- ○bare model token narrows within categoryId instead of teleporting
- ○preserves manufacturer filter when narrowing
- ○on clean /parts (no filters), bare model token still teleports to /parts-diagrams/model/
- ○from non-/parts pathname, bare model token still teleports
○Mobile search overlay (#2607 mobile slice)Browser journey4
- ○header search icon opens the overlay, focuses the input, and a suggestion tap navigates
- ○back button and Escape close the overlay without navigating
- ○mobile menu's search row closes the drawer and opens the overlay
- ○home hero pill's mobile diversion opens the overlay instead of the inline popover
○CT-674 T14 — BOM in-page searchBrowser journey3
- ○typing a part-number substring narrows the BOM rows and updates the count
- ○nonsense query shows the empty state with a Clear filter button that restores the list
- ○the X icon clears the filter input
○header search preserves /parts filtersBrowser journey2
- ○multi-word query keeps categoryId in URL
- ○seed pagination state is dropped on new search
○#3623 — the assembly page ships one BOM tree @smokeBrowser journey1
- ○the BOM renders once, and a row's PDP anchor is emitted once
Automated checks968
Browser journeys43
Code exercised67.8%
What we check automatically166 groups
✓#2908 — JSON-LD Offer availability never contradicts the visible badgeParts pages49
- ✓in_stock · clinton=true · live · flag=true
- ✓in_stock · clinton=true · cached · flag=true
- ✓in_stock · clinton=false · live · flag=true
- ✓in_stock · clinton=false · cached · flag=true
- ✓low_stock · clinton=true · live · flag=true
- ✓low_stock · clinton=true · cached · flag=true
- ✓low_stock · clinton=false · live · flag=true
- ✓low_stock · clinton=false · cached · flag=true
- ✓available · clinton=true · live · flag=true
- ✓available · clinton=true · cached · flag=true
- ✓available · clinton=false · live · flag=true
- ✓available · clinton=false · cached · flag=true
- ✓preorder · clinton=true · live · flag=true
- ✓preorder · clinton=true · cached · flag=true
- ✓preorder · clinton=false · live · flag=true
- ✓preorder · clinton=false · cached · flag=true
- ✓backorder · clinton=true · live · flag=true
- ✓backorder · clinton=true · cached · flag=true
- ✓backorder · clinton=false · live · flag=true
- ✓backorder · clinton=false · cached · flag=true
- ✓out_of_stock · clinton=true · live · flag=true
- ✓out_of_stock · clinton=true · cached · flag=true
- ✓out_of_stock · clinton=false · live · flag=true
- ✓out_of_stock · clinton=false · cached · flag=true
- ✓in_stock · clinton=true · live · flag=false
- ✓in_stock · clinton=true · cached · flag=false
- ✓in_stock · clinton=false · live · flag=false
- ✓in_stock · clinton=false · cached · flag=false
- ✓low_stock · clinton=true · live · flag=false
- ✓low_stock · clinton=true · cached · flag=false
- ✓low_stock · clinton=false · live · flag=false
- ✓low_stock · clinton=false · cached · flag=false
- ✓available · clinton=true · live · flag=false
- ✓available · clinton=true · cached · flag=false
- ✓available · clinton=false · live · flag=false
- ✓available · clinton=false · cached · flag=false
- ✓preorder · clinton=true · live · flag=false
- ✓preorder · clinton=true · cached · flag=false
- ✓preorder · clinton=false · live · flag=false
- ✓preorder · clinton=false · cached · flag=false
- ✓backorder · clinton=true · live · flag=false
- ✓backorder · clinton=true · cached · flag=false
- ✓backorder · clinton=false · live · flag=false
- ✓backorder · clinton=false · cached · flag=false
- ✓out_of_stock · clinton=true · live · flag=false
- ✓out_of_stock · clinton=true · cached · flag=false
- ✓out_of_stock · clinton=false · live · flag=false
- ✓out_of_stock · clinton=false · cached · flag=false
- ✓compared the whole matrix — every case shipped an Offer to check
✓generateProductSchemaParts pages44
- ✓includes required Product schema fields
- ✓includes offers with price when available
- ✓points the seller at the site-wide Organization node
- ✓resolves the Offer return policy from the shipping path
- ✓keeps the price out of Product.description but leaves it in the meta description
- ✓omits priceValidUntil (no real offer expiry to source it from)
- ✓drops offers for a purchasable:false part even when sellable and priced
- ✓keeps offers when purchasable is true or absent
- ✓offers.url + Product.url match the passed canonical URL (branded SKU)
- ✓offers.url tracks Product.url for non-branded fallback (raw PN edge case)
- ✓Product.url stays on schema when price is omitted (no offers node)
- ✓omits offers entirely when price is missing (#1287)
- ✓maps availability statuses correctly
- ✓falls back to OutOfStock when availability is null (unknown orderability)
- ✓leaves the shared mapper's null default untouched (the /parts chip fails open)
- ✓reads the part's own taxonomy field, title-cased
- ✓is omitted — never the brand — when the row carries no category
- ✓includes images from product media
- ✓leads with the CT hero (media.primaryImage), dealer angle after
- ✓emits the CT CDN URL first in the serialized JSON-LD (content marker)
- ✓does not duplicate the hero when it is already first in images[]
- ✓emits a single string (not an array) for a lone CT photo
- ✓image[0] is byte-identical to og:image (#3794)
- ✓falls back to the gallery order when there is no resolved hero
- ✓falls back to the per-brand OG image when no real part image exists (#3058)
- ✓does not use site-wide OG artwork as an unknown brand's Product.image
- ✓drops the Offer and suppresses the node for a priced imageless unknown-brand PDP (#3076)
- ✓keeps the Offer for a priced imageless known-brand PDP (per-brand OG image, #3058)
- ✓emits no Offer for a priced call_for_pricing row the upstream flags purchasable
- ✓still emits the Offer for the sellable twin of that row
- ✓never emits a CNH placeholder as Product.image
- ✓keeps a real photo as Product.image when a CNH placeholder sits beside it
- ✓emits eligibleQuantity on offers when part requires pack-buy
- ✓omits eligibleQuantity when requiresPackBuy is absent
- ✓omits eligibleQuantity when packQty is 1 (even if requiresPackBuy=true)
- ✓drops offers (and so eligibleQuantity) on price-less pack-buy parts
- ✓attaches the org-level MerchantReturnPolicy to a priced Offer
- ✓drops MerchantReturnPolicy on a price-less PDP (no offers node)
- ✓emits OfferShippingDetails for a DIS-stocked priced part
- ✓elides shippingDetails for a freight (requiresTruck) part
- ✓elides shippingDetails for a hazmat part
- ✓drops offers entirely for an unpriced part (#1287 — Merchant ineligible)
- ✓elides shippingDetails when shippingPath is unknown (insufficient PG signals)
- ✓elides shippingDetails when shippingPath is absent (legacy view-model)
✓toProductDetailViewModelParts pages39
- ✓uses shortTitle as the detail page title when available
- ✓falls back to title when shortTitle is missing
- ✓passes through enriched fitment metadata
- ✓omits enriched fitment fields when absent on Part
- ✓uses the source:'ct' photo as the hero, overriding the API primaryImage
- ✓drops own-host part images that don't reference the part's partNumber
- ✓keeps own-host part images whose URL matches the partNumber
- ✓normalizes gcp 360 frames into URL strings (strips poster frame[0])
- ✓falls back to disabled 360 view when frames are missing
- ✓preserves external 360 embeds
- ✓handles url_only 360 responses by returning external fallback
- ✓provides fallback images from primary image and 360 frames (poster stripped)
- ✓drops CNH placeholder URLs from media.images and primaryImage
- ✓yields no images when the only media is a CNH placeholder
- ✓deduplicates fitment labels into groups and related metadata
- ✓parses raw equipment key format (BRAND::MODEL::CATEGORY::...)
- ✓builds category breadcrumbs that link to filtered searches
- ✓falls back to manufacturer breadcrumb when categories are missing
- ✓keeps the faceted manufacturer crumb for a brand without an exposed hub (#1201)
- ✓derives dfs-ground for DFS parts
- ✓derives dis-stock for Clinton-in-stock parts
- ✓derives cnh-overnight for fresh depot stock (availability=in_stock, ct-3184)
- ✓omits the field when signals resolve to unknown
- ✓DFS part: both fields land on the view model
- ✓Clinton-singles part: packQty set, requiresPackBuy absent
- ✓non-pack part (no packQty/requiresPackBuy): both absent
- ✓packQty=1 on Part is omitted (backend should never emit but we guard)
- ✓absent from view model when Part has a positive clintonOnHand
- ✓absent from view model when Part has clintonOnHand=0
- ✓absent from view model when Part has explicit null clintonOnHand
- ✓absent from view model when Part has no clintonOnHand signal
- ✓produces dual layout with exact individualCap when clintonOnHand > 0
- ✓produces pack-only layout when clintonOnHand === 0
- ✓produces pack-only layout when clintonOnHand is null (no signal → no oversell)
- ✓omits dualBuyBoxLayout entirely for non-pack PNs (packQty absent)
- ✓caps to the real ceiling when known and below the fallback (no 99 oversell)
- ✓falls back to the familiar 99 range when stock is unknown
- ✓uses a large real ceiling instead of the 99 fallback
- ✓caps a part we do not stock ourselves at its depot ceiling
✓BuyBox — an in-stock chip never sits above a non-buy CTAParts pages26
- ✓in_stock · priced + purchasable
- ✓in_stock · priced, not purchasable
- ✓in_stock · unpriced, purchasable
- ✓in_stock · unpriced, not purchasable
- ✓pre_order · priced + purchasable
- ✓pre_order · priced, not purchasable
- ✓pre_order · unpriced, purchasable
- ✓pre_order · unpriced, not purchasable
- ✓backorder · priced + purchasable
- ✓backorder · priced, not purchasable
- ✓backorder · unpriced, purchasable
- ✓backorder · unpriced, not purchasable
- ✓out_of_stock · priced + purchasable
- ✓out_of_stock · priced, not purchasable
- ✓out_of_stock · unpriced, purchasable
- ✓out_of_stock · unpriced, not purchasable
- ✓discontinued · priced + purchasable
- ✓discontinued · priced, not purchasable
- ✓discontinued · unpriced, purchasable
- ✓discontinued · unpriced, not purchasable
- ✓unknown · priced + purchasable
- ✓unknown · priced, not purchasable
- ✓unknown · unpriced, purchasable
- ✓unknown · unpriced, not purchasable
- ✓the ship line goes with the chip — no same-day promise on a part we cannot sell
- ✓a sellable in-stock part keeps its chip and its ship line
✓shouldNoindexPart — CROP-front#1337 flag-gated noindex decisionParts pages21
- ✓defaults PDP_INDEXING_MODE to strict (#2912 — a silent revert to legacy must fail CI)
- ✓fails closed when registry state is missing or hold
- ✓indexes eligible and stock_grace pages
- ✓keeps the truly-empty defense even with an eligible verdict
- ✓indexes an eligible CNH part
- ✓holds a brand-catalog SKU whatever the registry says
- ✓agrees with shouldNoindexPart on a registry hold
- ✓noindexes a truly-empty PDP
- ✓noindexes a commerce-disabled dont_list row even when content-rich
- ✓noindexes a no_cnh_data row
- ✓noindexes a junk-template title even when priced and in stock
- ✓indexes a normal sellable priced part with a real title
- ✓indexes a call_for_pricing part (not commerce-disabled)
- ✓mode: legacy with no relaxed-indexing option matches the historical gate
- ✓indexes a priced junk-template part
- ✓indexes a priced dont_list part
- ✓still holds back a content-rich part with no price
- ✓always noindexes a truly-empty PDP regardless of flags
- ✓indexes a content-rich part with no price
- ✓indexes a content-rich no-price dont_list part
- ✓still noindexes a truly-empty PDP
✓CustomerAvailabilityBadgeInterface pieces19
- ✓renders the mapped label for state=in_stock
- ✓renders the mapped label for state=in_stock_limited
- ✓renders the mapped label for state=vendor_direct
- ✓renders the mapped label for state=delayed_supply
- ✓renders the mapped label for state=pre_launch
- ✓renders the mapped label for state=backorder
- ✓renders the mapped label for state=discontinued
- ✓renders the mapped label for state=unknown
- ✓never renders 'Contact Us for Availability'
- ✓defaults null/undefined to buyable 'In Stock'
- ✓renders 'Out of Stock' for an unknown + non-purchasable part
- ✓renders 'In Stock' for an unknown + purchasable part
- ✓forwards className to the underlying Badge
- ✓uses the `success` surface for in_stock
- ✓uses the `secondary` surface for backorder (ADR-0002 → Out of Stock)
- ✓uses the `success` surface for the unknown fold (default-buyable, fail-open)
- ✓renders generic 'In Stock' when clintonInStock=true and state=in_stock
- ✓renders generic 'In Stock' when clintonInStock=false and state=in_stock
- ✓does not surface 'In Stock in Clinton' under any state combination
✓isPartPurchasable — truth-table contractBusiness rules19
- ✓fixture file is non-empty (guards against accidental delete)
- ✓explicit purchasable:false dominates a sellable, in-stock part -> false
- ✓explicit purchasable:false dominates even with no other blocking signal -> false
- ✓explicit purchasable:false dominates an already-blocked part (double block) -> false
- ✓sellable + in_stock is purchasable -> true
- ✓sellable + out_of_stock blocks on availability alone -> false
- ✓sellable + unknown availability defers to backend authority (buyable) -> true
- ✓dont_list + in_stock blocks on publishStatus alone -> false
- ✓dont_list + out_of_stock blocks on both axes (CROP-0000023 incident shape) -> false
- ✓dont_list + unknown availability still blocks on publishStatus -> false
- ✓no_cnh_data + available blocks on publishStatus alone -> false
- ✓no_cnh_data + out_of_stock blocks on both axes -> false
- ✓no_cnh_data + unknown availability still blocks on publishStatus -> false
- ✓unknown publishStatus + in_stock is purchasable (legacy/unknown defers) -> true
- ✓unknown publishStatus + out_of_stock blocks on availability alone -> false
- ✓both signals absent defers to backend authority (buyable) -> true
- ✓explicit purchasable:true plus sellable plus unknown availability is purchasable -> true
- ✓explicit purchasable:true does not override a dont_list publishStatus -> false
- ✓explicit purchasable:true does not override an out_of_stock availability -> false
✓CustomerAvailabilityBadge — matrix (R9 pin, post-2026-05-13 channel-leak rule)Interface pieces18
- ✓state='in_stock' renders label='In Stock' variant='success'
- ✓state='in_stock_limited' renders label='In Stock' variant='success'
- ✓state='vendor_direct' renders label='In Stock' variant='success'
- ✓state='delayed_supply' renders label='In Stock' variant='success'
- ✓state='pre_launch' renders label='In Stock' variant='success'
- ✓state='backorder' renders label='Out of Stock' variant='secondary'
- ✓state='discontinued' renders label='Out of Stock' variant='secondary'
- ✓state='unknown' renders label='In Stock' variant='success'
- ✓state=null renders label='In Stock' variant='success'
- ✓state='in_stock' still renders label='In Stock' variant='success'
- ✓state='in_stock_limited' still renders label='In Stock' variant='success'
- ✓state='vendor_direct' still renders label='In Stock' variant='success'
- ✓state='delayed_supply' still renders label='In Stock' variant='success'
- ✓state='pre_launch' still renders label='In Stock' variant='success'
- ✓state='backorder' still renders label='Out of Stock' variant='secondary'
- ✓state='discontinued' still renders label='Out of Stock' variant='secondary'
- ✓state='unknown' still renders label='In Stock' variant='success'
- ✓state=null still renders label='In Stock' variant='success'
✓<FitsYourMachineBadge>Parts pages15
- ✓renders the badge with the nickname when a single garage record matches
- ✓falls back to brand-display + modelName when nickname is null
- ✓normalises short-form brand codes (NH -> New Holland) in the fallback
- ✓summarises multi-match as 'Fits N of your machines' with names + count in aria-label
- ✓exposes role='status' on the badge so screen readers announce the async update
- ✓renders nothing when the part has no fitment keys (no fetch fired)
- ✓renders nothing when the garage is empty
- ✓renders nothing when the garage has equipment but none match the part
- ✓renders nothing for signed-out users and does not fire a garage fetch
- ✓renders nothing while Clerk auth is still loading and does not fire a garage fetch
- ✓renders nothing on garage fetch error and does not surface a toast or fallback UI
- ✓reserves badge-row height while the garage query is pending so the surrounding layout doesn't shift
- ✓does not reserve space pre-query when the user is signed-out (no anonymous CLS)
- ✓does not reserve space pre-query when the part has no fitment keys
- ✓reuses a pre-warmed cache entry without firing a fetch (cache warm-share with /account/garage)
✓notFoundIfUnpublishableParts pages13
- ✓404s a "dont_list" part with neither a price nor an image (front#3698)
- ✓no-op for a "dont_list" part that carries a price (the relaxed-indexing cohort)
- ✓no-op for a "dont_list" part that carries an image
- ✓404s every "no_cnh_data" part, priced or not (front#3698)
- ✓no-op for publishStatus="sellable"
- ✓no-op for publishStatus="call_for_pricing"
- ✓no-op for publishStatus="superseded_sellable" (orderable mid-chain)
- ✓fail-open on undefined publishStatus (no notFound, warning goes to Sentry)
- ✓no-op for publishStatus="obsolete_no_supersession" (pending Alex signoff)
- ✓tags pdp.unpublishable_404 in Sentry when it withdraws a part
- ✓does NOT tag Sentry on a priced dont_list part that stays reachable
- ✓does NOT tag Sentry on known sellable status
- ✓emits pdp.missing_publishStatus warning when publishStatus is undefined
✓isPdpTrulyEmptyParts pages12
- ✓returns true when no description, no image, no price, no fitment
- ✓returns true for empty string description
- ✓returns true for short description under 20 chars
- ✓returns false for description >= 20 chars
- ✓returns false when descriptionHtml strips to >= 20 chars
- ✓returns true when descriptionHtml strips to < 20 chars
- ✓returns false when primaryImage exists
- ✓returns false when images array has items
- ✓returns false when price exists (including $0)
- ✓returns false when price has a positive value
- ✓returns false when fitment data exists
- ✓returns false when fitmentLabels exist
✓getMatrixLabel — badge string per DisplayState (3-status allowlist)Business rules10
- ✓'in_stock' → badge='In Stock'
- ✓'in_stock_limited' → badge='In Stock'
- ✓'vendor_direct' → badge='In Stock'
- ✓'delayed_supply' → badge='In Stock'
- ✓'pre_launch' → badge='In Stock'
- ✓'backorder' → badge='Out of Stock'
- ✓'discontinued' → badge='Out of Stock'
- ✓'unknown' → badge='In Stock'
- ✓every returned badge is on the customer-facing allowlist
- ✓never emits channel-hint substrings on customer-facing badges
✓isPartPurchasableBusiness rules10
- ✓blocks the CROP-0000023 part (dont_list + out_of_stock)
- ✓blocks commerce-disabled publishStatus even when availability is buyable
- ✓blocks out_of_stock even when publishStatus is sellable
- ✓allows a normal sellable, in-stock part
- ✓allows when both signals are absent (legacy/unknown → backend authority)
- ✓blocks an explicit purchasable:false even when sellable and unrestricted
- ✓allows an explicit purchasable:true sellable part
- ✓treats an absent purchasable flag as backend authority (buyable)
- ✓blocks a priced, available row the upstream still flags purchasable (CT-NHL-06404120C)
- ✓keeps blocking the row whose upstream flag already agrees (CT-AGC-000050147)
✓buildPartCanonical — branded canonical invariantParts pages10
- ✓derives /parts/ct-{BRAND}-{partNumber} from partNumber + manufacturer
- ✓is stable when title / shortTitle / description mutate
- ✓prefers the backend seo.canonicalHref (division-aware) over local synthesis (#2911)
- ✓falls back to local synthesis when seo is absent (prod Hono predates #702)
- ✓falls back to local synthesis when the backend SKU is empty (never emits an empty canonical)
- ✓percent-encodes the backend canonical SKU on the seo-preferred branch (#3650)
- ✓is stable when slug mutates (Phase 2: manufacturer DOES shift canonical)
- ✓falls back to the dynamic-route id when partNumber is missing
- ✓emits raw /parts/{PN} when manufacturer is absent (defensive fallback)
- ✓negative: mutating partNumber DOES change the canonical
✓buildPdpMetaFields — CROP-front#3302 the <title> keeps both the PN and the brand under truncationParts pages10
- ✓New Holland: an enriched title that already ends in the PN keeps the PN and the brand when the head overflows
- ✓Ferris: the brand suffix survives when the PN suffix forces a head cut
- ✓a PN buried mid-head is neither duplicated nor lost when the head is cut
- ✓keeps the brand in the head (no suffix duplicate) when the cut leaves it intact
- ✓New Holland PX64D00009F1 — the live front#3302 row carries brand and PN
- ✓New Holland 87605245 — the live front#3302 row carries brand and PN
- ✓Ferris 1608395 — the live front#3302 row carries brand and PN
- ✓Marcrest 631220 — the live front#3302 row carries brand and PN
- ✓McHale CBR00263 — the live front#3302 row carries brand and PN
- ✓a PN wrapped in parentheses is lifted out of the head, not duplicated in the suffix
✓buildBreadcrumbs — category source precedenceParts pages10
- ✓prefers part.breadcrumbs over every other source
- ✓drops non-string and blank breadcrumb entries, then falls through to categoryPath
- ✓splits the LAST categoryPath entry on '>' when breadcrumbs are absent
- ✓falls through to categoryName when categoryPath is empty
- ✓drops blank categoryName entries
- ✓uses a string category as a single crumb
- ✓ignores the generic 'parts' string category
- ✓uses the first node's name from an array category
- ✓ignores an array category whose first node is named 'parts'
- ✓ignores an array category whose first node carries no name
✓buildPartArticleParts pages10
- ✓composes every block, link and heading from a fully-populated part
- ✓returns null when no fitment, supersession or spec backs an article
- ✓writes the article on supersession data alone
- ✓drops the brand from the lead unless BOTH brand and part number are known
- ✓falls back to 'part' as the noun and capitalises the heading
- ✓uses 'What it fits' and the generated fit phrase when both are unknown
- ✓names at most the top three models
- ✓writes the spec block from dimensions alone or material alone
- ✓keeps only the last three linkable crumbs and never the current page
- ✓skips the brand link when the manufacturer has a partsHref but no name
✓_pdp-route.tsx wiringParts pages9
- ✓PartDetailPage invokes notFoundIfUnpublishable on the fetched part
- ✓generateMetadata invokes notFoundIfUnpublishable on corePart
- ✓PartDetailPage invokes redirectIfSuperseded after the unpublishable guard
- ✓imports both guards from ./_guards (no drift to a different module)
- ✓carries NEITHER revalidate NOR force-dynamic segment config (build-invalid under cacheComponents)
- ✓does NOT call fetchLivePartStatus server-side in the page (the live re-check crutch is removed)
- ✓does NOT read request headers() in the page (JSON-LD host must stay SITE_URL, not request-derived)
- ✓builds the JSON-LD product URL from SITE_URL (not the request host)
- ✓eParts client does not pass cache: 'no-store' alongside next.revalidate
✓getMatrixLabel — shippingLine is null for every state (channel-leak rule)Business rules8
- ✓in_stock → shippingLine === null
- ✓in_stock_limited → shippingLine === null
- ✓vendor_direct → shippingLine === null
- ✓delayed_supply → shippingLine === null
- ✓pre_launch → shippingLine === null
- ✓backorder → shippingLine === null
- ✓discontinued → shippingLine === null
- ✓unknown → shippingLine === null
✓reconcileAvailability — live signal wins when informativeBusiness rules8
- ✓propagates live=in_stock and tags source=live
- ✓propagates live=in_stock_limited and tags source=live
- ✓propagates live=vendor_direct and tags source=live
- ✓propagates live=delayed_supply and tags source=live
- ✓propagates live=pre_launch and tags source=live
- ✓propagates live=backorder and tags source=live
- ✓propagates live=discontinued and tags source=live
- ✓propagates clintonInStock through to the result
✓reconcileAvailability — falls through to cached when live is null/unknownBusiness rules8
- ✓uses cached when live is null
- ✓uses cached when live is 'unknown' (live is uninformative)
- ✓maps cached='in_stock' → state='in_stock'
- ✓maps cached='low_stock' → state='in_stock_limited'
- ✓maps cached='preorder' → state='pre_launch'
- ✓maps cached='available' → state='vendor_direct'
- ✓maps cached='backorder' → state='backorder'
- ✓maps cached='out_of_stock' → state='discontinued'
✓buildPdpMetaFields — CROP-front#1345 bare PN secondary suffix in <title>Parts pages8
- ✓appends the bare PN after a brand-bearing enriched title
- ✓appends the bare PN after the added brand suffix when the title omits the brand
- ✓does NOT duplicate the PN when the enriched title already contains it
- ✓never substitutes the SKU when source partNumber is absent
- ✓truncates the descriptive head (keeps the PN intact) when appending it would overflow the budget
- ✓truncates the shared head differently per PN, so two same-headed parts never collide
- ✓never exceeds the 70-char SERP budget when the PN is appended
- ✓leaves the PN-only / junk-template fallback path unchanged (PN already in fallback)
✓buildPdpMetaFields — imageless first-image fallbackParts pages8
- ✓returns the prebuilt per-brand OG image when no part image exists
- ✓falls back to the site-wide OG image when the brand slug is unknown
- ✓uses media.primaryImage when set (fallback NOT applied)
- ✓uses media.images[0].url when primaryImage is absent (fallback NOT applied)
- ✓supplies a deterministic brand-aware imageAlt on the fallback path
- ✓imageAlt falls back to the title when the part has no brand
- ✓uses the part image alt text on the real-image path
- ✓aligns imageAlt with the CT hero, not a non-hero gallery angle
✓resolvePartForRoute (front#1610)Parts pages8
- ✓routes a brand-catalog SKU to getCachedBrandCatalogPart, NOT the public part path
- ✓routes CT-VNT-49001 to getCachedBrandCatalogPart, NOT the public part path
- ✓routes CT-MCH-CST00094 to getCachedBrandCatalogPart, NOT the public part path
- ✓routes CT-MAR-100-0210 to getCachedBrandCatalogPart, NOT the public part path
- ✓routes CT-KUH-K5012340 to getCachedBrandCatalogPart, NOT the public part path
- ✓returns null for a brand-catalog SKU whose PN is absent (404 -> null)
- ✓strips a CNH branded SKU to its bare PN and goes through fetchPartCore (public path)
- ✓passes an SEO slug straight through fetchPartCore (CNH/legacy path)
✓shouldEmitProductSchema (#3027 — no bare Product node)Parts pages8
- ✓true for a priced, purchasable part
- ✓false for a price-less part (no Offer, no rating)
- ✓false for a zero-priced part (mirrors priceValueOrNull)
- ✓false for a priced part flagged purchasable:false
- ✓false for a commerce-disabled status even when priced (no_cnh_data)
- ✓true for a price-less part carrying a genuine rating (Product + AggregateRating)
- ✓false for a fake rating (reviewCount 0) on a price-less part
- ✓predicate agrees with the built schema across the matrix
✓StaffInventoryPanel — CNH-fallback statesParts pages8
- ✓renders cnh_depot state with CNH Depot label + 3-5 day lead time
- ✓renders vendor_direct state with Vendor Direct label + special-order copy
- ✓renders unavailable state with Contact CNH copy
- ✓renders the CNH depot-stock chip with its check date next to orderability
- ✓drops the depot chip when the catalog service omits the field (older backend)
- ✓renders unavailable with no orderability badge when signals null (degraded mode)
- ✓renders CNH-fallback + composite-PK rows when Clinton tracks the part but shelf is empty
- ✓renders 'not configured' note when the route reports configured=false
✓buildDiagramSpotlightParts pages8
- ✓returns null when no diagram has a schematic
- ✓returns the schematic with focus=null when callout coords are missing
- ✓prefers a diagram that has BOTH a schematic and callout coords
- ✓centers the crop + marker on a centered callout (square image)
- ✓clamps the crop to the edge and the marker to the [6,94] floor for a corner callout
- ✓caps the crop window at MAX_FRAC (72% of the shorter side) for an oversized callout
- ✓keeps a uniform scale on a non-square image (no distortion)
- ✓never produces NaN/Infinity for a zero-area callout box
✓parseFitmentLabels — free-text labelsParts pages8
- ✓buckets a separator-less label under 'Other equipment' with no identifier
- ✓splits category off the first ' - ' and lifts a trailing (identifier)
- ✓splits on the FIRST ' - ', keeping later ones inside the category
- ✓only lifts an identifier anchored at the end of the summary
- ✓leaves nested parentheses alone (the identifier pattern rejects them)
- ✓turns two MM/YY tokens into a year range and strips them from the summary
- ✓current behaviour: with three MM/YY tokens the range takes the LAST two, but all are stripped
- ✓keeps a lone MM/YY token in the summary and emits no year range
✓pdpAvailabilityView — strict 3-state customer view (#2626)Parts pages8
- ✓Clinton on-shelf in-stock → In Stock + same-day ship line
- ✓CNH-available (not on Clinton's shelf) → In Stock + 3-5 business days
- ✓an affirmative live back-order fails the in-stock row closed to Out of Stock
- ✓every non-in-stock state → Out of Stock, no ship line
- ✓a per-vendor shipLineOverride replaces the sourced default when we do not hold the part (#2518)
- ✓on the Clinton shelf outranks the per-vendor band — same day wins (#3205)
- ✓shipLineOverride is ignored on an Out of Stock row (no ship line at all)
- ✓never renders a channel / lifecycle / vendor word
✓admin price edit widgetAdmin editing7
- ✓offers the price edit trigger for an admin with the toggle on, keeps the price child
- ✓shows the current price read-only + a proposed input and files a price-review issue
- ✓renders NO trigger in prod even for an admin with the toggle on
- ✓renders the trigger for staff
- ✓renders NO trigger for a customer
- ✓renders NO trigger when the toggle is off
- ✓renders NO trigger for an anonymous visitor
✓resolveBomRowAvailability — fallback chainAssembly views7
- ✓prefers live displayState when present
- ✓falls back to snapshot when live is undefined
- ✓snapshot 'call_us' maps to DisplayState 'discontinued' (existing label collapse)
- ✓snapshot 'unclear' maps to DisplayState 'unknown'
- ✓returns source='none' when both live and snapshot are missing
- ✓explicit null snapshot (legacy hono) treats the same as missing
- ✓live with falsy displayState falls through to snapshot (defensive)
✓shippingLineForCachedAvailability — eParts-down fallback returns null on customer surfacesBusiness rules7
- ✓availability=in_stock → null (channel-leak rule)
- ✓availability=low_stock → null (channel-leak rule)
- ✓availability=preorder → null (channel-leak rule)
- ✓availability=available → null (channel-leak rule)
- ✓availability=backorder → null (channel-leak rule)
- ✓availability=out_of_stock → null (channel-leak rule)
- ✓returns null for null cached availability
✓buildPdpMetaFieldsParts pages7
- ✓leads equipment-first with the enriched title + brand (#1098)
- ✓appends the brand when the enriched title omits it (#1098)
- ✓falls back to partNumber · manufacturer when the title is just the PN (#1098)
- ✓enriches thin description from product.description
- ✓enriches thin description from stripped descriptionHtml
- ✓keeps long description as-is
- ✓uses enriched fallback when no description at all
✓isFixedShapeTitle (CROP-front#781 — description fitment bug guard)Parts pages7
- ✓accepts any non-empty title for small-N parts (<= 3 fitments)
- ✓rejects a cross-fit title that names a single fitment model (the bug)
- ✓accepts a fixed-shape cross-fit title (spec summary, no model name)
- ✓accepts a count-framed cross-fit title (hono#146 tier-3 shape)
- ✓rejects an empty title regardless of fitment count
- ✓only checks model names against cross-fit parts
- ✓keeps cross-fit titles within the 70-char SERP length budget when fixed-shape
✓extractPnFromSlugParts pages7
- ✓extracts trailing numeric PN from canonical SEO slug
- ✓extracts alphanumeric PNs with digits
- ✓rejects slugs whose tail contains no digit (phrase, not PN)
- ✓rejects SKU format (CT-XXX-) — treated as id, not slug
- ✓rejects bare PN (no hyphen segments)
- ✓rejects a bare PN whatever its casing (PN input, not SEO slug)
- ✓rejects a hyphenated part number rather than splitting it
✓fetchPartCoreParts pages7
- ✓returns part from ID lookup on first try
- ✓falls back to slug lookup when ID returns null
- ✓recovers the part from a canonical SEO slug by extracting the PN tail
- ✓does NOT do fuzzy search — nonexistent PN returns null instead of off-by-N
- ✓returns null when ID, slug, and PN recovery all miss
- ✓propagates network errors from getCachedPartById
- ✓propagates network errors from recovery getCachedPartById call
✓#3546 — the Offer carries the availability the badge is computed fromParts pages7
- ✓backorder + five on the shelf reads InStock in the Offer
- ✓available + five on the shelf reads InStock in the Offer
- ✓out_of_stock + five on the shelf reads InStock in the Offer
- ✓backorder + five on the shelf feeds Google in_stock
- ✓available + five on the shelf feeds Google in_stock
- ✓out_of_stock + five on the shelf feeds Google in_stock
- ✓leaves a part that is genuinely off the shelf alone
✓StaffInventoryPanel — role gating (client)Parts pages7
- ✓renders nothing (no DOM, no fetch) for anonymous (role=customer fallback)
- ✓renders nothing while Clerk is still loading
- ✓renders the panel + 'Staff' badge for role=staff
- ✓renders the panel + 'Admin' badge for role=admin
- ✓renders the panel + 'Staff' badge for role=manager (BI-shared Clerk)
- ✓renders nothing (no DOM, no fetch) for role=viewer (BI-only tier)
- ✓renders nothing when the route returns 204 (defence-in-depth, even if role read says staff)
✓buildAboutFitmentSummaryParts pages7
- ✓returns the 'list' tier with every model enumerated for N <= 10
- ✓returns the 'grouped' tier with families for N 11-50
- ✓returns the 'rollup' tier with family rollup + full list for N 51-200
- ✓returns the 'brand' tier with NO enumeration for N > 200
- ✓dedupes models by display name before tiering (hono#146 'U80C, U80C' fix)
- ✓sorts families largest-first
- ✓returns an empty summary for zero models
✓toRelatedCard (bought-together)Parts pages7
- ✓builds the branded canonical path from the manufacturer code + partNumber
- ✓drops an index-held row instead of linking its /lookup twin
- ✓falls back to the encoded bare PN when the vendor code is unknown
- ✓falls back to the slug for a PN-less row (no branded canonical to build)
- ✓falls back to the id when a PN-less row has no slug either
- ✓prefers the backend canonical sku over the request-side vendor code
- ✓encodes the slug fallback
✓parseFitmentLabels — structured equipment keysParts pages7
- ✓parses a fully-populated key into one grouped item
- ✓title-cases the underscored category and always sets identifier to the brand
- ✓omits yearRange when only yearFrom is known
- ✓omits yearRange when only yearTo is known
- ✓omits yearRange when the key carries no year segments at all
- ✓falls back to the free-text parser when the key has fewer than three segments
- ✓falls back to the free-text parser when a leading segment is empty
✓extractFramesParts pages7
- ✓maps string frames through the CDN and strips the poster frame at index 0
- ✓keeps a lone frame — the poster strip only applies from two frames up
- ✓carries row and col when both are numbers
- ✓keeps a zero row/col (0 is a valid grid index, not a missing value)
- ✓omits row/col keys when they are absent or null
- ✓drops unusable entries BEFORE the poster strip, so the strip counts valid frames
- ✓returns an empty list for a non-array, undefined, or empty frames field
✓buildSpecRowsParts pages7
- ✓emits identity and technical rows in source order from a full product
- ✓skips the tautological 'Part type: Part' row
- ✓defaults the weight unit to kg
- ✓omits the SKU row when the SKU merely repeats the part number
- ✓keeps the first value for a duplicated label, case-insensitively
- ✓drops empty, null and undefined specification values but keeps a literal zero
- ✓returns an empty sheet when nothing is known
✓getMatrixLabel — confirmed option is ignored (fixed orderability line)Business rules6
- ✓in_stock stays 'In Stock' (in_stock, success) for any confirmed value
- ✓in_stock_limited stays 'In Stock' (in_stock, success) for any confirmed value
- ✓vendor_direct stays 'In Stock' (in_stock, success) for any confirmed value
- ✓delayed_supply stays 'In Stock' (in_stock, success) for any confirmed value
- ✓pre_launch stays 'In Stock' (in_stock, success) for any confirmed value
- ✓backorder / discontinued stay 'Out of Stock' for any confirmed value
✓redirectIfSupersededParts pages6
- ✓permanent-redirects to the BRANDED replacement canonical on superseded_redirect
- ✓falls back to the bare replacement PN when the part has no brand code
- ✓redirects to the FINAL replacement's branded canonical for a multi-step chain (A->B->C)
- ✓no-op on self-loop (finalReplacementPn === partNumber)
- ✓no-op when finalReplacementPn is null
- ✓no-op for non-"superseded_redirect" status (even with finalReplacementPn set)
✓buildPdpMetaFields — CROP-front#3302 overflow invariantsParts pages6
- ✓strips EVERY occurrence of the PN from the head, not just the first
- ✓keeps the PN when brand + PN leave no room for a head
- ✓New Holland PX64D00009F1 — budget, PN present exactly once
- ✓New Holland Construction PX64D00009F1234 — budget, PN present exactly once
- ✓Harvest Tec CBR00263 — budget, PN present exactly once
- ✓Ferris 1608395 — budget, PN present exactly once
✓buildEnrichedDescription (#1882 — de-templated narrative)Parts pages6
- ✓never emits the old fixed template
- ✓leads with a named fitment model for a dimensionless part
- ✓leads with parsed dimensions when the title carries them
- ✓surfaces the PN in the description
- ✓stays within the 160-char SERP budget for a verbose part
- ✓CROP-front#3060 — gives two nameless parts sharing every fact except PN distinct descriptions
✓useNotifyWhenBackParts pages6
- ✓returns a return URL carrying the pathname + notify marker
- ✓resumes once on ?notify=1 when signed in: registers the alert and strips the param
- ✓preserves unrelated query params when stripping notify
- ✓does not resume when signed out
- ✓does not resume without the notify marker
- ✓registerAlert triggers the stock-alert action directly
✓AssemblyContextBar (front#1311)Parts pages6
- ✓renders the trail from stored context with a back link carrying ?highlight=
- ✓renders nothing for a direct/catalog visitor (no stored context)
- ✓renders nothing when the stored context is for a different part (stale guard)
- ✓omits ?highlight= on the back link when no ref was captured
- ✓matches via replacedFrom when a superseded part redirected to its replacement (#1319)
- ✓renders nothing when replacedFrom matches neither the current nor the stored part
✓buildBreadcrumbs — manufacturer crumb href precedenceParts pages6
- ✓prefers an available brand's landing hub over every supplied option
- ✓falls back to options.partsHref when the vendor code has no available config
- ✓falls back to the encoded options.slug when no partsHref is supplied
- ✓falls back to the encoded vendor code when no options are supplied
- ✓falls back to the encoded name when the manufacturer carries no code
- ✓labels and links a missing manufacturer as the literal 'Manufacturer'
✓buildBreadcrumbs — redundant trailing crumbParts pages6
- ✓pops a last crumb equal to the resolved title
- ✓pops a last crumb equal to the description
- ✓pops a last crumb that starts with the part number
- ✓pops the only crumb, leaving no category rung at all
- ✓keeps a last crumb that merely contains the title
- ✓keeps every crumb when the part number is empty (no blanket startsWith match)
✓toMedia360View — gcpParts pages6
- ✓returns the stripped frames with rows/columns on a fully-populated view
- ✓omits rows/columns when they are not numbers
- ✓falls back to the external URL when no frame survives extraction
- ✓falls back to sourceUrl when there is no externalUrl
- ✓prefers externalUrl over sourceUrl
- ✓returns the none view when there are neither frames nor a fallback URL
✓buildPartFaqParts pages6
- ✓emits a fitment Q&A keyed to the part's own models
- ✓emits a dimensions Q&A only when dimensions are parseable
- ✓emits a supersession Q&A when superseded
- ✓omits questions whose data is absent rather than templating empties
- ✓produces distinct fitment answers across different parts
- ✓tags data-driven entries with the data source
✓buildHeroBulletsParts pages6
- ✓prefers the supplied bullet points, trimmed and blank-filtered
- ✓caps supplied bullet points at six
- ✓generates every bullet from a fully-populated fact sheet
- ✓falls back to the model-count phrase when there is no fitment summary
- ✓treats a blank fitment summary as absent
- ✓emits nothing when no fact backs a bullet (never templates a blank)
✓buildFitmentRowsParts pages6
- ✓builds rows from fitment models and joins the matching fitment record
- ✓matches the fitment record ignoring case and whitespace
- ✓falls back through displayName, humanized product type, and brand for the series
- ✓falls back to the raw fitment records when no models are supplied
- ✓returns nothing when there is neither a model list nor a fitment record
- ✓truncates both paths at 60 rows
✓pdpRenderedValidlyProduct page5
- ✓accepts a sellable PDP
- ✓accepts an Out-of-Stock PDP, which emits no Add-to-cart CTA
- ✓accepts a categoryless PDP, which emits no breadcrumb trail
- ✓rejects the not-found body, whose bundled flight payload still names the segment
- ✓rejects ServiceUnavailable
✓resolveEffectivePart — supersession resolverAssembly views5
- ✓returns own PN when row is not superseded
- ✓returns own PN when fromReplacement is unset
- ✓returns finalReplacementPn (terminal) when fromReplacement and chain is set
- ✓falls back to currentReplacementPn when finalReplacementPn is null
- ✓defensively falls back to own PN when fromReplacement is set but no replacement PN exists
✓the 'Add all in-stock' selection never takes a part the snapshot deniesAssembly views5
- ✓excludes a call_us snapshot — the depot-RED shape (search#890)
- ✓excludes an unclear snapshot — no depot reading is not a stock claim
- ✓excludes a row with no snapshot at all
- ✓still includes an in_stock snapshot — the guard must not empty the CTA
- ✓a live signal still outranks the snapshot in both directions
✓availabilityConfirmed — relabel flag gateBusiness rules5
- ✓returns undefined when the flag is OFF (back-compat — labels unchanged)
- ✓flag ON: a live CNH signal is confirmed
- ✓flag ON: Clinton on-shelf stock is confirmed
- ✓flag ON: cached-orderability-only is UNconfirmed (the $10k-kit case)
- ✓flag ON: null/undefined reconciled is unconfirmed
✓recordReconcileObservability — live=unknown with informative cachedBusiness rules5
- ✓fires availability.live_unknown_cached_present when cached=in_stock + live=unknown
- ✓does NOT fire when cached=out_of_stock + live=unknown (terminal cached state, divergence is expected)
- ✓does NOT fire when cached=backorder + live=unknown (divergence is expected)
- ✓does NOT fire when live is informative (live wins, no warning)
- ✓does NOT fire when live=null + cached present (informative cached, expected fallback path)
✓resolveStockBackedAvailabilityBusiness rules5
- ✓treats positive Clinton stock as in-stock availability
- ✓does not let checked-none or secondary stock rewrite availability
- ✓no price outranks shelf stock
- ✓a priced part on the shelf still elevates
- ✓an omitted listPrice is 'not evaluated', so a caller that forgets it changes nothing
✓selectSpecModels — front#3009 vendor-model skipParts pages5
- ✓skips brand-catalog vendor models (they 404 on the CNH-only specs route)
- ✓keeps CNH / null-brand models
- ✓skips non-equipment sub-line models (they 404 on /equipment/{slug})
- ✓keeps equipment models whose sub_line is null or a real line
- ✓dedupes by display name and keeps CNH models when mixed with vendor ones
✓fetchYouTubeVideosParts pages5
- ✓returns empty result when api key is missing
- ✓splits shorts and regular videos by fetched duration
- ✓returns empty result when search endpoint fails
- ✓falls back to latest channel videos when brand query is empty
- ✓includes all search results regardless of channel (search is channel-scoped)
✓front#833 — priced RED / out_of_stock parts must still not 404Parts pages5
- ✓the exact 9624450 payload does NOT trigger notFound()
- ✓RED orderability + out_of_stock availability with dont_list does NOT trigger notFound()
- ✓no_cnh_data DOES 404 now — front#3698 withdrew that cohort outright
- ✓sellable parts continue to render normally
- ✓call_for_pricing parts continue to render (out-of-stock CTA path)
✓notFoundIfIndexHeld — the 404 half of the index verdict (#3827)Parts pages5
- ✓404s a registry-held part so it cannot answer 200 with a noindex tag
- ✓leaves an eligible part alone
- ✓renders the same part at /lookup, where the gate is off
- ✓opts a missing registry block out of the cache instead of 404ing on it
- ✓does nothing at all while the flag is off
✓isJunkTemplatePdp (CROP-front#831 — noindex gate predicate)Parts pages5
- ✓flags the upstream junk template
- ✓does NOT flag a PDP with a real human-readable title (regression guard)
- ✓does NOT flag the metadata-fallback title (`PN · Manufacturer`)
- ✓does NOT flag a count-framed cross-fit title
- ✓does NOT flag when manufacturer is missing on the view-model
✓buildPdpMetaFields — CROP-front#781 fixed-shape title tripwireParts pages5
- ✓emits a Sentry breadcrumb when a cross-fit title names a fitment model
- ✓does not fire for a fixed-shape cross-fit title
- ✓does not fire for a small-N part that names its fitment model (correct)
- ✓does not fire when fitmentCount is absent
- ✓also catches a leaked model name from fitmentLabels on a cross-fit part
✓checkSearchServiceHealthParts pages5
- ✓returns healthy when status=ok
- ✓returns healthy when legacy ok=true
- ✓returns unhealthy with error message when status=error
- ✓returns SERVICE_DEGRADED when ok=false
- ✓returns API_UNREACHABLE when health endpoint throws
✓AssembliesSectionParts pages5
- ✓renders a responsive grid (matches the streamed fallback shape)
- ✓pins the schematic image to its aspect box (h-full, never h-auto)
- ✓links the canonical assembly slug when the payload carries one
- ✓falls back to the assemblyCode when the vendor has no slug row
- ✓renders the branded wordmark placeholder for a schematic-less tile
✓BuyBox — strict 2-state availability badge + ship line (#2626)Parts pages5
- ✓a Clinton on-shelf part reads In Stock + usually ships same day
- ✓a CNH-available (not Clinton) part reads In Stock + 3-5 business days
- ✓an out-of-stock part reads Out of Stock with no ship line
- ✓an unknown-availability part reads Out of Stock with no ship line
- ✓leaks no channel / lifecycle word into the availability badge area
✓BuyBox — Out of Stock disables the buy CTA → notify (#2626)Parts pages5
- ✓out_of_stock: shows "Notify me when back", never Add to cart / Buy Now
- ✓unknown: shows "Notify me when back", never Add to cart / Buy Now
- ✓pre_order: shows "Notify me when back", never Add to cart / Buy Now
- ✓backorder: shows "Notify me when back", never Add to cart / Buy Now
- ✓in-stock control keeps the active buy CTA and shows no notify affordance
✓DiagramsExplorerParts pages5
- ✓renders the diagrams as a real table
- ✓every diagram is still reachable — one link per row, in order
- ✓rows past the cap stay in the DOM, hidden — crawlers still index them
- ✓the List / By model toggle is a native fieldset named by a hidden legend
- ✓By model renders one captioned table per machine and hides nothing
✓generateProductSchema — Offer drop on Merchant-ineligible rows (#1287)Parts pages5
- ✓priced part: offers present with price + currency + availability + return-policy + shipping
- ✓price-less part: offers === undefined (not a partial Offer object)
- ✓zero-priced part: offers === undefined (mirrors priceValueOrNull)
- ✓freight priced part: offers present with price, shippingDetails undefined (#1244)
- ✓price-less + image-less: no crash, no offer, image falls back per-brand
✓ReplacedBanner (#2536 — v2 PDP supersession explanation)Parts pages5
- ✓renders the green status banner naming both PNs on a replaced_from landing
- ✓renders nothing on a direct landing (no replaced_from param)
- ✓renders nothing on a self-redirect (old PN equals current PN)
- ✓renders nothing when the param is whitespace-only
- ✓renders nothing when the current PN is missing
✓FitmentTableParts pages5
- ✓renders a real table with a caption and column headers
- ✓the model cell is a row header, so a screen reader announces it with each cell
- ✓omits Years and Circuit while every row leaves them blank
- ✓grows to four columns as soon as one row carries the data
- ✓keeps the FitmentSearch island contract: .fit-tr rows carrying data-fit and data-of
✓pickAboutFitmentTier — must stay in sync with CROP-search-hono#146Parts pages5
- ✓classifies N <= 10 as 'list'
- ✓classifies N 11-50 as 'grouped'
- ✓classifies N 51-200 as 'rollup'
- ✓classifies N > 200 as 'brand'
- ✓uses the exact cutoffs from hono#146 (10 / 50 / 200)
✓relatedCardsFromRichParts pages5
- ✓links the branded sku, not the raw partNumber
- ✓drops rows with no resolvable sku (never emits a raw-PN hop link)
- ✓encodes a sku that carries a URL-special char
- ✓drops a brand-held sku when the 404 gate flag is on
- ✓returns an empty list for undefined input
✓buildKeySpecChipsParts pages5
- ✓chips dimensions, then material, then specification values
- ✓drops a value longer than 28 characters and keeps one exactly at the limit
- ✓de-duplicates case-insensitively and skips null values
- ✓caps the list at five chips
- ✓returns nothing when the part carries no chippable attribute
✓buildPrice (primary display — list only, CT-674)Parts pages5
- ✓returns list value when both list and net are populated (ignores dealer cost)
- ✓returns list value when only list is set
- ✓returns undefined when list is null even if net is populated (don't leak dealer cost)
- ✓returns undefined when neither list nor net is set
- ✓includes formatted currency string
✓sortFitmentModelsParts pages5
- ✓orders by assemblyCount DESC
- ✓ties broken alphabetically by displayName
- ✓all-zero counts fall back to alphabetical
- ✓empty input returns empty array
- ✓does not mutate input
✓filterFitmentModelsParts pages5
- ✓empty query returns all
- ✓case-insensitive substring on displayName
- ✓matches modelNumber
- ✓matches productType
- ✓no match returns empty
✓getMatrixLabel — allowlist is a closed set for every reachable inputBusiness rules4
- ✓returns only an allowlisted, non-empty badge across every state × option combo
- ✓never returns a retired badge for any input
- ✓routes out-of-contract values through the default without throwing
- ✓the allowlist itself carries no channel hint or 'call us' phrasing
✓buildAvailabilityStockLinesBusiness rules4
- ✓uses real Clinton qty as the primary stock line
- ✓shows no stock line for a part we cannot price, however many are on the shelf
- ✓keeps the line for a priced shelf part
- ✓treats vendor stock as secondary when Clinton has none
✓PDP head/body agreement under a degraded backend (#3827)Parts pages4
- ✓an unhealthy backend yields the soft-503 head, never a throw
- ✓a TRANSIENT fetch failure yields the soft-503 head, never a throw
- ✓a transient failure the health check calls HEALTHY is still a soft-503 head
- ✓the body renders ServiceUnavailable for the same transient failure
✓buildPdpMetaFields — CROP-front#1192 description == title de-dupParts pages4
- ✓falls through to the enriched fallback when description equals the title
- ✓de-dup is case- and whitespace-insensitive
- ✓falls through when the description is just the bare part number
- ✓leaves a description that genuinely differs from the title unchanged
✓buildEquipmentFirstPdpTitle truncation — CROP-front#1193 (item 1)Parts pages4
- ✓CROP-front#3060 — truncates the head but keeps the PN intact when a PN is present
- ✓truncates when the appended brand suffix pushes a title over the budget
- ✓leaves a title within budget untouched (no ellipsis)
- ✓keeps the PN · brand fallback path intact for junk/PN-only titles
✓buildPdpMetaFields — shared upstream description (CROP-front#3198)Parts pages4
- ✓distinguishes two parts handed the same upstream description
- ✓keeps the part number when the description overflows the SERP budget
- ✓adds no identity to a part that has no part number
- ✓leaves the narrative fallback byte-identical
✓rethrowIfTransientPartFetch — #1329 PDP catch discriminatorParts pages4
- ✓re-throws a transient 5xx so it never reaches the notFound() race
- ✓re-throws a 429 rate-limit (transient, not a permanent client error)
- ✓re-throws a timeout/network error
- ✓returns (does NOT throw) for a genuine 4xx so notFound() can proceed
✓isTransientSearchFailure — #3693 ServiceUnavailable discriminatorParts pages4
- ✓is true for the capacity rejection that caused the 16.7s 500
- ✓is true for 5xx and timeouts
- ✓is false for a genuine 4xx — that part is permanently missing, not unavailable
- ✓is false for a non-search error so a real bug still reaches the error boundary
✓BuyBox — lifecycle badge is decoupled from orderability (#2224)Parts pages4
- ✓an active, unpriced, non-purchasable brand part is NOT discontinued/superseded
- ✓a genuinely discontinued part keeps the superseded treatment; chip reads Out of Stock
- ✓a priced but non-purchasable part is suppressed, not labelled discontinued
- ✓a normal priced, purchasable part stays buyable
✓StaffInventoryPanel — clinton_local stateParts pages4
- ✓renders bin location + on-hand/avail + channel hint + cost + state badge
- ✓hides cost block when avgCost + dealerNet are both null (STAFF_SHOW_COST=false)
- ✓renders both rows + vendor header for composite-PK collision (BRIGGS / UEBLER)
- ✓shows stale warning badge when stale=true
✓ViewInDiagramButtonParts pages4
- ✓renders the trigger button in the part header
- ✓does not mount the dialog (or hit the API) until the button is clicked
- ✓opens the dialog pre-filled with the part number and runs the diagram search
- ✓shows the empty-state when the part appears on zero diagrams
✓legacy assemblies-list redirect — #1329Parts pages4
- ✓re-throws a transient 503 instead of notFound()
- ✓re-throws a transient timeout instead of notFound()
- ✓genuine 404 → null → notFound()
- ✓resolved chapters with a slug → redirect to the equipment URL
✓buildBreadcrumbs — title crumb fallbacksParts pages4
- ✓falls back to the part number when there is no title
- ✓prefers the short title the <h1> renders over the raw upstream title
- ✓falls back to the heading's own placeholder when nothing identifies the part
- ✓an empty-string title now falls through to the part number
✓parseFitmentLabels — grouping and orderingParts pages4
- ✓sorts groups by category and items by summary
- ✓merges structured and free-text labels that resolve to the same category name
- ✓keeps duplicate labels as separate items (no de-duplication)
- ✓does not mutate the caller's array
✓resolveFitmentId — collision-fence (ct-2434)Parts pages4
- ✓sends the branded SKU for a brand-catalog vendor (AGCO)
- ✓falls back to the route id when a brand-catalog part has no sku
- ✓keeps the bare PN for a CNH part (non-branded route id)
- ✓keeps the bare PN even for a branded NON-catalog vendor (NHL search-MV)
✓toGalleryImagesParts pages4
- ✓keeps real photos and carries their type + alt
- ✓excludes a diagram-typed drawing so it can't render as a fake studio photo
- ✓keeps the real photo but drops a co-listed diagram
- ✓drops CNH 'no image' placeholders (they load 200 OK)
✓buildMachineSpecCardsParts pages4
- ✓builds curated rows from real specs, skipping null fields
- ✓composes an engine summary when the pre-joined maker string is absent
- ✓combines hitch category and lift into one factual row
- ✓drops a thin model with fewer than three real attributes
✓toMedia360View — no viewParts pages4
- ✓returns the none view for null and undefined
- ✓returns the none view for an empty object (no status, not available)
- ✓returns the none view for an explicit none / not_available status
- ✓derives gcp from `available: true` when status is null, none otherwise
✓toMedia360View — externalParts pages4
- ✓passes an external status straight through, un-rewritten by the CDN
- ✓accepts url_only with a sourceUrl
- ✓degrades to none when an external status carries no URL, even with frames
- ✓returns none for an unrecognised status even when a URL is present
✓buildPartFaq — minimum floor (#1882)Parts pages4
- ✓keeps the honest data-only behaviour when no minimum is requested
- ✓pads a thin part to the requested minimum with operational entries
- ✓keeps data entries first, then tops up to the minimum
- ✓does not pad beyond the data it already has
✓dataOemSlugParts pages4
- ✓resolves New Holland from the slug, the vendor code, or the name
- ✓resolves clinton on a whole-word match
- ✓prefers New Holland when both patterns are present
- ✓returns undefined for another brand, an empty object, and no manufacturer
✓resolveDemoReviews deployment gatingParts pages4
- ✓resolves the fixture on a Vercel preview (VERCEL_ENV=preview)
- ✓returns null on the production deployment (VERCEL_ENV=production)
- ✓returns null when NEXT_PUBLIC_APP_ENV=prod even if VERCEL_ENV is unset
- ✓returns null for an unknown PN on preview
✓pickFitmentTierParts pages4
- ✓0..12 -> flat
- ✓13..30 -> grid
- ✓>30 -> groups when multiple product types
- ✓single product type downgrades to grid regardless of count
✓legacy assembly-detail redirect — #1329Parts pages4
- ✓re-throws a transient 503 instead of notFound()
- ✓re-throws a transient timeout instead of notFound()
- ✓genuine 404 → null → notFound()
- ✓resolved chapters with a slug → redirect to the equipment URL
✓isInStockDisplayState — Add-all CTA filterAssembly views3
- ✓matches the 5 in_stock-family states (mirrors getCustomerAction)
- ✓rejects call_us-family + unknown
- ✓rejects null / undefined (no chip = not addable)
✓getMatrixLabel — clintonInStock no longer elevates customer-facing copyBusiness rules3
- ✓does NOT elevate badge when clintonInStock=true (channel-leak rule)
- ✓does NOT elevate shippingLine when clintonInStock=true
- ✓treats clintonInStock=null/undefined identically to false
✓getMatrixLabel — action bucket + variantBusiness rules3
- ✓collapses every orderable tier (incl. pre-launch) to action=in_stock variant=success
- ✓collapses backorder + discontinued to action=call_us 'Out of Stock'
- ✓folds unknown (default-buyable) to action=in_stock 'In Stock' (fail-open)
✓getMatrixLabel — unknown folds against purchasabilityBusiness rules3
- ✓purchasable=false → 'Out of Stock' (call_us, secondary)
- ✓purchasable=true → 'In Stock' (in_stock, success)
- ✓both fold outcomes are on the customer-facing allowlist
✓reconcileAvailability — clintonInStock threadingBusiness rules3
- ✓threads clintonInStock=true even when state comes from cached fallback
- ✓treats clintonInStock=null as false
- ✓threads clintonInStock when state comes from live signal
✓isAvailabilityBuyableBusiness rules3
- ✓blocks out_of_stock
- ✓allows buyable states
- ✓defers to backend authority on null/undefined (buyable)
✓buildPdpMetaFields — CROP-front#831 junk-template description decouplingParts pages3
- ✓falls through to the enriched fallback when description equals the junk template
- ✓does not interfere with a real description that happens to be short
- ✓does not interfere when description has fitment descriptors (real human title)
✓buildEquipmentFirstPdpTitle fallback — CROP-front#1337 category-led identifier titleParts pages3
- ✓prepends the category to the PN · brand fallback for a PN-only title
- ✓keeps the bare PN · brand fallback when no category is present
- ✓drops the category prefix (keeps PN · brand intact) when it overflows the 70-char budget
✓AvailabilityPendingBannerParts pages3
- ✓renders the support-alias email and phone from lib/dealer
- ✓uses alert role so assistive tech announces the pending state
- ✓accepts prop overrides and builds correct mailto/tel hrefs
✓BuyBox — individual stepper caps to real stock (#2171)Parts pages3
- ✓dual layout caps the stepper at the exact DIS count (no 99 oversell)
- ✓dual layout shows the soft 'Also sold as a full pack' disclosure, not a pack-only claim
- ✓pack-only layout renders the pack claim and hides the individual stepper
✓generateProductSchema — no fitment Vehicle nodes (CROP-front#1065)Parts pages3
- ✓never emits a fitsForVehicle array
- ✓emits no standalone Vehicle node (GSC product-snippet rule)
- ✓keeps the Product node with offers intact
✓generateProductSchema — name/description de-dup (CROP-front#1192)Parts pages3
- ✓emits a description distinct from name when title == description upstream
- ✓keeps a genuinely distinct description
- ✓never emits name === description on the junk template
✓generateProductSchema — NH Construction (CE) sentinelParts pages3
- ✓emits a priced, in-stock Offer with the branded CE SKU
- ✓elides OfferShippingDetails for the CE part, which is freight-only
- ✓never leaks a wholesale field on the CE schema
✓generateBreadcrumbSchemaParts pages3
- ✓generates BreadcrumbList with correct positions
- ✓includes item URL on crumbs with href
- ✓returns null for empty breadcrumbs
✓generateProductSchema — price-leak guardrailParts pages3
- ✓offers.price equals the retail/public price field
- ✓serialized schema does not contain any wholesale field name
- ✓serialized schema with high-fitment + many specs does not leak
✓SupersessionSectionParts pages3
- ✓renders the chain as a table, one row per part number
- ✓exactly one row is the current number, and it is the last
- ✓cross-references are one term with a description per part number
✓HeroSummaryParts pages3
- ✓'About this item' is a named region, not a bare div with a heading
- ✓bullets stay a list
- ✓chips are a list and the replaced numbers a definition list
✓MachineSpecsSectionParts pages3
- ✓renders a real comparison table: attributes down, machines across
- ✓the machine column header keeps its equipment link
- ✓a machine missing an attribute gets an em dash, not a shifted column
✓AssemblyErrorParts pages3
- ✓reports the thrown error to Sentry with the route's tags
- ✓debounces the retry instead of resetting on the tap (front#1331)
- ✓keeps the escape hatch to the parts catalog
✓familyLabelParts pages3
- ✓title-cases the hono subLine series label
- ✓falls back to productType when subLine is null
- ✓falls back to a generic bucket when both are missing
✓buildBreadcrumbs — ordinary pathParts pages3
- ✓emits home → parts → brand hub → nested category trail → title
- ✓emits base + manufacturer + title when no category source resolves
- ✓gives the leaf crumb no href at all (JSON-LD leaf convention)
✓cachedAvailState — lifecycle 'discontinued' is the commerce-disabled flag only (#2224)Parts pages3
- ✓does NOT mark a live, unpriced part discontinued (no commerce-disable signal)
- ✓still marks a commerce-disabled part discontinued (dont_list / no_cnh_data)
- ✓maps cached availability through unchanged when commerce is enabled
✓parseFitmentLabels — degenerate inputParts pages3
- ✓returns an empty list for an empty array
- ✓skips blank and whitespace-only labels
- ✓trims a label before parsing and stores the trimmed form as `raw`
✓buildPartNarrative — leads with the most specific attributeParts pages3
- ✓leads a dimensioned part with its dimensions
- ✓leads a dimensionless fitment part with a named model
- ✓falls back to a PN lead when no distinguishing data exists
✓uniqueness across different partsParts pages3
- ✓never emits the old fixed template
- ✓produces a distinct leading 6 words per part
- ✓produces fully distinct descriptions
✓meta vs on-page introParts pages3
- ✓keeps every meta description within the SERP budget
- ✓includes price in the meta when it fits the budget
- ✓carries the PN in the meta but keeps price/CTA out of the on-page intro
✓determinismParts pages3
- ✓returns identical output for identical input (stable across ISR renders)
- ✓prefers a parsed material lead over a generic function lead
- ✓detects material from bulletPoints when the title carries none
✓getPartFactsParts pages3
- ✓derives the full fact sheet from labels alone when no fitment models are supplied
- ✓ranks supplied models by assembly count and counts them when fitmentCount is absent
- ✓falls back to the title as the part identifier ONLY when models are supplied
✓EnrichmentSectionSkeletonParts pages3
- ✓defaults to a single-row flex layout (carousel callers must not regress)
- ✓renders a responsive grid mirroring AssembliesSection when layout=grid
- ✓reserves multiple rows so the fallback height approximates the loaded grid
✓availabilityConfirmedFromClinton — signal-less surfaces (cards/cart)Business rules2
- ✓returns undefined when the flag is OFF
- ✓flag ON: confirmed iff Clinton on-shelf
✓availabilityConfirmedFromBomSource — BOM rows (live vs snapshot vs floor)Business rules2
- ✓returns undefined when the flag is OFF (labels unchanged)
- ✓flag ON: live and floor sources are confirmed; snapshot/none/undefined are not
✓recordReconcileObservability — both signals nullBusiness rules2
- ✓fires availability.both_signals_null when cached AND live are null
- ✓does NOT fire when at least one signal is populated
✓reconcileAvailability — fallback when both signals emptyBusiness rules2
- ✓returns state=unknown source=fallback when live=null AND cached=null
- ✓treats undefined inputs the same as null
✓reconcileAvailability — split-brain regression guardBusiness rules2
- ✓never returns 'unknown' when cached signal is informative
- ✓falls through to cached even when live signal is the literal string 'unknown'
✓fetchFitmentModelSpecs — vendor models never hit the specs clientParts pages2
- ✓fetches specs for CNH models only when the fitment list mixes in vendor models
- ✓makes zero outbound calls for an all-vendor fitment list
✓/parts/[id]/not-found generateMetadataParts pages2
- ✓post-flip (IS_INDEXING_ENABLED=true) emits NOINDEX_NOFOLLOW_ROBOTS with googleBot shape
- ✓pre-flip (IS_INDEXING_ENABLED=false) omits robots so layout's noindex,nofollow is inherited
✓composition: notFoundIfUnpublishable runs before redirectIfSupersededParts pages2
- ✓404s a withdrawn part before it can 308: no SEO signal passes to the replacement
- ✓does NOT 308 a reachable dont_list part: redirectIfSuperseded gates on superseded_redirect
✓PDP breadcrumb parity (visible DOM vs JSON-LD)Parts pages2
- ✓visible trail and JSON-LD agree on labels, order, and URLs
- ✓links the canonical categoryPath-only listing form (no categoryId)
✓BuyBox — standard (non-pack) stepper caps to real stock (#2258)Parts pages2
- ✓caps a known-stock standard part's stepper at the DIS count (no 99 oversell)
- ✓keeps the familiar 99 range when no stock signal is forwarded
✓BuyBox — pack-alias buy card (#2448)Parts pages2
- ✓renders the pack-alias card alongside the individual stepper in dual mode
- ✓falls back to the text-only pack hint when no offer could be resolved
✓Gallery product-image morph (#2458)Parts pages2
- ✓carries the morph name on the gallery stage as an inline style
- ✓renders no name when morphName is omitted
✓Gallery empty-media stateParts pages2
- ✓renders the placeholder inside a dimension-reserving wrapper and does not collapse
- ✓renders the stage as a named <section> region
✓SectionParts pages2
- ✓exposes an accessible name taken from its heading
- ✓derives the heading id from the section id so two sections never collide
✓generateProductSchema — availability ↔ badge alignment (#1634 / #2908)Parts pages2
- ✓emits InStock for a cached in_stock part regardless of the relabel flag / Clinton shelf
- ✓keeps the binary backorder → OutOfStock mapping regardless of the flag (#2897 / #1840)
✓FaqSectionParts pages2
- ✓announces how many questions there are, and keeps native details
- ✓every answer is in the markup, including the collapsed ones
✓buildBreadcrumbs — category href accumulationParts pages2
- ✓accumulates RAW labels into categoryPath while displaying formatted ones
- ✓emits categoryPath alone — never categoryId (the /parts canonical form)
✓toDiagramCardParts pages2
- ✓links the canonical assembly slug when the payload carries one
- ✓keeps the assemblyCode tail when the vendor has no slug row
✓effectiveAvail — an unknown (unpriced) part stays neutral + buyable, not destructiveParts pages2
- ✓renders a neutral 'Contact for availability', never the discontinued badge
- ✓renders the destructive Discontinued badge only for a discontinued part
✓parseTitleDimensionsParts pages2
- ✓parses ID/OD/Thk dimensions from a washer title
- ✓returns nothing for a dimensionless title
✓buildSupersessionViewParts pages2
- ✓puts the superseded numbers ahead of the current one
- ✓returns null with no replaced numbers, only blank ones, or no current number
✓recordReconcileObservability — PII safetyBusiness rules1
- ✓only carries productId in extras (no email, no JWT, no upstream payload)
✓SearchServiceDownErrorParts pages1
- ✓stores diagnostic and has correct name
✓PDP name parity (h1 vs breadcrumb leaf vs Product.name)Parts pages1
- ✓the h1, the breadcrumb leaf and Product.name are one string
✓Gallery diagram-edit mount-mechanics gateParts pages1
- ✓renders the schematic byte-identically and NO admin chrome when the gate is off
✓Gallery PDP part-photo edit mount-mechanics gateParts pages1
- ✓renders the main part photo region and NO admin chrome when the gate is off
✓generateProductSchema — the URL moved, the identity did notParts pages1
- ✓keeps an uppercase sku/mpn on a lowercase canonical url
✓VideoSectionParts pages1
- ✓renders the video rail as a list
✓StaffInventoryPanel — reconciled source attribute (#830)Parts pages1
- ✓surfaces data-staff-source=hono-override when the route reconciled an override
✓View360InteractiveParts pages1
- ✓exposes the focusable drag/arrow stage as an application, not an image
✓buildMachineSpecMatrixParts pages1
- ✓unions the ragged label sets along the curated order, not per machine
✓groupByProductTypeParts pages1
- ✓groups and sorts by count DESC
What we walk through in a real browser8 journeys
○PDP availability coherence (#573 + channel-leak rule)Browser journey15
- ○/parts/87687242 — zero literal "N/A" in rendered HTML
- ○/parts/87687242 — retired "Contact Us for Availability" copy never renders (#2135)
- ○/parts/87687242 — zero channel-hint copy on customer surface
- ○/parts/10118540 — zero literal "N/A" in rendered HTML
- ○/parts/10118540 — retired "Contact Us for Availability" copy never renders (#2135)
- ○/parts/10118540 — zero channel-hint copy on customer surface
- ○/parts/48052769 — zero literal "N/A" in rendered HTML
- ○/parts/48052769 — retired "Contact Us for Availability" copy never renders (#2135)
- ○/parts/48052769 — zero channel-hint copy on customer surface
- ○/parts/73344274 — zero literal "N/A" in rendered HTML
- ○/parts/73344274 — retired "Contact Us for Availability" copy never renders (#2135)
- ○/parts/73344274 — zero channel-hint copy on customer surface
- ○/parts/47378988 — zero literal "N/A" in rendered HTML
- ○/parts/47378988 — retired "Contact Us for Availability" copy never renders (#2135)
- ○/parts/47378988 — zero channel-hint copy on customer surface
○Price leak regression @smokeBrowser journey9
- ○PDP /parts/47622189 HTML has no wholesale fields
- ○PDP /parts/84496951 HTML has no wholesale fields
- ○PDP /parts/6559669 HTML has no wholesale fields
- ○category /parts/category/oil-filters has no wholesale fields
- ○resolve-parts batch endpoint strips wholesale tiers
- ○direct /api/parts endpoint strips wholesale tiers
- ○PDP of PN 87374182 never renders CNH net ($32.55) or exposes `net` price key
- ○/brands directory page has no wholesale fields
- ○/parts/brand/ferris/diagrams has no wholesale fields
○Availability signal leak regressionBrowser journey5
- ○PDP /parts/47622189 renders customer badge and hides raw signals @smoke
- ○PDP /parts/84496951 renders customer badge and hides raw signals @smoke
- ○PDP /parts/6559669 renders customer badge and hides raw signals @smoke
- ○listing /parts HTML has no raw CNH signal words @smoke
- ○category /parts/category/oil-filters HTML has no raw CNH signal words
○NH Construction (CE division) PDP (#1507)Browser journey5
- ○raw CE PN 308-redirects to the branded SKU
- ○PDP renders 200 with the CE part title
- ○shows a price, exactly one availability badge, and the buy CTA
- ○states a dispatch expectation with no channel wording
- ○emits Product JSON-LD with a priced Offer
○PDP — Supersession chain sectionBrowser journey4
- ○87800083 (ENGINE OIL FILTER) renders its chain with one Current row
- ○part with no chain does not render the section
- ○front#844 — sentinel ?replaced_from PN does NOT render as a circular link
- ○86521609 — heavy predecessor list renders every row, uncollapsed
○PDP — fitment sectionBrowser journey3
- ○87800083 renders the fitment section with a model count
- ○87800083 — typing a model narrows the compatibility table
- ○87800083 — fitment precedes diagrams in the DOM
○PDP — YouTube section smokeBrowser journey1
- ○87718230 renders the #videos section
○Static data-dump leak guard @smoke (#2072)Browser journey1
- ○no spreadsheet/database dump is committed under a CDN-served static dir
Automated checks630
Browser journeys72
Code exercised73%
What we check automatically117 groups
✓cart-storeApp state30
- ✓starts with empty cart
- ✓adds a new item to empty cart
- ✓increments quantity when adding existing item
- ✓adds multiple different items
- ✓merges a batch in one update — appends new lines, sums existing ones
- ✓dedupes repeats inside the same batch
- ✓leaves the cart untouched for an empty batch
- ✓removes an existing item
- ✓does nothing when removing non-existent item
- ✓removes only the specified item from multiple items
- ✓updates quantity for existing item
- ✓removes item when quantity is set to 0
- ✓removes item when quantity is negative
- ✓does not affect other items when updating one
- ✓removes all items from cart
- ✓works on already empty cart
- ✓toggles cart open state from false to true
- ✓toggles cart open state from true to false
- ✓sets cart open to true
- ✓sets cart open to false
- ✓returns 0 for empty cart
- ✓returns sum of all item quantities
- ✓is the only count selector, and diverges from items.length above qty 1
- ✓returns 0 for empty cart
- ✓calculates correct subtotal for single item
- ✓calculates correct subtotal for multiple items
- ✓calculates $12.50 for a pack_qty=5 item at $2.50/unit (John's scenario)
- ✓handles adding item with all optional fields undefined
- ✓handles large quantities
- ✓handles decimal prices correctly
✓createCheckoutSessionAction — server-side re-priceServer actions21
- ✓passes through when fresh data matches stale cart
- ✓rejects with CART_STALE + refreshedItems when price drifts
- ✓rejects with CART_STALE + droppedPartNumbers when part 404s
- ✓#3286 drops a zero-price line as CART_STALE, naming it, before the Zod parse
- ✓rejects CART_STALE when fresh part is commerce-disabled (dont_list)
- ✓rejects CART_STALE when fresh part is out_of_stock even if stale was never buyable
- ✓#2674 rejects CART_STALE when fresh brand part is purchasable:false (sellable + in_stock)
- ✓combines drop + drift in a single CART_STALE response
- ✓falls open on upstream batch failure (checkout proceeds with stale items)
- ✓#1563 fails CLOSED on batch failure when a cart line is commerce-disabled (dont_list)
- ✓#1563 fails CLOSED on batch failure when a cart line is out_of_stock
- ✓#1563 on batch failure drops only the non-purchasable line, blocks the whole session
- ✓batches the fetch into a single call (not N per item)
- ✓tags PaymentServiceApiError with payment_step=session_create + http.status_code in Sentry
- ✓emits http.status_code:'400' tag for 400 errors (alert filter contract per #576)
- ✓tags unexpected errors with payment_step=session_create + payment_error=unexpected
- ✓#2080 McHale cart lines use branded SKU for batch call, do not drop as unavailable
- ✓#2080 pack-alias line strips -PK suffix, keeps brand prefix → resolves (not dropped)
- ✓#2080 CNH branded single re-prices unchanged (no -PK suffix to strip)
- ✓#2080 mixed cart (CNH + brand-catalog) — both resolve via branded SKU
- ✓detects pack demotion drift (pack-only → singles)
✓initiateCheckoutServer actions21
- ✓returns error when amount is zero
- ✓returns error when amount is negative
- ✓returns error when cartId is empty string
- ✓returns error when cartId is missing (falsy)
- ✓creates checkout session and redirects with valid parameters
- ✓uses custom currency when provided
- ✓includes savePaymentMethod flag when provided
- ✓returns error when API response has success: false
- ✓returns error when API response has success: true but no URL
- ✓returns error when API response has success: true but data is undefined
- ✓uses error message from response when available
- ✓returns user-friendly error on PaymentServiceTimeoutError
- ✓returns custom message for 429 rate limit errors
- ✓returns API error message for non-429 errors
- ✓returns API error message for 500 errors
- ✓logs PaymentServiceApiError to console.error
- ✓returns generic error for unknown error types
- ✓logs unexpected errors to console.error
- ✓handles non-Error thrown values
- ✓re-throws NEXT_REDIRECT error to allow Next.js to handle redirect
- ✓does not catch or transform NEXT_REDIRECT error
✓CartRailSheetProduct grid15
- ✓renders nothing visible when isOpen=false
- ✓surfaces title, item count, line rows, subtotal, and Checkout link when open with items
- ✓uses singular 'item' copy when exactly one line is present
- ✓renders the workshop empty-state copy when items=[] and open
- ✓flips isOpen=false when the SheetClose × button is clicked
- ✓flips isOpen=false when Escape is pressed
- ✓decrements line quantity via the − stepper (calls updateQuantity)
- ✓increments line quantity via the + stepper (calls updateQuantity)
- ✓removes the line when Remove is clicked (calls removeItem)
- ✓hides the entire section (heading + list) when the store is empty
- ✓renders heading, count, and 3 mini cards when 3 items are tracked
- ✓renders price for priced items and 'Quote' badge for quote-only items
- ✓renders real <img> when imageUrl is present, no placeholder
- ✓renders placeholder when imageUrl is absent
- ✓renders 'viewed Nm ago' relative timestamp on each card
✓hasDriftServer actions14
- ✓true when price moves beyond tolerance
- ✓false when price moves within tolerance
- ✓false at exactly PRICE_DRIFT_TOLERANCE (boundary holds)
- ✓true just past the tolerance boundary
- ✓true on a clear price drop beyond tolerance (not just increases)
- ✓true when packQty changes
- ✓true when requiresPackBuy flips false → true
- ✓true when part becomes singles (drops pack fields)
- ✓skips price comparison when fresh.unitPrice is null (part has no price)
- ✓Gap D — true when fresh becomes out_of_stock from a buyable stale state
- ✓Gap D — true when stale availability is unknown and fresh is out_of_stock
- ✓Gap D — false when stale was already out_of_stock (no regression)
- ✓Gap D — false when fresh availability is unknown (defer to backend authority)
- ✓Gap D — false when fresh transitions to a different buyable state (in_stock → low_stock)
✓isLiveAffirmativelyUnavailableServer actions12
- ✓back-order + no error → true (affirmatively can't ship now)
- ✓discontinued + no error → true
- ✓back-order + hasError=null → true (null is not an errored read)
- ✓FAIL-OPEN: back-order but hasError=true → false (permission-blocked/errored)
- ✓FAIL-OPEN: discontinued but hasError=true → false
- ✓in_stock → false
- ✓FAIL-OPEN: unknown → false (uncertain, defer to snapshot authority)
- ✓delayed_supply → false (still orderable, not affirmatively unavailable)
- ✓pre_launch → false (upcoming, not a no-longer-available drop)
- ✓in_stock_limited → false (constrained but still orderable)
- ✓materialStatus === null + in_stock → false (optional-chains, never throws)
- ✓materialStatus === null + back-order → true (a null status is NOT an error signal, so a confirmed back-order still drops — only hasError===true fails open)
✓cartItemsToPackages (hotfix #928)Business rules12
- ✓ships a qty=1 item at 0.5 kg (regression of the 2 kg → 0.5 kg drop)
- ✓ships qty=10 at 5 kg (still well under the 68 kg cap, no split)
- ✓falls back to title 'Part' when none provided
- ✓does NOT split a qty=25 knife blade — 25 × 0.5 = 12.5 kg fits one package (vs 50 kg under old 2 kg default)
- ✓splits a qty=200 small part into ≥2 packages, each ≤68 kg, summing to the original total
- ✓splits a very large qty=2000 line into many equal sub-packages, all ≤68 kg, summing exactly
- ✓splits declared value proportionally so the sum matches the original line total
- ✓preserves the description on every split sub-package
- ✓boundary: qty exactly at cap (qty=136 → 68 kg) stays one package
- ✓boundary: one unit above cap (qty=138 → 69 kg) splits to 2 packages
- ✓produces three small packages (0.5 / 12.5 / 12.5 kg) instead of the old three oversized (2 / 50 / 50 kg)
- ✓processes one normal line + one split line independently (flatMap order preserved)
✓addressSchema — continental-US-only enforcement (#491 UC-D-15)Checkout pages12
- ✓accepts a valid NY address
- ✓rejects state=AK with NON_CONTINENTAL_ERROR
- ✓rejects state=HI with NON_CONTINENTAL_ERROR
- ✓rejects ZIP prefix 995 (AK)
- ✓rejects ZIP prefix 967 (HI)
- ✓rejects ZIP prefix 006 (PR) even when state=PR is not in dropdown
- ✓rejects ZIP prefix 008 (USVI)
- ✓accepts continental ZIP 10001
- ✓accepts continental ZIP 13323
- ✓accepts continental ZIP 94110
- ✓accepts continental ZIP 33101
- ✓accepts continental ZIP 75001
✓checkout-store — front#461 P1 #4 (rate invalidation)App state11
- ✓replaces the address wholesale, leaving no field of the previous one
- ✓preserves selectedRate when zone is unchanged (typo fix on street)
- ✓clears selectedRate when ZIP changes (different shipping zone)
- ✓clears selectedRate when state changes
- ✓does not clear when transitioning from null to first address
- ✓stamps the cart hash when rate is set
- ✓clears the stamp when rate is cleared
- ✓does nothing when no rate is selected
- ✓preserves rate when cart hash matches
- ✓clears rate when cart hash differs
- ✓clears legacy rate that has no stamp (persisted before P1 #4)
✓FreeShipCountdown — John spec (msg 1225883)Checkout pages11
- ✓$0 cart → '$75.00 away from FREE shipping' red
- ✓$40 cart → '$35.00 away from FREE shipping' red
- ✓$74.99 cart → '$0.01 away from FREE shipping' red (boundary just-below)
- ✓$75 cart → 'FREE shipping unlocked' green (boundary inclusive)
- ✓$100 cart → 'FREE shipping unlocked' green
- ✓hasFreightItem === true → renders null (countdown hidden for freight)
- ✓shippingMethod === 'pickup' → renders null (pickup is always free)
- ✓negative subtotal (defensive) → treated as $0, '$75.00 away' red
- ✓NaN subtotal → renders null defensively
- ✓Infinity subtotal → renders null defensively
- ✓shippingMethod === 'delivery' → still renders countdown (delivery does need the gate)
✓migrateCartPersistedState (CT-674 / front#148)App state10
- ✓v0 → current: normalizes legacy items with missing/invalid fields
- ✓v1 → v2: clears all items (discards stale dealer-cost snapshots)
- ✓v1 → v2: returns empty items even if persisted state is missing
- ✓current version: passes items through unchanged
- ✓v2 → current (front#296): pack fields survive round-trip
- ✓v2 → current (front#296): legacy item without pack fields stays non-pack
- ✓wipes items when an old v1 payload is found in localStorage
- ✓v2 → v3 (front#284) preserves existing items, leaving overnightEligible undefined
- ✓v3 → v4 (front#598) preserves existing items, leaving shippingPath undefined
- ✓v4 → current: shippingPath roundtrips through Zod-guarded passthrough
✓derivePackCartStateCart page10
- ✓#959 DFS part (requiresPackBuy=true, packQty=5): step=1, legacyPackSize=5
- ✓#959 regression guard: step stays 1 across pack sizes (10, 25, 100)
- ✓non-pack part: falls back to ±1 with full 99-unit cap
- ✓Clinton-singles (requiresPackBuy=false, packQty=5): no enforcement
- ✓packQty=1 is not a pack-buy even if requiresPackBuy slipped through
- ✓missing packQty with requiresPackBuy=true keeps ±1 (fail-open)
- ✓front#919 alias SKU: step = 1 pack at a time, badge reads from SKU
- ✓front#919 alias SKU coexists with legacy pack-buy fields — alias wins
- ✓#2258 caps cart stepper to known stockCount (mirrors PDP resolveStepperCap)
- ✓#2258 NULL-stock cart line keeps 99 fallback
✓formatUSPhoneCheckout pages10
- ✓returns empty string for empty input
- ✓formats 3-digit partial input as area code only
- ✓formats 6-digit partial input with prefix
- ✓formats a complete 10-digit number
- ✓strips +1 country code from an 11-digit input — front#461 P1 #3
- ✓strips a leading 1 when input is exactly 11 digits
- ✓preserves leading 1 when input is exactly 10 digits (1 is a valid area code)
- ✓handles formatted input with parens, dashes, and spaces
- ✓handles +1 prefix with formatting characters
- ✓ignores trailing digits beyond 10 when input has no leading 1
✓useCartSyncInterface behaviour9
- ✓loads server cart items when the user signs in
- ✓does not load the server cart on the checkout success page (front#3008)
- ✓clears the cart store when the user signs out
- ✓treats a missing backend as idle without surfacing an error
- ✓debounces cart mutations to syncUserCart
- ✓does not resurrect a locally-removed line when local edits are unsynced (dirty)
- ✓pushes an emptied local cart (full delete) to the server when dirty
- ✓adopts the server cart on a clean sign-in and leaves no dirty marker
- ✓marks the cart dirty on a local mutation and clears it after a successful sync
✓cartLineAvailabilityBadgeCart page9
- ✓live affirmative back-order overrides the cached label with a red dot
- ✓live discontinued overrides too
- ✓live override beats a stale add-time stockCount snapshot
- ✓no live verdict, in_stock → no badge
- ✓live present but NOT unavailable → still no badge
- ✓stockCount snapshot renders '{n} left' when no live override
- ✓every countless tier → null, so no two orderable lines look different
- ✓an unpriced line reads Out of Stock, with no live verdict and no flag
- ✓the price verdict outranks a stockCount that would otherwise render '{n} left'
✓useZipFormatterCheckout pages9
- ✓formats a 5-digit input as ZIP5
- ✓strips non-digits before formatting
- ✓formats 6+ digits with hyphen as ZIP+4
- ✓truncates beyond ZIP+4 (9 digits)
- ✓formats partial input (fewer than 5 digits) without hyphen
- ✓handles empty input by passing empty string through (lets Zod block)
- ✓strips an existing hyphen from the input then re-applies after digit 5
- ✓handles 6 digits as ZIP5 + 1-digit suffix
- ✓always calls setValue with shouldValidate: true
✓useCheckoutBusiness rules8
- ✓throws when used outside CheckoutProvider
- ✓reports a signed-out visitor as a guest
- ✓reports a signed-in visitor as not a guest
- ✓does not call the first-order action for a guest
- ✓defaults isFirstOrder to true before any resolution
- ✓stays loading until Clerk has loaded
- ✓treats a loaded guest as not loading
- ✓provides context values to a consuming component subtree
✓buildCartItemPdpPathCart page8
- ✓uses the branded sku for the base part path
- ✓routes a brand-held line (CT-KUH/FER/…) to its /lookup twin (#3854)
- ✓strips a lowercase pack alias too, so the href never keeps it
- ✓strips the -PK{N} pack-alias suffix → links to the BASE part, not the alias
- ✓falls back to the raw partNumber path when no branded sku is present
- ✓falls back to raw PN when sku is not a valid branded SKU
- ✓URL-encodes part numbers that contain unsafe characters
- ✓returns null when there is no usable identifier (legacy item)
✓CartLegacyHydrateCart page8
- ✓does NOT call refresh action before hydration completes (race guard)
- ✓posts only legacy partNumbers (those missing both pack fields) once hydrated
- ✓does NOT call applyPackBackfill when refresh action returns empty
- ✓no-ops when cart is empty after hydration
- ✓no-ops when all cart items already have pack fields
- ✓fires backfill on hydration transition (false → true via rerender)
- ✓does NOT re-fire backfill on subsequent renders after running once
- ✓swallows refresh-action rejection so the cart stays usable
−ReviewPageContent — UC-D-21 classification re-check (#539)Checkout pages8
- −calls recheckClassificationAction on mount with current cart + address
- −blocks the Place Order CTA when server returns classification drift for any line
- −renders DriftModal listing each drifted line with the changed flag
- −offers per-line 'Remove item' action that updates the cart store
- −offers a 'Cancel and return to cart' action that navigates to /cart
- −re-fetches selectedRate / transit estimate after the user acknowledges drift
- −does NOT block when no drift is detected
- −falls open (allows Place Order) when the recheck action errors
✓AddressSuggestionDialogCheckout pages8
- ✓renders 'Use Selected Address' when suggestions exist
- ✓front#461 P0 #2 — shows 'Use Address as Entered' when no suggestions and canContinueWithoutSuggestions=true
- ✓hides 'Use Address as Entered' when canContinueWithoutSuggestions is false (hard validation failure)
- ✓calls onConfirm with the original address when 'Use Address as Entered' is clicked
- ✓UC-9 — calls onConfirm with the SUGGESTED address (not the original) when confirmed
- ✓UC-9 — surfaces both the original and a single suggestion as radio choices
- ✓front#1621 — backdrop dismiss routes to onEdit
- ✓displays validation messages above the body
✓FreeShippingOptions — the overnight section is not offered at allCheckout pages8
- ✓renders no overnight toggle for a shelf cart
- ✓renders no overnight toggle for a CNH-direct cart
- ✓renders no overnight toggle for a supplier-direct cart
- ✓renders no overnight toggle for an unknown-path cart
- ✓renders no overnight toggle for a mixed shelf + CNH cart
- ✓shows no overnight row or price even with a full carrier rate-card in hand
- ✓never fires the rate fetch, since only overnight lanes consume it
- ✓leaves the free lanes untouched — nobody is left without an option
✓ShippingForm — #1063 four-cell behavior matrix at predicate boundaryCheckout pages8
- ✓OFF + any → continue allowed (backwards compat during 24h soak)
- ✓ON + valid:true → continue allowed normally
- ✓ON + valid:false + canContinue:true + cost MISMATCH → BLOCKED
- ✓ON + valid:false + canContinue:true + cost MATCH → warn+retry (no over-block)
- ✓ON + valid:false + canContinue:true + NO QUOTE (network/timeout) → warn+retry
- ✓ON + valid:false + canContinue:false → existing hard-block path stays in charge
- ✓edge: ON + FE has 0 selected rates (race) → no block
- ✓edge: cents-level rounding noise is absorbed by the tolerance
✓syncUserCart — purchasability backstop (front#1593)Server actions7
- ✓drops a commerce-disabled (dont_list) line before persisting
- ✓#2674 drops a brand line flagged purchasable:false even when sellable + in_stock
- ✓#2674 sends the branded SKU (not the bare PN) to the re-price batch
- ✓drops an out_of_stock line even when publishStatus is sellable
- ✓keeps a PN missing from the fresh batch (backend stays authoritative)
- ✓fails open — persists the whole cart when hono throws
- ✓does not call hono when no item carries a part number
✓toSharedCartItemsBusiness rules7
- ✓keeps only the safe minimal fields and drops everything else
- ✓carries optional identity fields when present
- ✓clamps quantity to the valid cart range and drops zero/negative lines
- ✓skips lines missing identity fields
- ✓caps the number of lines at MAX_SHARED_CART_ITEMS
- ✓coerces a non-positive price to 0 rather than leaking NaN
- ✓produces snapshots that satisfy the wire schema
✓resolveOrderRefWithRetryBusiness rules7
- ✓does not fetch when neither identifier is present
- ✓resolves on the first attempt when the order already exists (no poll latency)
- ✓retries the webhook race: null first, then resolves
- ✓gives up after the retry budget and returns null
- ✓prefers payment_intent over session_id
- ✓falls back to the gateway URL with no token when direct URL is unset
- ✓uses the direct URL + X-Admin-Token when configured (front#1656)
✓fetchCartLiveVerdictsCart page7
- ✓empty input → {} without calling the batch
- ✓affirmative back-order → unavailable:true
- ✓discontinued → unavailable:true
- ✓FAIL-OPEN: back-order but hasError → unavailable:false
- ✓in_stock live → unavailable:false, displayState passthrough
- ✓PN absent from the batch map → no verdict (cart keeps cached label)
- ✓batch throws → {} (fail-open, never breaks the cart)
✓failure classificationCheckout pages7
- ✓routes a dead shipping rate back to the shipping step, not a Retry
- ✓never echoes a raw config-class backend string to the customer
- ✓shows a retryable transient verbatim, with a Retry action
- ✓offers Retry on the first transient failure only, then stops
- ✓reports the failure to Sentry tagged as an unexpected payment step
- ✓un-busies the Place Order button after any failure
- ✓survives a thrown (non-Error) rejection with generic copy
✓FreeShippingOptions — John's 7-title spec baseline (free lanes)Checkout pages7
- ✓renders Pickup + FREE shipping for an eligible cart >= $75
- ✓re-dates the pickup row for a cart that is not on the Clinton shelf
- ✓hands the checkout the re-dated rate when an off-shelf cart picks up
- ✓renders $9 flat-rate row instead of FREE when cart subtotal < $75
- ✓renders Call-for-freight-pricing CTA on heavy-or-oversize ineligibility
- ✓does NOT render freight CTA on below-threshold ineligibility (front#960)
- ✓PRECEDENCE — heavy CTA renders on a mixed heavy + below-threshold cart (front#960)
✓getChargeAccountEligibilityBusiness rules6
- ✓reports an eligible customer with the limit
- ✓maps a 404 to not eligible — that is the feature flag being off
- ✓maps a 401 to not eligible
- ✓propagates a 500 instead of silently hiding the option
- ✓treats a success body with no data as not eligible
- ✓sends the Clerk bearer token
✓fetchUserCartServer actions6
- ✓returns UNAUTHORIZED without calling backend when no userId
- ✓forwards the userId from auth() to getUserCartFromBackend
- ✓propagates a typed FETCH_FAILED when backend reports failure
- ✓maps CartServiceApiError → status-derived code
- ✓front#3000: a CART_NOT_FOUND 404 is a normal empty cart, not an error
- ✓maps CartServiceTimeoutError → TIMEOUT code
✓createCheckoutSessionAction — server-side oversell clamp (front#2614)Server actions6
- ✓clamps qty above the ceiling and blocks the session (ceiling 1, qty 5)
- ✓passes through when qty is within a known ceiling (ceiling 3, qty 3)
- ✓clamps a depot-only part whose Clinton shelf is empty (shelf 0, depot 4, qty 20)
- ✓no clamp on NULL stock within the 99 fallback (unknown stock, qty 50)
- ✓clamps to the 99 fallback when stock is unknown and qty exceeds it (qty 150 → 99)
- ✓does NOT clamp a pack-alias line — packs, not individual units (qty 3 packs, ceiling 2)
✓ConfirmHeroInterface pieces6
- ✓renders the personalised headline when name is provided
- ✓renders the anonymous headline when no name is provided
- ✓formats the order number through formatOrderNumber
- ✓preserves Stripe payment-intent style identifiers verbatim
- ✓promises a ship email by default (ship order)
- ✓promises a pickup heads-up (no 'ships') for a pickup order — front#1084
✓deriveCartLineShippingPathBusiness rules6
- ✓returns pickup when shippingProvider === 'pickup' regardless of item state
- ✓returns dfs-ground for requiresPackBuy true (highest priority for non-pickup)
- ✓returns cnh-overnight for overnightEligible true (without pack-buy)
- ✓returns dis-stock for in_stock without overnight or pack-buy markers
- ✓returns unknown for low_stock or out_of_stock without other markers
- ✓treats null/undefined shippingProvider the same as a non-pickup carrier
✓isMultiSourceCartBusiness rules6
- ✓returns true for ≥2 distinct paths excluding pickup
- ✓returns false for all-DIS cart (single source)
- ✓returns false for pickup-only cart
- ✓treats pickup as single-source even with mixed underlying buckets
- ✓returns false for empty cart
- ✓counts unknown bucket as a distinct source
✓migrateCartPersistedState — v3→current Zod-guarded passthrough (#540)App state6
- ✓preserves valid items unchanged
- ✓drops items missing required fields (productId)
- ✓drops items with wrong-typed required fields (quantity as string)
- ✓drops items with invalid availability enum
- ✓returns empty array when state.items is not an array
- ✓survives a future-version persist (e.g. version=4) via passthrough branch
✓selectIsInCart / selectCartQuantity (round 2.5 O(1) index)App state6
- ✓returns false / 0 for productIds not in cart
- ✓returns true / quantity once a productId is added
- ✓reflects updateQuantity + removeItem mutations
- ✓clearCart + setItems rebuild the index
- ✓only flips the targeted productId's membership when a sibling is added
- ✓subscribers selecting a stable productId see no value change on unrelated mutations
✓applyPackBackfill (front#316)App state6
- ✓patches legacy items missing pack fields with fresh values
- ✓no-ops on PNs not in the cart (no spurious re-renders)
- ✓no-ops on empty backfill array
- ✓preserves items with already-correct pack fields (no churn)
- ✓preserves quantity, unitPrice, and other fields when patching
- ✓only patches matching items in a mixed cart
✓<CartItemCard> PDP link (front#1088)Cart page6
- ✓renders the title as a link to the part PDP with a descriptive name
- ✓pack-alias line links to the BASE part PDP (no -PK in the href)
- ✓#3854 — a held row's /lookup twin never reaches the markup as a URL
- ✓brands the no-image placeholder from the branded sku
- ✓renders the title as plain text (non-link) when no PDP path resolves
- ✓keeps the qty stepper and remove button OUTSIDE the anchor
✓<PaymentMethodRow>Account pages6
- ✓renders brand, masked last4 and expiry
- ✓shows the default chip when method.isDefault is true
- ✓hides the set-default button when method is already default
- ✓fires onSetDefault when the star button is clicked
- ✓fires onDelete when the trash button is clicked
- ✓renders an expiry warning when the card is within 60 days
✓TrackPurchaseCheckout pages6
- ✓emits the purchase event with the order's money fields
- ✓emits once per transaction id across re-renders
- ✓emits again for a genuinely different transaction
- ✓does not report a purchase with no transaction id
- ✓does not report a purchase with no line items
- ✓renders nothing
✓FreeShippingOptions — $9 flat-rate lane reachable via real eligibility (front#1080)Checkout pages6
- ✓surfaces the $9 flat row for a <$75 non-freight far-address cart (the prod repro)
- ✓the $9 flat row is a PRIMARY row, not buried in the overnight expander
- ✓the $9 flat row is selectable and round-trips the Flat Rate rate ($9)
- ✓the $9 flat row selection key matches FLAT_RATE_KEY (highlight round-trips)
- ✓FREE row (not $9) for a >= $75 cart via real eligibility (mutual exclusion holds)
- ✓NO Clinton ground row (FREE or $9) for a heavy cart — freight CTA owns it
✓InlineDeliveryOptions — selectedRate persistence (#521)Checkout pages6
- ✓renders selected radio with data-state='checked' when selectedRate is provided
- ✓renders unselected radios with data-state='unchecked'
- ✓rerenders checked-state correctly when rates arrive AFTER selectedRate hydrated (#521 transient)
- ✓re-derives checked-state when selectedRate changes after initial render
- ✓renders no checked radio when selectedRate is null
- ✓calls onRateSelect with the matching DeliveryRate when a radio is selected
✓paymentServiceClient.listPaymentMethodsBusiness rules5
- ✓calls GET /api/customers/:clerkUserId/payment-methods
- ✓url-encodes the clerkUserId so weird Clerk ids do not break the path
- ✓returns the JSON body when the request succeeds
- ✓refuses to fire when the supplied clerkUserId does not match the JWT sub claim
- ✓refuses to fire when there is no JWT at all
✓paymentServiceClient.createCheckoutSession — X-Stripe-Mode header gateBusiness rules5
- ✓does NOT send X-Stripe-Mode when testMode is omitted
- ✓does NOT send X-Stripe-Mode when testMode is explicitly false
- ✓sends X-Stripe-Mode: test when testMode is true
- ✓does NOT include testMode inside the JSON body (header only)
- ✓preserves the existing Content-Type + Accept headers when test header is added
✓refreshCartPackFieldsAction (front#316)Server actions5
- ✓returns [] for empty input without hitting hono
- ✓returns only pack-only entries (filters out singles + dropped PNs)
- ✓chunks > 50 PNs across multiple hono calls and merges results
- ✓fails open with [] when any batch throws
- ✓does not call hono twice for an exactly-50-PN cart (single batch)
✓syncUserCartServer actions5
- ✓returns UNAUTHORIZED without calling backend when no userId
- ✓preserves existing addedAt and stamps Date.now() onto items missing it
- ✓invalidates the user-cart tag after a successful sync (cross-device freshness)
- ✓does NOT invalidate the cache when the backend reports failure
- ✓maps an unknown thrown value to UNKNOWN code
✓selectLiveUnavailablePartNumbersServer actions5
- ✓drops only PNs present with an affirmative-unavailable verdict, preserving order
- ✓FAIL-OPEN: PN absent from the map is never dropped (network fail / baseUrl unset)
- ✓FAIL-OPEN: permission-blocked batch (every PN hasError=true) drops nothing
- ✓empty cart → []
- ✓ignores live entries for parts not in the cart
✓createCheckoutSessionAction — Stripe TEST-mode toggle (CROP-front#1057)Server actions5
- ✓does NOT set testMode when E2E_TEST_MODE is unset (prod-equivalent default)
- ✓does NOT set testMode when E2E_TEST_MODE is "0" (explicit off)
- ✓does NOT set testMode for non-canonical truthy values ("true", "yes")
- ✓sets testMode=true when E2E_TEST_MODE is exactly "1"
- ✓isStripeTestModeEnabledForRequest reads the env per-call (no module cache)
✓createSharedCartActionServer actions5
- ✓persists a snapshot and returns an unguessable share URL
- ✓builds the share link from the runtime request origin, not the SEO canonical
- ✓shares a link on the same host the request arrived on (preview host)
- ✓records a null creator for a guest share
- ✓rejects an empty cart without touching the repo
✓ProductCardAddToCart — addItem payloadProduct grid5
- ✓front#1619 — removes from cart when the part is already in the order
- ✓passes imageUrl from part.media.primaryImage into addItem
- ✓passes imageUrl as undefined when primaryImage is null
- ✓passes branded sku (CT-{BRAND}-{PN}) into addItem
- ✓omits sku when partNumber is empty
✓ProductCardAddToCart — purchasability gate (front#1601)Product grid5
- ✓does NOT render a quote CTA for a dont_list part — defer to PDP (#1863)
- ✓does NOT render a quote CTA for an out_of_stock part — defer to PDP (#1863)
- ✓renders add-to-cart when inventory availability is fresher than stale top-level availability
- ✓renders add-to-cart when real Clinton stock overrides stale out_of_stock
- ✓adds a purchasable part and snapshots publishStatus + availability
✓cart free-shipping threshold — single source of truth ($75) (front#1066)Cart page5
- ✓the cart constant resolves to the canonical $75 threshold, not the legacy $500
- ✓a $92 cart qualifies for free shipping — $0 away
- ✓a $40 cart shows $35 away from free shipping (75 - 40)
- ✓a cart exactly at the $75 threshold qualifies (>=, not >)
- ✓remaining never goes negative for an over-threshold cart
✓formatDisplaySkuCart page5
- ✓strips CT- prefix from a branded SKU
- ✓strips CT- prefix for a non-NHL brand
- ✓leaves pack-alias SKU unchanged (suffix carries meaning)
- ✓returns null for undefined/null/empty
- ✓returns the raw string when it is not a branded SKU
✓PaymentActions — pack-invariant guard removedCheckout pages5
- ✓renders Pay button enabled for a multi-pack-OK cart (baseline)
- ✓keeps Pay button enabled when a pack-buy item has non-multiple qty
- ✓keeps Pay button enabled across MULTIPLE non-multiple pack items
- ✓ignores items without requiresPackBuy even when quantity % packQty !== 0
- ✓ignores items where packQty is undefined (defensive — no division)
✓FreeShippingOptions — Pickup Today shelf gateCheckout pages5
- ✓offers Pickup Today when every line is on the shelf (dis-stock)
- ✓hides Pickup Today for a vendor cart that ships in first (cnh-overnight)
- ✓hides Pickup Today for a supplier-direct cart (dfs-ground)
- ✓hides Pickup Today on a mixed shelf + non-shelf cart (worst line wins)
- ✓hides Pickup Today for an unknown-path cart (fail-open is not a shelf promise)
✓addressRateKeyCheckout pages5
- ✓changes when only the street changes
- ✓changes when only the city changes
- ✓changes when only the state or ZIP changes
- ✓is stable across casing and surrounding whitespace
- ✓treats a missing street or city as empty rather than throwing
✓createCheckoutSessionAction — pack-invariant guard removed (#959)Server actions4
- ✓#959 accepts non-multiple pack qty (3 of a packQty=2 line)
- ✓#959 accepts multiple non-multiple pack lines with mixed packQty
- ✓#959 accepts multiple non-multiple pack lines sharing the same packQty
- ✓accepts singles (requiresPackBuy absent)
✓createCheckoutSessionAction — live availability gate (#1584)Server actions4
- ✓drops a part the live signal reports as back-order (orderability GREEN but 49wk out)
- ✓FAIL-OPEN: permission-blocked live read (hasError for every PN) → cart unchanged, proceeds to Stripe
- ✓FAIL-OPEN: live source unset (empty map) → no live drop, proceeds to Stripe
- ✓combines a hono 404 drop and a live back-order drop in one CART_STALE
✓sendCartToStaffActionServer actions4
- ✓creates a quote from cart lines and notifies staff + customer when signed in
- ✓requires a contact email for a guest with no account email
- ✓accepts a guest's supplied email and stores a null-user quote
- ✓rejects a malformed contact email
✓NextStepsInterface pieces4
- ✓renders the 4 lifecycle steps with packing as current
- ✓falls back to a generic arrival label when no ETA is provided
- ✓renders pickup-appropriate steps with no UPS / tracking / arrival copy
- ✓keeps the ship path unchanged when isPickup is false
✓cart-service client — request deadlineBusiness rules4
- ✓arms a live timeout signal on every request
- ✓maps a TimeoutError abort to CartServiceTimeoutError
- ✓still maps a plain AbortError to the timeout error
- ✓leaves an HTTP error an API error, not a timeout
✓groupByShippingPathBusiness rules4
- ✓groups items into ordered breakdown with counts
- ✓orders bucket output: dis-stock → cnh-overnight → dfs-ground → unknown → pickup
- ✓returns single pickup row when shippingProvider is pickup
- ✓counts pieces not lines (3 lines × 5 qty each = 15 items)
✓shared-carts-repoReference data4
- ✓createSharedCart persists the snapshot and round-trips items via jsonb
- ✓issues a distinct token per share
- ✓getSharedCart returns null for an unknown or empty token
- ✓getSharedCart treats an expired snapshot as missing
✓selectCartIsAllOvernight (front#284)App state4
- ✓returns false on an empty cart
- ✓returns true when every item is overnight-eligible
- ✓returns false when any item is undefined (legacy / unknown)
- ✓returns false when any item is explicitly false (DFS / freight)
✓<CartContent> — suppressAnalytics prevents the Suspense fallback/resolved double-fire (#2918)Cart page4
- ✓does not fire view_cart for the suppressed (fallback) instance
- ✓fires view_cart exactly once across a fallback -> resolved swap
- ✓fires view_cart once for a plain (non-Suspense) mount
- ✓restores a cleared cart in a single store write, still tracking every line
✓parsePackAliasSizeCart page4
- ✓returns the pack size from a CT-NHL alias SKU
- ✓returns null for plain part numbers
- ✓returns null for unknown SKU shape
- ✓reads the pack size whatever casing the suffix arrives in
✓<CartSummary> — shipping-note copy reflects $75-nationwide rule (front#1078)Cart page4
- ✓shows the $75 free-ship threshold and the $9 flat-rate line below threshold
- ✓shows the free-shipping confirmation at/above threshold
- ✓never renders the removed distance-gated / $100 / $99 copy
- ✓keeps the cart threshold in sync with the canonical constant
✓<ExpiryWarning>Account pages4
- ✓renders nothing when card has more than thresholdDays left
- ✓renders amber warning when within threshold but not expired
- ✓renders destructive treatment when expired
- ✓respects a custom thresholdDays prop
✓ClearCartOnMountCheckout pages4
- ✓clears the server cart, the local cart and the checkout state on mount
- ✓still clears locally when the server clear has not settled
- ✓renders nothing
- ✓does not re-clear on a re-render with unchanged store selectors
✓ChargeAccountActionCheckout pages4
- ✓renders nothing when the customer is not eligible
- ✓renders nothing while the answer is still pending
- ✓renders the action once the backend confirms eligibility
- ✓stays disabled while the card path is submitting
✓userFacingCheckoutError — backend-error mapping (#576)Checkout pages4
- ✓masks the exact incident message from #576
- ✓masks generic backend 5xx messages
- ✓preserves explicitly retryable wording (case-insensitive)
- ✓never returns the raw message for unknown backend errors
✓userFacingCheckoutError — shipping-rate-gone surfacing (front#1343)Checkout pages4
- ✓surfaces a clean, actionable message instead of the generic copy
- ✓does not leak the internal provider/serviceType key to the customer
- ✓flags the reselect class via isShippingReselectError but not generic errors
- ✓still masks the #576 incident message (no regression)
✓ShippingSummary multi-source breakdown — neutral copy (#1086)Checkout pages4
- ✓renders the breakdown for a multi-source cart
- ✓frames the title around timing, not location
- ✓uses a generic team voice — no named individual
- ✓leaks no fulfillment source/location or staff name anywhere in the breakdown
✓ShippingForm — the address that ships is the address on screenCheckout pages4
- ✓treats a ZIP the customer typed as input, not as an untouched form
- ✓does not leave validation errors on fields that seeding has just filled
- ✓leaves the error on a field the seed had nothing to put in
- ✓keeps the typed address when the saved checkout state arrives after mount
✓createChargeAccountOrderBusiness rules3
- ✓POSTs the order and returns the created reference
- ✓never sends an email field — the DIS X-ref key is server-resolved
- ✓throws on a 403 so the caller can surface the reason
✓pickFreshFieldsServer actions3
- ✓extracts unitPrice + pack fields for pack-only part
- ✓drops packQty=1 (not a pack) and requiresPackBuy=false
- ✓returns unitPrice=null when price is absent
✓applyFreshFieldsServer actions3
- ✓overwrites unitPrice and pack fields with fresh values
- ✓keeps stale unitPrice when fresh price absent
- ✓clears pack fields when a pack-only part is demoted to singles (regression)
✓toRefreshedCartItemServer actions3
- ✓maps validated item shape → CartItem with addedAt timestamp
- ✓omits packQty/requiresPackBuy for singles
- ✓round-trips through JSON to strip undefined pack fields (server → client)
✓createCheckoutSessionAction — shippingPath propagation (front#1343)Server actions3
- ✓forwards shippingPath to the persisted cart + checkout-session payload (CNH-overnight 400 fix)
- ✓survives the no-drift re-price round-trip (applyFreshFields preserves shippingPath)
- ✓omits shippingPath for legacy items that carry none
✓GuestSignupPromptInterface pieces3
- ✓renders the CTA with the email pre-filled in the sign-up href
- ✓URL-encodes special characters in the pre-filled email
- ✓renders the descriptive copy
✓ShareLinkDialogInterface pieces3
- ✓shows the link on reopen when the dialog was closed mid-mint (#3330)
- ✓discards a mint superseded by an edited cart (#3328)
- ✓clears the key on failure so reopening retries
✓SHIPPING_PATH_COPYBusiness rules3
- ✓provides plain-English copy for every bucket (no internal jargon)
- ✓never leaks the fulfillment source or location to the customer (#1086)
- ✓never names an individual staff member in customer copy (#1086)
✓daysUntilExpiryAccount pages3
- ✓returns positive count for a card with months left
- ✓returns negative count for a card that already expired
- ✓returns 0 when the card expires today
✓stale shipping rate (wrong-charge guard)Checkout pages3
- ✓drops a rate stamped against a different cart and routes back to re-quote
- ✓drops an unstamped legacy rate rather than trusting it
- ✓keeps a rate whose stamp still matches the cart, and lets payment render
✓complete reviewCheckout pages3
- ✓totals the cart subtotal plus the selected rate
- ✓marks the checkout step as review
- ✓renders the order summary and does not redirect
✓happy pathCheckout pages3
- ✓redirects to the Stripe url and fires add_payment_info before leaving
- ✓sends the cart, address and rate the caller was given
- ✓warns and un-busies the button if the Stripe navigation never happens
✓FreeShippingOptions — per-state timing badge (John's spec)Checkout pages3
- ✓renders 'Arrives in 3-5 business days' subtitle for a dis-stock cart
- ✓renders 'Arrives in 5 business days' subtitle for a cnh-overnight cart
- ✓renders 'Arrives in 6 business days' (slowest tier) for multi-source dfs+dis cart
✓FreeShippingOptions — regression guards for John's 2026-05-17 prod bugCheckout pages3
- ✓does NOT render any 'Standard' row (predicate leaked Local Pickup chip on prod)
- ✓does NOT render any 'Local Pickup' chip anywhere (chip leaked to Standard row on prod)
- ✓does NOT surface 'LTL Freight' as a selectable rate
✓addressSchema — phone is required (#515)Checkout pages3
- ✓rejects a missing phone
- ✓rejects an empty phone
- ✓still rejects a malformed phone
✓createAddressSchema(isGuest) — guest email requirement (regression pin)Checkout pages3
- ✓requires email when isGuest=true
- ✓accepts isGuest=false without email
- ✓accepts isGuest=true with valid email
✓ShippingForm — the validated address is the one in the formCheckout pages3
- ✓validates the edited address, keeping no field of the first entry
- ✓does not snap a mid-edit form back to the address already in the store
- ✓does not let a late profile hydration overwrite what the customer is typing
✓cart-service client — 404 handling (front#3000)Business rules2
- ✓passes a service-reported 404 (e.g. no saved cart) through as its own code/message
- ✓still reports a route-miss generically when the 404 body carries no service error
✓countSharedCartPiecesBusiness rules2
- ✓counts pieces, not lines — the cart badge counts the same way (#3263)
- ✓is 0 for an empty snapshot
✓a snapshot line is directly addable to the cartBusiness rules2
- ✓never carries a key the cart store would not accept
- ✓always carries every field the cart needs to render the line
✓<CartItemCard> subtitle — SKU displayCart page2
- ✓shows NHL-{PN} in subtitle when branded sku is present (no CT- prefix)
- ✓falls back to raw partNumber in subtitle when sku is absent
✓<CartSummary> — Continue to shipping link target (front#910)Cart page2
- ✓renders the checkout CTA as a plain anchor (full nav, not soft nav)
- ✓omits the checkout CTA when the cart is empty
✓<CartSummary> — first-order promo gated by NEXT_PUBLIC_FEATURE_FIRST_ORDER_DISCOUNT (#1101)Cart page2
- ✓hides the '15% off your first order' promo when the flag is OFF (default)
- ✓shows the promo when the flag is ON
✓<CartSummary> — shareable-cart hand-off stays surfaced (#2257)Cart page2
- ✓renders the Share cart + Send to staff actions for a non-empty cart
- ✓omits the share actions when the cart is empty
✓isCheckoutErrorRetryableCheckout pages2
- ✓flags retryable hints
- ✓treats config/permission classes as non-retryable
✓incomplete shippingCheckout pages2
- ✓blocks payment and routes to shipping when no address is stored
- ✓blocks payment and routes to shipping when no rate is selected
✓CART_STALECheckout pages2
- ✓drops the vanished lines, refreshes prices, and routes back to /cart
- ✓does not fire the payment-info funnel event on a stale cart
✓InlineDeliveryOptions — error panel (#621)Checkout pages2
- ✓renders single error panel + Retry when error AND no rates AND not loading
- ✓renders rate cards (not error panel) when error is present BUT cached rates remain
✓CNH-overnight parity — #1437 flag-state contractCheckout pages2
- ✓flag=on: mismatch → isMatch:false so caller sets shippingMismatchBlock
- ✓flag=off: mismatch → isMatch:false triggers Sentry warn only, no block
✓detectPOBoxCheckout pages2
- ✓flags common PO Box formats
- ✓does not flag ordinary street addresses
✓usePhoneFormatterCheckout pages2
- ✓calls setValue with formatted phone and shouldValidate
- ✓clears formatted value when input becomes empty
✓paymentServiceClient.deletePaymentMethodBusiness rules1
- ✓calls DELETE /api/customers/:clerkUserId/payment-methods/:pmId
✓paymentServiceClient.setDefaultPaymentMethodBusiness rules1
- ✓calls POST /api/customers/:clerkUserId/payment-methods/:pmId/default
✓createCheckoutSessionAction — country guard (Gap I)Server actions1
- ✓rejects a non-US country code at the Zod gate, before any backend call
✓MAX_LINE_QTYBusiness rules1
- ✓caps cart-line qty at 99 so the two PDP surfaces stay in sync
✓sumSharedCartSubtotalBusiness rules1
- ✓sums quantity times unit price
✓empty cartCheckout pages1
- ✓shows the empty-cart message and sends the customer to /cart
✓PACK_INVARIANT_VIOLATIONCheckout pages1
- ✓tracks each violation, warns Sentry, and shows a pack-specific error
✓FreeShippingOptions — John's 'never show mechanism' hard ruleCheckout pages1
- ✓does NOT leak the words DIS / CNH / depot / dfs anywhere on the customer surface
✓FreeShippingOptions — Pickup row click round-tripCheckout pages1
- ✓invokes onSelect with PICKUP_RATE when the Pickup row is clicked
✓ShippingForm — the PO Box warning reads the current streetCheckout pages1
- ✓clears the PO Box warning once the street is no longer a PO Box
✓checkout store — a new address leaves no trace of the previous oneCheckout pages1
- ✓replaces every field and clears the previous submission's rate failure
What we walk through in a real browser24 journeys
○Your order flowBrowser journey11
- ○should show empty cart state initially
- ○should add item to cart from product page
- ○should update quantity in cart
- ○should decrease quantity and enforce minimum of 1
- ○should remove item from cart
- ○should clear entire cart via dialog
- ○should navigate to checkout
- ○should display correct subtotal calculation
- ○should persist cart across page navigation
- ○removing one of two lines removes the correct line
- ○re-adding a removed part starts at quantity 1, not resurrected
○stage checkout - every cart keeps a way to check outBrowser journey9
- ○on-shelf cart below the free-shipping threshold
- ○on-shelf cart at or above the free-shipping threshold
- ○off-shelf cart below the free-shipping threshold
- ○off-shelf cart at or above the free-shipping threshold
- ○cart mixing an on-shelf line with one that ships in first
- ○heavy cart keeps pickup and is offered the freight route beside it
- ○heavy line mixed with an on-shelf line keeps pickup and the freight route
- ○a shelf line at quantity three is judged on the whole line, not the unit
- ○the carrier row swaps a price for free shipping across the threshold
○stage checkout — the money pathBrowser journey5
- ○a priced lane's own price is what the review step charges for shipping
- ○control — a free lane charges nothing and leaves the total equal to the subtotal
- ○the Pay control reaches Stripe checkout-session creation
- ○control — Pay refuses a cart the catalog cannot sell, and creates no session
- ○a quantity above the ceiling never reaches Stripe, and the cart comes back corrected
○stage checkout — the pickup promise matches the real catalogBrowser journey5
- ○a real ship-in part is never promised same-day collection
- ○a real Clinton-shelf part promises Today on a preselected lane
- ○the review step repeats the collection window the picker stated
- ○a mixed cart is governed by its worst line
- ○regression inverse — this build can still promise Today for a shelf cart
○stage cart — the four item-count surfaces agreeBrowser journey4
- ○one line at quantity 3 reads the same on all four surfaces
- ○two lines totalling 3 read the same on all four surfaces
- ○a quantity change on the page moves all four surfaces together
- ○control — every surface tracks the cart instead of printing one frozen number
○guest cart survives navigation @smokeBrowser journey3
- ○a removed line stays gone after a full-document reload
- ○a removed line stays gone through the checkout CTA and Back/Forward
- ○a quantity change survives the round-trip to checkout and back
○UC-7 — cart pack-buy stepper (#959 — singles allowed)Browser journey3
- ○pack-buy line shows pack hint + steps by 1
- ○pack-buy line: decrement disabled at qty=1 (singles lower bound)
- ○non-pack item steps by 1 (regression guard for the pack code path)
○checkout review — stale shipping rate is droppedBrowser journey3
- ○redirects to /checkout/shipping when the cart changed since the rate was chosen
- ○stays on review when the rate still matches the current cart
- ○a real cart edit (remove a line) invalidates the matching rate
○#1063 — checkout-shipping intent-gap blockBrowser journey3
- ○static DOM: blocking alert + Continue-disabled require a flag-on + block-state path
- ○BE valid:false + canContinue:true + cost mismatch → Continue blocked (BLOCKED on R9 mock-delivery)
- ○BE canContinue:true + transient (no rateCost) → warn+retry preserved (BLOCKED on R9 mock-delivery)
○stage checkout — address integrity, deployed site onlyBrowser journey3
- ○editing address A to B leaves no field holding A, and never the store's own PO Box
- ○the submitted payload and /checkout/review carry the edited address, not the abandoned one
- ○the PO Box warning tracks the street the field holds now
○stage checkout — delivery-lane coherenceBrowser journey3
- ○overnight is offered and honoured at its own price, or declared unavailable
- ○off-shelf cart preselects nothing and blocks submit until a lane is chosen
- ○control — an on-shelf cart arrives with a delivery lane already selected
○cart — bfcache restore keeps the price in sync @smokeBrowser journey2
- ○re-syncs subtotal to localStorage on a persisted pageshow
- ○re-syncs a combined add + remove + quantity change on restore
○Checkout address editBrowser journey2
- ○#3250 — editing the address leaves no field of the previous one
- ○#3250 — the PO-Box warning reads the street currently in the field
○Checkout address revisit editBrowser journey2
- ○the address corrected on a revisit is the one that gets validated
- ○no field of the stored address survives the correction
○checkout — cart hydration race (#316 guard)Browser journey2
- ○renders a legacy cart item missing packQty/requiresPackBuy fields
- ○empty cart hydrates to the empty-state copy (not stuck on a skeleton)
○Rate-label render via persisted checkout (front#497)Browser journey2
- ○sidebar "Delivery" row renders "Free — In-Store Pickup" for clinton pickup ($0)
- ○sidebar renders "$X.XX" for paid UPS rate
○checkout — shipping page entry guardsBrowser journey2
- ○shows empty-cart guard when arriving with no items
- ○populated cart shows the order-summary sidebar with item details
○UC-1 — same-state customer reaches checkout shipping (front#467 Phase H)Browser journey2
- ○NY customer with an in-stock part lands on the populated shipping form
- ○ZIP input is numeric on mobile (Phase A inputmode='numeric' regression pin)
○checkout — stale cart price is silently rejected server-side @smokeBrowser journey1
- ○a drifted line bounces the customer to /cart with no drift-notice UI
○cart multi-source ship-from bannerBrowser journey1
- ○renders one distinct row per shipping bucket (not a duplicated run)
○checkout — cancel pageBrowser journey1
- ○renders failure copy + recovery CTAs + support mailto
○UC-15 — international US-only block (front#467 Phase E)Browser journey1
- ○US-only notice + contact-us redirect render on /checkout/shipping
○checkout payment smoke (nightly, opt-in — places a TEST order)Browser journey1
- ○paying with the Stripe test card produces an order with a number
○NH buy-path — real part reaches the Stripe checkout step @smokeBrowser journey1
- ○real NH part → real add-to-cart → /checkout/review → session-create fires
Automated checks641
Browser journeys21
Code exercised77.4%
What we check automatically101 groups
✓handleModelRoutingRequest routing54
- ✓returns null when the pathname is not a model URL
- ✓redirects legacy BRAND::MODEL /equipment URLs to the clean slug assemblies page
- ✓handles URL-encoded legacy identifiers the same way
- ✓returns a hard 404 at the edge when a legacy identifier has no vocabulary entry
- ✓never consults the visibility probe for legacy identifiers
- ✓rewrites hidden /equipment slugs to /equipment-not-found with HTTP 404 (CT-674 / GH #65)
- ✓returns null when a non-legacy slug is visible (request proceeds to the page)
- ✓redirects a bare model number to the canonical slug when Hono vocabulary knows it
- ✓rewrites /parts-diagrams/model/* to /equipment-not-found when neither visibility probe nor model-number lookup place the identifier (CT-674 / GH #65)
- ✓redirects single-variant short slug to canonical compound PDP (308)
- ✓redirects multi-variant short slug to /variants disambig page (308)
- ✓falls through to equipment-not-found rewrite when resolveShortSlug returns null
- ✓attaches a browser Cache-Control to the short-slug 308 (#1734)
- ✓caches a resolved short slug so a crawl burst probes hono once (#1734)
- ✓does NOT cache short-slug misses — data refreshes stay re-probeable (#1734)
- ✓is not consulted when bare-number, /parts/, or visible-slug paths already short-circuit
- ✓rewrites /parts-diagrams/model/<uuid> to /equipment-not-found without probing Hono
- ✓matches uppercase-hex UUIDs (case-insensitive)
- ✓does NOT treat similar-looking but non-UUID slugs as UUIDs
- ✓redirects /parts-diagrams/model/9000 to /parts?q=9000 when vocabulary has no match (John's Apr 16 case)
- ✓takes precedence over equipmentNotFoundRewrite for 3-digit numerics
- ✓does NOT fire when resolveSlugByModelNumber finds a canonical slug
- ✓does NOT fire for non-numeric slugs (still rewrites to /equipment-not-found)
- ✓does NOT fire for 6+ digit identifiers (those are part-number shaped)
- ✓still returns edge 404 for /parts/{assemblyCode}/assemblies when unresolvable
- ✓does not consult the model-number lookup when the slug is already visible
- ✓also handles /parts/{assemblyCode}/assemblies paths through the visibility probe
- ✓does not try to resolve a legacy slug for clean slug URLs
- ✓rewrites /parts-diagrams/model/{hidden-slug}/parts-diagrams to /equipment-not-found (CT-674 / GH #88)
- ✓rewrites /parts-diagrams/model/{hidden-slug}/parts-diagrams/{code} to /equipment-not-found (CT-674 / GH #88)
- ✓returns null for a visible slug on /parts-diagrams/model/{slug}/parts-diagrams (CT-674 / GH #88)
- ✓redirects list form /parts/{UUID}/assemblies when model is visible
- ✓redirects detail form /parts/{UUID}/assemblies/{asm} preserving the assembly code
- ✓redirects detail form preserving the ?highlight=N query parameter
- ✓redirects ABC-prefixed model codes (e.g. NHL-style) the same way
- ✓returns 404 when the visible model has no resolvable slug
- ✓returns 404 when the model is hidden (never reveals the slug)
- ✓preserves multiple query parameters through the redirect
- ✓404s + noindex for a short model number with <4 digits (FX48)
- ✓308s a short model number to /parts-diagrams when the model resolves (FX48)
- ✓404s + noindex for a hyphenated branded SKU (CT-NHL-01A6663)
- ✓308s a branded SKU to /parts-diagrams when the model resolves
- ✓404s + noindex for a junk id with a junk assembly code (x / foo-bar-baz)
- ✓never resolves the slug for a hidden model (keeps Case IH hidden)
- ✓rewrites visible /parts-diagrams/model/{slug} with non-equipment sub_line to /equipment-not-found (HTTP 404)
- ✓rewrites /parts-diagrams/model/{slug}/parts-diagrams with non-equipment sub_line
- ✓returns null (request proceeds) when sub_line is a real equipment class
- ✓never consults non-equipment probe when visibility probe returns false
- ✓308s /parts-diagrams/model/COUNTY-1124 to the canonical lowercase slug
- ✓preserves the sub-path and query on the heal
- ✓does not probe for a canonical when the slug is already lowercase
- ✓leaves a canonical that differs by more than case to the page resolver
- ✓falls through when hono cannot resolve a canonical slug
- ✓still 308s an uppercase bare model number to its parts-diagrams page
✓resolveNhModelFamilyImageEquipment data53
- ✓maps New Holland T4.110 to bucket new-holland/models/t4.webp
- ✓maps T455 to bucket new-holland/models/t4.webp
- ✓maps New Holland T5.110 to bucket new-holland/models/t5.webp
- ✓maps New Holland T6.180 Auto Command to bucket new-holland/models/t6.webp
- ✓maps New Holland T7.270 to bucket new-holland/models/t7.webp
- ✓maps New Holland T7000 to bucket new-holland/models/t7.webp
- ✓maps New Holland T8.435 to bucket new-holland/models/t8.webp
- ✓maps New Holland Genesis T8.410 to bucket new-holland/models/t8.webp
- ✓maps New Holland T9.700 to bucket new-holland/models/t9.webp
- ✓maps Powerstar 120 to bucket new-holland/models/powerstar.webp
- ✓maps New Holland PowerStar T4.75 to bucket new-holland/models/powerstar.webp
- ✓maps New Holland BOOMER-40 to bucket new-holland/models/boomer-40.webp
- ✓maps BOOMER-45 to bucket new-holland/models/boomer-45.webp
- ✓maps New Holland Boomer 50 to bucket new-holland/models/boomer.webp
- ✓maps New Holland Boomer 3040 to bucket new-holland/models/boomer.webp
- ✓maps BOOMER-45D to bucket new-holland/models/boomer.webp
- ✓maps BOOMER-4055 to bucket new-holland/models/boomer.webp
- ✓maps WORKMASTER-75 to bucket new-holland/models/workmaster.webp
- ✓maps New Holland Workmaster 105 to bucket new-holland/models/workmaster.webp
- ✓returns null for uncovered tractor New Holland 54CMS (icon, never wrong-family art)
- ✓returns null for uncovered tractor New Holland 60CMS (icon, never wrong-family art)
- ✓returns null for uncovered tractor New Holland 71GM (icon, never wrong-family art)
- ✓returns null for uncovered tractor New Holland 72-85 (icon, never wrong-family art)
- ✓returns null for uncovered tractor New Holland 115UV (icon, never wrong-family art)
- ✓returns null for uncovered tractor New Holland T3.65 (icon, never wrong-family art)
- ✓returns null for uncovered tractor TN70 (icon, never wrong-family art)
- ✓returns null for uncovered tractor TC40DA (icon, never wrong-family art)
- ✓returns null for uncovered tractor TD5050 (icon, never wrong-family art)
- ✓returns null for uncovered tractor TS6110 (icon, never wrong-family art)
- ✓prefers the Powerstar/Boomer name over a bare T-token
- ✓maps ROLL-BELT-460 to bucket new-holland/balers/roll-belt.webp
- ✓maps New Holland Roll-Belt 560 to bucket new-holland/balers/roll-belt.webp
- ✓maps BR740A to bucket new-holland/balers/roll-belt.webp
- ✓maps PRO-BELT-165 to bucket new-holland/balers/pro-belt.webp
- ✓maps BIGBALER-330P to bucket new-holland/balers/big-baler.webp
- ✓maps BB940AP to bucket new-holland/balers/big-baler.webp
- ✓maps HAYLINER-275 to bucket new-holland/balers/small-square.webp
- ✓maps BC5070 to bucket new-holland/balers/small-square.webp
- ✓returns null for uncovered baler 565 (icon, never wrong-class art)
- ✓returns null for uncovered baler 4800 (icon, never wrong-class art)
- ✓returns null for uncovered baler D1000 (icon, never wrong-class art)
- ✓returns null for uncovered baler RF440-UTILITY (icon, never wrong-class art)
- ✓returns null for uncovered baler HS330-A (icon, never wrong-class art)
- ✓never resolves a baler token under tractors
- ✓never resolves a tractor token under balers
- ✓returns null for a type with no matcher set
- ✓is gated to New Holland — other brands always return null
- ✓normalizes the brand slug case
- ✓returns null for an empty/missing model name
- ✓maps the free-form singular labels the chapters API returns
- ✓passes already-canonical or unknown labels through slugified
- ✓feeds the family resolver end-to-end (label + bare model number)
- ✓every family photo's in-repo source asset exists on disk
✓resolveModelImageEquipment data43
- ✓uses model photo when imageUrl is present
- ✓falls back to per-type photo when imageUrl is missing
- ✓treats empty imageUrl string as missing
- ✓returns icon source when neither model nor type photo exists
- ✓treats undefined imageUrl as missing
- ✓accepts a marketing CDN hero URL as the rung-1 model photo
- ✓a marketing CDN hero outranks the repo-local curated cutout (DIS wins)
- ✓never renders a schematic CDN URL — falls through past rung 1
- ✓uses the representative family photo for a covered NH series
- ✓a real backend model photo still wins over the family photo
- ✓legacy/uncovered NH models fall through to the per-type illustration, not family
- ✓does not apply family photos to non-NH brands
- ✓covers the T4 utility series (grid-imagery pass)
- ✓covers the Workmaster utility series (grid-imagery pass)
- ✓maps the New Holland Roll-Belt 560 card to its class photo
- ✓maps the New Holland Pro-Belt 165 card to its class photo
- ✓maps the New Holland BigBaler 330 card to its class photo
- ✓maps the New Holland BC5070 card to its class photo
- ✓a numeric legacy baler falls through to the on-brand category card (no wrong-class art)
- ✓a baler token under tractors never borrows a baler photo
- ✓uses the curated cutout for a mapped model code
- ✓a real backend model photo still wins over the curated cutout (DIS is SoT)
- ✓the curated cutout wins over the brand category card
- ✓a schematic backend imageUrl is ignored and the curated cutout takes over
- ✓an unmapped model falls through to the brand category card (no near-miss)
- ✓renders the McHale Balers card on its own type grid (matching type)
- ✓renders the McHale Mowers card on its own type grid (matching type)
- ✓renders the McHale Bale Handlers card on its own type grid (matching type)
- ✓never borrows the baler card on the unscoped 'Other' grid (empty typeSlug)
- ✓ignores a schematic imageUrl and falls to the brand cutout (#2067)
- ✓never borrows the baler card for a McHale type with no card of its own (Shear Grab)
- ✓a brand type with no curated photo falls through to the icon (NH)
- ✓flags a /drawings/ assembly thumbnail as a schematic (McHale)
- ✓flags a /schematics/ assembly thumbnail as a schematic (Kuhn)
- ✓treats a real product photo path as a photo
- ✓is false for null/undefined/empty
- ✓uses the sub-category cutout for a construction model, keyed by product line
- ✓maps the numeric Ford heritage tail to the tractor-loaders cutout
- ✓a real backend model photo still wins over the category cutout
- ✓falls through to type-photo when the construction line maps to no sub-category
- ✓resolves the cutout from what the parts-diagrams header actually has (#2815)
- ✓never applies the construction cutout outside the construction type
- ✓does not apply the construction cutout to non-NH brands
✓getTypeImageSrc — cross-brand canon slugs (#1745)Equipment data25
- ✓canon slug zero-turn-mowers resolves to bucket ferris/equipment-types/zero-turn.webp
- ✓canon slug walk-behind-mowers resolves to bucket ferris/equipment-types/walk-behind.webp
- ✓canon slug riding-mowers resolves to bucket equipment-types/commercial-mowers.webp
- ✓canon slug skid-steers resolves to bucket equipment-types/construction.webp
- ✓canon slug attachments resolves to bucket ferris/equipment-types/attachments.webp
- ✓canon slug debris-blowers resolves to bucket ferris/equipment-types/blowers.webp
- ✓canon slug generators resolves to bucket ferris/equipment-types/standby-generator.webp
- ✓canon slug bale-wrappers resolves to bucket mchale/991B-Round-Bale-Wrapper-Cutout-small.png
- ✓canon slug bale-handlers resolves to bucket mchale/equipment-types/bale-handlers.webp
- ✓canon slug disc-mowers resolves to bucket mchale/equipment-types/disc-mowers.webp
- ✓canon slug turf-mowers resolves to bucket ventrac/equipment-types/turf-mowers.webp
- ✓canon slug snow-removal resolves to bucket ventrac/equipment-types/snow-removal.webp
- ✓source for zero-turn-mowers exists under public/ and is within the LCP weight budget
- ✓source for walk-behind-mowers exists under public/ and is within the LCP weight budget
- ✓source for riding-mowers exists under public/ and is within the LCP weight budget
- ✓source for skid-steers exists under public/ and is within the LCP weight budget
- ✓source for attachments exists under public/ and is within the LCP weight budget
- ✓source for debris-blowers exists under public/ and is within the LCP weight budget
- ✓source for generators exists under public/ and is within the LCP weight budget
- ✓source for bale-wrappers exists under public/ and is within the LCP weight budget
- ✓source for bale-handlers exists under public/ and is within the LCP weight budget
- ✓source for disc-mowers exists under public/ and is within the LCP weight budget
- ✓source for turf-mowers exists under public/ and is within the LCP weight budget
- ✓source for snow-removal exists under public/ and is within the LCP weight budget
- ✓keeps the icon fallback for a slug without an honest asset yet
✓getTypeImageSrc — Ferris category tilesEquipment data20
- ✓categoryId 250317 resolves to bucket ferris/equipment-types/zero-turn.webp
- ✓categoryId 250137 resolves to bucket ferris/equipment-types/walk-behind.webp
- ✓categoryId 781272 resolves to bucket ferris/equipment-types/blowers.webp
- ✓categoryId 780353 resolves to bucket ferris/equipment-types/spreader-sprayer.webp
- ✓categoryId 249721 resolves to bucket ferris/equipment-types/front-mount.webp
- ✓categoryId 250917 resolves to bucket ferris/equipment-types/front-mount.webp
- ✓categoryId 249811 resolves to bucket ferris/equipment-types/attachments.webp
- ✓categoryId 848593 resolves to bucket ferris/equipment-types/standby-generator.webp
- ✓categoryId 250911 resolves to bucket ferris/equipment-types/trim-mower.webp
- ✓source for 250317 exists under public/ and is within the LCP weight budget
- ✓source for 250137 exists under public/ and is within the LCP weight budget
- ✓source for 781272 exists under public/ and is within the LCP weight budget
- ✓source for 780353 exists under public/ and is within the LCP weight budget
- ✓source for 249721 exists under public/ and is within the LCP weight budget
- ✓source for 250917 exists under public/ and is within the LCP weight budget
- ✓source for 249811 exists under public/ and is within the LCP weight budget
- ✓source for 848593 exists under public/ and is within the LCP weight budget
- ✓source for 250911 exists under public/ and is within the LCP weight budget
- ✓returns null for an unmapped Ferris categoryId (tail → Lucide icon)
- ✓leaves the New Holland global slug map intact
✓handleEquipmentSlugCarveRequest routing14
- ✓leaves the showcase unit id /equipment/226238199 alone
- ✓leaves the showcase unit id /equipment/251737489 alone
- ✓leaves the showcase unit id /equipment/251431557/ alone
- ✓308s a legacy model slug to its diagram page
- ✓carves the bare model number 338 onto the model tree
- ✓carves the bare model number 8340 onto the model tree
- ✓carves the bare model number 12345 onto the model tree
- ✓preserves the query string, so ?brand= still disambiguates
- ✓carves a bare model number with a query string too
- ✓308s a trailing-slash slug
- ✓falls through on /equipment
- ✓falls through on /equipment/
- ✓falls through on /equipment/226238199/extra
- ✓falls through on /equipment/t7-230/variants
✓handleEquipmentTypeRedirectRequest routing13
- ✓308s an unknown equipmentType, preserving every other param
- ✓preserves multi-value params and drops only equipmentType
- ✓does not redirect a known-brand equipmentType
- ✓does not redirect when equipmentType is absent
- ✓does not redirect when equipmentType is empty
- ✓fails open (no redirect) when the probe errors after its retry
- ✓recovers when the retry succeeds
- ✓redirects (without probing) when no manufacturer is selected
- ✓redirects (without probing) for a multi-brand selection
- ✓redirects (without probing) when a search query is active
- ✓ignores paths other than the bare /parts leaf
- ✓caches the probe per brand slug
- ✓never includes equipmentType in the redirect target
✓KNOWN_VENDORSEquipment data12
- ✓carries exactly the activated vendors (NHL + FER + VNT + MCH + MAR + KUH + KRE + LDL + BRL + AGC)
- ✓flags Ferris carried but not seo-indexed (navigable, noindex)
- ✓flags VNT carried but not seo-indexed (navigable, noindex)
- ✓flags MCH carried but not seo-indexed (navigable, noindex)
- ✓flags MAR carried but not seo-indexed (navigable, noindex)
- ✓flags KUH carried but not seo-indexed (navigable, noindex)
- ✓flags KRE carried but not seo-indexed (navigable, noindex)
- ✓flags LDL carried but not seo-indexed (navigable, noindex)
- ✓flags BRL carried but not seo-indexed (navigable, noindex)
- ✓flags AGC carried but not seo-indexed (navigable, noindex)
- ✓covers every brand the legacy BRANDS array exposed
- ✓has unique vendor codes (no duplicate-code lookup ambiguity)
✓<EquipmentNotFoundEnhancer> slug extractionProduct features11
- ✓extracts the identifier from /parts-diagrams/model/county-1124
- ✓extracts the identifier from /parts-diagrams/model/county-1124/parts-diagrams
- ✓extracts the identifier from /parts-diagrams/model/county-1124/parts-diagrams/AB12
- ✓extracts the identifier from /parts-diagrams/model/county-1124/variants
- ✓extracts the identifier from /parts-diagrams/new-holland/CX8070
- ✓extracts the identifier from /parts-diagrams/new-holland/CX8070/AB12
- ✓never mistakes the literal 'model' namespace segment for the slug
- ✓renders nothing when no identifier can be parsed from /equipment-not-found
- ✓renders nothing when no identifier can be parsed from /parts-diagrams
- ✓renders nothing when no identifier can be parsed from /parts-diagrams/models
- ✓renders nothing when no identifier can be parsed from /parts-diagrams/model/
✓groupSavedPartsByMachineBusiness rules11
- ✓returns empty groups and empty unmatched when no parts and no equipment
- ✓puts all parts in unmatched when there are no machines
- ✓returns empty groups and empty unmatched when no parts are saved
- ✓groups a part under the single matching machine
- ✓places a part with no equipmentModelKeys into unmatched
- ✓places a part with an empty equipmentModelKeys array into unmatched
- ✓places a part in every machine it fits
- ✓separates matched and unmatched parts in one pass
- ✓ignores non-parts favorited products even when domain mixed input is passed
- ✓preserves machine order from the input equipment list
- ✓treats modelKey matching as exact string equality (case-sensitive)
✓loadInventoryEquipment pages11
- ✓narrows the result count when filtering by manufacturer
- ✓respects price bounds
- ✓narrows the result count when filtering by category family
- ✓narrows further when combined with a manufacturer filter
- ✓facetScope restricts facet counts and bounds, but never the result rows
- ✓returns different ids on page 2 than page 1
- ✓narrows the result count when filtering by year
- ✓excludes year-less rows once the year filter is set
- ✓narrows the result count on a keyword match against model or stock number
- ✓matches a keyword search case-insensitively against stock number
- ✓puts year-less rows after every dated row under year_desc
✓equipment-type canon (#1740 interim)Equipment data10
- ✓maps every live vendor key except the documented unmapped tail
- ✓canon contains no key outside the live vocabularies (no phantom mappings)
- ✓never maps one vendor key into two canonical types
- ✓headline mappings: NH construction → skid-steers, Ventrac split, McHale folds
- ✓GAP 2 split (#2134): disc-mowers = NH + McHale disc; turf-mowers = the Ventrac rough-cut tail
- ✓keeps ranking NH slugs as canonical slugs where they already align
- ✓hrefOverride: only skid-steers carries one, targeting the NHC surface (#1507)
- ✓ordering is unique, 1-based and NOT alphabetical
- ✓groupRowsByCanon sums counts, dedups brands and isolates unmapped rows
- ✓a type never lists a vendor that lacks it — groups only contain fetched rows
✓findGarageMatchesShared helpers10
- ✓returns the single equipment record whose modelKey is in the part's keys
- ✓returns multiple matches in original garage order
- ✓returns [] for an empty garage
- ✓returns [] when part keys are empty
- ✓returns [] when part keys are undefined
- ✓returns [] when part keys are null
- ✓returns [] when garage is undefined
- ✓requires exact string equality on modelKey (no prefix matches)
- ✓does not duplicate a garage record when the same key appears twice in part keys
- ✓does not match across non-canonical brand prefixes (NH vs NHL)
✓getClerkErrorSign-in10
- ✓returns a friendly message for known error codes
- ✓returns action link for form_identifier_not_found
- ✓includes redirect_url in action href when searchParams provided
- ✓returns action for form_identifier_exists
- ✓returns action for external_account_not_found
- ✓returns action for external_account_exists
- ✓falls back to longMessage for unknown Clerk error codes
- ✓uses error.message for plain Error instances
- ✓returns default message for non-Error values
- ✓returns default message for null
✓equipmentUrlSafeShared helpers9
- ✓returns slug URL when slug is provided
- ✓threads ?brand= onto the slug URL when brand is known
- ✓does NOT append ?brand= to the /parts fallback (no slug)
- ✓falls back to /parts?equipmentModelKey={modelKey} when slug is null
- ✓falls back when slug is undefined
- ✓falls back when slug is empty string
- ✓encodes special characters in modelKey
- ✓treats an all-digits slug as absent → legacy modelKey fallback (#3029)
- ✓keeps a kebab slug that merely contains digits (t7-230)
✓AdminInventoryPageAccount pages9
- ✓renders stock KPI stats in dev
- ✓renders the stock-by-category, trend and low-stock visualizations in dev
- ✓scales stock-health bars on a shared domain, not all full-length
- ✓derives bar heights from one shared ceiling across all category rows
- ✓renders the stock table with real demo rows in dev
- ✓offers a restock affordance per row in dev
- ✓labels the workspace as demo data in dev
- ✓shows an empty state with no fabricated stock in prod
- ✓redirects a non-admin away
✓EquipmentModelCombobox — custom equipment entryInterface pieces8
- ✓offers the custom option in the empty state and selecting it emits a CUSTOM model
- ✓renders the custom option below real results and keeps real results selectable
- ✓does not offer the custom option for a query below minQueryLength
- ✓does not offer the custom option while a search is in flight
- ✓normalizes collapsed whitespace in the custom model name and key
- ✓does not crash when the query itself contains '::'
- ✓offers the custom option on the mobile drawer path too
- ✓renders 'Custom equipment' as the trigger subtitle for a selected custom value
✓<ModelMediaTile>Interface pieces8
- ✓renders the photo for a representative family photo (object-cover default)
- ✓renders a construction cutout object-contain so the machine is never cropped
- ✓renders a brand category card object-contain (the brand's own per-type photo)
- ✓renders the branded placeholder (no photo) for the terminal icon case
- ✓renders the category illustration object-contain for source=type-photo (#2698)
- ✓falls back to the generic type illustration when the model photo fails to load
- ✓lands on the branded placeholder once every rung has failed
- ✓renders the image byte-identically and NO admin chrome when the gate is off (editContext, customer default)
✓runModelPipelineBusiness rules8
- ✓chooses the first triage-ranked candidate the detailed check passes (iteration 1)
- ✓walks down the triage ranking until one passes
- ✓never verifies a candidate at or below the 50% walk floor
- ✓does NOT accept a pass judged on a thumbnail fallback (routes to human)
- ✓feeds reject reasons into the NEXT round's optimizer call
- ✓feeds the distinct found-nothing note when a search returns zero live candidates
- ✓walks by search-heuristic order when triage is unavailable
- ✓returns needs-human with the last reason + recommended query after exhausting rounds
✓equipmentAssemblyListUrlSafeShared helpers8
- ✓returns slug URL when slug is provided
- ✓builds the slug URL without ?brand= (route resolves by slug)
- ✓falls back to /parts/{modelCode}/assemblies when slug is null
- ✓falls back when slug is undefined
- ✓falls back when slug is empty string
- ✓encodes special characters in fallback modelCode
- ✓front#522: redirects compound modelKey (`::`) to /parts?equipmentModelKey= instead of 404 path
- ✓treats an all-digits slug as absent → legacy assemblies fallback (#3029)
✓formatModelNameShared helpers8
- ✓returns empty string for empty input
- ✓formats simple model numbers
- ✓separates letter-number transitions
- ✓capitalizes first letter
- ✓cleans MCH model names with language suffixes
- ✓cleans MCH model names with category prefixes
- ✓preserves dot-separated model numbers
- ✓handles models with letter-number patterns
✓<MachinePartsCta>Account pages8
- ✓renders a link to the canonical filtered parts catalog (R7: encodes modelKey)
- ✓normalizes short-form backend brand codes (e.g. NH → NHL)
- ✓still emits the modelKey filter for unknown brand codes
- ✓encodes URL-special characters in modelKey
- ✓renders a visible label naming the model
- ✓aria-label contains both the visible text and the model (WCAG 2.5.3)
- ✓renders nothing for custom equipment (isCustom flag)
- ✓renders nothing for a CUSTOM brand code even without the isCustom flag
✓groupModelsByBrandGoogle visibility7
- ✓sections by brand, largest first
- ✓labels each link with the bare designation, not the brand-prefixed name
- ✓does NOT bucket by first letter
- ✓sorts within a section numerically (T6.50 before T6.180)
- ✓emits a slug-safe section key
- ✓parks a brandless model rather than dropping it
- ✓drops rows with a blank slug or no usable label (no anchor to render)
✓/api/equipment carried-vendor gateAPI endpoints7
- ✓defaults brandCode to the carried set when omitted
- ✓intersects a requested brandCode list with the carried set
- ✓short-circuits a strictly non-carried request with an empty result and no upstream fetch
- ✓rejects an over-limit pageSize with 400 and never hits upstream
- ✓rejects a non-numeric pageSize with 400
- ✓forwards an in-bounds custom pageSize to upstream unchanged
- ✓accepts lowercase brandCode by normalising to uppercase before the carried check
✓<ReorderMachineButton>Account pages7
- ✓adds cart items, toasts success, and navigates to /cart on happy path
- ✓preserves packQty and requiresPackBuy on cart items it adds
- ✓does not navigate when allFailed is true and emits a failure toast
- ✓surfaces an error toast when the action returns ok=false
- ✓surfaces an error toast when the action throws
- ✓emits grouped warnings for price_changed, stock_reduced, out_of_stock and discontinued
- ✓flips to the in-flight label while the re-order is pending
✓getHandlingBandEquipment data6
- ✓returns undefined for every vendor when the gate is off (default / PROD)
- ✓returns the configured band for each seeded vendor
- ✓seeds Kuhn/Ferris/Ventrac at John's interim 3–5 day window (CROP GREEN 2026-07-14, pending his per-vendor table hub#201)
- ✓is case-insensitive on the vendor code
- ✓returns undefined for an unconfigured vendor
- ✓returns undefined for null/undefined/empty input
✓handleEquipmentTypeRedirect — parity with buildListingHrefWithoutEquipmentTypeRequest routing6
- ✓matches for {"manufacturer":"NHL","equipmentType":"spaceships"}
- ✓matches for {"manufacturer":"NHL","equipmentType":"spaceships","utm_source":"google","gclid":"abc"}
- ✓matches for {"manufacturer":"NHL","equipmentType":"spaceships","highlight":["5185601","999"]}
- ✓matches for {"equipmentType":"spaceships"}
- ✓matches for {"manufacturer":"NHL,FER","equipmentType":"spaceships"}
- ✓matches for {"manufacturer":"NHL","equipmentType":"spaceships","q":"bolt"}
✓searchGarageModelsClientBusiness rules6
- ✓maps hono GarageModelResult to EquipmentModel shape
- ✓returns an empty list for carried-filtered no-match (e.g. ferris)
- ✓forwards q, limit, and offset to the proxy
- ✓throws GarageModelsApiError with status=400 on over-limit
- ✓throws on non-OK response without leaking statusText
- ✓propagates the supplied AbortSignal
✓partsCatalogForModelUrlShared helpers6
- ✓resolves brandCode to canonical manufacturer slug
- ✓normalizes lowercase brandCodes via SLUG_ALIASES
- ✓encodes whitespace in modelKey
- ✓encodes URL-special characters in modelKey so they cannot break out of the param
- ✓falls back to lowercased brandCode when no slug mapping exists
- ✓emits empty manufacturer param when brandCode is empty
✓equipmentAssemblyDetailUrlSafeShared helpers6
- ✓returns slug URL when slug is provided
- ✓falls back to /parts/{modelCode}/assemblies/{code} when slug is null
- ✓falls back when slug is undefined
- ✓encodes special characters in assemblyCode
- ✓front#522: redirects compound modelKey (`::`) to /parts?equipmentModelKey= instead of 404 path
- ✓treats an all-digits slug as absent → legacy detail fallback (#3029)
✓PDP v2 restyle — the three hero regionsEquipment pages6
- ✓prices the inquiry card in USD and names no availability state
- ✓offers the trade and financing paths, not an outbound listing link
- ✓puts the stock number in a copyable mono row
- ✓renders a newline-separated description as a checkmark list
- ✓keeps a prose description a paragraph
- ✓links the hero chips to the specs section below
✓/attachmentsAttachment pages5
- ✓names only category families that exist in the snapshot
- ✓shows attachments only, and not the whole catalog
- ✓scopes the filter rail to the attachment slice, so no facet dead-ends (#3871 UX pass)
- ✓stays noindex with a self canonical, never a www one (front#940)
- ✓numbers the page in the title past page 1
✓isKnownBrandEquipmentType — strip-gate (#2316)Parts pages5
- ✓accepts a slug that exists in the brand taxonomy
- ✓rejects a slug absent from the taxonomy
- ✓rejects without a single browse brand (multi-brand context)
- ✓rejects when no equipmentType is active
- ✓fails soft to false when the taxonomy fetch throws
✓<GroupedCrawlableModelIndex>Interface pieces5
- ✓renders every model anchor across all sections (crawlable inside <details>)
- ✓wraps each section in a <details> so links ship in SSR HTML but stay collapsed
- ✓groups the sections in a <ul> whose every child is an <li> (#3571)
- ✓defaultOpen expands every section (#3434 — a collapsed body reads as thin)
- ✓drops empty sections and renders nothing when all are empty
✓getCarriedVendorDisplayNameEquipment data5
- ✓returns the display name for the canonical carried code
- ✓returns the display name for legacy short-form codes
- ✓returns the display name for non-carried known vendors so pre-gate rows still render nicely
- ✓falls through to the raw code for unknown vendors
- ✓is case-sensitive — backend ships uppercase codes and a case slip is a regression signal
✓isCarriedVendorCodeEquipment data5
- ✓is true for the canonical carried code
- ✓is true for the legacy short form of a carried vendor
- ✓is true for the newly activated carried vendors (VNT + MCH + KUH + KRE)
- ✓is false for known but non-carried vendors
- ✓is false for unknown and empty inputs
✓groupBySuperCategory (#2134 Model A shelves)Equipment data5
- ✓SUPER_CATEGORY_CANON: 6 shelves, unique 1-based ordering, demand order (not alphabetical)
- ✓every canon type sits on a known shelf — no orphan super-category
- ✓shelves come back in canon order; types keep canon ordering within a shelf; totals sum
- ✓drops shelves with no live types — no bare heading for an empty zone
- ✓preserves the full type set — every grouped type lands on exactly one shelf
✓canon type-key <-> readable-slug bridge (front#2217)Equipment data5
- ✓maps a readable canon slug to a vendor's raw hono category key
- ✓maps a raw category key back to its readable canon slug
- ✓round-trips readable -> raw -> readable
- ✓returns null for an unknown slug, key, or vendor so callers fall back to raw
- ✓never maps a slug onto a vendor that does not carry it
✓getVendorAvailabilityFloorEquipment data5
- ✓is undefined for every vendor while the gate is off (John PROD go pending)
- ✓floors every assume-stock partner brand to in_stock, case-insensitive
- ✓floored rows read green 'In Stock' through the real BOM chain (isBomRowOrderable + getCustomerAction), NEVER 'Available to Order'
- ✓floored rows stay 'In Stock' regardless of confirmed (#2908 fixed-orderability line — the #1584 relabel is retired)
- ✓does NOT floor brands without an assume-stock rule (real per-part signal governs those)
✓applyModelMediaOverridesEquipment data5
- ✓fills empty imageUrl, keyed brand-lower / code-upper
- ✓replaces a schematic thumbnail but keeps a real backend photo
- ✓no matching entry leaves the model untouched
- ✓reads both New Holland division slugs from the one new-holland namespace
- ✓a fetch failure is swallowed — models unchanged (build-safe)
✓validateYearBusiness rules5
- ✓accepts an empty field — the year is optional
- ✓accepts the range dealers actually list
- ✓rejects outside the range
- ✓rejects non-numeric input
- ✓accepts a trailing-garbage year the way parseInt reads it
✓createEquipment error parsingBusiness rules5
- ✓extracts code + requestId from the Hono unexpected-error envelope on a 500
- ✓never surfaces the raw 'Garage service error: 500' string to the user
- ✓surfaces the cause-specific backend message on a 4xx (duplicate / validation)
- ✓handles the gateway's string-shaped error envelope (Bad gateway) without leaking the raw status
- ✓maps 401 to an auth-required message
✓assemblyRowUrlSegmentShared helpers5
- ✓prefers the row's slug
- ✓falls back to the assemblyCode when the slug is empty string
- ✓falls back to the assemblyCode when the slug is null
- ✓falls back to the assemblyCode when the slug is absent
- ✓never reads a sibling `assemblySlug` field
✓manufacturerSlugFromCodeShared helpers5
- ✓resolves canonical vendor codes via SLUG_ALIASES
- ✓normalizes case and whitespace
- ✓returns lowercased input when already a BRAND_MAP slug
- ✓falls back to lowercased input for unknown codes
- ✓returns empty string for empty input (caller is responsible for guarding)
✓brandTypeModelHref (front#1629)Shared helpers5
- ✓CNH (not brand-catalog) → /equipment/{slug}
- ✓CNH threads the brand code onto the /equipment link when provided (collision guard)
- ✓brand-catalog ignores brandCode (diagrams route is already brand-scoped by path)
- ✓brand-catalog (Ferris) → /parts-diagrams/{brandSlug}/{modelCode} (NOT /equipment)
- ✓brand-catalog encodes a modelCode with a slash (real briggs shape)
✓stripLanguageSuffixShared helpers5
- ✓strips confirmed MCH language suffixes
- ✓is case-insensitive
- ✓does not strip non-language suffixes
- ✓does not strip mid-string matches
- ✓preserves model names with non-MCH language codes
✓photo galleryEquipment pages5
- ✓renders no thumbnail strip for a single-image row
- ✓renders a keyboard-reachable thumbnail per photo for a multi-image row
- ✓falls back to the single `image` field when `images` is absent
- ✓drops the checksum-less Sandhills URL every harvested row carries (HTTP 400)
- ✓keeps the bordered placeholder when there is no image at all
✓AddEquipmentDialog — payload enrichment (#1480)Account pages5
- ✓includes denormalized brand/model/productLine and isCustom:false for a catalog model
- ✓sends isCustom:true, brandCode CUSTOM, productLine null for a custom model
- ✓shows 'Custom equipment' as the field summary for a selected custom model
- ✓shows the catalog '... compatible parts' summary for a selected catalog model
- ✓submits a custom model with no year
✓KNOWN_VENDORS derives carried entries from BRAND_REGISTRY (#1441)Equipment data4
- ✓carried entries equal the carried registry records
- ✓every registry-carried brand has a matching MANUFACTURER_CONFIGS row
- ✓non-carried KNOWN_VENDORS entries still align with their config row by name
- ✓Marcrest is in the registry as available:true and IS in KNOWN_VENDORS (carried, noindex)
✓normalizeBrandCodeEquipment data4
- ✓returns the canonical code unchanged for the canonical form
- ✓promotes legacy short-form codes to their canonical equivalents
- ✓falls back to the raw value when no mapping exists
- ✓is case-sensitive (an upstream short-form regression would surface here)
✓flagship card art (#2249)Equipment data4
- ✓every flagshipBrandSlug entry resolves to a real brand image for its own slug
- ✓harvesters carries the NH flagship and resolves to the repo-local combine cutout
- ✓every flagshipImageSrc points at a public asset that exists on disk
- ✓loaders + skid-steers carry the confirmed NH Construction division cutouts
✓resolveModelImage — low-confidence applied imagesEquipment data4
- ✓threshold is 0.8
- ✓flags an applied image whose confidence is below the threshold
- ✓does not flag an applied image at or above the threshold
- ✓does not flag an applied image with no recorded confidence (legacy / vetted)
✓model-routing — probe-with-retry (HEAD chapters)Request routing4
- ✓retries once on a 429 then renders (visibility resolves to true)
- ✓does NOT retry when the visibility probe 404s (model genuinely hidden)
- ✓retries exactly once then fails open (renders) when both attempts error
- ✓emits a fail-open breadcrumb tagged 'model-chapters' after the retry errors
✓equipmentUrlShared helpers4
- ✓builds equipment detail URL from slug
- ✓appends ?brand= when a brand code is known (cross-brand slug collision guard)
- ✓omits ?brand= when brand is null/undefined/empty (canonical + redirect callers stay bare)
- ✓URL-encodes the brand value so synonyms/display forms cannot break the query
✓assemblyUrlSegmentShared helpers4
- ✓prefers the canonical slug over the 308-ing legacy code
- ✓keeps the assemblyCode tail when the slug is null (brand-catalog vendor)
- ✓keeps the assemblyCode tail when the field is absent entirely
- ✓keeps the assemblyCode tail for an empty-string slug
✓modelCountLabelShared helpers4
- ✓uses the singular noun for exactly one model
- ✓uses the plural noun for more than one model
- ✓uses the plural noun for zero models
- ✓groups thousands
✓useSignInFlow.submit (classic clerk-js API)Sign-in4
- ✓submits a password via signIn.create({ identifier, password }) — NOT signIn.password
- ✓on complete, activates the session via setActive and routes to the redirect
- ✓on needs_second_factor, advances to the mfa step and exposes the offered strategies
- ✓surfaces an error message when signIn.create throws (classic methods throw)
✓AddEquipmentDialog — year fieldAccount pages4
- ✓rejects a year below 1900
- ✓rejects a year above currentYear+1
- ✓accepts a valid in-bounds year
- ✓does not auto-fill year or restrict bounds even when model carries yearFrom/yearTo
✓garage row links to detail pageAccount pages4
- ✓(mobile card) links the title to the equipment detail route
- ✓(desktop) links the title cell to the equipment detail route
- ✓(mobile card) link accessible name falls back to brand + model when nickname is missing
- ✓(mobile card) link accessible name is the nickname when present
✓/api/parts/[id]/staff-inventory — auth boundaryAPI endpoints4
- ✓returns 204 with NO body and private no-store for anonymous (customer)
- ✓returns the reconciled payload + private no-store for staff
- ✓applies the #830 hono-override when query params say the part is sellable
- ✓returns 400 for an over-long id (staff)
✓GET /feed/google/inventory/[id].xmlGoogle feed4
- ✓emits id, price and availability — and nothing else
- ✓skips a row it cannot price rather than publishing a zero
- ✓shares the primary's shard math and its batch-size tripwire
- ✓caches for six hours — fresher than the primary's daily fetch
✓buildSearchParams — Browse-by-Type (#2316)Parts pages3
- ✓forwards the equipmentType slug to the search request
- ✓stays unfiltered when no type is active
- ✓an explicit per-model filter wins — type is not forwarded alongside it
✓<CrawlableModelIndex> (front#1195 SSR crawl anchors)Interface pieces3
- ✓renders one /parts-diagrams/model/<slug>/parts-diagrams anchor per model
- ✓renders nothing when there are no models (no empty section in the DOM)
- ✓puts NO class attribute on any <li> or <a> (#3434 payload guard)
✓runModelV2Business rules3
- ✓auto-stages a chosen pick at/above the threshold, recording the AI confidence
- ✓holds a chosen-but-below-threshold pick for a human (no replacement staged)
- ✓flags a needs-human model with the pipeline reason + recommended query
✓modelIndexLabelGoogle visibility3
- ✓prefers the model number over the brand-prefixed display name
- ✓strips a leading brand word when the model number is blank
- ✓falls back to the raw display name when nothing else is usable
✓splitShortSlug — front#243 short-form fallbackShared helpers3
- ✓splits known brand prefixes (single-word and multi-word, longest-first)
- ✓preserves model tail dashes and normalizes input to lowercase
- ✓returns null on unknown brand, empty tail, or empty input
✓cleanModelNumberShared helpers3
- ✓strips language suffix and replaces underscores with spaces
- ✓handles models without suffixes or underscores
- ✓trims whitespace from result
✓price + primary actions — #3871 UX passEquipment pages3
- ✓shows a whole-dollar price with the subject-to-change caveat
- ✓puts our call and contact CTAs in the info panel, with the stock number in the subject
- ✓never links out to the legacy www listing (#3871 UX pass)
✓startClientTrustSign-in3
- ✓picks the email_code factor, prepares the code, and returns the masked destination
- ✓falls back to the phone_code factor when no email_code factor is offered
- ✓returns null and prepares nothing when no usable factor is available
✓media-ai-modelsAdmin logic3
- ✓returns default chains when env overrides are unset
- ✓prepends env override without duplicating the default slug
- ✓uses a custom override as the primary model
✓/equipment-not-found generateMetadataEquipment pages2
- ✓post-flip (IS_INDEXING_ENABLED=true) emits NOINDEX_NOFOLLOW_ROBOTS with googleBot shape
- ✓pre-flip (IS_INDEXING_ENABLED=false) omits robots so layout's noindex,nofollow is inherited
✓buildListingHrefWithoutEquipmentType (#2316)Parts pages2
- ✓strips equipmentType while preserving the other params
- ✓returns the bare listing when equipmentType was the only param
✓ModelMediaImage low-confidence badgeInterface pieces2
- ✓overlays the caution badge when the shown rung is low-confidence
- ✓shows no badge for a normal image
✓runAutoSearchV2 poolBusiness rules2
- ✓processes every model once and stages each without losing a store row
- ✓drains the pool with a stoppedReason when a lane hits an upstream limit
✓getHandlingShipLineEquipment data2
- ✓is undefined while the gate is off (falls back to the default ship-line)
- ✓wraps the band in the ship-line voice when the gate is on
✓equipmentAssemblyListUrlShared helpers2
- ✓builds assembly list URL from slug
- ✓never appends ?brand= — the assembly-list route resolves by slug alone
✓equipmentVariantsUrlShared helpers2
- ✓builds the variants URL from slug
- ✓appends ?brand= when known
✓equipmentAssemblyDetailUrlShared helpers2
- ✓builds assembly detail URL from slug and assemblyCode
- ✓appends ?brand= after the assembly segment when known
✓brandModelDiagramsUrl (front#2027)Shared helpers2
- ✓builds the bare brand model-diagrams URL
- ✓URL-encodes a modelCode with a slash
✓spec block — absent fields render nothingEquipment pages2
- ✓shows every present field and combines family/leaf into one non-repeating row
- ✓renders no empty Year/Hours row when the row has neither
✓collectMfaStrategiesSign-in2
- ✓maps the offered second factors to their strategies
- ✓returns an empty list when no second factors are offered
✓sendClientTrustCodeSign-in2
- ✓prepares the email_code second factor with its emailAddressId
- ✓prepares the phone_code second factor with its phoneNumberId
✓finalizeSessionSign-in2
- ✓activates the created session via setActive, then routes to the redirect URL
- ✓pushes the default redirect when no redirect_url is present
✓verifyMfaThenFinalizeSign-in2
- ✓verifies the factor and finalizes when the sign-in resolves to complete
- ✓does not finalize while the sign-in is still incomplete
✓withLoadingSign-in2
- ✓clears any prior error and toggles loading around a successful action
- ✓surfaces a thrown error via getClerkError and still clears loading
✓useForgotPasswordFlow.sendCode (classic clerk-js reset flow)Sign-in2
- ✓creates the sign-in then prepares the reset_password_email_code first factor with its emailAddressId
- ✓surfaces an error when no reset factor is offered
✓useForgotPasswordFlow.resetPassword (classic clerk-js reset flow)Sign-in2
- ✓calls signIn.resetPassword({ password }) and finalizes when complete
- ✓routes to the mfa step when a second factor is required after reset
✓useOtpAutoSubmitSign-in2
- ✓tracks code and fires onComplete only once the 6th digit lands
- ✓never fires onComplete while disabled
✓useSignInFlow client-trust (classic clerk-js API)Sign-in2
- ✓on needs_client_trust, prepares the offered second factor and routes to the trust step
- ✓submitClientTrust verifies the offered factor and finalizes when complete
✓useSignUpFlow.start (classic clerk-js API)Sign-in2
- ✓creates the sign-up via signUp.create + prepareEmailAddressVerification (NOT .password / .verifications)
- ✓surfaces an error and stays on the form when signUp.create throws
✓useSignUpFlow.verify (classic clerk-js API)Sign-in2
- ✓attempts the email verification then activates the session and routes home
- ✓does not activate a session when the sign-up is not complete
✓staff/fetch-inventory request shape pinBusiness rules2
- ✓calls fetch with X-Admin-Token header + no-store + encoded part number
- ✓returns unavailable snapshot WITHOUT calling fetch when CATALOG_ADMIN_TOKEN is unset
✓<EquipmentItem> (mobile card)Account pages2
- ✓renders exactly one primary 'Parts for this machine' CTA per row
- ✓dropdown still surfaces Edit/Remove and no longer surfaces the legacy 'Find Parts' item
✓<EquipmentTable> (desktop)Account pages2
- ✓renders one primary CTA per row with the canonical filtered href
- ✓dropdown still surfaces Edit/Remove and no longer surfaces the legacy 'Find Parts' item
✓custom equipment rowsAccount pages2
- ✓(desktop) renders no parts CTA, shows 'Custom' brand, keeps Edit/Remove
- ✓(mobile card) renders no parts CTA, shows 'Custom' brand, keeps Edit/Remove
✓<CompatibleParts>Equipment pages2
- ✓renders a catalogue link for a carried make
- ✓renders nothing for a make we don't carry
✓verifyMfaSign-in1
- ✓routes each strategy to attemptSecondFactor with the classic { strategy, code } shape
✓useForgotPasswordFlow.submitCode (classic clerk-js reset flow)Sign-in1
- ✓attempts the reset first factor with { strategy, code } and advances to the reset step
✓useResendCooldownSign-in1
- ✓calls onResend, arms a 30s cooldown, and ticks down each second
✓useSignInFlow.submitMfa (classic clerk-js API)Sign-in1
- ✓verifies the second factor via attemptSecondFactor and finalizes on complete
✓useSignUpFlow.resend (classic clerk-js API)Sign-in1
- ✓re-prepares the email-code verification
What we walk through in a real browser6 journeys
○Variants disambiguation pageBrowser journey6
- ○multi-variant slug lists the variants with the current one marked
- ○variants page is indexable, and self-canonical
- ○clicking a non-current variant navigates to its detail page
- ○single-variant slug redirects back to the detail page
- ○invalid slug renders not-found (HTTP 404 on Vercel edge)
- ○multi-brand collision exposes brand chip group
○CR-series Combines assemblies — chapter render regressionBrowser journey4
- ○new-holland-cr790-e5 renders chapters, not ServiceUnavailable
- ○new-holland-cr780-e2 renders chapters, not ServiceUnavailable
- ○new-holland-cr890-e0-12-5 renders chapters, not ServiceUnavailable
- ○new-holland-cx8070 (working baseline) still renders after fix
○Equipment detail — action-bar CTAsBrowser journey4
- ○model-actions-bar renders with Parts Diagrams CTA
- ○Parts Catalog CTA, when present, links to /parts with manufacturer + equipmentModelKey filters
- ○CTAs have aria-labels naming the model + are keyboard-focusable
- ○mobile 375px: action-bar lays out as a vertical full-width stack
○Equipment page — thin catalog + 404Browser journey3
- ○Workmaster 60 renders schematic actions and suppresses the call-us CTA
- ○thin pages opt out of indexing
- ○invalid slug renders not-found body (HTTP 404 on Vercel edge)
○Variants banner on equipment detail pageBrowser journey2
- ○multi-variant detail page shows the banner CTA
- ○single-variant detail page does not render the banner
○Garage — orders for this machine + re-orderBrowser journey2
- ○customer re-orders fitting parts from the machine detail in one click
- ○machine detail shows the empty state when no orders match
Automated checks770
Browser journeys8
Code exercised77.1%
What we check automatically141 groups
✓StaffOrderDetailViewAccount pages23
- ✓renders order number, total, customer, and items
- ✓renders status + payment badges
- ✓renders the placed event in the timeline
- ✓renders shipped + delivered events and skips future milestones once delivered
- ✓renders cancellation event with destructive styling and suppresses future milestones
- ✓does not throw when items is null (renders Items (0))
- ✓does not throw when items is missing entirely
- ✓falls back gracefully when shippingAddress is missing
- ✓links back to the staff orders list
- ✓renders the shipping label card when shippingLabelUrl is present
- ✓omits the shipping label card when shippingLabelUrl is absent
- ✓renders the staff action grid (desktop parity with mobile)
- ✓hides Print label + Mark shipped on the action grid for a pickup order
- ✓renders Carrier and Method as separate lines when both are present
- ✓renders 'Clinton' carrier label for clinton_tractor (not 'Clinton Tractor')
- ✓wraps the tracking number in an external link for UPS
- ✓renders the tracking number as plain text for clinton_tractor (no external page)
- ✓renders the raw lastCarrierStatus when present
- ✓omits the Carrier line when shippingProvider is absent (legacy order)
- ✓relabels the future milestones for a pickup order (Ready for pickup / Picked up)
- ✓relabels a reached 'shipped' event as 'Ready for pickup' on a pickup order
- ✓keeps Shipped/Delivered labels for a normal shipped order (ship path unchanged)
- ✓treats clinton_tractor ground delivery as a ship order (NOT pickup)
✓isOvernightEligibleCNH parts service18
- ✓returns true on the happy path (in_stock + GREEN + non-DFS + non-truck + sellable)
- ✓returns true for in_stock_limited (the second 'in stock' bucket)
- ✓returns false for vendor_direct (ships from supplier — not CNH overnight)
- ✓returns false for displayState=backorder
- ✓returns false for displayState=discontinued
- ✓returns false for displayState=delayed_supply
- ✓returns false for displayState=pre_launch
- ✓returns false for displayState=unknown
- ✓returns false when live data is missing entirely (fail closed)
- ✓returns false when live data is stale (fail closed)
- ✓returns false when csps.dfs === true
- ✓returns false when materialStatus.cnhStockOrdinability.dfs === true
- ✓returns false when csps section is null (no CNH availability confirmed)
- ✓returns false when csps.cnhStock !== GREEN
- ✓returns false when shipping.requiresTruck === true (LTL freight)
- ✓returns false when shipping.isHazardous === true
- ✓returns false when publishStatus === 'dont_list'
- ✓returns true when shipping is undefined (no truck/hazmat signals)
✓updateOrderStatusActionServer actions17
- ✓returns validation failure for empty input
- ✓rejects pending, which the backend status endpoint does not accept
- ✓rejects processing, which the backend status endpoint does not accept
- ✓rejects cancelled, which the backend status endpoint does not accept
- ✓rejects refunded, which the backend status endpoint does not accept
- ✓accepts ready
- ✓accepts out_for_delivery
- ✓accepts on_hold
- ✓accepts shipped
- ✓accepts delivered
- ✓returns unauthenticated when no Clerk session
- ✓returns unauthorized when the caller is a customer
- ✓PATCHes the status endpoint and revalidates staff and customer paths
- ✓forwards an optional note and omits it when blank
- ✓returns backend_error when the payment service is not configured
- ✓returns backend_error when the fetch itself throws
- ✓surfaces the backend's own error message (#1807)
✓fetchLivePartStatusCNH parts service17
- ✓returns null when baseUrl is not configured
- ✓returns null when partNumber is empty
- ✓URL-encodes PN containing slash / special chars
- ✓#1584 — unwraps branded CT-{BRAND}- SKU to the bare OEM PN in the URL
- ✓#1584 — returns null without fetching when PN unwraps to empty
- ✓parses a good response into PartStatusPublic
- ✓401 → session_expired Sentry + null
- ✓503 → config_missing info Sentry + null
- ✓502 → generic live_check_failed Sentry + null
- ✓timeout (AbortError) → live_check_timeout Sentry + null
- ✓network throw → live_check_error Sentry + null
- ✓malformed JSON body → response_shape_invalid + null
- ✓wholesale-leak regression (extra pricing keys) → wholesale_leak_detected + null
- ✓wholesale-leak detected even when extra key is NOT at csps.pricing path
- ✓plain shape drift (missing required field) stays in response_shape_invalid
- ✓breadcrumb fires ONLY on fully-healthy path (200 + valid schema)
- ✓#1708 — default read forwards next.revalidate: 300 (5-min window); forceFresh forwards 0
✓buildTrackingStepsOrder records15
- ✓renders 5 milestones with the first as current when no tracking data is available
- ✓advances the current step based on the tracking status
- ✓marks the delivered milestone current when status is delivered
- ✓falls back to estimatedDelivery date for the delivered detail line
- ✓populates the placed step from order.createdAt
- ✓returns [] for cancelled orders so the happy-path timeline isn't shown
- ✓returns [] when carrier tracking reports an exception status
- ✓returns [] when carrier tracking reports a returned/return_to_sender status
- ✓returns the normal 5-step ladder for a freshly placed order
- ✓renders a 4-step pickup ladder with no UPS transit stages
- ✓marks 'Ready for pickup' current when the order is staged (status shipped)
- ✓marks 'Picked up' current when delivered (collected)
- ✓ignores live UPS tracking for a pickup order
- ✓returns [] for a cancelled pickup order
- ✓treats clinton_tractor ground delivery as ship (5-step ladder)
✓TrackingSheetStaff tools13
- ✓ships without a tracking number
- ✓sends the tracking number as typed, and hints the carrier
- ✓accepts an unrecognised number without an error
- ✓toasts the server error and keeps the sheet open on failure
- ✓Upload photo opens the file picker
- ✓shows the camera only after Scan label is pressed
- ✓a decoded barcode fills the input and does not submit
- ✓clears the typed number when reused for a different order
- ✓opens as the tracking editor, pre-filled with the number on the order
- ✓saves a corrected number through the same action
- ✓a barcode on the photo fills the field client-side and uploads nothing
- ✓a barcode-less photo uploads, OCRs, and offers the candidates to tap
- ✓keeps the photo and stays usable when OCR is unavailable
✓findGuestOrderActionServer actions12
- ✓returns the sanitised order when ID + email match
- ✓strips the ORD prefix from ORD-7432 before calling the backend
- ✓strips the ORD prefix from ORD 7432 before calling the backend
- ✓strips the ORD prefix from ORD7432 before calling the backend
- ✓strips the ORD prefix from ord-7432 before calling the backend
- ✓strips the ORD prefix from ORD‒7432 before calling the backend
- ✓strips the ORD prefix from ORD–7432 before calling the backend
- ✓strips the ORD prefix from ORD—7432 before calling the backend
- ✓returns a generic not-found on backend miss
- ✓rejects when the email doesn't match — and uses the same generic error
- ✓validates the input shape with Zod
- ✓is case-insensitive on the email comparison
✓fetchStaffOrderDetailAdmin logic12
- ✓returns ok=false with 401 when token is null
- ✓returns ok=false with 400 when orderId is empty
- ✓encodes the orderId path segment so a stray slash cannot escape the route
- ✓unwraps `{ data: ... }` envelope and returns parsed payload
- ✓returns ok=false with status from upstream + error message on 4xx
- ✓returns ok=false with status from upstream on 5xx (without throwing)
- ✓returns 502 when upstream returns 200 but malformed payload
- ✓coerces a null `items` field to an empty array (front#1069)
- ✓coerces a missing `items` field to an empty array (front#1069)
- ✓preserves a populated `items` array unchanged
- ✓returns 500 when fetch throws (network error)
- ✓includes Bearer token in Authorization header
✓getCustomerAction — missing-signal fold (#2135, ex-#524 audit pin)CNH parts service12
- ✓null + purchasable=true → 'In Stock' (in_stock)
- ✓'unknown' + purchasable=true → 'In Stock' (in_stock)
- ✓undefined + purchasable=true → 'In Stock' (in_stock)
- ✓null + purchasable=false → 'Out of Stock' (call_us)
- ✓'unknown' + purchasable=false → 'Out of Stock' (call_us)
- ✓undefined + purchasable=false → 'Out of Stock' (call_us)
- ✓null never renders the retired 'Contact Us' copy
- ✓'unknown' never renders the retired 'Contact Us' copy
- ✓undefined never renders the retired 'Contact Us' copy
- ✓clintonInStock=true does NOT change the missing-signal fold
- ✓returns generic 'In Stock' when state='in_stock' and clintonInStock=true (channel-leak rule)
- ✓collapses non-primary in_stock variants to 'In Stock' under clintonInStock=true
✓staffCancelOrderActionServer actions11
- ✓rejects a reason outside the cancellation vocabulary
- ✓returns unauthenticated when there is no Clerk session
- ✓returns unauthorized when the caller is a customer
- ✓POSTs to the cancel endpoint and revalidates the dynamic detail route
- ✓files a refund request when the order still holds money
- ✓maps a cancellation reason the refund queue does not know onto `other`
- ✓files NO refund request when the money is already back
- ✓still reports success when the refund request fails — the cancel already landed
- ✓surfaces alreadyCancelled from the backend
- ✓surfaces the backend's own 422 message for an order already in transit
- ✓returns backend_error when the payment service is not configured
✓getCustomerActionCNH parts service11
- ✓maps 'in_stock' -> 'in_stock' ('In Stock')
- ✓maps 'in_stock_limited' -> 'in_stock' ('In Stock')
- ✓maps 'vendor_direct' -> 'in_stock' ('In Stock')
- ✓maps 'delayed_supply' -> 'in_stock' ('In Stock')
- ✓maps 'pre_launch' -> 'in_stock' ('In Stock')
- ✓maps 'backorder' -> 'call_us' ('Out of Stock')
- ✓maps 'discontinued' -> 'call_us' ('Out of Stock')
- ✓never throws on garbage input cast through `as unknown as DisplayState`
- ✓never renders the retired 'Contact Us for Availability' copy for any input
- ✓never leaks raw CNH signal words in any returned label
- ✓never leaks channel-hint substrings (depot/supplier/clinton/on shelf) on customer surfaces
✓filterOrdersForMachineOrder records11
- ✓returns orders whose line items reference parts fitting the machine
- ✓preserves the input order (most-recent-first)
- ✓collects every matching part number for an order with multiple fitting lines
- ✓returns empty results for empty orders
- ✓returns empty results when partsByPn is empty
- ✓treats undefined equipmentModelKey as 'does not fit'
- ✓treats empty equipmentModelKey as 'does not fit'
- ✓returns empty results for an empty target modelKey without throwing
- ✓silently skips line items whose part is not in partsByPn
- ✓deduplicates a partNumber repeated across multiple line items in the same order
- ✓requires exact string equality on modelKey (no prefix match)
✓buildReorderResultOrder records11
- ✓adds an in-stock part with the original quantity
- ✓brand-qualifies the rehydrated cart line so same-PN brands stay distinct
- ✓falls back to part.id when no manufacturer code is on the fresh snapshot
- ✓skips parts that the backend marks as not found
- ✓flags discontinued parts and does not add them
- ✓flags out-of-stock parts (availability OR stock=0)
- ✓clamps quantity to stock and surfaces stock_reduced
- ✓emits price_changed when the new unit price differs
- ✓forwards pack fields and shipping path into the cart item
- ✓reports allFailed when nothing was added
- ✓returns allFailed=false when at least one line was added
✓StaffOrderDetailErrorAccount pages11
- ✓renders heading with orderId from useParams when error does not carry one
- ✓prefers orderId from the error object over useParams
- ✓surfaces backend status from error.backendStatus
- ✓parses backend status from a legacy '(500)' message when not on the error object
- ✓parses backend status from a 'HTTP 502' message when not on the error object
- ✓calls Sentry.captureException with route + orderId tags
- ✓renders the Sentry digest when present
- ✓wires the 'Try again' button to reset()
- ✓links 'Back to orders list' to /account/staff/orders
- ✓hides retry + shows escalation copy after 3 reset clicks inside 10s
- ✓does not trip the storm guard when clicks are spread beyond the 10s window
✓formatCountdownBusiness rules10
- ✓formats 0 ms as 0s
- ✓formats -100 ms as 0s
- ✓formats 1000 ms as 1s
- ✓formats 59500 ms as 60s
- ✓formats 60000 ms as 60s
- ✓formats 60500 ms as 2m
- ✓formats 210000 ms as 4m
- ✓formats 3600000 ms as 1h
- ✓formats 6060000 ms as 1h 41m
- ✓formats 13260000 ms as 3h 41m
✓cancelOrderActionServer actions10
- ✓rejects with reason='validation' on empty orderId
- ✓rejects with reason='unauthenticated' when no Clerk session
- ✓returns reason='endpoint_missing' on backend 404 (graceful degradation)
- ✓returns reason='backend_error' on 500
- ✓returns reason='backend_error' on network failure (and tags Sentry)
- ✓succeeds + revalidates on backend 2xx
- ✓returns reason='endpoint_missing' when PAYMENT_SERVICE_URL is unset (Greptile P1)
- ✓returns reason='endpoint_missing' when PAYMENT_SERVICE_URL points at localhost (dev fallback)
- ✓posts only `reason` in body (userId is NOT sent — backend derives from JWT)
- ✓does NOT send response body to Sentry on backend failure (PII guard)
✓getShippingLabel — live signal returns null for every stateCNH parts service10
- ✓in_stock → null (channel-leak rule)
- ✓in_stock_limited → null (channel-leak rule)
- ✓vendor_direct → null (channel-leak rule)
- ✓delayed_supply → null (channel-leak rule)
- ✓pre_launch → null (channel-leak rule)
- ✓backorder → null (channel-leak rule)
- ✓discontinued → null (channel-leak rule)
- ✓unknown → null (channel-leak rule)
- ✓never throws on garbage input cast through `as unknown as DisplayState`
- ✓never returns the literal 'N/A' for any DisplayState
✓cnh-overnight golden fixture — subtotal vectors (#303)Shipping rules10
- ✓$0 cnh subtotal -> $25
- ✓$33.33 cnh subtotal -> $30
- ✓$33.34 cnh subtotal -> $30
- ✓$75 cnh subtotal -> $36.25
- ✓$99.99 cnh subtotal -> $40
- ✓$100 cnh subtotal -> $40
- ✓$129 cnh subtotal -> $44.35
- ✓$200 cnh subtotal -> $55
- ✓$1000 cnh subtotal -> $175
- ✓$5000 cnh subtotal -> $775
✓MERCHANT_RETURN_POLICY (lib/seo/return-policy)Google visibility10
- ✓uses the published 30-day return window
- ✓uses 20% restocking fee for CNH-sourced items
- ✓uses MerchantReturnFiniteReturnWindow category
- ✓uses ReturnByMail method
- ✓makes the customer responsible for default return shipping
- ✓offers free returns for defective / our-fault shipments
- ✓declares FullRefund as the refund type
- ✓applies to the US
- ✓links to the published /return-policy page
- ✓declares the schema.org type
✓OrderDetailsPage — refund and return offersAccount pages10
- ✓paid/processing → refund button shown
- ✓partially_refunded/shipped → refund button shown
- ✓paid/cancelled → refund button hidden
- ✓refunded/processing → refund button hidden
- ✓pending/processing → refund button hidden
- ✓paid/shipped → return link shown
- ✓paid/delivered → return link shown
- ✓partially_refunded/delivered → return link shown
- ✓paid/processing → return link hidden
- ✓refunded/delivered → return link hidden
✓getCutoffStateAtBusiness rules9
- ✓returns active with positive msUntilCutoff at 09:00 ET on a normal Monday
- ✓returns active at 13:59:59 ET (one second before cutoff)
- ✓returns after at exactly 14:00:00 ET
- ✓returns after at 14:00:01 ET on a normal weekday
- ✓returns weekend on Saturday 10:00 ET; next business day is Monday
- ✓returns holiday on Independence Day observed (Fri Jul 3 2026); next business day is Monday
- ✓returns weekend on Sunday before MLK Day 2027 (next business day skips holiday Mon to Tue)
- ✓returns holiday on the day after Thanksgiving when treated as one (Fri Nov 27 2026)
- ✓after-cutoff on Friday rolls forward across the weekend to Monday
✓addOrderNoteActionServer actions9
- ✓returns validation failure for empty input
- ✓rejects a whitespace-only note
- ✓returns unauthenticated when no Clerk session
- ✓returns unauthorized when the caller is a customer
- ✓POSTs the note to the staff notes endpoint and revalidates the detail path
- ✓returns backend_error when the payment service is not configured
- ✓returns backend_error when the fetch itself throws
- ✓surfaces the backend's own error message (#1807)
- ✓does not revalidate when the backend rejects the note
✓loadGarageMachineOrdersActionServer actions9
- ✓returns matching orders with the matched-part map
- ✓short-circuits for custom equipment without fetching orders or parts
- ✓returns empty matches and skips the batch when the user has no orders
- ✓surfaces partsBatchError when fetchUserOrders fails (outage path)
- ✓returns an error and does no downstream work when the user is signed out
- ✓returns an error when the equipment id is not in the user's garage
- ✓falls back to an empty matched list when getPartsBatch throws
- ✓treats partNumbers in `notFound` as 'does not fit' without crashing
- ✓passes limit 50, offset 0, and the email claim to fetchUserOrders
✓createStaffQuoteActionServer actions9
- ✓returns the pay link
- ✓accepts a non-US address — this is not the public checkout
- ✓sends the typed freight as a flat provider/serviceType/cost triple
- ✓rejects a bad email before calling the backend
- ✓caps the expiry at 30 days — the price is frozen until then
- ✓refuses an empty cart
- ✓returns unauthenticated with no Clerk session
- ✓returns unauthorized for a customer
- ✓reports a quote that came back without a link rather than claiming success
✓OrderRowAccount screens9
- ✓renders the formatted order number, item count, and status pill for a shipped order
- ✓shows the Track CTA + tracking number truncation for shipped orders
- ✓shows the Reorder CTA + delivered date for delivered orders
- ✓shows the channel-aware delivery status (not a minted tracking #) for a CT van delivery (#251)
- ✓labels a pickup order 'Ready for pickup' and a CT delivery 'On hold' (#251)
- ✓mutes cancelled orders and shows a struck-through total
- ✓respects a custom linkBase for staff lists
- ✓emits the readable orderNumber slug when useOrderNumberSlug is true (#1038)
- ✓falls back to internal orderId when useOrderNumberSlug=true but orderNumber missing
✓getCustomerAction — #2135 unclear fold against purchasabilityCNH parts service9
- ✓unknown + purchasable=true → 'In Stock' (in_stock)
- ✓null + purchasable=true → 'In Stock' (in_stock)
- ✓undefined + purchasable=true → 'In Stock' (in_stock)
- ✓unknown + purchasable=false → 'Out of Stock' (call_us)
- ✓null + purchasable=false → 'Out of Stock' (call_us)
- ✓undefined + purchasable=false → 'Out of Stock' (call_us)
- ✓unknown + purchasable omitted → default-buyable 'In Stock'
- ✓null + purchasable omitted → default-buyable 'In Stock'
- ✓undefined + purchasable omitted → default-buyable 'In Stock'
✓mergeLiveEnrichmentCNH parts service9
- ✓returns stale sentinel on null input
- ✓populates liveCheckedAtEpoch from Date.now()
- ✓carries displayState through unchanged
- ✓does NOT leak live price into the enrichment (no consuming UI yet)
- ✓extracts DMS availability + qty when present
- ✓null-safes missing DMS
- ✓preserves stale=false even when all sub-sections are null (display state is still live)
- ✓suppresses the freshness epoch for a last-known-good (stale) verdict but keeps the verdict (R1)
- ✓still stamps a fresh epoch when stale is absent/false
✓getShippingLabel — clintonInStock does not surface a channel hintCNH parts service9
- ✓in_stock + clintonInStock=true → null
- ✓in_stock_limited + clintonInStock=true → null
- ✓vendor_direct + clintonInStock=true → null
- ✓delayed_supply + clintonInStock=true → null
- ✓pre_launch + clintonInStock=true → null
- ✓backorder + clintonInStock=true → null
- ✓discontinued + clintonInStock=true → null
- ✓unknown + clintonInStock=true → null
- ✓does not surface 'On shelf in Clinton' under any combination
✓getShippingLabel — cached fallback (eParts down) returns null on customer surfacesCNH parts service9
- ✓availability=in_stock (live null) → null (channel-leak rule)
- ✓availability=low_stock (live null) → null (channel-leak rule)
- ✓availability=preorder (live null) → null (channel-leak rule)
- ✓availability=available (live null) → null (channel-leak rule)
- ✓availability=backorder (live null) → null (channel-leak rule)
- ✓availability=out_of_stock (live null) → null (channel-leak rule)
- ✓returns null when both signals are missing
- ✓live signal takes precedence and still returns null (no row either way)
- ✓clintonInStock=true under fallback also returns null
✓OrderDetailsPage — delivery section gateAccount pages9
- ✓is hidden for an order with no tracking number, provider or shipped status
- ✓is shown by a tracking number
- ✓is shown by a shipping provider alone
- ✓is shown by status=shipped alone
- ✓allows cancelling only while shipped and not yet delivered
- ✓flags an exception only when the tracking call itself succeeded
- ✓PINNED, NOT ENDORSED: hasException is undefined, not false, with no tracking number
- ✓prefers the carrier ETA over the stored one, and falls back when it is blank
- ✓falls back to the route orderId when the order carries no order number
✓OrderDetailsPage — optional blocks and money rowsAccount pages9
- ✓renders the part number placeholder for an item with no thumbnail
- ✓renders an image for an item that has a thumbnail
- ✓shows a discount row only for a positive discount
- ✓prints "Included" for a missing shipping figure that the total cannot explain
- ✓prints $0.00 for a missing shipping figure the total already reconciles
- ✓hides address, label and note cards when the order carries none of them
- ✓renders the address without a state or phone when neither is present
- ✓renders state and phone when the address has them
- ✓renders the label card and the note card when the order carries them
✓QuoteBuilderAccount pages9
- ✓adds a part at its catalogue price
- ✓bumps the quantity when the same part is added twice
- ✓explains a part that has no catalogue price instead of quoting it
- ✓says so when the part number is unknown
- ✓keeps the send button disabled until the address is complete
- ✓sends a German address through — this is not the public checkout
- ✓shows the link and offers to copy it before offering to email it
- ✓tells staff to send the link themselves when the email fails
- ✓surfaces a backend rejection rather than pretending the link exists
✓loadOwnedOrderBusiness rules8
- ✓returns the order for the owner and never touches the admin-token reader
- ✓reads with the caller's own Clerk token, on the configured template
- ✓404s a forbidden order instead of rendering it
- ✓404s a refused read even if the upstream still attached an order body
- ✓404s a missing order the same way a forbidden one is 404d
- ✓404s an ok-but-empty upstream result rather than returning null
- ✓still sends a null token through rather than falling back to an admin read
- ✓falls back to the local payment-service base URL when the env var is unset
✓loadDeskOrdersAdmin logic8
- ✓passes the page + optional filters through to the fetcher
- ✓omits absent filters rather than sending empty strings
- ✓returns the live orders + total when the backend answers
- ✓falls back to the demo desk in the dev app env
- ✓redirects to /account on 401 outside the demo env
- ✓redirects to /account on 403 outside the demo env
- ✓throws the backend's message on any other failure
- ✓names the status when the failure carries no message
✓fetchFullOrderForEmailBusiness rules8
- ✓sends X-Admin-Token when PAYMENT_ADMIN_TOKEN is set
- ✓omits X-Admin-Token when PAYMENT_ADMIN_TOKEN is unset
- ✓prefers PAYMENT_SERVICE_DIRECT_URL over the gateway URL when set
- ✓falls back to PAYMENT_SERVICE_URL when the direct URL is unset
- ✓returns null and captures the HTTP status on a non-ok response (front#1127)
- ✓flags tokenSent=true in the Sentry extra when a token was sent but still rejected
- ✓returns null and captures when fetch throws
- ✓returns null on ok response missing userEmail/items
✓UC-D-3 Scenario A overnight eligibility — fingerprint pinsCNH parts service8
- ✓[Scenario A pass] in_stock + GREEN + non-DFS + non-truck + non-haz + sellable
- ✓[fail liveDisplayState] backorder drops Scenario A
- ✓[fail cnhStock] YELLOW drops Scenario A
- ✓[fail csps.dfs] DFS=true drops Scenario A
- ✓[fail requiresTruck] LTL freight drops Scenario A
- ✓[fail isHazardous] hazmat drops Scenario A
- ✓[fail publishStatus] dont_list drops Scenario A
- ✓[fail live=stale] missing/stale live signal drops Scenario A (fail closed)
✓<ConditionalCutoffBanner> — account/auth route gateProduct features7
- ✓renders the banner on the storefront home
- ✓returns null on nested account routes
- ✓returns null on the account root
- ✓returns null on the sign-in auth route
- ✓returns null on the showcase route /equipment
- ✓returns null on the showcase route /equipment/226238199
- ✓returns null on the showcase route /attachments
✓CutoffBanner — per-part scopesProduct features7
- ✓returns null when overnightEligible is false on PDP
- ✓returns null when overnightEligible is undefined on PDP
- ✓returns null when overnightEligible is false on cart
- ✓renders active-state copy on PDP at 09:00 ET on a weekday for an overnight-eligible part
- ✓renders after-cutoff copy on cart after 14:00 ET
- ✓renders weekend copy on checkout on a Saturday
- ✓renders holiday copy on PDP on Independence Day observed (Fri Jul 3 2026)
✓getCustomerAction — confirmed option is ignored (fixed orderability line)CNH parts service7
- ✓in_stock stays 'In Stock' (in_stock) for any confirmed value
- ✓in_stock_limited stays 'In Stock' (in_stock) for any confirmed value
- ✓vendor_direct stays 'In Stock' (in_stock) for any confirmed value
- ✓delayed_supply stays 'In Stock' (in_stock) for any confirmed value
- ✓pre_launch stays 'In Stock' (in_stock) for any confirmed value
- ✓backorder stays 'Out of Stock' regardless of confirmed
- ✓confirmed does not fold the unclear tier (purchasability owns it)
✓buildTrackingSteps — Clinton Tractor delivery variant (#251)Order records7
- ✓renders the CT milestones, not the UPS carrier ones
- ✓marks ready as the current step
- ✓advances current to out_for_delivery
- ✓shows on_hold as still being prepared
- ✓drops cancelled orders off the happy path
- ✓surfaces an estimated delivery date when not yet delivered
- ✓pickup orders keep the counter-collection timeline
✓isPickupOrderShipping rules7
- ✓returns true for the literal pickup provider
- ✓is case-insensitive on the provider
- ✓returns true for clinton_tractor + a pickup service type
- ✓returns false for clinton_tractor ground delivery (no pickup in service type)
- ✓returns false for UPS even when the service name contains 'pickup'
- ✓returns false for a normal UPS Ground shipment
- ✓returns false when provider is missing
✓getOvernightOptions — gating branchesShipping rules7
- ✓returns empty + 'empty-cart' for empty cart
- ✓returns empty + 'heavy-blocked' when any line is on the heavy blocklist
- ✓returns 'heavy-blocked' when heavy line uses branded SKU shape
- ✓returns 'heavy-blocked' when heavy line uses pack-alias SKU shape
- ✓returns 'no-eligible-lines' when cart has only dfs-ground paths
- ✓surfaces UPS lanes for an 'unknown' cart (fail-open per derive-shipping-path)
- ✓returns 'no-eligible-lines' for dis-stock cart when UPS rates are absent
✓<CancelShipmentButton> — success armsAccount pages7
- ✓marks cancelled, toasts success, closes and refreshes on a clean cancel
- ✓treats a missing message as a clean success
- ✓downgrades a success carrying "already" to the informational toast
- ✓downgrades a success carrying "voided" to the informational toast
- ✓downgrades a success carrying "invalid" to the informational toast
- ✓downgrades a success carrying "provider api error" to the informational toast
- ✓matches the partial-success wording case-insensitively
✓<CancelShipmentButton> — failure armsAccount pages7
- ✓marks cancelled anyway when the error says "not found"
- ✓takes the same arm on "already"
- ✓refuses without touching the store on "picked up"
- ✓refuses without touching the store on "in transit"
- ✓surfaces an unrecognised error verbatim, without touching the store
- ✓PINNED, NOT ENDORSED: the dialog closes even on the arm that never calls setOpen(false)
- ✓PINNED, NOT ENDORSED: an empty error message toasts with no description
✓StaffActionsClient — Cancel order (#3280)Account pages7
- ✓offers the tile on a pre-transit order and mounts its sheet
- ✓HIDES the tile once the order is cancelled — nothing left to do
- ✓HIDES the tile for a 'shipped' order — that is a return, and the backend 422s it
- ✓HIDES the tile for a 'out_for_delivery' order — that is a return, and the backend 422s it
- ✓HIDES the tile for a 'delivered' order — that is a return, and the backend 422s it
- ✓tells staff a refund request follows while the order still holds money
- ✓says it just closes the order out once the money is already back
✓OrderConfirmationEmailOrders & fulfilment6
- ✓renders a full confirmation snapshot
- ✓renders without a customer name when omitted
- ✓renders without a shipping address when omitted
- ✓includes the order number and items
- ✓prints every money figure the customer was charged
- ✓links the shipping FAQ (#1775)
✓isHoliday / isWeekend / isBusinessDayBusiness rules6
- ✓recognizes 2026 Independence Day observed on Fri Jul 3 (Jul 4 falls on Sat)
- ✓treats actual Jul 4 (Sat) as a weekend, not as the observed holiday
- ✓recognizes Christmas 2027 observed on Fri Dec 24 (Dec 25 falls on Sat)
- ✓recognizes New Year's Day 2028 observed on Fri Dec 31 2027 (Jan 1 2028 falls on Sat)
- ✓treats Sat & Sun as weekend regardless of hour
- ✓returns true from isBusinessDay only when neither weekend nor holiday
✓quotes-repoReference data6
- ✓createQuote inserts awaiting_reply and returns the new id
- ✓createQuote throws when the INSERT returns no id
- ✓listUserQuotes returns the user's quotes newest first
- ✓updateQuoteState flips state and records orderNumber
- ✓updateQuoteState without orderNumber preserves the existing one
- ✓setQuotePricing flips state to priced and records pricing
✓sendOrderConfirmationEmail — Resend returned-error observability (#1091)Business rules6
- ✓records the send and emails staff on the clean happy path
- ✓does NOT record + captures when the CUSTOMER send returns an error (#1091)
- ✓still records but captures when only the STAFF send errors (customer ok)
- ✓uses support@ as the replyTo on both customer + staff sends (#1259)
- ✓sends from the Clinton Tractor Support display name on support@send (#1280)
- ✓omits bcc on both sends when env is empty (#1259)
✓deriveOrderStatusVariantOrder records6
- ✓returns terminal variants first regardless of payment state
- ✓maps refunded payments to refunded/returned
- ✓maps payment-failed orders to hold
- ✓returns shipped for in-flight fulfillment
- ✓returns packing for paid + processing orders
- ✓falls back to placed for pending payment
✓sanitizeOrderForGuestOrder records6
- ✓returns only the public-safe fields
- ✓never includes street, postalCode, phone, payment or user fields
- ✓falls back to orderId when orderNumber is missing
- ✓returns no shipCityState when no shipping address is present
- ✓never leaks shippedAt — design surfaces estimated delivery only
- ✓returns city-only when state is missing
✓isCnhSourcedOrderReturns6
- ✓true when any line is cnh-overnight
- ✓true when any line is dfs-ground (drop-from-supplier)
- ✓false when all lines are dis-stock (Clinton on-shelf)
- ✓false for pickup / unknown lines
- ✓false for legacy orders with no shippingPath on any line
- ✓false for an empty order
✓the shipped lane gate — we do not have overnight yetShipping rules6
- ✓is off
- ✓offers nothing to a shelf cart the carrier quoted
- ✓offers nothing to an unknown-path cart
- ✓offers nothing to a CNH-direct cart
- ✓offers nothing to a supplier-direct cart
- ✓reports lanes-disabled ahead of every cart rule, including an empty cart
✓StaffActionsClient — ship ordersAccount pages6
- ✓renders Print label + Mark shipped + Put on hold + Set status + Send message + Request refund for a UPS shipment
- ✓mounts the print-label sheet for a ship order
- ✓treats clinton_tractor GROUND delivery as a manual delivery lane (#251)
- ✓treats a UPS service literally named '...Pickup' as a shipment, not a pickup
- ✓disables Print label for a ship order with no shipping address
- ✓turns the ship tile into a live Edit tracking control once the order is shipped
✓payQuoteActionServer actions5
- ✓returns the Stripe URL
- ✓passes the backend's own wording through to the customer
- ✓refuses at the click when the quote stopped being payable while the tab sat open
- ✓rejects a malformed token without calling the backend
- ✓survives a transport failure
✓quote actions — authentication gateServer actions5
- ✓listQuotesAction refuses an anonymous caller and touches no repo
- ✓getQuoteAction refuses an anonymous caller and touches no repo
- ✓createQuoteAction refuses an anonymous caller and touches no repo
- ✓markQuoteOrderedAction refuses an anonymous caller and touches no repo
- ✓declineQuoteAction refuses an anonymous caller and touches no repo
✓markQuoteOrderedAction / declineQuoteAction — mutation through the same gateServer actions5
- ✓marks the owner's quote ordered with the order number
- ✓does NOT write state when the quote belongs to another user
- ✓declines the owner's quote
- ✓does NOT decline another user's quote
- ✓reports UPDATE_FAILED when the write itself throws
✓OrderSummaryAccount screens5
- ✓renders item rows, totals, and the payment line
- ✓renders a quantity badge with the unicode multiplication sign
- ✓hides the discount row when none is present
- ✓shows a green discount row when discount > 0
- ✓treats missing shipping/tax as zero
✓<QuoteRow>Account screens5
- ✓renders the state label and reference
- ✓shows the Accept button only when state is priced
- ✓does not render the Accept button for awaiting_reply / ordered / declined
- ✓links to the order detail when state is ordered + orderNumber present
- ✓dims declined rows via opacity utility class
✓getCustomerAction — clintonInStock does not elevate customer-facing labelCNH parts service5
- ✓returns generic 'In Stock' for state=in_stock + clintonInStock=true
- ✓returns generic 'In Stock' when clintonInStock=false
- ✓returns generic 'In Stock' when clintonInStock is omitted
- ✓does NOT alter labels for non-primary in_stock variants
- ✓does NOT alter the call_us bucket when clintonInStock=true
✓nextDeliveryStatuses — forward targets + on_holdOrder records5
- ✓offers the full forward sequence + on_hold from processing (CT delivery)
- ✓offers pickup forward steps from processing
- ✓only offers later steps once partway through
- ✓from on_hold offers the sequence again without re-offering on_hold
- ✓terminal states offer nothing
✓computeQueueCountsOrder records5
- ✓returns zeros for an empty input
- ✓buckets paid + processing orders by label presence
- ✓counts payment-failed orders as backorder regardless of fulfillment status
- ✓ignores delivered / shipped / cancelled and counts pending+paid in pack cohort
- ✓excludes pending + failed (those land in the backorder bucket, not pack)
✓acceptQuoteBusiness rules5
- ✓rejects quotes that are not in `priced` state
- ✓rejects empty quotes
- ✓replaces the cart contents with the quote items + returns checkout redirect
- ✓captures the quoteItemToCartItem failure when staff forgot to price a line
- ✓rejects a second rapid accept on the same quote id
✓OrderDeskViewAccount pages5
- ✓renders the caller's heading on both the mobile and desktop layouts
- ✓shows the queue snapshot on an unfiltered first page
- ✓hides the snapshot under a status filter — it would contradict the filtered list
- ✓hides the snapshot under an email filter, and past the first page
- ✓keeps every row link inside the desk's own route family
✓OrderShippedEmailOrders & fulfilment4
- ✓renders a full shipped snapshot
- ✓includes the tracking number and the deep-link CTA
- ✓uses the customer name in the greeting
- ✓links the shipping FAQ (#1775)
✓getQuoteAction — ownershipServer actions4
- ✓returns the quote to its owner
- ✓hides someone else's quote behind the same NOT_FOUND a missing one gets
- ✓treats a null-owner (guest) quote as not the signed-in caller's
- ✓reports GET_FAILED, not a crash, when the repo throws
✓listQuotesAction / createQuoteAction — user scopingServer actions4
- ✓lists only the caller's quotes, scoped by their own id
- ✓reports LIST_FAILED when the repo throws
- ✓stamps the caller's id on a created quote, ignoring any supplied userId
- ✓reports CREATE_FAILED when the insert throws
✓submitReturnRequestAction (pin)Server actions4
- ✓sends a staff return-request email with the expected envelope on the happy path
- ✓returns validation failure when orderId is missing and does NOT send
- ✓captures to Sentry when Resend resolves an error (returns true non-fatal)
- ✓fails closed when RESEND_API_KEY is empty — sendSpy not called
✓ReturnListAccount screens4
- ✓renders one row per order item
- ✓invokes the toggle callback with the clicked partId
- ✓marks selected items as pressed and disables final-sale rows
- ✓ignores clicks on final-sale rows
✓TrackingTimelineAccount screens4
- ✓renders nothing when steps are empty
- ✓renders one <li> per step with the matching state attribute
- ✓shows labels and details
- ✓labels the timeline for assistive tech
✓useCutoffStateProduct features4
- ✓returns null on the very first render (pre-hydration), then resolves to the active state on a Monday morning ET
- ✓flips from active to after when the clock crosses 14:00 ET
- ✓returns weekend on Sunday
- ✓returns holiday on Independence Day observed (Fri Jul 3 2026)
✓useCutoffAnnouncementProduct features4
- ✓returns null when state is null
- ✓returns null when state is not active
- ✓announces when the active state crosses a boundary (e.g. 5min)
- ✓does not re-announce the same boundary twice
✓buildStaffNotificationHtml — XSS guardBusiness rules4
- ✓html-escapes a hostile item name
- ✓html-escapes a hostile partNumber
- ✓html-escapes a hostile userEmail and orderNumber
- ✓renders benign data without entity noise on plain text
✓resolveDeliveryChannel (#251)Order records4
- ✓maps the literal pickup provider to pickup
- ✓maps clinton_tractor + a pickup service type to pickup
- ✓maps clinton_tractor ground to clinton_delivery
- ✓maps everything else to ups
✓formatOrderNumberOrder records4
- ✓prefixes bare numeric IDs with ORD and an em-dash
- ✓normalises existing ORD-prefixed IDs to the em-dash form
- ✓trims surrounding whitespace
- ✓returns the raw input when the shape is unrecognised
✓unpayableReasonBusiness rules4
- ✓answers 'already paid' even once the link has also expired
- ✓tells an expired link it can be reissued, and warns that the price may move
- ✓names the parts we are short on rather than failing vaguely
- ✓sends a revoked link to a human
✓classifyReturnReasonReturns4
- ✓classes damaged / wrong_part / defective as our_fault
- ✓classes change_of_mind as customer_fault
- ✓classes other as review
- ✓OUR_FAULT_REASONS contains exactly the three dealer-fault reasons
✓buildReturnCostPreview — CNH-sourced ordersReturns4
- ✓every reason carries the CNH constraint + 20% restocking
- ✓CNH our-fault → still emails a label, but freight + 20% still apply
- ✓CNH change-of-mind → 20% restocking + customer pays shipping + freight
- ✓CNH other (review) → review class, customer pays, freight applies
✓checkCnhOvernightParity (#1437)Shipping rules4
- ✓returns isMatch:true when BE rate matches FE constant within tolerance
- ✓returns isMatch:false when BE rate differs by more than tolerance
- ✓returns isMatch:true and beCost:null when BE has no CNH overnight row
- ✓handles negative subtotal as 0 (same as FE formula)
✓getOvernightOptions — UPS lane compositionShipping rules4
- ✓includes UPS Next Day Air + 2nd Day Air for a dis-stock cart
- ✓picks the cheapest Next Day Air when UPS returns duplicates
- ✓does NOT surface UPS lanes when cart has no dis-stock line
- ✓skips a missing UPS service type silently (only the present one surfaces)
✓getOvernightOptions — Clinton CNH-direct overnight synthesisShipping rules4
- ✓synthesises a Clinton Next Day rate when any cnh-overnight line exists
- ✓computes cost from SUM of cnh-overnight line extended prices only
- ✓rounds Clinton Next Day cost to whole cents
- ✓uses public constants so re-tuning + John's D&H swap touch one place
✓detectCarrierShipping rules4
- ✓recognises UPS 1Z numbers, spaced or not
- ✓recognises USPS 20- and 22-digit numbers
- ✓recognises FedEx 12- and 15-digit numbers
- ✓returns null for shapes it does not know
✓merchantReturnPolicyForShippingPathGoogle visibility4
- ✓charges no restocking fee on our own shelf stock
- ✓keeps the published fee on CNH-sourced paths
- ✓fails to the published worst case on an unresolved path
- ✓changes nothing but the fee
✓partToLineBusiness rules4
- ✓carries the catalogue price, so nobody types one
- ✓refuses a part with no list price
- ✓falls back through title, short title, then the part number
- ✓reads a manufacturer whether it is a string or an object
✓OrderDetailsPage — access + tracking fetchAccount pages4
- ✓redirects an anonymous visitor to sign-in with a return url
- ✓skips the tracking call entirely when the order has no tracking number
- ✓passes the provider through to the tracking call
- ✓renders without the tracking history when the tracking lookup fails
✓orders-columns tracking cell (#2872)Account pages4
- ✓customer table (no onEditTracking) never shows an edit affordance
- ✓staff table shows Add for a carrier order without tracking and fires the callback
- ✓staff table shows the edit pencil next to an existing number
- ✓manual lanes (pickup) get no edit affordance even on the staff table
✓OrdersMobileListAccount pages4
- ✓groups orders by month label
- ✓counts orders for each chip filter
- ✓filters orders when a chip is clicked
- ✓renders an empty-filter message when nothing matches
✓<OrdersForMachineSection>Account pages4
- ✓renders one card per matching order with only the matched line items
- ✓renders the custom-equipment empty state and no order cards
- ✓renders the no-matches empty state with a link to /account/orders
- ✓renders the soft-error empty state when partsBatchError is true
✓StaffActionsClient — pickup ordersAccount pages4
- ✓HIDES Print label + Mark shipped for the literal pickup provider
- ✓shows Update delivery status + Set status + Send message + Request refund (no inert hold tile) for a pickup order (#251)
- ✓hides ship-only actions for clinton_tractor + a pickup service type (case-insensitive)
- ✓does not mount the print-label sheet for a pickup order
✓StaffActionsClient — Set status (manual override, #1149)Account pages4
- ✓shows Set status for UPS orders
- ✓shows Set status for pickup orders
- ✓shows Set status for CT delivery orders
- ✓mounts the manual-status sheet for all channels
✓OrderNotesStaff tools3
- ✓shows the empty state when the order has no notes
- ✓renders notes with You for own notes and a short id for colleagues
- ✓opens the add-note composer from the Add note button
✓CutoffBanner — storewide scopeProduct features3
- ✓renders the storewide banner regardless of overnightEligible (marketing affordance)
- ✓collapses the storewide banner via grid-rows transition once dismissed
- ✓renders the storewide banner shell expanded when not dismissed
✓CutoffBanner — viewport-height variable (front#1523)Product features3
- ✓publishes 40px on :root while the storewide banner is shown
- ✓publishes 0px on :root while the storewide banner is dismissed
- ✓clears the variable on unmount so other routes are not offset
✓order-confirmations-repoReference data3
- ✓wasConfirmationSent is false before any record
- ✓records a send then reads it back (dispatch hits PG)
- ✓a retry for the same order is idempotent (single ledger row)
✓sendConfirmationEmailForOrderBusiness rules3
- ✓sends the confirmation with the order payload when the order is present
- ✓skips the send and drops a Sentry breadcrumb when the order is null
- ✓swallows a thrown send and captures it (best-effort, never rejects)
✓fetchLivePartStatusBatch (#1584 — branded vs bare PN keying)CNH parts service3
- ✓sends bare OEM PNs upstream and resolves the Map under BOTH branded and bare keys
- ✓dedups branded + bare inputs that normalize to the same OEM PN
- ✓returns an empty Map (no fetch) when baseUrl is unset — fail-open
✓deliveryStatusLabel — channel-awareOrder records3
- ✓relabels ready + delivered for pickup
- ✓uses dispatch wording for clinton_delivery ready
- ✓labels out_for_delivery + on_hold consistently
✓computeStaffOrderCountsOrder records3
- ✓buckets each status into the right queue lane
- ✓returns all-zero for an empty queue
- ✓excludes cancelled from every actionable bucket
✓loadPayPageQuoteBusiness rules3
- ✓returns the quote and asks the live gate about its parts
- ✓skips the live gate for a quote that can no longer be paid anyway
- ✓returns null on an unknown token, a body with no quote, or an unset base URL
✓buildReturnCostPreview — non-CNH ordersReturns3
- ✓our-fault reasons → free label, no restocking, no customer shipping
- ✓change_of_mind → 20% restocking + customer pays shipping, no label
- ✓other → review class, conservative customer-fault preview
✓estimateCnhReturnFreightReturns3
- ✓returns the flat estimate when the order is CNH-sourced with a positive subtotal
- ✓returns 0 for non-CNH-sourced orders
- ✓returns 0 when no items are selected (zero/negative/NaN subtotal)
✓cnh-overnight golden fixture — cart vectors (#303)Shipping rules3
- ✓single cnh-overnight line ($129 - the #299 / front#1343 P0 case)
- ✓overweight-split mixed cart (#301 - split-immune, packages mis-chunked)
- ✓multiple cnh-overnight lines sum before markup
✓resolveIsFirstOrder — first-order discount kill-switch (#1101)Shipping rules3
- ✓forces false when the flag is OFF, regardless of the requested value
- ✓passes through the requested value when the flag is ON
- ✓defaults to true when ON and the caller omits the signal (legacy 'assume first order')
✓getOvernightOptions — carrier-prefixed service names (real wire form)Shipping rules3
- ✓surfaces both UPS air lanes when the carrier prefixes the service name
- ✓keys a prefixed lane the same as a bare one so selection round-trips
- ✓picks the cheapest lane across mixed prefixed and bare quotes
✓AdminOrderTrackingPageAccount pages3
- ✓redirects a non-admin away
- ✓renders the order-tracking desk with the demo orders in dev
- ✓shows the queue-counts strip on the unfiltered first page
✓QuotesContent accept flowAccount pages3
- ✓accepts directly without dialog when the cart is empty
- ✓opens the replace-cart dialog when the cart already has items
- ✓confirms replacement and swaps the cart contents for the quote
✓DeliveryProgressSection — pickup vs shipAccount pages3
- ✓renders pickup milestones (no In Transit / Out for Delivery) for a pickup order
- ✓keeps the UPS milestone bar + 'Shipped via' for a ship order
- ✓treats clinton_tractor ground delivery as ship (not pickup)
✓OrderItemBrandLogoStaff tools2
- ✓renders a brand logo for a branded sku
- ✓renders nothing for a legacy line without a sku
✓return-requests-repoReference data2
- ✓findPendingReturnRequest returns null when nothing pending
- ✓createReturnRequest returns an id and findPending(order,user) then hits it
✓cancellation reasons contract (#3280)Order records2
- ✓is a real array mirroring the payment service's CancellationReasonSchema
- ✓labels every reason
✓deliverySequenceOrder records2
- ✓pickup skips out_for_delivery
- ✓clinton_delivery includes out_for_delivery
✓quoteItemToCartItemBusiness rules2
- ✓maps quote item into a CartItem with the staff-quoted unit price
- ✓throws when the quote item is unpriced
✓buildReturnCostPreview — copy guardrailsReturns2
- ✓non-CNH previews never promise/mention cancellation
- ✓every preview surfaces non-empty detail copy before confirm
✓restockingFeeAmountReturns2
- ✓computes 20% of subtotal rounded to cents
- ✓returns 0 for zero rate, zero/negative/non-finite subtotal
✓cnh-overnight-golden — exposureShipping rules2
- ✓GOLDEN exposes the constants and vectors from the JSON
- ✓the #303 acceptance vectors are present ($0 floor, $129 P0, $5000, split cart)
✓cnh-overnight-golden — expectedCostForShipping rules2
- ✓returns the expected cost for a known subtotal
- ✓throws a named error for a subtotal with no golden vector
✓cnh-overnight-golden — overnightLine builderShipping rules2
- ✓defaults to a non-heavy cnh-overnight line
- ✓applies overrides over the defaults
✓cnh-overnight-golden — pricingContract projectionShipping rules2
- ✓includes exactly the cross-repo contract fields
- ✓excludes _comment so doc-only edits never trip the cross-repo check
✓cnh-overnight golden fixture — constants parity (#303)Shipping rules2
- ✓FE constants match the golden fixture
- ✓rate key is derived from the fixture provider + serviceType pair
✓cnh-overnight golden fixture — display title bindings (#303)Shipping rules2
- ✓rate-title maps the fixture provider/serviceType to the fixture display title
- ✓display title is registered in the canonical shipping titles list
✓getOvernightOptions — strict per-state overnight (John 2026-05-18)Shipping rules2
- ✓returns ZERO options + 'mixed-stock-state' for mixed dis-stock + cnh-overnight cart
- ✓allows unknown + cnh-overnight (unknown is fail-open, not stock-pinned)
✓addLineBusiness rules2
- ✓bumps the quantity instead of repeating the row
- ✓appends a different part
✓isCompleteBusiness rules2
- ✓accepts an address with no state — this is not the US-only checkout
- ✓rejects a missing street, a bad email or a one-letter country
✓buildQuoteInputBusiness rules2
- ✓drops an empty note rather than sending a blank one
- ✓coerces the typed shipping and expiry, defaulting rather than sending NaN
✓monthBucketKeyAccount pages2
- ✓agrees with the local-time Intl month formatter across UTC boundaries
- ✓buckets a single boundary-crossing order under one section (no UTC/local split)
✓MobileOrderDetail — pickup vs shipAccount pages2
- ✓uses pickup copy (no 'ships' / 'Estimated arrival') for a pickup order
- ✓keeps ship copy ('ships from Clinton, NY' + 'Estimated arrival') for a ship order
✓STAFF_ACTION_ICONS (RSC serialization guard, front#1069)Account pages2
- ✓exposes one icon per staff action
- ✓passes every icon as a serializable React element, never a component reference
✓toEasternDateKeyBusiness rules1
- ✓returns the ET-local YYYY-MM-DD even when host TZ would format differently
✓sendOrderConfirmationEmail — BCC injection (#1259)Business rules1
- ✓BCCs the configured alias on the customer send only, NOT staff
✓types.ts ↔ schemas.ts parity (compile-time)CNH parts service1
- ✓DisplayState hand-type and schema enum are mutually assignable
✓isPostHandoffOrder records1
- ✓is true exactly for the statuses the backend 422s as ORDER_IN_TRANSIT
✓stillOwesMoneyOrder records1
- ✓is true only while money the customer has not got back sits on the order
✓isManualDeliveryChannelOrder records1
- ✓is true for pickup + clinton_delivery, false for ups
✓isPayableBusiness rules1
- ✓is true only for an open, unexpired quote with everything still available
✓RETURN_REASONS list integrityReturns1
- ✓contains all five reasons with no duplicates
✓cnh-overnight-golden — cartFromVectorShipping rules1
- ✓builds one cart line per vector line with its price and quantity
✓getOvernightRateKeyShipping rules1
- ✓matches the published key constants
✓normalizeTrackingNumberShipping rules1
- ✓strips the separators printed on carrier labels
✓quoteSubtotalBusiness rules1
✓StaffOrderCountsStripAccount pages1
- ✓renders each queue lane with its label and count
✓StaffOrdersMobileViewAccount pages1
- ✓presses the active status chip and declares no tab roles (#3570)
What we walk through in a real browser4 journeys
○Cutoff banner — selector smoke (front#284)Browser journey3
- ○storewide banner renders on the home page
- ○storewide dismiss collapses the banner and persists across reload
- ○cart page renders without the cutoff banner when empty (cart-level invariant requires items)
○Shipping uc5 multi overnightBrowser journey2
- ○UC-D-5 — no UPS overnight lane reaches the customer (mock-delivery)
- ○UC-D-5 — a correctly-matched wire response still surfaces no UPS lane
○Staff — order list -> detail (regression for #1037)Browser journey2
- ○staff can open the first order from the list without hitting error boundary
- ○invalid orderId surfaces a friendly error boundary (gated on #1037 fix)
○public /track (flagged off by default)Browser journey1
- ○serves the coming-soon stub at 200, held out of the index
Automated checks580
Browser journeys0
Code exercised—
Not part of the shipped site, so there is no code-exercised figure.
What we check automatically129 groups
✓next.config.ts headers() — public CDN cache (#939)Our own safety nets21
- ✓declares Vercel-CDN-Cache-Control header somewhere
- ✓declares CDN-Cache-Control mirror header
- ✓includes '/parts-diagrams (bare hub)' in the cacheable headers() entries
- ✓includes '/parts-diagrams/models (DETAIL overri…' in the cacheable headers() entries
- ✓includes 'assembly detail (DETAIL override)' in the cacheable headers() entries
- ✓includes '/parts (listing root)' in the cacheable headers() entries
- ✓includes '/parts-diagrams/*' in the cacheable headers() entries
- ✓includes '/brands' in the cacheable headers() entries
- ✓includes '/parts/brand/*' in the cacheable headers() entries
- ✓includes '/parts/category/*' in the cacheable headers() entries
- ✓pins '/parts-diagrams/:path*' to the REFERENCE tier (s-maxage=86400)
- ✓pins source: "/equipment", to the LISTING tier (s-maxage=600)
- ✓pins source: "/equipment/:path+" to the LISTING tier (s-maxage=600)
- ✓pins source: "/attachments" to the LISTING tier (s-maxage=600)
- ✓keeps same-key DETAIL overrides AFTER the broad /parts-diagrams REFERENCE rule
- ✓pins source: "/parts-diagrams", to the DETAIL tier (s-maxage=3600)
- ✓pins source: "/parts-diagrams/models" to the DETAIL tier (s-maxage=3600)
- ✓pins "/parts-diagrams/model/:slug/parts-diagrams/:code" to the DETAIL tier (s-maxage=3600)
- ✓uses public, s-maxage TTL presets (not no-store)
- ✓includes PDP /parts/[id] in the cacheable list (CT-950)
- ✓excludes auth surfaces (/checkout, /account, /admin, /sign-in) from cacheable list
✓suppressed steps must be read by outcome, never by conclusionRelease gates20
- ✓brand-pdp-gate.yml guards no unconditionally suppressed step on its conclusion
- ✓checkout-payment-smoke.yml guards no unconditionally suppressed step on its conclusion
- ✓ci-fleet-dark-check.yml guards no unconditionally suppressed step on its conclusion
- ✓ci.yml guards no unconditionally suppressed step on its conclusion
- ✓claude.yml guards no unconditionally suppressed step on its conclusion
- ✓close-on-dev-merge.yml guards no unconditionally suppressed step on its conclusion
- ✓e2e-deep.yml guards no unconditionally suppressed step on its conclusion
- ✓e2e-mobile.yml guards no unconditionally suppressed step on its conclusion
- ✓e2e-stage.yml guards no unconditionally suppressed step on its conclusion
- ✓fixture-parity.yml guards no unconditionally suppressed step on its conclusion
- ✓gsc-gate.yml guards no unconditionally suppressed step on its conclusion
- ✓main-protection-drift-check.yml guards no unconditionally suppressed step on its conclusion
- ✓mchale-launch-gate.yml guards no unconditionally suppressed step on its conclusion
- ✓moby-ds-checks.yml guards no unconditionally suppressed step on its conclusion
- ✓nh-launch-gate.yml guards no unconditionally suppressed step on its conclusion
- ✓nightly.yml guards no unconditionally suppressed step on its conclusion
- ✓pr-provenance.yml guards no unconditionally suppressed step on its conclusion
- ✓pr-soft-404-crawler.yml guards no unconditionally suppressed step on its conclusion
- ✓seo-main-dev-drift-check.yml guards no unconditionally suppressed step on its conclusion
- ✓sitemap-seo-gate.yml guards no unconditionally suppressed step on its conclusion
✓checkPageInternal scripts18
- ✓passes a page whose schema mirrors its visible trail
- ✓fails a page with no trail at all
- ✓fails a page rendering its trail twice
- ✓fails a trail that does not start at Home
- ✓fails a page that renders a trail and emits none
- ✓fails when the leaf links itself (#3414)
- ✓fails when a rung names a page the trail never shows (#3410)
- ✓fails when a rung points somewhere else than the visible link
- ✓fails when a rung is missing from the schema
- ✓tolerates a visible rung with no page of its own, which the schema drops
- ✓accepts a page with neither nav nor schema
- ✓reds if such a page grows a visible nav
- ✓reds if such a page grows a BreadcrumbList — the #744 shape must not come back
- ✓does not apply the rule to an ordinary page
- ✓accepts a visible trail with no BreadcrumbList
- ✓reds if the markup comes back
- ✓reds if the human trail is dropped instead
- ✓still demands the trail start at Home
✓every deployed-stage lane tests the build its specs came fromRelease gates18
- ✓e2e-stage.yml checks out stage, not the branch it was scheduled on
- ✓checkout-payment-smoke.yml checks out stage, not the branch it was scheduled on
- ✓e2e-stage.yml derives its target from the checked-out commit
- ✓checkout-payment-smoke.yml derives its target from the checked-out commit
- ✓e2e-stage.yml hands the resolve step the token it reads
- ✓checkout-payment-smoke.yml hands the resolve step the token it reads
- ✓e2e-stage.yml can read the deployments API it depends on
- ✓checkout-payment-smoke.yml can read the deployments API it depends on
- ✓e2e-stage.yml tells an unreadable API from a deploy that is not ready
- ✓checkout-payment-smoke.yml tells an unreadable API from a deploy that is not ready
- ✓e2e-stage.yml says which cut its verdict covers
- ✓checkout-payment-smoke.yml says which cut its verdict covers
- ✓e2e-stage.yml never names a branch alias as its target
- ✓checkout-payment-smoke.yml never names a branch alias as its target
- ✓e2e-stage.yml drives the suite at the resolved deployment
- ✓checkout-payment-smoke.yml drives the suite at the resolved deployment
- ✓e2e-stage.yml puts that scope in the issue it files
- ✓checkout-payment-smoke.yml puts that scope in the issue it files
✓next.config.ts redirects() — retired parts-diagrams surfaces do not redirect (#3345)Our own safety nets14
- ✓no longer redirects the /parts-diagrams/new-holland-agriculture landing
- ✓no longer redirects the /parts-diagrams/ferris landing
- ✓no longer redirects the /parts-diagrams/ventrac landing
- ✓no longer redirects the /parts-diagrams/mchale landing
- ✓no longer redirects the /parts-diagrams/marcrest landing
- ✓no longer redirects the /parts-diagrams/kuhn landing
- ✓no longer redirects the /parts-diagrams/kress landing
- ✓no longer redirects the /parts-diagrams/landoll landing
- ✓no longer redirects the /parts-diagrams/brillion landing
- ✓no longer redirects the /parts-diagrams/agco landing
- ✓drops the flatMap brand-retirement templates entirely
- ✓drops the legacy /parts-schematics redirects
- ✓adds no wildcard redirect over the retired tree
- ✓leaves the live model-diagram viewer unredirected
✓scheduled lanes run on the self-hosted pool (#3523)Release gates13
- ✓brand-pdp-gate.yml runs every job on the crop pool
- ✓checkout-payment-smoke.yml runs every job on the crop pool
- ✓e2e-deep.yml runs every job on the crop pool
- ✓e2e-mobile.yml runs every job on the crop pool
- ✓e2e-stage.yml runs every job on the crop pool
- ✓gsc-gate.yml runs every job on the crop pool
- ✓main-protection-drift-check.yml runs every job on the crop pool
- ✓mchale-launch-gate.yml runs every job on the crop pool
- ✓nh-launch-gate.yml runs every job on the crop pool
- ✓nightly.yml runs every job on the crop pool
- ✓seo-main-dev-drift-check.yml runs every job on the crop pool
- ✓sitemap-seo-gate.yml runs every job on the crop pool
- ✓the fleet watchdog is still hosted, and is the only exception
✓detectSoftError (200 + error-body soft-404 detection)Internal scripts12
- ✓returns undefined for a clean 200 body
- ✓returns undefined for any non-200 status, even with an error body
- ✓catches the exact #754 regression: 200 + 'Unable to load this equipment model'
- ✓catches 200 + 'Equipment Not Found' notFound boundary
- ✓catches 200 + 'Service Unavailable' and the no-space variant
- ✓catches 200 + 'We hit an unexpected error' generic boundary copy
- ✓is case-insensitive on the body
- ✓returns the first matching substring when multiple are present
- ✓does not false-positive on legitimate copy that lacks the markers
- ✓ignores the error substring when it only appears inside an RSC <script> block
- ✓ignores the error substring when it only appears inside a <template> block
- ✓still flags a genuine soft-404 with the error text in real body markup
✓an API route handler is not a screenshot (#3704)Release gates11
- ✓app/api/health/route.ts does not demand a screenshot
- ✓app/api/checkout/session/route.ts does not demand a screenshot
- ✓app/api/revalidate/route.ts does not demand a screenshot
- ✓app/parts/[id]/page.tsx still demands a screenshot
- ✓app/layout.tsx still demands a screenshot
- ✓app/page.tsx still demands a screenshot
- ✓app/(shop)/cart/page.tsx still demands a screenshot
- ✓app/parts/[id]/_styles/pdp.css still demands a screenshot
- ✓components/ui/button.tsx still demands a screenshot
- ✓pr-provenance reads the screenshot group, not visual
- ✓the heavy-gate groups still see app/api — a route handler can break e2e
✓main-required-contexts.json tracks real ci.yml jobsRelease gates11
- ✓names at least the three contexts #3550 asks main to require
- ✓'lint-and-build' is a job in ci.yml
- ✓'seo-smoke' is a job in ci.yml
- ✓'unit-tests' is a job in ci.yml
- ✓'e2e-smoke' is a job in ci.yml
- ✓'e2e-customer-flows' is a job in ci.yml
- ✓'lint-and-build' has no name: override that would rename its check
- ✓'seo-smoke' has no name: override that would rename its check
- ✓'unit-tests' has no name: override that would rename its check
- ✓'e2e-smoke' has no name: override that would rename its check
- ✓'e2e-customer-flows' has no name: override that would rename its check
✓interpretRunInternal scripts10
- ✓passes a run with passing tests
- ✓fails a run with failures, carrying Playwright's own exit code
- ✓fails a failing run even when the child reported no status
- ✓fails a run where every spec skipped, and says so
- ✓fails a run where nothing ran at all, with a different message
- ✓passes a partially-skipped run, because some specs did report
- ✓fails an all-skipped run even though the auth dependency passed
- ✓counts a real manifest pass alongside the dependency's
- ✓reads the ascii tick, so a runner without unicode is not silently green
- ✓fails closed when the summary claims passes the reporter lines do not show
✓the e2e harness — boot + spec as deep modules (#1408 C4)Release gates10
- ✓boot-app module owns the only health-check boot loop
- ✓ci.yml: no sleep-based server boot (the race that flaked lighthouse)
- ✓pr-soft-404-crawler.yml: no sleep-based server boot (the race that flaked lighthouse)
- ✓'e2e-smoke' runs its spec through the run-e2e-spec module
- ✓'seo-smoke-matrix' runs its spec through the run-e2e-spec module
- ✓run-e2e-spec uploads the failure report (debugging contract)
- ✓run-e2e-spec emits a machine-readable result set, not just console lines
- ✓run-e2e-spec uploads its report when the job is cancelled, not only on failure
- ✓e2e-deep reports when the run is cancelled, not only when it fails
- ✓e2e-deep uploads its shard report when cancelled, not only on failure
✓the deep lane splitInternal scripts9
- ✓accounts for every spec no other gate owns
- ✓claims nothing that is not in the lane
- ✓puts each spec in exactly one bucket
- ✓keeps a non-empty blocking set — an empty one would report green on nothing
- ✓gives every quarantined spec a stated failure mode
- ✓gives every quarantined spec an issue number, not just a symptom
- ✓keeps the blocking set larger than the quarantine
- ✓gives every reassigned spec the gate that owns it instead
- ✓names a quarantine owner and a review date
✓path filters — single source of truth (#1408 C2)Release gates9
- ✓'code' group contains the full shared app surface
- ✓'ui' group contains the full shared app surface
- ✓'visual' group contains the full shared app surface
- ✓code group covers every surface the e2e/seo gates assert against
- ✓ui group covers the render-affecting surfaces (lighthouse budgets)
- ✓visual group is the render surface WITHOUT the CI plumbing
- ✓crawl group covers every surface the localhost crawl job asserts against (#1409)
- ✓ci.yml changes job reads filters from the shared file, not an inline list
- ✓pr-provenance reads filters from the shared file, not an inline list
✓next.config.ts redirects() — apex migration map (#3871)Our own safety nets8
- ✓308s '/inventory' → '/equipment'
- ✓308s '/inventory/:path*' → '/equipment'
- ✓308s '/equipment/models' → '/parts-diagrams/models'
- ✓308s '/equipment/:slug/:rest+' → '/parts-diagrams/model/:slug/:rest+'
- ✓308s '/equipment/:slug/assemblies' → '/parts-diagrams/model/:slug/parts-dia…'
- ✓308s '/equipment/:slug/assemblies/:rest+' → '/parts-diagrams/model/:slug/parts-dia…'
- ✓pairs every star-tail rule with a bare rule, or the empty match costs a hop
- ✓leaves single-segment /equipment/{seg} to the proxy carve, not a config rule
✓findViolationsInternal scripts8
- ✓reds a 20-line block and names its span and length
- ✓stays green at the threshold and reds one line over it
- ✓exempts __pins__ fixtures, .d.ts and generated paths
- ✓exempts a file marked generated in its first lines
- ✓exempts a licence header but not a second oversized block
- ✓does not count a leading @ts- / eslint- / biome- directive run
- ✓still reds prose that follows a directive run
- ✓only scans TypeScript/JavaScript sources
✓evaluateGate — absolute sitemap floor (fires at 0 indexed, with no baseline)Internal scripts8
- ✓fails on sitemap errors
- ✓fails on a sitemap pending for more than 48h
- ✓tolerates a sitemap pending for less than 48h
- ✓fails when the last download is older than 7 days
- ✓fails when a long-submitted sitemap was never downloaded
- ✓tolerates a just-submitted sitemap Google has not fetched yet
- ✓fails when no sitemap is registered at all
- ✓fails on the floor even when the delta is clean
✓the mobile project manifestInternal scripts8
- ✓is declared in playwright.config.ts
- ✓has no stem that matches no file
- ✓collects one spec file per stem
- ✓collects only files that exist on disk
- ✓matches each spec by its whole stem, not by coincidence
- ✓runs under the phone project, not the desktop one
- ✓splits every mobile spec into exactly one half
- ✓refuses a quarantine entry the project no longer collects
✓PR accountability gate — what it demands, and of whomRelease gates8
- ✓asks a non-code PR for provenance only
- ✓asks a code PR for the full before/after and its evidence
- ✓passes a filled body
- ✓reads evidence pasted on the lines below its label
- ✓rejects a UI change whose evidence is prose about a screenshot
- ✓accepts a preview-deploy link in place of an attached image
- ✓rejects a driver that is not a GitHub handle
- ✓template carries every label the gate reads
✓deployed-stage lanes cannot mistake the login wall for a live target (#3665)Release gates8
- ✓e2e-stage.yml still has a preflight step to check
- ✓checkout-payment-smoke.yml still has a preflight step to check
- ✓e2e-stage.yml carries the bypass secret in its job env
- ✓checkout-payment-smoke.yml carries the bypass secret in its job env
- ✓e2e-stage.yml sends the bypass header when it probes the target
- ✓checkout-payment-smoke.yml sends the bypass header when it probes the target
- ✓e2e-stage.yml rejects a probe that landed on the login wall
- ✓checkout-payment-smoke.yml rejects a probe that landed on the login wall
✓gates probing a protected preview surface carry the bypass (#3637)Release gates7
- ✓some workflow actually probes crop-dev, or this contract is vacuous
- ✓brand-pdp-gate.yml passes the automation bypass secret
- ✓mchale-launch-gate.yml passes the automation bypass secret
- ✓nh-launch-gate.yml passes the automation bypass secret
- ✓brand-pdp-gate.yml calls a protection redirect by its name
- ✓mchale-launch-gate.yml calls a protection redirect by its name
- ✓nh-launch-gate.yml calls a protection redirect by its name
✓isPathClaimInternal scripts6
- ✓claims a deep path under a directory this repo has
- ✓claims a deep path with a file extension even outside a known root
- ✓does not claim branch names, labels or URL routes
- ✓does not claim URLs or paths reaching outside the repo
- ✓does not claim single-segment tokens — a convention name is not a location
- ✓does not claim globs, placeholders or sibling repos
✓findCommentBlocksInternal scripts6
- ✓treats consecutive // lines as one block
- ✓splits runs on a blank line
- ✓counts a /* */ block from opener to closer
- ✓joins a /* */ block and the // lines touching it
- ✓counts a JSX {/* */} block, the bloat vector in a .tsx repo
- ✓ignores trailing comments and comment-like string content
✓evaluateGate — baseline deltaInternal scripts6
- ✓establishes the baseline (passes) when there is no prior snapshot
- ✓passes when coverage is stable
- ✓passes on a small indexed dip below the 10% threshold
- ✓flags a >=10% sitemap-indexed drop
- ✓flags a canary going from indexed to not-indexed
- ✓does not flag a canary that stays indexed
✓parseArgsInternal scripts6
- ✓defaults to queries when no section flag is given
- ✓parses section flags + --json
- ✓captures an --inspect target but not a following flag
- ✓sets adc only with --adc
- ✓parses dates and limit
- ✓throws on an unknown flag
✓crawl (with injected fetch)Internal scripts6
- ✓passes when every URL is a clean 200
- ✓fails on a soft-404 (200 + error body) — the #754 scenario
- ✓passes a healthy streamed page whose RSC <script> payload contains error copy
- ✓fails on a hard non-200
- ✓records a fetch error as a failure
- ✓preserves fixture order in the report regardless of concurrency
✓the Tiering Gate — run/skip policy lives in one module (#1408 C1, #1409)Release gates6
- ✓'ci.yml' changes job exposes the gate decisions as outputs
- ✓'ci.yml': ''e2e-smoke'' consumes the ''heavy'' gate, never re-derives it
- ✓'ci.yml': ''seo-smoke-matrix'' consumes the ''heavy'' gate, never re-derives it
- ✓'ci.yml': ''lighthouse'' consumes the ''lighthouse'' gate, never re-derives it
- ✓'ci.yml': ''pr-localhost-crawl'' consumes the ''crawl'' gate, never re-derives it
- ✓ci.yml gate decision logs its inputs (debuggable from the run page)
✓deployed-stage lanes stop waiting for a build that already failed (#3665)Release gates6
- ✓e2e-stage.yml reads the terminal states, not only success
- ✓checkout-payment-smoke.yml reads the terminal states, not only success
- ✓e2e-stage.yml bails out only when nothing is still building
- ✓checkout-payment-smoke.yml bails out only when nothing is still building
- ✓e2e-stage.yml names a build failure as a build failure
- ✓checkout-payment-smoke.yml names a build failure as a build failure
✓the build job alone is off the production backend (#3707)Release gates6
- ✓build names the dev backend
- ✓every other job in ci.yml still names production
- ✓e2e-mobile.yml still reads the production backend
- ✓e2e-deep.yml still reads the production backend
- ✓nightly.yml still reads the production backend
- ✓sitemap-seo-gate.yml still reads the production backend
✓fetchCanonicalFixtureInternal scripts6
- ✓reports no-auth when there is neither a token nor a usable gh CLI
- ✓prefers the token path and returns the branch it hit
- ✓falls through to dev when main 404s, and reports absent when both do
- ✓throws on a non-404 API failure rather than passing as bootstrap
- ✓uses the gh CLI when no token is set
- ✓treats a gh 404 as a miss and a real gh error as a failure
✓next.config.ts redirects() — dead aliases removed (#3871)Our own safety nets5
- ✓no longer redirects /parts/brand/ferris/parts
- ✓no longer redirects /parts/brand/ventrac/parts
- ✓no longer redirects /parts/brand/mchale/parts
- ✓no longer redirects /parts/brand/marcrest/parts
- ✓no longer redirects /favorites
✓next.config.ts redirects() — new-holland → new-holland-agriculture 308Our own safety nets5
- ✓308s '/brand/new-holland' → '/brand/new-holland-agriculture'
- ✓308s '/parts/brand/new-holland' → '/parts/brand/new-holland-agriculture'
- ✓308s '/parts/brand/new-holland/:path*' → '/parts/brand/new-holland-agriculture/…'
- ✓308s '/parts/brand/new-holland-agriculture/…' → '/brand/new-holland-construction'
- ✓keeps the legacy /type/construction CE-hub heal BEFORE the /:path* wildcard
✓collectFindingsInternal scripts5
- ✓passes a body whose paths and scripts all resolve
- ✓reports a path that no longer exists, with its line
- ✓reports a documented bun script that is not in package.json
- ✓resolves the @/ path alias against the repo root
- ✓catches every drift class this gate was written for
✓diffFloorsInternal scripts5
- ✓passes when current equals baseline
- ✓passes when fractional pct wobble stays within the same integer floor (58.9 → 58.1)
- ✓fails when fractional pct crosses an integer floor boundary (58.9 → 57.9)
- ✓fails on a deliberate ~3 point drop below baseline
- ✓renders a diff table
✓commit-msg hookInternal scripts5
- ✓accepts AI attribution instead of rejecting it
- ✓keeps the trailer for an author who has not opted out
- ✓strips AI trailers for an author who opted out
- ✓leaves a human co-author alone even for an opted-out author
- ✓still enforces the conventional-commit format
✓crawler cookie jar (Clerk handshake loop)Internal scripts5
- ✓completes handshake in <= 5 hops when the jar persists cookies
- ✓exhausts MAX_HOPS without the jar (regression guard — demonstrates the old bug)
- ✓parses a Set-Cookie value into name / value, ignoring attributes
- ✓returns null for a malformed Set-Cookie with no equals sign
- ✓keeps the most recent value when the same cookie is reset mid-chain
✓detectSoftStatus (body-probe for soft-200 errors)Internal scripts5
- ✓returns undefined when status is not 200
- ✓returns soft-404 for Next.js notFound() body markers
- ✓returns soft-503 for ServiceUnavailable body markers
- ✓does NOT match prose copy that just mentions the words
- ✓returns undefined for healthy 200 bodies
✓isExempt404Internal scripts5
- ✓returns exempt:false when no entries
- ✓matches exact url
- ✓matches glob pattern with *
- ✓does not partial-match without wildcard
- ✓escapes regex special chars in pattern literal segments
✓role identityInternal scripts5
- ✓names one env var per role
- ✓keeps every state file inside the gitignored auth dir
- ✓treats blank and whitespace-only addresses as absent
- ✓trims a configured address
- ✓splits configured from missing roles
✓stripScriptAndTemplateBlocksInternal scripts5
- ✓removes <script> blocks and their contents
- ✓removes <template> blocks and their contents
- ✓removes multiple blocks and is case-insensitive on tag names
- ✓handles script tags with attributes
- ✓leaves markup outside script/template blocks untouched
✓parseUrlsFixtureInternal scripts5
- ✓returns the urls array for a valid fixture
- ✓ignores extra keys like _doc
- ✓throws on a non-object
- ✓throws on a missing or empty urls array
- ✓throws on non-string or empty entries
✓analyzeRobotsInternal scripts5
- ✓detects a Sitemap directive and no global block on a healthy robots.txt
- ✓flags a wildcard Disallow: / as a global block
- ✓does not flag a path-scoped disallow as a global block
- ✓only counts Disallow: / under the wildcard group, not a named bot
- ✓ignores comments
✓isHealthyInternal scripts5
- ✓is healthy when reachable sections pass and the rest are unavailable
- ✓is unhealthy when the sitemap probe returns not-ok
- ✓is unhealthy when robots.txt blocks all crawlers
- ✓is unhealthy when a CrUX metric rates POOR
- ✓does not penalize health for unavailable (key-missing) sections
✓soft-404 crawler — draft previews exit before paying for setup (#1409)Release gates5
- ✓the PR/draft gate is the job's first step (nothing is paid for before it)
- ✓the gate reads draft state and honors the run-e2e label override
- ✓the gate logs its decision (debuggable from the run page)
- ✓every paid step consumes the gate decision (fail-open, skip only on 'false')
- ✓re-crawls when a draft PR is marked ready (Vercel does not redeploy on ready)
✓security job — one semgrep scan, blocking decision in the gate script (#1409)Release gates5
- ✓runs semgrep exactly once
- ✓the single scan covers the custom rules and every community pack
- ✓the scan reports to SARIF and never decides blocking by itself
- ✓custom ERROR rules still block, through the unit-tested gate script
- ✓SARIF still uploads to the Security tab and as an artifact
✓required status checks — dev and main are gated alike (#1518, #3550)Release gates5
- ✓declares one ruleset for dev and one for the default branch
- ✓requires the same contexts on both branches
- ✓every required context is a job ci.yml defines
- ✓the apply script reads the declaration instead of its own copy
- ✓ci-conventions.md documents exactly the declared contexts, in one list
✓e2e-stage tests the build its specs came fromRelease gates5
- ✓a non-push run checks out stage, never the default branch it was scheduled on
- ✓the target is derived from the checked-out commit, not from an alias
- ✓the suite runs against the resolved deployment and nothing else
- ✓an unreadable API is reported as a CI fault, not as a deploy problem
- ✓every run says which cut its verdict covers
✓the light pool never gets a job that boots the build artifact (#3673)Release gates5
- ✓some job actually uses the light pool, or this contract is vacuous
- ✓changes neither builds nor boots the artifact
- ✓typecheck neither builds nor boots the artifact
- ✓unit-tests-shards neither builds nor boots the artifact
- ✓seo-smoke neither builds nor boots the artifact
✓next.config.ts redirects() — co-located diagrams ?type query → /type/ path 308 (#2367)Our own safety nets4
- ✓308s ?equipmentType= on …/diagrams to the /type/ path
- ✓308s ?category= on …/diagrams to the /type/ path
- ✓captures only the type value, never trailing query params, into the path
- ✓308s the NHC division ?sub= to the /type/ path, scoped to the division slug only
✓extractionInternal scripts4
- ✓reads the trail in order, marking hrefs and the leaf
- ✓decodes entities so an ampersand label can match its JSON-LD twin
- ✓ignores separators, which are list items too
- ✓counts navs and reads only real script blocks, not flight payload
✓--base scope (the CI contract)Internal scripts4
- ✓reds on Cyrillic this branch committed
- ✓reds on Cyrillic in a file that is not committed yet
- ✓ignores Cyrillic the base already carried — merge-base scope, not a whole-tree scan
- ✓ignores an extension it does not cover
✓diffReportsInternal scripts4
- ✓returns all current dead links as new when baseline is empty
- ✓returns empty new when current is subset of baseline
- ✓treats status change (404→500) as a new dead link
- ✓diffs correctly when baseline entries omit foundOn
✓renderGithubStepSummaryInternal scripts4
- ✓renders clean report when no dead links
- ✓renders dead links table
- ✓truncates long dead-link lists to 50 rows
- ✓shows ERR for errored links
✓the loud failureInternal scripts4
- ✓names every missing variable when coverage is required
- ✓names only the role that is actually missing
- ✓complains about the keys before the addresses
- ✓is silent once every role is configured
✓parseShardInternal scripts4
- ✓returns null when no shard is requested, so the caller runs the whole manifest
- ✓reads a well-formed shard
- ✓rejects a malformed value rather than silently running everything
- ✓rejects an out-of-range index
✓parseArgsInternal scripts4
- ✓defaults to the funnel when no section flag is given
- ✓parses section flags + --json
- ✓parses --property and --limit
- ✓throws on an unknown flag
✓classifyResultInternal scripts4
- ✓passes a clean 200
- ✓fails a non-200 status
- ✓fails a 200 with a soft-error body and records the match
- ✓fails a 5xx even though no body markers are present
✓buildAbsoluteUrlInternal scripts4
- ✓joins base and path
- ✓tolerates a trailing slash on the base
- ✓tolerates a path without a leading slash
- ✓preserves query strings
✓parseArgsInternal scripts4
- ✓defaults to the prod origin, ALL form factors, text output
- ✓parses --json, --url and --form-factor (case-insensitive)
- ✓throws on an invalid form factor
- ✓throws on an unknown flag
✓blockingFindingsInternal scripts4
- ✓keeps findings from blocking rules and drops everything else
- ✓returns nothing when the scan only has informational findings
- ✓returns nothing for an empty scan
- ✓collects findings across multiple SARIF runs
✓heavy-gate tiering — gated jobs (#1353/#1409)Release gates4
- ✓'lighthouse' lives in ci.yml and is tiered through its changes gate (#1409)
- ✓'pr-localhost-crawl' lives in ci.yml and is tiered through its changes gate (#1409)
- ✓the standalone performance / link-crawler workflows are gone
- ✓the chromatic workflow stays gone
✓aggregator required checks cannot skip-propagate (#1353 hardening)Release gates4
- ✓'lint-and-build' still runs when an upstream job fails
- ✓'seo-smoke' still runs when an upstream job fails
- ✓'lint-and-build' verdict checks every upstream result explicitly
- ✓'seo-smoke' verdict checks every upstream result explicitly
✓the app port is the runner's, not a constant (#3603)Release gates4
- ✓no workflow or composite action hardcodes the app port
- ✓boot-app publishes the port it chose
- ✓a dead server cannot pass the health wait on somebody else's port
- ✓the launcher opts out of -e, or it never records the exit status
✓e2e-stage waits out the Vercel build QUEUE, not just a build (#3314)Release gates4
- ✓the deploy-wait ceiling survives a queue several builds deep
- ✓the job can actually reach that ceiling before timeout-minutes kills it
- ✓the evidence steps are not blind on a timed-out run
- ✓running out of attempts still says it is a deploy problem, not a regression
✓discoverRouteTemplatesInternal scripts3
- ✓maps page files to routes and drops route groups from the URL
- ✓excludes the session-gated and developer subtrees, and the root itself
- ✓still excludes an auth route whose group is its only marker
✓extractFloorsFromSummaryInternal scripts3
- ✓maps app/ files into dir:app
- ✓tracks safety-net file paths
- ✓aggregates glob:lib/catalog/** across matched .ts/.tsx files
✓staged scope (the husky pre-commit contract)Internal scripts3
- ✓reds on a staged Cyrillic file and names it
- ✓passes a staged English file
- ✓inspects nothing on a clean tree — the vacuity that made it useless in CI (#3202)
✓parseExceptionsInternal scripts3
- ✓returns empty object for non-object input
- ✓extracts allow_404 and allow_redirect_chain arrays
- ✓filters out non-object entries
✓shouldExempt404Internal scripts3
- ✓exempts 4xx when path matches allowlist
- ✓NEVER exempts 5xx even when path matches allowlist
- ✓does not exempt 4xx when path is not in allowlist
✓.link-exceptions.json allow_404 pattern smoke testInternal scripts3
- ✓mutes representative #243 /equipment/new-holland-* URLs
- ✓does NOT mute non-NH or non-equipment 404s
- ✓does NOT mute 5xx even for muted paths (invariant: server errors always fail)
✓runMain — front#3438: the crawler must be able to see a 404 at allInternal scripts3
- ✓sends a UA that matches CRAWLER_UA_RE, or production answers 200 for every dead page
- ✓crawls a discovered link's query string instead of collapsing it onto the bare path
- ✓caps query variants per base path so a facet grid cannot starve the budget
✓timeout is slow, not dead (#3540)Internal scripts3
- ✓recognises an aborted fetch, and only that
- ✓gives the retry a wider budget than the first attempt
- ✓waits longer after a timeout than after a refusal
✓isIssueReferenceInternal scripts3
- ✓is true for a ticket id sitting in prose
- ✓is false for a hex that fills a quoted literal
- ✓is false for a letter-bearing hex, which no issue id has
✓the requirement switchInternal scripts3
- ✓is off when unset, so a local run degrades instead of failing
- ✓accepts the spellings a human writes into a CI variable
- ✓stays off for explicit negatives
✓loggingInternal scripts3
- ✓masks an address instead of printing it
- ✓says out loud which roles were skipped and why
- ✓never leaks a full address into the plan
✓shardSpecsInternal scripts3
- ✓deals round-robin so no shard gets only the slow end of the manifest
- ✓covers every spec exactly once across all shards
- ✓can hand a shard nothing when the manifest is shorter than the matrix
✓the pass count follows the project the lane selectedInternal scripts3
- ✓counts a mobile-chromium pass when the lane selected that project
- ✓would have failed that same run under the desktop default
- ✓still ignores a desktop dependency line on a mobile lane
✓row mappersInternal scripts3
- ✓toFunnelRows maps eventName + eventCount
- ✓toPurchaseRows maps itemId/itemName + qty/revenue
- ✓toTrafficRows maps channel + sessions/users
✓diffCoverageInternal scripts3
- ✓flags an indexed drop beyond the threshold
- ✓ignores a drop under the threshold
- ✓flags a canary that went un-indexed
✓buildCrawlHeaders (Vercel Deployment Protection bypass, #1491)Internal scripts3
- ✓sends only the user-agent when no bypass secret is set
- ✓adds x-vercel-protection-bypass when VERCEL_AUTOMATION_BYPASS_SECRET is set
- ✓ignores an empty bypass secret (anonymous crawl unchanged)
✓toMetricResultInternal scripts3
- ✓maps p75 + first-bucket density and rates it
- ✓coerces a string p75 (API sometimes returns strings)
- ✓returns null when the metric / p75 is absent
✓parseCruxResponseInternal scripts3
- ✓extracts the three CWV, the key and the collection period
- ✓omits metrics the dataset did not return and tolerates a missing period
- ✓yields an empty report for an empty body (no record)
✓blockingRuleIdsInternal scripts3
- ✓returns only ERROR-severity rule ids
- ✓returns an empty set for a file with no rules
- ✓ignores rules without an id or severity
✓parseArgsInternal scripts3
- ✓defaults to the prod site, text output
- ✓parses --json and --site
- ✓throws on an unknown flag
✓vercelBypassHeadersInternal scripts3
- ✓sends the bypass header when the secret is set
- ✓sends nothing when the secret is absent
- ✓sends nothing when the secret is an empty string
✓heavy-gate tiering — ci.yml (#1353)Release gates3
- ✓re-evaluates gates when a draft PR is marked ready (ready_for_review trigger)
- ✓'e2e-smoke' run-decision is tiered through the changes gate
- ✓'seo-smoke-matrix' run-decision is tiered through the changes gate
✓build-once — every consumer boots the build job's artifact (#1409)Release gates3
- ✓'bun run build' appears only in ci.yml/build and the scheduled lanes' own build jobs
- ✓'lighthouse' boots the artifact (no from-artifact opt-out)
- ✓'pr-localhost-crawl' boots the artifact (no from-artifact opt-out)
✓setup module — bun version + caches pinned in one place (#1408 C3)Release gates3
- ✓setup-bun-app composite action exists and pins the bun version
- ✓ci.yml: jobs use the setup module, never inline setup-bun
- ✓pr-soft-404-crawler.yml: jobs use the setup module, never inline setup-bun
✓sitemap-seo-gate survives a cold search-api (#3676)Release gates3
- ✓retries its search-api calls instead of giving up on the first cold start
- ✓never calls search-api with a ceiling under the measured cold start
- ✓does not report an unreachable backend as a collapsed indexable set
✓next.config.ts — Ferris ARI image host allowlist (front#1397)Our own safety nets2
- ✓adds cdn.datamanager.arinet.com to images.remotePatterns with /image/** path
- ✓adds cdn.datamanager.arinet.com to the CSP img-src directive
✓next.config.ts images.loaderFile — wired unconditionally (#3813)Our own safety nets2
- ✓declares the custom loader as a plain property, not a conditional spread
- ✓does not gate the loader on the variant-prefix flag
✓next.config.ts images.formats — one format only (#3819)Our own safety nets2
- ✓declares exactly one format, and it is AVIF
- ✓does not re-add webp alongside it
✓floorPctInternal scripts2
- ✓floors weighted percentage to an integer
- ✓returns 100 when there is nothing to cover
✓findUnmatchedFileGlobTargetsInternal scripts2
- ✓flags file targets with zero istanbul rows (rename/move false-green)
- ✓returns empty when every file/glob target has at least one row
✓check-coverage-ratchet CLIInternal scripts2
- ✓exits 2 when coverage-summary.json is missing
- ✓exits 2 when a file/glob target matches zero coverage rows
✓isExemptRedirectChainInternal scripts2
- ✓matches by pattern and permits any hop count when max_hops absent
- ✓honors max_hops cap when present
✓fetchSitemapUrlsInternal scripts2
- ✓extracts <loc> entries from xml
- ✓throws on non-ok response
✓seedFromSitemapIndexInternal scripts2
- ✓expands child sitemap index entries
- ✓applies random sample cap
✓runMain — an endpoint that never answers is dead, not absentInternal scripts2
- ✓exits non-zero when the timeout is exhausted (was: silent exit 0)
- ✓stays green when the retry recovers
✓a 503 is slow, not dead (#1846)Internal scripts2
- ✓stays green when the retry recovers
- ✓still reports a 503 that survives the retry
✓stripCommentsInternal scripts2
- ✓blanks a line comment without eating its line break
- ✓keeps a block comment's newlines so line numbers survive
✓isAchromaticInternal scripts2
- ✓accepts equal rgb channels and a zero-chroma oklch
- ✓rejects a real hue
✓reporter selection stays with the configInternal scripts2
- ✓does not pass --reporter on the CLI, which would discard the config's json half
- ✓always names a project, and still defaults to chromium
✓filters (#1159 data hygiene)Internal scripts2
- ✓hostnameFilter pins hostName EXACT to the prod storefront
- ✓purchaseDimensionFilter ANDs hostname with a NOT-in test-PN list
✓orderFunnelInternal scripts2
- ✓orders to the canonical funnel and computes conversion + drop-off
- ✓treats a missing step as 0 without dividing by zero
✓mock delivery server identityInternal scripts2
- ✓names itself in /health so a probe can tell whose server answered
- ✓dies instead of yielding the port, leaving the first owner's identity intact
✓renderFailureCommentInternal scripts2
- ✓includes the failing URL, the matched substring, and curl evidence
- ✓does not list passing URLs
✓checkUrl request headers (#1491)Internal scripts2
- ✓passes the bypass header to fetch when the env var is set
- ✓stays anonymous (user-agent only) when the env var is unset
✓buildRequestBodyInternal scripts2
- ✓uses origin and always requests the three CWV metrics
- ✓prefers url over origin and includes a concrete form factor
✓rateInternal scripts2
- ✓classifies LCP at the web.dev thresholds (ms)
- ✓classifies INP and CLS at their thresholds
✓deepSpecsInternal scripts2
- ✓drops the shipping specs, which e2e-shipping runs against its mock server
- ✓drops every spec the stage and customer-flow manifests already own
✓formatFindingInternal scripts2
- ✓formats rule, file and line for jump-to-violation output
- ✓degrades gracefully when SARIF location data is missing
✓parseErrorGroupStatsInternal scripts2
- ✓sums int64-string counts across groups
- ✓treats an empty / missing array as zero
✓the lint job has a local mirror that cannot drift (#3202)Release gates2
- ✓runs every bun gate the lint job runs
- ✓gates the English-only rule in CI, not only in the husky hook
✓next.config.ts images.maximumRedirects — the remotePatterns bypass is closed (#3893)Our own safety nets1
- ✓disables redirect following outright
✓aggregateEntriesInternal scripts1
- ✓weights by statement counts, not a naive average of file pcts
✓--help stays honestInternal scripts1
- ✓documents every flag the parser accepts
✓isNonColorLineInternal scripts1
- ✓skips token references and definitions, not usages
✓clerk backend keysInternal scripts1
✓defaultDateRangeInternal scripts1
- ✓ends lagDays before today and spans windowDays
✓defaultDateRangeInternal scripts1
- ✓ends lagDays before today and spans windowDays
✓toQueryRowsInternal scripts1
- ✓maps keys[0] to query and defaults nullish metrics to 0
✓summarizeSitemapsInternal scripts1
- ✓sums submitted/indexed across content types
✓resolveCanaryUrlsInternal scripts1
- ✓joins a trailing-slash base with absolute paths
✓isIndexedStateInternal scripts1
- ✓classifies common GSC coverage states
✓buildSnapshotInternal scripts1
- ✓aggregates sitemap totals and canary states
✓buildReportInternal scripts1
- ✓counts passed and failed
✓renderStepSummaryInternal scripts1
- ✓reports counts and lists failures
✓SOFT_ERROR_BODY_SUBSTRINGSInternal scripts1
- ✓covers exactly the substrings named in the issue acceptance criteria
✓workflow shell steps are shellcheck-enforced (#1409)Release gates1
- ✓ci.yml actionlint step runs with shellcheck enabled
Automated checks395
Browser journeys15
Code exercised83.1%
What we check automatically61 groups
✓handlePartsPaginationGuard (front#936)Request routing40
- ✓on /parts
- ✓on /parts?page=1
- ✓on /parts?page=2
- ✓on /parts?page=100
- ✓on /parts?page=99&manufacturer=NHL
- ✓on /parts?manufacturer=NHL
- ✓on /parts/
- ✓on /parts/?page=10
- ✓falls through on non-numeric ?page= so nuqs can clamp to default
- ✓falls through on empty ?page= so the parser default applies
- ✓falls through on whitespace-only ?page=
- ✓does not touch the PDP leaf or non-listing sub-routes
- ✓#2766 — brand + brand×type listing roots fall through on an in-range page
- ✓ignores decimal page= because parseInt would silently truncate
- ✓on /parts?page=-1
- ✓on /parts?page=-99
- ✓on /parts?page=0
- ✓on /parts?page=201
- ✓on /parts?page=250
- ✓on /parts?page=1000
- ✓on /parts?page=1001
- ✓on /parts?page=99999
- ✓on /parts/?page=-1
- ✓on /parts/?page=99999
- ✓on /parts?page=-1&manufacturer=NHL
- ✓on /parts?page=99999&q=tractor
- ✓on /parts/brand/new-holland-agriculture?page=201
- ✓on /parts/brand/new-holland-agriculture?page=1001
- ✓on /parts/brand/new-holland-agriculture?page=14088
- ✓on /parts/brand/new-holland-agriculture?page=0
- ✓on /parts/brand/mchale/type/Balers?page=99999
- ✓rewrites to /parts-not-found instead of redirecting
- ✓404s an in-cap page past the brand's real end
- ✓lets a known in-range brand page through
- ✓404s a brand×type page past the brand's (upper-bound) real end
- ✓honors the ?pageSize= preset when deriving the real end
- ✓does not probe (or 404) a non-adapter brand — the static cap already guards NH
- ✓skips the brand-count check on a ?q= search (pageSize shrinks to 20)
- ✓does not 404 an empty (0-part) brand — mirrors the render's empty-state 200
- ✓fails open when the probe errors (transient upstream) — never a false 404
✓googlebot-cdn-parity (front#3567)Request routing32
- ✓Googlebot renders on the cacheable path: Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)
- ✓Googlebot renders on the cacheable path: Googlebot/2.1 (+http://www.google.com/bot.html)
- ✓Googlebot renders on the cacheable path: Mozilla/5.0 (Linux; Android 6.0.1; Nexus 5X Build/MMB29P) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/W.X.Y.Z Mobile Safari/537.36 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)
- ✓Googlebot renders on the cacheable path: Mozilla/5.0 (compatible; Googlebot
- ✓the rewritten UA is still greppable as Googlebot: Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)
- ✓the rewritten UA is still greppable as Googlebot: Googlebot/2.1 (+http://www.google.com/bot.html)
- ✓the rewritten UA is still greppable as Googlebot: Mozilla/5.0 (Linux; Android 6.0.1; Nexus 5X Build/MMB29P) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/W.X.Y.Z Mobile Safari/537.36 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)
- ✓the rewritten UA is still greppable as Googlebot: Mozilla/5.0 (compatible; Googlebot
- ✓leaves other UAs untouched: Mozilla/5.0 (compatible; Bingbot/2.0; +http://www.bing.com/bingbot.htm)
- ✓leaves other UAs untouched: facebookexternalhit/1.1
- ✓leaves other UAs untouched: Slackbot-LinkExpanding 1.0 (+https://api.slack.com/robots)
- ✓leaves other UAs untouched: Googlebot-Image/1.0
- ✓leaves other UAs untouched: Mozilla/5.0 (compatible; Googlebot-News; +http://www.google.com/bot.html)
- ✓leaves other UAs untouched: Googlebot-Video/1.0
- ✓leaves other UAs untouched: Mozilla/5.0 (compatible; Google-InspectionTool/1.0)
- ✓leaves other UAs untouched: AdsBot-Google (+http://www.google.com/adsbot.html)
- ✓leaves other UAs untouched: Screaming Frog SEO Spider/19.0
- ✓leaves other UAs untouched: crop-audit/1.0
- ✓leaves other UAs untouched: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 Chrome/126 Safari/537.36
- ✓leaves a UA-less request untouched
- ✓is not stateful across calls
- ✓moves Googlebot to the cacheable path on every route: /parts
- ✓moves Googlebot to the cacheable path on every route: /parts/CT-NHL-47126655
- ✓moves Googlebot to the cacheable path on every route: /equipment/new-holland-workmaster-75
- ✓moves Googlebot to the cacheable path on every route: /parts/brand/new-holland-agriculture
- ✓moves Googlebot to the cacheable path on every route: /brands
- ✓moves Googlebot to the cacheable path on every route: /parts-diagramsomething
- ✓moves Googlebot to the cacheable path on every route: /parts-diagrams/new-holland/ZZZ-NOT-A-MODEL
- ✓moves Googlebot to the cacheable path on every route: /parts-diagrams/new-holland
- ✓moves Googlebot to the cacheable path on every route: /parts-diagrams
- ✓moves Googlebot to the cacheable path on every route: /brand/zzz-not-a-brand
- ✓moves Googlebot to the cacheable path on every route: /brand
✓cdnCacheControlFor (#1734)Business rules22
- ✓/parts -> public, s-maxage=60, stale-while-revalidate=300
- ✓/parts/ -> public, s-maxage=60, stale-while-revalidate=300
- ✓/parts/CT-NHL-226428 -> public, s-maxage=300, stale-while-revalidate=600
- ✓/parts/CT-NHL-226428/ -> public, s-maxage=300, stale-while-revalidate=600
- ✓/parts/brand -> public, s-maxage=1800, stale-while-revalidate=3600
- ✓/parts/brand/new-holland -> public, s-maxage=1800, stale-while-revalidate=3600
- ✓/parts/brand/new-holland/type/filters -> public, s-maxage=1800, stale-while-revalidate=3600
- ✓/parts/category -> public, s-maxage=1800, stale-while-revalidate=3600
- ✓/parts/category/filters -> public, s-maxage=1800, stale-while-revalidate=3600
- ✓/brands -> public, s-maxage=1800, stale-while-revalidate=3600
- ✓/parts/brandish-part -> public, s-maxage=300, stale-while-revalidate=600
- ✓/parts-diagrams -> public, s-maxage=300, stale-while-revalidate=600
- ✓/parts-diagrams/models -> public, s-maxage=300, stale-while-revalidate=600
- ✓/parts-diagrams/model/new-holland-t6-145 -> public, s-maxage=1800, stale-while-revalidate=3600
- ✓/parts-diagrams/model/new-holland-t6-145/variants -> public, s-maxage=1800, stale-while-revalidate=3600
- ✓/parts-diagrams/model/new-holland-t6-145/parts-diagrams -> public, s-maxage=1800, stale-while-revalidate=3600
- ✓/parts-diagrams/model/new-holland-t6-145/parts-diagrams/059a-radiator -> public, s-maxage=300, stale-while-revalidate=600
- ✓/parts-diagrams/new-holland -> public, s-maxage=1800, stale-while-revalidate=3600
- ✓/parts-diagrams/new-holland/755b-loader -> public, s-maxage=1800, stale-while-revalidate=3600
- ✓/ -> null
- ✓/checkout/review -> null
- ✓/account/orders -> null
✓favorites-storeApp state21
- ✓starts with empty items
- ✓adds a new item
- ✓is idempotent — does not duplicate
- ✓allows same itemId in different domains
- ✓removes an existing item
- ✓does nothing for non-existent item
- ✓only removes matching domain
- ✓returns true when adding
- ✓returns false when removing
- ✓toggle cycle: add → remove → add
- ✓returns null when at limit
- ✓still allows removal when at limit
- ✓removes all items
- ✓replaces all items
- ✓returns 0 for empty store
- ✓returns correct count
- ✓returns false when not favorited
- ✓returns true when favorited
- ✓is domain-specific
- ✓returns only items for the given domain
- ✓returns empty array when no items for domain
✓handleStreamedNotFoundRequest routing15
- ✓404s a slug with no moved hub, without probing
- ✓lets a carried brand's moved hub render
- ✓ignores deeper /brand paths it does not own
- ✓ignores paths outside the viewer
- ✓404s an unroutable brand to /brand-not-found without probing
- ✓404s a type-first brand's model URL — its models live under /parts-diagrams/model
- ✓falls through for the reserved `model` brand segment
- ✓never touches the reserved `assemblies` segment
- ✓404s a model with no diagrams
- ✓404s when hono reports the model 404
- ✓lets a model with diagrams render
- ✓404s a deep leaf naming an assembly outside the model
- ✓lets a deep leaf naming a real member render
- ✓fails open on a transient upstream error, after one retry
- ✓fails open when SEARCH_SERVICE_URL is unset
✓POST /api/internal/revalidate — validationAPI endpoints13
- ✓rejects > 1000 tags with payload_too_large listing field
- ✓reports over-cap on both tags and paths when both exceed limit
- ✓returns missing_fields for empty body {}
- ✓returns missing_fields for { tags: [] }
- ✓returns invalid_body with issues[] for whitespace-only tag entries
- ✓enumerates every invalid entry in issues[] for mixed errors
- ✓rejects paths missing leading slash
- ✓rejects non-string values in tags[] (number, null, boolean)
- ✓rejects { tag: null }
- ✓rejects over-long tag (> 256 chars)
- ✓rejects over-long path (> 1024 chars)
- ✓accepts tag at exactly 256 chars (boundary)
- ✓returns invalid_json for malformed JSON body
✓recently-viewed-storeApp state11
- ✓pushes a new item to the front of the list
- ✓dedupes by id and bumps the existing entry to the front
- ✓caps persisted history at 8 entries (oldest dropped)
- ✓persists imageUrl when provided
- ✓omits imageUrl when not provided
- ✓preserves price and isQuoteOnly when set
- ✓uses Date.now() when viewedAt is omitted
- ✓wipes all items
- ✓returns at most the first 4 items
- ✓returns all items when fewer than the preview limit are stored
- ✓returns the total persisted count, not the preview-limited slice
✓backend routingAPI endpoints11
- ✓/api/users/me -> http://user.test/api/users/me
- ✓/api/v2/admin/users -> http://user.test/api/v2/admin/users
- ✓/api/v2/users/u_1 -> http://user.test/api/v2/users/u_1
- ✓/api/v2/staff/orders -> http://payment.test/api/v2/staff/orders
- ✓/api/cart/items -> http://payment.test/api/cart/items
- ✓/api/checkout/session -> http://payment.test/api/checkout/session
- ✓/api/payment/intent -> http://payment.test/api/payment/intent
- ✓/api/delivery/rates -> http://delivery.test/api/delivery/rates
- ✓/api/unknown/thing -> http://search.test/api/unknown/thing
- ✓carries the query string through to upstream
- ✓does NOT let a v2/staff path reach user-service
✓GET /api/serial/classify — hono adapterAPI endpoints11
- ✓collapses multi-candidates sharing a modelNumber to single with variantCount
- ✓returns multi when candidates have distinct modelNumbers
- ✓normalizes hono single strong match at top level
- ✓emits Cache-Control on success responses
- ✓drops unroutable null-slug candidates → no_match
- ✓degrades to format_recognized_no_match on hono 404
- ✓returns 400 when no pin and no serial provided
- ✓decode → find-model chain → collapsed single when variants share modelNumber
- ✓decode success without modelNumber/serial → degradation
- ✓decode 404 → degradation (no chain call)
- ✓decode OK but chain find-model 404 → degradation
✓probeUpstreamOnceRequest routing9
- ✓hands the decoded body to resolve and returns its verdict
- ✓arms every probe with the shared deadline
- ✓treats 404 as definitive and never decodes the body
- ✓treats 429 as transient, not as a missing resource
- ✓treats 500 as transient, not as a missing resource
- ✓treats 503 as transient, not as a missing resource
- ✓fails open when the request throws
- ✓fails open when a 200 body is not JSON
- ✓treats any 2xx as ok for a HEAD existence check, without reading a body
✓useUserProfileStoreApp state9
- ✓hydrateFromServer migrates a legacy localStorage payload then clears it
- ✓hydrateFromServer skips migration when the flag is already set
- ✓hydrateFromServer skips migration when another tab marked it in-progress
- ✓two concurrent hydrateFromServer calls only fire one server migration
- ✓addAddress writes through to the server and updates store
- ✓first added address is forced to isDefault=true
- ✓getDefaultAddress returns the row flagged as default, otherwise the first row
- ✓deleteAddress fires the action and updates the cache
- ✓setDefaultAddress fires the action and stores the new default
✓QuantityStepperInterface pieces8
- ✓increments and decrements by step
- ✓disables decrement at min and increment at max
- ✓snaps to nearest step multiple on blur (pack-aware)
- ✓sizes md and lg map to expected tap targets
- ✓strips non-digit input safely and only commits on blur
- ✓does not commit when the user blurs without changing the value
- ✓clears to empty then blurs — reverts to last committed value, no onChange
- ✓typing 0 in a min=1 stepper snaps up to 1 on blur
✓probeWithRetryRequest routing8
- ✓returns ok on the first attempt without retrying
- ✓returns not-found on the first attempt without retrying (definitive)
- ✓retries once on a transient error, then resolves with ok
- ✓retries once on a transient error, then resolves with not-found
- ✓retries exactly once then fails open (kind:error) on persistent error
- ✓emits a fail-open breadcrumb tagged by probe kind after the retry errors
- ✓does NOT emit a breadcrumb when the retry resolves to ok
- ✓swallows breadcrumb-emitter errors so telemetry never breaks the request
✓path allowlistAPI endpoints8
- ✓rejects parent traversal with 400 and never calls upstream
- ✓rejects encoded slash with 400 and never calls upstream
- ✓rejects absolute url with 400 and never calls upstream
- ✓rejects shell metachar with 400 and never calls upstream
- ✓rejects percent escape with 400 and never calls upstream
- ✓rejects a hostile segment before it even asks Clerk for a token
- ✓blocks a traversal that would re-target another backend's surface
- ✓allows the id shapes real callers use (email, dot, plus, hyphen, underscore)
✓runBackstockCheckAPI endpoints8
- ✓returns zero counts when there are no favorites documents
- ✓records new state and notifies when a part moves out_of_stock -> in_stock
- ✓does NOT notify when state was already in_stock
- ✓does NOT notify when state transitions to anything other than in_stock
- ✓skips non-parts favorite domains so equipment + tires do not trigger alerts
- ✓treats undefined lastKnownStockState as 'unknown' so the first pass does not notify
- ✓aggregates across multiple users + items
- ✓respects MAX_ITEMS_PER_RUN and reports the deferred remainder
✓normalizeUppercasePathRequest routing7
- ✓returns null for already-lowercase paths
- ✓returns null for the root path
- ✓lowercases the first segment when uppercase
- ✓preserves case in later segments (part numbers are case-sensitive)
- ✓handles mixed case first segment
- ✓returns null when a non-letter character holds uppercase position
- ✓preserves deep paths and trailing slashes
✓POST /api/internal/revalidate — authAPI endpoints7
- ✓returns 401 on wrong Bearer token
- ✓returns 401 when Authorization header is missing
- ✓returns 401 for tokens of different length
- ✓returns 401 for same-length but wrong-content token
- ✓returns 503 when REVALIDATE_SECRET is empty string
- ✓returns 503 when REVALIDATE_SECRET is fully unset (undefined)
- ✓sets Cache-Control no-store on auth failures too
✓POST /api/internal/vercel-deploy-hook — authAPI endpoints7
- ✓returns 401 when X-Vercel-Signature is missing
- ✓returns 401 on signature computed with wrong secret
- ✓returns 401 on tampered body (sig was for original)
- ✓returns 401 on shorter wrong-length signature
- ✓returns 401 sets no-store cache control
- ✓returns 503 when VERCEL_DEPLOY_HOOK_SECRET is unset
- ✓returns 503 when VERCEL_DEPLOY_HOOK_SECRET is empty string
✓applyBfcachePolicy — scope boundaries (helper must not bleed)Request routing6
- ✓does not mutate /parts/[id] PDP responses
- ✓does not mutate /parts/brand/* responses
- ✓does not mutate /parts/category/* responses
- ✓does not mutate /equipment/* responses (out of scope)
- ✓does not mutate /api/* responses (route handlers own their headers)
- ✓does not mutate /account responses (auth-protected; sign-in flow)
✓applyBfcachePolicy — defensive short-circuitsRequest routing6
- ✓preserves intentional Cache-Control: no-store on 404 rewrites (pagination guard)
- ✓never labels a 5xx /parts response public (would CDN-cache an error page)
- ✓never labels a 3xx /parts redirect public
- ✓refuses to label /parts public when response carries x-clerk-auth-status=signed-in
- ✓still labels /parts public for signed-out (or absent) clerk header
- ✓mutates a plain Response (the shape inspectForSoft404 returns)
✓createTtlCacheShared helpers6
- ✓returns undefined before any value is set
- ✓returns a set value within the TTL window
- ✓preserves falsy values (null, 0, empty string)
- ✓evicts entries after the TTL elapses
- ✓refreshes the timestamp on set so a repeat write resets the TTL
- ✓clear() removes every entry
✓/api/parts/[id]/fitment — limit param contract (front#999)API endpoints6
- ✓returns 400 when ?limit exceeds MAX_LIMIT (1000) — no silent clamp
- ✓returns 400 when ?limit is non-numeric
- ✓returns 400 when ?limit is zero or negative
- ✓returns 200 and forwards limit when within bounds
- ✓returns 200 with default limit when ?limit is absent
- ✓accepts MAX_LIMIT boundary value (limit=1000)
✓EmptyStateInterface pieces5
- ✓renders the headline, body, and icon
- ✓renders multiple actions as buttons with the first one styled as primary
- ✓invokes onClick when an action is interactive
- ✓applies the destructive icon tint when requested
- ✓renders without an actions row when none provided
✓materialiseRewrittenStatusRequest routing5
- ✓serves the rewritten body under the status the proxy set
- ✓marks its subrequest so the proxy renders it instead of re-running
- ✓leaves a 308 rewrite alone
- ✓leaves an RSC navigation on the plain rewrite
- ✓fails open when the subrequest throws or does not render
✓isAuthedPersonalRouteRequest routing5
- ✓matches /cart with or without trailing slash
- ✓matches nested /cart paths
- ✓does not match unrelated routes
- ✓no longer matches the retired /favorites route (moved to /account/garage)
- ✓does not match prefix look-alike paths that aren't exactly /cart
✓GET /api/healthAPI endpoints5
- ✓reports ok and forwards X-Cold-Start when search is healthy
- ✓defaults X-Cold-Start to false when the header is absent
- ✓stays 200 when search sheds with 429, and says so in the body
- ✓stays 200 when search is unreachable
- ✓handles a non-JSON upstream response gracefully
✓misconfiguration alarmAPI endpoints5
- ✓flags CRITICAL when the customer domain is on development Clerk keys
- ✓flags CRITICAL when a non-production site is on live Clerk keys
- ✓warns when a non-production site points at the production Clerk domain
- ✓reports no issue for the matched dev pairing
- ✓reports no issue for the matched production pairing
✓POST /api/internal/revalidate — batchAPI endpoints5
- ✓accepts batch of 10 tags, revalidateTag called 10 times
- ✓accepts batch of 5 paths
- ✓mixes legacy + batch: normalises tag into tags[] and path into paths[]
- ✓dedupes duplicate tags
- ✓emits Sentry breadcrumb with size+duration metadata (no tag/path values)
✓POST /api/internal/vercel-deploy-hook — happy pathAPI endpoints5
- ✓invalidates every umbrella tag on production deployment.succeeded
- ✓emits Sentry breadcrumb with tag count + duration (no tag values)
- ✓sets Cache-Control no-store on success response
- ✓echoes caller-supplied X-Request-Id when present
- ✓mints a UUID v4 for X-Request-Id when none provided
✓<JumpToTopFAB>Interface pieces4
- ✓is not in the DOM until scrollY exceeds the threshold
- ✓hides again once the user scrolls back above the threshold
- ✓calls window.scrollTo({ top: 0, behavior: 'smooth' }) on click
- ✓is hidden on lg+ via lg:hidden
✓StatusPillInterface pieces4
- ✓renders all 8 variants with default labels
- ✓respects the label override
- ✓applies the variant token class for each surface
- ✓forwards additional HTML attributes
✓CACHE_CONTROL bfcache presetsBusiness rules4
- ✓BFCACHE_PUBLIC is bfcache-eligible (no no-store) and instant-restore on Safari
- ✓BFCACHE_PRIVATE is bfcache-eligible and private
- ✓CDN_LISTING carries s-maxage for the edge tier and never ships no-store
- ✓does not regress existing presets that the bfcache fix layers on top of
✓isPartsPdpRequest routing4
- ✓matches single-segment part identifiers under /parts
- ✓tolerates a trailing slash on the PDP path
- ✓does not match the listing root, brand, or category
- ✓does not match deeper nested paths under a part identifier
✓StoreHydration — every persisted storeApp state4
- ✓rehydrates every persisted store on mount
- ✓rehydrates every persisted store again on a bfcache restore (event.persisted)
- ✓does not rehydrate any store on a non-persisted pageshow (guards the authed-sync clobber)
- ✓removes the pageshow listener on unmount (no rehydrate after unmount)
✓upstream failure mappingAPI endpoints4
- ✓preserves an upstream error status and its scrubbed JSON body
- ✓keeps the upstream status when a JSON-typed body is unparseable
- ✓maps an upstream timeout to 504, not 502
- ✓maps any other upstream failure to 502 without leaking the cause
✓key maskingAPI endpoints4
- ✓never returns a publishable key in full, on either key family
- ✓reports an unset key as '(not set)' rather than masking an empty string
- ✓labels the key family from its prefix
- ✓reports only the presence of the secret key, never a value
✓POST /api/internal/revalidate — /parts/ casingAPI endpoints4
- ✓lowercases a branded /parts/ path so it matches the rendered route
- ✓lowercases every branded path in a batch
- ✓leaves a /parts-diagrams/ path alone — its casing is load-bearing
- ✓leaves a non-parts path alone
✓POST /api/internal/revalidate — X-Request-Id correlationAPI endpoints4
- ✓echoes caller-supplied X-Request-Id in response header
- ✓mints a UUID v4 when X-Request-Id is absent
- ✓uses caller-supplied id in Sentry breadcrumb for correlation
- ✓echoes X-Request-Id on error responses too (401, 400)
✓POST /api/internal/vercel-deploy-hook — event-type filterAPI endpoints4
- ✓acks 200 + skipped for deployment.created without invalidating
- ✓acks 200 + skipped for deployment.canceled without invalidating
- ✓acks 200 + skipped for deployment.error without invalidating
- ✓acks 200 + skipped when type is missing entirely
✓MobileBottomBarInterface pieces3
- ✓renders cta and is hidden on lg via Tailwind class
- ✓includes safe-area-inset padding so iOS notch is respected
- ✓shows context and total row only when provided
✓StatusDotInterface pieces3
- ✓renders each variant with the expected token class
- ✓is aria-hidden by default and labelled when aria-label is provided
- ✓respects size prop
✓ToasterInterface pieces3
- ✓anchors top-left with a header-aware offset on desktop and mobile
- ✓follows the forced theme over a stale stored one
- ✓falls back to the resolved theme once the pin is removed
✓applyBfcachePolicy — anon listing root /partsRequest routing3
- ✓sets bfcache-eligible public Cache-Control + CDN-Cache-Control on /parts
- ✓applies the same headers when /parts has a trailing slash
- ✓applies the same headers when /parts has a query string
✓applyBfcachePolicy — authed personal route /cartRequest routing3
- ✓sets bfcache-eligible private Cache-Control on /cart with geo Vary
- ✓handles nested /cart paths
- ✓does not mutate the retired /favorites route (moved under /account)
✓isAnonListingRootRequest routing3
- ✓matches the bare /parts root with or without trailing slash
- ✓does not match nested /parts paths (PDP, brand, category)
- ✓does not match unrelated routes
✓isPartsBrandOrCategoryRequest routing3
- ✓matches /parts/brand and /parts/category roots and subpaths
- ✓does not match the listing root or PDPs
- ✓does not match brand look-alike segments that aren't reserved
✓StoreHydration — cart price stays in sync (customer symptom)App state3
- ✓rehydrates the cart from localStorage on mount
- ✓re-syncs the cart subtotal to localStorage on a bfcache restore
- ✓does not re-sync the cart on a normal (non-bfcache) pageshow
✓body and method passthroughAPI endpoints3
- ✓forwards a POST body and its content type
- ✓sends no body and no Content-Type on a GET
- ✓proxies a DELETE (body method) through with its method intact
✓POST /api/internal/vercel-deploy-hook — target filterAPI endpoints3
- ✓acks 200 + skipped on preview deploys (no thrash on PR previews)
- ✓acks 200 + skipped when target is missing
- ✓tolerates older payload shape with target at payload.target (defensive)
✓<PopoverContent>Interface pieces2
- ✓defaults to the scale animation with no other animate-* class
- ✓animation="spotlight" replaces the base scale animation instead of racing it (#2647)
✓QuantityStepper cap hintInterface pieces2
- ✓shows 'Only N available' while the draft exceeds max and hides after blur clamps
- ✓renders no hint for an in-range draft
✓applyBfcachePolicy — kill switch + error containmentRequest routing2
- ✓no-ops when DISABLE_BFCACHE_POLICY=1 (operator kill switch)
- ✓does not throw when headers reject mutation (caught + reported)
✓auth gateAPI endpoints2
- ✓returns 401 and calls no upstream when Clerk yields no token
- ✓forwards the caller's token as a Bearer header on the upstream call
✓price-leak scrubbingAPI endpoints2
- ✓strips wholesale keys out of a JSON upstream body
- ✓redacts leak terms embedded in a non-JSON upstream body
✓production gateAPI endpoints2
- ✓403s on Vercel production and returns no configuration at all
- ✓serves the dump on preview and marks it no-store
✓POST /api/internal/revalidate — legacy single-keyAPI endpoints2
- ✓accepts { tag } and calls revalidateTag with 'max' profile
- ✓accepts { path } and calls revalidatePath with 'page' type
✓<TooltipContent>Interface pieces1
- ✓applies z-[70] so it clears the header-search dropdown (Popover z-50)
✓CACHE_CONTROL tier presets (#1734)Business rules1
- ✓keeps the canonical tier values
✓recently-viewed-store — v1 migrationApp state1
- ✓v1 entries load without crashing and get imageUrl: undefined
✓POST /api/internal/vercel-deploy-hook — body parsingAPI endpoints1
- ✓returns 400 invalid_json on malformed body (after sig passes)
✓POST /api/internal/vercel-deploy-hook — failure surfacingAPI endpoints1
- ✓returns 500 + Sentry capture when revalidateTag throws
What we walk through in a real browser3 journeys
○Edge proxy — 308 supersession + 404 invalid slugBrowser journey8
- ○/parts/{obsolete-pn} → HTTP 308 with canonical Location + replaced_from
- ○/parts/{invalid-pn} → HTTP 404 with 'Part Not Found' body
- ○/equipment/{invalid-slug} → 308 → /parts-diagrams/model/{slug} → HTTP 404 with 'Equipment Not Found' body
- ○/parts/{regular-sellable} → HTTP 200 or 308-to-slug (no supersession redirect)
- ○/equipment/{valid-slug} → 308 → /parts-diagrams/model/{slug} → HTTP 200 (no spurious 404)
- ○/equipment/{slug}?brand=X → 308 → /parts-diagrams/model/{slug}?brand=X (query preserved) @smoke
- ○/equipment/{invalid-slug}/parts-diagrams → 308 → /parts-diagrams/model/{slug}/parts-diagrams → HTTP 404
- ○/equipment/{valid-slug}/parts-diagrams → 308 → /parts-diagrams/model/{slug}/parts-diagrams → HTTP 200 with chapters (no soft-404)
○GH #89 — legacy /parts/{model-code}/assemblies always redirectsBrowser journey4
- ○list form /parts/{UUID}/assemblies → 308 → /parts-diagrams/model/{slug}/parts-diagrams
- ○detail form /parts/{UUID}/assemblies/{asm} → 308 preserves assembly code
- ○detail form with ?highlight=N → 308 preserves the query string
- ○final destination renders assembly detail (not 'Part Not Found')
○CT-674 #298 — legacy /assemblies segment 308s to /parts-diagrams @smokeBrowser journey3
- ○listing: /equipment/{slug}/assemblies → 308 → /parts-diagrams/model/{slug}/parts-diagrams
- ○detail: /equipment/{slug}/assemblies/{code} → 308 → /parts-diagrams/model/{slug}/parts-diagrams/{code}
- ○preserves the query string
Automated checks465
Browser journeys6
Code exercised90.3%
What we check automatically123 groups
✓M2 migrated kinds — registry+sink URL is byte-identical to the legacy builderAdmin logic15
- ✓matches buildEditIssueUrl (swap with candidate)
- ✓matches buildEditIssueUrl (swap without candidate)
- ✓matches buildEditIssueUrl (reject_all)
- ✓matches buildDiagramIssueUrl (wrong_diagram)
- ✓matches buildDiagramIssueUrl (suggest_replacement)
- ✓matches buildHeroIssueUrl (swap)
- ✓matches buildHeroIssueUrl (reject_all)
- ✓matches buildTextIssueUrl (copy)
- ✓matches buildTextIssueUrl (title)
- ✓matches buildSeoIssueUrl (full)
- ✓matches buildSeoIssueUrl (empty fallbacks)
- ✓reproduces the pre-M2 inline SEO dialog body byte-for-byte
- ✓matches buildPriceIssueUrl (with reason)
- ✓matches buildPriceIssueUrl (no reason)
- ✓matches buildPriceIssueUrl (no current price)
✓sendStaffMessageActionServer actions11
- ✓rejects with reason='validation' on empty message
- ✓rejects with reason='validation' on missing orderId
- ✓rejects with reason='validation' when message exceeds 2000 chars
- ✓rejects with reason='unauthenticated' when no Clerk session
- ✓rejects with reason='unauthorized' for non-staff role
- ✓rejects with reason='order_not_found' when backend returns not-ok
- ✓rejects with reason='backend_error' when the payment service is unconfigured
- ✓rejects with reason='send_failed' and captures to Sentry when email throws
- ✓succeeds and calls sendStaffMessageEmail with correct args
- ✓fetches order with baseUrl and jwt token
- ✓does not call sendStaffMessageEmail when order fetch fails
✓StaffRowStaff tools11
- ✓renders the formatted order id, customer, and shipping summary
- ✓prefixes the shipping line with 'UPS' when shippingProvider is ups
- ✓prefixes the shipping line with 'Clinton' when shippingProvider is clinton_tractor
- ✓prefixes the shipping line with 'Clinton' for pickup orders (in-store)
- ✓omits the provider token entirely when shippingProvider is undefined
- ✓renders the total formatted without cents
- ✓links to the staff order detail using the readable orderNumber slug (#1038)
- ✓falls back to internal orderId when orderNumber is missing
- ✓respects a custom linkBase
- ✓hides the customer line when hideCustomer is true
- ✓falls back to the user email when no shipping name exists
✓honoPartIsSellableBusiness rules11
- ✓returns false for null / undefined
- ✓returns false when publishStatus is missing
- ✓returns false when publishStatus is dont_list
- ✓returns false when publishStatus is obsolete_no_supersession
- ✓returns true for sellable + available + price (the #830 case)
- ✓returns true for sellable + in_stock without explicit price
- ✓returns true for superseded_sellable + price
- ✓returns true for sellable + price even when availability is null
- ✓returns false for sellable + out_of_stock with no positive price
- ✓returns false for sellable + zero / negative price
- ✓returns true when inventoryAvailability is orderable but availability is null
✓gatewayWriteInterface pieces10
- ✓returns the parsed body on a live success
- ✓reports a live write with an unparseable body rather than throwing
- ✓falls back to demo on 404 when the caller allows it
- ✓falls back to demo on 405 when the caller allows it
- ✓falls back to demo on 501 when the caller allows it
- ✓throws the mapped message on a missing endpoint when demo is off
- ✓throws the mapped message on a real error even when demo is on
- ✓surfaces the backend's raw message for an unmapped status
- ✓falls back to demo when the network is dead and demo is allowed
- ✓propagates a dead network when demo is off
✓PricingOverrideTableInterface pieces9
- ✓renders the backend-gated demo banner
- ✓renders one row per demo override with its part number and drift badge
- ✓renders no fabricated rows and a backend-gated notice when given an empty set (prod)
- ✓exposes no wholesale or net price columns
- ✓only offers Reconcile on drifted rows (an in-sync book needs no reconcile)
- ✓applies a reconcile choice to the demo state (accept-book re-marks the new book)
- ✓clears a single override out of the demo state
- ✓accept-book on a sale-brand row serves the brand factor, not the global markup
- ✓sets a per-part override that wins outright (no markup stacking) via the edit dialog
✓admin hero edit widgetAdmin editing9
- ✓offers the hero edit trigger for an admin with the toggle on
- ✓opens a prefilled kind=hero issue with the proposed photo populated
- ✓adds a pasted URL as a selectable tile and files it as the proposed hero
- ✓shows an inline error and no tile for an invalid pasted URL
- ✓renders NO trigger in prod even for an admin with the toggle on
- ✓renders the trigger for staff
- ✓renders NO trigger for a customer
- ✓renders NO trigger when the toggle is off
- ✓renders NO trigger for an anonymous visitor
✓admin text edit widgetAdmin editing8
- ✓offers the edit-copy trigger for an admin with the toggle on
- ✓files a prefilled kind=text issue with the suggested copy
- ✓keeps Suggest disabled until the copy actually changes
- ✓renders NO trigger in prod even for an admin with the toggle on
- ✓renders the trigger for staff
- ✓renders NO trigger for a customer
- ✓renders NO trigger when the toggle is off
- ✓renders NO trigger for an anonymous visitor
✓DASHBOARD_DEMO shapeAdmin logic8
- ✓carries every dashboard section
- ✓every KPI has a value, a delta and a non-empty series
- ✓every KPI carries a valid accent token index and an icon key
- ✓exposes a header summary with a bounded rating
- ✓has revenue series for week, month and year with aligned lengths
- ✓donut segments sum to 100 with valid color indices
- ✓low-stock rows are actually below their reorder point
- ✓contains no banned pricing/brand vocabulary
✓reconcileStaffState — backend says unavailable, Hono overrideBusiness rules8
- ✓overrides to cnh_depot for the canonical #830 case (47425516)
- ✓overrides to vendor_direct when Hono signals isDfs=true
- ✓does NOT override when Hono says publishStatus=dont_list (sibling: 9624450)
- ✓does NOT override when Hono says publishStatus=obsolete_no_supersession
- ✓does NOT override when Hono is missing entirely (listing context)
- ✓does NOT override when Hono says sellable but out_of_stock + no price
- ✓overrides for call_for_pricing PNs? — no, only sellable / superseded_sellable
- ✓overrides for superseded_sellable with price
✓RefundRequestSheetStaff tools7
- ✓does not render content when closed
- ✓renders all reason radios with default amount prefilled from order total
- ✓toasts an error and skips submit when the amount is zero
- ✓toasts an error when the amount exceeds the order total
- ✓submits the selected reason + amount + trimmed notes and closes on success
- ✓surfaces alreadyPending via an info toast
- ✓surfaces a server failure as a toast error
✓isAdminEditEnabledAdmin logic7
- ✓is true for admin with toggle on, off-prod
- ✓is false when the toggle is off
- ✓is true for staff with toggle on, off-prod
- ✓is false for a customer even with toggle on
- ✓is false in prod even for an admin with toggle on
- ✓is false on stage without the explicit feature flag
- ✓is true on stage when NEXT_PUBLIC_FEATURE_DEV_MEDIA_EDIT is true
✓normalizeRoleBusiness rules7
- ✓returns 'customer' for unknown roles
- ✓returns 'customer' for non-string types
- ✓returns 'staff' / 'admin' only for exact matches
- ✓normalizes 'owner' to 'staff' (pre-launch staff-equivalent)
- ✓normalizes 'manager' to 'staff' (BI-shared Clerk, staff-equivalent)
- ✓normalizes 'viewer' to 'customer' (BI-only tier, not staff)
- ✓normalizes 'bi-viewer' to 'customer' (unknown BI-only role, no leak)
✓payload handlingAPI endpoints7
- ✓purges each requested tag under the default 'max' profile
- ✓honours an allowlisted profile
- ✓never forwards a profile outside the allowlist
- ✓400s on an empty tag list and purges nothing
- ✓400s when tags is not an array
- ✓400s on an unparseable body instead of throwing
- ✓drops whitespace-only tags and trims the rest
✓AdminEditFrame overlay gateAdmin editing6
- ✓renders the overlay trigger for an admin off-prod with the toggle on
- ✓renders NO overlay trigger for an admin while the toggle is off (default OFF)
- ✓renders the overlay trigger for staff and manager (manager normalizes to staff)
- ✓renders NO overlay trigger for a customer
- ✓renders NO overlay trigger for an anonymous visitor
- ✓renders NO overlay trigger in prod even for an admin
✓AdminEditToggleCardAdmin editing6
- ✓renders nothing for a customer
- ✓renders the switch for staff and manager (manager normalizes to staff)
- ✓renders nothing for an anonymous visitor
- ✓renders the switch OFF by default for an admin
- ✓turns the preference ON and persists it for the same user across reload
- ✓shows the switch ON when the user already enabled it
✓edit widget blocks host navigation (admin on)Admin editing6
- ✓ProductCard (image widget inside a <Link>)
- ✓TypeCard (category image widget inside a ViewSwitchLink)
- ✓BrandTile (brand-cover image widget inside a BrandTileLink)
- ✓ExplorerModelCard (taxonomy widget inside a <Link>)
- ✓AssemblyCard (diagram widget inside a <Link>)
- ✓does not block a plain host click when no widget was invoked
✓ManualStatusSheet — status chipsStaff tools6
- ✓offers only Shipped on the UPS lane
- ✓offers the delivery statuses on the Clinton Tractor lane, never Shipped
- ✓drops Out for delivery on the pickup lane — the customer collects it
- ✓disables the chip for the current status
- ✓submit button is disabled until a status is selected
- ✓submit button label updates when a status is selected
✓PrintLabelSheetStaff tools6
- ✓does not render until open is true
- ✓renders the customer address summary when open
- ✓calls createShippingLabelAction with derived service code on submit
- ✓opens the returned label URL in a new tab on success
- ✓surfaces a toast info when the backend says not_implemented
- ✓disables the primary action when the order has no shipping address
✓fetchAdminActionLogAdmin logic6
- ✓returns the coerced entries + total on the happy path
- ✓returns ok=false with 401 when the token is null (no network call)
- ✓maps an HTTP_ERROR to a graceful non-ok result with the upstream status
- ✓surfaces CANCELLED as {ok:false,status:0,errorCode:CANCELLED}
- ✓coerces a malformed payload to empty entries + zero total
- ✓forwards limit/skip/action/targetRef as query params
✓DASHBOARD_DEMO literal unions the JSON boundary widensAdmin logic6
- ✓recentOrders and salesOrders carry a known status
- ✓salesOrders carry a known channel
- ✓inventory rows carry a known stock status
- ✓overview KPIs and needs-attention rows carry a known tone
- ✓overview KPI trend colors stay inside the chart token range
- ✓revenueSeries is keyed by exactly the three time ranges
✓admin chart palette guardInterface pieces6
- ✓scans at least the known chart primitives
- ✓area-line-chart.tsx uses only the admin brand palette (no --chart-1..5 / --chart-gradient-*)
- ✓donut-chart.tsx uses only the admin brand palette (no --chart-1..5 / --chart-gradient-*)
- ✓mini-bars.tsx uses only the admin brand palette (no --chart-1..5 / --chart-gradient-*)
- ✓sparkline.tsx uses only the admin brand palette (no --chart-1..5 / --chart-gradient-*)
- ✓trend-delta.tsx uses only the admin brand palette (no --chart-1..5 / --chart-gradient-*)
✓authAPI endpoints6
- ✓500s and purges nothing when no token is configured on the server
- ✓401s on a missing Authorization header and purges nothing
- ✓401s on a wrong token and purges nothing
- ✓401s on the right token without the Bearer scheme and purges nothing
- ✓401s on an empty bearer and purges nothing
- ✓401s on a token that is only a prefix of the real one and purges nothing
✓/staff (#3871)Site pages5
- ✓renders exactly one h1 in the server shell
- ✓server-renders the dealer facts a visitor came for
- ✓carries no form and no off-site dealer links
- ✓states no company history the staff page does not carry (#3871)
- ✓keeps the title inside the 60-character SERP budget
✓StaffActionsStaff tools5
- ✓renders all action labels and sublines
- ✓renders the pre-rendered icon element inside each action button
- ✓calls onSelect when an action is clicked
- ✓applies the danger tone class to the refund action
- ✓respects the disabled state and skips onSelect
✓buildEditIssueUrlAdmin logic5
- ✓builds a prefilled issue with brand, model, current URL, and page populated
- ✓renders _none_ when the model has no current image
- ✓falls back to the model code in the headline when no display name is given
- ✓files a 'none of these fit' issue on reject_all, dropping any proposed candidate
- ✓defaults to a swap issue when no action is given
✓buildCategoryImageIssueParts (S-ADMIN-M3.5)Admin logic5
- ✓titles + bodies the category card (brand + type label + current path)
- ✓renders the placeholder marker when no category image exists yet
- ✓carries the picked candidate on a swap and drops it on reject_all
- ✓routes through the image kind terminus (media-review label, #2311 epic, appdev-v)
- ✓does NOT emit the whole-model scope line (#2365) — that's the model branch only
✓buildBrandImageIssueParts (brand flagship cover)Admin logic5
- ✓titles + bodies the brand cover (brand identity only, no model/type)
- ✓renders the accent-wash marker when no cover exists yet
- ✓carries the picked candidate on a swap and drops it on reject_all
- ✓routes through the image kind terminus (media-review label, #2311 epic, appdev-v)
- ✓does NOT emit the whole-model scope line (#2365) — that's the model branch only
✓buildGlobalCategoryImageIssueParts (global cross-brand category tile)Admin logic5
- ✓titles + bodies the global tile (label + query + current path, no brand/type)
- ✓renders the placeholder marker when no tile image exists yet
- ✓carries the picked candidate on a swap and drops it on reject_all
- ✓routes through the image kind terminus (media-review label, #2311 epic, appdev-v)
- ✓does NOT emit the whole-model scope line (#2365) — that's the model branch only
✓reconciledServedPriceAdmin logic5
- ✓accept-book drops the override and re-marks the new book price
- ✓keep-override holds the current override
- ✓reapply-pct re-applies the override's own ratio to the new book price
- ✓accept-book uses the row's BRAND factor when given (a sale brand serves the sale, not the global markup)
- ✓reapply-pct with a zero basis has no meaningful ratio and degrades to keep-override
✓recordDecisionAdmin logic5
- ✓applies a price change as an admin, emitting an edit-apply row
- ✓rejects with an edit-reject row and no two-key requirement
- ✓blocks staff from applying a price change (capability)
- ✓blocks self-approval on apply (two-key)
- ✓lets staff apply an image change (has the capability, distinct proposer)
✓canBusiness rules5
- ✓grants admin every capability
- ✓lets staff edit content but not prices or the audit log
- ✓lets staff propose a price but not apply one (two-key split)
- ✓lets admin propose a price too (admin is a superset of staff)
- ✓grants a customer nothing
✓path buildersInterface pieces5
- ✓line/smooth/area paths carry no NaN
- ✓smooth path starts with a moveto and includes curves
- ✓area path is closed with Z
- ✓empty series yield empty paths, not NaN
- ✓falls back to a straight path below 3 points
✓'fetchAdminUsers' — authedFetch failure mappingAdmin logic5
- ✓surfaces the upstream status and a string-shaped `error` body verbatim
- ✓falls back to copy naming the status when the error body is not JSON
- ✓maps a transport failure to status 500 with network copy
- ✓surfaces `message` from a `{ error: { code, message } }` body
- ✓keeps TIMEOUT distinguishable from a generic transport failure
✓'fetchAuditLog' — authedFetch failure mappingAdmin logic5
- ✓surfaces the upstream status and a string-shaped `error` body verbatim
- ✓falls back to copy naming the status when the error body is not JSON
- ✓maps a transport failure to status 500 with network copy
- ✓surfaces `message` from a `{ error: { code, message } }` body
- ✓keeps TIMEOUT distinguishable from a generic transport failure
✓'fetchAdminActionLog' — authedFetch failure mappingAdmin logic5
- ✓surfaces the upstream status and a string-shaped `error` body verbatim
- ✓falls back to copy naming the status when the error body is not JSON
- ✓maps a transport failure to status 500 with network copy
- ✓surfaces `message` from a `{ error: { code, message } }` body
- ✓keeps TIMEOUT distinguishable from a generic transport failure
✓'postAdminActionLog' — authedFetch failure mappingAdmin logic5
- ✓surfaces the upstream status and a string-shaped `error` body verbatim
- ✓falls back to copy naming the status when the error body is not JSON
- ✓maps a transport failure to status 500 with network copy
- ✓surfaces `message` from a `{ error: { code, message } }` body
- ✓keeps TIMEOUT distinguishable from a generic transport failure
✓'fetchStaffOrders' — authedFetch failure mappingAdmin logic5
- ✓surfaces the upstream status and a string-shaped `error` body verbatim
- ✓falls back to copy naming the status when the error body is not JSON
- ✓maps a transport failure to status 500 with network copy
- ✓surfaces `message` from a `{ error: { code, message } }` body
- ✓keeps TIMEOUT distinguishable from a generic transport failure
✓'fetchStaffOrderDetail' — authedFetch failure mappingAdmin logic5
- ✓surfaces the upstream status and a string-shaped `error` body verbatim
- ✓falls back to copy naming the status when the error body is not JSON
- ✓maps a transport failure to status 500 with network copy
- ✓surfaces `message` from a `{ error: { code, message } }` body
- ✓keeps TIMEOUT distinguishable from a generic transport failure
✓POST /api/admin-edit/proposal (propose)API endpoints5
- ✓lets staff propose a price with capability 'propose-price' (202)
- ✓lets an admin propose a price too (202, one-admin bootstrap)
- ✓forbids a customer proposing a price (403)
- ✓hard-blocks prod (403)
- ✓rejects a malformed body (400)
✓PATCH /api/admin-edit/proposal (approve + apply)API endpoints5
- ✓forbids when the approver equals the proposer (two-key boundary, 403)
- ✓forbids a staff approving a price change (lacks edit-price, 403)
- ✓lets an admin approve + apply a price change (202)
- ✓hard-blocks prod (403)
- ✓rejects a malformed body (400)
✓UserManagementTable — manager (BI-shared Clerk) roleInterface pieces4
- ✓displays a manager user with a Manager badge (not coerced to Customer)
- ✓does not silently coerce a manager: no Save affordance until an explicit change
- ✓disables the role picker on the current admin's own row (self-exclusion)
- ✓PATCHes the new role when an admin promotes a manager to staff
✓InternalNoteStaff tools4
- ✓renders the author, timestamp, and body
- ✓colors the left border per role
- ✓renders raw iso for an invalid timestamp without throwing
- ✓preserves whitespace in the body (whitespace-pre-wrap)
✓StaffStripStaff tools4
- ✓renders all 3 tiles with values and labels
- ✓uses the warn tone styling for the backorder tile
- ✓renders tiles as links when href is set
- ✓renders tiles as plain divs when no href is provided
✓buildPriceIssueParts (in-place PDP price proposal)Admin logic4
- ✓titles + bodies the price proposal (customer price + proposed + reason)
- ✓renders _none_ for no current price and _(unspecified)_ for an empty proposal
- ✓carries NO wholesale / dealer / net term anywhere in the issue (price-leak guard)
- ✓routes through the price kind terminus (price-review label, #2311 epic, appdev-v)
✓store request idAdmin logic4
- ✓round-trips kind + modelCode through the synthesized id
- ✓preserves a modelCode that itself contains a colon
- ✓round-trips a free-text searchQuery key (spaces + commas) for a global-category surface
- ✓returns null for a non-store id
✓toChangeRequestAdmin logic4
- ✓adapts an image pick into a pending image request keyed by the store id
- ✓adapts a category pick into a category request with its label
- ✓adapts a diagram pick into a diagram request that gates on edit-diagram (not edit-image)
- ✓routes price / seo store rows to their own kind + capability
✓validationAdmin logic4
- ✓accepts a well-formed email
- ✓rejects malformed emails
- ✓flags missing name and invalid email
- ✓passes clean input
✓optimistic list transformsAdmin logic4
- ✓buildDemoUser splits the name and derives clintonTractorClient from the domain
- ✓appendUser prepends the new user
- ✓applyUserEdit updates only the matching row
- ✓removeUserFromList drops only the matching row
✓readBackendErrorMessageBusiness rules4
- ✓reads the payment-service `{ error: { code, message } }` shape (#1807)
- ✓reads the user-service flat `{ error: string }` shape
- ✓falls back when `error` is an object without a message
- ✓falls back on a non-JSON body (gateway HTML, empty 502)
✓capabilityToRoleNamesBusiness rules4
- ✓restricts price and audit to admin only
- ✓allows admin and staff for content edits, admin first
- ✓allows both admin and staff to propose a price
- ✓mirrors can() exactly
✓reconcileStaffState — backend agrees, no overrideBusiness rules4
- ✓keeps clinton_local even when Hono is missing
- ✓keeps clinton_local even when Hono says out_of_stock — local stock wins
- ✓keeps cnh_depot when backend already says sellable from depot
- ✓keeps vendor_direct when backend already routes via supplier
✓donutArcsInterface pieces4
- ✓emits one arc per segment
- ✓every arc path is finite and preserves label + color
- ✓sets the large-arc flag for a segment over 50%
- ✓normalises when values do not sum to 100
✓unwrapUserBodyInterface pieces4
- ✓returns a raw user body untouched
- ✓unwraps a `{ data }` envelope
- ✓keeps the envelope when `data` is explicitly undefined
- ✓passes null and primitives through
✓coerceUsersResponseInterface pieces4
- ✓reads a raw payload
- ✓reads a `{ data }`-wrapped payload
- ✓falls back to the envelope when `data` is null
- ✓renders an empty grid rather than crashing on a partial payload
✓WIDGET_REGISTRYAdmin logic4
- ✓has one entry per kind, each with epic/label/caption/sink/capability
- ✓carries plain-English review labels matching the routing map
- ✓is the single source getAdminEditRouting reads (no duplicate map)
- ✓exposes capabilities as plain product English (edit-* names)
✓/api/admin-edit/coverageAPI endpoints4
- ✓returns 403 { available:false } for a non-staff caller
- ✓returns { available:false } gracefully when the token env is unset (no throw)
- ✓counts OPEN media-review + diagram-review issues (deduped) with a token
- ✓falls back to { available:false } if the GitHub query fails (no throw)
✓StaffMessageEmailInternal admin tools3
- ✓renders a snapshot of the staff-message email
- ✓greets the customer and links to the order
- ✓escapes special characters in the body exactly once
✓PricingOverridesPanel (lifted drift state)Interface pieces3
- ✓seeds the banner + drift KPI from the live rows
- ✓recomputes the banner + drift KPI live after an admin reconciles a row
- ✓drops the drift banner once every row is reconciled/cleared
✓UserManagementTable — self-role-change is blocked (regression pins)Interface pieces3
- ✓locks the role picker when editing self and never demotes the admin's own role
- ✓blocks the guard when edit is asked to change the admin's own role (no mutation)
- ✓disables the inline role Save and picker on self (guard-backed, not UI-only)
✓non-pointer close leaves the next host click free to navigateAdmin editing3
- ✓Escape close → subsequent host click navigates (not blocked)
- ✓X-button close → subsequent host click navigates (not blocked)
- ✓filing an issue does not arm the guard → subsequent host click navigates
✓AddNoteSheetStaff tools3
- ✓submits the trimmed note through the server action and closes
- ✓keeps the sheet open and toasts the backend error on failure
- ✓disables Save while the note is empty
✓ManualStatusSheet — dispatchStaff tools3
- ✓dispatches the action exactly once per click with trimmed args, then closes
- ✓omits the note when left blank
- ✓toasts the server error and keeps the sheet open on failure
✓readAdminEditToggleAdmin logic3
- ✓defaults OFF when the per-user preference is absent
- ✓is OFF for any non-true stored value (defence-in-depth)
- ✓is ON only when the per-user preference is exactly true
✓getAdminEditRoutingAdmin logic3
- ✓routes every kind to the media epic #2311
- ✓maps each kind to its review label
- ✓gives diagram and text their own review labels distinct from media
✓postAdminActionLogAdmin logic3
- ✓POSTs the entry and reports persisted=true on the happy path
- ✓returns ok=false with 401 when the token is null (no network call)
- ✓maps an HTTP_ERROR to a graceful persisted=false result
✓withAdminAuditAdmin logic3
- ✓gates on the capability BEFORE running the mutation
- ✓runs the mutation and returns a born-audited entry
- ✓skips the capability gate for a role-change (null capability)
✓previewBrandServedPrice (group edit)Admin logic3
- ✓applies a brand promo factor to a book list (all-McHale-sale flow)
- ✓applies a positive markup factor to the list
- ✓changing the factor changes the served preview for that brand
✓splitNameForRequestAdmin logic3
- ✓splits a multi-part name into first / last
- ✓returns nulls for an empty name
- ✓keeps lastName null for a single token
✓buildUserFromResponseAdmin logic3
- ✓seeds the optimistic row from the live response id (not a demo placeholder)
- ✓falls back to form input for fields the response omits
- ✓returns null when the body carries no usable clerkId
✓reconcileStaffState — hint string contractBusiness rules3
- ✓cnh_depot override mints the canonical channel + lead-time hints
- ✓vendor_direct override mints the canonical channel + lead-time hints
- ✓unchanged backend state keeps the backend's hint strings verbatim
✓seriesToPointsInterface pieces3
- ✓spreads points evenly across the width
- ✓centers a single point and never divides by zero
- ✓survives a flat series (max === min)
✓buildQueryStringInterface pieces3
- ✓returns an empty string when nothing survives filtering
- ✓drops undefined and empty values but keeps a zero
- ✓encodes values
✓mapErrorMessageInterface pieces3
- ✓maps the statuses the admin console has copy for
- ✓prefers the mapped copy over the backend's raw message
- ✓falls back to the raw message, then to a generic one
✓taxonomy reference migration — byte-identicalAdmin logic3
- ✓produces the exact URL the pre-M1 direct buildKindedIssueUrl call produced
- ✓keeps the empty-input fallbacks byte-identical (_unknown_ / _(unspecified)_ / _none_)
- ✓preserves the accessible trigger caption (parity with the frame)
✓admin-widget-gate-null.regressionAdmin logic3
- ✓is null in prod for admin with toggle on
- ✓is null for a customer on dev with toggle on
- ✓is null for admin when toggle is off
✓UserManagementTable — add userInterface pieces2
- ✓validates the form and does not create when fields are invalid
- ✓appends a valid user to the grid (demo fallback)
✓UserManagementTable — remove user + self-exclusionInterface pieces2
- ✓removes a user from the grid after confirming
- ✓hides the Remove action on the current admin's own row (self-exclusion)
✓ManualStatusSheet — state resetStaff tools2
- ✓resets the selection to none when the sheet is reopened
- ✓resets when reused for a different order while open
✓assertCapabilityAdmin logic2
- ✓passes when the role holds the capability
- ✓throws when the role lacks the capability
✓assertDistinctApprover (two-key)Admin logic2
- ✓rejects self-approval
- ✓allows a different approver
✓computeServedPriceAdmin logic2
- ✓returns the override when present (final, markup never stacks)
- ✓applies the markup factor when there is no override
✓isDriftedAdmin logic2
- ✓flags a row whose book has moved off its basis
- ✓compares at cent precision — sub-cent noise is not drift
✓factorToPct / pctToFactorAdmin logic2
- ✓maps a factor to a signed whole-number percent
- ✓round-trips a percent back to a factor
✓setOverride (individual edit)Admin logic2
- ✓sets the override to the exact price and pins the basis to the current book
- ✓the override wins outright — the served price never stacks the markup on it
✓reconcileOverride (individual edit)Admin logic2
- ✓folds the chosen served price back in as a new in-sync override
- ✓threads the row's brand factor through accept-book so the folded override matches the promo
✓isEndpointMissingAdmin logic2
- ✓treats 404 / 405 / 501 as missing endpoints
- ✓does not treat real errors as missing endpoints
✓self-exclusion guardsAdmin logic2
- ✓isSelfMutation flags the acting admin's own row
- ✓isSelfRoleChange blocks a role change on self but allows same-role self edits
✓isStaffRoleBusiness rules2
- ✓treats both staff and admin as staff (admin is a superset of staff)
- ✓does not treat customer as staff
✓roundInterface pieces2
- ✓normalises non-finite input to 0
- ✓rounds to 2dp
✓domainOfInterface pieces2
- ✓includes zero and pads the top
- ✓handles an empty input
✓DonutChartInterface pieces2
- ✓renders one arc path per segment plus a legend row each
- ✓derives a percent headline from the largest segment
✓TrendDeltaInterface pieces2
- ✓shows an up caret and success surface for a positive delta
- ✓shows a down caret and destructive surface for a negative delta
✓removeUserRequestInterface pieces2
- ✓sends DELETE to the user's own path
- ✓treats a 404 as a demo removal in preview builds
✓buildHeroIssueUrlAdmin logic2
- ✓routes a hero swap to the media epic + media-review label (kind=hero)
- ✓builds a reject-all hero issue
✓admin-widget-candidate-engine.regressionAdmin logic2
- ✓maps a Custom Search response shape to media candidates
- ✓returns empty shelf for empty CSE results (demo fallback path)
✓buildTextIssueUrlAdmin logic2
- ✓routes a copy revision to the content-review label (kind=text)
- ✓renders _empty_ when the surface has no current copy, and handles a title field
✓admin/api request shape pin — fetchAdminUsersAdmin logic2
- ✓calls fetch with GET + Bearer + JSON + AbortSignal + no-store
- ✓returns errorMessage WITHOUT calling fetch when token is null
✓admin/api request shape pin — fetchAuditLogAdmin logic2
- ✓calls fetch with GET + Bearer + JSON + AbortSignal + no-store
- ✓returns errorMessage WITHOUT calling fetch when token is null
✓admin/staff-orders-api request shape pin — fetchStaffOrdersAdmin logic2
- ✓calls fetch with GET + Bearer + JSON + AbortSignal + no-store
- ✓returns errorMessage WITHOUT calling fetch when token is null
✓admin/staff-orders-api request shape pin — fetchStaffOrderDetailAdmin logic2
- ✓calls fetch with GET + Bearer + JSON + AbortSignal + no-store + encoded id
- ✓returns errorMessage WITHOUT calling fetch when token is null
✓UserManagementTable — edit userInterface pieces1
- ✓updates the user's email in the grid
✓UserManagementTable — live add seeds from the responseInterface pieces1
- ✓appends the row using the live response clerkId (not a demo_user_* id)
✓UserManagementTable — mapped error copyInterface pieces1
- ✓shows friendly mapped copy when remove returns 409 (last admin)
✓the synchronous dismiss ghost-click is still blockedAdmin editing1
- ✓a host click firing synchronously with the arm does not navigate
✓isAdminEditEnvEnabledAdmin logic1
- ✓is true on dev or when the feature flag is true
✓isProdHardBlockedAdmin logic1
- ✓blocks only when app env is prod
✓MISSING_LABEL_BOOTSTRAP_COMMANDSAdmin logic1
- ✓documents the gh label create commands for taxonomy, seo, and price
✓capabilityForKindAdmin logic1
- ✓maps each review-queue kind to its capability
✓isDemoEnvAdmin logic1
- ✓is true only when the app env is dev
✓impliedMarkupPctAdmin logic1
- ✓recovers the override's percent over its basis
✓summarizeChangeAdmin logic1
- ✓renders a price transition and an image swap
✓sendStaffMessageEmail — HTML encodingBusiness rules1
- ✓escapes special characters exactly once (no double encoding)
✓getStaffRole — error pathBusiness rules1
- ✓returns 'customer' when currentUser() throws (no auth context)
✓SparklineInterface pieces1
- ✓renders an svg path with no NaN
✓MiniBarsInterface pieces1
- ✓renders one rect per value
✓AreaLineChartInterface pieces1
- ✓renders one line path per series plus a gradient for the area series
✓createUserRequestInterface pieces1
- ✓POSTs a split name and a trimmed email
✓editUserRequestInterface pieces1
- ✓sends PATCH to the user's own path
✓IssueUrlSinkAdmin logic1
- ✓delegates to buildKindedIssueUrl byte-for-byte
✓admin-widget-coverage-metric.regressionAdmin logic1
- ✓computes a consistent N / (M − N) for the McHale demo shelf
✓admin-widget-issue-url-shape.regressionAdmin logic1
- ✓carries media-review label, assignee, and aligned table without template=
✓admin-widget-kind-label-map.regressionAdmin logic1
- ✓maps each kept kind to its review label
What we walk through in a real browser3 journeys
○Staff — Refund request drawer (mobile)Browser journey3
- ○opens the refund drawer when the staff member taps Request refund
- ○submits a valid refund and surfaces the success toast
- ○blocks submit when the amount is missing
○Staff — Print label sheet (mobile)Browser journey2
- ○opens the print-label drawer with default switch on
- ○disables the CTA when the order has no shipping address
○admin revalidate endpointBrowser journey1
- ○accepts valid revalidation requests
Automated checks319
Browser journeys15
Code exercised70.4%
What we check automatically50 groups
✓zipToStateBusiness rules22
- ✓resolves Clinton NY (14424) to NY
- ✓resolves NYC ZIPs (10001) to NY
- ✓resolves LA (90210) to CA
- ✓resolves Boston (02101) to MA
- ✓resolves Miami (33101) to FL
- ✓resolves Seattle (98101) to WA
- ✓resolves Anchorage (99501) to AK
- ✓resolves Honolulu (96813) to HI
- ✓resolves DC (20001) to DC
- ✓accepts ZIP+4 format (14424-1234)
- ✓strips non-digits before lookup
- ✓returns null for too-short input
- ✓returns null for unknown prefix (e.g. Caribbean 005)
- ✓returns null for empty input
- ✓resolves Sterling VA (20164) to VA
- ✓resolves Dulles VA (20166) to VA
- ✓keeps DC (20001) on 200 prefix
- ✓keeps DC (20201) on 202 prefix
- ✓returns null for USPS-reserved 213 prefix
- ✓returns null for USPS-reserved 269 prefix
- ✓returns null for USPS-reserved 353 prefix
- ✓returns null for USPS-reserved 854 prefix
✓source-markerBusiness rules20
- ✓returns the environment from env config
- ✓returns CROP marker with environment
- ✓returns false for undefined
- ✓returns false for empty string
- ✓returns false for string without CROP marker
- ✓returns true for CROP-dev marker
- ✓returns true for CROP-stage marker
- ✓returns true for CROP-prod marker
- ✓returns true for CROP-unknown marker
- ✓returns false for CROP marker in middle of string
- ✓returns just marker when no orderId provided
- ✓returns marker with orderId when provided
- ✓does not double-mark if already has CROP marker
- ✓preserves different environment markers
- ✓returns just marker when no instructions provided
- ✓returns marker with instructions when provided
- ✓does not double-mark if already has CROP marker
- ✓handles empty string as no instructions
- ✓prevents double marking when called twice on reference
- ✓prevents double marking when called twice on instructions
✓zipToState — continental boundary casesBusiness rules14
- ✓returns 'AK' for 99501 (Anchorage AK)
- ✓returns 'AK' for 99701 (Fairbanks AK)
- ✓returns 'AK' for 99801 (Juneau AK)
- ✓returns 'AK' for 99901 (Ketchikan AK)
- ✓returns 'AK' for 99950 (AK upper edge)
- ✓returns 'HI' for 96701 (Aiea HI)
- ✓returns 'HI' for 96813 (Honolulu HI)
- ✓returns 'HI' for 96720 (Hilo HI)
- ✓returns 'HI' for 96732 (Kahului HI)
- ✓returns 'HI' for 96768 (Makawao HI)
- ✓returns null for non-continental Caribbean 00601 (PR 006)
- ✓returns null for non-continental Caribbean 00701 (PR 007)
- ✓returns null for non-continental Caribbean 00801 (USVI 008)
- ✓returns null for non-continental Caribbean 00901 (PR 009)
✓getRateEstimateForZipBusiness rules13
- ✓returns null when DELIVERY_API_URL is empty (defensive guard)
- ✓returns null on empty cart
- ✓returns null on too-short ZIP
- ✓returns null when ZIP prefix maps to no state (Caribbean 005)
- ✓hides estimate (returns null) when UPS returns zero rates
- ✓returns lowest/highest cost + transit min/max + state on success
- ✓falls back to 2-5 transit days when no estimated_days returned
- ✓returns null on UPS error (silent hide)
- ✓strips non-digits from ZIP and slices to 5
- ✓passes is_guest=true to the delivery client (estimate is always guest-tier)
- ✓marks the destination with [estimate] sentinel for instrumentation filtering
- ✓populates lines[] with shippingPath when cart items carry the field
- ✓legacy cart items without shippingPath produce lines[] entries with no shippingPath key
✓useUserZipProduct features12
- ✓returns Clinton fallback when no localStorage and no initialZip
- ✓returns initialZip when provided and no persisted value
- ✓prefers persisted localStorage value over initialZip (user choice beats IP-geo)
- ✓does NOT auto-persist initialZip — IP-geo is a guess, not a user choice (B2)
- ✓setZip cleans non-digits, slices to 5, and persists with timestamp
- ✓setZip rejects too-short input without persisting
- ✓expires persisted ZIP after 7-day TTL and clears entry
- ✓survives malformed JSON in localStorage gracefully
- ✓rejects 6-digit non-US postal initialZip and falls back to 14424 (front#533)
- ✓rejects alphanumeric initialZip (e.g. UK SW1A1) and falls back to 14424
- ✓rejects ZIP+4 form initialZip and falls back to 14424
- ✓rejects persisted localStorage value with non-5-digit zip
✓isFreeShipEligible — John 2026-05-18 7-lane spec (front#960)Shipping rules12
- ✓ELIGIBLE — single light line at exactly $75 (threshold boundary, inclusive)
- ✓ELIGIBLE — single light line well above threshold
- ✓ELIGIBLE — John's $104.40 knife-blade cart (4 cnh-overnight pack lines)
- ✓ELIGIBLE — pack-qty line with shippingPath=dfs-ground above threshold
- ✓ELIGIBLE — pack-qty line with shippingPath=dis-stock above threshold
- ✓INELIGIBLE below-threshold — $50 cart with light non-heavy line
- ✓INELIGIBLE below-threshold — $74.99 cart (just under boundary)
- ✓INELIGIBLE heavy-or-oversize — heavy line at $200 subtotal still blocked
- ✓INELIGIBLE heavy-or-oversize — heavy line at $30 subtotal (heavy wins over threshold)
- ✓INELIGIBLE heavy-or-oversize — heavy line carried as branded SKU (CT-NHL-)
- ✓INELIGIBLE heavy-or-oversize — heavy line carried as pack-alias SKU (-PK10)
- ✓ELIGIBLE — mix of singles + non-stocked packs above threshold
✓validateAddressAction — catch ladderServer actions11
- ✓validation error with no details → the generic prefix, canContinue=false
- ✓validation error names each bad field, in fixed order
- ✓validation error on a single field names only that field
- ✓PINNED, NOT ENDORSED: details for an unrecognised field degrade to the bare prefix
- ✓timeout → canContinue=true
- ✓api 5xx → UPS-unavailable copy, canContinue=true
- ✓api 500 boundary takes the 5xx arm
- ✓api 4xx → format-check copy, canContinue=true
- ✓PINNED, NOT ENDORSED: a plain DeliveryServiceError loses its message here
- ✓unknown error → network copy, canContinue=true
- ✓PINNED, NOT ENDORSED: no failure arm ever sets rateCost, though #1063 types it
✓updateDeliveryStatusActionServer actions11
- ✓returns validation failure for empty input
- ✓rejects shipped, which belongs to the UPS lane
- ✓rejects a scheduled date that is not YYYY-MM-DD
- ✓returns unauthenticated when no Clerk session
- ✓returns unauthorized when the caller is a customer
- ✓PATCHes the status endpoint with the scheduled date and revalidates all three paths
- ✓returns backend_error when the payment service is not configured
- ✓returns backend_error when the fetch itself throws
- ✓surfaces a nested backend error message
- ✓surfaces a flat string backend error
- ✓falls back to the status code when the body carries no message
✓deriveShippingPath (PG-only, front#598 / ct-3184)Shipping rules11
- ✓Rule 1 — isDfs=true wins outright (even with clintonInStock + in_stock)
- ✓Rule 2 — clintonInStock=true (non-DFS) routes to dis-stock
- ✓Rule 3 — availability=in_stock, not Clinton, not DFS → cnh-overnight
- ✓DIS wins over CNH depot stock — clintonInStock takes precedence over availability
- ✓Rule 4 — all signals undefined falls through to unknown
- ✓availability=available (orderable, depot-empty — the #708 cohort) routes to unknown, not cnh-overnight
- ✓availability=out_of_stock routes to unknown — no premature CNH promise
- ✓availability=low_stock routes to unknown — depot YELLOW is a DFS channel, not air-eligible
- ✓in_stock but requiresTruck downgrades to unknown (no air lane for freight)
- ✓in_stock but isHazardous downgrades to unknown
- ✓in_stock but unpublishable (publishStatus=dont_list) falls through to unknown
✓shipping titles enum lock (7-title contract)Shipping rules10
- ✓CANONICAL_SHIPPING_TITLES is exactly 7 entries with no duplicates
- ✓renderer emits Title 1 (Pickup Today in Clinton Store — FREE) on every scenario
- ✓renderer emits Title 2 (Clinton Tractor FREE shipping) for cart >= $75 + eligible
- ✓renderer emits Title 3 (Clinton Tractor $9 flat rate shipping) for cart < $75 + eligible
- ✓Titles 4-6 stay in the title map
- ✓Titles 4-6 reach no customer — the overnight section is not offered
- ✓renderer emits Title 7 (Call for freight pricing) for a heavy/oversize cart
- ✓every reachable canonical title is emitted somewhere by the renderer (cross-check)
- ✓no customer-facing title literal in the renderer source is outside the canonical set
- ✓below-threshold eligibility hides the FREE row without surfacing extra titles (fixture sanity)
✓getCustomerFacingRateTitle — John's 7-title verbatim mapShipping rules9
- ✓Pickup → 'Pickup Today in Clinton Store'
- ✓Pickup with a readiness window → 'Pickup in Clinton Store'
- ✓Free Shipping → 'Clinton Tractor FREE shipping'
- ✓Flat Rate → 'Clinton Tractor $9 flat rate shipping'
- ✓Clinton Next Day → 'Clinton Tractor Overnight'
- ✓UPS Next Day Air → 'UPS Overnight'
- ✓UPS 2nd Day Air → 'UPS 2-Day'
- ✓falls through to raw service_type for unmapped rates
- ✓does NOT leak mechanism words (DIS / CNH / depot / dfs) for any mapped rate
✓getDeliveryRatesAction — success pathsServer actions8
- ✓defaults to guest and sends the request the backend expects
- ✓omits `lines` entirely for an empty cart
- ✓forces is_first_order=false while the #1101 kill-switch is off
- ✓honours the caller's isFirstOrder once the kill-switch is on
- ✓attaches guestSavings for a guest with a bonus-eligible discounted rate
- ✓adds the 15% first-order line on top of the rate discount when the flag is on
- ✓omits guestSavings when nothing is bonus-eligible
- ✓never computes guestSavings for a signed-in customer
✓getDeliveryRatesAction — catch ladderServer actions8
- ✓timeout → Shipping rates request timed out. Please try again.
- ✓validation → Invalid address. Please check your shipping address.
- ✓api 5xx → Shipping service temporarily unavailable. Please try again.
- ✓api 4xx → Unable to get shipping rates. Please try again.
- ✓base delivery error → upstream said no
- ✓unknown → An unexpected error occurred. Please try again.
- ✓treats exactly 500 as the 5xx arm (boundary)
- ✓only the validation arm is non-retryable
✓isValidUSZipProduct features8
- ✓accepts a 5-digit numeric string
- ✓rejects a 4-digit numeric string
- ✓rejects a 6-digit numeric string (covers non-US postal like 550000)
- ✓rejects ZIP+4 form
- ✓rejects alphanumeric postal codes (e.g. UK)
- ✓rejects empty string
- ✓rejects undefined and null
- ✓rejects whitespace-padded 5-digit input (caller must pre-trim)
✓shouldBlockOnShippingMismatch — matrix cellsBusiness rules8
- ✓matrix: flag OFF + valid:false + cost mismatch → no block
- ✓matrix: flag OFF + valid:false + no quote → no block
- ✓matrix: flag ON + canContinue:true + cost MATCH → no block
- ✓matrix: flag ON + canContinue:true + cost MISMATCH → block
- ✓matrix: flag ON + canContinue:true + no quote (null) → no block
- ✓matrix: flag ON + canContinue:true + no quote (undefined) → no block
- ✓matrix: flag ON + canContinue:false + cost mismatch → no block (handled elsewhere)
- ✓edge: flag ON + canContinue:true + FE has no selected cost → no block
✓isCartPickupEligibleByPath — path-only launch gateShipping rules8
- ✓allows a cart where every line is on the shelf
- ✓refuses a vendor line that has to ship in first
- ✓refuses a supplier-direct line
- ✓refuses an unknown stock state (fail-open path is not a shelf promise)
- ✓refuses a legacy line carrying no shipping path
- ✓refuses a mixed cart on its worst line, not its best
- ✓does not claim an empty cart is collectable today
- ✓ignores quantity — the path-only gate does not read shelf counts
✓isShippingCostMismatch — #1063 toleranceBusiness rules7
- ✓returns true on a $94 divergence (BE 99.99 vs FE 5.99)
- ✓returns false when BE matches FE exactly
- ✓returns false within the 0.01 tolerance
- ✓returns true just outside the tolerance
- ✓returns false when beRateCost is null (transient — no quote)
- ✓returns false when beRateCost is undefined (transient — no quote)
- ✓handles negative divergence symmetrically (FE > BE)
✓resolveCartTiming — multi-source 'longest applicable' ruleShipping rules7
- ✓returns the fastest tier for a pure-dis-stock cart
- ✓returns the cnh tier for a pure-cnh-overnight cart
- ✓returns the slowest tier (6 days) for a mixed dis + dfs cart
- ✓returns 6 days for a mixed cnh + dfs cart (dfs is slowest)
- ✓returns the slowest tier (cnh, 5 days) for a mixed dis + cnh cart
- ✓returns empty string for an empty cart (caller suppresses badge)
- ✓falls back to the conservative 6-day window when every line is unknown
✓<ShippingEstimateLine>Product features6
- ✓renders nothing when items is empty (hidden state)
- ✓shows accessible loading skeleton then resolves to estimate
- ✓hides itself when getRateEstimateForZip returns null
- ✓hides itself when getRateEstimateForZip throws
- ✓debounces rapid item-array changes into a single coalesced rate fetch (B1)
- ✓does not refetch when items array identity changes but contents are equal
✓validateAddress — single-candidate ZIP+4 auto-accept (onlyZip4Differs)Business rules6
- ✓accepts a ZIP+4 the customer did not type
- ✓does not fire when the customer already typed a ZIP+4 (it reads as a correction)
- ✓does not fire when the street also changed
- ✓does not fire when the city also changed
- ✓does not fire when the base ZIP also changed
- ✓PINNED, NOT ENDORSED: a changed state is applied with no correction notice
✓formatRateLabel — front#621 (no Custom quote tier)Business rules6
- ✓formats positive cost as currency
- ✓formats Clinton in-store pickup ($0) as 'Free — In-Store Pickup'
- ✓falls back to bare 'Free' when $0 rate is not a pickup variant
- ✓renders cost === undefined as 'Free' (defensive — backend always populates)
- ✓renders NaN cost as 'Free' (defensive)
- ✓uses non-USD currency code when present
✓generateCartHashBusiness rules6
- ✓returns 'empty' for empty cart
- ✓produces a stable hash regardless of item order
- ✓differs when quantity changes
- ✓differs when unitPrice changes (rates depend on order value)
- ✓ignores fields irrelevant to shipping cost (title, manufacturer, addedAt)
- ✓returns a non-empty string for non-empty carts
✓formatProviderShipping rules6
- ✓returns 'Clinton' for pickup
- ✓returns 'Clinton' for clinton_tractor (local label printed in-store)
- ✓returns 'UPS' for ups (case-insensitive)
- ✓returns 'FedEx' for fedex
- ✓capitalises unknown providers as best-effort fallback
- ✓returns null for undefined / null / empty string
✓trackingUrlShipping rules6
- ✓builds a UPS deep-link
- ✓builds a FedEx deep-link
- ✓URL-encodes the tracking number (defensive against odd payloads)
- ✓returns null for clinton_tractor (no external tracking page)
- ✓returns null for pickup (customer collects at store)
- ✓returns null when provider or tracking number is missing
✓isHeavyPartNumberShipping rules6
- ✓returns true for a raw PN that's on the blocklist
- ✓returns false for a PN that's not on the blocklist
- ✓strips the CT-{BRAND}- prefix before matching (branded SKU input)
- ✓strips the -PK{N} pack-alias suffix before matching
- ✓is case-insensitive (lowercase branded SKU still matches)
- ✓returns false for null / undefined / empty input (no defensive guard needed at call sites)
✓<ZipQuickForm>Product features5
- ✓renders pre-filled with initialZip
- ✓disables submit until 5 digits are entered
- ✓calls onSubmit with cleaned 5-digit ZIP
- ✓calls onCancel when cancel pressed
- ✓declares numeric inputmode and postal-code autocomplete for mobile keyboards
✓validateAddress — multi-candidate auto-selectionBusiness rules5
- ✓collapses candidates that differ only by ZIP+4 to the first one
- ✓PINNED, NOT ENDORSED: byte-identical duplicates also collapse, claiming ZIP+4 precision
- ✓keeps both candidates when they differ by more than ZIP+4
- ✓skips auto-selection while the address is ambiguous
- ✓skips auto-selection when UPS says is_valid=false
✓rate cache get/setBusiness rules5
- ✓returns null for a cache miss + increments misses metric
- ✓returns the entry on a fresh hit + increments hits metric
- ✓flags entry as stale after the SWR threshold (~half of TTL)
- ✓evicts entries beyond TTL
- ✓getCacheAge returns elapsed ms since insert
✓carrierServiceNameShipping rules5
- ✓strips the carrier prefix the delivery service puts on UPS lanes
- ✓passes an already-bare service name through untouched
- ✓leaves non-UPS service names alone
- ✓does not eat a service name that merely starts with the letters UPS
- ✓tolerates casing and padding drift from the carrier
✓deriveStockStateTimingShipping rules5
- ✓returns empty string for undefined path (caller suppresses badge)
- ✓returns the dis-stock badge for a dis-stock line
- ✓returns the cnh-overnight badge for a cnh-overnight line
- ✓returns the dfs-ground badge for a dfs-ground line
- ✓falls back to the conservative 6-day window for unknown paths
✓HeavyShippingBadgeParts pages5
- ✓renders the badge when partNumber is on the blocklist
- ✓renders the badge when the branded SKU resolves to a blocklisted PN
- ✓renders the badge for a pack-alias SKU that wraps a blocklisted PN
- ✓renders nothing when the PN is not on the blocklist
- ✓renders nothing when partNumber is null / undefined / empty
✓validateAddress — correction notice and final validityBusiness rules4
- ✓stays silent when the single candidate matches what the customer typed
- ✓PINNED, NOT ENDORSED: a shorter corrected ZIP reads as changed via startsWith
- ✓is invalid with no suggestions and no messages when UPS returns nothing
- ✓is invalid but still surfaces the single candidate when is_valid=false
✓buildRateCacheKeyBusiness rules4
- ✓formats key as rates:{zip5}:{state}:{cartHash}:{g|a}
- ✓uppercases state regardless of input casing
- ✓encodes guest vs authenticated as g/a
- ✓differs when cartHash differs (rates can change with cart contents)
✓isFreeShipEligible — boundariesShipping rules4
- ✓INELIGIBLE empty — zero-item cart with any subtotal
- ✓ELIGIBLE — single eligible item at threshold (boundary)
- ✓ELIGIBLE — 50 eligible items, $1000 subtotal (perf sanity)
- ✓collects ALL heavy offenders, not just the first
✓buildFreightQuoteHrefShipping rules4
- ✓encodes a single-PN cart with all context keys
- ✓pipe-joins multiple cart lines under the items key
- ✓omits optional zip + reason gracefully
- ✓prefers sku over partNumber when both present (alias surfaces in items)
✓sanitizeIPGeoZipProduct features3
- ✓returns the value unchanged for a valid 5-digit ZIP
- ✓returns undefined for a non-5-digit value
- ✓returns undefined for null/undefined input
✓rate cache lifecycleBusiness rules3
- ✓deleteCachedRates removes a single entry
- ✓clearRateCache empties the cache + leaves metrics retrievable
- ✓resetCacheMetrics zeroes all counters
✓SHIPPING_HELP_CONTACT — fallback CTABusiness rules3
- ✓uses the support@clintontractor.net mailbox
- ✓phone number is in E.164 format for tel: links
- ✓phone display matches the E.164 phone
✓zip-prefix-to-state.jsonBusiness rules3
- ✓maps a plausible number of prefixes
- ✓keys are all 3-digit prefixes
- ✓values are all real US state codes
✓validateAddressAction — success pathsServer actions2
- ✓returns valid with neither suggestions nor messages when the API sends neither
- ✓passes suggestions and messages straight through
✓DeliveryStatusSheet — state resetStaff tools2
- ✓resets the selection to the first option when the sheet is reopened
- ✓resets the selection when reused for a different order while open
✓<PdpShippingEstimate>Product features2
- ✓renders nothing for a non-positive unit price
- ✓reserves the two-line height on the single-column PDP (min-h-11 lg:min-h-0)
✓validateAddress — UPS candidate mappingBusiness rules2
- ✓title-cases the UPS candidate and carries the original's contact fields over
- ✓joins PostcodeExtendedLow onto the primary as ZIP+4
✓validateAddress — no_candidates_indicator armBusiness rules2
- ✓returns not-found and discards any candidates that came with it
- ✓does not fire when the indicator is absent (normalized to null)
✓validateAddress — response-shape routingBusiness rules2
- ✓reads the backend's camelCase UPS payload
- ✓falls back to the simple format, keeping the address only when valid
✓cartItemsToLineRefs (front#598)Business rules2
- ✓returns undefined for empty cart so /rates payload omits lines
- ✓preserves shippingPath when present, omits when absent
✓flatRateUsdShipping rules2
- ✓returns the $9 default for every vendor today (no overrides configured)
- ✓returns the default for missing/empty vendor codes
✓HEAVY_PN_BLOCKLISTShipping rules2
- ✓carries the whole PG seed, not a truncated head of it
- ✓is a Set of uppercased seed PNs
✓getCustomerFacingRateTitle — carrier-prefixed service names (real wire form)Shipping rules1
- ✓maps prefixed UPS lanes to the verbatim titles
✓STOCK_STATE_TIMING — John's verbatim per-state timing badgeShipping rules1
- ✓matches John's 2026-05-18 spec exactly (no paraphrase)
What we walk through in a real browser11 journeys
○Shipping uc12 local tiersBrowser journey3
- ○UC-D-12a — free Clinton Tractor pickup (blocked on R9 mock-server)
- ○UC-D-12b — standard local <50mi (blocked on R9 mock-server)
- ○UC-D-12c — premium $150 2-day (blocked on R9 mock-server)
○UC-D-15 — continental-US-only at /checkout/shipping (#491)Browser journey3
- ○AK is not selectable in the state dropdown
- ○AK ZIP 99501 entered manually surfaces the continental-only error
- ○PR ZIP 00601 entered manually surfaces the continental-only error
○Shipping uc10 no candidatesBrowser journey1
- ○UC-D-10 — UPS no-candidates path (mock-delivery)
○Shipping uc13 freightBrowser journey1
- ○UC-D-13 — heavy/freight cart surfaces the freight CTA only (mock-delivery)
○Shipping uc14 hazmatBrowser journey1
- ○UC-D-14 — hazmat disclaimer + add-to-cart enabled (blocked on hazmat UI)
○Shipping uc2 guest singleBrowser journey1
- ○UC-D-2 — guest single-line shipping flow (mock-delivery)
○Shipping uc3 scenario aBrowser journey1
- ○UC-D-3 — Scenario A overnight formula (mock-delivery)
○Shipping uc4 cnhBrowser journey1
- ○UC-4 — CNH overnight via Clinton (mock-delivery)
○Shipping uc4 scenario bBrowser journey1
- ○UC-D-4 — Scenario B DFS disclaimer copy (blocked on R9 mock-server)
○Shipping uc6 mixedBrowser journey1
- ○UC-D-6 — mixed freight+parcel routes to one freight surface (mock-delivery)
○Shipping uc9 suggestionBrowser journey1
- ○UC-D-9 — UPS suggestion dialog accept flow (mock-delivery)
Automated checks378
Browser journeys7
Code exercised76.1%
What we check automatically98 groups
✓resolveVariantUrlBusiness rules15
- ✓rewrites a covered CDN photo to a same-origin pre-baked webp variant
- ✓snaps up within baked widths and clamps oversized requests down to the largest
- ✓handles nested paths — dir/stem split on the last slash
- ✓routes a covered prefix with no declared baked widths through the optimizer
- ✓rewrites a gallery photo to its baked variant
- ✓serves the PDP hero from 1080 rather than silently shrinking it to 640
- ✓routes an uncovered CDN raster through the optimizer instead of the original
- ✓leaves CDN SVGs unresized — optimizer rejects SVG, line-art stays lossless
- ✓snaps quality to the nearest optimizer-allowed value, defaulting to 75
- ✓never rewrites external vendor hosts
- ✓routes a local /public raster through the optimizer instead of shipping the original
- ✓leaves a local /public SVG untouched
- ✓routes our own GCS buckets through the optimizer
- ✓leaves an unlisted GCS bucket untouched — not in remotePatterns, would 400
- ✓routes CDN rasters through the optimizer when no prefixes are covered
✓buildOptimizeQueryPromptAdmin logic12
- ✓keeps the P1-P4 preference gentle (recall over polish), no hard filters
- ✓NEVER instructs the OEM domain as a search keyword
- ✓tells the model to search like someone who knows the brand (rewrite bad codes)
- ✓carries ONE cosmetic hint at level 0 for a named model, none for a bare number
- ✓broadens by level: level 1 drops qualifiers, level 2 allows family/site last-resort
- ✓adds the found-nothing broaden note only when foundNothing is set
- ✓folds reject reasons into the prompt as distinct feedback
- ✓found-nothing overrides reject reasons (no candidates = nothing the reasons describe)
- ✓caps reject reasons in count and length (image-derived text is untrusted)
- ✓always ends with a guaranteed non-empty fallback query
- ✓improves the PREVIOUS round's query on re-optimization, not the seed
- ✓never doubles the brand when the display name already carries it
✓label photo actionsServer actions11
- ✓rejects a content type the bucket does not accept
- ✓returns unauthenticated when no Clerk session
- ✓returns unauthorized when the caller is a customer
- ✓POSTs to the upload-url endpoint and returns the signed URL
- ✓fails when the backend answers without an upload URL
- ✓surfaces the backend's own error message
- ✓fails without calling the backend when the payment service is unconfigured
- ✓fails when the fetch itself throws
- ✓returns the OCR candidates
- ✓returns an empty candidate list when the backend read nothing
- ✓requires a labelPhotoUrl
✓google-cse-clientAdmin logic11
- ✓resolves the vendor code to the brand name and distinguishes image vs diagram
- ✓maps a Custom Search response shape to media candidates
- ✓returns empty when every item matches currentUrl
- ✓cycles image query variants by attempt (OEM-biased first)
- ✓directs the image query by surface — a pdp part never picks up the equipment noun
- ✓maps attempt onto {variant index, page}: 0..2 = page 0, 3..5 = page 1, ...
- ✓attempt 0 vs 3 keep the SAME query but a DIFFERENT page (paged re-search)
- ✓diagram request pages by attempt (query stays stable)
- ✓drops junk domains and boosts OEM above aggregators
- ✓still drops currentUrl after junk-filter + OEM sort
- ✓maps diagram candidates from the same CSE shape
✓openrouter client model chainAdmin logic10
- ✓returns immediately without fetching when the key is unset
- ✓retries a 429 then succeeds on the same model
- ✓falls to the NEXT model when the primary times out at the network level
- ✓retries the SAME model without temperature on a 404 (frontier models reject it)
- ✓moves to the next model when the no-temperature retry also 404s
- ✓gives a vision stage a longer request timeout than a text stage
- ✓treats a 200 with a non-JSON body as a failure instead of throwing
- ✓treats an ok-but-empty completion as a failure and tries the fallback
- ✓json: parses fenced JSON and validates with zod
- ✓json: returns null (never throws) when the reply fails zod validation
✓isCnhPlaceholderUrlBusiness rules9
- ✓returns true for cnhiparts.widen.net/content URLs
- ✓returns true regardless of hostname case
- ✓returns true when URL has query string
- ✓returns false for other paths on the same host
- ✓returns false for GCS storage URLs
- ✓returns false for media.clintontractor.net URLs
- ✓returns false for a different Widen subdomain
- ✓returns false for null, undefined, empty string
- ✓returns false for malformed URLs
✓pickFromAspectRatioBusiness rules9
- ✓returns square dims for ratio 1
- ✓returns video dims for ratio 16/9
- ✓returns 4/3 dims for ratio 4/3
- ✓returns 5/2 dims for ratio 2.5
- ✓returns square fallback for ratio 0 without throwing
- ✓returns square fallback for NaN without throwing
- ✓returns square fallback for negative ratio without throwing
- ✓returns square fallback for Infinity without throwing
- ✓snaps an unknown ratio to the closest tabled key
✓isAllowedImageUrlShared helpers9
- ✓allows GCS URLs
- ✓allows CDN URLs
- ✓blocks m.media-amazon.com
- ✓blocks images-na.ssl-images-amazon.com
- ✓blocks images-amazon.com
- ✓blocks ecx.images-amazon.com
- ✓rejects empty URL
- ✓allows relative URLs
- ✓allows vendor CDN URLs
✓refuseUnlessAdminAdmin logic8
- ✓lets an admin through outside production
- ✓refuses role staff with 403
- ✓refuses role customer with 403
- ✓refuses role null with 403
- ✓refuses role undefined with 403
- ✓refuses a dev-only feature in production, naming it
- ✓lets a production-safe handler through in production
- ✓checks the role before the environment — a non-admin never learns which routes are dev-only
✓whole-model image edit widgetAdmin editing7
- ✓offers the edit trigger on a whole-model image for an admin with the toggle on
- ✓opens a prefilled issue with brand/model/current-url/page populated
- ✓renders NO trigger in prod even for an admin with the toggle on
- ✓renders the trigger for staff
- ✓renders NO trigger for a customer
- ✓renders NO trigger when the toggle is off
- ✓renders NO trigger for an anonymous visitor
✓POST /api/admin-edit/imageAPI endpoints7
- ✓accepts an authorized admin write and routes it for review (202)
- ✓allows staff (holds edit-image)
- ✓forbids a customer (403)
- ✓forbids when the admin-edit env gate is off / prod (403)
- ✓hard-blocks prod even when the env flag is on (403)
- ✓rejects a malformed body (400)
- ✓rejects invalid json (400)
✓/api/admin-media/enumerateAPI endpoints7
- ✓returns 403 for non-admin (staff)
- ✓returns 400 for an unknown / non-carried brand
- ✓resolves a display brand to its UPPERCASE vendorCode when fetching types
- ✓returns an explicit reason when a brand has no equipment types
- ✓returns a type's models (imageUrl normalized to null) when typeId is present
- ✓returns an explicit reason when a type has no models
- ✓returns 502 when the upstream enumerate throws
✓the optimizer fetches the media origin, not our own edge (#3847)Business rules6
- ✓hands an uncovered CDN raster to the optimizer as an absolute media URL
- ✓routes a mapped GCS bucket through the media origin, not storage.googleapis.com
- ✓never emits a relative /img optimizer source — that is the shape that 502s
- ✓leaves a genuine /public source relative — Next reads those off disk, no HTTP
- ✓keeps every published address on our own host — only url= names the origin
- ✓still leaves an external vendor host untouched
✓one file resolves to one URL however it was spelled (#3816)Business rules6
- ✓gives the mapped GCS spelling the same variant as the media-host spelling
- ✓agrees on every width in the ladder, not just the one
- ✓emits a query-free address for a covered path
- ✓does not swallow siblings of the covered prefix
- ✓still leaves an unlisted bucket and an external host alone
- ✓addresses the variant by path when the source carries a query or hash
✓AdminImageEditDialog — paste an image URLAdmin editing6
- ✓adds a selectable Pasted tile and auto-selects it (Save + Request enable)
- ✓files an issue whose proposed image URL is the pasted URL
- ✓shows an inline error and adds NO tile for an invalid URL
- ✓rejects a non-http(s) URL (e.g. javascript:) with the protocol error
- ✓replaces the manual candidate when a different URL is pasted
- ✓clears the pasted candidate when the dialog closes
✓MediaCoverageCardAdmin editing6
- ✓renders nothing for a customer
- ✓renders for staff and manager (manager normalizes to staff)
- ✓renders nothing for an anonymous visitor
- ✓renders nothing in prod even for an admin (hard block)
- ✓falls back to the demo shelf when the read-back is unavailable
- ✓prefers the live read-back count when the route reports it available
✓media candidate storeBusiness rules6
- ✓upserts and reads back a set
- ✓finds a set by its identity
- ✓does not let a different brand/model collide with an existing set
- ✓caps candidates per set at 20 and derives a missing host
- ✓removes a set by identity
- ✓clears all sets
✓media replacement storeBusiness rules6
- ✓appends and reads back rows
- ✓dedups by modelCode within a kind — last write wins
- ✓does not let a part/asset row clobber a model row with the same code
- ✓removes by kind + modelCode
- ✓clears all
- ✓back-fills requestKind from the surface for legacy rows missing it
✓buildPrioritizedImageListBusiness rules6
- ✓returns synthetic primary image when only primaryImage is provided
- ✓deduplicates synthetic primary when the same URL exists in images array
- ✓sorts images by priority when no primary image provided
- ✓drops CNH placeholder and placeholder-host URLs so the UI renders the branded fallback
- ✓keeps real images while dropping junk URLs from the same list
- ✓places synthetic primary image ahead of other prioritized images
✓isTrustedImageUrlShared helpers6
- ✓allows GCS URLs
- ✓allows the Clinton CDN
- ✓rejects vendor CDN hosts that isAllowedImageUrl permits
- ✓rejects Amazon marketplace hosts
- ✓rejects relative URLs (no parseable host)
- ✓rejects empty, null, and undefined
✓applyEntriesToEndpointAdmin logic6
- ✓uploads a WebP with provenance and returns cdnUrl on success
- ✓passes the thumbnail through to encode when present
- ✓records a failed item when the source is dropped (403) and never posts
- ✓records a failed item when the endpoint returns an error
- ✓skips an entry with no brand and does not encode or post it
- ✓uses the slugified type code for a category surface
✓planEntryAdmin logic6
- ✓places a brand-new model image under the brand dir (no current asset)
- ✓honors an existing local dir for a model (dir remap comes free)
- ✓writes a browse-by-type tile under the brand equipment-types dir
- ✓skips a bespoke local asset that is not an equipment-types tile
- ✓does not let a crafted currentImageUrl escape public/
- ✓skips entries missing a source URL or modelCode
✓isBlockedHostAdmin logic6
- ✓blocks loopback + localhost
- ✓blocks private IPv4 ranges
- ✓blocks the cloud metadata link-local address
- ✓blocks unique-local + link-local IPv6
- ✓blocks IPv4-mapped IPv6 forms of private targets (URL-normalized hex + dotted)
- ✓allows a normal public host
✓makeReplacementBusiness rules5
- ✓derives host, model bucket, and OEM quality from an OEM pick
- ✓carries the pick's match confidence when given (else leaves it unset)
- ✓flags a non-OEM aggregator source and marks a pdp pick as part
- ✓derives requestKind from the surface (category surface -> category kind)
- ✓falls back to modelCode when no model label is given
✓fromModelCsvBusiness rules5
- ✓round-trips toModelCsv output back into model rows
- ✓parses quoted cells containing commas
- ✓skips rows missing modelCode or imageUrl
- ✓defaults quality to flag and derives host when the CSV omits it
- ✓returns [] for empty text
✓runPoolBusiness rules5
- ✓runs every item exactly once
- ✓never exceeds the concurrency cap in flight
- ✓drains when a lane sets the shared stop flag (no new work starts)
- ✓stops starting new work once the signal aborts
- ✓does not deadlock when there are fewer items than lanes
✓sortImagesByPriorityBusiness rules5
- ✓leads with the CT-own photo regardless of its type or input position
- ✓keeps the CT photo first even when it trails several dealer angles
- ✓ranks real photos (detail/lifestyle) ahead of diagram/360 thumbnails
- ✓sinks a diagram below every real angle so it only leads when alone
- ✓is stable for equal-rank images and a no-op on empty
✓isOwnPartImageUrlShared helpers5
- ✓drops an own-host part image that names a different part
- ✓keeps an own-host part image that names this part, case-insensitively
- ✓keeps in-house CT photos, whose part number lives in the path
- ✓leaves alone anything that is not an own-host part-image path
- ✓passes when it cannot judge — empty part number, or an unparseable URL
✓planBrandMediaTargetAdmin logic5
- ✓maps a model surface to kind=model with the raw model code
- ✓maps a non-model surface to kind=type with the slugified type
- ✓writes both New Holland division slugs to the one new-holland namespace
- ✓slugifies the brand
- ✓skips entries missing an imageUrl, modelCode, or brand
✓verifyImageDetailedAdmin logic5
- ✓judges the full-size image and returns the rich verdict (no thumbnail fallback)
- ✓falls back to the thumbnail (flagged) when the full image cannot be fetched
- ✓is unavailable (matches null) when the key is unset — no fetch, no call
- ✓is unavailable when neither the full image nor the thumbnail fetches
- ✓is unavailable (matches null) when the model reply is unparseable
✓fetchGoogleCseItems — Serper providerAdmin logic5
- ✓POSTs to Serper with page = results-page + 1 (1-based)
- ✓retries once on a transient (non-200) failure, then succeeds
- ✓throws after both attempts fail (persistent upstream error)
- ✓does not retry a genuine empty (200 + no images)
- ✓returns [] and issues no request when unconfigured
✓optimizeSearchQueryAdmin logic5
- ✓returns the AI-improved query when the call succeeds
- ✓fails open to the seed query when the key is unset
- ✓fails open to the seed query when the reply is unparseable (null)
- ✓fails open to the seed query when the model returns an empty query
- ✓caps the improved query length at 200 chars
✓triageCandidatesAdmin logic5
- ✓joins per-image percents back to candidates even when a middle image fails to fetch
- ✓sends one text label directly before each inlined image
- ✓fails open (unavailable, null percents) when the key is unset
- ✓fails open when every image failed to fetch
- ✓fails open when the model reply is unparseable (null)
✓POST /api/admin-media/applyAPI endpoints5
- ✓returns 403 for a non-admin
- ✓returns 403 in production
- ✓returns 400 for invalid JSON
- ✓returns 400 when entries are missing or empty
- ✓delegates to applyEntriesToEndpoint and returns its result for an admin
✓useAdminMediaCandidates — refetch cycles attemptInterface behaviour4
- ✓fetches on mount with no attempt param and starts attempt at 0
- ✓refetch increments attempt and re-fetches with attempt in the URL
- ✓surfaces the route error (no mock fallback) when the search fails
- ✓does not fetch when disabled
✓global cross-brand category tile image edit widgetAdmin editing4
- ✓offers the edit trigger for an admin with the toggle on (label-keyed, no brand)
- ✓opens a prefilled issue with label + query + current path, no brand/type/#2365 scope
- ✓renders NO trigger in prod even for an admin with the toggle on
- ✓renders NO trigger for a customer
✓validatePastedUrlAdmin editing4
- ✓accepts an https URL
- ✓accepts an http URL
- ✓rejects a non-URL string
- ✓rejects a non-http(s) protocol
✓useManualCandidateAdmin editing4
- ✓adds a valid URL as a selected candidate
- ✓surfaces an error and no candidate for an invalid URL
- ✓resets the candidate and error when the dialog closes
- ✓resets when the target key changes
✓PickThumbInterface pieces4
- ✓prefers the Google thumbnail and sends no referer
- ✓falls back to the source URL when the thumbnail fails to load
- ✓shows a neutral icon (not a broken img) when every source fails
- ✓renders the source URL directly when no thumbnail is stored
✓applyTriageVerdictsBusiness rules4
- ✓merges AI percents into candidates joined by url
- ✓preserves the admin's chosenUrl through a triage write
- ✓skips null-percent verdicts (failed tiles) without wiping the field
- ✓is a no-op when the set does not exist
✓read/write auto-stage thresholdBusiness rules4
- ✓defaults to 80 when unset
- ✓round-trips a written value
- ✓clamps out-of-range writes into 0-100
- ✓falls back to the default on a corrupt stored value
✓processing claimsBusiness rules4
- ✓claims a fresh key and blocks a second claim of the same key
- ✓allows a different key to be claimed concurrently
- ✓re-allows a key after it is released
- ✓lets an EXPIRED claim (stale tab) be re-taken
✓mchaleDemoReviewSourceAdmin logic4
- ✓is scoped to McHale only (no other launch brand leaks in)
- ✓uses unique model keys (the metric counts distinct models)
- ✓marks the demo-shelf models checked and the rest needing review
- ✓includes the named McHale flagships in the review queue
✓appliedOverrideTargetAdmin logic4
- ✓targets the same dir + dest a model apply wrote (drift guard)
- ✓honors a local dir remap and uppercases the model key
- ✓targets a type tile by slug key
- ✓returns null when no brand dir resolves
✓removeAppliedEntriesAdmin logic4
- ✓removes a model override and prunes an emptied brand
- ✓deletes the committed model webp (in the sandbox public tree only)
- ✓reports removed even when the JSON entry was already absent (idempotent)
- ✓skips an entry with no resolvable brand dir
✓prepareTriageImagesAdmin logic4
- ✓keeps slot order, prefers the thumbnail URL, and inlines fetched images as JPEG
- ✓marks a failed fetch or undecodable body as not fetched, keeping its slot
- ✓judges a full page of results, not just the first few
- ✓caps the batch so an oversized candidate list cannot blow up one call
✓the baked-prefix list is the only coverage declaration (#3890)Business rules3
- ✓serves /gallery/100016.jpg from a baked variant
- ✓serves /ag/parts/80680.jpg from a baked variant
- ✓serves /equipment/equipment-types/tractors.jpg from a baked variant
✓DimensionedImage — aspect modeInterface pieces3
- ✓emits the aspect container class and intrinsic 600x600 for aspect=square
- ✓emits aspect-[4/3] container and 480x360 intrinsic for aspect=4/3
- ✓applies default object-cover className but lets callers override
✓DimensionedImage — unoptimized renders publish on our own host (#3801)Interface pieces3
- ✓moves the host when unoptimized bypasses the loader
- ✓moves it for source="natural" too, which forces unoptimized
- ✓leaves an optimized src alone — the loader owns that one
✓authorizeImageWriteAdmin logic3
- ✓authorizes admin and staff (both hold edit-image) and builds the audit row
- ✓carries the proposalId onto the audit row when present
- ✓refuses a customer (no edit-image capability)
✓requestDetailedVerifyBusiness rules3
- ✓returns the normalized server verdict on success
- ✓fails open to matches:null on a non-ok response
- ✓fails open to matches:null when the request throws
✓media AI tier preferenceBusiness rules3
- ✓defaults when nothing is stored
- ✓round-trips a written tier
- ✓falls back to the default for a stored value that is not a tier
✓toModelCsvBusiness rules3
- ✓emits Vova's header with a blank issue column, model rows only
- ✓escapes cells containing commas or quotes
- ✓returns the header alone when there are no model rows
✓computeMediaCoverageAdmin logic3
- ✓counts checked vs total and reports the remainder + ratio
- ✓is fully covered when every model is checked
- ✓avoids divide-by-zero for an empty source
✓measureMediaCoverageAdmin logic3
- ✓carries the coverage figures plus an elapsed timing
- ✓flags slow when the source pull crosses the threshold
- ✓never reports a negative elapsed time
✓admin-widget-m3-image-surface-invariant.regressionAdmin logic3
- ✓M3 model-list mount files a byte-identical image issue vs the live widget
- ✓M3 model-card mount files a byte-identical image issue vs the live widget
- ✓the surface-invariant issue equals the canonical buildEditIssueUrl output
✓modelOverrideValueAdmin logic3
- ✓writes a bare path when no confidence was recorded
- ✓writes a record carrying confidence + its source + priority class when present
- ✓omits the audit fields when only a confidence is given
✓guardedFetchImage DNS resolutionAdmin logic3
- ✓blocks a hostname that resolves to a private address (never fetches)
- ✓blocks when ANY resolved address is private (dual-record rebinding shape)
- ✓fails closed when the hostname does not resolve
✓isFetchableUrlAdmin logic3
- ✓requires https
- ✓rejects a literal private-IP url
- ✓rejects a malformed url
✓MediaCoveragePageAccount pages3
- ✓renders the per-brand coverage grid in dev
- ✓hides fabricated brand coverage in prod
- ✓redirects a non-admin away
✓individual-part images never offer the widget (#2365 whole-model only)Admin editing2
- ✓a PartCard exposes no admin edit trigger, even for an admin with the toggle on
- ✓the PDP part gallery exposes no admin edit trigger, even for an admin with the toggle on
✓AdminMediaCoverageMetric overlay gateAdmin editing2
- ✓renders nothing for an admin with the Cabinet edit toggle OFF
- ✓renders the demo-shelf readout for an admin with the toggle ON off-prod
✓DimensionedImage — aspectRatio modeInterface pieces2
- ✓snaps aspectRatio to nearest tabled key and emits intrinsic dims with no aspect container
- ✓falls back to square dims for invalid aspectRatio without throwing
✓parseImageWriteRequestAdmin logic2
- ✓accepts a well-formed body and carries an optional proposalId
- ✓rejects a non-object and missing/blank required fields
✓checkAllReplacementsBusiness rules2
- ✓un-applies AI-rejected picks, moves them back to candidates, keeps matches staged
- ✓keeps a pick staged (no un-apply) when the AI is unavailable (matches null)
✓partitionAppliedBusiness rules2
- ✓evicts the applied rows and keeps failed / skipped ones visible
- ✓keeps every row when nothing applied
✓approveCandidateSet confidence sourceBusiness rules2
- ✓records the detailed AI confidence + priority class when the chosen candidate carries them
- ✓falls back to the search heuristic confidence when no detailed verdict is present
✓skipNextCardNavigationBusiness rules2
- ✓arms a provided guard ref and is a no-op for undefined
- ✓self-disarms on the next macrotask so only a synchronous click is caught
✓host + widget integration (context guard)Business rules2
- ✓blocks host navigation for the click that follows a widget invocation
- ✓stops the trigger click itself from reaching the host
✓upsertCandidateSet — chosenUrl preservationBusiness rules2
- ✓preserves a prior chosenUrl and does not refresh a chosen set on re-run
- ✓refreshes an un-chosen set's candidates on re-run
✓setChosenUrlBusiness rules2
- ✓records the chosen url on an existing set
- ✓is a no-op (returns false) when the set is absent
✓needsReviewRateBusiness rules2
- ✓is the fraction of handled models not auto-staged
- ✓is 0 for an empty ledger
✓INTRINSIC_DIMSBusiness rules2
- ✓each tabled aspect key carries the documented ratio within 5% relative tolerance
- ✓every AspectKey has a matching container class
✓DELETE /api/admin-media/applyAPI endpoints2
- ✓returns 403 for a non-admin
- ✓delegates to removeAppliedEntries for an admin
✓buildManualCandidateAdmin editing1
- ✓stamps the pasted id, hostname source and full confidence
✓DimensionedImage — explicit modeInterface pieces1
- ✓emits explicit width/height with no aspect container
✓DimensionedImage — natural modeInterface pieces1
- ✓emits unoptimized and falls back to provided dims pre-load
✓effectiveAutoStageThreshold (floor)Business rules1
- ✓never returns below the 50% floor
✓meetsAutoStageBusiness rules1
- ✓gates a 0..1 confidence against the floored slider value
✓normalizeDetailedVerdictBusiness rules1
- ✓fills a partial body with safe defaults (never a fabricated pass)
✓useHostNavGuard capture handlerBusiness rules1
- ✓swallows the click only when the guard is armed, then disarms
✓synchronous ghost-click vs a lingering guardBusiness rules1
- ✓blocks the pointer-dismiss ghost-click but frees a later click on the same host
✓keyOfBusiness rules1
- ✓keys a set by surface + brand + modelCode
✓subscribeCandidateSetsBusiness rules1
- ✓fires the listener on a store change and stops after unsubscribe
✓replacementKindForSurfaceBusiness rules1
- ✓maps whole-model surfaces to model, pdp to part, cards to asset
✓requestKindForSurfaceBusiness rules1
- ✓maps category surfaces to category, everything else to image
✓importReplacementsBusiness rules1
- ✓appends imported rows through the dedup path and returns the count
✓makeStartGateBusiness rules1
- ✓hands out immediately when calls are spaced past the gap
✓estimateUsdBusiness rules1
- ✓sums call counts against the per-call cost
✓recordLedgerEntryBusiness rules1
- ✓accumulates calls, counts, and the cost estimate
✓mergeLedgersBusiness rules1
- ✓combines entries, counts, and cost across batches
✓serializeLedgerBusiness rules1
- ✓emits a rounded, stamped JSON report
✓isCtImageBusiness rules1
- ✓matches source === 'ct' case-insensitively, false otherwise
✓slugifyAdmin logic1
- ✓kebab-cases and collapses separators
✓fetchAndEncodeWebp drop-on-403 (#3085)Admin logic1
- ✓drops the candidate on a primary 403 and never falls back to the thumbnail
✓buildDetailedPromptAdmin logic1
- ✓encodes the reject rules and the P1-P4 ladder with the NH tractor preference
✓MAX_QUERY_ITERATIONSAdmin logic1
- ✓is 3 total optimize-search rounds
✓buildTriagePromptAdmin logic1
- ✓names only the received images and keeps the heuristic a weak prior
What we walk through in a real browser3 journeys
○perf — image width/height regression guardBrowser journey3
- ○home (/) — every img has width/height + ratio matches container
- ○brand-type-page (/parts/brand/new-holland-agriculture) — every img has width/height + ratio matches container
- ○pdp (/parts/87800083) — every img has width/height + ratio matches container
○Media override manifestBrowser journey2
- ○the override manifest is published and readable
- ○every brand's uploaded images reach the page they were applied from
○New Holland image-status network sweepBrowser journey2
- ○brand hub /parts/brand/new-holland-agriculture — every fetchable img is 200 + non-empty
- ○model diagram grid /parts/brand/new-holland-agriculture/diagrams — a fetchable img sample is 200 + non-empty
Automated checks2
Browser journeys39
Code exercised100%
What we check automatically1 groups
✓PartsFocusHeroProduct grid2
- ✓no longer renders the disabled Scan PN / Paste list placeholder buttons (#2245)
- ✓carries no category chip strip — the sidebar owns that axis (#3587)
What we walk through in a real browser5 journeys
○Page landmarks (#1756) @smokeBrowser journey20
- ○home — /
- ○parts-hub — /parts
- ○search-results — /parts?q=filter
- ○pdp — /parts/47622189
- ○nh-construction-hub — /brand/new-holland-construction
- ○brand-type-tractors — /parts/brand/new-holland-agriculture/type/tractors
- ○cart — /cart
- ○checkout-shipping — /checkout/shipping
- ○v2-brand-hub-new-holland-agriculture — /parts/brand/new-holland-agriculture
- ○v2-brand-hub-ferris — /parts/brand/ferris
- ○v2-brand-hub-ventrac — /parts/brand/ventrac
- ○v2-brand-hub-mchale — /parts/brand/mchale
- ○v2-brand-hub-marcrest — /parts/brand/marcrest
- ○v2-brand-hub-kuhn — /parts/brand/kuhn
- ○v2-brand-hub-kress — /parts/brand/kress
- ○v2-brand-hub-landoll — /parts/brand/landoll
- ○v2-brand-hub-brillion — /parts/brand/brillion
- ○v2-brand-hub-agco — /parts/brand/agco
- ○diagrams-ferris-landing — brand directory chrome
- ○assembly detail — ferris schematic + BOM mounted
○Accessibility smoke (axe-core) @smokeBrowser journey9
- ○@a11y home — / has no WCAG 2.1 A/AA violations
- ○@a11y parts-browse — /parts has no WCAG 2.1 A/AA violations
- ○@a11y pdp — /parts/47622189 has no WCAG 2.1 A/AA violations
- ○@a11y equipment-browse — /equipment has no WCAG 2.1 A/AA violations
- ○@a11y search — /search?q=filter has no WCAG 2.1 A/AA violations
- ○@a11y brands-directory — /brands has no WCAG 2.1 A/AA violations
- ○@a11y ferris-diagrams — /parts/brand/ferris/diagrams has no WCAG 2.1 A/AA violations
- ○@a11y nh-construction-brand-hub — /brand/new-holland-construction has no WCAG 2.1 A/AA violations
- ○@a11y cart — /cart has no WCAG 2.1 A/AA violations
○header without JavaScriptBrowser journey5
- ○primary nav is visible, not merely present in the markup
- ○the skip link is in the shell (WCAG 2.4.1)
- ○the desktop disclosure opens to every carried brand
- ○the drawer routes to the brand directory rather than repeating it
- ○search submits to /parts without JavaScript
○Phase A — checkout/shipping a11y/mobile fixes (front#461 P2)Browser journey3
- ○P2 #7 — ZIP input has numeric inputMode + a digits-and-hyphen pattern
- ○P2 #8 — name field is positioned above street in the DOM
- ○P2 #9 — Show more rate button has py-3 (≥44 px tap target)
○Header no jsBrowser journey2
- ○the nav marks the route you are on (#3188)
- ○closed disclosures mean no brand prefetch storm (#3336)
Automated checks274
Browser journeys8
Code exercised63.3%
What we check automatically56 groups
✓mockClerkUser — surface parity with the Clerk moduleSign-in & account22
- ✓exports useUser for every role
- ✓exports useAuth for every role
- ✓exports useSignIn for every role
- ✓exports useSignUp for every role
- ✓exports useClerk for every role
- ✓exports useSession for every role
- ✓exports useOrganization for every role
- ✓exports ClerkProvider for every role
- ✓exports SignIn for every role
- ✓exports SignUp for every role
- ✓exports SignedIn for every role
- ✓exports SignedOut for every role
- ✓exports Show for every role
- ✓exports SignInButton for every role
- ✓exports SignUpButton for every role
- ✓exports SignOutButton for every role
- ✓exports UserButton for every role
- ✓exports OrganizationSwitcher for every role
- ✓exports AuthenticateWithRedirectCallback for every role
- ✓exports ClerkLoaded for every role
- ✓exports ClerkLoading for every role
- ✓exports isClerkAPIResponseError for every role
✓RequestsWorkspaceAccount pages13
- ✓auto-selects the first request and renders its price summary old -> new
- ✓apply mutates the selected row status to Applied
- ✓blocks a reviewer from approving their own submission (two-key gate)
- ✓reject mutates the selected row status to Rejected
- ✓bulk-delete removes the selected request and closes the review sheet
- ✓filters the table by kind through the segmented pill
- ✓bulk-deletes checked requests
- ✓logs an applied decision into the recent-actions trail
- ✓bulk-applies checked requests through the spine, logging each once
- ✓apply-all-pending flips every pending row and logs them
- ✓does not re-log an already-applied request (bulk skip on non-pending)
- ✓clicking the already-selected row a second time hides the detail (toggle off)
- ✓switches selection when a different row is clicked, then toggles it off on re-click
✓AdminContentPageAccount pages12
- ✓titles the merged tab Content changes requests
- ✓renders the coverage statistics and the requests queue on one page
- ✓hides the requests queue rows in prod (no fabricated proposals)
- ✓explains how in-place editing works
- ✓links to the editable storefront surfaces
- ✓hides the demo editable surfaces outside dev (no fabricated rows in prod)
- ✓keeps media coverage reachable via the coverage card
- ✓renders the brand media-coverage grid
- ✓renders the editable content surfaces workspace
- ✓renders the content coverage donut
- ✓renders the pages-needing-attention gaps table
- ✓redirects a non-admin away
✓StaffProductDetailViewAccount pages11
- ✓renders part number, title, and slug in the header
- ✓renders Publishable badge when isPublishable is true
- ✓renders Not publishable badge when isPublishable is false
- ✓renders Not publishable badge when isPublishable is null
- ✓renders the list price
- ✓renders em-dash when price is absent
- ✓renders description section when description is present
- ✓renders fitment section with summary when fitmentCount > 0
- ✓renders supersession section for superseded_redirect parts
- ✓renders back link to /account/staff/products
- ✓renders public PDP link when slug is present
✓AdminSubNavAccount pages10
- ✓marks Overview active only on the exact /account/admin path
- ✓does not mark Overview active on a nested tab path
- ✓marks a nested tab active on its own sub-path
- ✓marks the Sales tab active on its own sub-path
- ✓marks the Inventory tab active on a deeper sub-path
- ✓marks the merged Content changes requests tab active on the content sub-path
- ✓no longer renders a separate Requests tab (merged into Content changes requests)
- ✓links Order Tracking to the admin console order-tracking route
- ✓marks the Order Tracking tab active on the admin order-tracking route
- ✓renders the capability tabs in order
✓AdminOverviewPageAccount pages9
- ✓renders the KPI row with every overview KPI in dev
- ✓renders the revenue bar chart with a total and legend in dev
- ✓renders the sales-by-channel donut and a KPI sparkline in dev
- ✓renders the needs-attention list with real console routes in dev
- ✓renders the jump-to-a-section grid in dev
- ✓labels the dashboard as demo data in dev
- ✓does not render a customer rating/reviews widget (removed from the ops console)
- ✓shows an empty state with no fabricated figures in prod
- ✓redirects a non-admin away
✓AdminSalesPageAccount pages9
- ✓renders sales KPI stats in dev
- ✓renders the orders table with real demo rows in dev
- ✓renders the revenue trend chart in dev
- ✓renders the sales-by-channel donut in dev
- ✓renders the top parts list in dev
- ✓renders the sales-by-brand breakdown in dev
- ✓labels the workspace as demo data in dev
- ✓shows an empty state with no fabricated orders in prod
- ✓redirects a non-admin away
✓RequestsWorkspace + Requests csv storeAccount pages9
- ✓surfaces a stored pick in the queue and removes it on approve
- ✓removes a stored pick from the store on reject too
- ✓evicts a stored pick from localStorage AND the list via BULK apply
- ✓evicts a stored pick from localStorage AND the list via BULK reject
- ✓evicts a stored pick from localStorage AND the list via Apply-all-pending
- ✓evicts a stored pick from localStorage AND the list via bulk-delete (deleteMany)
- ✓evicts a global-category searchQuery-keyed pick from localStorage on delete
- ✓surfaces a diagram store row as a Diagram request and gates it (exhaustive-kind)
- ✓re-syncs the queue from a cross-tab StorageEvent, not only the same-tab event
✓StaffQueueViewAccount pages9
- ✓renders the stat strip with the supplied counts
- ✓shows all 4 orders when the All filter is active
- ✓filters to packing orders when the Packing chip is clicked
- ✓filters to shipped orders when the Shipped chip is clicked
- ✓filters to backorder orders when the Backorder chip is clicked
- ✓narrows to packing orders that already have a shipping label when To-ship chip is clicked
- ✓exposes the filter chips as toggle buttons, not tabs (#3570)
- ✓renders the empty-state for a bucket with no matches
- ✓renders today's header and signed-in name
✓RefundEstimateAccount screens8
- ✓sums the selected items for an our-fault return (no fee)
- ✓subtracts the 20% restocking fee for customer-fault returns
- ✓shows zero refund when nothing is selected
- ✓renders the payment line when provided
- ✓applies the conservative 20% fee for review-class returns
- ✓subtracts the CNH freight estimate when provided
- ✓omits the CNH freight row when the estimate is zero
- ✓stacks restocking + CNH freight on a customer-fault CNH-sourced order
✓StaffLabelsViewAccount pages8
- ✓renders the table with order number, customer email, destination, and Print action
- ✓links the order-number cell to the readable orderNumber slug (#1038)
- ✓renders the empty state when there are no orders in the bucket
- ✓marks rows without a label URL with a No-label badge and suppresses the Print button
- ✓exposes a select-all checkbox + per-row checkboxes for batch print, opening one tab per selected label
- ✓surfaces a toast.error when the browser blocks the popup mid-batch
- ✓renders bucket chips as toggle buttons, not tabs, and presses the initial bucket
- ✓opens the label in a new tab when the URL is cross-origin (no same-origin fetch path)
✓StaffProductsView rowsAccount pages8
- ✓renders part number, title, publish badge, status badge, and price
- ✓renders Not publishable badge for dont_list status
- ✓renders Not publishable badge for superseded_redirect status
- ✓renders Publishable badge for call_for_pricing status
- ✓renders em-dash when price is absent
- ✓shows the empty state when no parts are provided
- ✓shows 'No products match' empty state when a query is active
- ✓renders the error banner when the server action rejects
✓<BackInStockAlert>Account screens7
- ✓renders the count with singular noun for 1 item
- ✓renders the count with plural noun for many items
- ✓renders nothing when count is zero
- ✓points the view CTA at the supplied href
- ✓invokes onDismiss when the dismiss button is clicked
- ✓hides the not-now button when onDismiss is undefined
- ✓uses 'View it' copy when count is one
✓<FavRow>Account screens7
- ✓renders title, meta, and links to the supplied href
- ✓shows stock label when supplied
- ✓adds the back-in-stock data attribute and 'Back' pill when isBackInStock=true
- ✓renders the domain pill when no thumbnail is supplied
- ✓invokes onRemove without navigating when the trash button is clicked
- ✓hides the trash button when onRemove is undefined
- ✓renders a held row's /lookup twin with no href and navigates client-side (#3843)
✓RolePillAccount screens7
- ✓renders the default label for variant user
- ✓renders the default label for variant staff
- ✓renders the default label for variant admin
- ✓renders the default label for variant owner
- ✓exposes the variant on the DOM for css/test hooks
- ✓allows callers to override the label without changing the variant
- ✓applies different palette classes per variant
✓StaffCustomerViewAccount pages7
- ✓renders the customer name + email header
- ✓computes lifetime stats and renders the stat strip
- ✓renders both addresses, deduped by street+city
- ✓includes a tel: link when the customer has a phone
- ✓falls back to the email when no shipping name is on file
- ✓links the View all CTA when more than RECENT_LIMIT orders exist
- ✓renders the empty-state card when the customer has zero staff-visible orders
✓ProfileCardAccount screens6
- ✓renders name, email, and the matching role pill
- ✓derives initials from the first and last word for the fallback avatar
- ✓falls back to a single initial when only one word is supplied
- ✓renders an edit link when editHref is provided
- ✓omits the edit affordance when no editHref or trailing is passed
- ✓renders a caller-supplied trailing slot in place of the edit link
✓mockClerkUser — overridesSign-in & account6
- ✓merges top-level user overrides (replaces named keys, preserves siblings)
- ✓user override is a shallow spread (nested objects fully replaced)
- ✓overrides useAuth fields without losing has()
- ✓ignores useAuth fields explicitly set to undefined (preserves role-derived defaults)
- ✓ignores useUser fields explicitly set to undefined (preserves role-derived defaults)
- ✓ignores user fields explicitly set to undefined (preserves defaults)
✓buildNavigation — role-scoped groupsAccount screens5
- ✓gives a customer only the personal groups
- ✓gives staff the work group above the personal ones
- ✓gives admin the Administration door on top of the staff tools
- ✓links the staff Queue dashboard, which /account/staff redirects to
- ✓keeps work groups before personal ones so Customer Orders never abuts Orders
✓NavRowAccount screens5
- ✓renders a Link when given an href
- ✓renders a button and fires onClick when no href is supplied
- ✓hides the chevron when hideChevron is true
- ✓applies the destructive tone palette
- ✓renders meta and badge slots when supplied
✓ThumbsStackAccount screens5
- ✓returns null on an empty list
- ✓shows all thumbs and no overflow when count <= maxVisible
- ✓renders +N overflow when count exceeds maxVisible
- ✓renders Package fallback when thumbnailUrl is absent
- ✓labels the stack with the item count
✓AccountListStatusAccount pages5
- ✓shows a spinner while loading
- ✓shows the error text with a retry
- ✓calls onRetry when the retry is pressed
- ✓renders nothing when idle
- ✓renders nothing when ready
✓AuditLogPage graceful degradationAccount pages5
- ✓renders demo entries + banner (does not throw) when the fetch fails in dev
- ✓shows a stat header with the total change count in dev
- ✓shows the banner + empty state with NO demo rows in prod
- ✓renders the real (empty) log with no banner when the fetch succeeds
- ✓redirects a non-admin away
✓AdminPricingPageAccount pages5
- ✓shows the KPI row, brand promo card, brand markup viz, drift summary, and demo rows in dev
- ✓hides the KPI row, promo card, and viz and shows no rows in prod
- ✓keeps drift figures consistent across banner, KPI, and donut (all derived from rows)
- ✓derives the avg-markup KPI from the brand factors (parts-weighted, not hardcoded)
- ✓redirects a non-admin away
✓AdminUsersPage graceful degradationAccount pages5
- ✓renders demo rows + banner (does not throw) when the fetch fails in dev
- ✓shows a role stat header over the demo directory in dev
- ✓shows the banner + empty state with NO demo rows in prod
- ✓renders the real table (no banner) when the fetch succeeds
- ✓redirects a non-admin away
✓AccountSessionFrameAccount pages4
- ✓redirects to sign-in when there is no session
- ✓redirects rather than rendering a nameless shell when the user record is missing
- ✓maps the Clerk user onto the layout's user shape
- ✓falls back to the first name, then a generic label, when fullName is absent
✓SocialLoginButtons (classic clerk-js API)Sign-in4
- ✓sign-in: Google click calls authenticateWithRedirect (not .sso) with the classic shape
- ✓sign-in: forwards a safe redirect_url as redirectUrlComplete
- ✓sign-up: routes through /complete-profile and uses the signUp resource
- ✓reports an error and clears loading when authenticateWithRedirect throws
✓SsoCallbackSign-in4
- ✓renders a visible, sized #clerk-captcha so Clerk's Turnstile challenge is completable (front#626 + front#1566 regression lock)
- ✓surfaces a visible 'Finishing sign-in' status so a flagged user isn't left on a blank page
- ✓mounts AuthenticateWithRedirectCallback to complete the OAuth handshake
- ✓renders nothing when Clerk is disabled via NEXT_PUBLIC_DISABLE_CLERK
✓isValidStaffProductId (malformed id → notFound guard)Account pages4
- ✓returns false for an empty id
- ✓returns false for an id longer than 100 chars
- ✓returns true for a valid part number
- ✓returns true for a branded slug
✓AccountErrorAccount pages3
- ✓does not reset synchronously and disables the control while pending
- ✓resets once after the backoff, however many times it is tapped
- ✓offers sign-out only for an auth error
✓mockClerkAnonymousSign-in & account3
- ✓returns null user with isSignedIn false
- ✓getToken resolves to null (no session)
- ✓SignedOut renders children; SignedIn renders nothing
✓mockClerkServerSign-in & account3
- ✓auth() resolves with userId + getToken for the given role
- ✓currentUser() returns a ClerkUserShape with publicMetadata.role propagated
- ✓clerkClient().users.getUser returns the same shape
✓account route targetsAccount pages3
- ✓every link the account home renders points at a route that exists
- ✓no account surface links to a route that does not exist
- ✓recognises a route that is genuinely absent
✓account/api request shape pin — fetchUserOrdersBusiness rules3
- ✓calls fetch with GET + Bearer token + JSON content-type + AbortSignal
- ✓appends email when provided
- ✓returns AUTH_TOKEN_MISSING shortcut WITHOUT calling fetch when token is null
✓AdminCountCardAccount pages3
- ✓shows the label and the count
- ✓renders zero rather than falling back to an empty tile
- ✓takes the accent bar colour from the chart token, never a literal
✓RequestAuditTrailAccount pages3
- ✓renders nothing when there are no entries
- ✓caps the visible rows at 8
- ✓renders an entry with no editKind (e.g. a role change) as its outcome, with no kind label
✓isStaffRole (non-staff redirect guard)Account pages3
- ✓returns false for customer — page.tsx redirects to /account
- ✓returns true for staff
- ✓returns true for admin
✓StaffProductsView searchAccount pages3
- ✓calls searchStaffParts after debounce when query differs from SSR
- ✓does not call searchStaffParts when query matches SSR initial query
- ✓resets to page 1 when the search query changes from a deep SSR page
✓NavListAccount screens2
- ✓renders an eyebrow when provided and omits it otherwise
- ✓wraps children in a divided card surface
✓mockClerkUser — customerSign-in & account2
- ✓returns a signed-in shape with publicMetadata.role === 'customer'
- ✓has() returns false for any permission (no staff/admin grant)
✓mockClerkUser — staffSign-in & account2
- ✓propagates 'staff' to publicMetadata.role and grants staff perms
- ✓does NOT grant admin perms
✓AccountHomeAccount pages2
- ✓renders the five primary destinations as links
- ✓does not render a standalone Favorites row (saved parts moved into My Garage)
✓AdminLayoutAccount pages2
- ✓renders the admin console chrome and children for an admin
- ✓redirects a non-admin away without rendering the console
✓AuthCard mobile shellSign-in2
- ✓drops the rounded corners and border on <sm so the card runs full-bleed
- ✓renders the title and the optional description
✓CompleteProfileForm (useMutation)Sign-in2
- ✓on submit, calls user.update with unsafeMetadata + termsAcceptedAt and then routes
- ✓renders error alert when user.update rejects
✓OtpInputSign-in2
- ✓renders 6 OTP slots
- ✓clears every deferred timer on unmount
✓RevenuePanelAccount pages2
- ✓renders one x-axis label per weekly bar, not a reduced set
- ✓keeps every weekday label present under its column
✓AuditLogPage outcome columnAccount pages2
- ✓shows Applied for a real role change (previousRole !== newRole)
- ✓shows Reviewed (not Applied) for a no-op review (previousRole === newRole)
✓mockClerkUser — adminSign-in & account1
- ✓grants every permission via has()
✓mockClerkUser — staff permission scopingSign-in & account1
- ✓returns false for non-staff, non-admin perm namespaces (e.g. org:billing:*)
✓SignInForm submit button labelSign-in1
- ✓renders the primary submit button with the lowercase voice copy
✓SignUpForm submit button labelSign-in1
- ✓renders the primary submit button with the lowercase voice copy
✓account/api request shape pin — fetchOrderByIdBusiness rules1
- ✓calls fetch with GET + Bearer token + JSON content-type + AbortSignal
✓AdminRequestsPage (merged redirect)Account pages1
- ✓redirects the legacy Requests route to the merged Content changes requests tab
✓StaffLabelsMobileViewAccount pages1
- ✓presses the active bucket chip and declares no tab roles (#3570)
✓isStaffRole (non-staff redirect guard)Account pages1
- ✓returns false for customer — page.tsx redirects to /account
What we walk through in a real browser4 journeys
○Auth smoke — real clerk-js (per-PR, front#1591) @smokeBrowser journey3
- ○classic clerk-js surface our flows depend on exists on the loaded SDK
- ○Google OAuth click initiates the Clerk redirect (no Core-3 hang)
- ○Microsoft OAuth click initiates the Clerk redirect (no Core-3 hang)
○Account signed inBrowser journey2
- ○the customer session opens the account area @smoke
- ○Clerk reports a signed-in user on the client @smoke
○Account wallBrowser journey2
- ○order history opens for a signed-in customer @smoke
- ○the account navigation has no dead link to saved addresses @smoke
○Auth setupBrowser journey1
- ○prepare authenticated storage states @smoke
How to read this. “Automated checks” run on every code
change in seconds and their ticks come from a real run made for this page. “Browser journeys”
drive a real browser against a deployed site; they are listed here and run by CI on its own
schedule, so they carry a hollow marker rather than a borrowed tick. “Code exercised” is the
share of that area’s code a test touches — useful for spotting a thin area, but it says a
test ran the code, not that it would catch the bug.