Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions .changeset/wild-pears-refresh.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
---
"@cosyte/transform": patch
---

Consume `@cosyte/hl7` from the registry at `0.0.10` instead of a vendored tarball at `0.0.1`, and prove by measurement that nothing this package emits moved with it. No emitted FHIR value changes, no diagnostic changes, no issue code is added, renamed or removed, and no mapping is touched: `src/` is byte-for-byte unchanged by this release.

The parser was nine published versions behind, pinned to a `pnpm pack` archive committed into the repository, which meant the version the tests exercised was watched by no dependency route and could only move by hand. It is now a plain devDependency resolved through the lockfile, the archive is deleted, and no copy of the library source remains in the tree. `@cosyte/fhir` is unaffected and stays vendored, for the one reason it always was: the registry does not have it.

Because this package sits in a PHI dataflow and its promise is never a confident wrong FHIR value, a green suite was not accepted as evidence on its own. Every HL7 v2 fixture the repository carries was collected mechanically into a frozen corpus, four synthetic inputs were authored for the malformed, truncated, empty and wrong-version classes, and all of it was transformed once on each side of the bump. The compared surface, meaning the FHIR output plus every diagnostic in emission order, is byte-identical across all 128 members. Both captures are committed beside the record so the comparison can be rerun rather than believed.

Two suites are added and none is removed or relaxed. One asserts the fail-safe rule class by class for malformed input, and sweeps every diagnostic the whole corpus raises to confirm each carries a registry-static message at a positional locator and no field content. The other records, as a call that compiles and runs, two upstream capabilities whose earlier absence shaped this package: an ADT message builder and a typed composite encoder both exist now. Neither is adopted here. The visit-carrying `Patient` plus `Encounter` output stays deferred, and the reverse path keeps building its fields by hand, because a refresh whose whole claim is that nothing moved cannot also change what is emitted.
13 changes: 8 additions & 5 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
# The vendored `@cosyte/hl7` and `@cosyte/fhir` tarballs are third-party archives that this
# repository consumes for dev and test (ADR 0001; refresh them with `pnpm vendor:refresh`).
# Declaring them keeps git from ever treating them as text, and it is the declaration that
# The vendored `@cosyte/fhir` tarball is a third-party archive that this repository consumes for
# dev and test (ADR 0001; refresh it with `pnpm vendor:refresh`). `@cosyte/hl7` used to sit beside
# it and no longer does: it is a registry devDependency resolved through `pnpm-lock.yaml`, so
# nothing vendored carries it. The glob is kept rather than narrowed to one filename because it is
# the shape `vendor/` has always had, and a rename must not silently escape it.
# Declaring the archive keeps git from ever treating it as text, and it is the declaration that
# `scripts/check-no-emdash.mjs` partitions on: a DEFLATE stream can hold the em dash's UTF-8
# bytes by coincidence, `vendor/cosyte-hl7-0.0.0.tgz` does, and there is no edit that removes
# a byte from someone else's compressed stream.
# bytes by coincidence, and there is no edit that removes a byte from someone else's compressed
# stream.
#
# THIS FILE IS NOT A SILENCER. The em-dash gate REFUSES any `binary` declaration outside
# `vendor/`, so widening the exclusion means editing that script deliberately rather than
Expand Down
26 changes: 17 additions & 9 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,14 @@ as a trap is clinical-safety content.
`TRANSFORM_NO_V2_MESSAGE_EMITTED` instead of returning an empty success. **The usage cells behind
those rows are asserted, NOT extracted** (the pass that wrote them had no network egress), so
re-extract before trusting or widening them. The `Patient` + `Encounter` visit-carrying ADT is
**deferred, not dropped**: the vendored parser exports no ADT assembly entry point (measured, zero
occurrences in its `dist/`), and hand-assembling PID + PV1 here would invert the tier split. Every
measurement, the refusal set, and the deferral:
`documentation/agent-notes.md#the-reverse-direction-and-what-it-does-not-claim`. Phase **8
**deferred, not dropped**, and **▶ THE UPSTREAM REASON FOR THE DEFERRAL IS GONE WHILE THE SHAPE IS
STILL NOT BUILT**: the parser exported no ADT assembly entry point when it was deferred, and
`@cosyte/hl7` `0.0.10` exports `buildAdt` (measured by a call that compiles and runs, in
`test/upstream-capabilities.test.ts`). Nothing else about the deferral changed, so do not read
"the builder exists" as "the shape is ready": hand-assembling PID + PV1 here would still invert
the tier split, and the IG grounding is still owed. Every measurement, the refusal set, and the
deferral: `documentation/agent-notes.md#the-reverse-direction-and-what-it-does-not-claim`; the
dependency refresh that took the measurement: `documentation/hl7-refresh/record.md`. Phase **8
(profiles)** and deeper terminology remain deferred.
- **Never quote a version here.** This line read "not yet published to npm" for several releases
after first publish, which is part of why a `VERSION` constant stuck at `"0.0.0"` shipped unnoticed.
Expand All @@ -63,11 +67,15 @@ as a trap is clinical-safety content.
never recall: `npm view @cosyte/fhir version`. **Visibility and publish state are independent**;
never infer one from the other. Why:
`documentation/agent-notes.md#publish-state-and-the-stale-claim-inside-it`.
- **Consumes two cosyte siblings** (`@cosyte/hl7`, `@cosyte/fhir`) as **peer dependencies**, vendored
as `pnpm pack` tarballs in `vendor/` for dev/test (ADR 0001 + umbrella ADR 0008): refresh with
`pnpm vendor:refresh`. Pinned shas: hl7 `46d50eb`, fhir `7a099b2`. **They are not both unpublished,
and that wording was stale**; `@cosyte/hl7` is on the registry and it is the `fhir` peer alone that
makes this package uninstallable. **Third-party runtime deps: zero.**
- **Consumes two cosyte siblings** (`@cosyte/hl7`, `@cosyte/fhir`) as **peer dependencies**, and the
two are no longer consumed the same way for dev/test. **`@cosyte/hl7` is a plain registry
devDependency** resolved through `pnpm-lock.yaml`; **▶ DO NOT RE-VENDOR IT**, and do not add
`vendor/cosyte-hl7-*.tgz` back, because a second copy of that library in this tree is what
removing it was for. **`@cosyte/fhir` alone stays a vendored `pnpm pack` tarball** in `vendor/`
(ADR 0001 + umbrella ADR 0008; refresh with `pnpm vendor:refresh`, pinned sha `7a099b2`), for one
reason and one only: the registry does not have it. **They were never both unpublished, and that
wording was stale**; it is the `fhir` peer alone that makes this package uninstallable.
**Third-party runtime deps: zero.**

