Skip to content

Link motions to agenda items in ExtractVotesJob #76

@AndreRobitaille

Description

@AndreRobitaille

Problem

`Motion` has a `belongs_to :agenda_item` association, but `ExtractVotesJob` never populates `agenda_item_id`. All motions currently have `agenda_item_id: nil`.

This means:

  • Cannot trace votes to topics — the chain `Vote → Motion → AgendaItem → AgendaItemTopic → Topic` is broken, so we can't show "history of votes on a particular topic"
  • Topic page "Key Decisions" section is empty for all topics — even topics with documented contracts and votes show "No votes or motions recorded." This is the biggest credibility gap on topic pages (see Topic page UI/UX overhaul — visual hierarchy, affordances, intuitiveness #63).
  • Cannot show vote detail per agenda item — the meeting show page can't render database-backed vote grids per item

Why this matters now

The homepage redesign (Apr 10, 2026) creates a newspaper-style front page linking to topic pages. The topic page needs to be a credible landing page, but Key Decisions being empty for topics with clear votes (e.g., lead service lines has a $2.4M contract mentioned in its Record section but zero Key Decisions) makes the site look broken. This is the #1 blocker for making topic pages the primary homepage destination.

What Works Today

  • `Vote → Motion → Meeting` — member votes per meeting ✓
  • `Motion → Meeting → Committee` — which committee ✓
  • `Vote → Member` — who voted how ✓

What Needs to Change

`ExtractVotesJob` (which calls `Ai::OpenAiService#extract_votes`) needs to:

  1. Include agenda item context in the extraction prompt — pass agenda item IDs and titles alongside the minutes text so the AI can match motions to items
  2. Return `agenda_item_id` in the structured response for each motion
  3. Populate `Motion.agenda_item_id` when creating/updating motion records

The AI already reads minutes text that contains motion descriptions adjacent to agenda item discussions. The matching should be straightforward for most motions. Some motions (like consent agenda batch approvals) may not map cleanly to a single item — those can have `agenda_item_id: nil` and that's fine.

Enables

Backfill

After fixing `ExtractVotesJob`, re-run for all meetings with minutes to populate `agenda_item_id` on existing motions. The job is idempotent (uses `find_or_create_by`).

Not in Scope

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