Auto-link reliability: punctuation-blind name matching and an event-driven transcript wait - #3
Open
nicw wants to merge 2 commits into
Open
Auto-link reliability: punctuation-blind name matching and an event-driven transcript wait#3nicw wants to merge 2 commits into
nicw wants to merge 2 commits into
Conversation
…tion findObviousMeeting compares a calendar subject against a transcript/note title that came through filename sanitization, which drops characters like "/" and '"'. The old whitespace-collapsing normalization could never equate the two forms, so any subject containing those characters silently failed to auto-link. Normalize to lowercase alphanumerics (keeping Unicode letters) so both sides erase the asymmetry, and move the helper to src/utils with unit tests. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…d poll budget The link tail used to wait for the transcript file with a fixed budget of 1-second polls, but the recording service's post-processing can land the final export minutes after capture ends — a budget that expired before the export landed silently killed auto-linking. Replace the fixed waits with an event-driven wait (metadataCache "changed" scoped to the transcript folder, plus a periodic belt-and-braces recheck) bounded by a wall-clock cap. The session-guid match ladder is hoisted into a findReady closure the wait re-runs on every change signal, so a service-reported filename learned during the status poll still beats the heuristics, and the newest-file fallback now also refuses a candidate already linked to some other meeting note. The status poll is skipped entirely when a transcript is already in the vault (a reconcile hand-off can arrive when /status already describes a different meeting), and the status poll's give-up paths now fall through to the file wait instead of abandoning an export that merely ran long. In-flight waits register cancel hooks so plugin unload releases their listeners immediately. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This was referenced Jul 30, 2026
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.
Closes two auto-link gaps, one per commit.
1. Punctuation-blind meeting-name matching. Filename sanitization drops
/and quotes, so a calendar subject like "Platform / Data Weekly Sync" can never equal its transcript/note title under the current normalizer (whitespace collapse only) — those meetings sit in the unlinked list forever unless a session guid links them.normalizeMeetingNamemoves toutils/meetingName.tsand now strips all non-alphanumerics (Unicode-aware, so non-ASCII names don't collapse below the too-generic length guard). This still matters with guid matching in place: the name matcher is the only recovery for un-stamped/legacy transcripts and for guid-stamped notes that were deleted and recreated.2. Event-driven transcript wait. The recording service's post-processing can land the final export minutes after capture ends. Today the post-poll file wait is 15×1 s, and the status-poll give-up paths return "Transcript not ready" without ever checking disk again — the session then only recovers on the next reload (persistence) or unlinked-list refresh. This PR adds a
TranscriptWaitmodule: the file wait re-arms onmetadataCache"changed" events (30-min cap, 30-s belt recheck, cancelled immediately on plugin unload). The session-guid match ladder is preserved intact as the wait'sfindReadyprobe (rung order unchanged; the newest-file rung additionally rejects candidates already linked to another note), the status poll is skipped when a finalized transcript is already on disk (a reconcile/watch hand-off can arrive after/statusdescribes a different meeting), and the give-up paths now fall through to the event wait. The terminal "failed" path still removes persistence and does not fall through.Deliberately not ported from my local branch, because upstream already covers them (as well or better): watch-loop
/statusfailure tolerance, thereconcileRecordingLockhand-off, and a cross-link guard superseded by thenamePrefixscan restriction + guid rejection.Tests: 16 (9 name normalization, 7 transcript wait), plus an
npm testscript (no new deps).Notes for review:
findReadyshould also gate acceptance onhasLiveLegLabels. Kept out of this PR to avoid overlapping diffs.package.jsontest-list union conflict — I'll rebase.Tested on this branch against v0.8.7:
npm run build,npm run lint,npm test(16/16).🤖 Generated with Claude Code