Skip to content

9.6 Challenger promises view (3 pts) #62

Closed

Description

@developer-ainative

Epic: E9 — Promise collection and extraction
Points: 3 · Priority: Must · Iteration: 7

As a voter, I want to see a challenger's promises even though they have no voting record, so that I can still compare them.

Acceptance criteria:
Promises are grouped by my interests; a prior record in another office is linked if one exists.

ZeroDB data: promises


Source: backlog.md, story 9.6

Activity

  1. developer-ainative commented on Oct 20, 2026

    @developer-ainative
    ContributorAuthor

    Closed by PR #184 (merged).

    GET /v1/candidates/{id}/promises?profile_id= groups a challenger's promises by the voter's own stance_id — the same key AlignmentReason already groups by for incumbents — since a challenger has no candidate_positions rows to drive the existing /alignment endpoint. Promises outside the voter's stated interests are counted in unmatched_count, never silently dropped. A promise with no resolvable promise_sources citation is omitted rather than shown uncited. Prior office comes from people.terms[] — any term whose district isn't the current candidacy's own seat — reusing data app.ballot.service already reads, never fabricated.

    frontend/src/candidate/ChallengerPromisesView.tsx reuses story 7.5's Drawer for each promise's source citation, wired into BallotPage.tsx so incumbents route to CandidateDetailPage and challengers route here — a small, backward-compatible widening of BallotView's existing onViewDetails callback to also carry isIncumbent.

    Honest state of live data, stated plainly rather than glossed over: the live promises table is empty, confirmed by story 9.4/9.5's finding (PR #182) that the real extractor currently produces zero genuine promises against all 6 live promise_sources rows. This endpoint and view are built and tested only against synthetic fixtures — no live verification script was run or claimed, and every real candidate today correctly shows the honest 'no promises on file yet' empty state rather than a populated-looking fixture presented as live data.

    Judgment calls flagged for review: 'linked' prior office is a plain text notice, not a hyperlink, since there's nothing real yet to link to; /alignment was kept untouched rather than widened to also carry promises, since unscored promise data and scored position data shouldn't mix in one response shape.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions