Latest Results
refactor(bench): consolidate benchmarks into a single CodSpeed home (#687)
* chore(bench): repair benchmark wiring
- turbo bench task now depends on ^build (the central suite imports dist)
- drop bench scripts from lint-profile-extra-{fields,components}, which have
no bench files and failed every root pnpm bench
- give @glion/benchmarks a check-types script and a tsconfig that typechecks
the workspace; fix the stale ConnectionInfo mock it immediately caught
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* feat(bench): fixture corpus and real regression suites
Restructure the central workspace around a curated CodSpeed suite:
- fixtures/ — canonical message corpus (builder trees pinned to HL7 v2.5,
deterministic MLLP strings), byte/stream helpers, and an in-memory MLLP
wire that ACKs every frame
- suites/ — nine regression suites; continuing benches keep their titles
and fixtures so CodSpeed history survives
- annotate/lint processors now include hl7v2AnnotateProfileContext and a
VFile, so profile plugins do real work instead of bailing on a missing
file.data.profile; an explicit structuredClone baseline makes the
per-iteration clone cost of mutating plugins subtractable
- new coverage: annotate-profile, mllp-transport, and mllp-client (send()
round-trip over the in-memory wire — first client benchmarks since #645)
- codec/transport suites carry same-bytes single-chunk vs trickled ratio
pairs as amortised-O(N) guards
- canary.test.ts asserts every suite's processor/fixture pairing produces
observable work, so a silent-bail bench fails CI instead of measuring
an early return
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* refactor(bench): single benchmark home — migrate lab sweeps, delete package benches
- move the full mllp-codec and mllp-transport workload sweeps and the
profiles cache comparison into benchmarks/lab/ (local-only, pnpm
bench:lab, no CodSpeed); the profiles warmup the old header described
now actually exists
- convert annotate-profile-context's assertion-shaped benches (LRU
reference sharing, per-message Map sizes, idempotent second run) into
real tests in tests/cache-invariants.test.ts; the GC-dependent
heap-growth bench is superseded by the retained-files identity check
- delete every packages/*/bench/ directory and bench script: the central
workspace is the single benchmark home, so the two copies can no longer
drift; serve.bench.ts's TCP loopback timing is dropped outright (its
middleware comparison lives deterministically in the mllp-handle suite)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* docs(bench): benchmark architecture contract
benchmarks/README.md pins the framework: the four jobs (regression
suites / lab sweeps / invariant ratio-pairs / behavioral tests in the
owning package), the suite rules (measure dist, names are API, measured
body contains only the operation, deterministic and CPU-bound, canary
per suite), the coverage matrix with explicit reasons for unbenchmarked
packages, and the PR norms (baseline-first, link the CodSpeed
comparison). CLAUDE.md points at it.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* docs(bench): explain the end-of-chunk trailer check in the memory wire
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* refactor(bench): dogfood the memory wire's ACK path
The in-memory wire now reads MSH-10 through @glion/util-query's value()
over a parsed tree, and constructs its ACK with @glion/builder +
@glion/to-hl7v2 instead of string surgery. Only the MSH segment is
parsed so the wire's cost stays constant in message size — it runs
inside the measured client round-trip.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* refactor(bench): one message builder — streams.ts stops building HL7v2
buildPayload duplicated buildOruMessage's job in the byte-layer helpers.
fixtures/messages.ts now owns all HL7v2 message construction; streams.ts
is purely byte/stream mechanics (tile, chunk, concat, source). The codec
and transport sweeps encode buildOruMessage() output instead — their
payloads shift slightly (~300 B small), labels updated to match.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* refactor(bench): compositional fixtures — primitives plus repeat/hl7
The corpus no longer exports finished shapes (lintAdtTree, buildOruMessage
and friends). It exports segment builders, per-index line builders, and two
combinators — repeat() and hl7() — and every suite composes its fixture
inline: m(msh(), pid(), ...repeat(obx, 50)). The input shape is readable
at the bench site; continuing fixtures stay byte-identical.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* refactor(bench)!: text-as-canonical fixtures — .hl7 files, parse-derived trees
Rethink of the fixture corpus. HL7v2 text is now the single canonical
form: named messages are .hl7 files in fixtures/messages/ (hl7File()
loads and normalizes newlines to CR), scale is composed from per-index
line builders via repeat(), and the tree suites derive their input with
parseHL7v2 — the same trees production pipelines lint and annotate, not
a hand-built builder dialect. The @glion/builder DSL leaves the corpus
entirely (it remains only in the memory wire's ACK construction).
Tree-suite fixture content therefore changes (parsed trees replace
builder trees) — their CodSpeed baselines reset, which is free pre-merge.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* refactor(bench): name fixtures for what the message is, not who consumes it
adt-a01-lint / adt-a01-annotate / mllp-adt-a01 leaked the consuming suite
or transport into the message's name. Renamed by content — sparse, coded,
violations, minimal — and restructured messages.ts by message family
(ADT^A01 shapes, ORU^R01 shapes) with each fixture's distinguishing
property in its JSDoc. Constants follow: ADT_A01_MINIMAL and ORU_R01_LARGE
replace MLLP_SMALL_MESSAGE / MLLP_LARGE_MESSAGE.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* chore(codecov): ignore the benchmarks workspace
Bench harness code (suites, lab sweeps, fixtures) is not product code;
its patch coverage is whatever the canary happens to execute and was
failing coverage checks on benchmark-only changes.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Fable 5 <noreply@anthropic.com> feat(mllp-client)!: native TypeScript implementation (no framework) (#669)
* feat(mllp-client)!: native TypeScript client on a pull-based wire
Rebuilds @glion/mllp-client as a plain TypeScript client — no
state-machine framework. MllpClient is a thin class over a
per-connection wire: the read loop puts decoded frames into a
per-connection inbox and each send takes its ACK from that inbox under
its own deadline, so "the connection dropped before the ACK wait
registered" stops being a race to recover from.
- send(string | Root): the AST is the wire currency, cleaned and
re-serialized; raw bytes are decoded at the caller's I/O boundary.
- Single-flight: one message on the wire, ALREADY_SENDING otherwise.
- Terminal by design: a send timeout OR an uninterpretable reply drops
the connection — a stray frame must never be consumed as a later
send's acknowledgment. A NAK keeps the connection.
- Every failure is one MllpClientError with a code to branch on; NAKs
are @glion/ack exceptions. A closed client explains itself: later
calls carry the original drop or connect failure on `cause`.
- An ACK racing the remote system's own close is not lost.
- Node 20 throws synchronously from write() on a closed stream where
later versions reject; both shapes wrap as DROPPED.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* chore(mllp-client): FIXME markers for parser enforcement at the send boundary (#685)
The client bakes in @glion/parser for outbound clean-on-send and inbound
ACK parsing. Whether the parser should be injectable (as on the server via
Mllp.parser()) is deferred to issue #685; these markers anchor the two
call sites.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix(mllp-client): restore the explicit-parser parseResponse signature
A bad rebase resolution reverted parseResponse to a baked-in parseHL7v2
while connection.ts still passed the parser explicitly — the package no
longer type-checked. Restore the reviewed three-argument signature; the
parser stays caller-supplied (see issue #685 for making it an application
choice end to end).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* feat(cli)!: glion send speaks the new client contract; retire mllp-transport
The CLI adapts to the rewritten client: an unsendable message renders as
the `invalid` outcome instead of a transport failure, NAK durations
measure the same wire span as accepts, and the NAK code no longer needs
a narrowing cast. @glion/mllp-transport is deleted now that its last
consumer is gone — its successor, @glion/mllp-codec, has carried every
call site since the earlier layers. ADR 0018 records the rename and the
error-model changes.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* refactor(mllp-ack)!: remove @glion/mllp-ack — the baseline for ADR 0019
Delete the package wholesale: ackMiddleware's onion slot is the source of
every acknowledgment ordering bug (registration-order-dependent NAKs, false
AA for unrouted messages, error.message leaked to MSA-3), and per ADR 0019
translation moves to a framework-owned error boundary in @glion/mllp.
This is the first PR of the stack: no replacement is introduced here.
@glion/ack is untouched; acknowledge() returns inside @glion/mllp with the
renderer in the next PR, with mllp-ack's spec pins ported onto it. Examples
still compile against the published npm package and migrate when their
replacement pattern exists.
- delete packages/mllp-ack and its pending changeset
- drop the @glion/cli devDependency and the unused @glion/benchmarks dependency
- scrub quick-start snippets and package catalogs (root README, package READMEs,
CLAUDE.md, glion-readme skill)
- add docs/adr/0019-acknowledgment-translation.md (Proposed)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Fable 5 <noreply@anthropic.com> Latest Branches
0%
dependabot/npm_and_yarn/tools/testing/npm_and_yarn-945fe4de7f N/A
0%
docs/mllp-client-actor-adr © 2026 CodSpeed Technology