# stage1_outputs

thread_id: 019f5b4d-c79f-7172-96a4-80e10b3959e2
rollout_slug: purchase-plan-and-cross-store-refresh-audit
raw_memory:
  ---
  description: approved browser-persistent purchase-plan feature plus a follow-up cross-store refresh audit/fix that eliminated availability-text false positives and was committed
  task: spec-and-implement-pirkumu-plans-with-cross-store-refresh-audit
  task_group: car-parts-comparator-poc
  task_outcome: success
  cwd: /home/Messier82/projects/car-parts-comparator-poc
  keywords: purchase-plan, localStorage, refresh banner, directRefresh, availability normalization, Handler.lv, IC24, noVNC, regression tests, commit b28f1f8
  ---

  ### Task 1: Purchase-plan spec, implementation, and commit

  task: plan-and-implement browser-persistent Pirkumu plāns feature
  task_group: frontend/backend feature work
  task_outcome: success

  Preference signals:
  - user said: "The plan is to write up a functional spec first and then implement it after it has been verified and finalized." -> keep spec-first workflow for similar feature additions
  - user said: "Name: Pirkumu plans is good." -> default to the Latvian `Pirkumu plāns` terminology
  - user clarified: "they are alternatives for consideration ... maybe one store will have other, cheaper products and the overall order will be larger which is preferrable" -> model one chosen offer plus alternatives, not a flat cart
  - user asked: "show a banner that the offers may be outdated with a button to refresh? What do you think?" -> explicit stale-data banner + manual refresh is the preferred UX pattern
  - user asked: "selectable out of all options" -> store ordering should be user-selectable/persisted rather than fixed

  Reusable knowledge:
  - purchase plan is stored in browser local storage under `car-parts-comparator.purchase-plan` as versioned JSON
  - primary view groups chosen offers by store/orders; secondary view groups by part requirement and shows alternatives
  - only chosen offers contribute to store subtotals and grand total; alternatives do not
  - refresh requests must bypass the ordinary 15-minute search-result cache and claim freshness only on a newly successful store response
  - deterministic part markers should stay stable across reloads

  Failures and how to do differently:
  - ambiguous "keep both" semantics required multiple spec revisions; future work should settle whether alternatives are purchases or merely candidates before coding
  - first pass drifted toward a standard cart model; correct model is part requirements + one chosen offer + alternatives
  - no implementation should begin until the spec is approved

  References:
  - `PURCHASE-PLAN-FUNCTIONAL-SPEC.md` (approved)
  - `PURCHASE-PLAN-IMPLEMENTATION-PLAN.md`
  - commit `b28f1f8283c833b28e01c619bbe0632a92acbc71` / `Add persistent purchase planning and offer refresh`
  - validation: `npm run test`, `npm run test:web`, `npm run typecheck`, `npm run build:web`, `npm run lint`, live probes

  ### Task 2: Cross-store refresh false-positive audit and fix

  task: audit all enabled stores for refresh false positives and normalize availability handling
  task_group: backend refresh/parsing + regression tests
  outcome: success

  Preference signals:
  - user corrected scope: "You need to test all the stores for such a case and see how it behaves and fix if needed" -> always audit all enabled stores for this class of bug, not just the first failing one
  - user wanted the issue fixed, not just explained -> require regression tests and a live matrix before closing similar parsing/refresh bugs

  Reusable knowledge:
  - `availability` is display-only; refresh comparison should rely on structured stock state (`inStock`) and ignore wording/punctuation/delivery-note churn
  - Handler.lv search pages are a marketplace of supplier rows; exact-refresh must normalize the chosen row, keep shipping date separate, and avoid treating delivery-note-only changes as offer changes
  - unknown schema.org availability values should remain unknown rather than being forced to out-of-stock
  - IC24 exact-refresh can require the warm resident browser/noVNC human challenge path

  Failures and how to do differently:
  - the first fix was Handler-only; the user requested a store-wide audit, and the final fix became a cross-store rule with store-specific normalization only where necessary
  - comparing raw availability text caused false change warnings across multiple stores; compare structured stock changes instead
  - the initial handling of unknown schema availability was too aggressive; unknown must stay unknown
  - combined browser probes can skip or challenge some stores, so fall back to per-store probes and recorded fixtures where needed

  References:
  - live audit touched: `partsale`, `xparts`, `eoltas`, `carparts`, `handler`, `trodo`, `rd24`, `euautodalas`, `autodoc`, `ic24`
  - files involved in the fix: `src/core/directRefresh.ts`, `web/src/app/core/purchase-plan.domain.ts`, `tests/directRefresh.test.ts`, `tests/handler.test.ts`, `web/src/app/core/purchase-plan.domain.spec.ts`
  - final commit includes the cross-store fix and the purchase-plan feature: `b28f1f8283c833b28e01c619bbe0632a92acbc71`
  - live verification included IC24’s noVNC challenge flow and then confirmed search-to-refresh parity

rollout_summary:
  # Approved purchase-planning feature and a cross-store refresh false-positive audit/fix were implemented, tested, deployed, and committed.

  Rollout context: repo at `/home/Messier82/projects/car-parts-comparator-poc`; the user first asked to plan/approve a new `Pirkumu plāns` feature, then asked to implement it, then requested a broader store-by-store audit of refresh behavior, and finally asked to commit the work.

  ## Task 1: Purchase-plan spec, implementation, and commit

  Outcome: success

  Preference signals:
  - The user wanted the feature planned before coding: “The plan is to write up a functional spec first and then implement it after it has been verified and finalized.” -> future similar feature work should stay spec-first until the spec is approved.
  - The user explicitly preferred `Pirkumu plāns` as the name: “Name: Pirkumu plans is good.” -> use that terminology by default for this feature.
  - The user clarified alternatives vs selected offers: “they are alternatives for consideration … maybe one store will have other, cheaper products and the overall order will be larger which is preferrable” -> model the plan as one chosen offer per part requirement plus alternatives, not a plain cart of all offers.
  - The user preferred freshness UX as a warning + manual action: “show a banner that the offers may be outdated with a button to refresh? What do you think?” -> for future similar refresh flows, default to an explicit stale-data banner with a refresh button rather than auto-refresh on open.
  - The user wanted store-order sorting to be selectable: “selectable out of all options” -> preserve preferences and offer multiple sort modes rather than hardcoding one order.
  - The user later accepted the full design: “Sounds good” -> the spec/implementation decisions were approved, not tentative.

  Reusable knowledge:
  - The approved plan feature is browser-persistent local storage under `car-parts-comparator.purchase-plan`, with versioned JSON and a chosen-offer vs alternative-candidate model.
  - The UI has two views of the same data: orders by store and parts/alternatives by requirement; only chosen offers count toward store subtotals and grand total.
  - Refresh behavior is explicit/manual, with an “Offers may be outdated” banner when snapshots are old or unresolved; plan refresh bypasses the ordinary 15-minute search cache.
  - Matching-part markers are deterministic from the part identity and should remain stable across reloads.

  Failures and how to do differently:
  - Initial spec drafts needed multiple refinements because “keep both” was ambiguous. Future work should ask early whether alternatives are purchases or only comparison options.
  - The first pass treated selected offers and alternatives too much like a standard cart. The corrected model is a part requirement with exactly one chosen offer and optional alternatives.
  - The purchase-plan work was deliberately kept spec-first; no implementation should start until the spec is approved.

  References:
  - `PURCHASE-PLAN-FUNCTIONAL-SPEC.md` was added and approved.
  - `PURCHASE-PLAN-IMPLEMENTATION-PLAN.md` was added.
  - Commit: `b28f1f8283c833b28e01c619bbe0632a92acbc71` / `Add persistent purchase planning and offer refresh`.
  - Validation used: `npm run test`, `npm run test:web`, `npm run typecheck`, `npm run build:web`, `npm run lint`, plus live store probes.

  ## Task 2: Cross-store refresh false-positive audit and fix

  Outcome: success

  Preference signals:
  - The user corrected the scope from one store to all stores: “You need to test all the stores for such a case and see how it behaves and fix if needed” -> future refresh-fix work should audit every enabled store, not just the one that surfaced the bug.
  - The user wanted the issue fixed before considering the work done, not merely described -> treat live verification and regression coverage as required for refresh/parsing changes.

  Reusable knowledge:
  - The refresh path must distinguish structured stock changes from display-only wording, punctuation, rolling delivery dates, and disclaimer text.
  - In the live audit, false positives came from several stores because search snapshots and exact-product refreshes used different display wording for the same structured stock state.
  - Handler needed store-specific handling: its product page exposes a marketplace of supplier rows, so the refresh parser had to normalize the selected row, keep shipping date separate from availability, and avoid using delivery-note churn as a change signal.
  - `availability` is display-only; change detection should rely on structured stock state (`inStock`) and treat unknown schema availability conservatively.
  - IC24 is challenge-gated; exact-product refresh requires the warm resident browser/noVNC challenge path, and its live state can still be verified after human solve.

  Failures and how to do differently:
  - The first fix was too narrow: it only addressed Handler. The user corrected this, and the final fix became a cross-store rule plus store-specific normalization where needed.
  - The first comparison logic treated availability text as a change source, which caused false “changed” states from wording-only differences. The corrected approach ignores display-only wording and compares structured state.
  - A second bug appeared when schema.org availability values were unknown: unknown should stay unknown, not be forced to out-of-stock.
  - The live matrix showed that the combined browser pass could skip or challenge some stores; after that, probes had to be split out per store, including using recorded fixtures for exact-product URLs where needed.

  References:
  - Live audit covered all enabled stores: `partsale`, `xparts`, `eoltas`, `carparts`, `handler`, `trodo`, `rd24`, `euautodalas`, `autodoc`, `ic24`.
  - Final deployed behavior: ignore display-only availability wording and delivery-date churn; detect only price and structured stock changes.
  - Relevant files touched during the fix: `src/core/directRefresh.ts`, `web/src/app/core/purchase-plan.domain.ts`, `tests/directRefresh.test.ts`, `tests/handler.test.ts`, `web/src/app/core/purchase-plan.domain.spec.ts`.
  - Final live confirmations: search-to-refresh probes were run for all stores; IC24 required the existing noVNC human challenge and was then verified successfully.
  - A later live IC24 probe confirmed the warm session path: search showed `6.76 €`, `inStock: true`, `Pieejams (9 gab.)`; exact refresh returned the same price and structured stock, with display wording differences no longer treated as changes.


