Add JSON repair + review ground-truth worktree diff#17
Conversation
Port pi's conservative JSON string-literal repair (MIT, from @earendil-works/pi packages/ai/src/utils/json-parse.ts, trimmed to the non-streaming path) into engine/jsonExtract.ts and apply it per candidate in parseLastValidJson. Model output that is almost-valid (raw control characters or invalid backslash escapes inside strings) now parses instead of costing a repair-retry round-trip or a NEEDS_HUMAN give-up. Fix the actor-critic diff soundness gap: the critic reviewed the actor's self-reported diff, but the worktree contents are what actually get committed and integrated. Add worktreeDiff() to capture the real diff (including newly created files via intent-to-add) and a captureDiff seam on the loop that prefers it over the model diff when non-empty, wired in session.ts for worktree runs. Falls back to the model diff on empty/error. Tests: new test/jsonExtract.test.ts; worktreeDiff coverage in test/git.test.ts; captureDiff override/fallback/throw in test/loop.test.ts. Co-authored-by: Inzimam Ul Haq <27832433+inhaq@users.noreply.github.com>
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (1)
🚧 Files skipped from review as they are similar to previous changes (1)
📝 WalkthroughWalkthroughThe PR adds two independent improvements: a conservative JSON repair/parse fallback ( ChangesJSON Repair and Parse Fallback
Ground-Truth Diff Capture Pipeline
Sequence Diagram(s)sequenceDiagram
participant Session as session.ts runGoal
participant RunTask as runTask BUILDING
participant WorktreeDiff as worktreeDiff
participant MechanicalGate
participant Critic
Session->>RunTask: runTask(deps) with captureDiff wired
RunTask->>RunTask: actor produces built.diff
RunTask->>WorktreeDiff: worktreeDiff(taskCwd, gitExec)
alt non-empty ground-truth diff
WorktreeDiff-->>RunTask: real diff string
RunTask->>RunTask: lastDiff = captured diff
else empty or error
WorktreeDiff-->>RunTask: empty or throws
RunTask->>RunTask: lastDiff = actor diff unchanged
end
RunTask->>MechanicalGate: evaluate lastDiff
RunTask->>Critic: review(lastDiff)
Critic-->>RunTask: GREEN or RED
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/engine/jsonExtract.ts`:
- Around line 119-128: When the unicode escape validation at lines 120-126 fails
(nextChar is "u" but not followed by exactly four hexadecimal digits), the code
currently falls through to the VALID_JSON_ESCAPES check on line 127, which
incorrectly treats the invalid escape as valid. Add an else block after the
successful unicode escape handling to catch failed unicode escapes and
literalize them by escaping the backslash (add "\\\\" to repaired instead of
"\\") so that invalid sequences like "\uZZZZ" are properly converted to
"\\uZZZZ" in the output, preventing JSON.parse from failing.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro Plus
Run ID: 40e25e12-3c27-4708-994c-e3d66a7bf11f
📒 Files selected for processing (7)
src/engine/jsonExtract.tssrc/engine/loop.tssrc/session.tssrc/workspace/git.tstest/git.test.tstest/jsonExtract.test.tstest/loop.test.ts
When \u is not followed by exactly four hex digits, the code fell through to the VALID_JSON_ESCAPES check (which includes "u"), leaving the broken sequence intact so JSON.parse still failed. Literalize it by doubling the backslash instead. Addresses CodeRabbit review on PR #17. Co-authored-by: Inzimam Ul Haq <27832433+inhaq@users.noreply.github.com>
This pull request was created by @kiro-agent on behalf of @inhaq 👻
Comment with /kiro fix to address specific feedback or /kiro all to address everything.
Learn about Kiro Web
Two self-contained robustness/correctness improvements to the actor-critic engine, derived from studying the earendil-works/pi agent harness. Both are additive — no engine, scheduler, or role-interface changes.
1. Robust JSON repair (borrowed from pi)
Ports pi's conservative JSON string-literal repair (MIT, from
@earendil-works/pipackages/ai/src/utils/json-parse.ts, trimmed to the non-streaming path — nopartial-jsondependency added) intosrc/engine/jsonExtract.ts, and applies it per candidate inparseLastValidJson.Model output is frequently almost valid JSON — a raw newline/tab inside a string, or an invalid backslash escape (e.g. a Windows path). Stock
JSON.parserejects these, which previously cost a full repair-retry round-trip (thePARSE_REPAIR_NUDGEinrunnerRoles.tsand the critic retry inloop.ts) and often ended inNEEDS_HUMAN.repairJsononly rewrites characters stock JSON would reject, so already-valid input is returned byte-for-byte.2. Review the ground-truth worktree diff, not the model's self-reported diff
The critic reviewed
built.diff(what the model claimed it changed), but the worktree contents on disk are what actually get committed and integrated — so a file-editing actor's reviewed artifact could diverge from the integrated artifact.worktreeDiff()tosrc/workspace/git.ts: captures the real unified diff including newly created files (viaadd -A --intent-to-addthengit diff HEAD, with agit difffallback). Never throws.captureDiffseam toLoopDeps(src/engine/loop.ts), read right after build and before the mechanical gate (so build/test artifacts don't pollute the diff). When it returns a non-empty diff, that becomes the artifact the critic reviews; otherwise it falls back to the model-reported diff.captureDiffinsrc/session.tsfor worktree runs.Testing
test/jsonExtract.test.ts(10 tests): repair of raw control chars, invalid escapes, preserved\uXXXX, byte-for-byte no-op on valid JSON, last-valid-object preference, and original-error rethrow.test/git.test.ts:worktreeDiffcaptures modified + newly created files and returns empty on a non-repo.test/loop.test.ts:captureDiffoverrides the model diff (critic sees ground truth) and falls back on empty/throw.npm run typecheckclean; full suite 188 tests pass.Limitations / follow-ups
captureDiffoverrides the revieweddiffonly;touchedFilesis still model-reported (informational in the bundle). Deriving it fromgit diff --name-onlyis a small follow-up.kind:"agent"runner (piagent-core+ai) that actually edits the worktree.Summary by CodeRabbit
New Features
Bug Fixes
Tests