Skip to content

TypeSchema: precompute derived slice facts and refine the slicing model - #207

Draft
ryukzak wants to merge 9 commits into
mainfrom
typeschema-slice-derived-facts
Draft

TypeSchema: precompute derived slice facts and refine the slicing model#207
ryukzak wants to merge 9 commits into
mainfrom
typeschema-slice-derived-facts

Conversation

@ryukzak

@ryukzak ryukzak commented Jul 27, 2026

Copy link
Copy Markdown
Collaborator

Second PR of the slice-refactor sequence started in #203.

Derived slice facts

  • FieldSlice gains four derived facts, computed once at snapshot build (enrichSlice in the index): effectiveRequired (required − match keys − choice-declaration base names), constrainedChoice (the single narrowed choice variant), autoStub (stub-eligible with just the discriminator match), resourceType (matched resource type of type-discriminated slices).
  • TS and Python writers consume the facts instead of re-deriving them per language; the duplicated collectors (choice-base resolution, tsIndex.constrainedChoice calls, two divergent resource-type extractors) are deleted.
  • Two bugs fixed by the unification:
    • validateSliceFields/validate_slice_fields no longer require choice-declaration base names — a phantom key ("value") that never exists in FHIR JSON and could only false-fail;
    • Python no longer auto-stubs slices that need user data beyond the match (adopts TS semantics); extension profiles keep extension as an optional create() param populated via sub-extension setters, mirroring the TS Raw type.
  • Transform-level tests cover all four facts, including the deliberate asymmetry: choice-base names are dropped from effectiveRequired but still block autoStub.

Slicing model refinements

  • match becomes a discriminated SliceMatch union: { kind: "value" | "type", value }; empty matches are no longer stored, so consumers test presence instead of key-counting.
  • Extension-style slices are fully populated: the { url } match is recovered from schema.url and cardinality from the slice schema (fhirschema convention) — no more degenerate slicing entries. Writers replace the accidental skip (missing match) with an explicit ownership rule: on resource-based profiles extension/modifierExtension slices belong to the ProfileExtension mechanism; Extension-based profiles keep their sub-extension slice API.
  • Re-slicing a field now refines the inherited slice set in flatProfile (leaf header and same-name slices win, inherited slices survive) instead of replacing it wholesale.
  • docs/type-schema.schema.json documents the slicing model (incl. derived facts) and the reference: { resource, profiles } shape from TypeSchema/TS/PY: resolve reference targets to base resources, keep profile expectations separately #201.

Example of the enriched serialized slice (BP component):

"SystolicBP": {
  "min": 1, "max": 1,
  "match": { "kind": "value", "value": { "code": { "coding": [{ "code": "8480-6", "system": "http://loinc.org" }] } } },
  "required": ["value"],
  "constrainedChoice": { "choiceBase": "value", "variant": "valueQuantity", ... },
  "autoStub": false /* needs a valueQuantity, not just the match */
}

Generated output changes are limited to the two bug fixes (US Core race/ethnicity/tribal extension profiles, TS + Python); everything else is byte-identical.

ryukzak added 9 commits July 27, 2026 11:27
FieldSlice gains effectiveRequired, constrainedChoice, autoStub and
resourceType, populated once at snapshot build. The TS and Python writers
consume them instead of re-deriving the same semantics per language, which
removes duplicated collectors and fixes two divergences that duplication had
already produced:
- Python auto-stubbed required slices that need user data beyond the
  discriminator match (e.g. US Core race/ethnicity text slices) — extension
  profiles now keep 'extension' as an optional create() param populated via
  sub-extension setters, mirroring the TS Raw type;
- validateSliceFields no longer requires choice-declaration base names
  (phantom 'value' key that never exists in FHIR JSON) inside slices.
FieldSlice.match becomes { kind: "value" | "type", value } — the runtime
discriminator values keep their shape under 'value', while 'kind' states
whether they are fixed/pattern discriminator values or a resource-type
discriminator. Empty matches are no longer stored, so consumers test presence
instead of key-counting. Generated output is unchanged.
…ield

flatProfile previously replaced the whole inherited FieldSlicing when a
child profile restated slicing on the same field. Now the child refines it:
its header and same-name slices win, inherited slices survive.
…extension-slice ownership explicit

Extension-style slices carry their discriminator value as schema.url and
their cardinality on the slice schema (fhirschema convention); buildSlicing
now recovers both, so the slicing map has no degenerate entries. Writers
replace the accidental skip (missing match) with an explicit rule: on
resource-based profiles, extension/modifierExtension slices are owned by the
ProfileExtension mechanism; on Extension-based profiles the slice machinery
keeps generating the sub-extension slice API as before. Generated output is
unchanged.
…N schema

Adds field-slicing/field-slice/slice-match/slice-discriminator definitions —
including the snapshot-time derived facts (effectiveRequired,
constrainedChoice, autoStub, resourceType) — attaches the schema-level
'slicing' map next to 'fields', and updates 'reference' to the
{ resource, profiles } shape.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant