fix(hts): align tx-ecosystem conformance with 2026-07-01 upstream changes#189
Merged
Conversation
Establish the structure and rules of the road for multi-language support
across the stack:
- locales/{en,es,de}/main.ftl — seeded Fluent UI message catalogs
(English source + Spanish + German)
- locales/README.md — catalog conventions
- docs/multi-language.md — discussion document covering the front-to-back
approach, locale negotiation, UI/error/content/terminology layers,
formatting, security, and language roadmap. Notes existing HTS SNOMED
multi-language import/display as the terminology localization layer.
Relates to #186 (HTMX-first web UI foundation).
Lay the foundation for a server-rendered, HTMX-first web UI per #186. - New helios-web crate: thin Axum handlers -> Askama (compile-time, auto-escaping) templates; no HTML in Rust, no browser-facing JSON API. - Working POC: active-search demo showing the HX-Request full-page vs. fragment pattern, with graceful no-JS fallback. - Vendored, version-pinned htmx.org@2.0.4 (no runtime CDN); local CSS. - Template layout: layouts/ pages/ partials/; assets/ for static files. - README.md: approach, templating trade-offs, file-placement rules of the road, asset/security policy, and mount follow-ups, with references. - Wired into workspace default-members. Refs #186
…nges
The nightly HTS Terminology IG Conformance run went red after
HL7/fhir-tx-ecosystem-ig landed several expectation changes on 2026-07-01.
The validator and HTS binary were unchanged; only the upstream test suite
moved. This updates HTS to match the tightened expectations.
- CodeableConcept validation now returns the FIRST valid coding, not the
last (both CodeSystem and ValueSet $validate-code paths), matching
upstream b5658de8. Fixes permutations/good-cc2-* (6) and
overload/validate-good2a (its version 1.0.0->2.0.0 falls out of the
first-coding selection).
- Inactive+retired concepts now emit a SINGLE merged status warning
("...has a status of retired and inactive...") instead of two separate
issues, matching upstream 030182b7. Fixes validation/validation-contained-good,
inactive/inactive-3{,a,b}-validate, and batch/batch-validate.
- Expansion now dedupes identical (property, value) pairs. concept_property_values
joins by CodeSystem URL only, so a URL stored in two versions returned each
concept's `status` property once per version. Fixes tho/act-exclusion.
- search/search-filter-yes added to IGNORED_TESTS: HTS returns a spec-valid
flat $expand that matches upstream's own search-expand-filter-yes-flat-response.json
byte-for-byte, but upstream never wired that flat variant via `response:flat`
in test-cases.json. Excluded pending an upstream PR.
Bump helios-serde's quick-xml 0.38 -> 0.41 to fix the two DoS-via-XML advisories on the client-facing FHIR XML parse path. The remaining transitive copies (0.37.5 via object_store, 0.38.4 via octofhir-ucum's build dependency) are not reachable with attacker-controlled input and are ignored in the CI audit with a documented justification until their upstreams ship on quick-xml >= 0.41. Also regenerates Cargo.lock, which picks up the previously-uncommitted helios-web/askama entries added by the feat(web) scaffold.
…ode)
overload/validate-good2a has two codings sharing (overload, code2) but with
different displays ("Display #2" then "Display 2"). The coding_displays /
coding_versions / coding_index maps were keyed by (system, code) and built
with last-wins .collect(), so the first-wins loop still echoed the second
coding's display and resolved the wrong CS version (1.0.0 instead of 2.0.0).
Build these maps keep-first to match first-wins selection.
build_concept_closure_pg loaded concepts and inserted closure rows without
holding any lock on the parent code_systems row. In the shared-database
postgres integration tests, a concurrent delete_normalized("CodeSystem", ..)
(e.g. importer_dicom_runs_against_postgres deleting the DICOM system at
teardown) could remove the code_systems row — cascading its concepts — in the
window between the concept load and the closure INSERT. The INSERT then
violated concept_closure_system_id_fkey ("Key (system_id)=(dicom|current) is
not present in table code_systems"), intermittently failing the whole test
binary (seen only under the Code Coverage job's timing, green under Test Rust).
Do the whole build in one transaction that first pins the code_systems row
with SELECT ... FOR SHARE (skipping the system if the row is already gone),
and read concepts/hierarchy within that transaction. A concurrent delete now
blocks until the build commits, closing the FK window. This also hardens
server startup against a code system being deleted mid closure-migrate.
SQLite is unaffected: it serializes writers and its tests use per-test DBs.
Codecov Report❌ Patch coverage is 📢 Thoughts on this report? Let us know! |
…se:flat HL7/fhir-tx-ecosystem-ig#51 merged (upstream 49c830c3), adding the `response:flat` key for search-filter-yes. HTS's spec-valid flat $expand now matches, so the temporary IGNORED_TESTS entry is no longer needed.
Removing the skip and re-running (run 28662146109) revealed search-filter-yes is a real HTS hierarchy-nesting gap, NOT the upstream wiring gap first diagnosed. Upstream 7409a11a flipped the test from flat to hierarchical; HTS keeps filtered/URL-resolved expansions flat. The validator treats HTS as hierarchy-capable and always compares against the hierarchical response, so the merged upstream response:flat wiring (#51) does not help. Re-skipping with an accurate rationale until the default-nesting heuristic is broadened.
An `is-a` / `descendent-of` compose filter designates a hierarchy subtree, so its $expand should nest matched concepts under their in-result ancestors by default (tx.fhir.org behaviour). HTS only defaulted to tree mode for pure full-system *inline* composes, leaving filtered and URL-resolved composes flat — so search/search-filter-yes (URL-resolved is-a filter) expanded flat while the IG (upstream 7409a11a) expects it nested. Extend the default-nesting decision: when the compose (inline or URL-resolved) carries an is-a/descendent-of filter, default hierarchical=true unless the caller set hierarchical/excludeNested. No hierarchy-detection gate — an is-a filter over a flat CS resolves to just its own code, so nesting is a no-op there; gating on code_system_is_hierarchical would wrongly drop nesting when that probe under-reports (as it does for the `search` CS). Full-system-with- text-filter (search-all-yes) and enumerated composes (search-enum) stay flat. Verified no run-test regressions: the only other is-a expand tests run against HTS are broken-filter-expand (empty expansion) and parameters-expand-isa-* (already excludeNested=false); the snomed/loinc/pc is-a tests are tx.fhir.org/ snomed-mode and not run. ecl_expand's expand_codes helper now collects codes recursively (it asserts concept-set membership, not tree shape). Removes the temporary search-filter-yes skip.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
The nightly HTS Terminology IG Conformance run went red on 2026-07-02 after an 8+ day green streak — failing 14 of 600 tests on both backends (sqlite/R4 and postgres/R5). The validator (runner v6.9.11, tests v1.90) and the HTS binary were byte-identical to the last green run; only the upstream
HL7/fhir-tx-ecosystem-igsuite — which this workflow checks out at HEAD every night — moved. Four commits landed upstream on 2026-07-01 (after our green run, before the red one) and tightened expected server behavior. This PR updates HTS to match.Root-cause investigation: run 28565301822.
Changes
permutations/good-cc2-*(6),overload/validate-good2ab5658de8$validate-codereturns the first valid coding, not the last (both CS and VS paths). good2a's version1.0.0→2.0.0falls out of first-coding selection.validation/validation-contained-good,inactive/inactive-3{,a,b}-validate,batch/batch-validate(5)030182b7"...has a status of retired and inactive...") instead of two issues.tho/act-exclusion(1)7409a11a(property, value)pairs.concept_property_valuesjoins by CodeSystem URL only, so a URL stored in two versions returned each concept'sstatusonce per version.search/search-filter-yes(1)7409a11aIGNORED_TESTS— not an HTS bug. See below.search/search-filter-yes— upstream wiring gapThe primary
responsefixture is a hierarchical expansion. Upstream added a flat variant (search-expand-filter-yes-flat-response.json) but never wired it via aresponse:flatkey intest-cases.json(unlikesearch-all-yes, which got both). HTS returns a spec-valid flat$expandthat matches that flat fixture byte-for-byte. Excluded from the gate pending an upstream PR to add the missingresponse:flatwiring.Verification
cargo test -p helios-hts— all suites passsqlitedefault +--features postgres,R4)cargo fmt --checkclean;cargo clippyexits 0 (no new warnings)The full HL7 tx-ecosystem IG bench is the CI job itself (
HTS Terminology IG Conformance) — the true green confirmation comes from running it against this branch.