fix(cli): add --execution-env-priority flag to plan use #972
No reviewers
Labels
No labels
auto/needs-reevaluation
controller-managed
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
Bounty
$100
Bounty
$1000
Bounty
$10000
Bounty
$20
Bounty
$2000
Bounty
$250
Bounty
$50
Bounty
$500
Bounty
$5000
Bounty
$750
MoSCoW
Could have
MoSCoW
Must have
MoSCoW
Should have
Needs Feedback
Points
1
Points
13
Points
2
Points
21
Points
3
Points
34
Points
5
Points
55
Points
8
Points
88
Priority
Backlog
Priority
CI Blocker
Priority
Critical
Priority
High
Priority
Low
Priority
Medium
Signed-off: Owner
Signed-off: Scrum Master
Signed-off: Tech Lead
Spike
State
Completed
State
Duplicate
State
In Progress
State
In Review
State
Paused
State
Unverified
State
Verified
State
Wont Do
Type
Automation
Type
Bug
Type
Discussion
Type
Documentation
Type
Epic
Type
Feature
Type
Legendary
Type
Refactor
Type
Support
Type
Task
Type
Testing
No project
No assignees
3 participants
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
cleveragents/cleveragents-core!972
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "feature/m3-plan-use-env-priority"
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
Adds the missing
--execution-env-priorityflag to theagents plan usecommand, aligning the CLI with the specification (spec line 12501). The flag acceptsfallback(default) oroverrideand controls execution environment routing precedence per ADR-043:override: The specified execution environment always wins, bypassing devcontainer auto-detection.fallback: The specified environment defers to auto-detected devcontainers or project-level overrides.Changes
cleveragents.domain.models.core.plan):ExecutionEnvPriorityStrEnum withFALLBACK/OVERRIDEvalues.execution_env_priorityfield type toExecutionEnvPriority | None(leverages Pydantic enum validation).@model_validatorenforcing thatexecution_env_priorityrequiresexecution_environment(domain-level fail-fast invariant). Verifiedvalidate_assignment=Trueis set onPlan.model_config.Plan.as_cli_dict()to includeexecution_environmentandexecution_env_priority, with fallback default of"fallback"for pre-migration data whereexecution_env_priorityisNone.cleveragents.cli.commands.plan):--execution-env-priorityparameter touse_action.--execution-environment, enum value validation, case-insensitive input."fallback"when--execution-environmentis set without explicit priority._print_lifecycle_planand_plan_spec_dictto display the priority, defaulting to"fallback"for pre-migration data._plan_spec_dictdocstring to mention new keys.ExecutionEnvPriorityimport to function-entry deferred imports in both_plan_spec_dictand_print_lifecycle_plan(no longer conditional on execution environment being set).service.save_plan(plan)withhas_overridesflag so it is only called when CLI overrides were actually applied.cleveragents.infrastructure.database):execution_environment(String(255), nullable) andexecution_env_priority(String(20), nullable) columns toLifecyclePlanModel.from_domain()/to_domain()for round-trip serialization includingExecutionEnvPriorityenum reconstruction. Uses direct attribute access (plan.execution_environment) instead of defensivegetattr— Plan fields always exist on the Pydantic BaseModel.LifecyclePlanRepository.update()to persist both fields using direct attribute access.m4_003_plan_env_columnsadding both columns to thev3_planstable. UsesString(255)forexecution_environmentto accommodate namespaced resource names. Descends fromm6_005_profile_guards_json.cleveragents.application.services.plan_lifecycle_service):save_plan()public convenience method for callers that need to re-persist after post-creation mutations.call_argsverification).ValueError; construction with both fields succeeds.ExecutionEnvPriorityenum: values verification,StrEnumsubclass assertion.Plan.as_cli_dict(): includes both fields when set, omits both whenNone, defaults priority to"fallback"for pre-migration data.from_domain()→to_domain()preserves both fields; preservesNonevalues.SimpleNamespace-based plan test fixtures indatabase_models_lifecycle_coverage_steps,database_models_new_coverage_steps,database_models_coverage_r2_steps, andrepositories_error_handling_coverage_stepsto includeexecution_environmentandexecution_env_priorityattributes.sys.pathpattern to standard approach.Review Fixes (Brent Edwards, Review #2384)
getattr: Replacedgetattr(plan, "execution_environment", None)with directplan.execution_environmentaccess in bothLifecyclePlanModel.from_domain()andLifecyclePlanRepository.update(). Plan is a Pydantic BaseModel withdefault=None, so the field always exists. Updated 4 pre-existingSimpleNamespace-based test fixtures to include the new attributes.ExecutionEnvPriorityimport from inside conditional blocks to function-entry deferred imports in both_plan_spec_dictand_print_lifecycle_plan.m4_003to descend fromm6_005_profile_guards_json(post-rebase chain fix).masterwith merge conflict inCHANGELOG.mdresolved.Deferred Items
save_plan()fails afteruse_action()succeeds, the plan exists in the DB without CLI overrides. This requires service-layer restructuring beyond the scope of this ticket.m4_003depends onm6_005, creating non-sequential naming. Renaming an existing migration risks breaking the chain for anyone who has already applied it.Quality Gates
Closes #886
Code Review — PR #972 (
fix(cli): add --execution-env-priority flag to plan use)Self-review by: @hurui200320
Ticket: #886
Branch:
feature/m3-plan-use-env-priorityVerdict: REQUEST CHANGES
The specification compliance of the flag implementation is strong — the flag name, allowed values, default behavior, validation, and output all exactly match the spec. The code is well-structured and follows existing patterns consistently. However, several issues need to be addressed before merge.
Blocking Issues
1. CHANGELOG.md not updated
CHANGELOG.mdhas no changes in this PR.--execution-env-priorityflag.2.
execution_env_priority(andexecution_environment) not persisted to databasesrc/cleveragents/cli/commands/plan.py:1571-1646,src/cleveragents/infrastructure/database/models.py(LifecyclePlanModel),src/cleveragents/application/services/plan_lifecycle_service.py:716-718use_actionCLI handler callsservice.use_action()at line 1571, which creates and persists the plan to the database. Theexecution_env_priority(and other overrides likeexecution_environment, actors, etc.) are set on the in-memory plan object after the persist call. No re-persist follows. Additionally,LifecyclePlanModelhas no columns forexecution_environmentorexecution_env_priority, so even a re-persist would not save them. This means the values are lost on process restart or any subsequentplan status/plan executecall.plan_lifecycle_service.pyplan creation," which implies the service should receive and persist this value.execution_env_priority(andexecution_environment) as columns toLifecyclePlanModel, updatefrom_domain()/to_domain()/update(), and add a re-persist call after mutations; or (b) pass the value as a parameter toservice.use_action()so it's set before the initial persist. If this is intentionally deferred to a future PR, the subtask and acceptance criteria should be updated to reflect that.3. Missing model-level validation for priority-without-environment invariant
src/cleveragents/domain/models/core/plan.py:694-697execution_env_priorityrequiresexecution_environmentis enforced only in the CLI layer (plan.py:1624-1629). There is no@model_validatoron thePlanclass. Any code path that creates aPlanoutside the CLI (service layer, API, tests, deserialization) can silently violate this invariant. CONTRIBUTING.md's "Fail-Fast" and "Argument Validation" principles require domain-level validation.@model_validator(mode="after")toPlan:Major Issues
4.
Plan.as_cli_dict()omitsexecution_environmentandexecution_env_prioritysrc/cleveragents/domain/models/core/plan.py:914-1014_plan_spec_dict()function in the CLI correctly includes both fields, but the model's ownas_cli_dict()method does not. Any code path that usesas_cli_dict()(programmatic API consumers, other CLI commands) will silently omit these fields.as_cli_dict():5. Robot Framework integration tests use mocks (CONTRIBUTING.md violation)
robot/helper_plan_use_env_priority.py(throughout)MagicMockandpatchextensively. This follows an established codebase-wide pattern (20+ existing helpers), but technically violates the guidelines.6. Tests do not verify
use_action()was actually calledfeatures/steps/plan_use_env_priority_steps.py:203-219Thensteps verify plan attribute values by readingcontext.mock_service.use_action.return_value, but no scenario asserts thatuse_action()was actually called or checks the arguments passed to it. If a refactor changed the CLI to skipuse_action(), these tests could still pass.mock_service.use_action.assert_called_once()and verifycall_argsin at least one scenario.Minor Issues
7. Model field typed as
str | Noneinstead ofExecutionEnvPriority | Nonesrc/cleveragents/domain/models/core/plan.py:694execution_environmentpattern but misses Pydantic's built-in enum validation.ExecutionEnvPriority | Noneor add a@field_validator.8. Naming inconsistency:
execution_env_priorityvsexecution_environmentenvinexecution_env_prioritybut fullenvironmentinexecution_environment. This flows through the model field, CLI flag, and enum class names.execution_environment_priority/--execution-environment-priorityfor consistency. This is easier to change now than later.9. No test for case-insensitive input handling
features/plan_use_env_priority.feature.lower(), soOVERRIDEandOverrideshould work, but no scenario tests this. If.lower()were removed, existing tests would still pass.10. Behave Scenario 6 output assertion is fragile
features/plan_use_env_priority.feature:41"Execution Env Priority"but not the value. The test could pass even if the priority value were missing.11. Robot helper uses aggressive
sys.path/sys.modulesmanipulationrobot/helper_plan_use_env_priority.py:14-26sys.path.insert(0, _SRC).Positive Observations
.lower()is applied to both validation and storage in single-threaded CLI code."plan env priority"prefix; no conflicts with existing steps.022e43f9168df51f61d2Review Response — Commit
8df51f61Addressed all actionable items from the self-review. Force-pushed an amended commit. Here is the disposition of each item:
Blocking Issues
1. CHANGELOG.md not updated — FIXED
Added entry under
## Unreleaseddescribing the new--execution-env-priorityflag, domain model changes, and model validation. References(#886).2.
execution_env_prioritynot persisted to database — DEFERREDThis is a pre-existing architectural gap that affects all CLI overrides (
execution_environment, actor overrides, etc.). TheLifecyclePlanModelhas no columns for any of these fields. Fixing this requires:LifecyclePlanModelforexecution_environmentandexecution_env_priorityfrom_domain()/to_domain()/update()methodsuse_action()signatureThis is a cross-cutting concern that should be addressed as a separate issue covering all CLI overrides. The subtask "Pass priority value through to
plan_lifecycle_service.pyplan creation" is satisfied in that the value is correctly set on the Plan domain object returned by the service; the gap is that the service does not re-persist after CLI mutations (same as all other overrides).3. Missing model-level validation — FIXED
Added
@model_validator(mode="after")namedvalidate_env_priority_requires_environmentto thePlanclass. Enforces the invariant thatexecution_env_priorityrequiresexecution_environmentto be set. Withvalidate_assignment=Truein the model config, this fires on every field assignment, providing defense-in-depth for all code paths (CLI, service, API, deserialization).Major Issues
4.
Plan.as_cli_dict()omits fields — FIXEDAdded
execution_environmentandexecution_env_priority(with.valuefor stable string output) toas_cli_dict(), conditionally included when execution environment is set.5. Robot Framework integration tests use mocks — DEFERRED
This is a pre-existing codebase-wide pattern used by 20+ Robot helpers. Rewriting just this helper to use real services would be inconsistent with the rest of the test suite. This should be addressed as a comprehensive effort across all Robot helpers, not piecemeal per PR.
6. Tests do not verify
use_action()was called — FIXEDAdded
step_verify_use_action_calledstep definition withmock_service.use_action.assert_called_once(). Used in Scenario 1 ("Plan use with --execution-env-priority override and --execution-environment") to verify the service was actually invoked.Minor Issues
7. Model field typed as
str | None— FIXEDChanged
execution_env_priorityfield type fromstr | NonetoExecutionEnvPriority | None. This leverages Pydantic's built-in enum validation via coercion. Note: this is actually more consistent with the existing codebase pattern —phase: PlanPhaseandprocessing_state: ProcessingStateare both typed as their enum types, notstr. Theexecution_environment: str | Nonepattern is the outlier. Updated all output sites to use.valuefor explicit string serialization.8. Naming inconsistency — NOT CHANGED (spec-driven)
The CLI flag name
--execution-env-prioritycomes directly from the specification (CLI Synopsis line 331). The model field nameexecution_env_priorityfollows standard kebab-to-snake-case mapping. Changing this would deviate from the spec. If the naming should be aligned, that would require a spec amendment first.9. No test for case-insensitive input — FIXED
Added Scenario 8: "Plan use accepts uppercase --execution-env-priority value" that passes
"OVERRIDE"and verifies it normalizes to"override".10. Behave Scenario 6 output assertion fragile — FIXED
Strengthened Scenario 6 to assert both the label
"Execution Env Priority"AND the value"override"are present in the output.11. Robot helper aggressive sys.path manipulation — FIXED
Replaced the aggressive
sys.pathrebuild +sys.modulesflush pattern with the standard simpler approach:if _SRC not in sys.path: sys.path.insert(0, _SRC). This matches the pattern used byhelper_action_cli_spec.pyand others.Quality Gates (post-fix)
8df51f61d2ad3e4708c4Review Response — Commit
ad3e4708Addressed the remaining deferred item (issue 2: persistence) from the self-review. Force-pushed an amended commit. Here is the updated disposition:
Previously Deferred — Now Resolved
2.
execution_env_priority(andexecution_environment) not persisted to database — FIXEDThis was previously deferred as a pre-existing architectural gap, but the ticket's acceptance criterion explicitly states "Flag value is persisted on the Plan model when creating the plan." The persistence gap has now been fully addressed:
LifecyclePlanModel): Addedexecution_environmentandexecution_env_priorityasString(20)nullable columns.from_domain(): SerializesExecutionEnvPriorityenum to its.valuestring with null guard.to_domain(): ReconstructsExecutionEnvPriorityenum from stored string, with null handling.update(): Writes both fields during plan updates using the samegetattr+.valuepattern as other optional enum fields.PlanLifecycleService.save_plan(): New public convenience method that delegates to_commit_plan(), giving callers a clean API to re-persist after post-creation mutations. No-op in non-persisted (in-memory) mode.use_action: Callsservice.save_plan(plan)after applying all CLI overrides (environment, priority, actors, automation profile), ensuring the values survive across sessions.m4_003_plan_env_columns: Adds both columns tov3_planswith nullable constraint and batch-mode DDL for SQLite compatibility.Test coverage for persistence:
save_plan.assert_called_once()to verify the re-persist path.save_plan.assert_called_once()to verify persistence on the default path.Note: This approach (re-persist after mutation) is intentionally scoped to the fields introduced by this PR. The broader architectural gap (other CLI overrides like actor overrides also not being persisted) remains a separate concern — those fields were already not persisted before this PR, and this PR does not regress them. A separate issue should be created to address the remaining unpersisted CLI overrides.
Items Unchanged from Previous Response
All other items from the self-review remain as addressed in commit
8df51f6:@model_validatoradded.as_cli_dict()omissions — Both fields added.use_action()called — Step added.ExecutionEnvPriority | None.sys.path— Simplified.Quality Gates (post-fix)
--execution-env-priorityflag toplan use#886PM Day 36 Triage: --execution-env-priority flag for plan use. Closes #886. Self-reviews identified and fixed Blocking issues (CHANGELOG, DB persistence gap, model validation). DB persistence now properly implemented with Alembic migration. Reviewer needed: @hamza.khyari. M4 scope.
ad3e4708c4200365acbdSelf-QA Review — Verdict: ✅ Approve
This PR has been through an automated self-review and fix loop (2 cycles). The code is now ready for external review.
Loop Summary
Cycle 1 — Findings & Fixes
Major fixes applied:
String(20)→String(255)forexecution_environmentcolumn (DB model + Alembic migration) to accommodate future resource names likelocal/my-dev-container.@model_validatorindependently of CLI (priority without environment raisesValueError; both fields set succeeds).LifecyclePlanModel.from_domain()→to_domain()for both set andNonevalues.as_cli_dict()test coverage: Added 3 Behave scenarios (fields set, fieldsNone, pre-migration fallback default).save_plannow verified withcall_argsidentity check, not just call count.has_overridesguard sosave_plan()only fires when CLI overrides are actually applied.Minor fixes applied:
ExecutionEnvPriorityimport above conditional branches."fallback") inas_cli_dict(),_plan_spec_dict(), and_print_lifecycle_plan().ExecutionEnvPriorityenum test scenarios._plan_spec_dictdocstring.Deferred (documented, out of scope):
save_plan()— requires service-layer restructuring beyond #886.m4_003depends onm6_004) — renaming risks breaking migration chain; cosmetic only.Cycle 2 — Remaining Minor Items (Non-blocking)
Plan.effective_env_priorityproperty.except (ValueError, Exception).ExecutionEnvPriorityimport inuse_action()hoisted unconditionally — could be guarded.save_planassertion.update()path not independently tested for new fields._plan_spec_dict()/_print_lifecycle_plan()output paths.None of these affect functional correctness — they are code style and test quality refinements.
Quality Gates (All Passing)
nox -e lintnox -e typechecknox -e unit_testsnox -e integration_testsnox -e coverage_reportFull implementation notes posted to ticket #886.
200365acbd55c7bc73f1PM Status — Day 37 — Rebase Required
This PR has merge conflicts and cannot be merged in its current state. 42% of all open PRs (21 of 50) have conflicts — this is a project-wide issue that must be resolved.
@hurui200320 — Please rebase this PR onto
masterby Day 39 EOD (2026-03-19). If you cannot rebase by then, please post a comment explaining the blocker.PM rebase request — Day 37
Code Review — PR #972
fix(cli): add --execution-env-priority to plan useReviewer: @brent.edwards | Size: L (+795, 11 files) | Focus: Domain model, CLI, migration, persistence
No P0 or P1 findings.
This is a well-structured feature implementation:
ExecutionEnvPriorityasStrEnumwith Pydantic model validator is the correct patternupgrade()/downgrade()withbatch_alter_tablefor SQLitehas_overridesflag avoids unnecessary DB writes — good optimizationsave_plan()public API onPlanLifecycleServiceis cleanP2:should-fix (2)
1. Defensive
getattron fields that always exist —repositories.py:1365:getattr(plan, "execution_environment", None). SincePlanis a Pydantic BaseModel withdefault=None, the field always exists. Useplan.execution_environmentdirectly — thegetattrcreates a false impression of optional attributes.2. Late conditional import of
ExecutionEnvPriorityinside_plan_spec_dictrendering function — fragile, import failure surfaces only when displaying a plan with an execution environment. Move to module-level.P3:nit (1)
3. Migration naming jumps from
m6_004tom4_003which is confusing. PR description acknowledges this as deferred — acceptable.Verdict: APPROVED with P2 comments. Both are minor and can be fixed in follow-up.
55c7bc73f13d2fc8b383New commits pushed, approval review dismissed automatically according to repository settings
Review Response — Brent Edwards Review #2384
Addressed both P2 items from @brent.edwards's review. Branch rebased onto latest
masterand force-pushed as commit3d2fc8b3.P2 #1 — Defensive
getattron always-present fields — FIXEDReplaced
getattr(plan, "execution_environment", None)with directplan.execution_environmentaccess in:LifecyclePlanModel.from_domain()(cleveragents.infrastructure.database.models)LifecyclePlanRepository.update()(cleveragents.infrastructure.database.repositories)Same for
execution_env_priority: replacedgetattr(plan, "execution_env_priority", None) is not Nonewithplan.execution_env_priority is not None.Since
Planis a PydanticBaseModelwithdefault=Nonefor both fields, they always exist. Thegetattrcreated a false impression of optional attributes.Ripple fix: Four pre-existing
SimpleNamespace-based test fixtures that simulatePlanobjects neededexecution_environment=Noneandexecution_env_priority=Noneadded:_make_plan_object()indatabase_models_new_coverage_steps.pyplan_domain_statelessindatabase_models_lifecycle_coverage_steps.py_base_plan_ns()indatabase_models_coverage_r2_steps.py_make_fake_plan()inrepositories_error_handling_coverage_steps.pyP2 #2 — Late conditional import of
ExecutionEnvPriority— FIXEDHoisted
ExecutionEnvPriorityimport from inside conditionalif plan.execution_environment:blocks to function-entry deferred imports in:_plan_spec_dict()— added to existingfrom cleveragents.domain.models.core.plan import ...deferred import_print_lifecycle_plan()— added to existingfrom cleveragents.domain.models.core.plan import ...deferred importThe imports are now eagerly resolved when the function is called, rather than lazily when a plan happens to have an execution environment. Import failures will now surface immediately, not only on specific code paths.
P3 — Migration naming — DEFERRED (acknowledged)
Migration
m4_003now descends fromm6_005_profile_guards_json(updated post-rebase to fix the Alembic multiple-heads issue). The non-sequential naming (m4_003depending onm6_005) remains cosmetic and is documented in the PR description.Rebase
Branch rebased onto latest
master(20efab90). One merge conflict inCHANGELOG.mdwas resolved (both master's new entries and our entry preserved).Quality Gates (All Passing)
nox -e lintnox -e typechecknox -e unit_testsnox -e integration_testsnox -e coverage_report3d2fc8b383a1e6c63f5d