Fibretrace Monet docs/QC test script/Script analysis

FibreTrace QC Test Script — Analysis

Source: .local/qc-test-script/fibretrace-qc-test-script.docx (v1.0, from Malcolm, 2026-08-19). Condensed cases: test-cases.md (same folder). Line references X:<n> cite extracted.txt.

Citation shorthand. L:<path>:<line> = the Lovable clone fibre-trace-studio-8b5c03d8 read at ref origin/main = ffab85ca, 2026-08-19 (the clone’s checked-out working tree is 4,264 commits behind that ref — every Lovable citation below was verified against the ref via git show/git grep, not the stale files on disk). M:<path>:<line> = fibretrace-monet/apps/dashboard. Memory/business-logic citations use full paths.

TL;DR

  • The script targets the live Lovable MVP, not monet: 30 of 31 distinct routes exist at Lovable origin/main; monet is missing 10 of them outright and stubs the data layer on 14 more. Running this script against monet would produce false bug reports on essentially every case.
  • The one route that exists nowhere (Lovable, monet, or canvas) is /insights (R-13), and the Insights module toggle (A-08) does not exist either — the admin module registry has exactly 5 modules, none named Insights (L:src/pages/admin/AdminCompanies.tsx:81).
  • The document does not settle the two known open questions: it uses both CU labels itself (“Claim Unit / credit unit”, X:6, X:276), and it mandates “Nominations (not Purchase Order)” wording (X:276) while still titling R-01 “Create a nomination (PO)” and routing everything through /purchase-orders — the table-rename question stays open.
  • Malcolm’s fresh-accounts requirement is achievable self-serve for users/companies (real signup + admin approval flow exists at HEAD), but 7 of the 11 object types in the env checklist are FT-Admin-gated (programme, programme registration, reservation, license, scanner, SDU, product categories). The QC account-switcher tab would remove login friction but does not remove the admin-gated object creation — that is the actual bottleneck.

a) Which app is under test

Verdict: the live Lovable MVP (fibre-trace-studio), full stop. Not monet’s apps/dashboard, and not “partly both”.

Evidence:

  1. Route census. Of the 31 distinct routes referenced by the 50 cases, 30 exist at Lovable origin/main (full matrix in section b). The only miss is /insights (R-13), which exists in no codebase we can inspect: at Lovable origin/main the only hit for “insight” is an unrelated local constant (L:src/components/EmptyProgrammeHealthCard.tsx:51); monet has no route or page; a case-insensitive sweep of frontend-canvas (.local/frontend-canvas/repo/src/) returns zero hits. R-13 tests a feature that has not been built anywhere yet (unverified whether it is in-flight inside Lovable today).
  2. Admin-route freshness. The script references /admin/programs (not programmes), /admin/reservation-requests, /admin/overrides, /admin/claim-verifications, /admin/settings — all of which only came into existence in the recent Lovable window (.local/lovable/sync-20260819/port-plan.md:176 records the AdminOverrides/AdminReservationRequests additions and the admin/programmesadmin/programs rename). At origin/main, /admin/programs is canonical and old /admin/programmes is a redirect (L:src/App.tsx:215-216). Monet still routes the OLD name only (M:src/App.tsx:168-169) and has no reservation-requests, signup-requests, overrides, claim-verifications, or admin-settings routes at all. Whoever wrote the script was looking at the live Lovable app as of this week.
  3. Business-rule fingerprints. The script’s rules are implemented only in Lovable: the 18-month reservation default (L:src/pages/admin/AdminProgrammes.tsx:110,209,247), the negative-adjustment ledger (“Use a negative value to subtract. 1,000 CU = 1 MT”, L:src/pages/admin/AdminProgrammes.tsx:1463), the obfuscation setting key obfuscate_verification_ids defaulting to ON (L:src/hooks/useObfuscateVerificationIds.ts:4, toggle at L:src/pages/admin/AdminSettings.tsx:169), and the product-category CU rate model (L:src/pages/admin/AdminProductCategories.tsx:144). The real Fibretrace REST backend has none of these concepts — “real backend has no expires_at concept anywhere (confirmed 2026-08-18)” (.local/lovable/sync-20260819/port-plan.md:79).
  4. Context fit. Malcolm’s message is about the MVP used for demos, the demo modal, and a possible “QC modal account-switcher tab” — the demo modal (DemoNavBar) exists only in the Lovable app (L:src/components/DemoNavBar.tsx:15-28).

Note on a premise: the working assumption that monet has no admin surface is not literally true — monet routes a 13-page /admin block (M:src/App.tsx:167-184) and 4 of 5 owner pages (M:src/App.tsx:151-154). But those pages are an early, now-stale port: they lag Lovable’s admin surface by 5+ screens, and their data tables are almost all no-op stubs (section b). The practical conclusion is the same — admin-route tests cannot be run against monet.

b) Route coverage matrix

Monet data-layer ground truth: M:src/lib/apiAdapter.ts registers 50 tables in ALL_TABLES (:109-128); only 12 have real mappers (company_modules:142, company_api_access:154, app_settings:161, company_users:263, company_partners:304, company_details:367, scanners:440, audits:462, facilities:533, invoices:577, companies:614, collections:647); the other 38 fall through to the no-op stub returning []. Every write through the fake client throws MutationNotImplementedError regardless of table (M:src/lib/apiAdapter.ts:835-858) — writes are only “supported” where a page bypasses the adapter for a real RTK Query mutation (e.g. facility creation). The 2026-08-19 port-plan’s API resolution confirms the window: EXISTS=0, 9 GAP, 3 PARTIAL (.local/lovable/sync-20260819/port-plan.md:4,69-189), and state.json carries 10 known_unported units — the whole PO/claims/programmes domain has been BE-blocked since June.

