Summary
The provider contract at openapi/contracts/tpen-services-to-tinypen.openapi.yaml uses relative $refs into the local TinyNode mirror. The refs resolve correctly inside TinyPen's directory layout but do not resolve on cubap/rerum_openapi after sync, because the receiver's directory layout places the TinyNode mirror at a sibling path that does not exist relative to the synced contract.
Where it occurs
openapi/contracts/tpen-services-to-tinypen.openapi.yaml lines 22-24:
/query:
$ref: ../external/tpen-services-to-tinynode.openapi.yaml#/paths/~1query
/update:
$ref: ../external/tpen-services-to-tinynode.openapi.yaml#/paths/~1update
How ../external/ resolves in each repo
|
Contract lives at |
../external/ resolves to |
File exists? |
| TinyPen (local) |
openapi/contracts/ |
openapi/external/tpen-services-to-tinynode.openapi.yaml |
✓ yes |
cubap/rerum_openapi (receiver, after sync) |
seams/tpen-services-to-tinypen/openapi/ |
seams/tpen-services-to-tinypen/external/tpen-services-to-tinynode.openapi.yaml |
✗ no |
On the receiver, the TinyNode mirror lives at a sibling path — seams/tpen-services-to-tinynode/openapi/baseline.openapi.yaml — not under seams/tpen-services-to-tinypen/external/. Any OpenAPI-aware tool that dereferences $refs against the receiver copy gets a file-not-found for /query and /update.
What does and doesn't break
- ✓ Local TinyPen
npm test — passes (resolves under openapi/external/)
- ✓ Receiver file storage — fine (YAML text lands; broken refs sit dormant)
- ✓
__tests__/provider_contract_surface.test.js — passes (verifies the literal $ref string and that the local mirror exists; does not simulate receiver-side resolution)
- ✗ Any
$ref-resolving tool run against the receiver copy: Redocly bundle/lint, swagger-cli bundle, doc renderers, code generators
Surfaced when
The first cross-repo sync after #47 landed: cubap/rerum_openapi#7. The synced file has the broken refs visible in the diff.
Remediation — three options, all single-file commits in this repo
- Inline the imported operations in
openapi/contracts/tpen-services-to-tinypen.openapi.yaml (recommended). Self-contained, survives any transport, matches how the other baselines on the receiver are structured. Costs a few lines of duplication.
- Use a receiver-relative path like
../../tpen-services-to-tinynode/openapi/baseline.openapi.yaml#/paths/~1query. Breaks local resolution unless we also reorganize TinyPen's openapi/external/ to match the receiver layout. Trades one breakage for another — not recommended.
- Bundle/dereference at sync time with
redocly bundle or swagger-cli bundle added as a step in .github/workflows/sync_tinypen_provider_contract.yaml before the copy. Cleanest semantically, adds a tooling dependency.
Acceptance criteria
- The receiver copy of
seams/tpen-services-to-tinypen/openapi/baseline.openapi.yaml resolves cleanly with npx @redocly/cli bundle <file> (no missing-ref errors).
- TinyPen's existing tests continue to pass.
- A receiver-side bundle check could be added later to catch this class of regression in CI.
Context
Surfaced during the #47 static review. Out-of-scope for that PR by agreement.
Summary
The provider contract at
openapi/contracts/tpen-services-to-tinypen.openapi.yamluses relative$refs into the local TinyNode mirror. The refs resolve correctly inside TinyPen's directory layout but do not resolve oncubap/rerum_openapiafter sync, because the receiver's directory layout places the TinyNode mirror at a sibling path that does not exist relative to the synced contract.Where it occurs
openapi/contracts/tpen-services-to-tinypen.openapi.yamllines 22-24:How
../external/resolves in each repo../external/resolves toopenapi/contracts/openapi/external/tpen-services-to-tinynode.openapi.yamlcubap/rerum_openapi(receiver, after sync)seams/tpen-services-to-tinypen/openapi/seams/tpen-services-to-tinypen/external/tpen-services-to-tinynode.openapi.yamlOn the receiver, the TinyNode mirror lives at a sibling path —
seams/tpen-services-to-tinynode/openapi/baseline.openapi.yaml— not underseams/tpen-services-to-tinypen/external/. Any OpenAPI-aware tool that dereferences$refs against the receiver copy gets a file-not-found for/queryand/update.What does and doesn't break
npm test— passes (resolves underopenapi/external/)__tests__/provider_contract_surface.test.js— passes (verifies the literal$refstring and that the local mirror exists; does not simulate receiver-side resolution)$ref-resolving tool run against the receiver copy: Redocly bundle/lint,swagger-cli bundle, doc renderers, code generatorsSurfaced when
The first cross-repo sync after #47 landed: cubap/rerum_openapi#7. The synced file has the broken refs visible in the diff.
Remediation — three options, all single-file commits in this repo
openapi/contracts/tpen-services-to-tinypen.openapi.yaml(recommended). Self-contained, survives any transport, matches how the other baselines on the receiver are structured. Costs a few lines of duplication.../../tpen-services-to-tinynode/openapi/baseline.openapi.yaml#/paths/~1query. Breaks local resolution unless we also reorganize TinyPen'sopenapi/external/to match the receiver layout. Trades one breakage for another — not recommended.redocly bundleorswagger-cli bundleadded as a step in.github/workflows/sync_tinypen_provider_contract.yamlbefore the copy. Cleanest semantically, adds a tooling dependency.Acceptance criteria
seams/tpen-services-to-tinypen/openapi/baseline.openapi.yamlresolves cleanly withnpx @redocly/cli bundle <file>(no missing-ref errors).Context
Surfaced during the #47 static review. Out-of-scope for that PR by agreement.