Skip to content

(SP: 3) [SHOP] fix launch scope decisions and harden checkout totals fail-closed#414

Merged
ViktorSvertoka merged 5 commits intodevelopfrom
lso/feat/shop-legal
Mar 24, 2026
Merged

(SP: 3) [SHOP] fix launch scope decisions and harden checkout totals fail-closed#414
ViktorSvertoka merged 5 commits intodevelopfrom
lso/feat/shop-legal

Conversation

@liudmylasovetovs
Copy link
Collaborator

@liudmylasovetovs liudmylasovetovs commented Mar 24, 2026

Description

This PR combines two launch-readiness blocks for the Shop module:

  1. Phase 0 — documents and fixes the launch business decisions in repo docs so implementation scope is explicit.
  2. Phase 1 / Workstream 1 — hardens checkout totals so pricing remains server-authoritative and fail-closed for launch.

The goal is to remove ambiguity before launch and prevent stale or client-controlled monetary inputs from silently creating incorrect orders.


Related Issue

Issue: #<issue_number>


Changes

  • Added Phase 0 shop launch policy docs:
    • launch scope decisions
    • payments runbook
    • checkout/notifications contract
    • legal merchant identity content package
  • Hardened checkout against stale merchandise pricing using pricing fingerprint / quote validation with controlled fail-closed behavior
  • Made checkout totals include authoritative server-side shipping and reject unsupported/stale shipping quote states
  • Enforced an explicit no-discount launch contract by rejecting discount-shaped checkout input and keeping payable total server-authoritative
  • Added/updated targeted shop tests covering:
    • stale pricing rejection
    • missing pricing fingerprint rejection
    • authoritative shipping total inclusion
    • shipping currency fail-closed behavior
    • no-discount checkout contract
  • Kept scope limited to Shop launch safety without expanding into refunds, admin shipping workflow, promotions, or unrelated refactors

Database Changes (if applicable)

  • Schema migration required
  • Seed data updated
  • Breaking changes to existing queries
  • Transaction-safe migration
  • Migration tested locally on Neon

How Has This Been Tested?

  • Tested locally
  • Verified in development environment
  • Checked responsive layout (if UI-related)
  • Tested accessibility (keyboard / screen reader)

Additional notes:

  • Used the local Shop test DB only
  • Ran targeted Vitest coverage for checkout/cart/shop flows relevant to:
    • stale pricing fail-closed
    • shipping total hardening
    • shipping currency guardrails
    • no-discount contract
  • Ran narrow file-scoped TypeScript / lint verification for touched files where needed

Screenshots (if applicable)

N/A — docs + backend / checkout contract hardening only.


Checklist

Before submitting

  • Code has been self-reviewed
  • No TypeScript or console errors
  • Code follows project conventions
  • Scope is limited to this feature/fix
  • No unrelated refactors included
  • English used in code, commits, and docs
  • New dependencies discussed with team
  • Database migration tested locally (if applicable)
  • GitHub Projects card moved to In Review

Reviewers

Summary by CodeRabbit

  • New Features

    • Order summary now shows actual shipping cost when a delivery quote is selected; totals update accordingly.
    • Checkout enforces stricter pricing/shipping validation (fail-closed) to prevent mismatched totals.
    • Guest checkout requires a validated email to complete processing; checkout UI adjusted (removed pay-on-delivery note).
  • Documentation

    • Added launch scope, merchant identity, payments runbook, and checkout-notifications contract.

@vercel
Copy link
Contributor

vercel bot commented Mar 24, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
devlovers-net Ignored Ignored Preview Mar 24, 2026 8:58pm

Request Review

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Mar 24, 2026

📝 Walkthrough

Walkthrough

Adds deterministic pricing and shipping quote fingerprinting and strict fail-closed validation to checkout; introduces authoritative shipping quote resolution, pricing fingerprint generation/validation, new error codes and tests, updates cart/checkout payloads, and adds related documentation and tests.

Changes

