---
active: true
description: "Search-agent Pattern D recipe (counting / aggregation of distinct atoms). Loaded conditionally by render_search_prompt when the question is classified as list-shape. Isolated from the main search_agent prompt so changes to Pattern D do not bleed into Patterns A/B/C/E/F/G/H."
variables: []
---
### Pattern D — Counting / aggregation of distinct atoms
Structure: a complete answer enumerates ≥2 distinct items of the same type, OR is a count / sum / superlative across many candidates. The answer-noun is plural ("books", "games", "items", "trips", "people"), or the question contains a counting/aggregation operator ("how many", "total", "list all", "which X did I do the most/least"). Surface phrasing varies — use the structural test, not phrase matching.
Recipe (mandatory order — do NOT skip steps):
1. `search_user_profiles(query verbatim, top_k=20)` — WIDE first pass. The bi-encoder routinely misses numeric/count-bearing atoms; top_k=20 surfaces more of the candidate set than the default top_k=10.
2. **MANDATORY rehydration**: identify ALL distinct `session_id`s present in step 1's top-20 hits, then call `read_session_text(session_ids=[<every distinct session_id, up to 4>])` in a single call. Counting questions span multiple sessions; passing only ONE `session_id` will miss candidates in other sessions. Do not skip this step.
3. After reading the raw turns, if you observe candidate atoms whose profiles aren't in step 1's results, run one targeted `search_user_profiles(query=<refined query>, top_k=20, rerank=True, refine_with=<distinguishing predicate>)` to surface them — but only one such follow-up.
4. Count from raw turns + profiles together. Dedupe by real-world entity, not by profile_id. Apply the question's predicate strictly.
5. `finish`.

Skip step 2 ONLY when step 1's top_k=20 returns ZERO topic-matching profiles (the topic is absent from memory). In every other case rehydration is required.

**Hard anti-bypass rule (CRITICAL — read before every Pattern D `finish`).** If you are about to call `finish` AND you have not called `read_session_text` for this question AND step 1 returned ANY topic-matching profile, **STOP**. Multiple `search_user_profiles` calls are NOT a substitute for `read_session_text`. The enumerated items live in the source conversation turns, not in the profile summaries — profile compression collapses lists into summary atoms that do not preserve every member.

Failure mode this rule prevents: the agent dispatches to Pattern D, runs 2-4 search calls reformulating the query, finds the topic but not all members, then finishes with the few it found. Result: wrong-because-incomplete answer. The fix is always: stop reformulating, rehydrate the top hits, count from raw turns.

Reasoning hint: Count only atoms satisfying every predicate. Separate candidates into qualifies, related-but-not-qualifying, duplicate, and superseded. Dedupe by real-world item/project/event, not profile id. For action/status questions, require the action/status words in the evidence (pickup/return, led/currently leading), not merely membership in the broad category. If the predicate contains alternatives ("pick up or return", "led or currently leading"), count atoms satisfying either branch, but do not infer a branch from unrelated context.
Rerank: prefer `rerank=False` on the wide first pass (you want recall); prefer `rerank=True` on the focused second pass with `refine_with` set to the qualifying predicate, so duplicates and near-misses get pushed below the qualifying atoms. **Exception — category-listing/superlative when items are branded** (e.g. "which grocery store did I spend most at", "list all my streaming subscriptions", "how many luxury items did I buy" — questions where the items are likely brand/proper-noun atoms that don't share the literal category keyword): set `llm_rerank=True` on the wide first pass so brand-mentioning profiles are scored as members of the category. **Do NOT skip the mandatory rehydration step** — counting still needs raw-turn enumeration; the rerank only changes which profiles surface, not whether you cross-check raw turns.
Rehydration use: see step 2 of the Recipe — mandatory, before counting, no exceptions outside the absent-topic case.
