@@ -31,8 +31,12 @@ and optionally apply fixes.
3131 accepts both ` project_uid ` and ` committee_uid ` can only send one at a time.
3232- ` handleSearchPastMeetingParticipants ` and ` handleSearchPastMeetingSummaries `
3333 are dedicated handlers — each owns its own filter logic independently.
34- - When sampling documents, use ` "size": 3 ` to keep output small. Use
35- ` _source ` filtering to request only ` tags ` and ` parent_refs ` fields.
34+ - ** Prefer count-only queries over random sampling.** A handful of random
35+ documents proves nothing — you can get lucky and see the right fields while
36+ 90% of the corpus has them missing. Always run ` "size": 0 ` prefix count
37+ queries first. Only pull sample documents (` "size": 3 ` ) as a secondary
38+ debugging aid when a count is zero or surprising (e.g. to understand what
39+ fields are actually present on that resource type).
3640
3741## Step 1 — Discover infrastructure
3842
@@ -64,19 +68,32 @@ Substitute the kubectl context as needed to target dev vs. prod.
6468
6569## Step 2 — Enumerate search tools and their filter mappings
6670
67- Read every ` *Args ` struct in ` internal/tools/ ` and record how each filter
71+ ** Do not rely solely on the reference table below — always grep the codebase
72+ first** to find every file that calls ` QueryResources ` . The table may be out of
73+ date if new tools have been added since it was last updated.
74+
75+ ``` bash
76+ grep -rEn " QueryResources|QueryResourcesPayload" internal/tools/ | grep -v " _test.go"
77+ ```
78+
79+ For each file that appears, read the handler and record how each filter
6880parameter is sent to the query service. The mechanisms are:
6981
7082| Mechanism | Query service field | Index field |
7183| ---| ---| ---|
7284| ` payload.Parent = "<type>:<uid>" ` | ` Parent ` | ` parent_refs ` |
7385| ` payload.Tags = ["<key>:<value>"] ` | ` Tags ` | ` tags ` |
7486| ` payload.Filters = ["<field>:<value>"] ` | ` Filters ` | top-level doc fields |
87+ | ` payload.FiltersAll = ["<field>:<value>"] ` | ` FiltersAll ` | top-level doc fields (AND semantics) |
7588| ` payload.Name = "<value>" ` | ` Name ` | ` name ` (text search) |
7689| ` payload.DateField ` / ` DateFrom ` / ` DateTo ` | date range | date fields |
7790
78- Current tools using the query service SDK and their structured filter parameters
79- (update this list if new tools are added):
91+ Only ` Parent ` , ` Tags ` , ` Filters ` , and ` FiltersAll ` are structural filters that
92+ map to indexed fields — these are the ones to validate. ` Name ` and date fields
93+ are query-time text/range operations and do not need index field verification.
94+
95+ Reference table of known tools and their structured filter parameters (verify
96+ against the grep output above before trusting this):
8097
8198| Tool | Resource type | Parameter | Mechanism | Sent as |
8299| ---| ---| ---| ---| ---|
@@ -98,8 +115,13 @@ Current tools using the query service SDK and their structured filter parameters
98115| ` search_past_meeting_participants ` | ` v1_past_meeting_participant ` | ` project_uid ` | Parent (fallback) | ` project:<uid> ` |
99116| ` search_past_meeting_summaries ` | ` v1_past_meeting_summary ` | ` past_meeting_id ` | Parent (preferred) | ` past_meeting:<meeting_and_occurrence_id> ` |
100117| ` search_past_meeting_summaries ` | ` v1_past_meeting_summary ` | ` project_uid ` | Parent (fallback) | ` project:<uid> ` |
101-
102- Re-read the handler code to verify this table is current before proceeding.
118+ | ` search_members ` | ` project_membership ` | ` project_uid ` | FiltersAll | ` project_uid:<uid> ` |
119+ | ` search_members ` | ` project_membership ` | ` b2b_org_uid ` | FiltersAll | ` b2b_org_uid:<uid> ` |
120+ | ` search_members ` | ` project_membership ` | ` tier_uid ` | FiltersAll | ` tier_uid:<uid> ` |
121+ | ` search_members ` | ` project_membership ` | ` tier_name ` | FiltersAll | ` tier_name:<name> ` |
122+ | ` search_members ` | ` project_membership ` | ` status ` | FiltersAll | ` status:Active ` (hardcoded default) |
123+ | ` get_membership_key_contacts ` | ` key_contact ` | ` membership_uid ` | FiltersAll | ` membership_uid:<uid> ` |
124+ | ` search_b2b_orgs ` | ` b2b_org ` | * (none — Name only)* | — | — |
103125
104126## Step 3 — Fetch indexer contracts
105127
@@ -126,82 +148,87 @@ for each resource type. Record which tag keys and parent_ref prefixes the
126148contract defines. If a URL 404s or has no contract doc, note it and continue —
127149treat those filters as "no contract definition" in the report.
128150
129- ## Step 4 — Sample the live index
151+ ## Step 4 — Count hits in the live index
152+
153+ For each filter parameter, run a ** count-only query** (` "size": 0 ` ) via the
154+ NATS box. This is the primary evidence step. Use the ` $NATS_POD ` and
155+ ` $OPENSEARCH_BASEURL ` variables set in Step 1.
130156
131- For each resource type, run the following queries via the NATS box. Use the
132- ` $NATS_POD ` and ` $OPENSEARCH_BASEURL ` variables set in Step 1.
157+ > ** Note:** These queries omit ` track_total_hits: true ` , so ` hits.total.value `
158+ > may be capped on very large indices. This is intentional — an approximate
159+ > count is sufficient to confirm a field is populated. Check ` hits.total.relation `
160+ > in the response: ` "eq" ` means the count is exact; ` "gte" ` means it is a lower
161+ > bound and the true total is higher.
133162
134- ** Sample tags and parent_refs from 3 recently indexed documents (last 45 days):**
163+ ** Count documents where a specific tag key has non-empty values (last 45 days):**
135164
136165``` bash
137166kubectl exec -n lfx " $NATS_POD " -- \
138167 curl -s --max-time 15 -X GET " $OPENSEARCH_BASEURL /_search" \
139168 -H ' Content-Type: application/json' \
140169 -d ' {
141- "size": 3,
142- "_source": ["tags", "parent_refs", "object_type"],
170+ "size": 0,
143171 "query": {
144172 "bool": {
145173 "must": [
146174 { "term": { "object_type": "<RESOURCE_TYPE>" } },
175+ { "prefix": { "tags": "<TAG_KEY>:" } },
147176 { "range": { "updated_at": { "gte": "now-45d" } } }
177+ ],
178+ "must_not": [
179+ { "term": { "tags": "<TAG_KEY>:" } }
148180 ]
149181 }
150182 }
151183 }'
152184```
153185
154- ** Check whether a specific tag key has any non-empty values (last 45 days):**
186+ ** Count documents where a specific parent_ref prefix exists (last 45 days):**
155187
156188``` bash
157189kubectl exec -n lfx " $NATS_POD " -- \
158190 curl -s --max-time 15 -X GET " $OPENSEARCH_BASEURL /_search" \
159191 -H ' Content-Type: application/json' \
160192 -d ' {
161- "size": 1,
162- "_source": ["tags"],
193+ "size": 0,
163194 "query": {
164195 "bool": {
165196 "must": [
166197 { "term": { "object_type": "<RESOURCE_TYPE>" } },
167- { "prefix": { "tags ": "<TAG_KEY >:" } },
198+ { "prefix": { "parent_refs ": "<PREFIX >:" } },
168199 { "range": { "updated_at": { "gte": "now-45d" } } }
169- ],
170- "must_not": [
171- { "term": { "tags": "<TAG_KEY>:" } }
172200 ]
173201 }
174202 }
175203 }'
176204```
177205
178- ** Check whether a specific parent_ref prefix exists (last 45 days):**
206+ Record the ` hits.total.value ` from each response. A non-zero count confirms the
207+ key/prefix is present in recently indexed data. If the count is zero but the
208+ resource type has older data, note it as "not seen in last 45 days" rather
209+ than immediately marking it broken.
210+
211+ ** Only when a count is zero or surprising** , pull a small sample to understand
212+ what fields are actually present on that resource type:
179213
180214``` bash
181215kubectl exec -n lfx " $NATS_POD " -- \
182216 curl -s --max-time 15 -X GET " $OPENSEARCH_BASEURL /_search" \
183217 -H ' Content-Type: application/json' \
184218 -d ' {
185- "size": 1 ,
186- "_source": ["parent_refs"],
219+ "size": 3 ,
220+ "_source": ["tags", " parent_refs", "object_type "],
187221 "query": {
188222 "bool": {
189223 "must": [
190224 { "term": { "object_type": "<RESOURCE_TYPE>" } },
191- { "prefix": { "parent_refs": "<PREFIX>:" } },
192225 { "range": { "updated_at": { "gte": "now-45d" } } }
193226 ]
194227 }
195228 }
196229 }'
197230```
198231
199- Record the ` total.value ` from each response. A non-zero value confirms the
200- key/prefix is present in recently indexed data. If the count is zero but the
201- resource type has older data, note it as "not seen in last 45 days" rather
202- than immediately marking it broken — check the sample query to understand
203- overall coverage before rendering a verdict.
204-
205232## Step 5 — Build the truth table
206233
207234Cross-reference: tool parameter → mechanism → contract definition → index
@@ -256,6 +283,6 @@ After applying fixes, run `make build` to confirm compilation succeeds.
256283
257284## Step 8 — Verify fixes
258285
259- Re-run the targeted ` curl ` queries from Step 4 against the corrected
286+ Re-run the count-only queries from Step 4 against the corrected
260287mechanism to confirm non-zero results. Report before/after hit counts for
261288each fixed filter.
0 commit comments