Skip to content

Richer agenda→topic matching for preview summaries #100

@AndreRobitaille

Description

@AndreRobitaille

Context

Shipped in commit eb9ae71: agenda-preview summaries inject relevant TopicBriefing content into the analyze_meeting_content prompt when a topic name or alias appears as a substring in the agenda text. This lets the AI ground preview summaries in established civic concerns rather than treating each agenda item as an isolated title.

The Limitation

Substring matching has poor recall when agenda phrasing diverges from how a topic was named during extraction. Real example from meeting 173 (Advisory Recreation Board, 2026-04-15):

  • Agenda item: "Cemetery Flower Planting Ordinance Change"
  • Existing topic: #563 cemetery perpetual care flowers (impact score 3, 5 appearances)
  • Topic aliases: cemetery perpetual care flowers funding, perpetual care flower fund for the cemetery, update on cemetery perpetual flower program, investment fund for perpetual care flowers and community band
  • Topic briefing headline: "Council voted 9-0 to fund cemetery flowers for 2026, but the paperwork didn't match the dollar plan"

No alias is a literal substring of the agenda phrasing (Cemetery Flower Planting), so the briefing never surfaces. The AI writes a flat sentence about perennials vs annuals, missing the live paperwork-mismatch context residents have been tracking.

Same pattern likely repeats for other committee agendas where civic topic names are formal (perpetual care flowers funding) but agenda items use different wording (Flower Planting Ordinance Change).

Possible Approaches (ordered by scope)

1. Admin-managed alias broadening

When a topic's briefing is created/refreshed, surface candidate agenda phrasings and let admins add them as TopicAlias rows. Lowest code effort, highest manual burden.

2. Token-overlap matching

Replace pure substring match with a bag-of-content-words comparison. For each topic (and its aliases), check if N% of its content tokens appear within a window of agenda text. Would catch cemetery + flower + planting overlap between cemetery perpetual care flowers and Cemetery Flower Planting. Needs tuning to avoid false positives on generic vocabulary.

3. Vector-similarity match against topic embeddings

Embed each topic's name + description + briefing headline into pgvector. Split agenda text into items; embed each; for each agenda item, cosine-match against topic vectors; inject the top matches. Most semantically aware, highest infrastructure cost, but reuses existing VectorService stack.

4. Hybrid

Start with approach 2 (token overlap) as an additive path beside the current substring match. If that still misses important cases, layer in approach 3. Approach 1 is always available as a manual escape hatch.

Notes

  • The current substring matcher ships in app/jobs/summarize_meeting_job.rb as agenda_topic_context. It's scoped to agenda_preview mode only; full mode (packet / transcript / minutes) does not use topic-context injection yet.
  • Any richer matching approach should also consider extending to full mode — minutes summaries currently don't receive per-topic briefing context at the meeting level either, though they do get it per-topic inside generate_topic_summaries.
  • Filter thresholds in the current implementation (AGENDA_TOPIC_MIN_WORDS = 2, AGENDA_TOPIC_MIN_CHARS = 15, AGENDA_TOPIC_MIN_IMPACT = 3) are tuned to avoid over-matching. Any replacement should preserve the over-match protection.

Acceptance criteria (future)

  • Meeting 173's "Cemetery Flower Planting Ordinance Change" item surfaces topic 563's briefing context in the agenda preview.
  • Meeting 173's concession stand item continues to surface topic 564's briefing (regression guard).
  • No false-positive topic injections (e.g. topic construction not injected for every meeting that mentions the word).
  • Approach documented with tradeoffs, tuning parameters, and test coverage.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions