TT-7621 fix: follow real segment changes, ignore spurious ones - #536
Open
nabalone wants to merge 5 commits into
Open
TT-7621 fix: follow real segment changes, ignore spurious ones#536nabalone wants to merge 5 commits into
nabalone wants to merge 5 commits into
Conversation
Base automatically changed from
TT-7621_pbt-segment-selection-and-recorder-state
to
develop
August 24, 2026 22:33
Recording segment 1, then segment 3, then clicking back to segment 2 filed the next take on segment 3, on top of the take already there. The step learns that the selection moved by watching currentSegmentIndex, but that field's numbering is not agreed between its writers: usePlayerLogic writes the waveform's 1-based sorted position (0 meaning "whole"), Mark Verses writes a table row, and this component writes a 0-based clause index. So a real move can arrive carrying the number the previous writer used - selecting segment 2 puts 1+1 there, which is what the step itself had just written for segment 3 - and the navigation effect never re-runs. The waveform selection and playhead move, the step does not, and the take goes wherever the step still thinks it is. Adds currentSegmentSeq to PassageDetailContext: a token bumped whenever the current segment actually changes. The two navigation effects watch it instead of inferring a change from the index. The step never used the number itself - it derives its own index from the region - so it now depends only on what it actually needs. Unifying the numbering would remove the need for this and is worth doing, but it touches every caller across Mark Verses, the players and this step, so it is deliberately not in here. There is also a latent off-by-one at useWavesurferRegions.tsx:955 that the same discrepancy causes; see the write-up that accompanies this branch. Test: "follows a click back to an earlier segment and files the take there" now passes, and asserts the take's uploaded source-segments is segment 2's span and that segment 3 still holds exactly one take. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
ADR 0010. Writes up the 0-based/1-based split in PassageDetailContext.currentSegmentIndex: who writes which convention, who reads which, what it broke on this ticket, and the latent off-by-one at useWavesurferRegions.tsx:955 that the same split causes. Deferred on purpose - unifying touches every caller across Mark Verses, the players and the guided-record step, and Noel's call is to do it after the next release. The ADR says what becomes removable then (currentSegmentSeq and the two navigation dependency lists) and what does not (the other TT-7621 fixes, which are unrelated to the numbering). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
nabalone
force-pushed
the
TT-7621_pbt-follow-segment-change
branch
from
August 25, 2026 12:40
1cae219 to
60cd79d
Compare
nabalone
marked this pull request as draft
August 25, 2026 12:51
nabalone
added a commit
that referenced
this pull request
Aug 25, 2026
This branch was cut before #527 gained the `@known-defect` tagging, so its copy of the defects spec won the merge and took the tags with it. Every still-broken repro then ran in CI and failed the check. Restores develop's tags on the three defects this branch does not fix, and keeps the pause repro untagged — that one is fixed here, so it should run. Also tags `clicking back to segment 2 leaves the step on segment 3` in the selection spec. It is a known defect (fixed in #536) that #527 missed, so it was failing CI untagged. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
nabalone
added a commit
that referenced
this pull request
Aug 25, 2026
This branch was cut before #527 gained the `@known-defect` tagging, so its copy of the defects spec won the merge and took the tags with it. Every still-broken repro then ran in CI and failed the check. Restores develop's tags on the three defects this branch does not fix, and keeps the loading-hang repro untagged — that one is fixed here, so it should run. Also tags `clicking back to segment 2 leaves the step on segment 3` in the selection spec. It is a known defect (fixed in #536) that #527 missed, so it was failing CI untagged. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
gtryus
pushed a commit
that referenced
this pull request
Aug 25, 2026
* TT-7621 fix: clear the loading flag when a load is abandoned Leaving a segment while its take was still loading killed the recorder: the status line stuck, and Record stayed disabled on that segment and every later one. Only leaving the step and coming back recovered it, which is what the hung-PBT report describes. MediaRecord holds `loading` until an effect sees `blobReady && originalBlob`. Both abandon paths - mediaId becoming undefined, and an explicit doReset, which this step triggers on every segment change - call reset(), which drops originalBlob. Once that happened mid-load the condition could never be met again, so `loading` stayed true, and the record button is disabled by Boolean(loading). Abandoning a load now clears the flag it set. Kept separate from reset() on purpose: handleLoadAudio calls reset() itself right after setting loading, so clearing it in there would cancel every load immediately. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * TT-7621 fix: gate the abandon on a load-only flag (Devin) Devin flagged that abandonLoadInFlight gated on a mirror of `loading`, which the save path sets too (MediaRecord.tsx:522). A doReset arriving mid-save - and this step sets resetMedia from handleClearRecording, which can run during a save - would have cleared the flag and the status text, re-enabling Record and dropping "Saving..." while the save was still running. Correct, and reachable. Replaced the mirror with loadInFlightRef, true only while handleLoadAudio is fetching a take, cleared wherever that load ends. It is also set synchronously rather than in an effect, which was Devin's second point: the [mediaId] and [doReset] effects now see it immediately instead of one commit late. jest MediaRecord + MediaRecord.load: 13 green. The loading-hang repro stays fixed; edit spec 16 green. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * TT-7621 test: keep the still-broken defect repros out of CI This branch was cut before #527 gained the `@known-defect` tagging, so its copy of the defects spec won the merge and took the tags with it. Every still-broken repro then ran in CI and failed the check. Restores develop's tags on the three defects this branch does not fix, and keeps the loading-hang repro untagged — that one is fixed here, so it should run. Also tags `clicking back to segment 2 leaves the step on segment 3` in the selection spec. It is a known defect (fixed in #536) that #527 missed, so it was failing CI untagged. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
…ision ADR 0010 records that currentSegmentIndex is written with two numberings. The same field has a second problem: a change to it does not say whether the user moved the selection or the playhead did. The guided-record step has to guess, and four mechanisms exist to do that guessing - pendingOvershootSwallowRef, the suppressClauseAutoPlay counter (four expected phantom events, a literal nobody can derive), currentSegmentSeq, and the per-event onSegmentClick exemption. ADR 0011 writes up why the intuitive fix - stopping playback precisely at the clause boundary - does not work, since the regions plugin's membership test is inclusive at both ends and contiguous clauses share that boundary. It then documents the two refactors that would: tagging every setCurrentSegment write with its source, and turning targeted region playback into an explicit operation with a lifecycle rather than a race between region-out and a two-frame programmatic-seek window. Cross-referenced from ADR 0010, since both touch the same 17 call sites. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…ed one Parking after an auto-play arms the overshoot swallow, because one spurious region-in on the next clause follows (playback overshoot, or the recorder mounting). The navigation effect only consulted that swallow after its completed-clause branch, so when the clause the overshoot landed on already had a take the step read it as a real move: the label, the yellow selection and the phase all followed, and the clause the user was parked on and about to record went back to pending. Reported from hand testing: record segment 1, arrow forward to segment 3, record it, then arrow back to segment 2. Segment 2 auto-plays as expected, and then segment 3 is left selected. Decide the swallow first, and stop playback inside that branch since it no longer inherits the stop from the code below it. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
develop brought #530's fix and its untagged defects spec, plus TT-7631/TT-7634. The selection spec conflicted on the segment-click test: develop still carries it as the `DEFECT:`/`@known-defect` repro, this branch carries the fixed, untagged version that asserts where the take lands. Kept this branch's version - the fix it asserts is in this PR. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
nabalone
marked this pull request as ready for review
August 25, 2026 21:27
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Split out of #527 so that PR could merge as tests-only. #527 has since merged, so
this now targets
developdirectly and carries the one behaviour fix plus thewrite-up that goes with it.
The bug
Reported from hand testing:
Clicking segment 2 moves the waveform selection and the playhead there, but the
guided-record step stays on segment 3. The next take is uploaded with segment 3's
source-segments, so it lands on top of the take already there. Nothing warns theuser; the label still reads the old segment, and the audio they just recorded for
segment 2 has silently overwritten segment 3's.
Two other reports turn out to be the same fault seen from different angles:
from the engine's index while the label comes from the step's own index, so when
a click reaches only the engine the two disagree (briefly in the recoverable
case, indefinitely in the one above);
Root cause
PassageDetailContext.currentSegmentIndexis written by three places using twodifferent numberings, and nothing forces agreement — the setter takes a bare
index: number:sortedIndex + 1,0= whole)business/player/usePlayerLogic.ts:113— the waveformPassageDetailMarkVerses.tsx(925, 934, 1079, 1389, 1477)PassageDetailGuidedPhraseRecord.tsx— 17 call sitesPassageDetailItem.tsx:246,DiscussionList.tsx:107crud/useWavesurferRegions.tsx:955The step learns the selection moved by watching
currentSegmentIndexchange. Itnever uses the number — it derives its own index from the region via
findClauseIndex— so the field is purely a change signal to it. That is exactlywhy the collision went unnoticed: clicking segment 2 makes the waveform write
1 + 1 = 2, and the step had itself just written2for segment 3. Same value,so the dependency never changed, the navigation effect never re-ran, and the step
stayed put while everything visible moved.
The fix
currentSegmentSeq— a token inPassageDetailContextincremented whenever thecurrent segment actually changes. The step's two navigation effects watch it
instead of inferring a change from the index.
currentSegmentIndexstays in thedependency lists because the value is still read there.
This is deliberately the small fix. Unifying the numbering is the right repair but
touches every caller across Mark Verses, the players and the guided-record step,
and Noel's call is to do it after the next release.
Second fix: an overshoot onto a recorded clause steals the selection
The same navigation effect, the other direction. Reported from hand testing of
this branch:
Parking after an auto-play arms
pendingOvershootSwallowRef, because one spuriousregion-inon the next clause follows it — playback overshooting the clauseend, or the recorder mounting once Record is allowed. The effect only consulted
that swallow after its completed-clause branch, so when the clause the
overshoot landed on already had a take (segment 3 here) that branch took the
overshoot for a real move: the label, the yellow selection and the phase all
followed it, and segment 2 went back to pending under a user who was waiting to
record it. Pressing Record then filed the take on segment 3, over the take
already there.
The swallow is now decided before the completed-clause branch, and stops playback
itself, since it no longer inherits the stop from the code below it.
Test
PassageDetailPhraseBackTranslate.selection.cy.tsx—"follows a click back to an earlier segment and files the take there" loses its
DEFECT:/@known-defectmarking and now asserts the real consequence, not justthe label: the third take's uploaded
source-segmentsis segment 2's span(3–6s), and segment 3 still holds exactly one take.
"keeps the parked segment when playback overshoots onto a recorded one", in the
same spec, covers the second fix. It drives the reported arrow sequence, then
uses the harness's
tapSegment— an engine segment change with no click behindit, which is what that spurious
region-inlooks like to the step — and assertsthat the label and the painted selection both stay on segment 2, that Record stays
armed, and that the next take files at 3–6s with segment 3 still holding exactly
one take.
All four PBT specs on this branch, with
developmerged in: 35 passing, 7pending (
@known-defect), 0 failing.npm testmatchesdevelopexactly - thesame two suites fail there (
MetadataView, on the pre-existingReact.SubmitEventtype error, and aVertListDndsnapshot).ADR 0010
docs/adr/0010-current-segment-index-numbering.mdrecords the whole situation sothe deferred work is actionable: who writes and reads which convention, what it
broke here, the recommended unification (pick 1-based; make the convention
unmissable rather than conventional), and what becomes removable when it happens —
currentSegmentSeq, its ref, and the two dependency-list entries. The otherTT-7621 fixes (#528, #529, #530, #532) are unrelated to the numbering and stay.
It also documents a separate latent off-by-one the same split causes, at
crud/useWavesurferRegions.tsx:955:defaultRegionIndexis the context'scurrentSegmentIndex, so a region load thatreads a 1-based value selects the segment after the current one. Every region
load is affected —
WSAudioPlayer889, 1042, 1370, 1517 (loadRegionsJson, whichSplit, Combine, segment undo and Reset all call). It is not reproducible from PBT
(an effect there continuously re-asserts a 0-based index, so a load usually reads
the right convention by accident); Mark Verses and the generic segment player are
where to look. No fix attempted here.
Review note on the numbering
Every
currentSegmentSeqtouchpoint in this diff is scaffolding around thenumbering split, not something we want permanently. Reviewers: read it as "this
exists because the index cannot be trusted as a change signal", and expect it to
come out with ADR 0010's unification after the next release.