Cohort / File(s) Summary
Checkout UI & Cart
frontend/app/[locale]/shop/cart/CartPageClient.tsx
Extended ShippingMethod with amountMinor and quoteFingerprint; added shipping-method normalization/validation; derive checkout shipping/total from selected quote; updated order summary UI and checkout POST payload to include pricingFingerprint and shippingQuoteFingerprint.
Checkout API
frontend/app/api/shop/checkout/route.ts
Added new error codes (DISCOUNTS_NOT_SUPPORTED, CHECKOUT_PRICE_CHANGED, CHECKOUT_SHIPPING_CHANGED, SHIPPING_AMOUNT_UNAVAILABLE); early-reject unsupported discount fields (400); accept pricingFingerprint and shippingQuoteFingerprint and pass them to createOrderWithItems; include InvalidPayloadError details in responses.
Shipping Methods API
frontend/app/api/shop/shipping/methods/route.ts
Shipping methods now include authoritative amountMinor and quoteFingerprint; getMethods takes currency and the route returns available:false with CURRENCY_NOT_SUPPORTED for unsupported currencies.
Shipping Quote Utilities
frontend/lib/services/shop/shipping/checkout-quote.ts
New module resolving authoritative shipping quotes from env, validating non-negative integer amountMinor, returning CheckoutShippingQuote with deterministic SHA-256 quoteFingerprint and exported currency/type guards.
Pricing Fingerprint Utility
frontend/lib/shop/checkout-pricing.ts
New createCheckoutPricingFingerprint that deterministically hashes normalized items+currency into a 64-hex fingerprint.
Core Checkout Service
frontend/lib/services/orders/checkout.ts
Removed reconcileNoPaymentOrder; createOrderWithItems accepts pricingFingerprint/requirePricingFingerprint and shippingQuoteFingerprint/requireShippingQuoteFingerprint; validates authoritative pricing and shipping quotes, computes totals including shipping, persists itemsSubtotalMinor, and throws specific InvalidPayloadError codes on mismatch.
Cart Rehydrate & Cart Consts
frontend/lib/services/products/cart/rehydrate.ts, frontend/lib/cart.ts
Rehydrate now computes/returns summary.pricingFingerprint; emptyCart includes summary.pricingFingerprint: undefined; removed old cart summary helpers.
Validation Schemas
frontend/lib/validation/shop.ts
Added pricingFingerprint schema (64-char lowercase hex); extended checkoutPayloadSchema and cartRehydrateResultSchema.summary to include optional fingerprint fields.
Tests
frontend/lib/tests/... (checkout-price-change-fail-closed.test.ts, checkout-shipping-authoritative-total.test.ts, checkout-shipping-phase3.test.ts, checkout-currency-policy.test.ts, shipping-methods-route-p2.test.ts, cart-rehydrate-variant-sanitize.test.ts)
Added/updated integration and unit tests covering: pricing fingerprint enforcement (fail-closed), authoritative shipping quote flows and fingerprints, currency support checks in shipping methods, inclusion of pricingFingerprint in checkout requests, and fingerprint format assertions.
Docs Added
frontend/docs/shop/checkout-notifications-contract.md, frontend/docs/shop/launch-scope-decisions.md, frontend/docs/shop/legal-merchant-identity-content.md, frontend/docs/shop/payments-runbook.md
Added launch contracts, scope/decisions, merchant identity content, and payments runbook documentation.
Docs Removed
frontend/docs/payments/monobank/E0-gap-report.md, frontend/docs/payments/monobank/F0-report.md
Removed two Monobank-specific documentation files.

Sequence Diagram(s)

sequenceDiagram
    participant Client as Client (Browser)
    participant CartService as Cart Service (rehydrateCartItems)
    participant ShippingAPI as Shipping Methods API
    participant CheckoutAPI as Checkout API (/api/shop/checkout)
    participant OrderService as Order Service (createOrderWithItems)
    participant DB as Database (orders)

    Note over Client,DB: Authoritative pricing & shipping fingerprint flow

    Client->>CartService: rehydrateCartItems(items, currency)
    CartService-->>Client: CartSummary { pricingFingerprint }

    Client->>ShippingAPI: GET /api/shop/shipping/methods?currency=UAH
    ShippingAPI->>ShippingAPI: resolveCheckoutShippingQuote(env)
    ShippingAPI-->>Client: methods[] with amountMinor & quoteFingerprint

    Client->>CheckoutAPI: POST /api/shop/checkout { pricingFingerprint, shippingQuoteFingerprint, ... }
    CheckoutAPI->>CheckoutAPI: early-check unsupported discount fields -> 400 (if any)

    CheckoutAPI->>OrderService: createOrderWithItems(..., requirePricingFingerprint=true, requireShippingQuoteFingerprint=true)
    OrderService->>OrderService: recompute pricingFingerprint (authoritative)
    OrderService->>OrderService: resolveCheckoutShippingQuote (authoritative)
    OrderService->>OrderService: validate fingerprints -> 409 on mismatch
    OrderService->>DB: INSERT order (itemsSubtotalMinor, shippingAmountMinor, totalAmountMinor)
    DB-->>OrderService: order created
    OrderService-->>CheckoutAPI: order
    CheckoutAPI-->>Client: 201 { success:true, order }
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~65 minutes

