You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The public /shop/:slug page must show one fixed, plain retry message when a product lookup cannot load. It must never inspect, render, or log a rejected Firestore, SDK, provider, or exception value to an anonymous visitor.
Fixed public message:
We could not load this product right now. Please try again later.
Current defect
src/pages/shop/ProductDetail.tsx catches the rejected product lookup and renders err.message directly. The route is public and the production shop service rethrows Firestore lookup failures, so a crawler or anonymous visitor can receive provider diagnostics, project identifiers, paths, or other private detail.
The separate checkout rejection is a different commerce boundary and is explicitly excluded.
Invariant
do not capture or inspect the lookup rejection
stop the loading state and show exactly one accessible fixed result
retain the existing Back to shop link
do not emit the rejection through browser console output
preserve the distinct missing-product and successful-product projections
make no Firebase/provider call in tests and use no real visitor, member, product, or order data
Exact scope
src/pages/shop/ProductDetail.tsx
only the getProductBySlug rejection hunk
only the early load/not-found error paragraph accessibility attributes
src/App.test.jsx
additive getProductBySlug shop-service mock/reset control and one focused actual anonymous product-route describe
separately named Public product-detail load failure privacy — SOURCE ONLY, NOT LIVE section only
Everything else is excluded, especially the handleBuy checkout rejection/form error, shop/event services, checkout/provider/Functions/Rules/root docs/lint/workflows/packages/deploy/data paths and every #249/#246 path.
Acceptance
Old-source tests expose a synthetic private canary and execute a hostile message getter, then pass after correction.
Rejection shows exactly the fixed accessible result and ends Loading.
Back to shop remains available and the lookup runs exactly once.
No rejected detail reaches DOM or five console methods.
A hostile throwing message getter is never accessed.
Resolved null still shows the existing Product not found result.
A synthetic success still shows the existing title, price, and product form.
Focused and full frontend checks, typecheck, lint safety, SPA/release/artifact guards, build, diff review, and independent security/accessibility/officer reviews pass.
Officer impact, officer documentation, and exact deployment truth are recorded.
Safety and deployment truth
Tests use only made-up values and mocks. Do not contact Firebase, Stripe, or another provider; inspect a real account/order/catalog; change provider configuration; or use production data. Source, tests, merge, preview, and green CI do not prove the website, Firebase, provider, or live behavior changed.
Outcome
The public
/shop/:slugpage must show one fixed, plain retry message when a product lookup cannot load. It must never inspect, render, or log a rejected Firestore, SDK, provider, or exception value to an anonymous visitor.Fixed public message:
We could not load this product right now. Please try again later.Current defect
src/pages/shop/ProductDetail.tsxcatches the rejected product lookup and renderserr.messagedirectly. The route is public and the production shop service rethrows Firestore lookup failures, so a crawler or anonymous visitor can receive provider diagnostics, project identifiers, paths, or other private detail.The separate checkout rejection is a different commerce boundary and is explicitly excluded.
Invariant
Exact scope
src/pages/shop/ProductDetail.tsxgetProductBySlugrejection hunksrc/App.test.jsxgetProductBySlugshop-service mock/reset control and one focused actual anonymous product-route describedocs/officers/EVENTS_SHOP_MEMBERS.mdPublic product-detail load failure privacy — SOURCE ONLY, NOT LIVEsection onlyEverything else is excluded, especially the
handleBuycheckout rejection/form error, shop/event services, checkout/provider/Functions/Rules/root docs/lint/workflows/packages/deploy/data paths and every #249/#246 path.Acceptance
messagegetter, then pass after correction.messagegetter is never accessed.Safety and deployment truth
Tests use only made-up values and mocks. Do not contact Firebase, Stripe, or another provider; inspect a real account/order/catalog; change provider configuration; or use production data. Source, tests, merge, preview, and green CI do not prove the website, Firebase, provider, or live behavior changed.