fix(voice): hear "یادداشت" as a note request, and stop the note at the next instruction

Two reports from live dictation in fa.

The locale trigger vocabulary listed only verbs that ask for a note ("بنویس",
"یادداشت کن"). Naming the field itself — "توی یادداشت‌ها بنویس", "در توضیحات" —
reported no commentTrigger, and the resolver discards a comment without one, so
the note was silently dropped. Added the field-name shape to fa, en and nl.

Where the dictated note ends was never stated, so the model answered it
inconsistently: "توی توضیحات بنویس سلام چطوری و بفرست برای لابراتوآر سانشاین"
sometimes put the lab dispatch inside the comment. Added a no-overlap rule — a
clause reported as a lab, tooth, prosthesis or deadline is an instruction and
must not appear in comment as well — with that sentence as a worked example.

Both rules go in the prompt and in the JSON-schema field descriptions, because
the schema description is what the model reads while filling the field. No code
enforcement for the second: stripping an extracted clause out of free-speech
note text by string matching is guesswork, and the review sheet shows the note
before it is saved.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-09-11 19:33:49 +08:00
parent b71b4e9ca9
commit 78fd3eb092
4 changed files with 61 additions and 8 deletions

View File

@@ -524,6 +524,32 @@ step — only build and deploy. Combined with `nest build` excluding `**/*spec.t
running transpile-only under `isolatedModules`, nothing in this repo would ever catch a type error
in a spec file. That is how two of them reached this branch unnoticed.
## 2026-09-11 — note triggers and where a note ends (dyolink)
Two reports from live dictation in `fa`, both prompt-side, no resolver change.
1. «یادداشت» / «یادداشت‌ها» produced no trigger, so the note was discarded. The locale notes
listed only verbs that ask («بنویس», «یادداشت کن»); naming the field itself was not in the
vocabulary. Added the field-name shape for all three locales — fa «یادداشت/یادداشت‌ها/توضیحات/
کامنت», en "note/notes/comments/remarks", nl "notitie/notities/opmerkingen".
2. The note swallowed the next instruction. For «توی توضیحات بنویس سلام چطوری و بفرست برای
لابراتوآر سانشاین» the model sometimes put the whole tail in `comment`, sometimes only
«سلام چطوری». Added a no-overlap invariant: a clause reported as a lab, tooth, prosthesis or
deadline is an instruction and must not also appear in `comment`, plus that exact sentence as
a worked example.
Both rules are stated twice on purpose — in `extraction.prompt.ts` and in the `comment` /
`commentTrigger` descriptions in `extraction.wire.ts`, since the schema description is what the
model reads while filling the field.
No code enforcement for (2). Stripping an extracted clause out of free-speech note text by string
matching is guesswork, and the review sheet shows the note before it is saved.
Files: `backend/src/modules/voice/extraction.prompt.ts`,
`backend/src/modules/voice/extraction.wire.ts`, `docs/specs/voice-treatment-entry/spec.md`.
Verified: `npx eslint src/modules/voice/**/*.ts` clean, `npm test -- extraction` 74/74.
No unit test — both are prompt text, which the extraction specs deliberately do not assert on.
## Remaining before this is shippable
- The **manual pass in §12** — none of it has been run. Safari and iPad especially, since that is