Possibly related PRs

Suggested reviewers

  • AM1007
  • ViktorSvertoka

Poem

🐇
I hashed the carrots, counted the peas,
Stamped tiny footprints in cryptic keys.
No sneaky coin may slip or roam,
This rabbit guards the checkout home.

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title directly and specifically describes the main objective: hardening checkout totals with fail-closed behavior and fixing launch scope decisions for the Shop module, which aligns with the core changes across checkout, shipping, and pricing validation logic.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch lso/feat/shop-legal

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 5422f34092

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
frontend/lib/cart.ts (1)

169-205: ⚠️ Potential issue | 🟡 Minor

buildCartFromItems is unused; remove it or document its purpose.

This exported function (and computeSummaryFromItems which it calls) are not referenced anywhere in the codebase. The actual pattern for cart initialization is rehydrateCart, which fetches the cart summary (including pricingFingerprint) from the server API. If buildCartFromItems were ever used, it would fail checkout since it hardcodes pricingFingerprint: undefined, but since it has zero call sites, it appears to be dead code.

Either remove both functions or add a comment explaining the intended use case (e.g., if this is a utility for external consumers or future use).

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/lib/cart.ts` around lines 169 - 205, The exported helper functions
buildCartFromItems and computeSummaryFromItems appear to be dead/unsafe (no call
sites and computeSummaryFromItems hardcodes pricingFingerprint: undefined which
would break checkout); either remove both exports or clearly document their
intended purpose and limitations (e.g., note they are offline/local-only
helpers, warn about missing pricingFingerprint and mixed-currency checks) and/or
update buildCartFromItems to populate pricingFingerprint correctly if you intend
it to be used by app code; locate these by the function names buildCartFromItems
and computeSummaryFromItems and either delete them or add a top-of-function
comment and adjust the implementation to return a real pricingFingerprint or
delegate to rehydrateCart when a server-validated summary is required.
🧹 Nitpick comments (4)
frontend/lib/services/shop/shipping/checkout-quote.ts (1)

43-54: Minor: Redundant negative check after digit-only regex.

The check parsed < 0 on line 51 is unreachable since /^\d+$/ only matches non-negative integer strings. This is harmless but could be simplified.

♻️ Optional simplification
   const parsed = Number.parseInt(trimmed, 10);
-  if (!Number.isSafeInteger(parsed) || parsed < 0) return null;
+  if (!Number.isSafeInteger(parsed)) return null;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/lib/services/shop/shipping/checkout-quote.ts` around lines 43 - 54,
The function readNonNegativeIntEnv contains an unnecessary runtime check for
parsed < 0 because the /^\d+$/ regex already guarantees only non-negative
digits; remove the redundant parsed < 0 condition from the safety checks (inside
readNonNegativeIntEnv where parsed is validated with Number.isSafeInteger) so
validation relies on the regex and Number.isSafeInteger only, keeping behavior
identical but simplifying the logic.
frontend/lib/tests/shop/checkout-price-change-fail-closed.test.ts (2)

312-314: Minor: Redundant String() conversion.

The typeof json.order?.id === 'string' check already confirms the value is a string, making the String() conversion redundant.

✨ Simplify the conditional
-    const orderId =
-      typeof json.order?.id === 'string' ? String(json.order.id) : null;
+    const orderId =
+      typeof json.order?.id === 'string' ? json.order.id : null;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/lib/tests/shop/checkout-price-change-fail-closed.test.ts` around
lines 312 - 314, The conditional converting json.order?.id to a string is
redundant: when typeof json.order?.id === 'string' is true you can use the value
directly. Change the assignment of orderId (the const orderId variable) to
return json.order.id when the type check passes instead of wrapping it with
String(), e.g. use json.order.id in the true branch (or cast if needed) and keep
null otherwise so downstream expect(orderId).toBeTruthy() still receives the
original string or null.

134-173: Potential price inconsistency between products.price and productPrices.priceMinor.

The products.price field is hardcoded to '9.00' (line 145) while productPrices.priceMinor uses the parameter. If a test passes a different priceMinor value, these would be inconsistent. Currently all tests use 900 (matching $9.00), so this works, but it could cause confusion for future test variations.

✨ Proposed fix to derive product.price from priceMinor
     .values({
       slug,
       title: 'Checkout price change test product',
       description: null,
       imageUrl: 'https://example.com/checkout-price-change.png',
       imagePublicId: null,
-      price: '9.00',
+      price: (priceMinor / 100).toFixed(2),
       originalPrice: null,
       currency: 'USD',
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/lib/tests/shop/checkout-price-change-fail-closed.test.ts` around
lines 134 - 173, The products insertion in seedProduct hardcodes products.price
to '9.00' which can diverge from the productPrices.priceMinor parameter; change
the products insert in seedProduct to compute price from the priceMinor argument
(e.g., set products.price = (priceMinor / 100).toFixed(2)) so products and
productPrices remain consistent when inserting into products and productPrices;
update any related fields (originalPrice if needed) in the same seedProduct
function to use the same derived value.
frontend/lib/tests/shop/checkout-shipping-authoritative-total.test.ts (1)

