perf(fixer): skip defensive deep copy when caller owns document#297
perf(fixer): skip defensive deep copy when caller owns document#297
Conversation
The fixer deep-copies parsed documents before mutating them, protecting callers who reuse the input. Three code paths in the CLI never reuse the parsed document, so the copy is wasted work: - Fix() parses internally and owns the result — now sets MutableInput with defer-based save/restore for panic safety - CLI stdin path owns its locally-parsed result - CLI source-map path owns its locally-parsed result Also modernizes isFixEnabled to use slices.Contains (gopls hint). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
Warning Rate limit exceeded
⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. 📝 WalkthroughWalkthroughAdds a MutableInput mode to the fixer: new Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes 🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches🧪 Generate unit tests (beta)
Comment |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #297 +/- ##
==========================================
+ Coverage 84.59% 84.62% +0.02%
==========================================
Files 158 158
Lines 25125 25125
==========================================
+ Hits 21255 21261 +6
+ Misses 2625 2618 -7
- Partials 1245 1246 +1
🚀 New features to boost your workflow:
|
Exercises the Fix(path) code path to cover the new MutableInput save/restore logic, and verifies the field is restored after return. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Fix all issues with AI agents
In `@fixer/fixer_test.go`:
- Around line 604-615: Add a subtest to TestFix_SetsInternalMutableInput that
sets f.MutableInput = true before calling f.Fix(...) and then asserts the
original value is restored after Fix returns; specifically, create a
t.Run("starts true") block that creates f := New(), sets f.MutableInput = true,
calls result, err := f.Fix("../testdata/bench/small-oas3.yaml"),
require.NoError(t, err), assert.True(t, result.Success), and finally
assert.True(t, f.MutableInput, "MutableInput should be restored to true after
Fix()") to ensure the save/restore (defer) logic in Fix handles both starting
true and false cases.
Addresses CodeRabbit review: the false→false case would also pass if Fix() hardcoded false instead of saving/restoring. The true→true subtest validates the defer actually restores the original value. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Fix all issues with AI agents
In `@fixer/fixer_test.go`:
- Around line 604-627: Add a subtest in TestFix_SetsInternalMutableInput that
verifies MutableInput is restored when Fix() returns an error: create f :=
New(), set f.MutableInput to true (and another case false if desired), call
f.Fix() with an input that provably causes an error (e.g., invalid path or
malformed test fixture) and require an error, then assert f.MutableInput equals
the original value; ensure the test exercises the same defer/restore path used
by Fix() so the panic/error-safe restore is validated.
- Around line 604-627: The test relies on Fix() toggling MutableInput to skip
defensive copies, which violates the "always deep copy" rule; change Fix() so it
never mutates or relies on the MutableInput flag internally—instead always
perform a defensive deep copy of the input document (use JSON marshal/unmarshal)
before any modifications and ensure MutableInput remains unchanged by Fix();
then update or keep TestFix_SetsInternalMutableInput to assert that
f.MutableInput is unchanged before and after Fix() and that Fix() still succeeds
(refer to the Fix(), MutableInput field, New(), and
TestFix_SetsInternalMutableInput symbols to locate the code).
Addresses CodeRabbit review: adds error-path subtest. Note this tests the early-return path (parse failure at line 408, before save/restore), not the defer — the field is untouched, not restored. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The previous guideline recommended JSON marshal/unmarshal for deep
copying OAS documents — this silently loses interface{} type
distinctions (string vs []string in OAS 3.1 schema.Type) and drops
json:"-" fields. Updated to recommend the generated DeepCopy() methods
and document the WithMutableInput(true) opt-in for owned documents.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Audit found locations recommending JSON marshal/unmarshal for deep
copying OAS documents. This approach silently loses interface{} type
distinctions (string vs []string in OAS 3.1 schema.Type) and drops
json:"-" fields.
Updated all to recommend generated DeepCopy() methods instead.
Files fixed:
- AGENTS.md
- .claude/docs/oas-concepts.md
- .claude/agents/developer.md
- CONTRIBUTORS.md
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Summary
Fixer.Fix()now setsMutableInput=truewith defer-based save/restore before callingFixParsed(), since it always owns the parsed document it creates internallyf.MutableInput=true— the parse result is locally scoped and discarded after fixingWithMutableInput(true)— same ownership reasoningisFixEnabledmodernized to useslices.Contains(gopls hint)Why
The fixer defensively deep-copies the entire parsed document before mutating it, protecting callers who reuse the input afterward. But in all three CLI code paths (file, stdin, source-map), the parsed document is never reused — it's consumed by the fixer and discarded. Skipping the copy eliminates an unnecessary O(n) allocation on every fix invocation.
Test plan
TestMutableInput*tests pass (6/6)Fix()path)go_diagnosticsclean on both modified filesdeferpattern adopted per silent-failure-hunter recommendation🤖 Generated with Claude Code
Summary by CodeRabbit
New Features
Bug Fixes
Tests
Documentation