Insights: the sources tables' Interviews column and the Interviews widget count different things #449

Closed
opened 2026-10-01 10:46:47 +00:00 by tiagoagueda · 0 comments
Owner

Found on 2026-09-29 in a read-only review of postulo at 95348908d, comparing how the Insights figures define "reached an interview".

Related to #224.

Checked again on 2026-10-01 against main at 0a5cad587: still present.

Two figures on the same Insights dashboard both claim to count applications that reached an interview, and they use different rules. The Interviews column of the sources tables counts applications whose status ever reached Screening, Interviewing or Assessment; the Interviews widget counts applications with an interview entry on the timeline. They disagree whenever a person moves a status without recording an interview, or records one without moving the status.

  • Where:
    • applications/analytics.py:492-493, the count helper inside build: if statuses & {Status.INTERVIEWING, Status.SCREENING, Status.ASSESSMENT}: row.interviewed += 1. Feeds the Interviews column of Where they came from, By referrer, By agency and By industry (templates/widgets/_source_table.html:14, :30).
    • applications/analytics.py:457-458: interview_days = _first_interview_days(ever_applied); insights.interviewed = len(interview_days), which reads EventKind.INTERVIEW entries (:264-287). Shown as Applications that reached one (templates/widgets/interviews_summary.html:8).
    • postulo.wiki/Insights.md:59-68 describes both as how many applications "reached" an interview.
  • What happens: three applications are moved to Screening after a recruiter's call and no interview is recorded: the sources table shows 3 under Interviews and the widget says 0 applications reached one. The other way round, an interview typed onto the timeline of an application whose status was never moved (for example one already rejected, which settle_interview deliberately does not reopen) counts in the widget and not in the column.
  • Why it matters: the sources table is the figure the wiki calls "most likely to change what you do", and its Interviews column is not what the Interviews widget beside it means by an interview, so the two cannot be compared or reconciled by the reader.
  • Fix: decide one rule, for example "has an interview entry, or reached Interviewing or Assessment", compute it once per application in build into a set of ids, and use that set for both insights.interviewed and SourceRow.interviewed. If Screening is meant to count, name the column for what it counts instead (for example Screened or further) and say so in Insights.md.

Done when

  • A test in tests/test_insights.py builds insights for an application moved to Screening with no interview entry and one with an interview entry but no interview-stage status, and asserts that the widget's count and the sources row's count agree; it fails today.
Found on 2026-09-29 in a read-only review of postulo at 95348908d, comparing how the Insights figures define "reached an interview". Related to #224. Checked again on 2026-10-01 against `main` at `0a5cad587`: still present. Two figures on the same Insights dashboard both claim to count applications that reached an interview, and they use different rules. The *Interviews* column of the sources tables counts applications whose status ever reached Screening, Interviewing or Assessment; the Interviews widget counts applications with an *interview* entry on the timeline. They disagree whenever a person moves a status without recording an interview, or records one without moving the status. - **Where:** - `applications/analytics.py:492-493`, the `count` helper inside `build`: `if statuses & {Status.INTERVIEWING, Status.SCREENING, Status.ASSESSMENT}: row.interviewed += 1`. Feeds the *Interviews* column of *Where they came from*, *By referrer*, *By agency* and *By industry* (`templates/widgets/_source_table.html:14`, `:30`). - `applications/analytics.py:457-458`: `interview_days = _first_interview_days(ever_applied)`; `insights.interviewed = len(interview_days)`, which reads `EventKind.INTERVIEW` entries (`:264-287`). Shown as *Applications that reached one* (`templates/widgets/interviews_summary.html:8`). - `postulo.wiki/Insights.md:59-68` describes both as how many applications "reached" an interview. - **What happens:** three applications are moved to *Screening* after a recruiter's call and no interview is recorded: the sources table shows 3 under *Interviews* and the widget says 0 applications reached one. The other way round, an interview typed onto the timeline of an application whose status was never moved (for example one already rejected, which `settle_interview` deliberately does not reopen) counts in the widget and not in the column. - **Why it matters:** the sources table is the figure the wiki calls "most likely to change what you do", and its *Interviews* column is not what the Interviews widget beside it means by an interview, so the two cannot be compared or reconciled by the reader. - **Fix:** decide one rule, for example "has an *interview* entry, or reached *Interviewing* or *Assessment*", compute it once per application in `build` into a set of ids, and use that set for both `insights.interviewed` and `SourceRow.interviewed`. If Screening is meant to count, name the column for what it counts instead (for example *Screened or further*) and say so in `Insights.md`. ## Done when - A test in `tests/test_insights.py` builds insights for an application moved to *Screening* with no interview entry and one with an interview entry but no interview-stage status, and asserts that the widget's count and the sources row's count agree; it fails today.
tiagoagueda added this to the 0.6.0 milestone 2026-10-01 10:46:47 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
Postulo/postulo#449
No description provided.