## Tech Stack (the shared `@cosyte/*` standard)

Expand Down
7 changes: 4 additions & 3 deletions docs-content/installation.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,10 @@ the package is not on the registry at all; dropping it and installing this packa
succeed, but leaves both peers genuinely absent at runtime, so the first conversion you attempt
fails.

Until `@cosyte/fhir` publishes, this repo's own tests build against **vendored tarballs** in
`vendor/` (regenerated by `pnpm vendor:refresh`): the same interim mechanism `@cosyte/mllp` uses,
replaced by a real npm install once the peer is on the registry.
This repo's own tests install `@cosyte/hl7` from the registry, exactly as a consumer does. Until
`@cosyte/fhir` publishes, that one peer alone builds from a **vendored tarball** in `vendor/`
(regenerated by `pnpm vendor:refresh`): the same interim mechanism `@cosyte/mllp` uses, replaced by
a real npm install once the peer is on the registry.

## Smoke test

Expand Down
53 changes: 36 additions & 17 deletions documentation/agent-notes.md
Original file line number Diff line number Diff line change
Expand Up @@ -136,15 +136,24 @@ wrong field number it fires on every conversion rather than once.
`Do\S\e\F\Public` and reads back identically, where a hand-joined `"Do^e"` string would have become
two components. Nothing in `src/reverse` writes a `^` or a `~`.

**Deferred, and why: the `Patient` + `Encounter` visit-carrying ADT.** The vendored `@cosyte/hl7`
this repository actually builds and tests against exports no ADT assembly entry point (no
`buildAdt`, and no `buildOru`/`encodeComposite` either): measured on the installed package, zero
occurrences in both `dist/index.d.ts` and `dist/index.mjs`. Assembling PID + PV1 by hand instead
**Deferred, and why: the `Patient` + `Encounter` visit-carrying ADT.** The `@cosyte/hl7` this
repository built and tested against at the time (`0.0.1`, vendored) exported no ADT assembly entry
point (no `buildAdt`, and no `buildOru`/`encodeComposite` either): measured on the installed package,
zero occurrences in both `dist/index.d.ts` and `dist/index.mjs`. Assembling PID + PV1 by hand instead
would be this package inventing a message-structure layout that the parser tier owns, which is the
opposite of the tier split ADR 0001 draws. The mapping itself is not the blocker and the deferral is
dated and written out in `documentation/decisions/`. **Re-measure the vendored package before
picking it up again** (`pnpm vendor:refresh` is a by-hand job, and the tarballs are unwatched by both
Dependabot routes): the entry point may exist in a later parser release than the one vendored here.
dated and written out in `documentation/decisions/`.

