Conversation
…alProperties
3.0 keeps a boolean `additionalProperties`, but a Schema Object is never a
boolean, so a `$ref` kept pointing at one resolved to `true` or `false`.
The 3.1 to 3.0 converter now treats a location whose output is a boolean
as dangling, so such a `$ref` is replaced by `{}` or `{ not: {} }`, like
any other boolean schema.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JZezsg72P27RPnwVijmprt
…t check `danglesIn` asked two questions for one rule: a placeholder check hard-coded in shared.ts, and the converter's `isTarget`. Placeholders are 3.1 to 3.0 only, so the WeakSet moves into that converter and joins `isRefTarget`, leaving `danglesIn` with the injected check alone. Also trims the new tests to one table and the reported spec case. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JZezsg72P27RPnwVijmprt
…-hwcl0r # Conflicts: # packages/downgrader/src/shared.ts # packages/downgrader/src/v3.1-to-v3.0.ts # packages/downgrader/tests/v3.1-to-v3.0/schema/references.test.ts
|
your Pullfrog Router balance is empty, and this repo has no provider key to fall back on, so the agent never ran. To fix, any one of: add a payment method or top up your Router balance · add a provider API key (GitHub Actions secret or Pullfrog secret) · switch this repo to a free model. Top up Router → · Model settings → · Setup docs → · Ask in Discord → |
|
The No code change can fix this. It needs a top-up, a provider key, or a free model in the Pullfrog settings. I didn't re-run the check, because it would fail the same way until that's done. The rest of CI is green on 5be01b5: Generated by Claude Code |
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |

Problem
3.0 keeps a boolean
additionalProperties, the one place it allows a boolean. But a 3.0 Schema Object is never a boolean, so a$refmust not resolve to one.danglesIncounted a boolean in the output as present, so a$refto that location was kept and resolved totrueorfalse:properties.a{ $ref: '#/additionalProperties' }, which findsfalse(matches nothing)mainfalse{ not: {} }(matches nothing)The same happens:
downgradeSpecV31ToV30, forcomponents.schemas = { M: { type: 'object', additionalProperties: false }, X: { $ref: '#/components/schemas/M/additionalProperties' } }, whereXstayed a$reftofalse.not, wherenot: { $ref }pointing at atrueresolved tonot: true.Everywhere else, boolean schemas already become
{}or{ not: {} }, including afalseinlined from$defs. The README also says$refs to boolean schemas are handled.Fix
downgrade(packages/downgrader/src/shared.ts) takes an optionalisTargetpredicate.danglesIntreats an output value that fails it like a missing one, so the$refis inlined with the converted target.isRefTarget, which rejects booleans. 3.2 → 3.1 keeps the default, since boolean schemas are valid 3.1 targets.$refis inlined only when it must be.items: falsebecomes{ not: {} }in place, so{ $ref: '#/items' }stays as written. A$refto a component likeNever: falsestays as written too.PLACEHOLDERSandplaceholder()were only used by 3.1 → 3.0, so they move fromshared.tsintov3.1-to-v3.0.tsand joinisRefTarget.danglesInis left with one rule:to === undefined || !isTarget(to).Tests
schema/references.test.ts, newdescribe('references to a boolean additionalProperties'):$reftofalsenotover a$reftotrue$refwith siblings, which moves intoallOf$refto the location that now holds the inlined schema, which stays as written$reftoitems: falseconverted in place, which stays as writtenspec/components.test.ts: theM/Xcase fromcomponents.schemas.main.pnpm test(688 passed),pnpm lint, andpnpm type:checkare clean on the merge withmain.Side effects
The rule covers every kind of reference in 3.1 → 3.0, because no 3.0 reference may resolve to a boolean. Both cases below were already invalid 3.0 output before this PR.
mappingentry pointing at a booleanadditionalPropertiesis now removed. Entries pointing into an inlined$defsare already removed the same way.$ref), which is already invalid in 3.1, is now replaced by the boolean instead of kept.$refs to boolean targets in removed parts, such aswebhooks, already behaved this way.$reftakes one more conversion pass of thedowngradeloop. This is the same cost as other$refs that are found to dangle only after the first pass.Interaction with middleapi/openapi-spec#44
That PR replaces
placeholder()withreplace()and also editsdanglesIn, so whichever PR merges second has a conflict:isTargetparameter and!isTarget(to), and reduceisRefTargettotypeof value !== 'boolean'.PLACEHOLDERSandplaceholder()fromv3.1-to-v3.0.tsinstead ofshared.ts, and keeps|| !isTarget(to)indanglesIn.replace()cannot cover this case:additionalProperties: falseis not replaced, it is kept as written.🤖 Generated with Claude Code
https://claude.ai/code/session_01JZezsg72P27RPnwVijmprt
Generated by Claude Code