feat(events): enrich PLAN_CANCELLED event with progress and resource cleanup context #1301

Merged
freemo merged 1 commit from feature/m6-plan-cancelled-enrichment into master 2026-04-02 17:07:42 +00:00
Owner

Summary

Enriches the PLAN_CANCELLED domain event emitted by PlanLifecycleService.cancel_plan() with additional context fields to improve the audit trail quality (SEC7 Audit Logging spec).

Changes

src/cleveragents/application/services/plan_lifecycle_service.py

The cancel_plan() method now captures plan state before mutating it to CANCELLED, and includes the following additional fields in the PLAN_CANCELLED event details dict:

Progress context (where the plan was when cancelled):

  • cancelled_phase — the plan phase at cancellation (e.g. "strategize")
  • cancelled_processing_state — the processing state at cancellation (e.g. "queued")
  • last_completed_step — index of the last successfully completed step (-1 if none)
  • subplan_count — number of spawned subplans at cancellation time

Resource cleanup context (what needs cleanup):

  • sandbox_refs — list of active sandbox reference IDs requiring cleanup
  • changeset_id — ID of any in-progress changeset that needs cleanup
  • resources_pending_cleanup — count of sandbox refs pending cleanup

Existing fields (reason, project_names) are preserved for backward compatibility.

features/plan_cancelled_enrichment.feature + features/steps/plan_cancelled_enrichment_steps.py

15 BDD scenarios covering:

  • All new progress context fields present in event details
  • All new resource cleanup context fields present in event details
  • Cancellation reason field (explicit and default empty string)
  • Accurate field values (phase, step, sandbox refs count)
  • Backward compatibility of existing fields

Quality Gates

  • nox -e lint — all checks passed
  • nox -e typecheck — 0 errors, 0 warnings
  • nox -e unit_tests -- features/plan_cancelled_enrichment.feature — 15/15 scenarios pass
  • nox -e unit_tests -- features/plan_lifecycle_service_coverage_boost_r2.feature — 14/14 scenarios pass (no regressions)

Closes #717

## Summary Enriches the `PLAN_CANCELLED` domain event emitted by `PlanLifecycleService.cancel_plan()` with additional context fields to improve the audit trail quality (SEC7 Audit Logging spec). ## Changes ### `src/cleveragents/application/services/plan_lifecycle_service.py` The `cancel_plan()` method now captures plan state **before** mutating it to `CANCELLED`, and includes the following additional fields in the `PLAN_CANCELLED` event `details` dict: **Progress context** (where the plan was when cancelled): - `cancelled_phase` — the plan phase at cancellation (e.g. `"strategize"`) - `cancelled_processing_state` — the processing state at cancellation (e.g. `"queued"`) - `last_completed_step` — index of the last successfully completed step (`-1` if none) - `subplan_count` — number of spawned subplans at cancellation time **Resource cleanup context** (what needs cleanup): - `sandbox_refs` — list of active sandbox reference IDs requiring cleanup - `changeset_id` — ID of any in-progress changeset that needs cleanup - `resources_pending_cleanup` — count of sandbox refs pending cleanup Existing fields (`reason`, `project_names`) are preserved for backward compatibility. ### `features/plan_cancelled_enrichment.feature` + `features/steps/plan_cancelled_enrichment_steps.py` 15 BDD scenarios covering: - All new progress context fields present in event details - All new resource cleanup context fields present in event details - Cancellation reason field (explicit and default empty string) - Accurate field values (phase, step, sandbox refs count) - Backward compatibility of existing fields ## Quality Gates - ✅ `nox -e lint` — all checks passed - ✅ `nox -e typecheck` — 0 errors, 0 warnings - ✅ `nox -e unit_tests -- features/plan_cancelled_enrichment.feature` — 15/15 scenarios pass - ✅ `nox -e unit_tests -- features/plan_lifecycle_service_coverage_boost_r2.feature` — 14/14 scenarios pass (no regressions) Closes #717
feat(events): enrich PLAN_CANCELLED event with progress and resource cleanup context
Some checks failed
CI / lint (pull_request) Failing after 2s
CI / typecheck (pull_request) Failing after 1s
CI / coverage (pull_request) Has been skipped
CI / security (pull_request) Failing after 1s
CI / quality (pull_request) Failing after 1s
CI / integration_tests (pull_request) Failing after 2s
CI / e2e_tests (pull_request) Failing after 2s
CI / build (pull_request) Failing after 1s
CI / helm (pull_request) Failing after 2s
CI / unit_tests (pull_request) Successful in 6m19s
CI / docker (pull_request) Has been skipped
CI / status-check (pull_request) Failing after 1s
CI / benchmark-publish (pull_request) Has been skipped
CI / benchmark-regression (pull_request) Has been skipped
6efbd4f7d2
Enriches the PLAN_CANCELLED domain event emitted by PlanLifecycleService.cancel_plan()
with additional context fields to improve audit trail quality (SEC7 Audit Logging).

Progress context fields added to event details:
- cancelled_phase: the plan phase at the moment of cancellation (e.g. 'strategize')
- cancelled_processing_state: the processing state at cancellation (e.g. 'queued')
- last_completed_step: index of the last successfully completed step (-1 if none)
- subplan_count: number of spawned subplans at cancellation time

Resource cleanup context fields added to event details:
- sandbox_refs: list of active sandbox reference IDs requiring cleanup
- changeset_id: ID of any in-progress changeset that needs cleanup
- resources_pending_cleanup: count of sandbox refs pending cleanup

Existing fields (reason, project_names) are preserved for backward compatibility.
Progress context is captured before the plan state is mutated to CANCELLED so the
event accurately reflects the state at the moment of cancellation.

BDD tests added in features/plan_cancelled_enrichment.feature covering:
- All new progress context fields present in event details
- All new resource cleanup context fields present in event details
- Cancellation reason field (explicit and default empty string)
- Accurate field values (phase, step, sandbox refs count)
- Backward compatibility of existing fields

Closes #717
Author
Owner

Review claimed by reviewer pool instance reviewer-pool-1. Dispatching independent code review.

Review claimed by reviewer pool instance reviewer-pool-1. Dispatching independent code review.
freemo left a comment

Independent Code Review — APPROVED

Summary

This PR enriches the PLAN_CANCELLED domain event with progress and resource cleanup context, improving the audit trail per SEC7 Audit Logging spec requirements. The implementation is clean, well-typed, and well-tested.

What Was Reviewed

  • Service change (plan_lifecycle_service.py): ~30 lines of net change to cancel_plan() method
  • Feature file (plan_cancelled_enrichment.feature): 15 BDD scenarios
  • Step definitions (plan_cancelled_enrichment_steps.py): 252 lines of test infrastructure
  • Commit message: Conventional Changelog format, detailed body, Closes #717

Findings

Specification Alignment

  • Enriched event payload aligns with SEC7 Audit Logging requirements
  • Progress context captured before state mutation — correctly reflects state at moment of cancellation
  • Backward compatibility preserved (existing reason and project_names fields retained)

Correctness

  • State capture before mutation prevents data loss: cancelled_phase, cancelled_processing_state, last_completed_step, sandbox_refs, changeset_id, subplan_count are all captured before plan.processing_state = ProcessingState.CANCELLED
  • list(plan.sandbox_refs) creates a defensive copy — good practice
  • resources_pending_cleanup derived from len(sandbox_refs) provides convenient count for consumers
  • Removal of the COV-3 comment is appropriate since the data is now available

Type Safety

  • All captured variables have explicit type annotations (str, int, list[str], str | None)
  • event_details: dict[str, object] is correctly typed for mixed-value dict
  • No # type: ignore suppressions

Test Quality

  • 15 BDD scenarios cover: field presence (7), value accuracy (4), backward compatibility (2), reason handling (2)
  • _RecordingBus helper is minimal and focused
  • Sandbox ref injection via model_copy is a clean approach for testing resource context
  • stop_all_active_containers properly mocked to avoid side effects

⚠️ Minor Process Notes (non-blocking)

  • PR is missing a Type/ label and milestone assignment (issue #717 has Type/Documentation and milestone v3.5.0)
  • No Robot Framework integration tests included, but the issue subtasks list this as a separate item
  • _RecordingBus.events uses bare list type hint — could be list[object] for stricter typing, but this is test-only code

Verdict

The code changes are solid, well-tested, and aligned with the specification. Proceeding with merge.

## Independent Code Review — APPROVED ✅ ### Summary This PR enriches the `PLAN_CANCELLED` domain event with progress and resource cleanup context, improving the audit trail per SEC7 Audit Logging spec requirements. The implementation is clean, well-typed, and well-tested. ### What Was Reviewed - **Service change** (`plan_lifecycle_service.py`): ~30 lines of net change to `cancel_plan()` method - **Feature file** (`plan_cancelled_enrichment.feature`): 15 BDD scenarios - **Step definitions** (`plan_cancelled_enrichment_steps.py`): 252 lines of test infrastructure - **Commit message**: Conventional Changelog format, detailed body, `Closes #717` ### Findings #### ✅ Specification Alignment - Enriched event payload aligns with SEC7 Audit Logging requirements - Progress context captured **before** state mutation — correctly reflects state at moment of cancellation - Backward compatibility preserved (existing `reason` and `project_names` fields retained) #### ✅ Correctness - State capture before mutation prevents data loss: `cancelled_phase`, `cancelled_processing_state`, `last_completed_step`, `sandbox_refs`, `changeset_id`, `subplan_count` are all captured before `plan.processing_state = ProcessingState.CANCELLED` - `list(plan.sandbox_refs)` creates a defensive copy — good practice - `resources_pending_cleanup` derived from `len(sandbox_refs)` provides convenient count for consumers - Removal of the `COV-3` comment is appropriate since the data is now available #### ✅ Type Safety - All captured variables have explicit type annotations (`str`, `int`, `list[str]`, `str | None`) - `event_details: dict[str, object]` is correctly typed for mixed-value dict - No `# type: ignore` suppressions #### ✅ Test Quality - 15 BDD scenarios cover: field presence (7), value accuracy (4), backward compatibility (2), reason handling (2) - `_RecordingBus` helper is minimal and focused - Sandbox ref injection via `model_copy` is a clean approach for testing resource context - `stop_all_active_containers` properly mocked to avoid side effects #### ⚠️ Minor Process Notes (non-blocking) - PR is missing a `Type/` label and milestone assignment (issue #717 has `Type/Documentation` and milestone v3.5.0) - No Robot Framework integration tests included, but the issue subtasks list this as a separate item - `_RecordingBus.events` uses bare `list` type hint — could be `list[object]` for stricter typing, but this is test-only code ### Verdict The code changes are solid, well-tested, and aligned with the specification. Proceeding with merge.
freemo merged commit 65aa7a7842 into master 2026-04-02 17:07:42 +00:00
freemo deleted branch feature/m6-plan-cancelled-enrichment 2026-04-02 17:07:43 +00:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
cleveragents/cleveragents-core!1301
No description provided.