Route QC cases Lovable origin/main Monet router Monet data layer Run on monet?
/ (home) M-07, R-12 L:src/App.tsx:165 M:src/App.tsx:126 company_modules/app_settings wired; all PO/claim KPIs stubbed PARTIAL — KPIs empty for a known BE reason
/signup, /signup/status A-10 L:src/App.tsx:151-152 ABSENT NO — route absent
/admin/programs A-01, A-02 L:src/App.tsx:215 (old programmes redirects, :216) ABSENT as named (only stale /admin/programmes, M:src/App.tsx:168-169) fibre_programmes stub (apiAdapter.ts:178-183), programme_reservations stub (:233) NO
/admin/reservation-requests A-03, A-04, R-04 L:src/App.tsx:222 ABSENT reservation_requests not even in ALL_TABLES NO
/admin/companies A-05…A-09 L:src/App.tsx:219 M:src/App.tsx:170 companies/company_details/company_modules wired; programme_participants/programme_producers stubs (:230-231); writes throw PARTIAL — lists render, registrations impossible
/admin/signup-requests A-10 L:src/App.tsx:221 ABSENT signup_requests not in ALL_TABLES NO
/admin/facilities A-11 L:src/App.tsx:225 M:src/App.tsx:173 facilities WIRED (:533) READS yes
/admin/scanners A-11 L:src/App.tsx:224 M:src/App.tsx:172 scanners WIRED (:440); scanner_facility_assignments stub (:381) PARTIAL
/admin/licensing A-12 L:src/App.tsx:226 M:src/App.tsx:174 facility_licenses stub (:237) NO — empty shell
/admin/overrides A-13 L:src/App.tsx:223 ABSENT NO
/admin/claim-verifications A-14 L:src/App.tsx:234 ABSENT (only /admin/verifications, M:src/App.tsx:179) claim_verifications not in ALL_TABLES; verifications/sessions stubs marked “BE-blocked” (:200-209) NO
/admin/settings A-15 L:src/App.tsx:244 ABSENT — no AdminSettings.tsx in monet at all NO
/admin/fibre-production P-05 (expected) L:src/App.tsx:232 M:src/App.tsx:180 production_records stub (:234) NO — empty shell
/owner O-01, A-09 L:src/App.tsx:190 NOT ROUTED — OwnerDashboard imported (M:src/App.tsx:73) but never given a <Route>; dead code NO
/owner/certificates O-02 L:src/App.tsx:192 M:src/App.tsx:153 program_certificates(+assignments) stubs NO — shell
/owner/documents O-02 L:src/App.tsx:191 M:src/App.tsx:154 program_documents(+assignments) stubs NO — shell
/owner/program-uptake O-03 L:src/App.tsx:194 M:src/App.tsx:152 stubs NO — shell
/owner/program-record O-03 L:src/App.tsx:193 M:src/App.tsx:151 stubs NO — shell
/sdu P-01, P-02 L:src/App.tsx:184 M:src/App.tsx:143 sliver_delivery_units (:236) / sdu_activity_logs stubs NO — shell
/fibre-creation P-03…P-06 L:src/App.tsx:183 M:src/App.tsx:142 production_records (:234) / pigment_orders (:228) stubs NO — shell
/facilities M-01 L:src/App.tsx:185 M:src/App.tsx:144 facilities WIRED (:533) YES (closest to runnable)
/facilities/add M-01 L:src/App.tsx:140 M:src/App.tsx:111 real facilitiesApi mutation hooks (bypasses adapter) YES
/scanners M-02, A-11 L:src/App.tsx:179 M:src/App.tsx:141 scanners WIRED (:440) READS yes
/verifications (Scan History) M-03 L:src/App.tsx:177 M:src/App.tsx:138 verifications/sessions stubs, “BE-blocked” (:200-209) NO — shell
/partners M-04 L:src/App.tsx:188 (old /settings/partners redirects, :189) ABSENT — monet has only /settings/partners (M:src/App.tsx:161) company_partners WIRED (:304) PARTIAL — feature exists at the old path
/link-to-po M-05, M-06 L:src/App.tsx:176 M:src/App.tsx:134 purchase_orders/purchase_order_verifications/purchase_order_evidence_packs all stubs NO — shell
/purchase-orders R-01, R-02 L:src/App.tsx:173 (+:id detail :174) M:src/App.tsx:132 purchase_orders stub NO — shell
/claim-position R-03, R-04, R-05, A-02 L:src/App.tsx:170-171 (incl. :id) M:src/App.tsx:129 (no :id; separate flat /claim-position-list, :130) fibre_programmes/programme_reservations stubs NO — shell
/ready-to-claim R-06, R-07 L:src/App.tsx:175 M:src/App.tsx:133 same PO/claim stubs NO — shell
/claims R-08…R-11 L:src/App.tsx:172 M:src/App.tsx:131 production_claims stub (:235) NO — shell
/insights R-13 ABSENT (only word-hit L:src/components/EmptyProgrammeHealthCard.tsx:51) ABSENT NO — exists nowhere

Tally (31 routes): Lovable origin/main has 30/31 (missing: /insights). Monet: 7 routed with at least partially wired data (/, /admin/companies, /admin/facilities, /admin/scanners, /facilities, /facilities/add, /scanners), 14 routed but empty-state shells (all owner pages, /sdu, /fibre-creation, /verifications, /link-to-po, /purchase-orders, /claim-position, /ready-to-claim, /claims, /admin/licensing, /admin/fibre-production), 10 absent (/signup(+status), /admin/programs-as-named, /admin/reservation-requests, /admin/signup-requests, /admin/overrides, /admin/claim-verifications, /admin/settings, /owner, /partners, /insights).

Practical consequence: zero of the 50 cases can pass end-to-end on monet today — every write path either throws MutationNotImplementedError or is toast-guarded (“backend pending”), except facility creation. If anyone runs this script against monet, the failures on all A/O/P cases, M-03…M-07, and R-01…R-13 are known BE gaps, not bugs — filing them would duplicate .local/backend-specs/integration-audit/ and the port-plan beSpecForGap blocks. Only M-01 (facilities) and read-only parts of M-02/A-11 exercise real monet wiring.

c) Business rules captured

Cross-checked against .local/business-logic/, ~/.claude/memory/fibretrace/, and the Lovable sync records (research by a read-only agent; quotes spot-checked against the files).

