The treatment form was overhauled after voice v1 merged (a3c14a1,7f92e73,72f885d,5d3597f): one prosthesis type per tooth became stacked jobs, jaw-level appliances and a category tree. Voice still compiled against it but could no longer express it, and in two places wrote data the form itself refuses. Rewrites the extraction contract (§5), the resolver rules and the unresolved-reason table (§6), the review sheet (§7) and verification (§12), and records decisions 34-46. Adds the repos: block and a progress ledger so the task resolves from the branch. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
72 lines
4.2 KiB
Markdown
72 lines
4.2 KiB
Markdown
---
|
||
type: task-progress
|
||
status: active
|
||
repos:
|
||
- repo: dyolink
|
||
path: ~/PersonalProjects/dyolink
|
||
branch: feat/treatment/add-voice-input-for-new-treatment-form
|
||
base: origin/master
|
||
role: extraction contract + resolvers + review sheet
|
||
spec_slug: voice-treatment-entry
|
||
merge_after: []
|
||
---
|
||
|
||
# PROGRESS — Voice Treatment Entry
|
||
|
||
Spec: [spec.md](./spec.md)
|
||
|
||
Adapting the merged voice feature to the overhauled prosthesis model (spec §5–§7,
|
||
decisions 34–46). v1 shipped on `master`; this branch revises it.
|
||
|
||
Status legend: ⬜ not started · 🟡 in progress · ✅ done · ⛔ blocked
|
||
|
||
| # | Work item | Repo | Status | Notes / refs |
|
||
|---|-----------|------|--------|--------------|
|
||
| 1 | `pickRecordingMimeType` falls back to the empty hint instead of `null` | `dyolink` | ⬜ | §9. The Safari failure |
|
||
| 2 | `voiceForEditor` also checks `isMediaRecorderSupported()` | `dyolink` | ⬜ | §2 render policy, `TreatmentWorkspace.tsx` |
|
||
| 3 | Add Vitest for the frontend's pure helpers; update `CLAUDE.md` | `dyolink` | ⬜ | §12. One dev dep, one config, one script |
|
||
| 4 | `buildCatalog` passes `category` / `subcategory` / `chartRegion` / `stackGroup` through | `dyolink` | ⬜ | §5. `voice.service.ts` already receives all four |
|
||
| 5 | Wire schema: `prosthesisAssignments`, `arch: 'both'`; drop default + overrides | `dyolink` | ⬜ | §5, `extraction.wire.ts` |
|
||
| 6 | Resolver: assignments, arch derivation, leaf-vs-category classification | `dyolink` | ⬜ | §5, §6, `extraction.resolver.ts` |
|
||
| 7 | Resolver: new unresolved reasons; retire `tooth_not_selected` | `dyolink` | ⬜ | §6 reason table |
|
||
| 8 | Resolver: a resolved assignment forces `treatmentType` to `prosthesis` | `dyolink` | ⬜ | §5. Only `prosthesis` is `labDependent` |
|
||
| 9 | Prompt: present the catalog as a tree; teach stacks and jaw-level codes | `dyolink` | ⬜ | §5, `extraction.prompt.ts` |
|
||
| 10 | Backend Jest suites for items 6–8, including the namespace-disjointness assertion | `dyolink` | ⬜ | §12 |
|
||
| 11 | Frontend types follow the new `ResolvedExtraction` | `dyolink` | ⬜ | `types/voice.ts` |
|
||
| 12 | `voiceReviewRows`: merged row, chip folding, retire `complete` as a blocker | `dyolink` | ⬜ | §6, §7 |
|
||
| 13 | `VoiceReviewSheet`: merged row, chart colours, three chip kinds | `dyolink` | ⬜ | §7. `crownColors` / `rootColors` / `archHighlight` already exist |
|
||
| 14 | `applyVoiceResult` writes through `applyLeafToJobs`; handles arch rows | `dyolink` | ⬜ | §6, §7 |
|
||
| 15 | Vitest specs for `prosthesisTree.ts` and `voiceReviewRows.ts` | `dyolink` | ⬜ | §12 |
|
||
| 16 | New user-visible strings in `en.json`, `fa.json`, `nl.json` | `dyolink` | ⬜ | i18n is mandatory, not a follow-up |
|
||
| 17 | Run every gate in §12, then the manual pass including Safari and iPad | `dyolink` | ⬜ | §12 |
|
||
|
||
## Key decisions
|
||
|
||
Full table in the spec's §13, rows 34–46. The load-bearing ones:
|
||
|
||
- **One assignment list, no default type.** A default plus per-tooth overrides has a
|
||
precedence rule, and that rule already mis-filled tooth 13 once.
|
||
- **An arch target is derived from the code's `chartRegion`, not declared on the wire.**
|
||
The catalog already answers it, and `partial_denture` already carries `chartRegion: 'crown'`.
|
||
- **Stack rules stay frontend-only.** The backend's dispatch check knows nothing about
|
||
stacking; porting `canStackLeaf` would make voice stricter than the manual path and create
|
||
a second copy of a rule that must never disagree.
|
||
- **Teeth and prosthesis merge into one sheet row for lab-dependent types.** Two ticks can
|
||
save an empty detail today, because `persistDraft` prunes lab-dependent details to their jobs.
|
||
- **Nothing is guessed.** A missing material, a missing jaw and a missing quadrant all become
|
||
chips. A jobless tooth is named and left out.
|
||
|
||
## Deviations from spec
|
||
|
||
(none yet)
|
||
|
||
## Next steps / open questions
|
||
|
||
- Amin reviews and approves this spec revision. That approval is the only human gate before
|
||
`/orchestrate --dry`.
|
||
- Open items 15 and 16 in §11 are carried forward unchanged and are **not** in this branch:
|
||
the pre-authentication body limit on the voice path, and transcript salvage still being
|
||
specified but not built.
|
||
- `feat/voice-treatment-entry` and `backup/pre-rebase-voice` are stale local branches from the
|
||
v1 work. Safe to delete once this lands.
|