fix(adapters): Claude Code NotebookEdit dropped its cell content - #35
Merged
Merged
Conversation
NotebookEdit is in WRITE_TOOLS, so the adapter advertises that it gates notebook writes, but the cell body arrives as tool_input.new_source and parse() read only content/new_string/edits -- so Event.content was None and any content policy was blind at a notebook write. Claiming to gate a write while dropping the write is an internal contradiction in the adapter's own contract, which is why this is a safe desk fix rather than a vendor guess: it rests on NotebookEdit already being a declared write tool, not on an unobserved payload shape. Verified by execution: NotebookEdit content now reaches the handler; Write, Edit and MultiEdit are unchanged. From the vendor-truth backlog. Two neighbouring findings in the same batch did NOT survive the same scrutiny and were deliberately not touched: the finding's "MultiEdit content is dropped" half is false (edits[].new_string was already read), and the cursor beforeReadFile top-level-content claim has no recorded basis (that event was never observed and no docstring documents the shape), so it stays on the live-capture checklist rather than being guessed at. Signed-off-by: Claude <noreply@anthropic.com>
There was a problem hiding this comment.
🟢 Approval recommended
The change is small, consistent with the adapter’s declared write-tool contract, and is covered by a targeted regression test.
Pull request overview
This PR fixes the Claude Code adapter’s NotebookEdit parsing so notebook cell bodies are no longer dropped from Event.content, ensuring content-based policies (e.g., secret scanning / memory guard) can actually evaluate notebook write payloads as claimed by WRITE_TOOLS.
Changes:
- Read
tool_input.new_sourceintoEvent.contentfor Claude CodeNotebookEditevents. - Add a regression test asserting
NotebookEditcontent andnotebook_pathpropagate into the parsedEvent. - Document the fix in
CHANGELOG.md.
File summaries
| File | Description |
|---|---|
| src/agentseam/adapters/claude_code.py | Extends content extraction to include tool_input.new_source so NotebookEdit writes are surfaced to policies. |
| tests/test_adapter_claude_code.py | Adds a regression test proving NotebookEdit cell content reaches Event.content (and path maps from notebook_path). |
| CHANGELOG.md | Notes the fixed blind spot where NotebookEdit previously produced Event.content=None. |
Review details
- Files reviewed: 3/3 changed files
- Comments generated: 0
- Review effort level: Lite
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
5 tasks
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.
What this changes
NotebookEditis inWRITE_TOOLS, so the adapter advertises that it gates notebook writes — but the cell body arrives astool_input.new_source, andparse()read onlycontent/new_string/edits. SoEvent.contentwasNoneand any content policy (secret scan, memory guard) was blind at a notebook write.Claiming to gate a write while dropping the write is an internal contradiction in the adapter's own contract — which is why this is a safe desk fix, not a vendor guess: it rests on NotebookEdit already being a declared write tool, not on an unobserved payload shape.
Claim check
edits[].new_stringwas already read;beforeReadFilecarries top-levelcontent" claim has no recorded basis (that event was never observed, no docstring documents the shape), so it stays on the live-capture checklist rather than being guessed.Checks
pytest -q— 749 passed, 1 skipped (up 1)ruffclean; stdlib-only; signed offNotes for the reviewer
This is the disciplined outcome of working the backlog: of the "verifiable dropped-field / matrix-mismatch" cluster, exactly one was a clean desk fix. The cursor
failClosed-on-beforeSubmitPromptitem is a genuine matrix-vs-code mismatch but unresolvable without knowing whether Cursor acceptsfailClosedon that hook (it uses thecontinueprotocol, notpermission) — so it is flaggedneeds-live-run, not patched.Generated by Claude Code