Files
cleveragents-core/features/plan_ulid_validation.feature
freemo 300a5d6ddc fix(cli): disallow mixing legacy and v3 plan workflows
Add ULID format validation to all v3 plan commands to prevent users from
accidentally mixing legacy ('agents tell') and v3 ('agents plan use')
workflows. The two systems use separate storage backends and cannot be
mixed; this change detects the mismatch early and provides actionable
error messages.

Changes:
- Add _validate_plan_ulid() with proper Crockford Base32 regex
  (^[0-9A-HJKMNP-TV-Z]{26}$, re.IGNORECASE) that correctly rejects
  invalid characters (I, L, O, U), hyphens, and wrong-length strings
- Add _PLAN_ULID_RE compiled regex and _ULID_VALIDATION_ERROR_MSG constant
  with actionable guidance explaining the legacy/v3 incompatibility
- Apply ULID validation to all v3 commands: execute_plan,
  _lifecycle_apply_with_id, lifecycle_apply_plan, plan_status,
  plan_errors, cancel_plan (only on user-provided IDs, not auto-discovered)
- Update _LEGACY_DEPRECATION_MSG and tell/build command warnings to
  explicitly state that the two workflows are INCOMPATIBLE and cannot be mixed
- Add comprehensive BDD tests in features/plan_ulid_validation.feature
  with step definitions using Typer CLI runner (not subprocess)
- Update CONTRIBUTING.md with 'Workflow Choice: Legacy vs. v3 Plan
  Lifecycle' section documenting the incompatibility and migration path

ISSUES CLOSED: #1560
2026-04-03 00:01:48 +00:00

142 lines
7.1 KiB
Gherkin

Feature: ULID validation for v3 plan commands
As a CleverAgents user
I want clear, actionable error messages when I accidentally mix legacy and v3 plan workflows
So that I understand the incompatibility and know how to fix it
# ===================================================================
# _validate_plan_ulid unit tests
# ===================================================================
Scenario: _validate_plan_ulid accepts a valid ULID
When I call _validate_plan_ulid with "01HXM8C2ZK4Q7C2B3F2R4VYV6J"
Then ulid-val the validation should succeed and return "01HXM8C2ZK4Q7C2B3F2R4VYV6J"
Scenario: _validate_plan_ulid accepts a valid ULID in lowercase
When I call _validate_plan_ulid with "01hxm8c2zk4q7c2b3f2r4vyv6j"
Then ulid-val the validation should succeed and return "01hxm8c2zk4q7c2b3f2r4vyv6j"
Scenario: _validate_plan_ulid rejects a legacy plan name
When I call _validate_plan_ulid with "64-bit port plan"
Then ulid-val the validation should raise ValidationError
And ulid-val the error message should contain "not found"
And ulid-val the error message should contain "ULID"
And ulid-val the error message should contain "legacy"
And ulid-val the error message should contain "agents plan use"
Scenario: _validate_plan_ulid rejects a plain string that is not a ULID
When I call _validate_plan_ulid with "not-a-ulid"
Then ulid-val the validation should raise ValidationError
And ulid-val the error message should contain "ULID"
Scenario: _validate_plan_ulid rejects a string that is too short
When I call _validate_plan_ulid with "01ARZ3NDEK"
Then ulid-val the validation should raise ValidationError
And ulid-val the error message should contain "ULID"
Scenario: _validate_plan_ulid rejects a string that is too long
When I call _validate_plan_ulid with "01ARZ3NDEKTSV4RRFFQ69G5FAAEXTRA"
Then ulid-val the validation should raise ValidationError
And ulid-val the error message should contain "ULID"
Scenario: _validate_plan_ulid rejects a ULID with invalid characters (I, L, O, U)
When I call _validate_plan_ulid with "01ARZ3NDEKTSV4RRFFQ69G5FII"
Then ulid-val the validation should raise ValidationError
And ulid-val the error message should contain "ULID"
# ===================================================================
# agents plan execute — ULID validation
# ===================================================================
Scenario: plan execute rejects a legacy plan name with actionable error
Given a ulid-validation CLI runner
When I invoke ulid-validation plan execute with "my-legacy-plan"
Then the ulid-validation command should abort
And the ulid-validation output should contain "not found"
And the ulid-validation output should contain "ULID"
And the ulid-validation output should contain "legacy"
And the ulid-validation output should contain "agents plan use"
Scenario: plan execute rejects a non-ULID string with actionable error
Given a ulid-validation CLI runner
When I invoke ulid-validation plan execute with "not-a-valid-id"
Then the ulid-validation command should abort
And the ulid-validation output should contain "ULID"
Scenario: plan execute accepts a valid ULID and proceeds normally
Given a ulid-validation CLI runner
And a mocked lifecycle service for ulid-validation execute
When I invoke ulid-validation plan execute with "01HXM8C2ZK4Q7C2B3F2R4VYV6J"
Then the ulid-validation command should not abort due to ULID validation
# ===================================================================
# agents plan apply — ULID validation
# ===================================================================
Scenario: plan apply rejects a legacy plan name with actionable error
Given a ulid-validation CLI runner
When I invoke ulid-validation plan apply with "my-legacy-plan"
Then the ulid-validation command should abort
And the ulid-validation output should contain "not found"
And the ulid-validation output should contain "ULID"
And the ulid-validation output should contain "legacy"
Scenario: plan apply rejects a non-ULID string with actionable error
Given a ulid-validation CLI runner
When I invoke ulid-validation plan apply with "not-a-valid-id"
Then the ulid-validation command should abort
And the ulid-validation output should contain "ULID"
# ===================================================================
# agents plan status — ULID validation
# ===================================================================
Scenario: plan status rejects a legacy plan name with actionable error
Given a ulid-validation CLI runner
And a mocked lifecycle service for ulid-validation status
When I invoke ulid-validation plan status with "my-legacy-plan"
Then the ulid-validation command should abort
And the ulid-validation output should contain "ULID"
And the ulid-validation output should contain "legacy"
Scenario: plan status rejects a non-ULID string with actionable error
Given a ulid-validation CLI runner
And a mocked lifecycle service for ulid-validation status
When I invoke ulid-validation plan status with "not-a-valid-id"
Then the ulid-validation command should abort
And the ulid-validation output should contain "ULID"
# ===================================================================
# agents plan errors — ULID validation
# ===================================================================
Scenario: plan errors rejects a legacy plan name with actionable error
Given a ulid-validation CLI runner
When I invoke ulid-validation plan errors with "my-legacy-plan"
Then the ulid-validation command should abort
And the ulid-validation output should contain "ULID"
# ===================================================================
# agents plan cancel — ULID validation
# ===================================================================
Scenario: plan cancel rejects a legacy plan name with actionable error
Given a ulid-validation CLI runner
When I invoke ulid-validation plan cancel with "my-legacy-plan"
Then the ulid-validation command should abort
And the ulid-validation output should contain "ULID"
# ===================================================================
# Legacy deprecation warning content
# ===================================================================
Scenario: Legacy tell command deprecation warning explains workflow incompatibility
When I call tell_command programmatically for ulid-validation
Then the ulid-validation deprecation warning should mention "incompatible"
And the ulid-validation deprecation warning should mention "agents plan use"
And the ulid-validation deprecation warning should not suggest simple command swap
Scenario: Legacy build command deprecation warning explains workflow incompatibility
When I call build_command programmatically for ulid-validation
Then the ulid-validation deprecation warning should mention "incompatible"
And the ulid-validation deprecation warning should mention "agents plan use"