{ "feature_id": "F-080", "verdict": "APPROVED", "checks": [ { "name": "PVP value bound to state, not derived", "result": "PASS", "notes": "PVP value reads from gross[v.id], not from centsToEur(... netCents * (1 + rate)) on each render." }, { "name": "type=text + inputMode=decimal", "result": "PASS", "notes": "All 4 price inputs (coste, PVP, oferta, neto) switched to type=text inputMode=decimal; comma and dot accepted." }, { "name": "net <-> gross cross-sync on edit", "result": "PASS", "notes": "PVP onChange derives net; Neto onChange derives gross; IVA onChange recomputes gross from net using new rate." }, { "name": "savePrice prefers gross and persists correctly", "result": "PASS", "notes": "savePrice now reads gross, converts to net via rate, posts to pricingApi.setVariantPrice. No API contract change." }, { "name": "Pre-existing lint cleaned up", "result": "PASS", "notes": "Removed unused PricingSectionProps interface, unused loadingPrices and prices states (pre-existing) so lint is green." }, { "name": "Margin still computed from gross", "result": "PASS", "notes": "calcMarginBruto(grossCents, costCents) uses eurToCents(gross[v.id]) — no longer recomputed on every render from netCents." } ], "lint": { "errors_introduced": 0, "pre_existing_cleaned": true }, "typecheck": "PASS", "verdict_reason": "PVP is now a free-text controlled input, mirrors Neto behavior, save uses gross. UI-only change, no API contract change.", "reviewer": "reviewer", "reviewed_at": "2026-08-20T04:01:00Z", "agent": "reviewer" }