Skip to content

feat(signals): record personal ranking readiness on Inbox viewed #134818

Closed

Description

@andrewm4894

Related: #131415, #129978, #133661.

Problem

We can't tell from product analytics whether a person had a personal ranking ready when they opened the inbox.

  • Inbox viewed carries no personal ranking state. It has report counts by priority and actionability, but no sort, no ranker, and nothing about the viewer's stored personal ranking.
  • The list response only names a ranker for model sorts. ranker and ranking_id are null for every sort except recommended and personal, so a view under the default sort says nothing about whether a personal ranking existed.
  • There is no eligibility count. A personal ranking needs at least 2 of the viewer's own reports to change any order. Nothing on the event says how many reports are routed to the viewer, so "no ranking yet" can't be separated from "nothing to rank".

Today the only way to answer "was a ranking ready on a person's second visit" is a warehouse join from inbox views to personal inbox ranking built events through user email. That join is slow, web only, and can't see eligibility.

Proposed behavior

Inbox viewed reports the viewer's personal ranking state at the moment the inbox loaded.

Read products/signals/frontend/inbox/inboxAnalytics.ts, products/signals/frontend/inbox/components/tabs/ReportsTab.tsx, and products/signals/backend/personal_ranking/serve.py and list_sort.py first.

  1. Return the viewer's personal ranking status with the first page of the report list. Add a personal_ranking_status object to the list response, for every sort, on the first page only. It reads the stored ranking row and never starts a build. Fields:

    • state: real (status ok, personalized, 2 or more reports), one_report, not_personalized, empty, fallback, or none (no stored ranking).
    • size: reports in the stored ranking, null for none.
    • age_minutes: minutes since the ranking was built, null for none.
    • checked_age_minutes: minutes since the scheduled tick last confirmed the ranking's inputs, null for none.
    • fallback_reason: the stored reason for fallback, else null.

    It is null when the personal-inbox-ranking flag is off for the viewer. It always describes the viewer's own ranking, also with scope=teammate.

  2. Add these properties to Inbox viewed: personal_list_state, personal_list_size, personal_list_age_minutes, personal_list_checked_age_minutes, personal_list_fallback_reason, from the status object. Send null for each when the status is null.

  3. Add the eligibility count. for_you_report_count: the number of reports in the viewer's "For you" scope across the states that already make up Inbox viewed. Reuse a count the scene already loads if there is one. If it needs a new request, say so in the PR and keep it off the critical path.

  4. Add the served order. sort_field and ranker_id on Inbox viewed, with the same meaning as on Inbox reports impressed.

Acceptance criteria

  • The first page of the report list returns personal_ranking_status for every sort when the flag is on for the viewer, and null when it is off.
  • Later pages don't run the status read.
  • Reading the status never starts or queues a build.
  • state is real only for a stored ranking with status ok, personalized, and 2 or more reports. A test covers each state.
  • With scope=teammate, the status still describes the viewer's ranking.
  • Inbox viewed carries the five personal_list_* properties, for_you_report_count, sort_field and ranker_id.
  • Inbox viewed still fires once per view, and no later than it does today.
  • The status read adds at most one indexed query to the first page. State the query count before and after in the PR.
  • The OpenAPI types are regenerated and the frontend reads the generated type.

Scope

Web inbox list endpoint and Inbox viewed only.

Not in this issue:

  • The desktop app's Inbox viewed. It sends the same event name, so it should get the same properties later, in its own repository.
  • Changing which sort is the default.
  • Building a ranking on demand when the status is none.
  • Dashboards or warehouse views that read the new properties.

Activity

  1. posthog commented on Nov 12, 2026

    @posthog
    Contributor

    PostHog self-driving picked up this issue. Status: No further self-driving work is planned on this.

    Somebody may already be working on it, so ask before you start a fix.

    Report (team access only): https://us.posthog.com/project/2/inbox/reports/13491ca7-ca17-4b87-a865-d4aa82e3a1ec?link_source=github_comment

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

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions