fix(cli): implement plan diff --correction to show real correction attempt diff #9221
Merged
hurui200320
merged 2 commits from 2026-04-17 09:56:31 +00:00
fix/plan-diff-correction-stub into master
Labels
Clear labels
auto/needs-reevaluation
controller-managed
overdue
auto/blocked-by-deps
auto/ci-timeout
auto/claimed-implementer
auto/claimed-merge
auto/claimed-reviewer
auto/driver-down
auto/invariant-violation
auto/last-attempt-tier-0
auto/last-attempt-tier-1
auto/last-attempt-tier-2
auto/last-attempt-tier-min
Automation Tracking
auto/needs-conflict-resolution
auto/needs-implementer
auto/postmortem
auto/ready-to-merge
auto/restart-throttled
auto/revert
auto/sentinel
auto/stale-inactivity
auto/unstable
Blocked
Needs Feedback
Signed-off: Owner
Signed-off: Scrum Master
Signed-off: Tech Lead
Spike
Controller deferred this PR; awaiting Phase 6+ scope-evaluator or operator re-enablement.
Auto-agents controller manages this PR/issue (see tools/controller/deploy/RUNBOOK.md). Remove this label to abandon controller management.
PR blocked by an open issue dependency. Operator must close the dep (or remove the dependency link) before the merge driver can act. Auto-cleared by merge_drive when no open deps remain.
Most recent merge cycle hit CI timeout. Driver excludes this PR while last merge_cycle row is < 30 min old; label persists thereafter as visible history.
Currently being processed by an implementer worker.
Currently being processed by the merge driver.
Currently being processed by a reviewer worker.
Merge driver heartbeat stale; pipeline halted. Closed automatically on next clean tick.
Detected master commit violating the strict merge invariant. Tracked as an issue (not a PR label); kept here for label completeness.
In-cycle escalation: most recent attempt ran at the Tier 0 slot (`tier-0`). Slot's model defined in .opencode/models/tiers.yaml.
In-cycle escalation: most recent attempt ran at the Tier 1 slot (`tier-1`). Slot's model defined in .opencode/models/tiers.yaml.
In-cycle escalation: most recent attempt ran at the Tier 2 slot (`tier-2`). Slot's model defined in .opencode/models/tiers.yaml. Gated behind IMPLEMENTER_ESCALATION_TIER2_ENABLED.
In-cycle escalation: most recent attempt ran at the Tier -1 slot (`tier-min`). Slot's model defined in .opencode/models/tiers.yaml. Suffix is ``-min`` (not ``--1``) so the Forgejo UI reads naturally.
Tracking issues used by the AI Automation system for agents to communicate and report.
Rebase conflict needs LLM conflict-resolver.
Failing CI needs implementer attention.
Documenting a driver incident or rollback.
Reviewer has APPROVED this PR and no later REQUEST_CHANGES is outstanding. The merge driver requires this label to even consider a PR for merging. Set by the reviewer worker on APPROVE; cleared on REQUEST_CHANGES.
Train repeatedly lost master-tempo races. Driver excludes via merge_cycle until cooldown elapses; label persists as visible history.
Revert PR backing out an invariant violation. Fast-tracked through the merge driver.
Sentinel PR duplicated from upstream into a personal fork by tools/duplicate_prs_to_fork.py for pipeline testing. Lives only in the fork; the canonical pipeline never sees it.
No implementer activity for N days. Flagged for human review. Auto-cleared on next push to head branch.
Repeatedly fails on current master (>= 3 ci-fail-on-rebased-sha releases in 12 h). Excluded from driver until human triage.
A ticket in a blocked state and unable to complete until some other task is completed first.
Bounty
$100
A bounty of $100 for any open-source contributor who provides a MR that solves this issue
Bounty
$1000
A bounty of $1000 for any open-source contributor who provides a MR that solves this issue
Bounty
$10000
A bounty of $10000 for any open-source contributor who provides a MR that solves this issue
Bounty
$20
A bounty of $20 for any open-source contributor who provides a MR that solves this issue
Bounty
$2000
A bounty of $2000 for any open-source contributor who provides a MR that solves this issue
Bounty
$250
A bounty of $250 for any open-source contributor who provides a MR that solves this issue
Bounty
$50
A bounty of $50 for any open-source contributor who provides a MR that solves this issue
Bounty
$500
A bounty of $500 for any open-source contributor who provides a MR that solves this issue
Bounty
$5000
A bounty of $5000 for any open-source contributor who provides a MR that solves this issue
Bounty
$750
A bounty of $750 for any open-source contributor who provides a MR that solves this issue
MoSCoW
Could have
Could have feature in order to satisfy the epic/legendary.
MoSCoW
Must have
Must have feature in order to satisfy the epic/legendary.
MoSCoW
Should have
Should have feature in order to satisfy the epic/legendary.
There are questions in the ticket that can not be completed until the project owner provides clarity.
Points
1
1 man-hours worth of work for an expert with no learning curve.
Points
13
13 man-hours worth of work for an expert with no learning curve.
Points
2
2 man-hours worth of work for an expert with no learning curve.
Points
21
21 man-hours worth of work for an expert with no learning curve.
Points
3
3 man-hours worth of work for an expert with no learning curve.
Points
34
34 man-hours worth of work for an expert with no learning curve.
Points
5
5 man-hours worth of work for an expert with no learning curve.
Points
55
55 man-hours worth of work for an expert with no learning curve.
Points
8
8 man-hours worth of work for an expert with no learning curve.
Points
88
88 man-hours worth of work for an expert with no learning curve.
Priority
Backlog
This ticket has backlogged priority and is not to be worked on yet
Priority
CI Blocker
Critical priority issue that blocks CI/CD pipeline and prevents PR merges
Priority
Critical
The priority is critical
Priority
High
The priority is high
Priority
Low
The priority is low
Priority
Medium
The priority is medium
When an epic or legendary is in review it must be signed off by owner, tech lead, and scrum master before being marked as completed.
When an epic or legendary is in review it must be signed off by owner, tech lead, and scrum master before being marked as completed.
When an epic or legendary is in review it must be signed off by owner, tech lead, and scrum master before being marked as completed.
A ticket for learning a tool or technology that is needed to be able to do future planning and design.
State
Completed
The ticket has been fully implemented, completed, and merged with the source code. This label should only be applied once a ticket is closed.
State
Duplicate
A ticket that represents the same content as an existing ticket.
State
In Progress
A ticket that is actively being developed.
State
In Review
A ticket that has had some code completed to implement but is waiting to pass peer review and is not yet merged in.
State
Paused
This ticket's work started but wasn't finished. It's on hold (likely in a feature branch) and will be resumed later, either due to a blocker or a delay.
State
Unverified
All new tickets start in this state. A developer may set it to show the ticket is unverified. This means we haven't agreed to work on it. It will either move to a verified state or be closed as wontdo.
State
Verified
The issue has been verified by a developer as legitimate. It will be worked on and verified tickets are now considered part of the backlog.
State
Wont Do
This ticket has been decided it wont be done. This may mean the bug has been determined to not be real (cant verify) or the feature is one we have decided we dont want to adopt.
Type
Automation
Any edits or discussion about the AI automated coding system.
Type
Bug
Something that doesnt work as intended.
Type
Discussion
Anytime a ticket represents a discussion about a subject and doesnt fall into one of the other categories.
Type
Documentation
An error or improvement needed in the documentation.
Type
Epic
Any first tier epic. That is, an epic which contains only issues as children and will not have sub-epics.
Type
Feature
Some new functionality not present.
Type
Legendary
A type of Epic which will contain other Epics.
Type
Refactor
A code change that restructures existing code without changing its external behavior.
Type
Support
Someone needs help using the project.
Type
Task
A generic task that doesnt fit into the other type categories.
Type
Testing
Work exclusively focusing on fixing or expanding testing.
Projects
Clear projects
No project
Assignees
aditya (Aditya Chhabra)
aleenaumair (Aleena Umair)
brent.edwards (Brent Edwards)
CoreRasurae (Luis Mendes)
drew (Drew Morris)
eugen.thaci (Eugen Thaci)
freemo (Jeffrey Phillips Freeman)
HAL9000 (HAL 9000)
HAL9001 (HAL9001)
hamza.khyari (Hamza Khyari)
hurui200320 (Rui Hu)
justin.morris
khird (Kyle Hird)
org.cleveragents
Clear assignees
No Assignees
Notifications
Due Date
No due date set.
Blocks
#9085 [BUG] `agents plan diff --correction` is a stub — returns placeholder text instead of real correction diff
cleveragents/cleveragents-core
Reference: cleveragents/cleveragents-core#9221
Reference in New Issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Delete Branch "fix/plan-diff-correction-stub"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
Implements spec-compliant
agents plan diff --correction <CORRECTION_ATTEMPT_ID>output. Fixes all issues identified in the cycle-1, cycle-2, and cycle-3 reviews.Branch Note (M1)
The canonical CONTRIBUTING.md branch name is
bugfix/m4-plan-diff-correction-stub. Because Forgejo's API does not support changing a PR's head branch after creation, bothfix/plan-diff-correction-stub(PR head) andbugfix/m4-plan-diff-correction-stubare kept in sync via force-push. Both branches point to the same commit SHA.Changes — Cycle 1 (C1–C8, M3–M8, m1–m3, n1)
unit_of_work.transaction()context manager — eliminatesAttributeErrorcrash and session resource leak.unit_of_workviacontainer.unit_of_work()in_get_apply_service().features/plan_correction_diff.featurewith BDD scenarios.bugfix/m4-plan-diff-correction-stubcreated and synced.ISSUES CLOSED: #9085footer.except Exceptiontoexcept CorrectionAttemptNotFoundError.Changes — Cycle 2 (M2–M11, m1–m5, n3–n4)
Major Fixes
get_container()fallback entirely fromcorrection_diff(). RaiseValidationError("unit_of_work is required for correction_diff()")ifNone. No container-singleton access inside service methods (ADR-003).import jsonandimport yamlfrom inline method bodies to top-level imports inplan_apply_service.py(CONTRIBUTING.md §imports).from typing import Literal, castfrom inlineplan_diff()body to top-levelfrom typing importinplan.py; remove both duplicate inline imports.ValueError→ValidationErrorfor empty-input guards incorrection_diff().ValidationErroris aCleverAgentsErrorsubclass; the CLI'sexcept CleverAgentsErrorhandler now correctly surfaces these errors.COMMANDS: dict[str, object]→dict[str, Callable[[], None]]withfrom collections.abc import Callable; remove# type: ignore[operator]comment._make_apply_service_with_mocked_uowfrom-> PlanApplyServiceto-> tuple[PlanApplyService, str].plan_idand emptycorrection_attempt_idinputs produce error output.robot/plan_correction_diff.robotand_correction_diff_yamlhelper._build_mock_svcinplan_correction_diff_steps.py.Minor Fixes
_render_correction_diff_rich()and# Servicesection are correct (2 blank lines).files_changed/new_insertions/new_deletions→decisions_changed/decisions_added/decisions_revertedin comparison section._build_correction_diff_dictnoting the comparison section deviates from spec's file-level schema; reference follow-up in issue #9085.correction-diff the service was called with format "<fmt>"assertingcorrection_diff()was called with correctfmtarg for JSON and YAML format scenarios.step_new_cov_no_mocksto reflect that the correction branch now calls the service (no longer returns early)._build_correction_diff_dictnotingpatch_previewnever produces real diff hunks and referencing future enhancement in issue #9085.if attempt.original_decision_id:guard explaining the field is always non-empty but the check is retained as a safety net.Changes — Cycle 3 (Review Fixes)
Major Fixes
_build_correction_diff_dict()summary section documenting the deviation from spec'sfiles_changed/new_insertions/new_deletionsfields. All three spec deviation sections now have consistent documentation.plan_idand emptycorrection_attempt_idscenarios — change mock fromPlanErrortoValidationErrorto match the realcorrection_diff()behavior. Update assertions to check for"Error:"prefix (not"Diff Error:").Minor Fixes
#9085references in code comments with generic "future follow-up issue" text.unit_of_work is Noneguard — constructsPlanApplyService(unit_of_work=None)and assertsValidationErroris raised.get_plan()call incorrection_diff()withtry/except NotFoundErrorto convert toPlanError, ensuring consistent"Diff Error:"prefix in CLI output for all not-found conditions.yaml.dump()withyaml.safe_dump()in bothdiff()andcorrection_diff()to prevent serialization of arbitrary Python objects.rich.markup.escape()onguidanceandarchived_artifacts_pathfields in_render_correction_diff_rich()to prevent Rich markup injection."orig-decision-001"inplan_commands_new_coverage.featureafter the removed"plan-100"assertion.correction_diff()entry and warning logging on ownership-check failure.Nits
-> PlanApplyServicereturn type annotation to_get_apply_service()withTYPE_CHECKINGimport.cast()expression inplan_diff()to a single_fmtvariable before theif correction:branch.if correction_diff_side_effect:toif correction_diff_side_effect is not None:in_build_mock_svc.__enter__.return_value = mock_ctxinstead of__enter__ = MagicMock(return_value=mock_ctx).hasattrfallbacks onStrEnumfields (CorrectionMode.valueandCorrectionAttemptState.valueare always available).[OK] Correction diff generated) and rich (✓ OK Correction diff generated) output.Quality Gates
nox -s lint: PASSnox -s typecheck: PASS (0 errors, 3 pre-existing warnings)nox -s unit_tests: PASS (635 features, 15193 scenarios, 0 failures)nox -s integration_tests: PASS (1967 tests, 0 failures)nox -s e2e_tests: 3 pre-existing M6 failures (unrelated to this PR)nox -s coverage_report: PASS (97.1% ≥ 97% threshold)Issue Reference
Closes #9085
Automated by CleverAgents Bot
Agent: pr-fix-agent (Cycle 3)
Code Review Decision: REQUEST CHANGES
PR: fix(cli): implement plan diff --correction to show real correction attempt diff
Focus Area: Test Quality and Coverage (primary), plus correctness and architecture
✅ What Works Well
attempt.plan_id != plan_id) is a good security guard_build_correction_diff_dicthelper is well-structured❌ Blocking Issues
1. Missing BDD Scenarios (Critical — Required by Issue #9085)
The issue explicitly lists as a subtask:
The
features/plan_diff_artifacts.featurefile was not modified in this PR. There are no correction diff scenarios added anywhere. This is a required acceptance criterion and a Definition of Done item.Required scenarios should include at minimum:
agents plan diff --correction <ID> <PLAN_ID>returns real diff (not stub)2. Overly Broad Exception Catch (Code Quality Violation)
In
correction_diff()(plan_apply_service.py):The CONTRIBUTING.md standard prohibits bare
except:and requires catching specific exceptions. This should catch the specific repositoryNotFoundErroror equivalent, not the genericException. CatchingExceptionmasks programming errors (e.g.,AttributeError,TypeError) that should propagate.3. Architecture Violation: Direct Container Access in Service Layer
The
correction_diffmethod callsget_container()directly inside the service method:This violates the four-layer architecture. The correction attempt repository should be injected via the constructor (like
_changeset_storeand_checkpoint_managerare), not fetched from the global container at call time. This also makes the method untestable without mocking the global container.4. Unit of Work Not Used as Context Manager
The unit of work is obtained but not used as a context manager:
Typically, unit of work should be used with
with container.unit_of_work() as uow:to ensure proper transaction management and cleanup.⚠️ Non-Blocking Issues
5. Missing Input Validation
The
correction_diffmethod does not validate its inputs. Following the pattern ofcleanup_changeset(which validatesplan_id), bothplan_idandcorrection_attempt_idshould be validated as non-empty strings at the start of the method.6. Unused Variable
The
planvariable returned fromself._lifecycle.get_plan(plan_id)is assigned but never used after the existence check. Should be documented with a comment or assigned to_.7. Missing Blank Line Separator
The
correction_diffmethod is missing a blank line between the end of thediffmethod and its definition. Minor style issue but inconsistent with the rest of the file.Summary
ExceptionThe core functionality is implemented correctly, but the missing BDD tests, overly broad exception handling, and architecture violation (direct container access) must be addressed before merging.
Automated by CleverAgents Bot
Supervisor: PR Review Pool | Agent: pr-review-pool-supervisor
Worker tag: [AUTO-REV-9221]
Summary
Issues
agents plan diff --correctionstill prints the equivalent of the old stub panel instead of calling the newPlanApplyService.correction_diff()implementation. Insrc/cleveragents/cli/commands/plan.py(see theplan_diffhandler around lines 3288-3310) the code continues to short-circuit with the placeholder Panel. As a result, the CLI never reaches the new service logic, so the feature remains non-functional.Additional Observations
Automated by CleverAgents Bot
Supervisor: PR Review Pool | Agent: pr-review-pool-supervisor
Grooming Report — PR #9221
Worker: [AUTO-GROOM-BATCH]
Actions Taken
✅ Added
State/In-ReviewlabelStatus
This PR has been groomed. Check existing reviews for any required changes.
[GROOMED]
Automated by CleverAgents Bot
Supervisor: Grooming | Agent: grooming-pool-supervisor
a6310990fdto54bf60af8854bf60af88to3189066640Code Review: APPROVED ✅
PR: fix(cli): implement plan diff --correction to show real correction attempt diff
Review Focus: api-consistency, naming-conventions, code-patterns
Cycle: 3 (addresses all Cycle 1 + Cycle 2 blocking issues)
✅ All Blocking Issues from Previous Cycles — Resolved
1. Missing BDD Scenarios — ✅ RESOLVED
A dedicated
features/plan_correction_diff.featurefile was added with 9 scenarios covering all 4 output formats (rich, plain, json, yaml) and 5 error paths (plan not found, correction not found, ownership mismatch, empty plan_id, empty correction_attempt_id). Three existing BDD scenarios inplan_cli_commands_r2.feature,plan_cli_uncovered_region_coverage.feature, andplan_commands_new_coverage.featurewere updated to mock the new service path. Full step definitions infeatures/steps/plan_correction_diff_steps.py(183 lines).2. Overly Broad Exception Catch — ✅ RESOLVED
Now catches
CorrectionAttemptNotFoundErrorspecifically (imported fromcleveragents.infrastructure.database.repositories). No bareexcept Exceptionremains.3. Architecture Violation (Direct Container Access) — ✅ RESOLVED
_get_apply_service()inplan.pynow callscontainer.unit_of_work()and passes it toPlanApplyService(lifecycle_service=lifecycle, unit_of_work=container.unit_of_work()). Thecorrection_diff()method no longer callsget_container()— it usesself._unit_of_workexclusively. RaisesValidationError("unit_of_work is required for correction_diff()")if None (ADR-003 compliant).4. Unit of Work Not Used as Context Manager — ✅ RESOLVED
Uses
with uow.transaction() as ctx:correctly, ensuring proper transaction management and resource cleanup.5–7. Non-Blocking Issues — ✅ ALL RESOLVED
if not plan_id/if not correction_attempt_idguards added withValidationErrorself._lifecycle.get_plan(plan_id)called without assignment (existence check only)✅ Review Focus Areas
API Consistency
correction_diff(plan_id, correction_attempt_id, fmt="rich")mirrorsdiff(plan_id, fmt="rich")— consistent signature shape ✅fmt: Literal["rich", "plain", "json", "yaml"]— consistent type annotation withdiff()✅ValidationErrorfor input guards,PlanErrorfor domain errors — consistent with service-layer conventions ✅_get_apply_service()DI pattern consistent with other service factories ✅Naming Conventions
_build_correction_diff_dict— mirrors_build_artifacts_dictnaming pattern ✅_render_correction_diff_plain/_render_correction_diff_rich— mirrors_render_diff_plain/_render_diff_rich✅decisions_changed,decisions_added,decisions_reverted— domain-appropriate renaming from the file-levelfiles_changed/new_insertions/new_deletionsstub names ✅correction-diff— consistent with other step file prefix conventions ✅_PATCH_GET_APPLY_R2constant — consistent with existing_PATCH_GET_APPLYpattern ✅Code Patterns
cast(Literal[...], fmt if fmt in (...) else "rich")used for type-safe format coercion — valid and consistent ✅_build_mock_svchelper in step definitions — good DRY pattern ✅COMMANDS: dict[str, Callable[[], None]]— correct type annotation replacingdict[str, object]✅from __future__ import annotationsat top of all new files ✅use_step_matcher("re")/use_step_matcher("parse")switching — correct Behave pattern for mixed matchers ✅yaml.safe_load()for YAML parsing — correct ✅✅ PR Criteria Checklist (12/12)
fix(cli): implement plan diff --correction to show real correction attempt diffCloses #9085Type/BugState/In Reviewbugfix/m4-plan-diff-correction-stub(synced; Forgejo limitation noted)robot/plan_correction_diff.robot+ helperSummary
This is a well-executed Cycle 2 fix that fully addresses every blocking and non-blocking issue raised in the previous review rounds. The implementation is correct, the architecture is clean (proper DI, no container singleton in service layer), exception handling is specific, the UoW is used as a context manager, and the test suite is comprehensive (BDD + Robot Framework, all 4 formats, all error paths). Coverage at 97.1% meets the 97% threshold.
Approved for merge.
Automated by CleverAgents Bot
Supervisor: PR Review Pool | Agent: pr-reviewer
Code Review Decision: APPROVED ✅
Reviewer: HAL9001 (AUTO-REV-48)
Review Focus: api-consistency, naming-conventions, code-patterns
Cycle: 3 — all Cycle 1 + Cycle 2 blocking issues resolved
All Previous Blocking Issues — Resolved
plan_correction_diff.feature+ 3 updatedexcept ExceptioncatchCorrectionAttemptNotFoundErrorspecificallyunit_of_workinjected via constructor (ADR-003 compliant)with uow.transaction() as ctx:used correctlyValidationErrorguards for emptyplan_id/correction_attempt_idget_plan()called without assignmentReview Focus Areas — All Pass
correction_diff()signature mirrorsdiff(), consistent error types, consistent DI pattern ✅_build_correction_diff_dict,_render_correction_diff_*mirror existing patterns;decisions_*naming is domain-appropriate ✅cast(Literal[...])for type-safe format coercion,_build_mock_svcDRY helper,Callable[[], None]type annotation,yaml.safe_load()for parsing ✅Quality Gates (self-reported)
nox -s lint: PASSnox -s typecheck: PASS (0 errors)nox -s unit_tests: PASS (632 features, 15050 scenarios, 0 failures)nox -s coverage_report: PASS (97.1% ≥ 97%)This PR is approved for merge.
Automated by CleverAgents Bot
Supervisor: PR Review Pool | Agent: pr-reviewer
3189066640toebb71dc747ebb71dc747to1fda56b778