Skip to content

Fix five code-review bugs (#37–#41)#42

Merged
TYRMars merged 1 commit into
mainfrom
claude/vibrant-dijkstra-J8uXs
May 29, 2026
Merged

Fix five code-review bugs (#37–#41)#42
TYRMars merged 1 commit into
mainfrom
claude/vibrant-dijkstra-J8uXs

Conversation

@TYRMars
Copy link
Copy Markdown
Owner

@TYRMars TYRMars commented May 29, 2026

Resolves the five open code-review bugs. Each fix is targeted and ships a regression test.

#37 — Security: arbitrary command execution via unvalidated git-include URL

  • New validate_git_url rejects git's remote-helper transport syntax (ext::, fd::, any <name>::<addr>), leading -, and control chars — while still allowing normal https/ssh/git/file URLs, scp-like git@host:path, and plain local paths (which git clones over the safe local transport, and which existing tests rely on).
  • Applied at IncludeDirective::parse_target (dangerous directives never parse into a GitUrl) and in git_clone (defence in depth, plus a -- separator before the URL).
  • run_git now exports GIT_ALLOW_PROTOCOL=https:ssh:git:file so git itself refuses command-executing transports even if a bad URL slipped through.
  • The same validator replaces the leading---only check in memory_sync's remote_url.

#38 — Panic: byte-slice truncation in GET /v1/tasks

  • Subagent task labels are now truncated by char count (chars().take(47)), not a raw byte slice, so multibyte (CJK/emoji) task names >48 bytes no longer panic — and no longer take down the WS socket via the turn-terminal handler.

#39 — Streaming agent loop: terminal tool orphans sibling tool_calls / dangles ToolStart

  • Sequential path: on a terminal tool, synthesize a tool cancelled: … tool_result for every unprocessed sibling before returning, so the persisted conversation has a reply for every tool_call id (no more provider 400 on resume).
  • Parallel path: track which ToolEnds genuinely fired and emit a closing ToolEnd for any call cancelled in-flight, so no ToolStart is left dangling on the wire.

#40fs.patch: disk-commit phase not atomic on I/O failure

  • The commit phase now snapshots each target's prior content, then rolls back every already-committed write/delete on any mid-batch I/O error, honouring the "atomic per call" contract. Error message reports whether rollback was complete.

#41SummarizingMemory: summary inserted out of chronological order under cache breakpoint

  • The summary is now placed at the chronological position of the dropped turns. On the cache-breakpoint path (non-contiguous kept set: cached prefix + recent tail with a hole), the summary sits between the cached prefix and the recent tail instead of before the cached prefix.

Testing

Closes #37, closes #38, closes #39, closes #40, closes #41.

https://claude.ai/code/session_013gxHmLU1sk8WabMxPvMRf7


Generated by Claude Code

#37 security: validate git-include URLs before cloning. Reject git's
remote-helper transport syntax (`ext::`, `fd::`, any `<name>::<addr>`)
and leading-`-`/control chars in `validate_git_url`, applied at
`parse_target` (so dangerous directives never parse) and in
`git_clone` (defence in depth, plus `--` separator). `run_git` now
exports `GIT_ALLOW_PROTOCOL=https:ssh:git:file`. Same validator is
applied to `memory_sync`'s remote_url.

#38 panic: truncate subagent task labels in GET /v1/tasks by char
count, not raw byte slice — multibyte (CJK/emoji) names >48 bytes no
longer panic (and no longer crash the WS socket).

#39 streaming agent loop: when a terminal tool is emitted alongside
sibling calls, synthesize a cancelled tool_result for every
unprocessed sibling on the sequential path (avoids orphaned tool_calls
→ provider 400 on resume), and emit a closing ToolEnd for cancelled
in-flight calls on the parallel path (no dangling ToolStart on the
wire).

#40 fs.patch atomicity: make the disk-commit phase atomic. Snapshot
each target's prior content, and on any mid-batch I/O failure roll
back every already-committed write/delete so the working tree is left
unchanged.

#41 SummarizingMemory: place the summary at the chronological position
of the dropped turns. On the cache-breakpoint path the kept set is
non-contiguous (cached prefix + recent tail); the summary now sits
between them instead of before the cached prefix.

Adds regression tests for all five.

https://claude.ai/code/session_013gxHmLU1sk8WabMxPvMRf7
@TYRMars TYRMars marked this pull request as ready for review May 29, 2026 03:12
@TYRMars TYRMars merged commit ea06734 into main May 29, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment