QC test report
This page records what Optivo is verified against and what the last full run produced. It is written for anyone who needs evidence rather than assurances: a reviewer, a merchant evaluating the app, or us, six months from now, trying to remember what was covered.
Every result below comes from a run executed on the date given. Nothing here is a claim about code that was not exercised — cases that are not automated are listed as such, in their own section.
Run summary
Section titled “Run summary”Run date: 28 October 2026 · Environment: Docker Compose (node:22-alpine,
PostgreSQL 16, Redis 7)
| Gate | Scope | Result |
|---|---|---|
| Application suite | 47 suites, 1,459 assertions (Vitest) | 1,459 passed, 0 failed |
| Cart Transform function | 33 tests (Rust, cargo test) |
33 passed, 0 failed |
| Type checking | react-router typegen && tsc --noEmit, strict mode |
Clean |
| Lint | ESLint across the repo | Clean |
| Storefront bundle budget | Core payload on every product page | 15,489 B / 15,872 B gzipped |
Total: 1,492 automated assertions, all passing. The application suite takes about 4 minutes 40 seconds; the function suite is effectively instant.
Test cases by area
Section titled “Test cases by area”Pricing accuracy — the category’s worst failure mode
Section titled “Pricing accuracy — the category’s worst failure mode”The defining risk for an app of this kind is a product page previewing one price and checkout charging another. It is tested as a first-class concern rather than as a side effect.
| ID | Case | Verified by | Result |
|---|---|---|---|
| QC-01 | A flat fee, percentage, per-character, formula or tiered rule produces the same figure in the widget and in the function | priceAccuracy, pricingRoundTrip |
Pass |
| QC-02 | 228 pricing permutations across rule types, quantities and option combinations | pricing |
Pass |
| QC-03 | Formula evaluation, including precedence, division and malformed input | formula (40), Rust formula.rs |
Pass |
| QC-04 | Quantity tier boundaries — the first unit, the tier edge, and above the last tier | tiered |
Pass |
| QC-05 | Checkout pricing against fixtures shared byte-for-byte with the widget | checkoutPricing, Rust pricing::matches_every_shared_fixture |
Pass |
| QC-06 | A choice surcharge survives the JSON round trip without floating-point drift | Rust wire.rs |
Pass |
| QC-07 | An absent, tampered or unknown-version metafield charges nothing rather than guessing | Rust wire.rs |
Pass |
| QC-08 | Individually invalid rules are skipped while the remaining valid rules still price | Rust wire.rs |
Pass |
QC-05 and QC-06 are the pair that matter most: the same fixtures are evaluated by the TypeScript widget and by the Rust function, and the two must agree.
Option types
Section titled “Option types”| ID | Case | Verified by | Result |
|---|---|---|---|
| QC-09 | All input types render, validate and serialise their answer | newOptionTypes, optionBuilder |
Pass |
| QC-10 | Static types (Heading, Paragraph, Divider, HTML) carry no answer and accept no pricing rule | staticOptionTypes (36) |
Pass |
| QC-11 | Choice rows — radio, dropdown, checkbox, single and multiple selection | choiceRows (38) |
Pass |
| QC-12 | Colour swatch parsing and palette handling | colourPalette (23) |
Pass |
| QC-13 | Custom-field patterns cannot be used to mount a ReDoS | patternSafety (40) |
Pass |
| QC-14 | HTML blocks are rebuilt from an allowlist; scripts, handlers and javascript: URLs do not survive |
patternSafety, staticOptionTypes |
Pass |
| QC-15 | Per-option style customisation applies without leaking between options | optionStyle (18) |
Pass |
| QC-16 | Plan gating is enforced when an option is added, never when it renders or prices | optionAccess, planFeatures |
Pass |
Assignment and publishing
Section titled “Assignment and publishing”| ID | Case | Verified by | Result |
|---|---|---|---|
| QC-17 | Broad scopes (all, tag, type, vendor, collection) resolve to the right product set | assignmentScopes, scopeWorker |
Pass |
| QC-18 | A product created after a scope was matched still receives its options | scopeBackfill, webhooks |
Pass |
| QC-19 | Publishing writes the pricing config to the product metafield; a draft set never reaches the storefront | metafieldSync, configCache |
Pass |
| QC-20 | The Cart Transform function is registered on install and removed on uninstall | cartTransformRegister |
Pass |
Storefront widget
Section titled “Storefront widget”| ID | Case | Verified by | Result |
|---|---|---|---|
| QC-21 | Widget rendering, selection state and the running price preview | widget |
Pass |
| QC-22 | Theme app extension renders only on product templates | themeAppExtension (29), themeEmbed (33) |
Pass |
| QC-23 | App Proxy responses are correctly shaped and HMAC-verified | proxyResponse |
Pass |
| QC-24 | Rate limiting buckets per shop and per client IP, so one busy shop cannot exhaust another’s quota | rateLimit (12) |
Pass |
| QC-25 | Core bundle stays within 15,872 B gzipped on every product page | build:widget |
Pass |
Lifecycle, privacy and billing
Section titled “Lifecycle, privacy and billing”| ID | Case | Verified by | Result |
|---|---|---|---|
| QC-26 | app/uninstalled removes the app’s records and the config written to products |
webhooks, reinstall |
Pass |
| QC-27 | Reinstalling after an uninstall produces a clean, working install | reinstall |
Pass |
| QC-28 | The three mandatory privacy webhooks handle disclosure and deletion according to their purpose | webhooks, webhookJson |
Pass |
| QC-29 | Webhook handlers accept real Shopify payload shapes, not hand-written approximations | webhookJson |
Pass |
| QC-30 | Plan changes, cancellation and lapse are reflected in entitlements | billing, planFeatures |
Pass |
| QC-31 | Operator panel access control and credential hashing | operatorPanel, operatorCrypto |
Pass |
Admin experience
Section titled “Admin experience”| ID | Case | Verified by | Result |
|---|---|---|---|
| QC-32 | Option set index, settings and dashboard render with real data shapes | optionSetIndex, optionSetSettings, dashboard |
Pass |
| QC-33 | Onboarding reflects the true app-embed state read from the published theme | onboarding |
Pass |
| QC-34 | Form intents route to the right action and reject unknown intents | formIntentFields |
Pass |
| QC-35 | Polaris components receive valid props (guards against silent UI breakage on upgrade) | polarisProps |
Pass |
What is not automated
Section titled “What is not automated”Stated plainly, because a QC report that implies total coverage is worse than no report at all.
- A real storefront purchase. The preview-versus-charge agreement is proven against shared fixtures in both implementations (QC-05), not by driving a browser through a live checkout. The five-minute manual run on App testing is what closes that gap, and it is worth running against any theme you intend to support.
- Theme compatibility across the ecosystem. The extension is verified against Online Store 2.0 app-embed behaviour, not against individual commercial themes. Vintage themes are unsupported by design.
- File upload. The option type is marked Coming soon and is not
selectable, so its storage paths (
uploads,customerUploads,storage,storageIntegration,shopifyFiles— all passing) are exercised in isolation rather than end to end. - Order-line recording.
orders/createis not subscribed, because it requires theread_ordersscope and adding a scope forces every existing merchant to re-consent. Customer selections still reach the order as native line item properties; the app simply keeps no copy. - Load and concurrency. Rate limiting is unit-tested (QC-24); the app has not been load-tested at scale.
Defects found and fixed in this cycle
Section titled “Defects found and fixed in this cycle”| Found | Defect | Status |
|---|---|---|
| 28 Oct 2026 | Documentation search was disabled site-wide: astro build left import.meta.env.DEV true, so Starlight rendered “Search is only available in production builds” on the published site, over a complete Pagefind index |
Fixed — the build script now pins NODE_ENV=production |
| 27 Oct 2026 | The help centre 404’d at every path because the nginx vhost on the host predated the static-docs routing | Fixed — vhost updated and reloaded |
| 25 Oct 2026 | ssl_stapling warnings and an http2 directive incompatible with nginx 1.24 |
Fixed — HTTP/2 set as a listen parameter |
Reproducing this run
Section titled “Reproducing this run”Everything above runs inside Docker. No step needs anything installed on the host beyond Docker itself.
docker compose up -ddocker compose exec app npm run test # 1,459 assertionsdocker compose exec functions cargo test # 33 testsdocker compose exec app npm run typecheckdocker compose exec app npm run lintdocker compose exec app npm run build:widget # enforces the bundle budgetThe same five gates run on every pull request and on every push to main, and
the deploy is gated on them. A release that fails any one of them does not
reach production.