**▶ THAT BLOCKER IS GONE, AND THE SHAPE IS STILL NOT BUILT: DO NOT READ ONE FROM THE OTHER.**
`@cosyte/hl7` `0.0.10` exports `buildAdt(event, init)` with typed `AdtPatient` / `AdtVisit` / `AdtEvent`
bodies, and `buildOru` and `encodeComposite` with it. `test/upstream-capabilities.test.ts` is the
measurement, kept as a call that compiles and runs rather than a sentence: it builds an ADT, parses
it back, and reads the values out again. What that removes is the UPSTREAM reason for the deferral,
nothing else. The visit-carrying `Patient` + `Encounter` output is still not implemented here, it is
still owed the same IG grounding as every other shape, and the refresh that measured the builder
deliberately did not start it: a dependency refresh whose whole claim is "no emitted FHIR value
moved" cannot also add a message graph. The full record of the refresh, the capability inventory it
enumerated and where the shape is routed next: `documentation/hl7-refresh/record.md`.

## Publish state, and the stale claim inside it

Expand Down Expand Up @@ -318,9 +327,16 @@ cannot hold `security-events: write`) has been observed.
repo showed **zero** open Dependabot PRs, which meant nothing was looking, not that nothing was stale.
Two limits are written into that file rather than left to be discovered: automatic **security** update
PRs are a repo setting that currently reads `disabled`, and **Dependabot never resolves a
`file:vendor/*.tgz` specifier**, so the vendored `@cosyte/hl7` and `@cosyte/fhir` tarballs -- the
versions the tests actually exercise -- are unwatched by both the `file:` route and the peer-dep route
and stay a `pnpm vendor:refresh` job by hand.
`file:vendor/*.tgz` specifier**, so a vendored tarball -- the version the tests actually exercise --
is unwatched by both the `file:` route and the peer-dep route and stays a `pnpm vendor:refresh` job by
hand.

**That limit now covers ONE sibling rather than two, and the halves diverged deliberately.**
`@cosyte/hl7` is a registry devDependency resolved through `pnpm-lock.yaml`, so the `npm` ecosystem
route in `.github/dependabot.yml` reaches it like any other package and the by-hand job no longer
applies to it. `@cosyte/fhir` is still `file:vendor/cosyte-fhir-0.0.0.tgz` and still unwatched, and it
stays that way until the registry has it. **Do not read the two as one dependency any more**: a
sentence that treats them together was true when both were vendored and is not true now.

## The `attw` guardrail, in full

Expand Down Expand Up @@ -1055,13 +1071,16 @@ an exemption that silently grows to cover the generated half. The archive is als
**on-disk canary**: a scan that reports it clean has gone blind rather than found good news, and
the gate refuses rather than reporting that as a pass.

**`vendor/cosyte-hl7-0.0.0.tgz` (1), declared `binary` in `.gitattributes`.** A DEFLATE stream can
hold `E2 80 94` by coincidence and this one does; there is no edit that removes a byte from someone
else's compressed archive, and the tarball is third-party content this repo consumes rather than
authors. `vendor/cosyte-fhir-0.0.0.tgz` is declared alongside it and carries none today.
**`.gitattributes` is not a silencer**: the gate REFUSES any `binary` declaration outside
`vendor/`, so widening the exclusion means editing the gate deliberately. And a declaration about a
file's BYTES says nothing about its NAME, so tracked filenames are scanned whatever that file says.
**`vendor/cosyte-fhir-0.0.0.tgz`, declared `binary` in `.gitattributes`, and it is the ONLY declared
path now.** A DEFLATE stream can hold `E2 80 94` by coincidence; there is no edit that removes a byte
from someone else's compressed archive, and a vendored tarball is third-party content this repo
consumes rather than authors. The fhir archive carries none today. **The measurement that used to
sit here was taken on `vendor/cosyte-hl7-0.0.0.tgz` (1 occurrence)**; that path is gone, because
`@cosyte/hl7` became a registry devDependency, so the declared set is one path rather than two and
the count it carried retired with it. **`.gitattributes` is not a silencer**: the gate REFUSES any
`binary` declaration outside `vendor/`, so widening the exclusion means editing the gate
deliberately. And a declaration about a file's BYTES says nothing about its NAME, so tracked
filenames are scanned whatever that file says.

**Nothing else was skipped.** `CLAUDE.md` (47) and this file (68) were swept like any other tracked
file. The banner at the top of this file protects its **claims** from being softened; it is not a
Expand Down
Loading
Loading