fix(register): resolve cross-package + transitive-version + cache-mismatch canonical lookups#151
Open
sussdorff wants to merge 2 commits intoatomic-ehr:mainfrom
Open
Conversation
…match canonical lookups The canonical resolver had three related bugs causing 'Base resource not found' errors when packages have different versions of the same dependency. This commit consolidates three iterations (vrq, 7y9, pkt) of the fix into a single change. ## Bug 1: kbv.basis@1.8.0 .index.json has null id entries de.basisprofil.r4@1.5.4 ships an .index.json with null-id ImplementationGuide entries. parseIndex treats any null id as fatal and rejects the entire .index.json — leaving the package with 0 indexed resources. Cross-package base-type lookups for KBV profiles that inherit from de.basisprofil.r4 fail at transform time. Fix (vrq): when manager.search returns 0 for a package, scan the canonical-manager's node_modules cache directly. Equivalent to scanDirectoryForResources but tolerant of malformed .index.json. Implemented as scanNodeModulesPackage with a nodeModulesPath parameter computed from the focusedPackages cache key. ## Bug 2: top-level + transitive package version mismatch When the top level loads de.basisprofil.r4@1.6.0-ballot2 and a dependency (kbv.basis) needs de.basisprofil.r4@1.5.4, npm installs the older version into a nested location: node_modules/kbv.basis/node_modules/de.basisprofil.r4/. The original scanNodeModulesPackage only checked the flat top-level path → returned wrong-version content. Fix (7y9): scanNodeModulesPackage now reads the package.json version from the flat path, and if it doesn't match the requested version, scans nested node_modules/<parent>/node_modules/<dep>/ paths. Returns the first one whose version matches; falls back to flat path if no match (graceful degradation). ## Bug 3: APIBuilder.localTgzPackage cache-key divergence When packages are added via APIBuilder.localTgzPackage() (or addTgzPackage on the manager), the canonical-manager's cache hash is computed from constructor packages ONLY. addTgzPackage adds packages to the cache record but doesn't change the hash. Codegen however computed nodeModulesPath from ALL focusedPackages → divergent hashes → computed path doesn't exist → fallback never triggers → silent failure. Concrete failure: polaris dental builder uses .localTgzPackage(praxis) + .localTgzPackage(dental). manager.search returned 0 for de.basisprofil.r4@1.6.0-ballot2 even though the resource existed in the actual cache directory. Fix (pkt): when the computed nodeModulesPath does not exist, scan ALL sibling cache record directories under <workdir>/canonical-manager-cache/ and try each one. The warning message identifies which cache record was actually scanned. ## Tests - test/unit/typeschema/versioned-canonical.test.ts (5 tests): cross-package base type lookup with kbv.basis@1.8.0 + de.basisprofil.r4@1.5.4 against null-id .index.json scenario - test/unit/typeschema/transitive-version-mismatch.test.ts (5 tests): - Integration: 1.6.0-ballot2 top-level + kbv.basis@1.8.0 → no errors - Synthetic: scanNodeModulesPackage prefers nested 1.5.4 over flat 1.6.0-ballot2 - Synthetic: scanNodeModulesPackage scans sibling cache dirs when computed path missing All 10 tests pass on upstream/main.
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.
Summary
Three related canonical-resolver bugs caused 'Base resource not found' errors when packages have different versions of the same dependency. Discovered while running codegen on @polaris (fhir-de) which loads
de.basisprofil.r4@1.6.0-ballot2(top-level) pluskbv.basis@1.8.0(transitive, depends onde.basisprofil.r4@1.5.4) plus FHIR IG packages vialocalTgzPackage().This PR consolidates three iterative fixes from our cognovis fork (vrq → 7y9 → pkt) into a single change.
Bugs Fixed
1. Null-id
.index.jsonrejection causes 0 indexed resourcesde.basisprofil.r4@1.5.4ships an.index.jsonwith null-idImplementationGuideentries.parseIndextreats any null id as fatal and rejects the entire.index.json— leaving the package with 0 indexed resources. Cross-package base-type lookups for KBV profiles (e.g.KBV_PR_Base_Observation_Care_Level→observation-de-pflegegrad) fail at transform time.Fix: When
manager.searchreturns 0 for a focused package, fall back to a direct directory scan of the canonical-manager'snode_modulescache (scanNodeModulesPackage). Equivalent to the manager's ownscanDirectoryForResourcesbut tolerant of malformed.index.json.2. Top-level + transitive package version mismatch
When the top level loads
de.basisprofil.r4@1.6.0-ballot2and a transitive dep (kbv.basis) needsde.basisprofil.r4@1.5.4, npm/bun installs the older version into a nested location:node_modules/kbv.basis/node_modules/de.basisprofil.r4/. The originalscanNodeModulesPackageonly checked the flat top-level path → returned wrong-version content silently.Fix:
scanNodeModulesPackagenow readspackage.jsonversion from the flat path; if it doesn't match the requested version, scans nestednode_modules/<parent>/node_modules/<dep>/paths. Returns the first one whose version matches; falls back to flat path with a warning if no exact match.3. APIBuilder.localTgzPackage cache-key divergence
When packages are added via
APIBuilder.localTgzPackage()(ormanager.addTgzPackage()), the canonical-manager's cache hash is computed from constructor packages only.addTgzPackageadds packages to the cache record but doesn't change the hash. Codegen however computednodeModulesPathfrom ALLfocusedPackages(those returned bymanager.init(), including tgz adds) → divergent hashes → computed path doesn't exist → fallback never triggers → silent 0-resource failure.Concrete failure: a build like
```ts
new APIBuilder()
.fromPackage('hl7.fhir.r4.core', '4.0.1')
.fromPackage('de.basisprofil.r4', '1.6.0-ballot2')
.localTgzPackage('vendor/de.cognovis.fhir.dental-0.17.0.tgz')
.typescript({})
.outputTo('generated/dental')
```
returns
Base resource not found 'http://fhir.de/StructureDefinition/observation-de-pflegegrad'despite the resource existing in the actual cache.Fix: When the computed
nodeModulesPathdoes not exist, scan ALL sibling cache record directories under<workdir>/canonical-manager-cache/and try each one. The warning message identifies which cache record was actually scanned.Test plan
10 tests across 2 files, all passing:
test/unit/typeschema/versioned-canonical.test.ts(5 tests):kbv.basis@1.8.0+de.basisprofil.r4@1.5.4.index.jsonscenario via real package downloadstest/unit/typeschema/transitive-version-mismatch.test.ts(5 tests):1.6.0-ballot2top-level +kbv.basis@1.8.0resolves without errorsscanNodeModulesPackageprefers nested1.5.4over flat1.6.0-ballot2scanNodeModulesPackagescans sibling cache dirs when computed path missingRun with:
```bash
bun test test/unit/typeschema/versioned-canonical.test.ts test/unit/typeschema/transitive-version-mismatch.test.ts
```
Background
This branch consolidates three iterative fixes from our
cognovis/mira-adaptersfork:codegen-vrq: introducednodeModulesPathfallback (Bug 1)codegen-7y9: added nested-path version-aware scan (Bug 2)codegen-pkt: added sibling-cache scan forlocalTgzPackagelayouts (Bug 3)The single squashed commit makes review simpler. Happy to split into per-bug commits if preferred.
We've been running this on production codegen for polaris — verified 11/11 builders complete cleanly.