Repository navigation
feat(notes): highlight a selection note's words, found again after a reprocess - #659
Conversation
…reprocess A selection note keeps the span its words were selected at and the words as the user saw them. The processed view now finds those words in the transcript as it reads now and marks them, tinted and underlined: solid where found exactly, dotted where found with changes (the original words in the title). The underline keeps a mark visible on a bubble of the tint's own colour. When they can't be found near the note's time nothing is marked, and the note line strikes the quote through, says the words changed, and quotes what the span reads now. A click on the tinted words, or the new pencil on a saved note's line, opens the note popover to edit the note or delete it, each write against the revision shown; a 409 shows the note as it is now and keeps the text typed, so a second Save replaces it knowingly. Decision record (anchoring rule) Context: a reprocess deletes every utterance and finalize supersedes the live ones, so nothing in the transcript keeps a stable id or offset. The audio clock is what survives: the note's start_ms/end_ms. Rule: resolved at read time, never written back. Look only among words timed within 2 s of the stored span; compare case-folded with punctuation stripped; take the run with the fewest word edits from the quote (approximate substring matching), ties to the run nearest the span's middle. All words equal is exact, 1 - edits/words >= 0.5 is fuzzy, less is unanchored. Placement still reads only the stored span, and prompts keep the stored quote. Alternatives: time span only (option C) would tint whatever words now sit there, silently; prefix/suffix context columns (E) are a migration for a gain only on repeated phrases, which the time tie-break already handles; re-anchoring at finalize and writing back (F) would make the pipeline a second writer of notes, bumping revisions under users' open edits. Trade-offs: the margin and floor come from 7,500 selections made the way the client makes them, on live and processed text of three benchmark recordings, resolved on their final and reprocessed text. At 2 s and 0.5: 78% exact, 19% fuzzy, 4% unanchored; 95% marked on the right words, 1.5% on wrong ones. A 5 s margin finds 0.2% more and marks 0.4% more wrongly. A 0.6 floor (the design's 0.7 was a guess) refuses 1.6% more, 113 of 117 of them right, mostly two-word quotes with one word changed; 0.4 adds 0.1%. 92 of the 110 wrong marks are one-word quotes; the clear cases are a word said twice within a few seconds, where the neighbouring copy is marked.
…it is unsent A selection's quote keeps just the characters chosen (B3c), so a drag that starts or ends inside a word, ordinary in Firefox and Safari, stores "ousand for the ve". The resolver compared whole words only, so such a note read "Words changed since this note" straight after it was saved. Now the quote's first word also matches the end of a word, its last word the start of one, and a one-word quote any part of one, with no edit counted. A whole word wins a tie over a part word, so "the" lands on "the" rather than inside "breathe". The stored quote is unchanged. Editing or deleting a saved note now holds the page as an unsent note does: from Save or Delete until the write is confirmed or the editor is closed, a refused write still open included. The hold lives in memory beside the outboxes (holdPendingNoteWrite); nothing retries it. A refused write puts focus back in the box, as disabling the pressed button dropped it to the page, and the reason is announced as an alert. The note underline (action-text on action-tint) is now in the contrast gate at 3:1; it is what marks the words on a light card. Calibration, margin and floor frozen at 2 s and 0.5. All figures are on the dev fixtures (Lords, London, Seattle) the margin and floor were tuned on, not on held-out data. On the 7,500 tuning selections the part-word rule leaves 94.9% marked right; wrong marks go from 1.5% to 1.7%, and unanchored from 3.7% to 3.5%. On 3,000 drags added after the freeze (inside words, over two or three lines, and over 2,000 characters, so shortened), right goes from 84.9% to 97.2%, unanchored from 14.8% to 1.5%, and wrong from 0.3% to 1.3%. Drags inside one line go from 10% to 83% exact. The wrong marks are part-word quotes of one to three words, mostly one-word ones that land on a neighbouring word holding the same letters. Limiting a one-word part match to the note's own span cut those from 12.8% to 8.4% of one-word drags but lost 12 points of right ones, so it is not done.
wordsChanged built a map of every line for each unanchored note each time a note line rendered, and note lines render on every playback tick. The text is now read inside the memo with the marks, so a tick only looks it up.
…essed A click on another note's marked words, or its pencil, replaced the open editor: the text typed in it was lost, and a save of it still on its way let go of the page. An editor holding typed text now stays until it is saved or cancelled; one left as it opened closes on the press as before, and the words pressed open theirs.
USAGE read as though any change typed into a note's editor made the page ask before closing. The hold starts when the change or delete is sent, as ARCHITECTURE.md says, so the guide now says that.
|
2ecad25 memoises what an unanchored note's span now reads. |
|
742c7d3 keeps an edit being typed when another note's marked words or pencil are pressed. Before, the open editor was replaced, so the typed text was lost and a save still on its way let go of the page. An editor left as it opened still closes on the press and the words pressed open theirs, as with a new note. Test added to |
|
ab656b5 is a docs fix. USAGE.md read as though typing a change made the page ask before closing, but the hold starts at Save note or Confirm delete, as ARCHITECTURE.md says. The guide now says that. |
Valtora
left a comment
There was a problem hiding this comment.
Approved at ab656b5. The resolver follows the rule agreed on #488, the edit, delete and 409 paths keep the typed text and the revision right, and lint, contrast, the full vitest run and the build all pass with main merged in. The new underline pairing measures 4.52:1 at its lowest, against the 3:1 floor. I pushed three small fixes, each with its own comment above.
Pull Request
Description
Addresses #488 (B3d). The processed transcript marks a selection note's words, refound after a reprocess: underlined on a light tint, dotted where they changed (original quote in the title). Lost words aren't marked; the note line strikes the quote and shows the span's words now. Marked words, or a saved note's new pencil, open #613's popover to edit or delete; a 409 shows the current note, keeping the typed text. Unconfirmed edits arm the leave warning. No hover link from mark to note line.
Decision record. Context: a reprocess replaces every utterance; only the note's span and quote survive. Rule: resolved at read time, never written back: within 2 s of the span, ignoring case and punctuation, the run with fewest word edits wins (end words may be part words, as a mid-word drag stores them), ties to whole words, then the nearest; fuzzy from 0.5. Alternatives: time only (silently marks other words), context columns (a migration), re-anchoring at finalize (a second note writer). Trade-off: on the tuning fixtures (Lords, London, Seattle; not held out), 95% of 7,500 sampled selections mark the right words, 1.7% wrong ones (mostly repeated one-word quotes); of 3,000 drags inside words, across lines or shortened, 97% and 1.3%. Figures in the commits.
Type of change
Checks run
check_whitespace.py,validate_docs.py,check_file_size.pypass.npm run lint,check:contrast,testandbuild, at currentmain.Migration impact
Documentation impact
docs/USAGE.mdanddocs/ARCHITECTURE.md(highlight invariant).Security impact
Manual verification
New tests fail on
mainunless they guard what it already does; all 50 mutants fail one. A production build on a faked API (synthetic data) passed 19 Chromium checks, incl. a mid-word drag and Pixel 7; a real-phone pass is to come.Screenshots (if relevant)