openehr-rails 0.7.0 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.github/workflows/release.yml +2 -0
- data/.ruby-version +1 -1
- data/CHANGELOG.md +57 -0
- data/CLAUDE.md +8 -1
- data/docs/backlog.md +28 -0
- data/docs/design/multi-leaf-non-observation-plan.md +31 -0
- data/docs/design/rm-object-builder-section-instruction-plan.md +134 -0
- data/docs/reports/fsh-generator-log.md +76 -0
- data/docs/reports/referral-upstream-log.md +303 -0
- data/lib/openehr_rails/aql/dataset_adapter.rb +22 -4
- data/lib/openehr_rails/fhir/profile_generator.rb +1 -1
- data/lib/openehr_rails/fhir/type_map.rb +8 -6
- data/lib/openehr_rails/fhir/unsupported_profile_error.rb +25 -12
- data/lib/openehr_rails/opt/field_extractor.rb +10 -2
- data/lib/openehr_rails/rm/rm_object_builder.rb +151 -49
- data/lib/openehr_rails/version.rb +1 -1
- data/spec/openehr_rails/aql/dataset_adapter_spec.rb +47 -0
- data/spec/openehr_rails/aql/executor_execute_demo_queries_spec.rb +101 -0
- data/spec/openehr_rails/aql/executor_spec.rb +68 -0
- data/spec/openehr_rails/fhir/fsh_generator_spec.rb +82 -0
- data/spec/openehr_rails/fhir/profile_generator_spec.rb +80 -0
- data/spec/openehr_rails/opt/field_extractor_binding_spec.rb +21 -1
- data/spec/openehr_rails/rm/rm_object_builder_spec.rb +100 -0
- data/spec/support/synthetic_referral_canonical_hash.rb +80 -0
- metadata +6 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: a30bd4a561f8193c0603c1e43e1873e1c8835d2e7c418b95c429ac6e2b397e83
|
|
4
|
+
data.tar.gz: 180145cf2e294cc68ae84ddc35b147e07e6fb52f99062d14f8df3cb0e306108e
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 46b84468c263139208e522562831d103cd43d8d3c865aa274fe7cf6db7ebe486fa67329b4e175564a9fc0f94d0a0a4454d679f3d42735ac4c7214b739fa7ba3a
|
|
7
|
+
data.tar.gz: dc189063ef16d43253287e9fed472bdc7d69b0b0c72fb5f393f772cf9adbe596ebd24b6dbea57514435c3a6afe8cdba048fd4b1c3c2e73e39b4a17315ad03b6d
|
data/.ruby-version
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
4.0.
|
|
1
|
+
4.0.7
|
data/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,63 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.8.0] - 2026-10-12
|
|
11
|
+
|
|
12
|
+
> **Upgrade note.** A stored Composition holding a `SECTION` or an `INSTRUCTION`
|
|
13
|
+
> (with its `ACTIVITY`s) now reads back through `to_rm` and AQL; the ones 0.7.1
|
|
14
|
+
> skipped with `openehr-rails AQL: skipping composition uid=...` are exactly the
|
|
15
|
+
> ones that become visible, so query row counts can grow. Two injected defaults
|
|
16
|
+
> are approximations until a later release persists them as columns: an
|
|
17
|
+
> INSTRUCTION without a stored narrative reads back with its node name as
|
|
18
|
+
> `narrative`, and every ACTIVITY with `action_archetype_id` `'/.*/'`.
|
|
19
|
+
|
|
20
|
+
### Added
|
|
21
|
+
- `RmObjectBuilder` rebuilds `SECTION`, `INSTRUCTION` and `ACTIVITY` nodes (and
|
|
22
|
+
every CARE_ENTRY's `protocol`), so compositions holding them -- a referral's
|
|
23
|
+
`service_request` with its requester/receiver under `protocol[...]`, entries
|
|
24
|
+
nested in a `SECTION` -- become readable through `to_rm` and queryable by AQL
|
|
25
|
+
instead of being skipped with the 0.7.1 warning (#45). Two values are
|
|
26
|
+
**approximations** because the graph does not carry them yet: an INSTRUCTION
|
|
27
|
+
without a stored narrative gets its node name as `narrative`, and every
|
|
28
|
+
ACTIVITY gets `action_archetype_id` `'/.*/'` (any ACTION archetype). Both will
|
|
29
|
+
be persisted as columns in a later release. `ACTION`, `ITEM_SINGLE` and
|
|
30
|
+
`ITEM_TABLE` are still unsupported (skipped with the warning).
|
|
31
|
+
- `FieldExtractor` fields carry `rm_type_alternatives`: every value type the OPT
|
|
32
|
+
allows for the ELEMENT, in OPT order (e.g. `["DV_TEXT", "DV_CODED_TEXT"]` for
|
|
33
|
+
`problem_diagnosis` at0002). Additive; the chosen `rm_type` is unchanged. Lets a
|
|
34
|
+
host app tell an OR-constrained coded text (free text allowed) from a coded-only
|
|
35
|
+
one instead of rendering an empty select (#52, anlage #33).
|
|
36
|
+
|
|
37
|
+
### Fixed
|
|
38
|
+
- An entry with no extracted leaves (today every `INSTRUCTION`, see #47) no
|
|
39
|
+
longer gets a profile consisting of the archetype `code` rules and an empty
|
|
40
|
+
`component` slicing header; it is skipped and reported through `#skipped`
|
|
41
|
+
with a message saying the entry has no leaves, whatever its resource (#49).
|
|
42
|
+
|
|
43
|
+
## [0.7.1] - 2026-09-25
|
|
44
|
+
|
|
45
|
+
> **Upgrade note.** AQL now skips a stored composition that holds an RM type
|
|
46
|
+
> `RmObjectBuilder` cannot rebuild, with a warning
|
|
47
|
+
> (`openehr-rails AQL: skipping composition uid=...`), instead of failing every
|
|
48
|
+
> query in the store. No host-app change is needed; if that line appears in
|
|
49
|
+
> your log, the composition is a #45 case (SECTION / INSTRUCTION / ACTIVITY
|
|
50
|
+
> read-back, next minor release).
|
|
51
|
+
|
|
52
|
+
### Fixed
|
|
53
|
+
- A single-leaf entry mapped to a resource other than `Observation` and without a
|
|
54
|
+
`TypeMap::ENTRY_ELEMENT_MAPS` row no longer produces `<Resource>.value[x]`, which
|
|
55
|
+
`Condition`/`ServiceRequest`/`Procedure`/`Encounter` do not have; it is skipped and
|
|
56
|
+
reported through `#skipped` like the multi-leaf case since 0.7.0 (#38). The
|
|
57
|
+
`UnsupportedProfileError` message now names both missing elements.
|
|
58
|
+
- AQL no longer fails for the whole store when one stored composition cannot be
|
|
59
|
+
rebuilt as RM objects (a node type outside `RmObjectBuilder::TYPE_CLASSES`,
|
|
60
|
+
such as `SECTION`/`INSTRUCTION`, or an RM constructor rejecting stored data).
|
|
61
|
+
`DatasetAdapter` now warns (`Rails.logger` when present, else stderr), naming
|
|
62
|
+
the composition uid and the cause, and skips that composition; queries on the
|
|
63
|
+
rest of the store return their rows. `RmObjectBuilder` raises
|
|
64
|
+
`OpenehrRails::Rm::UnsupportedRmTypeError` (composition uid, node path,
|
|
65
|
+
rm_type) instead of an accidental `NoMethodError` (#44).
|
|
66
|
+
|
|
10
67
|
## [0.7.0] - 2026-09-10
|
|
11
68
|
|
|
12
69
|
> **Upgrade note.** Regenerate `app/fhir/profiles/*.json`. `Condition.component`
|
data/CLAUDE.md
CHANGED
|
@@ -61,6 +61,13 @@ documentation files and `lib/` was byte-identical - but nothing in the release
|
|
|
61
61
|
path caught it. Measurements in `docs/reports/fsh-generator-log.md` R8; the
|
|
62
62
|
matching `release:check` guard is `skoba/openehr-rails#34`.)
|
|
63
63
|
|
|
64
|
+
**Local dev Ruby tracks the patch release CI builds with.** `.ruby-version`
|
|
65
|
+
moved 4.0.6 -> 4.0.7 (2026-10-12) so a local rebuild at the tag stamps the same
|
|
66
|
+
`rubygems_version` (4.0.20) as `ruby/setup-ruby`'s ruby 4.0 image did for 0.7.1,
|
|
67
|
+
whose `metadata.gz` differed from the local rebuild by that one line
|
|
68
|
+
(`docs/reports/referral-upstream-log.md` R2). The cross-check still judges by
|
|
69
|
+
`data.tar.gz`, not the whole-gem sha256: the two toolchains can drift apart again.
|
|
70
|
+
|
|
64
71
|
**Confirm publication by checksum, not by version number.** RubyGems publishes
|
|
65
72
|
the sha256 it recorded at push time (`/api/v1/gems/openehr-rails.json` `sha`, and
|
|
66
73
|
the `checksum:` field in `https://index.rubygems.org/info/openehr-rails`). The
|
|
@@ -225,7 +232,7 @@ This is `openehr-rails`, a Rails engine gem that turns an openEHR Operational Te
|
|
|
225
232
|
|
|
226
233
|
## Development Notes
|
|
227
234
|
|
|
228
|
-
- Ruby 3.3+ required (raised from 3.0 in 2026-08 to track the `openehr` gem dependency dropping Ruby 3.2 support at EOL); CI matrix covers 3.3/3.4/4.0, local dev pinned via `.ruby-version` (currently 4.0.
|
|
235
|
+
- Ruby 3.3+ required (raised from 3.0 in 2026-08 to track the `openehr` gem dependency dropping Ruby 3.2 support at EOL); CI matrix covers 3.3/3.4/4.0, local dev pinned via `.ruby-version` (currently 4.0.7)
|
|
229
236
|
- Rails 7.0+ and Rails 8.x supported (CI matrix: `gemfiles/rails_{7_2,8_0,8_1}.gemfile`; demo app runs on Rails 8.1)
|
|
230
237
|
- URI compatibility workaround implemented for Ruby 3.4
|
|
231
238
|
- `ostruct` is an explicit development dependency — it left Ruby's default gems as of 4.0, and a couple of specs use `OpenStruct` as a lightweight test double
|
data/docs/backlog.md
CHANGED
|
@@ -74,6 +74,26 @@ that verification is deferred to the next real release (>= 0.5.0), not simulated
|
|
|
74
74
|
|
|
75
75
|
## Release automation
|
|
76
76
|
|
|
77
|
+
- **`release.yml` records no sha256 of the built `.gem`** (found at the 0.7.0
|
|
78
|
+
release, 2026-09-10, `docs/reports/fsh-generator-log.md` R14). The only digest in
|
|
79
|
+
the run log is `actions/upload-artifact`'s "SHA256 digest of uploaded artifact",
|
|
80
|
+
which hashes the uploaded archive, not the gem file, so `CLAUDE.md`'s "compare
|
|
81
|
+
against the value recorded for that run" cannot be followed literally; the
|
|
82
|
+
tag-rebuild cross-check is what pins the bytes today. Add a "Record sha256" step
|
|
83
|
+
after `rake build` (`sha256sum pkg/*.gem`), as openehr-ruby's `release.yml` has.
|
|
84
|
+
CI-only change; needs a PR, no Issue. **In PR #51 as `1410274` (2026-10-12,
|
|
85
|
+
`docs/reports/referral-upstream-log.md` R5)**; first run that prints it will be
|
|
86
|
+
the `v0.8.0` tag's.
|
|
87
|
+
- **The tag-rebuild cross-check compares `data.tar.gz`, not the whole `.gem`**
|
|
88
|
+
(0.7.1, 2026-09-25, `docs/reports/referral-upstream-log.md` R2). A `.gem` embeds
|
|
89
|
+
`rubygems_version` in `metadata.gz`, so a rebuild on a different ruby/rubygems
|
|
90
|
+
(local 4.0.6/4.0.16 vs CI 4.0.7/4.0.20) yields a different whole-gem sha256 with
|
|
91
|
+
byte-identical shipped files. Procedure: `tar xf` both gems, compare
|
|
92
|
+
`sha256sum data.tar.gz` (must match) and `diff` the gunzipped `metadata.gz`
|
|
93
|
+
(only `rubygems_version` may differ). 0.7.0's whole-gem match was a coincidence
|
|
94
|
+
of equal toolchains. Fold this into `CLAUDE.md`'s Release convention together
|
|
95
|
+
with the "Record sha256" step above.
|
|
96
|
+
|
|
77
97
|
**Done (2026-08-23, PR #28)** — kept below for the original rationale; see the CI
|
|
78
98
|
status entry above for verification details.
|
|
79
99
|
|
|
@@ -122,6 +142,14 @@ status entry above for verification details.
|
|
|
122
142
|
|
|
123
143
|
## Fixture conventions
|
|
124
144
|
|
|
145
|
+
- **`spec/templates/sample_blood_pressure.opt` does not parse** -- `OpenehrRails::Opt.parse`
|
|
146
|
+
raises `ArgumentError: invalid archetype id form` from
|
|
147
|
+
`OpenEHR::RM::Support::Identification::ArchetypeID` under openehr 2.4.2 *and* 2.4.3
|
|
148
|
+
(measured 2026-09-10 while checking fixtures for #38), and no spec, script or
|
|
149
|
+
generator references the file. Orphan fixture: either find which archetype id in
|
|
150
|
+
it is malformed and decide whether that is an openehr-ruby parser gap worth an
|
|
151
|
+
upstream Issue, or delete the file. Not touched in 0.7.0.
|
|
152
|
+
|
|
125
153
|
- **Licensed terminology-code literals in spec expectations: keep minimal, cite the
|
|
126
154
|
source fixture's file:line.** Adopted from Anlage's C2 firewall precedent (SNOMED
|
|
127
155
|
CT is a licensed terminology; reproducing its codes verbatim in more places than
|
|
@@ -365,3 +365,34 @@ Still **minor**, on top of §8.5: `#skipped` and `UnsupportedProfileError` are
|
|
|
365
365
|
new public API; the `category` anchor and the `comment` change the JSON facade's
|
|
366
366
|
shape again for `EVALUATION` entries. `CHANGELOG.md` `[Unreleased]` updated in
|
|
367
367
|
the same change.
|
|
368
|
+
|
|
369
|
+
## 9.7 #38 (2026-09-10 ruling): the decision point widened to any leaf count
|
|
370
|
+
|
|
371
|
+
The ruling on 9.5 allowed #38 to ride in 0.7.0 if it stayed on the same
|
|
372
|
+
decision point, small, and green. It does: `TypeMap.assert_supported!` drops
|
|
373
|
+
its `fields.size <= 1` early return, so *any* entry whose base resource is not
|
|
374
|
+
`Observation` and which has no `ENTRY_ELEMENT_MAPS` row is skipped and
|
|
375
|
+
reported -- a single leaf would have produced `<Resource>.value[x]`, which
|
|
376
|
+
`Condition` / `ServiceRequest` / `Procedure` / `Encounter` lack just as they
|
|
377
|
+
lack `component` (measured: 1 sushi Error on the 9.5 probe). The error message
|
|
378
|
+
now names both missing elements and the leaf count in the singular where it is
|
|
379
|
+
one. Resolution shape (a) bug.
|
|
380
|
+
|
|
381
|
+
- **Fixture check before widening**: every OPT under `spec/templates/`,
|
|
382
|
+
`spec/generators/templates/` and `demo_assets/templates/` was listed with
|
|
383
|
+
`FieldExtractor#entries` -- all single-leaf entries are `OBSERVATION`
|
|
384
|
+
(`height.v2`, `body_weight.v2`, `heart_rate-pulse.v1`); the only
|
|
385
|
+
non-`Observation` entry is `problem_diagnosis.v1` (5 leaves, mapped). So no
|
|
386
|
+
fixture's output changes. (`spec/templates/sample_blood_pressure.opt` does not
|
|
387
|
+
parse at all -- `ArgumentError: invalid archetype id form` -- under openehr
|
|
388
|
+
2.4.2 *and* 2.4.3, and no spec references it; pre-existing, noted in
|
|
389
|
+
`docs/backlog.md`, not touched here.)
|
|
390
|
+
- **Red**: 4 new examples (two per generator, synthetic single-leaf
|
|
391
|
+
`EVALUATION` entry `openEHR-EHR-EVALUATION.synthetic_single_leaf_test.v1`):
|
|
392
|
+
**40 examples, 4 failures** across the two spec files.
|
|
393
|
+
- **Green**: the same files 40/0; `spec/openehr_rails/fhir/` 52/0; full suite
|
|
394
|
+
308/0. Regenerated FSH for `problem_list.opt` + `bmi_calculation.opt`
|
|
395
|
+
byte-identical to before and **0 Errors** under `sushi` 3.16.0 -- the pin.
|
|
396
|
+
- **Semver**: 0.7.1 (0.7.0 shipped before PR #43 was merged; see log R13); a bug fix (patch) that changes no
|
|
397
|
+
fixture output, only what an unmapped single-leaf non-`Observation` entry
|
|
398
|
+
yields (invalid FHIR before, a `#skipped` entry now).
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
# Plan: `RmObjectBuilder` reads back SECTION / INSTRUCTION / ACTIVITY
|
|
2
|
+
|
|
3
|
+
- Status: **explore + plan, awaiting approval** (2026-09-25). No code written.
|
|
4
|
+
- Issue: [#45](https://github.com/skoba/openehr-rails/issues/45) (anlage upstream candidate 15)
|
|
5
|
+
- Log: `docs/reports/referral-upstream-log.md` R1
|
|
6
|
+
- Prerequisite landed as its own fix: #44 / PR #50 (a failing `to_rm` no longer
|
|
7
|
+
fails the whole store; unknown types raise `UnsupportedRmTypeError`).
|
|
8
|
+
|
|
9
|
+
## 1. Current behaviour (measured, `file:line` on `master` after PR #50)
|
|
10
|
+
|
|
11
|
+
**Write side accepts the types.** `Rm::TypeMap::NODE_TYPES`
|
|
12
|
+
(`lib/openehr_rails/rm/type_map.rb:9-26`) lists SECTION, INSTRUCTION, ACTION,
|
|
13
|
+
ACTIVITY (and ITEM_SINGLE, ITEM_TABLE); the STI classes exist
|
|
14
|
+
(`lib/openehr_rails/rm/nodes.rb:10,14,15,18`). `GraphBuilder#infer_type`
|
|
15
|
+
(`lib/openehr_rails/rm/graph_builder.rb:111-122`) maps `activities` -> ACTIVITY and
|
|
16
|
+
`protocol` / `description` -> ITEM_TREE for `_type`-less hashes. `build_children`
|
|
17
|
+
(`:64-79`) persists Hash-valued attributes as child nodes or data-value rows and
|
|
18
|
+
Array-valued ones as ordered children; **String-valued attributes are dropped** --
|
|
19
|
+
so `ACTIVITY.action_archetype_id` never reaches the graph. `INSTRUCTION.narrative`
|
|
20
|
+
(DV_TEXT), `ACTIVITY.timing` (DV_PARSABLE: `text_value` + `formalism`, `:180-181`)
|
|
21
|
+
and `INSTRUCTION.expiry_time` (DV_DATE_TIME) are stored as data-value rows keyed by
|
|
22
|
+
`rm_attribute_name`.
|
|
23
|
+
|
|
24
|
+
**Read side does not.** `RmObjectBuilder::TYPE_CLASSES`
|
|
25
|
+
(`lib/openehr_rails/rm/rm_object_builder.rb`, 10 entries) has none of them;
|
|
26
|
+
`build_node` sets entry defaults only for Observation / Evaluation / AdminEntry,
|
|
27
|
+
`data` only for `EntryNode`, and never `protocol`, `narrative`, `activities`,
|
|
28
|
+
`description`. After PR #50 such a node raises `UnsupportedRmTypeError` and the
|
|
29
|
+
composition is skipped from AQL with a warning; before it, the whole store failed
|
|
30
|
+
(anlage referral-intake-log R6).
|
|
31
|
+
|
|
32
|
+
**What the openehr gem (2.4.3) demands of the objects** (`openehr-ruby`
|
|
33
|
+
`lib/openehr/rm/composition/content/`):
|
|
34
|
+
|
|
35
|
+
| class | mandatory | optional / notes |
|
|
36
|
+
|---|---|---|
|
|
37
|
+
| `Navigation::Section` (`navigation.rb:12-27`) | -- | `items` must be nil or non-empty; `path_attribute :items` |
|
|
38
|
+
| `Entry::Instruction` (`entry.rb:112-138`) | Entry: `language`, `encoding`, `subject`; `narrative` | `activities` nil or non-empty; `expiry_time`, `wf_definition`; CareEntry `protocol`, `guideline_id` (`entry.rb:69-78`); `path_attribute :activities, :protocol` |
|
|
39
|
+
| `Entry::Activity` (`entry.rb:140-171`) | `description`, `action_archetype_id` (non-empty String) | `timing` optional since RM 1.1.0; `path_attribute :description` |
|
|
40
|
+
| `Entry::Action` (`entry.rb:173-204`) | Entry attrs; `time`, `description`, `ism_transition` (with `current_state` validated against the openEHR terminology, `:236-275`) | out of scope here, see section 5 |
|
|
41
|
+
|
|
42
|
+
`OpenEHR::RM::Composition::Composition` has `path_attribute :content, :context`,
|
|
43
|
+
so objects built with the attributes above are navigable by the AQL engine's
|
|
44
|
+
path evaluator without engine changes.
|
|
45
|
+
|
|
46
|
+
## 2. Design -- phase A, no schema change
|
|
47
|
+
|
|
48
|
+
1. `TYPE_CLASSES` gains `SECTION`, `INSTRUCTION`, `ACTIVITY`.
|
|
49
|
+
2. `build_node` gains, per type (each in its own small private helper, because
|
|
50
|
+
`build_node` already sits at rubocop's AbcSize/complexity limits -- PR #50 had to
|
|
51
|
+
extract `node_class` for a one-line change):
|
|
52
|
+
- **Section**: `items` = children built in position order; `nil` when there
|
|
53
|
+
are none (the constructor rejects `[]`).
|
|
54
|
+
- **Instruction**: the same entry defaults as the other entries
|
|
55
|
+
(`language` / `encoding` / `subject`; extend the `is_a?` list);
|
|
56
|
+
`narrative` = the `narrative` data-value row as DvText, **defaulting to the
|
|
57
|
+
node's name** when the row is absent (an injected default, documented like
|
|
58
|
+
`language`); `activities` = children with `rm_attribute_name == 'activities'`,
|
|
59
|
+
`nil` when none; `expiry_time` when its row exists.
|
|
60
|
+
- **Activity**: `description` = the `description` child (ITEM_TREE) -- no
|
|
61
|
+
default: a missing description is an RM-conformance failure and surfaces
|
|
62
|
+
through #44's warning; `timing` = the `timing` row as
|
|
63
|
+
`OpenEHR::RM::DataTypes::Encapsulated::DvParsable` when present;
|
|
64
|
+
`action_archetype_id` = the injected default `'/.*/'` (the RM's "any ACTION
|
|
65
|
+
archetype" pattern) because the graph cannot carry it yet (section 5).
|
|
66
|
+
- **`protocol` for every CareEntry** (Observation, Evaluation, Instruction):
|
|
67
|
+
`attrs[:protocol] = build_node(protocol child)` when present. Same
|
|
68
|
+
mechanism, and it is where `jp_referral` keeps 紹介先/紹介元
|
|
69
|
+
(`service_request` `protocol[at0008]`, anlage memory of 2026-09-25) -- without
|
|
70
|
+
it the INSTRUCTION would be readable but its most-queried data not.
|
|
71
|
+
3. `UnsupportedRmTypeError` keeps covering ACTION, ITEM_SINGLE, ITEM_TABLE.
|
|
72
|
+
|
|
73
|
+
Injected defaults are listed in the class comment next to the existing ones.
|
|
74
|
+
|
|
75
|
+
## 3. Spec plan (t-wada: red before green), resolution shape (b) enhancement
|
|
76
|
+
|
|
77
|
+
- **Fixture**: a spec-level synthetic canonical hash (invented ids, stated in the
|
|
78
|
+
comment with this section as design authority; no real canonical JSON with
|
|
79
|
+
SECTION/INSTRUCTION exists in this repo -- anlage's is hand-mapped and outside):
|
|
80
|
+
COMPOSITION whose `content` is `[SECTION { items: [EVALUATION { data: ITEM_TREE {
|
|
81
|
+
items: [ELEMENT DV_TEXT] } }] }, INSTRUCTION { narrative, protocol: ITEM_TREE {
|
|
82
|
+
items: [ELEMENT DV_TEXT] }, activities: [ACTIVITY { description: ITEM_TREE {
|
|
83
|
+
items: [ELEMENT DV_TEXT] }, timing: DV_PARSABLE }] }]`, committed with
|
|
84
|
+
`CompositionCommitter`.
|
|
85
|
+
- `rm_object_builder_spec.rb`: **red** today = `UnsupportedRmTypeError`; green =
|
|
86
|
+
`Section` with one `Evaluation` item; `Instruction` with the stored narrative,
|
|
87
|
+
one `Activity` whose `description.items.first.value` is the DvText,
|
|
88
|
+
`action_archetype_id == '/.*/'`, `protocol.items` present; entry defaults on the
|
|
89
|
+
Instruction.
|
|
90
|
+
- `executor_spec.rb`: AQL through the new objects --
|
|
91
|
+
`SELECT i/activities[at0001]/description[at0009]/items[at0121]/value/value ...
|
|
92
|
+
CONTAINS INSTRUCTION i[<synthetic id>]` and
|
|
93
|
+
`SELECT i/protocol[at0008]/items[at0010]/value/value`, plus
|
|
94
|
+
`... CONTAINS SECTION s[<id>] CONTAINS EVALUATION ev[<id>]`. Whether the
|
|
95
|
+
engine's CONTAINS chain accepts SECTION/ACTIVITY is **unknown until measured**;
|
|
96
|
+
if it does not, that becomes an openehr-ruby item and the spec pins the `i/...`
|
|
97
|
+
path form only.
|
|
98
|
+
- `dataset_adapter_spec.rb` / `executor_spec.rb` (#44): switch the "to_rm fails"
|
|
99
|
+
fixture from SECTION to ITEM_TABLE, which stays unsupported.
|
|
100
|
+
- Regression pins: `bmi_calculation` / `problem_list` specs unchanged; full suite
|
|
101
|
+
green; `CanonicalSerializer` round-trip of the new fixture is checked and, if it
|
|
102
|
+
does not survive (`narrative` / `timing` rows), recorded as its own issue rather
|
|
103
|
+
than fixed here.
|
|
104
|
+
|
|
105
|
+
## 4. Size and schedule
|
|
106
|
+
|
|
107
|
+
Estimate: +3 map entries; ~50 lines of new helpers plus splitting `build_node`'s
|
|
108
|
+
existing per-type `if` blocks into helpers (~80 lines moved, behaviour-neutral,
|
|
109
|
+
needed to stay inside the rubocop limits); ~130 lines of specs across three files;
|
|
110
|
+
no migration, no generator template change, no dependency change. **Small** by the
|
|
111
|
+
ruling's criterion (same builder, one file of runtime code, existing test
|
|
112
|
+
infrastructure). Recommendation: **implement before the freeze**, in one PR,
|
|
113
|
+
`Fixes #45`, after this plan is approved.
|
|
114
|
+
|
|
115
|
+
## 5. Out of scope (phase B, December unless pulled forward)
|
|
116
|
+
|
|
117
|
+
- **Persisting `action_archetype_id`**, `narrative`, `timing` as columns instead
|
|
118
|
+
of injected defaults / data-value rows: needs a migration in
|
|
119
|
+
`lib/generators/**/templates/` (shipped product, host apps migrate) -- its own
|
|
120
|
+
issue and plan.
|
|
121
|
+
- **ACTION**: `ism_transition` is persisted today as a generic CLUSTER node
|
|
122
|
+
(`infer_type` falls through), and rebuilding it needs codes valid against the
|
|
123
|
+
terminology; separate design.
|
|
124
|
+
- **ITEM_SINGLE / ITEM_TABLE**: no consumer yet.
|
|
125
|
+
|
|
126
|
+
## 6. Semver
|
|
127
|
+
|
|
128
|
+
New read-side capability, observable through AQL and `to_rm`: **minor**. If it
|
|
129
|
+
lands with #38 (PR #43) and #44 (PR #50), the next release is **0.8.0**, not 0.7.1
|
|
130
|
+
-- to be decided at the inventory.
|
|
131
|
+
|
|
132
|
+
## 7. Stop point
|
|
133
|
+
|
|
134
|
+
Explore + plan only. Implementation starts on approval.
|
|
@@ -923,3 +923,79 @@ retitled `[0.7.0] - 2026-09-10` with the Upgrade note, fresh empty
|
|
|
923
923
|
`[Unreleased]`) -> tag `v0.7.0` -> `release.yml` -> artifact sha256 (R14) ->
|
|
924
924
|
human `gem push` of that artifact -> confirmation by published checksum, the
|
|
925
925
|
first application of the rule PR #42 added.
|
|
926
|
+
|
|
927
|
+
## R14 -- v0.7.0 tagged, release.yml green, artifact sha256 recorded; gem push is the human's
|
|
928
|
+
|
|
929
|
+
- Release prep on `master` after `acb1e3f`: `b1bfaa3` (lint), `2212955` (R13),
|
|
930
|
+
`aafbd2c` (Release: bump version to 0.7.0). Before the release commit: full
|
|
931
|
+
suite **304 examples, 0 failures**, `rubocop` **109 files, no offenses**,
|
|
932
|
+
`release:check OK` (no tag yet, so the tag check was silent by design).
|
|
933
|
+
- Tag `v0.7.0` -> `aafbd2c`, pushed 2026-09-10. **Deviation noted**: this is a
|
|
934
|
+
lightweight tag; `v0.6.0` is an annotated tag object. Harmless for
|
|
935
|
+
`release.yml` (tag push) and `release:check` (`v0.7.0^{commit}`), but the
|
|
936
|
+
next release should use `git tag -a` to keep the series uniform.
|
|
937
|
+
- `release.yml` run **34438238454**: all 12 jobs success (9 spec matrix, demo
|
|
938
|
+
smoke, application template smoke, Build gem artifact). `release:check OK`
|
|
939
|
+
inside the run, i.e. HEAD was the tag commit.
|
|
940
|
+
- **Artifact**: downloaded with `gh run download 34438238454 -n gem -D pkg`:
|
|
941
|
+
`pkg/openehr-rails-0.7.0.gem`, 242176 bytes,
|
|
942
|
+
sha256 **`922ec940f15c8793ef6ee08568e4d7ea16f8a158da0d45936ff898e73cd1171a`**.
|
|
943
|
+
- **Cross-check**: a fresh `gem build` in a scratch worktree at `v0.7.0`
|
|
944
|
+
(local ruby 4.0.6, not `pkg/`) produced the **same sha256** -- CI artifact and
|
|
945
|
+
tag rebuild are byte-identical, as for 0.5.0 and 0.6.0.
|
|
946
|
+
- **Gap found in the comparison rule**: `CLAUDE.md` says to compare the
|
|
947
|
+
downloaded artifact "against the value recorded for that run", but
|
|
948
|
+
`release.yml` records no gem sha256 -- the only digest in the run log is
|
|
949
|
+
`actions/upload-artifact`'s `SHA256 digest of uploaded artifact`
|
|
950
|
+
(`671c8de1…238b`), which is the digest of the uploaded archive, **not of the
|
|
951
|
+
.gem**. The two are not comparable. The tag-rebuild cross-check above is what
|
|
952
|
+
actually pins the bytes today. Filed in `docs/backlog.md` "Release
|
|
953
|
+
automation": add a "Record sha256" step (as openehr-ruby's `release.yml`
|
|
954
|
+
has) so the rule can be followed literally.
|
|
955
|
+
- **Handed to the human**: `gem push pkg/openehr-rails-0.7.0.gem` (the
|
|
956
|
+
downloaded CI artifact, never a local build), then confirm by checksum per
|
|
957
|
+
the rule PR #42 added: `https://rubygems.org/api/v1/gems/openehr-rails.json`
|
|
958
|
+
`sha` (or the compact index `checksum:`) must equal `922ec940…171a`; use
|
|
959
|
+
`versions/openehr-rails/latest.json` rather than `versions/openehr-rails.json`
|
|
960
|
+
while the latter lags. Then delete `pkg/openehr-rails-0.7.0.gem`. Result goes
|
|
961
|
+
in R15.
|
|
962
|
+
- `master` is now past the tag by the docs commits that record this entry, so
|
|
963
|
+
`release:check` on `master` fails again by design until 0.7.1.
|
|
964
|
+
|
|
965
|
+
## R15 -- 0.7.0 published; confirmed by checksum (first application of the PR #42 rule)
|
|
966
|
+
|
|
967
|
+
Human `gem push` of the CI artifact `pkg/openehr-rails-0.7.0.gem` (R14). Confirmation
|
|
968
|
+
2026-09-10, every source compared against the CI artifact's sha256
|
|
969
|
+
`922ec940f15c8793ef6ee08568e4d7ea16f8a158da0d45936ff898e73cd1171a`:
|
|
970
|
+
|
|
971
|
+
| source | value |
|
|
972
|
+
|---|---|
|
|
973
|
+
| `/api/v1/gems/openehr-rails.json` `sha` | `922ec940…171a`, version 0.7.0 |
|
|
974
|
+
| compact index `https://index.rubygems.org/info/openehr-rails` | `checksum:922ec940…171a`, `created_at:2026-09-10T11:47:16Z` |
|
|
975
|
+
| `/api/v1/versions/openehr-rails/latest.json` | `{"version":"0.7.0"}` |
|
|
976
|
+
| `/api/v1/versions/openehr-rails.json` | 0.7.0, `sha` `922ec940…171a` (no lag observed this time) |
|
|
977
|
+
| `gem list -r -e openehr-rails` | 0.7.0 |
|
|
978
|
+
|
|
979
|
+
CI artifact, tag rebuild and published gem are one and the same bytes. The
|
|
980
|
+
`pkg/` copy was deleted after the confirmation, leaving `pkg/` empty.
|
|
981
|
+
|
|
982
|
+
### Tooling note (why two commits on the #43 branch fix single characters)
|
|
983
|
+
|
|
984
|
+
The PowerShell -> `wsl` wrapper used to run this session's scripts carried a
|
|
985
|
+
`sed -i "s/\r$//"`; the `\r` reached WSL as a plain `r`, so every script line
|
|
986
|
+
ending in "r" lost that letter. Effects found and handled: `git checkout master`
|
|
987
|
+
silently became `maste` (harmless, caught by the error), a backlog line on the
|
|
988
|
+
#43 branch was committed as "script o" (restored in `566cddb`), and the
|
|
989
|
+
`5fcc0ec` commit message reads "unde" for "under" (left as is). `master`'s
|
|
990
|
+
tracked files were grepped for the same pattern: clean. The wrapper no longer
|
|
991
|
+
runs sed.
|
|
992
|
+
|
|
993
|
+
### State after 0.7.0
|
|
994
|
+
|
|
995
|
+
- `master` = tag `v0.7.0` + docs (R14, R15). `release:check` fails on `master`
|
|
996
|
+
by design until the next release.
|
|
997
|
+
- PR #43 (`fix/38-single-leaf-non-observation`, Fixes #38): rebased for 0.7.1,
|
|
998
|
+
CHANGELOG line under the new `[Unreleased]`, awaiting the human's merge.
|
|
999
|
+
- Open follow-ups: `release.yml` "Record sha256" step (backlog, CI-only PR);
|
|
1000
|
+
next tag annotated (`git tag -a`); `json < 3` pins until Rails ships the
|
|
1001
|
+
`JSON.decode` fix (#40, backlog); reserves #35, #36, #37.
|