Repository navigation
0.0.5
Added
-
The web template compatibility surface (#54):
ferrochart-webtemplatereads
a web template another tool produced into a form definition, and writes a
form definition back out as one. The web template is a compatibility target
and no openEHR specification defines it, so the crate sits beside the
compiler rather than under it and linksferrochart-formand nothing else
of this tree. A member the form definition does not model, a third party's
annotations among them, survives a round trip verbatim: a read keeps each
node's source object beside the definition, and a write starts from it, so
a node the definition still states as it was read goes back out untouched.
Over the whole vendored CKM pack, every document built from it reads and
writes back as the document it came from, with annotations, per-option
terminology bindings and members this crate has never seen put into it
first.minandmaxare read as the flattened integers they are, and
template version detection readstemplateIdand the root archetype
identifier, neversemVer, which not one document of the pack states. -
A COMPOSITION reads back into the form it was built from (#23), completing
the pair. The reader walks the data rather than the form, so a node the form
does not cover is reported instead of silently dropped, which is what an
editing round trip needs if it is not to delete a colleague's content. Over
the committed pack every value entered comes back against its own field, a
null flavour and its reason survive both directions, and a repeated field
reads back into the right occurrence. Where several form nodes share an
identity and the data cannot fill them all, the assignment is a guess the
reader reports as one rather than presenting as certain. -
The pre-post validation gate (#24), in the new
ferrochart-validatecrate
andferrochart_server::commit. A COMPOSITION FerroCHART built is judged
against its own operational template before any request reaches a CDR, and
every failure it finds is keyed onto the form definition, so a renderer puts
it on the field a clinician got wrong. The gate is the only path in this
workspace from entered values to a CDR write, and the ordering is tested by
construction: the client is pointed at a port nothing listens on, so a
refusal proves the gate ran first. A negative case per constraint kind
covers the value set, the numeric range, the string pattern, the data value
class, the occurrences, the cardinality, a mandatory node left out, and a
code outside its openEHR terminology group. A live case commits through the
gate to a real CDR and reads the document back. -
A validation report a renderer reads, in
ferrochart-form. It carries one
failure per problem, each with the node key it belongs to, the path it was
found at, its message and its category, so a renderer still links one crate
of this tree. A failure that names no field of the form keeps its path and
is reported unplaced rather than dropped. -
A best-effort reader for a CDR's own error body, marked vendor-specific.
openEHR ITS-REST Release-1.1.0 publishes no path on an error entry, so the
reader recognises one inside the prose where a CDR writes one and reports
the refusal verbatim where it does not. -
Three layers that guard the two documents FerroCHART publishes, after a
dependency's cargo feature took one of them off the wire with no change to
this tree (#107).serde_json/arbitrary_precision, enabled for the whole
workspace by one new dependency, sends a number to serde's content buffer as
a map, and the internally tagged enums of the form definition stopped
deserializing. Each layer catches something the others do not: the form
definition and the layout overlay each round-trip a document carrying every
number-bearing shape they publish, so a document that no longer reads back
fails; each also carries a golden snapshot of its exact bytes, so a document
that still reads back and no longer means the same thing to a consumer
written against the old bytes is a diff a person reads and accepts; and
scripts/checks/serde-json-features.shcompares the resolvedserde_json
feature set against the reviewed one, failing on a refused or an unreviewed
feature and naming what turned it on, which is the cause the two tests can
only report the effect of. The form definition'sFORMAT_VERSIONnow says
what the number covers, so a byte change is a decision rather than an
accident. -
The composition builder (part of #23), in
ferrochart-compose. It turns
what a clinician entered into a COMPOSITION, working from the form
definition alone and never from the template, which keeps that definition a
contract a third party can commit against as well as render against. 78 of
the 121 committed templates that read build a document; the 36 rooted at
CLUSTERare refused by name, because a fragment is not a document.
docs/architecture.mdsections 5.3 and 5.4 record where every Reference
Model field a form never shows comes from, which of them FerroCHART invents,
and what a round trip may assert. -
The terminology client (#25), in
ferrochart-term. It resolves the codes
behind a coded field, and the default path needs no network: an
archetype-localat-code list comes out of the template's own terminology
with its rubrics in the requested language, and openEHR's own terminology
groups come from theopenehr-termcrate. A test proves the local path
issues zero HTTP requests. Where the template names a target, the client
calls a FHIR R4 4.0.1 terminology server:ValueSet/$expandto fill a
picker,CodeSystem/$lookupfor the display text of an enumerated external
code, andValueSet/$validate-codeto confirm a chosen one. Every request
is formatted against the generatedfhir-typesoperation contracts, and no
FHIR resource is hand-written. A refused expansion, a value set the server
does not hold, a timeout and a binding no FHIR request can name are each a
typed error carrying the upstream status, theOperationOutcomediagnostics
where the body carries one, and the raw body regardless. None of them is an
empty picker. Expansions are cached per template, language and request, and
a recompile of one template drops that template's entries. -
FerroCHART does not parse the SNOMED CT expression constraint language, and
passes an expression through to the server as the implicit value set of FHIR
R4snomedct.htmlsection 4.3.1.0.9. The reason is in
docs/architecture.mdsection 7.3 and its decision register: executing an
expression needs a SNOMED CT release, a concept store and a closure index,
which is a terminology server's work, andsct-eclwould add a BUSL-1.1
licence exception for a check the server repeats anyway. -
scripts/test-term.shruns the terminology client's wire tests against a
real server, HL7's public R4 service by default and the compose demo profile
with--ferroterm. The cases are#[ignore]d, so a run without a server
reports them as ignored rather than as passes. -
Every chapter that asks for a table of contents is checked to have one
(#98).scripts/checks/book-toc.shreads the rendered pages, and the docs
lane runs it after the site is assembled, because mdBook reports a
preprocessor that ran and produced nothing as a warning at most and would
otherwise publish a chapter with a missing table of contents and a green
build. -
The terminology of an archetype can be enumerated, where it could only be
asked about a code the caller already held (#91).Terminology::definitions
returns the rubrics one language states,all_bindingsand
all_constraint_bindingsreturn every binding as a code and one target, and
value_setsreturns every enumerated value set with its members. All four
borrow the terminology and come back in code order, so a caller that wants
one code still pays for one lookup. The terminology client needs this to
emit an archetype's value sets as FHIRCodeSystemandValueSet
resources, which a lookup-only interface cannot do. -
The openEHR ITS-REST client (#22), in
ferrochart-cdr. It creates, reads
and updates a COMPOSITION, uploads and retrieves a template in both ADL
generations, and creates the EHR a first run needs. Every identifier the
wire carries is its own type, because the three composition operations spell
uid_based_idalike and accept different forms of it: the read takes either
a versioned object uid or a full version uid, and the update takes the
object uid only.If-Matchis sent quoted and unweakened on every update,
Preferis always explicit, and a 412 is a concurrent-edit outcome the form
surfaces rather than a retry. Every status openEHR ITS-REST Release-1.1.0
publishes has its own error variant, plus a catch-all, because the same
section permits statuses beyond that set. Nothing absorbs an upstream
failure into an empty value. -
The FHIR model comes from the published
fhir-typescrate (Apache-2.0,
pinned at 0.1.85), whichferrochart-termnow depends on (#95). It is
generated from the HL7 FHIR packages, soValueSet,CodeSystem,
ConceptMap,ParametersandOperationOutcomeare read from a generated
model the way the openEHR types already are, and no FHIR resource is
hand-written here. The crate also carries$expand,$lookupand
$validate-codeas typed request and response shapes that convert to and
fromParameters, which is why the terminology engine of the same release
line is left alone: FerroCHART is a client of a terminology server rather
than one.docs/architecture.mdsection 7.3 records both decisions.
Fixed
-
The last hand-built archetype identifier in the three-part
template_id
form, inferrochart-form's wire test. #127 corrected the.optfixtures
and its check covers those only, so this one sat in a hand-built key and in
the committed wire snapshot, disagreeing withkey.rs's own example. -
The synthetic fixtures stated two shapes the Reference Model does not admit
(#127), both invisible until the commit gate landed something that judges an
instance. Ten.optfixtures gave anarchetype_ida three-part version,
which is the template identifier's form: openEHR BASE Release-1.2.0
base_types.htmlsection 5.5 gives anarchetype_ida single version
number, and section 5.4.11 leavesTEMPLATE_IDwith no lexical form at all.
TwelveOBSERVATION-rooted fixtures put anITEM_STRUCTURE, aCLUSTERor
anELEMENTstraight underOBSERVATION.data, where RM Release-1.1.0
ehr.htmlsection 8.3.4 types that attributeHISTORY<ITEM_STRUCTURE>, so
aHISTORYand anEVENTbelong between; all 118OBSERVATION.data
attributes of the vendored CKM pack already state it that way. Anything
those fixtures proved about anOBSERVATIONwas proved about a structure no
CDR would accept. A new check over every committed.optfixture holds all
three shapes, so the next one fails at the fixture rather than at a CDR. -
docs/architecture.mdsection 6.2 recorded a corpus split that does not
sum: "87 single-purpose conformance templates plus 16 CKM clinical
templates" for a total of 102. The total is consistent everywhere and is
what every measurement rests on; the split is not re-derivable, because that
corpus has since grown past 400 templates, so the document now says so
rather than repeating an arithmetic that cannot be right. Section 16 gains
the two upstream-report candidates found since it was written (#111, #129). -
An operational template can declare two sibling constraints sharing the node
id, the archetype id, the Reference Model type and the pinned name, which no
instance can tell apart, and a form offering a field per member built a
document its own template refuses (#122). AOM 1.4 permits the shape: it says
a node id distinguishes siblings but states no invariant that requires it,
and the ITS-XML schemas carry no identity constraint either. The compiler now
folds such a group before it computes a key. Members that state the same
constraint become one node, carrying the collective occurrences under a
container attribute, which is lossless because the members are the same
constraint. Members that differ under a container attribute are refused by
name, because no instance could say which one it satisfies; that refuses no
template of the committed pack. Folding before the key is what keeps the
layout overlay stable when a template is republished with the duplicate
gone. Over the pack, two more templates now build a document their own
template accepts, and the gate reports no occurrences failure at all. -
A composition wrapped around a template rooted below COMPOSITION named the
entry's archetype as its own, so the document claimed a COMPOSITION was an
OBSERVATION archetype root. That was 113 of the 123 committed templates.
ehr.htmlsection 5.4.1 makesIs_archetype_rootan invariant of
COMPOSITION andcommon.htmlsection 3.2.2 requires a root's
archetype_node_idto be the stringified archetype id, so the wrapper needs
an archetype of its own. Configuration names it, the way it names the
territory, and a build with none refuses rather than inventing one. Found by
the commit gate of #24. -
A COMPOSITION FerroCHART built put no
ARCHETYPEDon any node below its
root, so every ENTRY it wrote violatedIs_archetype_root
(openEHR RM Release-1.1.0ehr.htmlsection 8.3.1, with
LOCATABLE.Archetyped_validincommon.htmlsection 3.1.2). Every
archetype root below the document root now carries its own archetype
identifier and the Reference Model release, and the template identifier
stays at the document root alone, which is whatcommon.htmlsection 3.2.3
says. The pre-post gate of #24 is what found it.
Changed
- The hard rule about the non-canonical formats now names the two of them
separately, because openEHR only specified one (#104). ITS-REST
Release-1.1.0 publishessimplified_formats.html, "Simplified Formats for
openEHR Data", in the STABLE state, so that document is the authority for
the FLAT and structured formats: their media types (section 2.3), their
field identifiers (section 4.2), level removal (section 4.6), the|other
suffix (section 4.7), and the Reference Model mapping class by class
(section 5). The web template stays a compatibility target, on the same
document's word: section 2.2 puts "Web Template itself as a resource" under
what the specification does not cover. Where the Reference Model and
simplified_formats.htmldisagree, no specification settles it, so the two
divide by subject and a real contradiction is filed upstream.
CLAUDE.md,.claude/rules/spec-adherence.md,.claude/rules/testing.md,
thespec-researcheragent, the/spec-lookupskill, the contributor book
and thecompatlabel all carry the corrected split.
Fixed
docs/VERSIONS.mdsaid "Nothing is vendored yet" twelve lines above the
table of what is vendored, and carried two headings for one subject (#112).
It now has one section that says what is vendored, what is not, and that no
specification text is, which is the fact a reader of a citation needs. The
same file no longer claims there is no Cargo workspace, and
.claude/rules/vendored-inputs.mdno longer says nothing is vendored.- The datatype grid fixture carries the two field kinds it claimed to and did
not (#114).ferro_datatype_grid.optnow states aDV_ORDINALwith three
graded symbols and aDV_STATEwith a two-state machine, so the derivation
of both is snapshotted rather than asserted by a comment.DV_SCALEstays
the exception the comment now names:OpenehrProfile.xsddeclares no
C_DV_SCALE, so only the ADL 2 reader reaches it.