# Rule (X:6-11) Status vs recorded knowledge
1 1 CU = 1 kg; CU = qty × net weight × blend % ALREADY RECORDED — but the formula as stated MISMATCHES the app. Recorded: “CU/piece = baseline_net_weight_kg × blend% × loss_multiplier (1000 CU = 1 MT)” (~/.claude/memory/fibretrace/reference_claim_units_product_categories_fibretrace-monet.md:23). The app itself says the same: “A CU is one kilogram of raw marked fibre: baseline weight x blend ratio x internal loss multiplier” (L:src/pages/admin/AdminProductCategories.tsx:144), and the loss multiplier is deliberately internal-only (...md:29). The QC rule omits loss_multiplier — testers computing expected CU by qty × weight × blend will get numbers that don’t match the app wherever loss_multiplier ≠ 1. “1 CU = 1 kg” itself is consistent everywhere.
2 Blend % from admin product-category config, never hard-coded ALREADY RECORDED, matches (reference_claim_units_product_categories_fibretrace-monet.md:29: product_categories.default_blend_pct, admin CRUD in AdminProductCategories.tsx).
3 Fibre Producer only via programme registration; SDU/EWR = feature gate, not persona Resolves a recorded fork. The old hook contradicts it: isProducer = company_modules("sdu").enabled OR ≥1 programme_producers row (.local/business-logic/persona-case-matrix.md:20, usePersona.ts:34). The newer hook matches exactly: isProducer = ≥1 programme_producers row (persona-case-matrix.md:31, usePersonaContext.ts:36). The rule effectively declares usePersonaContext canonical and marks the old SDU-OR clause as a bug to retire — worth confirming with Malcolm (P-01 is precisely the test for this).
4 IDs/GUIDs obfuscated by default, unmask when claim-linked ALREADY RECORDED, matches (reference_verification_id_obfuscation_fibretrace-monet.md:27-31: visibility = NOT app_settings['obfuscate_verification_ids'] OR session_is_claim_linked, default true). Rule 4 + A-15 also narrow that memory’s open question 3 (server-side vs client-side masking): confirms the product intent; the mechanics question stays open.
5 18-month default expiry; negative entries allowed ALREADY RECORDED, matches closely (reference_reservation_requests_expiry_fibretrace-monet.md:3,16,26-27). Closes that memory’s open question 3 (“per-adjustment ledger including negative deltas, or single reserved_mt override?” — ...md:58): the QC script now tests the ledger model as expected behaviour, so the ledger IS the product decision. Note this is exactly port-plan unit 14’s GAP — the real BE has neither expires_at nor negative ledger entries (port-plan.md:145).
6 reserved ≥ nominated ≥ claimed must reconcile NEW. No prior record states the three-way inequality; the closest is a two-way demand-vs-supply check in OwnerDashboard (reference_programme_owner_domain_be_gap_fibretrace-monet.md:162). Worth saving to business-logic notes as a first-class invariant (X-01, O-03, R-03, R-06 all test facets of it).

The two known open questions:

  • Q1 — CU label (“Claim Unit (CU)” vs “credit units”), open since 2026-08-18 (.local/lovable/sync-20260818/RUN-SUMMARY.md:30, re-confirmed open in sync-20260819/RUN-SUMMARY.md:104). NOT settled by this document. The script itself writes “1 CU (Claim Unit / credit unit)” (X:6), O-01 says “credit units (CU)” (X:106), and X-02’s expected wording is “Claim Unit (CU) / credit units” (X:276) — it canonises the pair, not a winner. Anyone hoping this doc closes the terminology sweep (port-plan unit 9) will be disappointed; ask on Thursday.
  • Q2 — Purchase Order → Nomination rename. Partially settled. X-02 mandates “Nominations (not Purchase Order)” as UI wording (X:276) — that settles the display-terminology direction. But the script itself still says “Create a nomination (PO)” (X:198), “Link your Purchase Orders > New nomination” (X:200), routes everything through /purchase-orders, and A-07 calls the menu “Link your POs” (X:56). The open question recorded in reference_po_domain_be_gap_fibretrace-monet.md:146 — whether the underlying TABLE/domain renames purchase_ordersnominations — remains open (also flagged “enum unconfirmed post-2026-08-18 rename” in port-plan.md:136).

d) Test-data build-out (Malcolm’s fresh-accounts requirement)

All findings verified at Lovable origin/main (an earlier pass against the stale working tree wrongly concluded signup and reservation requests didn’t exist — they do at HEAD). Auth model first, because everything hangs off it: login is a company_users email lookup (ilike), the password is only checked for non-emptiness, and the 2FA code is a demo code displayed on the login screen itself (L:src/pages/Login.tsx:102-115,151). “Emails” (invites, approvals) are simulated — appended to localStorage["fibretrace_signup_emails"] (L:src/lib/signup.ts:67-70), never actually sent. So creating and entering fresh accounts is cheap; nothing requires a real inbox.

Build order and who can create what:

Step Object Screen / write Persona Self-serve?
0 Product categories (blend %) /admin/product-categories, product_categories CRUD (L:src/pages/admin/AdminProductCategories.tsx) FT Admin ADMIN-ONLY. Missing from the script’s env checklist entirely, yet R-01/A-13/rule 2 depend on it
1 Fibre programme /admin/programs, fibre_programmes.insert (L:src/pages/admin/AdminProgrammes.tsx:257); default_reservation_term_months default 18 (:247); no blend-% field on the form FT Admin ADMIN-ONLY
2 Companies + users Self-serve: /signup 4-step wizard inserts signup_requests incl. company_type/tier (L:src/pages/Signup.tsx:191-192) → admin approves at /admin/signup-requests, which bootstraps companies+company_details (with type/tier, :70-77)+facilities+company_users+notification in one action (L:src/pages/admin/AdminSignupRequests.tsx:63-108). Or direct: admin quick-create is name+code only (L:src/pages/admin/AdminCompanies.tsx:197-199) + user (L:src/pages/admin/AdminUsers.tsx:68). Third path: partner-CSV bulk invite creates unclaimed:true placeholder companies with an invite token, claimed later via /signup?claim=<token> (L:src/components/partners/ImportPartnersCsvModal.tsx:104-140, Signup.tsx:75-113) Any (signup) + FT Admin (approval) YES, with an admin approval step. company_type lives on company_details, but per rule 3 the persona still comes from programme registration (next row)
3 Programme registration (participant / manufacturer / producer / owner) AdminProgrammes sub-dialogs: participant (L:...AdminProgrammes.tsx:448), manufacturer (:508), producers + owner company (:262-270 — delete-then-insert enforces max one owner company per programme; the old standalone /admin/program-owners page is gone at HEAD); owner visibility flag separately via company_modules("program_owner") (L:src/pages/admin/AdminCompanies.tsx:254) FT Admin ADMIN-ONLY
4 Reservation (+ negative adjustment) Programme’s reservation panel, programme_reservations.insert; negative allowed there (“Use a negative value to subtract”, L:...AdminProgrammes.tsx:542,1463; no floor check on the manual override insert, :568,598). Retailer-side request: AddReservationModalreservation_requests.insert (L:src/components/AddReservationModal.tsx:167-173; submit disabled for addCu <= 0, :158), reviewed at /admin/reservation-requests where approve throws if cu <= 0 (L:src/pages/admin/AdminReservationRequests.tsx:97-135, floor check :101) FT Admin (grant) / Tier 0 (request) Request self-serve; grant ADMIN-ONLY. Negative entries possible ONLY via the programme panel, never through the request queue
5 Facility license, then facility License grant: /admin/licensing (facility_licenses). Facility: self-serve /facilities/add but hard-gated on available licenses; admin path via /admin/facilities FT Admin (license), Tier 1 (facility) Facility self-serve ONLY after admin grants a license
6 Scanner Create+assign at /admin/scanners. Company-side /scanners has NO in-app request — the “request” is a mailto to support (L:src/pages/Scanners.tsx:154-165) FT Admin ADMIN-ONLY (M-02’s “request” step is out-of-band)
7 SDU device /admin/sdu, sliver_delivery_units.insert (L:src/pages/admin/AdminSDU.tsx:88). Company /sdu page cannot register devices FT Admin ADMIN-ONLY
8 Scans / verifications Demo Scan simulator only (DemoScanModalV2 insert chain: collection :570 → verification :580 → scans :656 → audits :710) — no hardware/BE ingestion in this app. M-03 explicitly allows “simulate” Tier 1 YES (simulator)
9 Production records (SDU / EWR / manual) /fibre-creation manual insert (L:src/pages/FibreCreation.tsx:441); SDU via DemoSDUModal.tsx:165; EWR via DemoEWRModal.tsx:49 (source:"ewr_demo") — EWR is simulator-only; no real EWR integration exists Tier 4 YES (manual + simulators), after steps 3/5/7
10 Nominations (POs) + partners PO create/import at /purchase-orders (CSV import insert ImportPoCsvModal); partner invite by 3-letter code, case-insensitive ilike match, at /partners (L:src/pages/settings/SettingsPartners.tsx:160-177) Tier 0 / Tier 1 YES
11 Insights module on/off DOES NOT EXIST. Module registry is exactly billing, verified_cta, verifications_menu, scanners_menu, program_owner (L:src/pages/admin/AdminCompanies.tsx:81); no /insights route or page anywhere BLOCKED — cannot be built by anyone

