Skip to content

Salient Fields

Every profile in this IG can declare salient fields: the handful of values that ARE the resource when you only get a handful. A Slot is its status, start, end, and schedule. A Patient is a name, a birth date, an identifier. Salient fields write that judgment down, per profile, in the FSH -- instead of leaving it to every consumer to re-decide.

A salient field is a triple (plus one optional part):

Part What it is
key The field's name as consumers see it (snake_case by convention)
expression A restricted FHIRPath value expression that computes the value from the instance
type The value's type (string, code, dateTime, ...)
chart (optional) An alternate name to use when the field is rendered into a chart/LLM context

They are declared at the StructureDefinition level (a repeating salient-field complex extension), and every profile page in the FHIR reference shows its set under the Salient fields tab.

What they drive

Salient fields are a contract consumed by machines, not documentation prose:

  1. TypedFhir synthesized accessors. Each salient field becomes a first-class typed property on the profile's facade class (see the TypedFhir API tab on any profile page), in all three ports. Where the expression is invertible -- a plain navigation path -- the accessor gets a setter with validated write-back; where it is not (e.g. a union or a join), it is read-only.

  2. Chart and LLM contexts. When TypedFhir renders a resource into a compact document view -- the shape handed to an LLM as context -- the salient fields are the attributes that surface, under their key (or chart) names. This is the token-economy lever: a raw FHIR resource is hundreds of tokens of envelope around a few values; the salient set is the profile's own statement of which values those are. The raw FHIR remains the lossless substrate underneath -- salience selects, it never discards.

  3. This site. The Salient fields view on each profile page is generated directly from the declarations, so the site, the facades, and the LLM shapes can never drift apart.

How to define them

In the profile's FSH, insert one rule per field (the rulesets live in rulesets.fsh). Wrap the expression in [[ ]] so its parens and quotes survive the ruleset call:

* insert Salient(given_name, [[name.first().given.first()]], string)
* insert Salient(status, [[status]], code)

// rendered into charts/LLM contexts as `class` instead of `visit_class`:

* insert SalientAs(visit_class, [[class.code]], code, class)

Rules of the road:

  • Stay inside the emittable subset. Expressions are restricted FHIRPath value expressions: navigation paths, first(), join(sep), and top-level unions (|). Anything fancier is rejected by the compiler and the field is marked unemittable -- declare a simpler expression instead.
  • One date concept is separate. The resource's effective date is declared with the EffectiveDate ruleset, not as a salient field -- every facade exposes it uniformly as $effectiveDate.
  • snake_case keys. They surface verbatim in LLM contexts and Python.
  • Regenerate after changing them: npm run gen:all (and the -py / -cs twins) in backend/lib/TypedFhir/ts; parity tests will catch a port that drifts.

What to pick

The test is editorial, not technical: if a clinician (or a model) saw only these fields, would they know what this resource says? Aim for the 3-8 values that answer that. Everything else stays reachable through the typed accessors and the raw FHIR.