fix: make the published manifest installable, and stop VERSION lying - #27
Merged
Conversation
Two defects that together made @cosyte/cli unusable, plus a third found while
verifying the first.
1. CLI-UNINSTALLABLE-MANIFEST. 0.0.1 and 0.0.2 both published with all ten
@cosyte/* siblings declared as file:vendor/*.tgz local paths. vendor/ is not
in files and there is no bundledDependencies, so the tarball shipped none of
them and every install route died with ENOENT on
node_modules/@cosyte/cli/vendor/cosyte-fhir-0.0.0.tgz.
The siblings are now real registry ranges: @cosyte/hl7 ^0.0.7 and
@cosyte/terminology ^0.0.9 as hard dependencies, the six breadth parsers plus
@cosyte/transform ^0.0.4 as optionalDependencies. Verified by packing the
tarball and installing it in a clean directory outside the repo (exit 0), then
running both bins and importing the . subpath under ESM and CJS. Negative
control: the published 0.0.2 still ENOENTs.
@cosyte/fhir could NOT be made real and is not declared at all. It is not on
the registry, and declaring it in any form alongside @cosyte/transform (whose
@cosyte/fhir peer is mandatory) fails the whole install with ERESOLVE, as an
optional dep and as an optional peer alike. Either alone installs clean; the
pair does not. Do not attribute that to a missing peerDependenciesMeta.optional
flag: measured across the suite that flag does not decide the outcome, and the
mechanism is unexplained. It is retained as a devDependency on the vendored
tarball so this repo's own FHIR and convert tests run.
Consequence, stated on every consumer surface rather than left to be
discovered: an installed copy has no FHIR support. FHIR parse/inspect/fmt/
validate and convert now degrade to a value-free CLI_PARSER_UNAVAILABLE (69)
instead of crashing on a bare await import(). Adds
loadOptionalPackage(detail, load) beneath loadOptional (which takes a
CosyteFormat and hardcodes the word "parser", wrong for both cases) and
loadFhir(), whose diagnostic says the package is not on the registry rather
than "install it". test/absent-sibling.test.ts pins the mapping and adds a
static guard that reds if a new bare import("@cosyte/fhir") or
import("@cosyte/transform") appears in src/.
2. CLI-VERSION-DRIFT. src/core/version.ts exported "0.0.0" against a 0.0.2
manifest, confirmed in the published tarball, and reached two user-visible
surfaces: cosyte --version and the MCP server's advertised
serverInfo.version. The constant's own doc comment already claimed a sync step
that did not exist. scripts/sync-version.mjs (ported from @cosyte/transform)
now runs inside the version script, and test/sanity.test.ts compares the export
against package.json.
The assertions are fixed, not just the value, because those are what let the
same defect through five sibling releases: docs-content/installation.md
asserted typeof VERSION, true of every wrong value, and now asserts the exact
version, which the sync script keeps in step; and the declaration's ": string"
annotation that the script's pattern keys on is pinned by its own test.
Verified that dropping the annotation reds only that assertion and makes the
script exit 1 rather than silently no-op.
3. Pre-existing, and NOT fixed by either of the above: npx @cosyte/cli fails with
"could not determine executable to run", because npx runs the bin matching the
package name's last segment (cli) and this package ships cosyte and
cosyte-mcp. Reproduced on the published 0.0.2 and on the fixed tarball, whose
bin block is byte-identical. The docs now use the measured working form,
npx --package @cosyte/cli cosyte. A cli bin alias would fix the short form and
is deliberately not added, because npm install -g would then claim the name
cli on the user's PATH; that trade is a founder call.
Remedy for gate-refuter pass 1 (VERDICT: REFUTED, two majors, both documentation-honesty rather than code). No loader or guard was grown. 1. The convert diagnostic gave advice that cannot be followed. It said "install it to use convert (it is an optional dependency)", but `npm install @cosyte/transform` fails E404 on its own @cosyte/fhir peer, so it pointed at a command that always fails. That is the exact defect the fhir diagnostic exists to avoid, and the same commit's test asserted the fhir message must NOT say it. In a plain install the transform branch is the only one convert can reach, so this was the shipped behaviour, on the terminal and the MCP surface alike. The message now names the real cause. CHANGELOG, the changeset and troubleshooting.md claimed it already did; that claim is now true. test/absent-sibling.test.ts pins both diagnostics against the "install it" wording. 2. README.md still said "The swap is blocked, not scheduled, and it stays blocked until @cosyte/fhir can be published under a name npm accepts", forty-four lines below new text saying the swap was done. It also restated the name-similarity diagnosis that was retracted ecosystem-wide on 2026-08-03 and that this same commit retracted in RELEASING.md and CHANGELOG.md. Corrected. 3. "It is not published, because devDependencies are not" is false. devDependencies ARE published (npm view @cosyte/hl7@0.0.7 devDependencies returns a full list), so the fix release's manifest does still carry one file:vendor/*.tgz specifier. It is harmless because a consumer never installs a dependency's devDependencies, which is what the text now says. RELEASING.md and vendor-refresh.sh. 4. New docs presented --omit=optional as a supported way to slim the install. Measured: it installs clean, then every invocation including --version dies with ERR_MODULE_NOT_FOUND on @modelcontextprotocol/sdk and a raw stack trace, because dist/bin/cosyte.mjs imports the SDK statically at top level. That code defect is PRE-EXISTING (identical on c858cb0) and is NOT fixed here; it is now documented rather than implied away, and recorded as needing its own change. Also: the static guard's reach was overstated as catching "any" new call site. A refuter falsified that by assigning the thunk to a variable, leaving the suite green. RELEASING.md and CLAUDE.md now state what it does and does not catch, including that it cannot see the repo's first static `import type` of @cosyte/fhir, one token from a runtime import. And README/installation no longer imply an installable release exists: 0.0.2 is still the newest on npm.
Pass-2 finding, minor. Both source-extraction helpers in absent-sibling.test.ts matched `"..."` segments followed by ` +` or a newline, but the LAST line of each concatenation ends `";`, so the final segment never matched. Measured: the transform detail came out 182 of 270 characters, the fhir detail likewise short. The helpers' own comment said they read the shipped text "not a copy", while asserting about 62% of it, and the blind spot sat exactly where a re-introduced "install it" tail would land, so the regression the test was written for could have walked back in unseen. One token (`;?`) in each regex, plus a test pinning the last words of both strings so a truncation of any length reds. Verified as a negative control: restoring the old regex reds that one assertion and nothing else.
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.
Two defects that together made
@cosyte/cliunusable, plus a third found while verifying the first.1. The published manifest was uninstallable
0.0.1and0.0.2both published with all ten@cosyte/*siblings declared asfile:vendor/*.tgzlocal paths.vendor/is not infilesand there is nobundledDependencies, so the tarball shipped none of them.Negative control, run first, on the current published version:
Every version was derived from the live registry, never from a file. The siblings are now real ranges:
@cosyte/hl7^0.0.7and@cosyte/terminology^0.0.9as harddependencies; the six breadth parsers plus@cosyte/transform^0.0.4asoptionalDependencies.Verified by installing, which a dry-run cannot do
What still blocks a fully-featured install, stated rather than papered over
@cosyte/fhircould not be de-vendored and is not declared at all. It is a registry 404 (FHIR-NPM-NAME, a persistent unexplainedE403; the name-similarity reading was retracted ecosystem-wide today, so no rename is proposed and the publish was not re-tested). Decision:@cosyte/fhiris undeclared,@cosyte/transformis declared optional. That was measured, not reasoned:npm install@cosyte/fhiralone0@cosyte/transformalone0ERESOLVE, exit1@cosyte/fhiras an optional peer + transformERESOLVE, exit1So the two cannot both be named.
transformis declared because it is real and starts resolving by itself the dayfhirpublishes, with no release here. Not attributed to a missingpeerDependenciesMeta.optionalflag: measured across the suite, that flag does not decide the outcome (synthmarks all seven peers optional and stillERESOLVEs;deiddeclares the same optionalfhirpeer and installs cleanly). The mechanism is unexplained; only the measurements are recorded.Consequence, stated on every consumer surface: an installed copy has no FHIR support. That required a code change, because shipping the manifest swap alone would have been worse than the install break. Both packages were loaded with a bare
await import(), so an install without them raised a raw resolver error and a stack frame, which the value-free posture forbids.loadOptionalPackage(detail, load)now sits underloadOptional(which takes aCosyteFormatand hardcodes "parser", wrong for both cases), plusloadFhir():Neither says "install it", deliberately:
npm install @cosyte/transformfailsE404on its own peer, so that advice would point at a command that cannot succeed.@cosyte/fhiris kept as adevDependencyon the vendored tarball so this repo's FHIR/converttests still run. Note precisely:devDependenciesare published, so onefile:specifier does remain in the manifest, harmlessly, because a consumer never installs a dependency's devDependencies, verified by the exit-0 install above.The dependabot config keeps its honesty and gains coverage: the siblings are now watchable for the first time;
@cosyte/fhiris the one it still cannot see, and the comment says so rather than implying cover.2. The
VERSIONexport liedsrc/core/version.tsexported"0.0.0"against a0.0.2manifest, and its JSDoc already claimed a Changesets sync step that did not exist. Confirmed independently in the published tarball:It reached two user-visible surfaces:
cosyte --versionand the MCP server's advertisedserverInfo.version.Proof the new test fails on the unfixed tree, as required:
scripts/sync-version.mjsis ported from@cosyte/transform(87b5282), andtest/sanity.test.tsnarrows the parsed manifest **without anascast`.Both named traps closed
docs-content/installation.mddid exactly whatsynth's docs did:typeof VERSION; // => "string", true of every wrong value, executed against builtdist/bytest/docs-content.test.tson every release. It now assertsVERSION; // => "0.0.2", a realtoStrictEqual, and the sync script rewrites that literal as a second target so the docs gate stays load-bearing instead of going stale.: stringannotation. It was absent entirely; it is now present and pinned by its own test. Verified that disarming it reds only that assertion:3. Pre-existing, and NOT fixed by either of the above
npx @cosyte/clinever worked, independent of the packaging defect.npxruns the executable matching the package name's last segment (cli); this package shipscosyteandcosyte-mcp. Reproduced on published0.0.2and on the fixed tarball, whosebinblock is byte-identical, so the swap provably cannot have changed it:Docs (
README,installation.md, both MCP registration snippets) now use the measured working form. Aclibin alias would fix the short form and is deliberately not added, becausenpm install -gwould then claim the nameclion every user'sPATH. That trade is a founder call, not a packaging tidy-up.Gate
gate-refuter(notconformance-refuter: no healthcare-data parsing is touched), 2 passes.VERDICT: REFUTED: two INTRODUCED majors, both documentation-honesty, no code defects. (a)README.mdstill said "the swap is blocked... until@cosyte/fhircan be published under a name npm accepts", stale and restating the retracted diagnosis, 44 lines below new text saying the swap was done. (b) theconvertdiagnostic said "install it to use convert", advice that failsE404, while three documents claimed it said the opposite, and in a plain install that is the only branchconvertreaches. Plus four minors. Remedied in7b2b596; the fix was text plus one diagnostic string, and neither the loader nor the guard was grown.VERDICT: NOT REFUTED: all seven findings resolved or accepted, re-measured in a clean room. One new minor inside the remedy: my source-extraction regexes silently dropped each constant's last line (182 of 270 chars), so the negative assertions had a blind spot exactly where a re-introduced "install it" tail would land. Fixed in4778919(one token,;?) with a test pinning both strings' final words; negative control confirms restoring the old regex reds that assertion and only it.Filed, not fixed here (PRE-EXISTING, reproduces on
c858cb0): the builtdist/bin/cosyte.mjsimports@modelcontextprotocol/sdkstatically at top level, so--omit=optionalyields an install where every command,--versionincluded, dies withERR_MODULE_NOT_FOUNDand a raw stack trace. It also falsifiessrc/bin/cosyte.ts's "a plaincosyte parsenever pulls it" and thetest/mcp-isolation.test.tsclaim. This release makes it reachable for the first time, because the package could not be installed at all before. Three docs pages now say not to use that flag rather than implying it is supported. It needs its own change.Verification
scripts/verify.sh cligreen.typecheck,lint(--max-warnings=0),format:check,check:no-emdash,check:no-internal-refs,phi-scan,attw,smokeall green. 361 tests, 29 files. Coverage 97.7 / 92.28 / 93.87 / 98.56, per-directory ≥ 90 oncoreandcommands. Treat this PR's own check runs as authoritative.Changeset included (
patch,0.0.xladder). The open "Version Packages" PR #26 is deliberately untouched: the release is the coordinator's to drive once this is onmain. No umbrella pointer bump, nooperations/,documentation/,.gitmodulesor other submodule touched.