Dependency chain: 0 → 1 → 2 → 3 → {4, 5} → {6, 7} → {8, 9, 10}. Nothing needs a database seed or BE work except item 11 (feature absent) — everything else has a working create form at HEAD.

Does the QC account-switcher tab help? Partially. The current demo modal is a hardcoded list of 7 seed personas (L:src/components/DemoNavBar.tsx:15-28 — Tier 4 GIN “SUNDOWN”, Tier 4 rPET, Tier 1, Tier 2, Tier 0 WALMART, Program Owner, plus a dev-gated empty Tier 0); switchUser() re-fetches those fixed user IDs (:53-62) and cannot see newly created companies. So yes — a switcher tab that lists arbitrary/fresh accounts would remove the logout → email → demo-2FA cycle per persona hop, and it is the only switching aid besides admin Impersonate (L:src/pages/admin/AdminUsers.tsx:83-84,180), which already exists and works today. But switching is not the real friction: object creation is. Steps 0-1, 3-7 are all FT-Admin-gated, so either every tester gets FT Admin access (the /admin block is gated by an adminLoginRequired setting, L:src/components/AdminLayout.tsx:60-69), or one person pre-builds the env per the chain above. The switcher solves neither the admin-gated spine nor the two feature absences (Insights, override-add).

One direct conflict with Malcolm’s rule: R-13 says “Insights module (Walmart only in test data)” (X:258) — but WALMART is precisely one of the demo-modal companies testers are forbidden to touch, and no admin toggle exists to enable Insights for a fresh company. As written, R-13 is doubly impossible: the feature doesn’t exist, and its only named data home is a banned account.

e) Risks and gaps in the script itself

Internal contradictions:

  1. A-01 vs rule 2 (blend %). A-01 step 2 says set “default blend %” on the programme and expects “no blank blend %” (X:25-26), but rule 2 (X:7) says blend % lives in product-category config — and the programme create form at HEAD has no blend field at all (insert payload: name/description/status/dates/pigment/fibre_type/country/heatmap/logo, L:src/pages/admin/AdminProgrammes.tsx:257 region; default_reservation_term_months is the only numeric default, :247). A-01 will “fail” on a field that is by-design elsewhere.
  2. Rule 1 omits the loss multiplier the app itself applies (L:src/pages/admin/AdminProductCategories.tsx:144; memory reference_claim_units_product_categories...md:23). Any tester hand-computing CU = qty × weight × blend will file false mismatches for categories with loss_multiplier ≠ 1 (and the multiplier is internal-only, so they can’t even see it).
  3. X-02 vs the script’s own vocabulary. X-02 demands “Nominations (not Purchase Order)” and “Verification Records (not Claims)” (X:276), yet the script itself says “Create a nomination (PO)” (X:198), “Link your Purchase Orders” (X:200), “Link your POs” (X:56), and routes /purchase-orders and /claims. If URLs count as “wording”, X-02 can never pass; define scope = visible copy only.
  4. A-04 contradicts the implementation at the route it names. A-04 expects a negative CU entry to be “accepted and saved… no validation error blocking the minus sign” at /admin/reservation-requests (X:39-41) — but that queue actively rejects non-positive values: the approve path throws if cu <= 0 (L:src/pages/admin/AdminReservationRequests.tsx:101) and the retailer request modal disables submit for addCu <= 0 (L:src/components/AddReservationModal.tsx:158). The only negative-capable surface is the programme’s reservation panel at /admin/programs (“Use a negative value to subtract”, L:src/pages/admin/AdminProgrammes.tsx:542,588,1463). As written, A-04 will fail at the named route by design — either the route is a mislabel or the queue is intended to gain negative-entry support.

Cases testing things that don’t exist (would fail for a known reason, not a bug):

  1. A-08 + R-13 (Insights) — no module toggle, no route, anywhere (section d, item 11). Plus the Walmart conflict above.
  2. A-13 (overrides)/admin/overrides at HEAD is a read-only calibration/audit report (reads PO lines vs category defaults, computes deltas, exports rate-and-quantity-overrides.csv; zero .insert( calls in the file, L:src/pages/admin/AdminOverrides.tsx:48-84,161-175). Step 1 “Add a rate/quantity override” has no UI on that page; overrides appear to arise from editing blend/qty on a nomination line. Either the step means “edit a nomination line and observe it on /admin/overrides”, or the add-UI is still to be built.
  3. P-06 (production limits) — no allocation-limit validation found in FibreCreation.tsx at HEAD (only .limit(1) query calls; no “exceeds allocation” guard located — unverified, may exist server-side, but nothing client-side names a limit). Expect this to fail as written.
  4. M-02 (request a scanner) — the in-app “request” is a mailto to support (L:src/pages/Scanners.tsx:154-165); the expected “request CTA” exists, but its delivery is out-of-band email, so “Admin assigns it” (step 2) can’t be triggered by the request itself.

Observability gaps:

  1. Invite/approval emails are simulated into localStorage["fibretrace_signup_emails"] (L:src/lib/signup.ts:67-70). A-09’s “Owner user receives an invite” and A-10’s approval email are only observable via that demo log/toasts — the pass criterion should say so.
  2. X-05 (persona isolation) — access control is client-side demo auth: /admin is gated only when the adminLoginRequired setting is on (L:src/components/AdminLayout.tsx:60-69), the login accepts any password value, and the 2FA code is printed on the login page (L:src/pages/Login.tsx:151). “Access denied” expectations need the auth settings stated as a precondition, and “no other company’s data is ever visible” is a data-scoping check in a client-side-filtered app — deep verification is out of QC’s reach here.
  3. Companion CSV missing. The doc tells testers to record results in fibretrace-qc-test-script.csv (X:4), which was not part of what we received (.local/qc-test-script/ holds only the docx).

Unstated dependencies / ordering:

  1. The prescribed section order is broken by M-05. “Run the sections in order” (X:4), but M-05 (section 4) requires “a shared nomination line” that only R-01 (section 5) creates (X:180 vs X:200). Minimum viable order: A → R-01/R-02 (retailer creates+shares nominations) → M-01…M-07 → rest of R → O → X. Similarly O-03 and X-01 need claims from R-07/R-08 to exist.
  2. Product-category setup is a hidden precondition (R-01, A-13, rule 2 depend on /admin/product-categories; no A-case creates categories and the env checklist omits them).
  3. Unlabeled case-to-case couplings inside sections: A-02 needs A-07’s participant; A-03 needs R-04’s request (admin section runs before the retailer section that generates requests — A-03 needs at least one pre-staged request or must be revisited after R-04); A-14 needs claims (R-07/R-08) and scans (M-03); O-01’s “over-commitment red” needs nominations exceeding capacity, i.e. deliberate over-raising in R-01.

Parallelisation: after the FT Admin spine (A-01…A-02, A-05…A-12) and product categories are built, the Producer chain (P-01…P-06) and the Manufacturer+Retailer chain (R-01→M-01…M-07→R-03…R-12) are independent of each other and can run in parallel on the same programme; O and X run last (they reconcile the others’ outputs). Two testers can also parallelise fully by building two independent programmes.

f) Proposed split + questions for Thursday

Assumption: testing happens on the live Lovable MVP with fresh nia-/tester-marked data per the build order in (d); one person holds FT Admin.

Who Sections Cases Rough effort
Tester A (holds FT Admin) Env build (d) + Section 1 + X-05/X-06 A-01…A-15 (A-08/A-13 expected-blocked), 2 X cases 0.5 day env + 1 day testing
Tester B Section 3 + Section 4 P-01…P-06, M-01…M-07 (needs R-01 from Tester C first) 1 day
Tester C Section 5 + X-01…X-04 R-01…R-13 (R-13 expected-blocked), 4 X cases 1.5 days
Whoever frees first Section 2 (after claims exist) O-01…O-03 0.5 day

Total ≈ 4.5 tester-days per full pass, minus ~3 cases currently untestable (A-08, A-13, R-13). Binh Le as coordinator/reviewer fits Tester A (admin spine) since that role sequences everyone else.

Questions for Malcolm (each tied to a finding above):

  1. (e5/d11) Insights: no /insights route and no Insights module toggle exist at Lovable HEAD — are A-08/R-13 testing something you’re about to build, or should they be dropped from this round? And R-13 names Walmart — a demo-modal company we’re told not to touch. Which rule wins?
  2. (e6) /admin/overrides is a read-only calibration report with no “add override” form — is A-13’s intended trigger “edit blend/qty on a nomination line, then verify it appears here”? If so we’ll reword the step.
  3. (e1/e13) Where does blend % actually get set — the programme form has no blend field; only /admin/product-categories carries default_blend_pct. Should A-01 drop that step, and should the env checklist gain “product categories configured” as step 0?
  4. (e2) Rule 1 omits the internal loss multiplier that the app applies (CU = baseline weight × blend × loss multiplier per the admin UI’s own description). For QC math, should testers assume loss_multiplier = 1 categories only, or get the multiplier values?
  5. (c/Q1) The script uses both “Claim Unit” and “credit unit” — X-02 asks us to verify “consistent wording”, so which label is canonical? (Open since 2026-08-18; blocks the terminology sweep too.)
  6. (e12) “Run the sections in order” breaks at M-05, which needs a nomination shared by R-01 (section 5). Confirm the intended order is A → R-01/R-02 → M → rest of R → O → X.
  7. (e9) Invites/approval emails only land in the in-app demo email log (localStorage), not a real inbox — is checking that log the accepted pass criterion for A-09/A-10?
  8. (d) Env build is FT-Admin-gated at 7 of 11 steps (programme, registrations, reservations, licenses, scanners, SDUs, product categories). Do all testers get admin access, or does one person pre-build? Related: the switcher tab you offered helps persona-hopping (fresh accounts aren’t in the demo modal, and admin Impersonate already exists) — but it won’t remove the admin-gated creation. Still want it?
  9. (e11) The companion tracking CSV (fibretrace-qc-test-script.csv) wasn’t attached — please share it so results can be recorded per release.
  10. (e10) For X-05, what auth settings should be ON during QC (adminLoginRequired etc.)? With the demo login (any password, on-screen 2FA code), “access denied” only holds if those settings are set.
  11. (e4) A-04 expects a negative CU entry to be accepted at /admin/reservation-requests, but that queue rejects cu <= 0 on approve — negative adjustments only exist on the programme’s reservation panel. Which surface should A-04 target, and is the queue meant to accept negatives at all?

Method note: three read-only research agents fanned out (route matrix, business-logic cross-check, test-data chain); every load-bearing claim above was re-verified against origin/main of the Lovable clone by the synthesising session, because the clone’s working tree is 4,264 commits behind the ref — two agent conclusions (no signup flow; no reservation-request flow) were stale-tree artefacts and are corrected here. The Lovable clone was not modified: all reads used git show/git grep against the fetched ref.