Version Packages - #132
Open
NSchatz wants to merge 1 commit into
Open
Version Packages#132NSchatz wants to merge 1 commit into
NSchatz wants to merge 1 commit into
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This PR was opened by the Changesets release GitHub action. When you're ready to do a release, you can merge this and publish to npm yourself or setup this action to publish automatically. If you're not ready to do a release yet, that's fine, whenever you add more changesets to main, this PR will be updated.
Releases
@cosyte/ccda@0.1.0
Minor Changes
23c8223: feat: measure conformance against the normative artifacts, and fix what the measurement found
A built document's conformance was expected rather than proven. The README said so:
the builder's gap had been "grounded against the raw C-CDA R2.1 IG text rather than a
validator run". It is measured now, and measuring it found 86 error-severity results
across the populated document the builder emits, then eight more once the measured set
covered every section it can emit rather than one populated init shape.
pnpm conformancefetches the normative C-CDA R2.1 Schematron, its vocabulary fileand the CDA R2 XML schema at run time from pinned immutable references, validates
every document the builder emits against the schema and then the Schematron's
error-severity phase, re-runs the Schematron over a public sample corpus parsed and
re-serialized through this library, and writes
documentation/conformance-report.md.The run fails if the committed report differs from what it just produced, and the
ordinary suite fails unless the README's conformance statement agrees with the report
on the artifact revision, the document types validated, the count of error-severity
results and the count of round trips whose error sets differed. The current result is
zero and zero.
This is why the bump is minor rather than patch. It adds one exported type
(
BuildCcdaSelfCareActivity) and one warning code (MISSING_SELF_CARE_ACTIVITY), andit moves what the builder emits and therefore what a consumer reads back from it. The
emitted changes: the patient carries
raceCodeandethnicGroupCodeasnullFlavor="UNK"; the device author carries arepresentedOrganization; a CCDcarries
documentationOf/serviceEvent; a Referral Note carries aninformationRecipient; an empty required section declares the entries-requiredtemplateIdalongside the entries-optional one; both Concern Acts carry theCONCcode the guide fixes and the CDA R2
Actsequence makes mandatory; a ReactionObservation carries an
id; a no-known-allergy entry carries the substanceparticipant with a
nullFlavor="NA"code; the Vital Signs Organizer carries theLOINC code its 2.1-only branch requires rather than the SNOMED one; an Immunization
Activity states
negationIndon both arms; a Result Organizer emits itseffectiveTimeas an interval; and an act-variant procedure carries theeffectiveTimethat variant alone requires at error severity.Two reads change with them. A no-known-allergy entry's
allergenis now present andexplicitly
nullFlavor="NA"rather than absent, which is what an entry from any othersystem has always parsed to here;
noKnownAllergyandnegatedare unchanged andthere is no code to mistake for an allergen. An administered immunization now reads
back
refused: falserather thanundefined, because the document states it.Widening the measured set from one populated init shape to every section the builder
emits found eight more, and closing them moved five more things. The Age Observation's
fixed
codeis SNOMED CT445518008"Age At Onset" rather than397659008"Age"; theFamily History Death Observation's fixed
valueis419099009"Dead" rather than419620001"Death"; a Family History Observation's fixedcodecarries the LOINC75315-2translation its template requires; a Mental Status Observation's fixedcodecarries the LOINC
75275-8translation its template requires; and a Functional StatusOrganizer is written only when it carries the Self-Care Activities (ADL and IADL)
observation the template SHALL contain.
That last one is the only change a caller has to do anything about.
BuildCcdaFunctionalStatusOrganizertakesselfCareActivities, each written as a…22.4.128observation and read back as an ordinary functional-status finding. Supplynone and the organizer is not written: its findings go out as standalone Functional
Status Observations, every one of them present and unchanged, and the returned document
carries
MISSING_SELF_CARE_ACTIVITYsaying the grouping, its categorization code andits
effectiveTimewere dropped and why. Fabricating an all-nullFlavoractivity wouldassert an assessment nobody performed, and writing the organizer anyway would stamp a
template the document does not satisfy.
The XML schema the harness validates against is the SDTC-extended tree at the same
pinned commit rather than
schema/normative, because the builder emits the HL7-approvedsdtc:deceasedIndextension and the normative schema declares no extension elements.Every fix keeps the never-invent-content rule: a
SHALLslot with no known value isnullFlavor, and no clinical time, dose, route or code is invented to satisfy acardinality.
What the measurement does not cover, stated where the capability is rather than
below it: the two document types the builder emits and not the other ten, the
error-severity phase and not the warning phase, value-set membership only where the
Schematron's own vocabulary file checks it, and a round trip that is differential
rather than absolute. It is an assessment against a published artifact, not a
certification, and no accredited body has reviewed it. The harness needs network
egress and fails explicitly without it; there is no offline pass. Nothing it fetches
is committed or ever sits in a tracked path.
Two development dependencies, neither reaching the runtime set:
xmllint-wasmforXML Schema validation and
xpathfor XPath 1.0 evaluation.2f90283: required sections: every document type now reports how far it was verified
Six of the twelve required-section (SHALL) tables asserted nothing, and nothing
in the API said whether that meant "no requirement", "not checked yet" or "the
requirement is unassertable". A consumer could not tell a verified all-clear from
an unverified silence, and only the prose warned them not to.
Five of those six were read off the normative C-CDA R2.1 base implementation
guide's document-level conformance statements. Consultation Note now asserts
History of Present Illness (CONF:1198-28907), Allergies and Intolerances
(-28911) and Problems (-28929); each is scoped to the R2.1
@extensionstamp itsconstraint's rule context carries, so an R1.1-origin document is asserted exactly
as before. Progress Note, Procedure Note, Operative Note and Diagnostic Imaging
Report assert nothing still, and that is now a traced result rather than an
unread table: every SHALL section their templates name is either outside this
parser's recognized catalog or a choice, and each is reported by name with the
reason. Unstructured Document carries no
structuredBodyat all (its componentSHALL be a
nonXMLBody, CONF:1198-31086), so it has no section obligation.The addition is additive: nothing is removed, narrowed or renamed.
requiredSectionKeysandmissingRequiredSectionskeep their signatures andtheir shape, and the six document types that already asserted keys (CCD,
Discharge Summary, Referral Note, History and Physical, Care Plan, Transfer
Summary) return exactly the same values as before, including under the unstamped
reading, with every conformance id they already carried left in place.
New exports:
requiredSectionStatus(documentType, options?): the assertedkeysplus averificationoftraced-complete,traced-partial,untracedornot-applicable, thetracedprovenance (conformance id and the source's ownsection name) behind each traced key, and every SHALL section left
unassertedwith the reason it is unassertable.requiredSectionStatuses(options?): all twelve, so the whole picture isenumerable by a consumer.
DOCUMENT_TYPES: the runtime enumeration behind theDocumentTypeunion.RequiredSectionStatus,RequiredSectionVerification,TracedRequiredSection,UnassertedRequiredSectionandUnassertedSectionReason.The only behaviour change is the one the trace bought: a Consultation Note that
carries the R2.1 stamp and omits History of Present Illness, Allergies or
Problems now draws
REQUIRED_SECTION_MISSING(a warning, never a fatal) where itpreviously parsed silent. A traced state is a claim about what was read for that
type, so the six types nobody re-read report
untracedwhether or not their keysalready cite a conformance id.
0ec5734: required sections: a SHALL warning fires exactly where the normative source says it should
The per-document-type required-section (SHALL) tables now cover all twelve
recognized types. Six of them (CCD, Discharge Summary, Referral Note, History and
Physical, Care Plan, Transfer Summary) had asserted sets that predated anyone
reading the normative source for them, and reported
verification: "untraced"tosay so. Their document-level
errorsandwarningsrules have been read off theHL7 C-CDA R2.1 normative Schematron and the tables corrected. No recognized
document type reports
untracedany more.Two defects went in opposite directions and both are closed.
Discharge Medications section as a SHALL. The normative source states it as a
SHOULD, in that document's warnings rule (CONF:1198-30525), so a conformant
Discharge Summary that omits the section was drawing a
REQUIRED_SECTION_MISSINGit had not earned. It is withdrawn, in the stampedand the unstamped reading alike.
omitted Plan of Treatment (CONF:1198-30528), which the errors rule requires
unconditionally; a History and Physical asserted one of the ten SHALL sections
its errors rule names; a Transfer Summary asserted three of six. Every one of
those sections that this parser's catalog recognizes is asserted now.
What changed on the published surface, for
requiredSectionKeys,missingRequiredSections,requiredSectionStatusand the parser warnings thatfollow from them:
dischargeMedicationswithdrawn,planOfTreatmentadded.
familyHistory,pastMedicalHistory,medications,results,socialHistoryandvitalSignsadded besideallergies.results,vitalSignsandreasonForReferraladded.Expect a document of the three changed types to draw warnings it did not draw
before, and a conformant Discharge Summary with no Discharge Medications section
to fall silent.
REQUIRED_SECTION_MISSINGremains a Tier-2 warning, never afatal, and remains safety-critical, so no vendor profile can quiet it.
Every key an added rule contributed is scoped to the R2.1 stamp, because each
of those document-level rules matches only a
ClinicalDocumentwhosetemplateIdcarries@extension="2015-08-01". An unstamped, R1.1-origin documentis therefore asserted exactly as it was before, with one exception in the safe
direction: a key withdrawn because the source states it as a SHOULD or as a choice
is withdrawn from the unstamped reading too, since "no sentence made this
unconditional" does not depend on a version stamp.
Provenance is on the surface, not in a commit message. Every asserted key now
carries the conformance statement it was read from and the source's own name for
the section; every SHALL section the source names that this package cannot assert
is enumerated with its reason (
outside-section-catalogfor Hospital Course,General Status, Physical Exam and Review of Systems;
not-unconditionally-requiredfor each choice); and
requiredSectionStatus(type).sourcenames the normativeartifact and that artifact's own revision date, so a reader holding a later
revision can tell a table is stale without re-deriving it. The new
RequiredSectionSourcetype is exported alongside it.This is document-level validation only: which sections a document type SHALL
contain, never what a section or an entry SHALL contain. A quiet parse is still
not a conformance result.
ca77a09: version stamps: a document says which C-CDA release it was written for
C-CDA 3.0.0 gave every document template a new
@extension,2024-05-01, and4.0.0 and 5.0.0 kept it, so a document written for a release later than R2.1 is
detectable from the
templateIdthat resolves its type. Through0.0.15thisparser got that case wrong twice, once loudly and once in silence.
Loudly: any
@extensionthat was not2015-08-01drewTEMPLATE_EXTENSION_ABSENT, whose frozen message reads "carries no @extensionversion stamp ... (may pre-date R2.1)". For a
2024-05-01document both halvesare false, because it carries a stamp and it post-dates R2.1.
Silently, and worse: the same path reported the document as unstamped, and the
required-section tables read that as the R1.1-origin reduction, which drops
every R2.1-stamp-scoped SHALL key. A post-R2.1 CCD carrying neither Social
History nor Vital Signs therefore drew no
REQUIRED_SECTION_MISSINGat all. Thelibrary had classified a document from the future as one from the past.
Two warning codes are added and none is renamed or removed.
TEMPLATE_EXTENSION_UNMODELED_RELEASEfires when the resolvingtemplateIdcarries an
@extensionthat is present and is not the R2.1 stamp;REQUIRED_SECTIONS_NOT_EVALUATEDfires once for such a document to say its SHALLobligation was not computed.
TEMPLATE_EXTENSION_ABSENTkeeps its narrowermeaning ("no
@extensionat all", the R1.1-origin shape) and its registry messagebyte for byte.
An unmodelled stamp is reported, never reduced. Such a document draws no
REQUIRED_SECTION_MISSINGin either reading, andrequiredSectionStatus(type, { stamp: "unmodeled-release" })reportsevaluation: "not-evaluated"so an empty key set still says which emptiness itis.
evaluationis a new field onRequiredSectionStatusand a separate axisfrom
verification, which remains a claim about the document type that no optionmoves.
The release this package validates against is an exported value now.
CCDA_CONFORMANCE_RELEASEis"R2.1", beside the closed table of stamps thispackage can name (
CCDA_RELEASE_STAMPS, plusR30_EXTENSION,releaseForTemplateExtensionand the three-statereadTemplateStamp). Thisdoes not retarget the library: regulation still adopts R2.1 and SVAP use is
voluntary, so a later release is recognized and named, never read against.
4.0.0 also relaxed the US Realm Header and 5.0.0 added a Pregnancy Section, and
neither is modelled here.
Four things are decisions rather than details:
message names a member of
CCDA_RELEASE_STAMPSor names no stamp at all, so asender-controlled
@extensioncan never reach aCcdaWarning.message(or,under
{ strict: true }, a thrown error's stack). No factory gained aparameter that a message interpolates.
carrying the resolving root twice, once stamped
2015-08-01and once for alater release, is inside the Schematron rule's context and is evaluated under
the full R2.1 obligation, in either sibling order.
{ r21Stamped }behaves exactly as it did.requiredSectionKeys("ccd", { r21Stamped: false })returns the same four keysin the same order. A boolean cannot express three states, so the three-state
{ stamp }was added beside it rather than repurposing a published option.legacyR11does not tolerate the new code. It is receive-tolerance fordocuments from the past, grounded in the receive-both-R2.1-and-R1.1
requirement; quieting a future-release stamp there would restore the silence
this change removes. Neither new code is safety-critical, so a consumer who has
read the later guide can still write their own profile for it.
Nothing became stricter. No fatal was added, no content the C-CDA open-template
rule permits is refused, and a post-R2.1 document's clinical reading (patient,
sections, entries, values) and its byte-faithful re-serialization are identical
to the same document stamped
2015-08-01. Under{ strict: true }the newwarnings escalate like every other Tier-2 warning, which is pre-existing
caller-opted behaviour.
0151ab9: subject override: an entry is never read as the patient's unless it is
CDA R2 gives
Section.subjectcardinality0..1and defines it as the "primarytarget of the entries recorded in a section"; C-CDA admits the same override on a
clinical statement. So a conformant document can carry a relative's, a donor's or
a contact's clinical statement inside the patient's document. This parser read
<subject>in exactly one place (a Family History Organizer'srelatedSubject)and every other extractor handed such an entry back as the patient's, silently.
That is another person's clinical data attributed to this patient, in a read path
documented as the patient's own.
A top-level
<entry>that a subject declaration governs is now withheld fromevery record-target read path and flagged with a new safety-critical Tier-2
warning,
SUBJECT_CONTEXT_OVERRIDE, which no vendor profile may tolerate. Anentry is governed when it carries a declaration itself, when a clinical statement
nested inside it carries one, or when an enclosing section carries one (the
nearest enclosing declaration wins, which is the standard's own conduction rule).
Four things are decisions rather than details:
Nothing is compared with the record target and nothing is resolved to the
patient, because that would make a clinical answer depend on vendor identifier
hygiene. A document that redundantly restates the patient as an entry subject
therefore loses those entries from the record-target read paths and gains a
warning for each: the safe direction of the error, and the accepted cost.
nested inside it, and the same unit does the counting. A declaration on the
second Problem Observation of a Problem Concern Act withholds that whole concern
act and emits one warning at the act's locus, never a concern act handed back
one observation short.
is that template's mechanism for naming the relative, whatever it contains, so
it is never an override, draws no warning, and re-overrides an enclosing section
declaration.
getFamilyHistory(), thefamilyHistoryfield,extractFamilyHistoryand the aggregate's family-history slot return exactlywhat they returned before, in every document shape. That carve-out is read-side
and reaches only the organizer the family-history path itself reads: an entry
that carries the Family History Organizer template beside one a record-target
read path returns (a Result Organizer, a Problem Concern Act) is withheld and
reported like any other, because a
templateIdis one element and C-CDA entriescarry several. A declaration nested deeper inside an entry is never that slot.
byte-faithful round trip through
toString()/serializeCcdareproduces itunchanged, and section narrative is returned unredacted, unreordered and
unannotated.
The count is per section and sums over the document: N governed top-level entries
in a section produce exactly N instances, in document order, each naming that
entry's own bounded locus (an element path from the CDA vocabulary, the section's
LOINC code, line and column, with
<withheld>for anything that fails its bound),and a section that declares an override but governs no entry anywhere beneath it
produces exactly one instance at its own locus instead. The same withholding
applies to a per-family or aggregate extraction invoked directly on a section,
including a nested subsection governed by an ancestor's declaration, with the
warnings delivered on the parse context those functions already accept: no
signature, parameter or return type changes.
extractFamilyHistorydelivers themtoo, while returning its own contents whole.
Two behaviour changes to expect. A document carrying an override loses those
entries from
getProblems()/getMedications()/getAllergies()and the otherten record-target families where it previously returned them as the patient's,
and under
{ strict: true }it now throws, because the new code escalates likeevery other safety-critical Tier-2 warning. Nothing is modelled for third-party
subjects: a withheld entry is reachable only through the re-serialized document.
33c543b: Add the shared
toObject/toISO/toDateconversion surface for a parsedTSEvery
@cosyte/*standard parser now exports the same three conversions, under the samenames, with the same return shapes and the same timezone rule, so moving between two of
them costs nothing to relearn. Five names are added to the package entry point:
toObject,toISO,toDate, and theDatePartsandToDateOptionstypes.toObject(ts)returns a frozenDatePartscarrying only the components the documentstated. Nothing is zero-filled, so
Object.keys()on a year-precision value is["year"]and the value's precision survives the conversion.
monthis the spec-native 1 to 12, thecomponent names are singular, and there is no
raw,precisionorvalidkey.millisecondis the first three digits of the stated fraction taken verbatim andright-padded (
.5is 500,.0500is 50), never a floating-point fraction multiplied by 1000.offsetMinutesis present if and only if the value carried an explicit offset, astated zero included. Deleting
offsetMinutesleaves an objectTemporal.PlainDateTime.fromand luxon'sDateTime.fromObjectaccept unchanged; neitherlibrary is a dependency and neither is imported.
toISO(ts)renders ISO-8601 truncated to that same precision and pads nothing out, withfractional digits rendered exactly as written. A stated offset is appended (
Zfor astated zero, otherwise
+HH:MM/-HH:MM); with no stated offset nothing is appended andno
Zis fabricated. Because a stated zero rendersZ, this is not a byte round-trip ofthe wire value, and
serializeCcdaremains the round-tripping route.toDate(ts, options?)returns aDateonly when the zone is determinate: the valuecarried an offset, or the caller passed
assumeOffsetMinutes(signed minutes east of UTC,where an explicit
0means "read this naive value as UTC"). With neither, the answer isundefined. The host machine's timezone is never read and UTC is never assumed. A value'sown offset always beats an assumed one, a year below 100 stays that year rather than being
remapped into the 1900s, and components below the stated precision fill to their lowest
legal value for the instant only. An
assumeOffsetMinutesthat names no usable zone isrefused the same way:
NaNand the two infinities are not a number of minutes, and a finiteoffset large enough to push the result outside the range a JS
Dateholds denotes noinstant. Both answer
undefined. What never comes back is anInvalid Date, whichsatisfies the declared return type and defeats its point.
bound the value is refused whole by all three functions. The v3
±ZZZZtoken is four digitswide and constrains neither field, so
+2400,+9999and-9999are legal literals stating1440, 6039 and -6039 minutes: finite numbers, none of them a zone, and none of them
expressible in the shared
+HH:MM/-HH:MMslot, whoseHHis a two-digit hour of theday. Refusing them together is what keeps
toObjectfrom reporting a hundred-hour zone thattoISOrenders as+100:39, a string no ISO-8601 reader accepts.@cosyte/hl7bounds atthe same 23:59;
@cosyte/dicombounds tighter, at 14:59.None of the three ever throws, for any input: an absent value, a
TSwith no@value, aTSwhose@nullFlavorcontradicts a populated@value(the grounds on whichparseTsalready withholds
date), and a@valuethis package parses as malformed all answerundefined.TS.dateis unchanged and stays unchanged. It remains eager: it zero-fills a truncatedvalue, resolves an offset-less one as if it had said UTC, and resolves an unstatable stated
offset too, so there are values where
ts.dateis a populatedDateandtoDate(ts)isundefined, on the same object.parseTs,parseV3DateTimeand the warning codes areuntouched, and an out-of-range offset raises no new warning. That
divergence is deliberate rather than an oversight, it is documented in
README.mdand in thedocs bundle, and the old answer stays reachable by asking for it with
{ assumeOffsetMinutes: 0 }. Nothing readingTS.datetoday reads anything different.Parts are derived by re-parsing
TS.raw, the document's own bytes;TS.dateis never read.No dependency of any kind was added, runtime or development, and
engines.nodeis unchangedat
>=22.0.0.Patch Changes
de5305e: docs: cover the profile, terminology and conformance surfaces, and gate the bundle
The published narrative documentation gained a page and a guard. Three surfaces
that a caller has to configure correctly were described only in passing inside
the limitations page, with nothing a reader could copy and run: the vendor
profile system, the bring-your-own
TerminologyAdapter, and the required-sectionconformance status. Each now has its own section on a new "Conformance, profiles
& terminology" page with an executable example, and every one of those examples
is compiled and run against the built package by the existing doc/code agreement
suite, so a documented call that stops working fails the build rather than
misleading a reader. The terminology example uses an in-process stub adapter: it
opens no socket and needs no licensed terminology service, which is also what
makes it a usable template for testing an adapter of your own.
Three pages claimed the package was "published on npm at
0.0.3" while it wastwelve patches past that. No page names a published version now; they point at
npm view @cosyte/ccda version, which cannot go stale. Every historical notethat dates a behaviour change to a past version is untouched and is now held in
place by a retention floor, because those sentences are the change record for a
reader pinned to an older version, not staleness.
Page frontmatter was inconsistent (
sidebar_labelon five pages of nine) andsidebar_positioncollided across five pages. Every page now carries the samefour keys, and each position agrees with the page's place in
sidebars.jsonrather than being a second, disagreeing answer to what comes next.
A new guard holds all of it: every symbol the public entry point exports, types
included, must be named by a page or carry a stated reason in a committed
exemption record that cannot outlive the symbol it excuses. The formatter now
covers the bundle as well, so the pages cannot drift out of format.
4bc6aa8: Bring this repo to the shared package baseline: install hardening, the required
js-yaml override, and a CLAUDE.md under its line ceiling
Three drifts the meta-repo's
config/drift-manifest.jsonmeasures against thisrepo are closed, and nothing else changes.
pnpm-workspace.yamlis new and carriesminimumReleaseAge: 1440andtrustPolicy: no-downgrade, the publication cooldown and trust policy thestandard requires of every
@cosyte/*package repo. Both keys are switched offby default in pnpm 10, and both are ignored outright by a pnpm older than
10.16.0 and 10.21.0 respectively, so
packageManageris raised frompnpm@10.0.0to
pnpm@10.34.5: a settings file the pinned package manager ignores decoratesrather than defends. A cold-store
pnpm install --frozen-lockfilewas measuredagainst the new policy and raised no
ERR_PNPM_TRUST_DOWNGRADE, so notrustPolicyExcludeentry is carried and the exemption lists are absent ratherthan empty.
pnpm.overridesgains the requiredjs-yaml@>=4.0.0 <4.3.0entry. It is listedBEFORE this repo's own
js-yaml@>=4.0.0 <4.3.2entry on purpose: pnpm appliesthe LAST matching override, measured on this tree, and the other order resolved
js-yaml 4.x down from 4.3.2 to 4.3.0, which would have been an advisory
remediation quietly undone by a compliance edit. The lockfile still resolves
js-yaml at 4.3.2, and no existing override was removed, narrowed or repointed.
CLAUDE.mdgoes from 459 lines to 232, under the ceiling of 300 the standarddeclares, entirely by RELOCATION. Every block of prose that left it is
reproduced verbatim in
documentation/agent-notes.md, under the very headingthe imperative's
Why:pointer already resolved to, and what is left inCLAUDE.mdis the rule plus that pointer. Nothing was deleted, no imperativelost its file, and no claim was reworded, softened or strengthened.
No published API, warning code, parser behaviour or emitted XML changes.
af15008: README: standardize the page, and make its usage example a test
The npm package page and the GitHub landing page are the same file, and for most
consumers it is the only page they will ever read. It was 1086 lines of deep
reference with no answer above the fold to the three questions a reader arrives
with: what is this for, is it safe to depend on, and what does it do with my
patients' data. It also carried a status line claiming the package was published
at
0.0.3, twelve patch releases out of date, and a hand-writtenaltstring onthe banner that disagreed with the one the brand assets declare for that tile.
The page now opens with the banner (carrying the declared
altstring), thetitle, a one-line hook, the four house badges and the
package.jsondescriptionverbatim, followed by a table of contents. Four sections are new:would otherwise reach for, and why this is not that.
version does and does not claim about the public API, and names the surfaces
that are still moving instead of implying they are settled.
each of logging, in-memory retention and writing to disk, and names what the
consuming application still owns.
are accepted, and every check a contribution has to clear.
Installnow states the Node engine floor and the module format. The parsewalkthrough is consolidated into a single
Usageexample that builds a completesynthetic CCD, reads it back and shows what every call returns, and that block is
now executed by the test suite against the built entry point: an example whose
shown output stops matching what the code produces fails the build. Roughly half
of documentation traffic is agents that lift a usage block verbatim, so a wrong
example is wrong generated code at scale.
No parse, emit, builder or profile behaviour changes, and no documented behaviour
was dropped: every reference section the page carried is still on it.
c361b4a: phi-scan: a target enumerated and never read refuses the scan
--allow-fixturewithdrew a path from the target list and the run reported onwhatever remained, so the withdrawal never showed up in the verdict: four argv
shapes printed
OK, no hitsat exit 0 over a corpus holding a live, detectableviolator, including a whole-run sweep whose only violator was the withdrawn file.
CI could print a clean verdict over a corpus it never opened.
The scanner now refuses (exit 2), in every mode, over any target this run
enumerated and never read, naming the paths. The comparison is a set difference
rather than a count, because a count counts the targets that did get read. A
bypass naming a path the run does not enumerate refuses too, under its own
message, since such a flag subtracts nothing (in
pathsmode a nonexistent pathis refused earlier still, by
File not found).--allow-fixtureno longerselects the mode and is unioned into the target list in
pathsmode, so it meansthe same thing in every argv.
What it costs, stated rather than left to be discovered:
--allow-fixturecan nolonger reach exit 0 in any mode. The flag,
phi-scan-overrides.mdand the loggate all stay, so an attempt is recorded and then refused rather than silently
honored, and
scripts/phi-allow-list.txtis now the only mechanism that reachesa clean run. The hit footer no longer advertises the flag as a remedy.
No published API, warning code or parser behaviour changes; this is the commit
gate only. There was no real unread corpus in this repo: the all-mode sweep
enumerates and reads the same set, and the four states were reproduced with
planted fixtures rather than found.