167-234: Minor: Type assertions (as any) bypass schema validation.

The as any assertions on lines 191, 201, 211, and 223 bypass TypeScript's schema validation. While acceptable in tests, consider using proper typed inserts to catch schema drift during compilation. This is a low-priority improvement.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/lib/tests/shop/checkout-shipping-authoritative-total.test.ts` around
lines 167 - 234, The test helper seedShippingCheckoutData uses as any on
db.insert calls which silences TypeScript schema checks; replace the unsafe
assertions by importing/using the proper table row types or DTOs and pass
strongly-typed objects to db.insert for products, productPrices, npCities, and
npWarehouses (e.g., use ProductRow/ProductPriceRow/NPCCityRow/NPWWarehouseRow
types or the ORM's Insert<T> types) so the insert calls in
seedShippingCheckoutData remain type-safe and will catch schema drift at compile
time while still populating createdProductIds, createdCityRefs, and
createdWarehouseRefs as before.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@frontend/docs/shop/checkout-notifications-contract.md`:
- Around line 27-30: Remove the stray CMS/citation artifact
`:contentReference[oaicite:2]{index=2}` from the sentence "Notification flows
depend on a reliable recipient..." in checkout-notifications-contract.md so the
sentence reads cleanly (e.g., "If a guest order is created without email, the
notification pipeline can fail or dead-letter because there is no guaranteed
recipient identity."). Ensure no other `:contentReference[...]` tokens remain in
the document.

---

Outside diff comments:
In `@frontend/lib/cart.ts`:
- Around line 169-205: The exported helper functions buildCartFromItems and
computeSummaryFromItems appear to be dead/unsafe (no call sites and
computeSummaryFromItems hardcodes pricingFingerprint: undefined which would
break checkout); either remove both exports or clearly document their intended
purpose and limitations (e.g., note they are offline/local-only helpers, warn
about missing pricingFingerprint and mixed-currency checks) and/or update
buildCartFromItems to populate pricingFingerprint correctly if you intend it to
be used by app code; locate these by the function names buildCartFromItems and
computeSummaryFromItems and either delete them or add a top-of-function comment
and adjust the implementation to return a real pricingFingerprint or delegate to
rehydrateCart when a server-validated summary is required.

---

Nitpick comments:
In `@frontend/lib/services/shop/shipping/checkout-quote.ts`:
- Around line 43-54: The function readNonNegativeIntEnv contains an unnecessary
runtime check for parsed < 0 because the /^\d+$/ regex already guarantees only
non-negative digits; remove the redundant parsed < 0 condition from the safety
checks (inside readNonNegativeIntEnv where parsed is validated with
Number.isSafeInteger) so validation relies on the regex and Number.isSafeInteger
only, keeping behavior identical but simplifying the logic.

In `@frontend/lib/tests/shop/checkout-price-change-fail-closed.test.ts`:
- Around line 312-314: The conditional converting json.order?.id to a string is
redundant: when typeof json.order?.id === 'string' is true you can use the value
directly. Change the assignment of orderId (the const orderId variable) to
return json.order.id when the type check passes instead of wrapping it with
String(), e.g. use json.order.id in the true branch (or cast if needed) and keep
null otherwise so downstream expect(orderId).toBeTruthy() still receives the
original string or null.
- Around line 134-173: The products insertion in seedProduct hardcodes
products.price to '9.00' which can diverge from the productPrices.priceMinor
parameter; change the products insert in seedProduct to compute price from the
priceMinor argument (e.g., set products.price = (priceMinor / 100).toFixed(2))
so products and productPrices remain consistent when inserting into products and
productPrices; update any related fields (originalPrice if needed) in the same
seedProduct function to use the same derived value.

In `@frontend/lib/tests/shop/checkout-shipping-authoritative-total.test.ts`:
- Around line 167-234: The test helper seedShippingCheckoutData uses as any on
db.insert calls which silences TypeScript schema checks; replace the unsafe
assertions by importing/using the proper table row types or DTOs and pass
strongly-typed objects to db.insert for products, productPrices, npCities, and
npWarehouses (e.g., use ProductRow/ProductPriceRow/NPCCityRow/NPWWarehouseRow
types or the ORM's Insert<T> types) so the insert calls in
seedShippingCheckoutData remain type-safe and will catch schema drift at compile
time while still populating createdProductIds, createdCityRefs, and
createdWarehouseRefs as before.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: f904de93-a79d-434a-99e9-d19f4155a12d

📥 Commits

Reviewing files that changed from the base of the PR and between 446bb36 and 5422f34.

📒 Files selected for processing (21)
  • frontend/app/[locale]/shop/cart/CartPageClient.tsx
  • frontend/app/api/shop/checkout/route.ts
  • frontend/app/api/shop/shipping/methods/route.ts
  • frontend/docs/payments/monobank/E0-gap-report.md
  • frontend/docs/payments/monobank/F0-report.md
  • frontend/docs/shop/checkout-notifications-contract.md
  • frontend/docs/shop/launch-scope-decisions.md
  • frontend/docs/shop/legal-merchant-identity-content.md
  • frontend/docs/shop/payments-runbook.md
  • frontend/lib/cart.ts
  • frontend/lib/services/orders/checkout.ts
  • frontend/lib/services/products/cart/rehydrate.ts
  • frontend/lib/services/shop/shipping/checkout-quote.ts
  • frontend/lib/shop/checkout-pricing.ts
  • frontend/lib/tests/shop/cart-rehydrate-variant-sanitize.test.ts
  • frontend/lib/tests/shop/checkout-currency-policy.test.ts
  • frontend/lib/tests/shop/checkout-price-change-fail-closed.test.ts
  • frontend/lib/tests/shop/checkout-shipping-authoritative-total.test.ts
  • frontend/lib/tests/shop/checkout-shipping-phase3.test.ts
  • frontend/lib/tests/shop/shipping-methods-route-p2.test.ts
  • frontend/lib/validation/shop.ts
💤 Files with no reviewable changes (2)
  • frontend/docs/payments/monobank/F0-report.md
  • frontend/docs/payments/monobank/E0-gap-report.md

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
frontend/lib/tests/shop/checkout-shipping-authoritative-total.test.ts (1)

50-79: Note: resetEnvCache() called at mock factory time.

Line 64 calls resetEnvCache() during the mock factory execution (module load time). This works because beforeEach also calls resetEnvCache() after stubbing env vars. However, this placement is slightly unusual—consider moving it to beforeAll if the intent is test-time initialization rather than module-load-time.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/lib/tests/shop/checkout-shipping-authoritative-total.test.ts` around
lines 50 - 79, The call to resetEnvCache() is happening inside the vi.mock
factory (module-load time) which is unusual; remove the resetEnvCache()
invocation from the mock factory that defines ensureStripePaymentIntentForOrder
and instead call resetEnvCache() in test runtime setup (e.g., in a beforeAll()
or beforeEach() block depending on desired scope) so environment cache is reset
during test initialization rather than during module import.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@frontend/lib/tests/shop/checkout-shipping-authoritative-total.test.ts`:
- Around line 50-79: The call to resetEnvCache() is happening inside the vi.mock
factory (module-load time) which is unusual; remove the resetEnvCache()
invocation from the mock factory that defines ensureStripePaymentIntentForOrder
and instead call resetEnvCache() in test runtime setup (e.g., in a beforeAll()
or beforeEach() block depending on desired scope) so environment cache is reset
during test initialization rather than during module import.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: dcc54f25-963c-4f96-9a00-f9e5956fc66c

📥 Commits

Reviewing files that changed from the base of the PR and between 5422f34 and de48708.

📒 Files selected for processing (5)
  • frontend/docs/shop/checkout-notifications-contract.md
  • frontend/lib/cart.ts
  • frontend/lib/services/shop/shipping/checkout-quote.ts
  • frontend/lib/tests/shop/checkout-price-change-fail-closed.test.ts
  • frontend/lib/tests/shop/checkout-shipping-authoritative-total.test.ts
✅ Files skipped from review due to trivial changes (3)
  • frontend/docs/shop/checkout-notifications-contract.md
  • frontend/lib/tests/shop/checkout-price-change-fail-closed.test.ts
  • frontend/lib/services/shop/shipping/checkout-quote.ts

@ViktorSvertoka ViktorSvertoka merged commit 8310e18 into develop Mar 24, 2026
7 checks passed
@ViktorSvertoka ViktorSvertoka deleted the lso/feat/shop-legal branch March 24, 2026 18:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants