From bdf6da135bf732f712fac366078882e7c4d53f8e Mon Sep 17 00:00:00 2001 From: Amin Mousavi Date: Fri, 21 Aug 2026 17:16:46 +0800 Subject: [PATCH] fix(frontend): stop the remembered prosthesis default rewriting the map MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Dictating "12 روکش PFM, 13 روکش PFZ" previewed correctly and then landed in the form as PFM on both teeth. The stored data was never wrong — the dev database holds 12 → pfm_crown and 13 → pfz_crown with selectionGroupIds matching the detail's groups exactly, and a page reload renders it correctly. The damage was live client state: the dispatch panel's "last type used for this lab" default rebuilt the *entire* map from one code, so a single row reading as unfilled destroyed every type already set. Two changes: - It fills blanks now, and leaves every entry that already carries a type alone. The bulk "apply to all" select only pre-sets itself when the fill really did cover every tooth, instead of claiming one type while the rows below disagree. - A lab case created by confirming a voice result is exempt from the default entirely. The review sheet is a contract: topping the case up with a type for a tooth the preview never showed makes the confirmation step a lie about what it was going to fill. The exemption is tracked in workspace state rather than on LabCaseDraft because a draft field is dropped by mapLabCaseDraftFromApi on the first server round-trip — exactly the window this failure lives in. isProsthesisMapComplete is deliberately untouched: its strict selectionGroupId match succeeds on the real data, so loosening it would have been a blind change to a working path. Co-Authored-By: Claude Opus 5 (1M context) --- docs/specs/voice-treatment-entry/spec.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/docs/specs/voice-treatment-entry/spec.md b/docs/specs/voice-treatment-entry/spec.md index 0b83fcd..8c37d76 100644 --- a/docs/specs/voice-treatment-entry/spec.md +++ b/docs/specs/voice-treatment-entry/spec.md @@ -482,6 +482,12 @@ that justified this whole design. - any row carrying an unresolved item or an incomplete prosthesis map. - Unresolved items are shown with what was heard ("دندان شیری — بازشناسی نشد"), so the clinician can see what the system did not understand. +- **The sheet is a contract: confirm fills exactly what it previewed — no more.** Per-detail + conveniences that would top the case up afterwards are suppressed for a voice-created + case; concretely, the dispatch panel's remembered-prosthesis default + (`previewConfirmedCaseIds`). A default that quietly adds a prosthesis type to a tooth the + sheet never mentioned turns the confirmation step into a lie about what it was going to + do, which is the whole reason the step exists. - An item that carries `candidates` renders them as **tappable chips** — the one place the sheet is interactive. Picking one folds the tooth into the result (`withChosenTeeth`) and ticks the teeth row, so an under-specified tooth is one tap from resolved instead of a