Skip to content

Auto-link reliability: punctuation-blind name matching and an event-driven transcript wait - #3

Open
nicw wants to merge 2 commits into
dloomis:mainfrom
nicw:pr/auto-link-reliability
Open

Auto-link reliability: punctuation-blind name matching and an event-driven transcript wait#3
nicw wants to merge 2 commits into
dloomis:mainfrom
nicw:pr/auto-link-reliability

Conversation

@nicw

@nicw nicw commented Jul 30, 2026

Copy link
Copy Markdown

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. normalizeMeetingName moves to utils/meetingName.ts and 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 TranscriptWait module: the file wait re-arms on metadataCache "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's findReady probe (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 /status describes 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 /status failure tolerance, the reconcileRecordingLock hand-off, and a cross-link guard superseded by the namePrefix scan restriction + guid rejection.

Tests: 16 (9 name normalization, 7 transcript wait), plus an npm test script (no new deps).

Notes for review:

Tested on this branch against v0.8.7: npm run build, npm run lint, npm test (16/16).

🤖 Generated with Claude Code

nicw and others added 2 commits July 29, 2026 21:18
…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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant