Repository navigation
fix(#11370): find authored reports by submitter, not freetext contact - #11378
Conversation
…ntact Master's medic#11371 moved the report-author indexing out of reports_by_freetext and into docs_by_replication_key as a searchable submitter field, on the grounds that a contact mapping had nothing to do with freetext search. That landed on master the same day move merged into the feature branch, so neither side saw the other, and syncing the two broke move. Move looked reports up with exact_match:"contact:<lowercased id>" against reports_by_freetext. That emission no longer exists, so the query returns nothing and a move silently skips every report its contacts authored, leaving them caching a lineage that no longer holds. Four integration tests catch it, all reporting set-contact.reports as 0 where 1 is expected. The fix is also a simplification. Finding the reports needed two index reads: a freetext query for the ids, then an _id query here to read the author out of stored fields, because submitter was stored but not searchable. Now that it is searchable, one query by submitter returns both the report and the author its guard has to check, so getReportIdsByCreator and getReportAuthorIds collapse into getReportAuthorPairs. Two details the single query changes. Ids are matched verbatim rather than lowercased, since this index uses the keyword analyzer, which is what Josh's own test for medic#11370 does. And because chunked queries can each return the same report, hits are de-duplicated as they arrive rather than relying on a Set of ids built by the first pass. 25 unit tests passing, 1729 across unit-api, eslint clean.
|
Ran the branch and mutation-tested the changed logic rather than just reading it. Comment only. Verified: the fix is correctChecked the two things that would make the new single-query approach unsound:
Then mutated the changed function directly and reran
Both died. Reran the pagination/stuck-bookmark/escaping tests by inspection against the same logic and they check out too — the "stops paging when the bookmark does not advance" test in particular would genuinely hang on a stuck-bookmark mutation, not just fail an assertion, so that guard is real. One nit, not a defectThe comment on
That specific race — staleness between two separate reads — is gone now that id and author come from the same query response. The test right next to the equivalent case ( This review used Claude Code (Anthropic) under my direction: I read the index definitions and diff, directed the mutation testing, and verified both mutations failed and the fix passes as described. |
jkuester
left a comment
There was a problem hiding this comment.
LGTM! Nice to see this query shift work well! 🚀
4ab2d28
into
medic:10706-dmp-2026-add-api-endpoints-for-advanced-contact-management-operations
Description
Move stopped finding the reports its contacts authored after the feature branch was synced with master. Four integration tests catch it, all the same way:
The cause is #11371. It removed the
contact:<id>emission fromreports_by_freetext, on the grounds that a contact mapping had nothing to do with freetext search, and madesubmittersearchable ondocs_by_replication_keyinstead. Move queries exactly that removed emission withexact_match:"contact:<lowercased id>". #11371 landed on master on 26 August and move (#11311) merged into the feature branch on 26 August, so the two crossed and neither side saw the other. cht-conf's equivalent consumer was already migrated in medic/cht-conf#838.Worth being explicit about the failure mode: nothing errors. A move silently skips every report its contacts authored and leaves them caching a lineage that no longer holds.
The fix, which is also a simplification
Finding those reports previously took two index reads: a freetext query for the report ids, then an
_idquery ondocs_by_replication_keyto read the author out of stored fields, becausesubmitterwas stored but not searchable. Now that it is searchable, one query bysubmitterreturns both the report and the author its guard has to check, sogetReportIdsByCreatorandgetReportAuthorIdscollapse into a singlegetReportAuthorPairs.Two details the single query changes:
docs_by_replication_key#11370 test forsubmitterdoes.Setof ids built by a first pass.Blast radius
Move was the only cht-core consumer of the removed emission. The other
reports_by_freetextreferences (shared-libs/cht-datasource/src/local/report.ts,local/libs/nouveau.ts,api/src/services/monitoring.js) are genuine freetext search and unaffected.Verification
api/tests/mocha/services/move-contact.spec.js, rewritten for the single-query designunit-api1729 passing, coverage above every thresholdThe four integration tests that currently fail on #11275 are the regression test for this; they should pass with this change.
Why this matters now
#11275 cannot go to master while move is broken on the feature branch.
Closes #10706
Code review checklist
License
The software is provided under AGPL-3.0. Contributions to this project are accepted under the same license.