Skip to content

fix(x): stop KG agent from rewriting meeting notes; gate People notes on calendar attendees - #785

Open
arkml wants to merge 2 commits into
mainfrom
fix/kg-meeting-note-protection
Open

fix(x): stop KG agent from rewriting meeting notes; gate People notes on calendar attendees#785
arkml wants to merge 2 commits into
mainfrom
fix/kg-meeting-note-protection

Conversation

@arkml

@arkml arkml commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

Problem

Two user-reported bugs, root-caused via the knowledge repo's git history:

  1. Meeting summaries destroyed. The note_creation agent treated knowledge/Meetings/ as one of its own writable note types (an empty "Meetings" template was rendered into its prompt, and nothing marked source files read-only). On the graph tick after a meeting ended it rewrote the recorded note into an invented entity format, replacing the detailed summary + transcript with ~3 lines. Git evidence: Research_reading.md went 60KB → 1,073 bytes mid-recording (only the recorder's 1s debounced rewrite restored it), and the agent fabricated a duplicate meeting-<timestamp>.md entity note alongside it.
  2. Phantom people. Meeting notes were processed while still being recorded (the file changes every ~1s, so every 15s tick re-ran the LLM on the growing transcript — ~20 runs in one meeting), minting People notes from speech-recognition name variants: one attendee "Shubham" became Shubham.md, Shubhrant.md, and Shivam.md, plus 47-byte stubs for other misheard names.

Fixes

Meeting sources are read-only to the KG agent (prompt + mechanical guard)

  • Empty-template note types (Meetings) no longer render into the agent prompt (note_system.ts)
  • New non-negotiable prompt rules: source files are read-only; there is no "meeting note" type to create or update (note_creation.ts, batch message in build_graph.ts)
  • revertAgentSourceWrites backstop: a Pre-agent snapshot commit runs before every agent batch; any agent write under knowledge/Meetings/, knowledge/Voice Memos/, gmail_sync/, or knowledge_sources/ is restored from the batch snapshot / git HEAD, or deleted if the agent created it (deletion requires the repo to have a HEAD commit, so a fresh install can never lose data). Reverts surface as warn service-log events. Wired into both the main batch loop and the voice-memo loop.

In-flight recordings are held

  • MEETING_NOTE_QUIET_MS (6 min, above the recorder's 5-min silence backstop): meeting-source files are skipped until they stop changing — one LLM run per meeting instead of ~20, and no partial-transcript processing.

People notes anchored to the calendar invite

  • The recorder stamps the invite's attendees ("Name <email>") into the note's calendar_event frontmatter, resolved from the linked event file or passed through from the detector/notification flow (useMeetingTranscription.ts, App.tsx, calendar-block.tsx)
  • meetingAttendeesBanner stamps an authoritative ATTENDEES-GATE onto each rowboat-recorded source (frontmatter attendees → linked event file → calendar_sync scan by exact title+start): new People notes only for listed attendees — teammates on the invite included; similar-sounding transcript names resolve to ONE attendee's note (variant spellings go to Aliases); ad-hoc recordings with no invite create no People notes at all, though names still appear in summaries
  • Granola/Fireflies notes are not gated (platform-reported attendee lists are trusted)

Testing

  • npm run deps, npm run typecheck clean; lint errors are pre-existing in untouched files
  • 536/536 core tests pass, including 3 new meetingAttendeesBanner tests (non-rowboat sources ignored, stamped attendees listed, ad-hoc → no-People banner)

🤖 Generated with Claude Code

arkml and others added 2 commits July 23, 2026 23:21
… on calendar attendees

The note_creation agent treated knowledge/Meetings/ as one of its own
writable note types (an empty "Meetings" template was rendered into its
prompt), so it rewrote recorded meeting notes into an invented entity
format — destroying the post-meeting summary and transcript — and
fabricated duplicate "meeting entity" notes. It also processed notes
mid-recording (the file changes every ~1s, so every 15s tick re-ran the
LLM on the growing transcript) and minted People notes from ASR name
variants ("Shubham" heard as "Shubhrant"/"Shivam") with no attendee
ground truth.

Fixes:
- Source files are read-only to the agent: empty-template note types no
  longer render into the prompt; new non-negotiable prompt rules; and a
  mechanical guard (revertAgentSourceWrites) that snapshots the
  knowledge repo before each agent batch and restores/deletes any agent
  write under knowledge/Meetings/, knowledge/Voice Memos/, gmail_sync/,
  or knowledge_sources/ (deletes only when the repo has a HEAD commit).
  Reverts are logged as warn service events.
- In-flight recordings are held: meeting-source files modified within
  the last 6 minutes (above the recorder's 5-minute silence backstop)
  are skipped until quiet — one LLM run per meeting instead of ~20.
- People notes anchored to the calendar invite: the recorder stamps the
  invite's attendees into the note's calendar_event frontmatter, and
  build_graph emits an authoritative ATTENDEES-GATE banner per recorded
  meeting (frontmatter → linked event file → calendar_sync title+start
  match). New People notes only for listed attendees (teammates on the
  invite included); similar-sounding transcript names resolve to one
  attendee note via Aliases; ad-hoc recordings with no invite create no
  People notes at all — names still appear in summaries.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
People sometimes join a meeting without being on the calendar invite.
Previously the summarizer's hard "attendee names only" rule left them
permanently unnamed ("They"), and the new ATTENDEES-GATE wording could
be read as blocking even updates to their existing People note.

- Summary: a non-attendee name may be used when the transcript clearly
  supports it (introduced/addressed by that name repeatedly), with one
  canonical spelling for similar-sounding ASR variants; a name heard
  once or inconsistently stays "They".
- Knowledge graph: an off-list transcript name that clearly matches an
  EXISTING People note (name/alias plus context) may update that note;
  creating a new note for anyone off the invite stays forbidden.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@arkml

arkml commented Jul 23, 2026

Copy link
Copy Markdown
Contributor Author

Follow-up commit (0206b0f) for uninvited joiners — people who join a meeting without being on the invite:

  • Summary: may name them when the transcript clearly supports it (introduced/addressed by that name repeatedly), using one canonical spelling for similar-sounding ASR variants; a name heard once or inconsistently stays "They".
  • Knowledge graph: an off-list name that clearly matches an existing People note may update that note (so a teammate who drops in still accrues the meeting on their note); creating a new note for anyone off the invite remains forbidden.

🤖 Generated with Claude Code

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