fix(joiner): stop the nil-schema panic in deep comparison - #419
Conversation
`oastools join --semantic-dedup` panicked on a valid document. `properties:
{name:}` is legal YAML and parses to a present key with a nil value, and
`compareDeep` dereferenced both operands immediately.
`CompareSchemasWithOptions` guards its own two arguments, but nothing
re-guarded the recursion, so every one of the fourteen nested walks that can
produce a nil was exposed. #416 patched two of them individually; that
approach needed each new nested walk to remember.
Guard once at the top of `compareDeep` instead, and revert the two spot fixes
to plain calls. A nil against a present schema is recorded as a difference at
the caller's path, which already names the field or entry, so the diagnostics
land where they did before. Two nils are equivalent.
The `*Schema` pointer fields (`not`, `if`, `then`, `else`, `contains`,
`propertyNames`, `contentSchema`) each carry their own presence check with a
field-specific message and are left alone; the central guard is a backstop
under them, not a replacement.
A driftguard case populates each of the twenty nested-schema fields with a nil
in turn, so the class cannot come back by way of a field added later. Thirteen
of those twenty fail without this fix.
Fixes #417
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: ASSERTIVE Plan: Pro Plus Run ID: 📒 Files selected for processing (4)
📝 WalkthroughWalkthroughThe schema equivalence comparator now handles nil nested schemas at the recursion boundary. Tests cover nested schema shapes, comparison directions, equivalent nil values, and semantic deduplication of parsed OpenAPI documents. ChangesNil-schema equivalence
Estimated code review effort: 3 (Moderate) | ~20 minutes Possibly related PRs
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #419 +/- ##
==========================================
+ Coverage 86.62% 86.63% +0.01%
==========================================
Files 200 200
Lines 28778 28778
==========================================
+ Hits 24930 24933 +3
+ Misses 2549 2546 -3
Partials 1299 1299
🚀 New features to boost your workflow:
|
oastools join --semantic-deduppanicked on a valid document. 💥properties: {name:}is legal YAML and parses to a present key with a nil value.compareDeepdereferenced both operands immediately, so comparing two such schemas segfaulted.Fixes #417
The fix
CompareSchemasWithOptionsguards its own two arguments, but nothing re-guarded the recursion — so all fourteen nested walks that can produce a nil were exposed. #416 patched two of them where they were found; that approach makes correctness something each future nested walk has to re-derive.One guard at the top of
compareDeepinstead, and the two spot fixes revert to plain calls. A nil against a present schema is recorded as a difference at the caller's path, which already names the field or entry, so diagnostics land exactly where they did before. Two nils are equivalent.The
*Schemapointer fields —not,if,then,else,contains,propertyNames,contentSchema— each carry their own presence check with a field-specific message and are untouched. They aren't the bug, and rewriting them would change existing diagnostic strings for no correctness gain. The central guard sits under them as a backstop. That seven-fold duplication is what #418 is filed for.Verification
Every test here was run twice — once with the fix, once with it stripped out:
internal/driftguardnested-nil casesjoinerpublic-API tablejoin --semantic-dedupCLI reproA test that has never been observed failing asserts that the code compiles, not that the bug is fixed — and
assert.NotPanicsis especially prone to passing vacuously, since a function that returns early for the wrong reason also doesn't panic.The seven that pass without the fix are precisely the pointer fields listed above, which confirms the boundary rather than undermining it.
Coverage
The integration test parses real YAML rather than building structs, because the claim under test is that an ordinary document produces this shape. It asserts the nil parse actually happened before asserting anything else, so it can't silently stop covering the bug if parsing changes. Dedup still consolidates the two schemas to one — surviving a nil is not the same as treating it as a difference.
Checks
make checkgreen — 10243 tests, no lint or gopls findings. CodeRabbit CLI run pre-push: no critical or warning findings; one minor applied, one skipped with the reasoning recorded in the test file.