Repository navigation
Manual test pass: MongoDB backend #940
Description
Summary
Run the manual testing pass in MANUAL_TESTING_MATRIX.md for the MongoDB backend (HFS_STORAGE_BACKEND=mongodb) and record the results in this issue.
The matrix is organised backend-first: every backend gets the same T0 through T9 sequence. This issue covers one row of that matrix.
Procedure
Follow MANUAL_TESTING_MATRIX.md sections 2 through 12 in order, using the mongodb row of the per-backend environment table in section 5.
Infrastructure: start MongoDB 7.0 per section 4 as a single-node replica set (transaction Bundles need it, #997). Bulk Data $export (T5) is supported on MongoDB through a SQLite sidecar job store (#1004). $sql-export (T7) runs in-DB as an aggregation pipeline and is expected to work. _content (T4 row 4.13) and composite search (row 4.8) are N/A on this row.
- T0 Build with the CI selection:
cargo build --workspace --all-features --release - T1 Start HFS with
HFS_STORAGE_BACKEND=mongodb HFS_MONGODB_URI=mongodb://localhost:27017/?replicaSet=rs0&directConnection=true HFS_MONGODB_DATABASE=heliosand confirm/health,/metadata, and/ui - T2 Batch / Transaction page
- T3 Import at least 10,000 resources from the Synthea
bulk_1karchive (record wall-clock time, bundle count, resource total) - T4 One search per type: string, token, date, number, quantity, reference, uri, composite, special, plus chained, reverse-chained,
_include/_revinclude,_sort, paging,_content, POST search - T5 Bulk Data
$export: system, patient, group; all three NDJSON format spellings; unsupported format returns 400; UI/ui/bulk-export - T6 Create a ViewDefinition via API and via
/ui/sql/view-definitions; examine$sql-runoutput in json, csv, ndjson, parquet - T7
$sql-exportwith a ViewDefinition subject, a SQLQuery Library subject, and a SQLView Library subject, cycling all four formats; UI/ui/sql/export - T8 Create a SubscriptionTopic (R4 backport
Basic) and rest-hook Subscription, trigger notifications, verify delivery,$status,$events - T9 Verify the
/ui/subscriptionsactivity dashboard (cards, table row, sparkline, failure streak, rehydration after restart)
Results to attach
- The filled-in
mongodbrow of the matrix table from section 1 ofMANUAL_TESTING_MATRIX.md build.logtail,hfs-mongodb.log,import-mongodb.log, and the T3 timing line- One T5 manifest and one T7 result manifest
- Screenshots of
/uiafter import,/ui/sql/exportwith a completed card, and/ui/subscriptionsafter T9 - For any failure: the request, the OperationOutcome, the log excerpt, and a link to the issue filed for it
Acceptance criteria
- Every T0 through T9 cell for the
mongodbrow is marked pass, or marked fail with a linked issue, or marked N/A where section 1's expected-support table says the capability is unsupported on this backend - Results and artifacts listed above are attached to this issue
Activity
dougc95 commentedon Sep 10, 2026
mongodbrow — completeTester: @dougc95 · Windows 11 Pro 10.0.26200 / x86_64 (MSVC) · 2026-09-06 → 2026-09-10
Commits:
6080c4cb8(T0–T4), then0e201b577after a mid-pass rebuild (T5–T9)mongodbFive pass, five fail. Of the five failures, three trace to already-reported causes, and one (T8) is fixed upstream in a commit that merged hours after the build under test.
Environment deviations
--all-features— that flag also enablesheadlessand produces a binary with no/ui(#975, fixed after this build)mongo:7.0 --replSet rs0. Standalone makestransactionBundles return 501, so §4's infrastructure cannot pass T2 (#997)FILE_CONCURRENCY=160e201b577on 2026-09-09; T4 was re-verified against the new binary with 0 differencesTimings
finished in: 4 s forvd-ndjson— 11,705 rowsIssues filed from this row
distinct too big$bulk-submit~60 rec/s per file — since fixed:belowreturn 400_sortby a search parameter scans the whole resource type — newEvidence comments were added to #870, #958, #968, #969, #1008, #1009, #1010, #1014. Roughly half of what this pass found was already tracked upstream, so every finding went through a duplicate check across 400 issues before anything was filed.
The one pattern worth naming
Three of the open 🔴 findings — #999, #1040 and #1041 — are the same failure in different clothes: an operation whose cost is proportional to the whole collection rather than to the requested result. One materialises every matching id before intersecting; one sorts every resource of a type before filtering to the 165 that matched; one sweeps every resource until its lease expires, then starts over.
The counter-evidence is just as consistent. Work sized to the answer is fast on this backend: 11,705 rows exported in 4 s, 50 rows drawn from 7.7 M Observations in 12 ms, a warm
Condition?patient=PIDin 1.2 s. They are likely to want the same remedy — push the selective predicate down before materialising.Two things that will cost the next tester time
Cache temperature changes results, not just timings. Indexes are ~55 GB against a 7.14 GB WiredTiger cache.
Condition?patient=PIDreturns nothing in 120 s on a cold server and 1.2 s warm — same binary, same data. It also means a 500 and a timeout are the same failure: warm, the query reaches the 16 MBdistinctcap and fails fast; cold, it never gets there. Our original tally of "5 × 500 and 10 × timeout" was one failure mode, not two. Do not compare a first pass after a restart.Several matrix expectations are wrong, in both directions. Chained and
_hasare marked N/A and work. Bulk$exportis marked N/A in three places and works. Parquetdate→ string is correct per the SoF ballot's type table (#569), not the defect the doc implies. Row 5.1's "3 files" only holds under 1,000 resources per type. T9's "~30 s" to see the failure chip is really ~5 minutes, because it counts exhausted deliveries rather than connection failures. All twelve corrections are on #1004.Deliverables
T4-api.tsv(84 queries with counts, status, timings) andT5-api.tsv$sql-exportresult (note: aParameters, not a Bulk Data manifest)hfs-mongodb.log— 13 server startsScreenshots are attached below.
dougc95 commentedon Oct 19, 2026
mongodbrow: complete (bounded pass,bulk_1k)Tester: @dougc95. Claude Code agents ran the pass, driving the web UI with headless Playwright.
Environment: Linux VPS
vmi3636660(Ubuntu, kernel 6.8.0-147-generic, x86_64, 12 cores, 47 GB RAM) with Docker. There is no Rust toolchain on the host, so the build and the server ran in thehfs-rust-devimage. The UI was driven by Playwright 1.49.1 with headless Chromium 131.Date: 2026-10-19. The build ran 05:34Z → 14:10Z, and T1–T9 ran 14:01Z → 18:56Z.
Commit:
d3976b4bd(v0.2.5). Onehfsbinary was used for every step: sha256de774a4f839f1fe0061c753b7f8840f7e749d9863efe667ee08a113a2b81aee8, 989,906,640 bytes.HFS_STORAGE_BACKEND)mongodbTen pass, zero fail, no new product issue.
One T1 sub-check failed as written: "sidebar shows MongoDB". A second, independent run confirmed that this comes from a stale matrix line and is not an HFS fault (see Failures). The other deviations from the written text are matrix errors, listed under Matrix corrections.
Cell notes
T0.
cargo build --workspace --all-features --releaseexited 0 (Finished release profile [optimized] target(s) in 424m 02s,BUILD_EXIT=0at 14:10:06Z), andhfs --helpprints usage.pysof) was still compiling. The issue owner chose this. Every binary was already built, and thehfsbinary was not touched afterwards: its mtime is 12:12:34Z and its sha256 was unchanged at report time.git status --shortwas empty after the build.T1. Every check in the matrix's pass criteria (L340-344) passed:
/healthreturned 200 after 21 s./metadatareportsfhirVersion4.0.1, andfhirVersion=5.0returns 5.0.0.Initializing MongoDB backend url=mongodb://localhost:27017/?replicaSet=rs0&directConnection=true database=heliosappears, with no ERROR and no panic./uirenders. The dashboard reads 1.4k (the exact figure is 1,377), and the clinical rail is at 0.The L337 annotation "sidebar shows the backend" fails as written, because the HFS UI has no backend label.
T2. All 12 sub-checks passed in the UI.
T3. All 18 expected-pass sub-checks passed.
T4. 4.13 is N/A: 501 "Feature 'full-text search not available' is not implemented.", as §1 marks it.
Bundle.totalreceived on all 87._search(from the issue checklist) was checked through the API, because the Resources page only sends GET. It answered 200 with total 5, the same ids as the GET.T5. All 20 sub-checks passed. 9.5 (S3 output backend) is N/A on this row.
_outputFormatspellings (202),text/csv(400 "unsupported _outputFormat 'text/csv'"), and patient- and group-level$export.T6. All 17 sub-checks passed.
$sql-runin json/csv/ndjson/parquet (200, 1,001 rows each). Those were done through the API by design.T7. All 26 sub-checks passed. 11.7 (S3 sink) is N/A.
/ui/sql/export.T8. All 8 sub-checks passed: the handshake,
requested → active, 3 notifications withBearer manual-token, no notification for a Condition, and delivery after the receiver restarted.$statuswas read through the API (events-since-subscription-start6).$events(issue checklist, not in the matrix) was not run.T9. All 12 sub-checks passed.
Failed to persist subscription status transition.Environment deviations
CARGO_BUILD_JOBS=2 cargo build --workspace --all-features --release, run in Docker imagehfs-rust-dev:1776(rustc/cargo 1.99.0, Python 3.11.2).--releasewas added because matrix L143 omits it. Attempt 1 used 4 jobs and was killed (see Timings).BUILD_EXIT=0at 14:10:06Z, with onlypysofleft compiling. Thehfsbinary that was used is unchanged.hfs940-server(--network host, worktree mounted read-only at/work), with stdout appended tohfs-mongodb.log. It was not started with./target/release/hfs | tee.HFS_BULK_SUBMIT_OUTPUT_DIR=$WORK/submit(keeps the read-only checkout clean) andHFS_REQUEST_TIMEOUT=600. Deferred indexing was left at its default (on).mongo:7.0(mongod 7.0.43) as a single-node replica setrs0with host networking, bound to 127.0.0.1 and ::1, on a named volume, with--wiredTigerCacheSizeGB 8because the host is shared.bulk_1k(Aidbox archive, sha2567844b5f8…5eaf5f, 418,110,093 bytes), converted to 50 NDJSON parts plus a manifest. It was served by nginx 1.31.7 with keep-alive onlocalhost:8000. The whole-file byte check gave 50 ok and 0 TRUNC.12fc97d7-…(male, 2008-07-17, Haverhill) replaced Parker433 /7d24f7a0-…. Every count came from an offline model of the loaded NDJSON./ui. Uploads used the page's own file input, and each step has screenshots. Every check done through an endpoint instead of the UI is marked as such above.webhook.pywas used, with the same JSON lines plus a timestamp, instead of the §12.1 heredoc.Timings
helios-fhirwas killed withsignal: 9, SIGKILL, probably OOM.hfsbinary at 12:12:34Z took 5 h 06 m 44 s.BUILD_EXIT=0came at 14:10:06Z, 7 h 04 m 16 s after the start (cargo reports424m 02s).bulk_1k). 1,000 transaction Bundles, converted to 50 NDJSON files, gave 1,630,685 resources.aba79678-7564-4abf-94c7-6c033b9c7425ran 15:10:46.678Z → 16:23:04.382Z:completed, errorCount 0, 1,631,364 resources, 31,203,895 index entries, 376 res/s.heliosdataSize 20,933,311,989; storageSize 4,061,364,224; indexSize 11,022,086,144; objects 37,759,601._has:Observationtook 50.5 s, then 19.2 s warm.vd-ndjson(1,001 rows):finished in 0m 05son the card, which is the 5 s poll. The server'sexportStartTime → exportEndTimewas 0.18 s.observation_flat's 689,186 rows.observation_flatexport took 25.97 s and produced 2 files (500,000 + 189,186 rows).tall_female_patientspreview with a value took 20–38 s.consecutive_failures=3and the Error chip took 15 min 06 s: 3 notifications × 10 attempts, with 30Connection failedwarnings.Failures
No product failure, no new issue. The one sub-check that failed as written:
5.uiGET /ui,/ui/resourcesand 10 more/uipages, cold and warm, in Chromium and with curl. Read the sidebar text.curl -s $HFS/ui | grep -ci mongo→ 0).crates/ui/templates/layouts/base.htmlhas never had a backend field:git log -S backendon it is empty, and L337 dates from the matrix's first commitb216565e6. The backend was confirmed from the startup log instead. Evidence was added to #2141.Verified fixed since the September row (
6080c4cb8/0e201b577)d3976b4bd--all-featuresdrops/ui--all-featuresbinary serves/ui(200).$bulk-submit~60 rec/s per file_summary=count.distinct too big(T4 ❌):below:belowreturns 1. 4.8 composite returns 13,858, equal to 4.5. The 4.21 composite returns 3.Bundle.totalon 87/87 queries._sortscans the whole typecancel-mecancelled andbad-groupfailed, as designed. Lease expiry itself was not provoked.Writing 0 of 1_typeFilter_elements=statuscolumn work.Still open: confirmed or not reached by this row
<Type>-0001.ndjson. Item 4: Retry creates a new card, so Delete is needed twice. Item 5: rows carry nosubject.display.deferred reindex generation started … job_id=log line; the/uibanner does not show it either.GET /Observation?_summary=countover 689,186 answered 200 in 1.2 s with no 422.observation_flathas 689,186 rows, below the 1,000,000 cap.Observations (not failures; seen once, not independently verified, nothing filed)
Content-Type: application/json, while reads and/metadataare served asapplication/fhir+json; fhirVersion=4.0. This coversGET /Patient?_id=…,GET /Patient/<id>/_historyandPOST /Patient/_search. The$exportstatus manifest is alsoapplication/json. No existing issue was found; rest: PATCH never negotiates the response format, and conditional PATCH has no route #863 covers PATCH only.ERROR helios_rest::error: internal error while processing request error.detail=View execution was cancelled. It is the only ERROR line in the log that is not an expected 501. The UI shows Cancelled correctly. Related closed issues: sof: deterministic order, bounded memory and cancellable runs on every SQL-on-FHIR runner #1623, sof: stop database work when a run is abandoned or times out #1864.queries-results-total = { $count } results(crates/ui/locales/en/main.ftl:492). ui(export): the 'N running' header on Exports and SQL Exports stays stale after a job finishes; singular counts use plural words #1583 (closed) fixed the same wording on the Exports pages.WARN … LockTimeout … helios.search_index … running it againwhile the generation-4 index build runs. Seeding then finished withfailed=0.resourceas required but notstatus, while the guided form marksstatusrequired. The lint modelsstatusas optional on purpose (crates/sof/src/lint.rs:400-414).Not run
_content(501).$events, which is on the issue checklist but not in the matrix procedure.HFS_SUBSCRIPTION_REHYDRATE=false.PATCH /_user/settingsand removed afterwards.Matrix corrections
There are 38 new entries against
d3976b4bd, beyond the five already in #2141 (all five confirmed here). The full list with line numbers is on the evidence page. The main ones:--release.--all-featuresskips the R6 download, and the tree stayed clean._summary=truerow.These are added to #2141.
Evidence
All the attachments are on one page: https://claude.ai/artifact/GMuvgtEWESzwZb1JWLhN25. It shows each file's contents in tables, charts and log views; the files themselves are not downloadable from it.
/uiafter the import, the T3 submission in its Completed state, the T2 Per-Action Outcomes for the transaction, SQL Exports with completed cards, and/ui/subscriptionsafter T9 step 3 and in the error state.BUILD_EXIT=0, attempt 1 the SIGKILL).Parameters(not Bulk Data manifests), and the first rows of one output file per subject kind × format.hfs-mongodb.log(1,164 lines, 5 server starts, 3 ERROR lines: 2 expected 501s and observation 2), with every WARN and ERROR grouped and a searchable view of all lines.dougc95 commentedon Oct 27, 2026
Closing
The 2026-10-19 pass on v0.2.5 (
d3976b4bd) passes all ten cells of themongodbrow: see the results comment. The evidence, screenshots included, is on one page.This was a bounded pass on
bulk_1k(1,630,685 resources), so it says nothing about fhir2-scale limits. T8's$eventswas not run.Still open: