Skip to content

feat(review): add deterministic reviewer target resolution - #208

Merged
elkaix merged 11 commits into
mainfrom
feat/review-target-resolution
Jul 17, 2026
Merged

feat(review): add deterministic reviewer target resolution#208
elkaix merged 11 commits into
mainfrom
feat/review-target-resolution

Conversation

@elkaix

@elkaix elkaix commented Jul 16, 2026

Copy link
Copy Markdown
Member

Related Issue

No issue was specified.

Description

Reviewer subagents previously inferred their Git scope from free-form prompt text and could
recompute a different merge base after dispatch. This change adds a structured, pre-dispatch
target contract for review, code-reviewer, and security-reviewer.

  • Resolve auto, uncommitted, base, and commit targets to explicit Git anchors before child
    allocation.
  • Reject invalid, missing, empty, or drifting targets with typed failure categories.
  • Preserve requested and resolved target lineage through Agent, RunAgents, foreground, and
    background execution.
  • Compose one authoritative target block after generic Git orientation and caller instructions.
  • Neutralize prompt-visible repository metadata and invoke Git with bounded, shell-free process
    handling.
  • Document the live-worktree limitation: HEAD is pinned and revalidated, while index/worktree
    content remains live.

This gives reviewer children deterministic scope without coupling them to the standalone review
engine or changing non-reviewer behavior.

Validation

  • make check-pythinker-code — passed; Ruff and ty clean, 1,262 files formatted, Pyright 0
    errors/0 warnings/0 informations.
  • Focused 11-file regression set — 289 passed, 1 warning.
  • Primary suite excluding the proven baseline PTY node — 7131 passed, 9 skipped, 1 deselected, 1 xfailed.
  • Separate tests_e2e suite — 65 passed, 4 skipped.
  • Final implementation and closeout reviews — zero Critical, Important, or Minor findings;
    C01/C03/C05/C06/C08/C12/C13/C14/C15 passed.
  • git diff --check origin/main...HEAD — clean.

Known Baseline Failure

make test-pythinker-code remains nonzero solely at:

tests/e2e/test_shell_pty_e2e.py::test_shell_cancel_running_command_kills_process_and_recovers

The isolated test fails identically on this branch and clean main: Escape is ignored and the
five-second command completes. The branch Make run reported 1 failed, 7131 passed, 9 skipped, 1 xfailed before its separate tests_e2e phase. This is documented as a repository baseline blocker,
not a passing gate or feature-owned regression.

Checklist

  • Added focused tests for success, failure, malformed input, empty scope, drift, transport, and
    background behavior.
  • Added the root CHANGELOG.md Unreleased entry and synced the generated docs changelog.
  • Updated the approved design and adoption/task ledgers.
  • Full make test-pythinker-code is green — blocked by the reproducible clean-main PTY failure
    described above.

Summary by CodeRabbit

  • New Features
    • Added deterministic Git-based review targeting via a structured review_target option for fresh reviewer agents, including propagation through foreground/background runs and orchestration fingerprints.
  • Bug Fixes
    • Improved Git metadata collection with bounded output/timeouts, safer escaping/sanitization, stricter target validation, and safer handling of resumed/non-reviewer scenarios.
    • Added review-task prompt composition and live HEAD drift revalidation.
  • Documentation
    • Updated agent tool docs and parameter/schema snapshots for reviewer-only review_target.
  • Tests
    • Expanded end-to-end and unit coverage for resolution, drift handling, propagation, Git context safety, and bounded Git execution.

@coderabbitai

coderabbitai Bot commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: d7112c6c-e38e-4384-9659-eb345974947d

📥 Commits

Reviewing files that changed from the base of the PR and between e3ef446 and ec57659.

⛔ Files ignored due to path filters (2)
  • docs/en/release-notes/changelog.md is excluded by !docs/**
  • tasks/lessons.md is excluded by !tasks/**
📒 Files selected for processing (1)
  • CHANGELOG.md

📝 Walkthrough

Walkthrough

Reviewer subagents now receive structured, deterministic Git targets. Scopes are validated, Git metadata is bounded and escaped, and resolved targets propagate through foreground, background, and multi-agent execution with HEAD-drift checks.

Changes

Reviewer Git scope pipeline

Layer / File(s) Summary
Bounded Git context and prompt data
src/pythinker_code/subagents/git_context.py, src/pythinker_code/utils/trust.py, tests/test_git_context.py, tests/utils/test_trust.py
Git execution applies timeouts, output limits, cleanup, categorized errors, and escaped context rendering.
Review target resolution and revalidation
src/pythinker_code/subagents/review_target.py, tests/subagents/test_review_target.py
Structured targets resolve to live worktree or commit scopes with typed errors, safe prompt blocks, and HEAD revalidation.
Reviewer dispatch and prompt integration
src/pythinker_code/tools/agent/..., src/pythinker_code/subagents/core.py, src/pythinker_code/subagents/runner.py, src/pythinker_code/background/..., tests/tools/..., tests/core/..., tests/background/..., src/pythinker_code/tools/agent/description.md, CHANGELOG.md
Foreground, background, and batch launches carry resolved targets, enforce reviewer-only rules, compose prompts, report hints, and update schemas and documentation.

Estimated code review effort: 5 (Critical) | ~90+ minutes

Sequence Diagram(s)

sequenceDiagram
  participant AgentTool
  participant resolve_review_target
  participant ForegroundRunner
  participant BackgroundTaskManager
  participant prepare_soul
  AgentTool->>resolve_review_target: resolve structured review_target
  resolve_review_target-->>AgentTool: ResolvedReviewTarget
  AgentTool->>ForegroundRunner: launch with resolved target
  AgentTool->>BackgroundTaskManager: create task with resolved target
  ForegroundRunner->>prepare_soul: prepare SubagentRunSpec
  BackgroundTaskManager->>prepare_soul: prepare background SubagentRunSpec
  prepare_soul-->>ForegroundRunner: composed review prompt
  prepare_soul-->>BackgroundTaskManager: composed review prompt
Loading

Suggested labels: enhancement

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 27.17% which is insufficient. The required threshold is 70.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title follows the required conventional-commit format and matches the reviewer target resolution change.
Description check ✅ Passed The description includes the required sections and substantial implementation, validation, and checklist detail, with only the issue link left generic.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/review-target-resolution

Comment @coderabbitai help to get the list of available commands.

Comment thread src/pythinker_code/subagents/review_target.py Fixed
Comment thread src/pythinker_code/subagents/review_target.py Fixed
Comment thread src/pythinker_code/subagents/git_context.py Fixed
Comment thread tests/test_git_context.py Fixed
Comment thread tests/test_git_context.py Fixed
Comment thread tests/background/test_manager.py Fixed
@codecov

codecov Bot commented Jul 16, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 98.66310% with 5 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
src/pythinker_code/subagents/git_context.py 95.49% 0 Missing and 5 partials ⚠️

📢 Thoughts on this report? Let us know!

@elkaix
elkaix marked this pull request as ready for review July 16, 2026 00:16

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

🤖 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/pythinker_code/subagents/git_context.py`:
- Around line 170-176: Only derive and append the project name in the
approved-host branch of the remote URL handling, after _sanitize_remote_url
returns a valid value. Update the logic around _sanitize_remote_url and
_parse_project_name so rejected hosts cannot expose project names, while
preserving existing escaping and limits for approved remotes.

In `@tests/background/test_manager.py`:
- Around line 393-469: The test should verify prompt and resolved-target
transport through the public background-task flow rather than directly invoking
BackgroundAgentRunner._run_core. Launch the task via create_agent_task, stub
only the model-execution boundary, and assert the resulting observable prompt
snapshot or output contains both the original caller prompt and
resolved_review_target; remove mocks and assertions tied to prepare_soul,
_mark_task_running, _prepare_isolation_worktree, and SubagentRunSpec internals.

In `@tests/subagents/test_review_target.py`:
- Around line 373-440: Rewrite these tests to exercise the public
resolve_review_target entry point rather than patching _run_resolver_git or
invoking _resolve_commit, _resolve_head, and _try_resolve_commit directly.
Provide controlled Git results through the run_git boundary, preserving
assertions for fatal verification errors, missing refs, quiet invocation
behavior, and sanitized error messages by checking the resulting public resolver
outcomes. Apply the same change to the tests in the referenced additional range.
- Line 158: Correct the assertion in the relevant test by checking the prompt’s
actual field spelling, selected_base_ref, when verifying that main was not
selected; otherwise remove the trivially true assertion. Keep the test’s
intended protection against accidental selection of main.

In `@tests/tools/test_agent_tool.py`:
- Around line 2434-2448: Remove the `_journal_foreground_agent_start` mock and
the `events` tracking used only to assert journaling order in the affected test.
Keep the `resolve_before_allocation` assertion that
`runtime.subagent_store.list_instances() == []`, since it verifies the
observable resolution-before-allocation contract without coupling the test to
private implementation sequencing.
🪄 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: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 2ab4c8aa-374b-4f51-92d3-24399ab92b33

📥 Commits

Reviewing files that changed from the base of the PR and between 10aedf2 and 72090c4.

⛔ Files ignored due to path filters (6)
  • docs/en/release-notes/changelog.md is excluded by !docs/**
  • docs/superpowers/plans/2026-07-15-deterministic-review-target-resolution.md is excluded by !docs/**
  • docs/superpowers/specs/2026-07-15-review-target-resolution-design.md is excluded by !docs/**
  • tasks/agent-harness-adoption-plan.md is excluded by !tasks/**
  • tasks/lessons.md is excluded by !tasks/**
  • tasks/todo.md is excluded by !tasks/**
📒 Files selected for processing (21)
  • CHANGELOG.md
  • src/pythinker_code/background/agent_runner.py
  • src/pythinker_code/background/manager.py
  • src/pythinker_code/subagents/core.py
  • src/pythinker_code/subagents/git_context.py
  • src/pythinker_code/subagents/review_target.py
  • src/pythinker_code/subagents/runner.py
  • src/pythinker_code/tools/agent/__init__.py
  • src/pythinker_code/tools/agent/description.md
  • src/pythinker_code/utils/trust.py
  • tests/background/test_manager.py
  • tests/background/test_task_metadata.py
  • tests/core/test_default_agent.py
  • tests/core/test_prepare_soul.py
  • tests/subagents/test_git_context_gate.py
  • tests/subagents/test_review_target.py
  • tests/test_git_context.py
  • tests/tools/test_agent_tool.py
  • tests/tools/test_tool_descriptions.py
  • tests/tools/test_tool_schemas.py
  • tests/utils/test_trust.py

Comment thread src/pythinker_code/subagents/git_context.py Outdated
Comment thread tests/background/test_manager.py Outdated
Comment thread tests/subagents/test_review_target.py Outdated
Comment thread tests/subagents/test_review_target.py Outdated
Comment thread tests/tools/test_agent_tool.py Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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/pythinker_code/subagents/core.py`:
- Around line 126-128: Update _compose_review_prompt to escape or neutralize
reserved review-task and review-target boundary tags in caller_prompt before
interpolation, preventing forged target sections while preserving the
authoritative target.prompt. Add a regression test verifying malicious caller
input still produces exactly one <review-target> block.
🪄 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: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 2caa79c7-b0e3-4e7a-b1d5-9a00e08bc46c

📥 Commits

Reviewing files that changed from the base of the PR and between 72090c4 and 045950e.

⛔ Files ignored due to path filters (2)
  • tasks/lessons.md is excluded by !tasks/**
  • tasks/todo.md is excluded by !tasks/**
📒 Files selected for processing (8)
  • src/pythinker_code/subagents/core.py
  • src/pythinker_code/subagents/git_context.py
  • src/pythinker_code/subagents/review_target.py
  • src/pythinker_code/tools/agent/__init__.py
  • tests/background/test_manager.py
  • tests/subagents/test_review_target.py
  • tests/test_git_context.py
  • tests/tools/test_agent_tool.py

Comment thread src/pythinker_code/subagents/core.py Outdated
@elkaix
elkaix merged commit 21fc085 into main Jul 17, 2026
34 checks passed
@elkaix
elkaix deleted the feat/review-target-resolution branch July 17, 2026 20:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant