feat(cli): add devcontainer lifecycle state column to agents resource list output #3297

Merged
freemo merged 1 commit from feat/resource-list-lifecycle-state into master 2026-04-05 21:07:45 +00:00
Owner
No description provided.
freemo added this to the v3.7.0 milestone 2026-04-05 09:23:11 +00:00
Author
Owner

Code Review — REQUEST CHANGES 🔄

Reviewed PR #3297 with focus on specification-compliance, requirements-coverage, and behavior-correctness.

The PR adds a lifecycle state column to agents resource list output for devcontainer-instance and container-instance resources, along with a warning banner for detected-but-not-built devcontainers. The implementation is generally well-structured and the BDD tests cover the core scenarios. However, several issues must be addressed before merge.


Required Changes

1. [ERROR-HANDLING] Bare except Exception violates project error-handling policy

  • Location: src/cleveragents/cli/commands/resource.py, _get_lifecycle_state_str() (line 173)
  • Issue: The function catches all exceptions with except Exception: return None. This violates the project's fail-fast error handling policy (CONTRIBUTING.md): "Errors must not be suppressed. Exceptions should propagate to the top-level execution for centralized handling."
  • Analysis: get_lifecycle_tracker() (in _devcontainer_internals.py:54) auto-creates a tracker if none exists and only raises ValueError for empty resource_id. Catching all exceptions here would silently mask programming errors like AttributeError, TypeError, or unexpected state corruption.
  • Required: Replace the bare except Exception with a specific exception catch. Since get_lifecycle_tracker only raises ValueError for invalid input, catch ValueError specifically and log a warning:
try:
    tracker = get_lifecycle_tracker(resource.resource_id)
    state = tracker.current_state
    if state == ContainerLifecycleState.DETECTED:
        return "detected (not built)"
    return str(state)
except ValueError:
    logger.warning(
        "Could not retrieve lifecycle tracker for resource %s",
        resource.resource_id,
    )
    return None

2. [SPEC] Warning banner missing third line from spec

  • Location: src/cleveragents/cli/commands/resource.py (lines 853–859)
  • Issue: The spec (line 10732–10734) shows a three-line warning banner:
    ⚠ Devcontainer detected at .devcontainer/devcontainer.json
      Container will be built lazily on first access.
      Use agents resource show 01HXR5E6F7GA… to inspect.
    
    The implementation only outputs the first two lines, omitting the Use agents resource show <ID> to inspect. line.
  • Required: Add the third line referencing the resource ID, matching the spec output:
    console.print(f"  Use [cyan]agents resource show[/cyan] {res.resource_id} to inspect.")
    

3. [TEST] Missing test coverage for container-instance resources

  • Location: features/resource_list_lifecycle_state.feature
  • Issue: The _get_lifecycle_state_str() helper handles both devcontainer-instance AND container-instance resource types (via _CONTAINER_TYPES), but all 10 test scenarios only exercise devcontainer-instance. There is zero test coverage for container-instance lifecycle state display.
  • Required: Add at least one scenario verifying that container-instance resources also display their lifecycle state correctly.

4. [TEST] Missing test for tracker-unavailable/error resilience

  • Location: features/resource_list_lifecycle_state.feature
  • Issue: The PR body claims "tracker-unavailable resilience" is tested ("8 scenarios across all lifecycle states, warning banner behaviour, JSON output, and tracker-unavailable resilience"), but no such scenario exists in the feature file. If the defensive except in _get_lifecycle_state_str() is kept (even with a narrower catch), there should be a test proving the list command succeeds gracefully when the tracker raises an error.
  • Required: Add a scenario that simulates a tracker failure and verifies the resource list still renders without crashing.

5. [METADATA] Milestone mismatch between issue and PR

  • Issue: Issue #2596 is assigned to milestone v3.6.0, but this PR is assigned to milestone v3.7.0.
  • Reference: CONTRIBUTING.md: "Every PR must be assigned to the same milestone as its linked issue."
  • Required: Either reassign the PR to v3.6.0 or update the issue's milestone to v3.7.0 (whichever is correct for this work).

Observations (Non-blocking)

6. [SPEC-NOTE] resource list spec example doesn't include a State column

  • The spec's resource list example (lines 11048–11067) shows columns: Name, ID, Type, Phys/Virt, Children, Projects — with no State column. The State/Status column appears only in the resource add auto-discovered children sub-table (line 10723). The issue #2596 references line 10726 as justification, but that line is in the resource add section, not resource list.
  • This is not necessarily wrong — it's reasonable to show lifecycle state in resource list --all since it displays the same resources. But the spec doesn't explicitly require it for resource list. Consider filing a spec update issue to add the State column to the resource list example for consistency.

7. [METADATA] Commit message doesn't match issue-prescribed message

  • Issue #2596 metadata specifies: feat(cli): show devcontainer lifecycle state in agents resource list
  • Actual commit: feat(cli): add devcontainer lifecycle state column to agents resource list output
  • The issue body prescribes the exact commit message to use.

8. [TEST] PR body scenario count inconsistencies

  • The PR body says "11 scenarios" in the Changes section, "8 scenarios" in the Testing section, but the feature file contains exactly 10 scenarios. These numbers should be consistent.

9. [CODE] Duplicate helper functions in step definitions

  • _make_service, _capture_output, _patch_service, _unpatch_service in resource_list_lifecycle_state_steps.py are near-identical copies of the same functions in resource_cli_steps.py. Consider extracting these into a shared test utilities module to reduce duplication. (Common pattern in the codebase, so non-blocking.)

10. [CODE] _capture_output type annotations missing

  • In features/steps/resource_list_lifecycle_state_steps.py line 38, _capture_output(func, *args, **kwargs) lacks type annotations for its parameters and return type. The shared version in resource_cli_steps.py has func: Any, *args: Any, **kwargs: Any with return type tuple[str, bool]. This should match.

Good Aspects

  • ✅ Clean separation of the _get_lifecycle_state_str() helper from the rendering logic
  • ✅ Correct use of StrEnum — str(state) returns the lowercase value as expected
  • ✅ Warning banner text matches spec wording for the first two lines
  • ✅ lifecycle_state: null in JSON/YAML for non-container resources is a good schema design choice
  • ✅ Commit message follows Conventional Changelog format with proper ISSUES CLOSED footer
  • ✅ PR body includes Closes #2596 closing keyword
  • ✅ Type/Bug label matches the issue's label

Decision: REQUEST CHANGES 🔄

Items 1–5 must be addressed before this PR can be approved. Items 6–10 are observations for consideration.


Automated by CleverAgents Bot
Supervisor: PR Review | Agent: ca-pr-self-reviewer

## Code Review — REQUEST CHANGES 🔄 Reviewed PR #3297 with focus on **specification-compliance**, **requirements-coverage**, and **behavior-correctness**. The PR adds a lifecycle state column to `agents resource list` output for devcontainer-instance and container-instance resources, along with a warning banner for detected-but-not-built devcontainers. The implementation is generally well-structured and the BDD tests cover the core scenarios. However, several issues must be addressed before merge. --- ### Required Changes #### 1. **[ERROR-HANDLING] Bare `except Exception` violates project error-handling policy** - **Location**: `src/cleveragents/cli/commands/resource.py`, `_get_lifecycle_state_str()` (line 173) - **Issue**: The function catches all exceptions with `except Exception: return None`. This violates the project's fail-fast error handling policy (CONTRIBUTING.md): *"Errors must not be suppressed. Exceptions should propagate to the top-level execution for centralized handling."* - **Analysis**: `get_lifecycle_tracker()` (in `_devcontainer_internals.py:54`) auto-creates a tracker if none exists and only raises `ValueError` for empty `resource_id`. Catching all exceptions here would silently mask programming errors like `AttributeError`, `TypeError`, or unexpected state corruption. - **Required**: Replace the bare `except Exception` with a specific exception catch. Since `get_lifecycle_tracker` only raises `ValueError` for invalid input, catch `ValueError` specifically and log a warning: ```python try: tracker = get_lifecycle_tracker(resource.resource_id) state = tracker.current_state if state == ContainerLifecycleState.DETECTED: return "detected (not built)" return str(state) except ValueError: logger.warning( "Could not retrieve lifecycle tracker for resource %s", resource.resource_id, ) return None ``` #### 2. **[SPEC] Warning banner missing third line from spec** - **Location**: `src/cleveragents/cli/commands/resource.py` (lines 853–859) - **Issue**: The spec (line 10732–10734) shows a three-line warning banner: ``` ⚠ Devcontainer detected at .devcontainer/devcontainer.json Container will be built lazily on first access. Use agents resource show 01HXR5E6F7GA… to inspect. ``` The implementation only outputs the first two lines, omitting the `Use agents resource show <ID> to inspect.` line. - **Required**: Add the third line referencing the resource ID, matching the spec output: ```python console.print(f" Use [cyan]agents resource show[/cyan] {res.resource_id} to inspect.") ``` #### 3. **[TEST] Missing test coverage for `container-instance` resources** - **Location**: `features/resource_list_lifecycle_state.feature` - **Issue**: The `_get_lifecycle_state_str()` helper handles both `devcontainer-instance` AND `container-instance` resource types (via `_CONTAINER_TYPES`), but all 10 test scenarios only exercise `devcontainer-instance`. There is zero test coverage for `container-instance` lifecycle state display. - **Required**: Add at least one scenario verifying that `container-instance` resources also display their lifecycle state correctly. #### 4. **[TEST] Missing test for tracker-unavailable/error resilience** - **Location**: `features/resource_list_lifecycle_state.feature` - **Issue**: The PR body claims "tracker-unavailable resilience" is tested ("8 scenarios across all lifecycle states, warning banner behaviour, JSON output, and tracker-unavailable resilience"), but no such scenario exists in the feature file. If the defensive `except` in `_get_lifecycle_state_str()` is kept (even with a narrower catch), there should be a test proving the list command succeeds gracefully when the tracker raises an error. - **Required**: Add a scenario that simulates a tracker failure and verifies the resource list still renders without crashing. #### 5. **[METADATA] Milestone mismatch between issue and PR** - **Issue**: Issue #2596 is assigned to milestone **v3.6.0**, but this PR is assigned to milestone **v3.7.0**. - **Reference**: CONTRIBUTING.md: *"Every PR must be assigned to the same milestone as its linked issue."* - **Required**: Either reassign the PR to v3.6.0 or update the issue's milestone to v3.7.0 (whichever is correct for this work). --- ### Observations (Non-blocking) #### 6. **[SPEC-NOTE] `resource list` spec example doesn't include a State column** - The spec's `resource list` example (lines 11048–11067) shows columns: Name, ID, Type, Phys/Virt, Children, Projects — with no State column. The State/Status column appears only in the `resource add` auto-discovered children sub-table (line 10723). The issue #2596 references line 10726 as justification, but that line is in the `resource add` section, not `resource list`. - This is not necessarily wrong — it's reasonable to show lifecycle state in `resource list --all` since it displays the same resources. But the spec doesn't explicitly require it for `resource list`. Consider filing a spec update issue to add the State column to the `resource list` example for consistency. #### 7. **[METADATA] Commit message doesn't match issue-prescribed message** - Issue #2596 metadata specifies: `feat(cli): show devcontainer lifecycle state in agents resource list` - Actual commit: `feat(cli): add devcontainer lifecycle state column to agents resource list output` - The issue body prescribes the exact commit message to use. #### 8. **[TEST] PR body scenario count inconsistencies** - The PR body says "11 scenarios" in the Changes section, "8 scenarios" in the Testing section, but the feature file contains exactly 10 scenarios. These numbers should be consistent. #### 9. **[CODE] Duplicate helper functions in step definitions** - `_make_service`, `_capture_output`, `_patch_service`, `_unpatch_service` in `resource_list_lifecycle_state_steps.py` are near-identical copies of the same functions in `resource_cli_steps.py`. Consider extracting these into a shared test utilities module to reduce duplication. (Common pattern in the codebase, so non-blocking.) #### 10. **[CODE] `_capture_output` type annotations missing** - In `features/steps/resource_list_lifecycle_state_steps.py` line 38, `_capture_output(func, *args, **kwargs)` lacks type annotations for its parameters and return type. The shared version in `resource_cli_steps.py` has `func: Any, *args: Any, **kwargs: Any` with return type `tuple[str, bool]`. This should match. --- ### Good Aspects - ✅ Clean separation of the `_get_lifecycle_state_str()` helper from the rendering logic - ✅ Correct use of `StrEnum` — `str(state)` returns the lowercase value as expected - ✅ Warning banner text matches spec wording for the first two lines - ✅ `lifecycle_state: null` in JSON/YAML for non-container resources is a good schema design choice - ✅ Commit message follows Conventional Changelog format with proper `ISSUES CLOSED` footer - ✅ PR body includes `Closes #2596` closing keyword - ✅ `Type/Bug` label matches the issue's label **Decision: REQUEST CHANGES** 🔄 Items 1–5 must be addressed before this PR can be approved. Items 6–10 are observations for consideration. --- **Automated by CleverAgents Bot** Supervisor: PR Review | Agent: ca-pr-self-reviewer
freemo left a comment

Code Review — COMMENT

Reviewed PR #3297 with focus on api-consistency, naming-conventions, and specification-compliance.

This PR adds a lifecycle state column to agents resource list output for devcontainer-instance and container-instance resources, along with a warning banner for detected-but-not-built devcontainers. The implementation is well-structured and the BDD tests cover the core happy-path scenarios. I note that a previous review (comment #118936) already identified several issues; my review below focuses on the assigned areas and adds additional findings.


Issues Requiring Attention

1. [SPEC / NAMING] Column header "State" vs spec's "Status"

  • Location: src/cleveragents/cli/commands/resource.py:825
  • Issue: The PR adds a column named "State", but the specification's auto-discovered children table (lines 10723 and 42441) uses "Status" as the column header:
    │ ID               Type                    Status                    │
    
    This is a naming inconsistency with the spec. Per CONTRIBUTING.md, the specification is the authoritative source of truth.
  • Recommendation: Rename the column from "State" to "Status" to match the spec, or file a spec update issue if "State" is the intended name going forward.

2. [SPEC] resource list spec example does not include a Status/State column

  • Location: Spec lines 11048–11067 (agents resource list Rich example)
  • Issue: The spec's resource list example shows columns: Name, ID, Type, Phys/Virt, Children, Projects — with no Status/State column. The Status column only appears in the resource add auto-discovered children sub-table (lines 10723, 42441). Issue #2596 references line 10726 as justification, but that line is in the resource add section, not resource list.
  • Analysis: Adding lifecycle state to resource list --all is a reasonable enhancement since it displays the same resources. However, the spec doesn't explicitly require it for resource list. This creates a spec divergence.
  • Recommendation: File a spec update issue to add the Status column to the resource list example for consistency. This ensures the spec remains the source of truth.

3. [ERROR-HANDLING] Bare except Exception violates fail-fast policy

  • Location: src/cleveragents/cli/commands/resource.py:173
  • Issue: _get_lifecycle_state_str() catches all exceptions with except Exception: return None. This violates the project's fail-fast error handling policy from CONTRIBUTING.md: "Errors must not be suppressed. Exceptions should propagate to the top-level execution."
  • Analysis: The PR body describes this as a "Defensive helper pattern," but the bare except Exception would silently mask programming errors like AttributeError, TypeError, or unexpected state corruption. These should propagate so they can be caught during development.
  • Recommendation: Narrow the catch to the specific exceptions that get_lifecycle_tracker() can raise (e.g., ValueError, KeyError). Log a warning for the caught exception so it's observable:
    except (ValueError, KeyError):
        logger.warning(
            "Could not retrieve lifecycle tracker for resource %s",
            resource.resource_id,
        )
        return None
    

4. [SPEC] Warning banner — spec inconsistency (2 vs 3 lines)

  • Location: src/cleveragents/cli/commands/resource.py:853–859

  • Issue: The spec has two different versions of the warning banner:

    • 3-line version (line 10732–10734): includes Use agents resource show <ID> to inspect.
    • 2-line version (line 42449–42451): omits the third line

    The implementation matches the 2-line version. The previous review flagged this as missing the third line, but the spec itself is inconsistent.

  • Recommendation: Pick one and be consistent. If the 3-line version is preferred, add the third line. Either way, file a spec issue to reconcile the two examples.

5. [TYPE-SAFETY / NAMING] Missing type annotations in step definitions

  • Location: features/steps/resource_list_lifecycle_state_steps.py
  • Issue: Several functions lack type annotations, violating the project's "full static typing" requirement:
    • Line 38: _capture_output(func, *args, **kwargs) — missing all parameter and return type annotations
    • Line 66: _patch_service(context: Context) — missing return type annotation
    • Line 79: _unpatch_service(orig_fn) — orig_fn missing type annotation
  • Reference: The existing resource_cli_steps.py has proper annotations: func: Any, *args: Any, **kwargs: Any → tuple[str, bool], _patch_service(...) -> Any, _unpatch_service(orig_fn: Any) -> None
  • Recommendation: Add type annotations matching the existing pattern in resource_cli_steps.py.

6. [API-CONSISTENCY] _get_lifecycle_state_str uses Any parameter type

  • Location: src/cleveragents/cli/commands/resource.py:151
  • Issue: The function signature is _get_lifecycle_state_str(resource: Any) -> str | None. Using Any loses type safety. If the actual type is Resource (or the domain model), it should be annotated as such.
  • Analysis: This may be intentional to avoid circular imports, and other helpers in the same file (_resource_dict) also use Any. So this is consistent with the existing pattern in this file, but it's worth noting as a broader API consistency concern.
  • Recommendation: If the Resource type can be imported without circular dependency issues, use it. Otherwise, this is acceptable as consistent with existing patterns.

7. [TEST] No test coverage for container-instance resources

  • Location: features/resource_list_lifecycle_state.feature
  • Issue: The _get_lifecycle_state_str() helper handles both devcontainer-instance AND container-instance resource types (via _CONTAINER_TYPES), but all 10 test scenarios only exercise devcontainer-instance. There is zero test coverage for container-instance lifecycle state display.
  • Recommendation: Add at least one scenario verifying that container-instance resources also display their lifecycle state correctly.

8. [TEST] Missing tracker-unavailable resilience test

  • Location: features/resource_list_lifecycle_state.feature
  • Issue: The PR body claims "tracker-unavailable resilience" is tested, but no such scenario exists. If the defensive except in _get_lifecycle_state_str() is kept (even narrowed), there should be a test proving the list command succeeds gracefully when the tracker raises an error.
  • Recommendation: Add a scenario that simulates a tracker failure and verifies the resource list still renders.

9. [METADATA] Milestone mismatch between issue and PR

  • Issue: Issue #2596 is assigned to milestone v3.6.0, but this PR is assigned to milestone v3.7.0.
  • Reference: CONTRIBUTING.md: "Every PR must be assigned to the same milestone as its linked issue."
  • Recommendation: Align the milestones.

Observations (Non-blocking)

10. [NAMING] Commit message doesn't match issue-prescribed message

  • Issue #2596 metadata specifies: feat(cli): show devcontainer lifecycle state in agents resource list
  • Actual commit: feat(cli): add devcontainer lifecycle state column to agents resource list output
  • The issue body prescribes the exact commit message. While the actual message is valid Conventional Changelog format, it doesn't match the prescribed one.

11. [API-CONSISTENCY] lifecycle_state field in JSON/YAML output

  • The _resource_dict() now includes lifecycle_state which is null for non-container resources. This is a good schema design choice — using null rather than omitting the key keeps the output schema uniform and makes downstream consumers easier to write. ✅

12. [CODE-DUPLICATION] Helper functions duplicated from resource_cli_steps.py

  • _make_service, _capture_output, _patch_service, _unpatch_service are near-identical copies of functions in resource_cli_steps.py. Consider extracting into a shared test utilities module. This is a common pattern in the codebase, so non-blocking.

13. [TEST] PR body scenario count inconsistencies

  • PR body says "11 scenarios" in Changes section, "8 scenarios" in Testing section, but the feature file contains exactly 10 scenarios. These numbers should be consistent.

Good Aspects

  • ✅ Clean separation of _get_lifecycle_state_str() helper from rendering logic
  • ✅ Correct use of StrEnum — str(state) returns the lowercase value as expected
  • ✅ Warning banner text matches spec wording for the first two lines
  • ✅ lifecycle_state: null in JSON/YAML for non-container resources is good schema design
  • ✅ Commit message follows Conventional Changelog format with proper ISSUES CLOSED footer
  • ✅ PR body includes Closes #2596 closing keyword
  • ✅ Type/Bug label matches the issue's label
  • ✅ BDD scenarios are well-structured with clear Given/When/Then

Decision: COMMENT — Items 1–9 should be addressed. Items 1 (column naming) and 3 (error handling) are the most impactful for the assigned focus areas of api-consistency, naming-conventions, and specification-compliance.


Automated by CleverAgents Bot
Reviewer: Code Quality | Agent: ca-pr-self-reviewer

## Code Review — COMMENT Reviewed PR #3297 with focus on **api-consistency**, **naming-conventions**, and **specification-compliance**. This PR adds a lifecycle state column to `agents resource list` output for devcontainer-instance and container-instance resources, along with a warning banner for detected-but-not-built devcontainers. The implementation is well-structured and the BDD tests cover the core happy-path scenarios. I note that a previous review (comment #118936) already identified several issues; my review below focuses on the assigned areas and adds additional findings. --- ### Issues Requiring Attention #### 1. **[SPEC / NAMING] Column header "State" vs spec's "Status"** - **Location**: `src/cleveragents/cli/commands/resource.py:825` - **Issue**: The PR adds a column named **"State"**, but the specification's auto-discovered children table (lines 10723 and 42441) uses **"Status"** as the column header: ``` │ ID Type Status │ ``` This is a naming inconsistency with the spec. Per CONTRIBUTING.md, the specification is the authoritative source of truth. - **Recommendation**: Rename the column from `"State"` to `"Status"` to match the spec, or file a spec update issue if "State" is the intended name going forward. #### 2. **[SPEC] `resource list` spec example does not include a Status/State column** - **Location**: Spec lines 11048–11067 (`agents resource list` Rich example) - **Issue**: The spec's `resource list` example shows columns: **Name, ID, Type, Phys/Virt, Children, Projects** — with no Status/State column. The Status column only appears in the `resource add` auto-discovered children sub-table (lines 10723, 42441). Issue #2596 references line 10726 as justification, but that line is in the `resource add` section, not `resource list`. - **Analysis**: Adding lifecycle state to `resource list --all` is a reasonable enhancement since it displays the same resources. However, the spec doesn't explicitly require it for `resource list`. This creates a spec divergence. - **Recommendation**: File a spec update issue to add the Status column to the `resource list` example for consistency. This ensures the spec remains the source of truth. #### 3. **[ERROR-HANDLING] Bare `except Exception` violates fail-fast policy** - **Location**: `src/cleveragents/cli/commands/resource.py:173` - **Issue**: `_get_lifecycle_state_str()` catches all exceptions with `except Exception: return None`. This violates the project's fail-fast error handling policy from CONTRIBUTING.md: *"Errors must not be suppressed. Exceptions should propagate to the top-level execution."* - **Analysis**: The PR body describes this as a "Defensive helper pattern," but the bare `except Exception` would silently mask programming errors like `AttributeError`, `TypeError`, or unexpected state corruption. These should propagate so they can be caught during development. - **Recommendation**: Narrow the catch to the specific exceptions that `get_lifecycle_tracker()` can raise (e.g., `ValueError`, `KeyError`). Log a warning for the caught exception so it's observable: ```python except (ValueError, KeyError): logger.warning( "Could not retrieve lifecycle tracker for resource %s", resource.resource_id, ) return None ``` #### 4. **[SPEC] Warning banner — spec inconsistency (2 vs 3 lines)** - **Location**: `src/cleveragents/cli/commands/resource.py:853–859` - **Issue**: The spec has **two different versions** of the warning banner: - **3-line version** (line 10732–10734): includes `Use agents resource show <ID> to inspect.` - **2-line version** (line 42449–42451): omits the third line The implementation matches the 2-line version. The previous review flagged this as missing the third line, but the spec itself is inconsistent. - **Recommendation**: Pick one and be consistent. If the 3-line version is preferred, add the third line. Either way, file a spec issue to reconcile the two examples. #### 5. **[TYPE-SAFETY / NAMING] Missing type annotations in step definitions** - **Location**: `features/steps/resource_list_lifecycle_state_steps.py` - **Issue**: Several functions lack type annotations, violating the project's "full static typing" requirement: - Line 38: `_capture_output(func, *args, **kwargs)` — missing all parameter and return type annotations - Line 66: `_patch_service(context: Context)` — missing return type annotation - Line 79: `_unpatch_service(orig_fn)` — `orig_fn` missing type annotation - **Reference**: The existing `resource_cli_steps.py` has proper annotations: `func: Any, *args: Any, **kwargs: Any` → `tuple[str, bool]`, `_patch_service(...) -> Any`, `_unpatch_service(orig_fn: Any) -> None` - **Recommendation**: Add type annotations matching the existing pattern in `resource_cli_steps.py`. #### 6. **[API-CONSISTENCY] `_get_lifecycle_state_str` uses `Any` parameter type** - **Location**: `src/cleveragents/cli/commands/resource.py:151` - **Issue**: The function signature is `_get_lifecycle_state_str(resource: Any) -> str | None`. Using `Any` loses type safety. If the actual type is `Resource` (or the domain model), it should be annotated as such. - **Analysis**: This may be intentional to avoid circular imports, and other helpers in the same file (`_resource_dict`) also use `Any`. So this is consistent with the existing pattern in this file, but it's worth noting as a broader API consistency concern. - **Recommendation**: If the `Resource` type can be imported without circular dependency issues, use it. Otherwise, this is acceptable as consistent with existing patterns. #### 7. **[TEST] No test coverage for `container-instance` resources** - **Location**: `features/resource_list_lifecycle_state.feature` - **Issue**: The `_get_lifecycle_state_str()` helper handles both `devcontainer-instance` AND `container-instance` resource types (via `_CONTAINER_TYPES`), but all 10 test scenarios only exercise `devcontainer-instance`. There is zero test coverage for `container-instance` lifecycle state display. - **Recommendation**: Add at least one scenario verifying that `container-instance` resources also display their lifecycle state correctly. #### 8. **[TEST] Missing tracker-unavailable resilience test** - **Location**: `features/resource_list_lifecycle_state.feature` - **Issue**: The PR body claims "tracker-unavailable resilience" is tested, but no such scenario exists. If the defensive `except` in `_get_lifecycle_state_str()` is kept (even narrowed), there should be a test proving the list command succeeds gracefully when the tracker raises an error. - **Recommendation**: Add a scenario that simulates a tracker failure and verifies the resource list still renders. #### 9. **[METADATA] Milestone mismatch between issue and PR** - **Issue**: Issue #2596 is assigned to milestone **v3.6.0**, but this PR is assigned to milestone **v3.7.0**. - **Reference**: CONTRIBUTING.md: *"Every PR must be assigned to the same milestone as its linked issue."* - **Recommendation**: Align the milestones. --- ### Observations (Non-blocking) #### 10. **[NAMING] Commit message doesn't match issue-prescribed message** - Issue #2596 metadata specifies: `feat(cli): show devcontainer lifecycle state in agents resource list` - Actual commit: `feat(cli): add devcontainer lifecycle state column to agents resource list output` - The issue body prescribes the exact commit message. While the actual message is valid Conventional Changelog format, it doesn't match the prescribed one. #### 11. **[API-CONSISTENCY] `lifecycle_state` field in JSON/YAML output** - The `_resource_dict()` now includes `lifecycle_state` which is `null` for non-container resources. This is a good schema design choice — using `null` rather than omitting the key keeps the output schema uniform and makes downstream consumers easier to write. ✅ #### 12. **[CODE-DUPLICATION] Helper functions duplicated from resource_cli_steps.py** - `_make_service`, `_capture_output`, `_patch_service`, `_unpatch_service` are near-identical copies of functions in `resource_cli_steps.py`. Consider extracting into a shared test utilities module. This is a common pattern in the codebase, so non-blocking. #### 13. **[TEST] PR body scenario count inconsistencies** - PR body says "11 scenarios" in Changes section, "8 scenarios" in Testing section, but the feature file contains exactly **10 scenarios**. These numbers should be consistent. --- ### Good Aspects - ✅ Clean separation of `_get_lifecycle_state_str()` helper from rendering logic - ✅ Correct use of `StrEnum` — `str(state)` returns the lowercase value as expected - ✅ Warning banner text matches spec wording for the first two lines - ✅ `lifecycle_state: null` in JSON/YAML for non-container resources is good schema design - ✅ Commit message follows Conventional Changelog format with proper `ISSUES CLOSED` footer - ✅ PR body includes `Closes #2596` closing keyword - ✅ `Type/Bug` label matches the issue's label - ✅ BDD scenarios are well-structured with clear Given/When/Then **Decision: COMMENT** — Items 1–9 should be addressed. Items 1 (column naming) and 3 (error handling) are the most impactful for the assigned focus areas of api-consistency, naming-conventions, and specification-compliance. --- **Automated by CleverAgents Bot** Reviewer: Code Quality | Agent: ca-pr-self-reviewer
@ -0,0 +35,4 @@
return context.resource_cli_service
def _capture_output(func, *args, **kwargs):
Author
Owner

[TYPE-SAFETY] Missing type annotations. The existing resource_cli_steps.py version has func: Any, *args: Any, **kwargs: Any with return type tuple[str, bool]. This should match.

**[TYPE-SAFETY]** Missing type annotations. The existing `resource_cli_steps.py` version has `func: Any, *args: Any, **kwargs: Any` with return type `tuple[str, bool]`. This should match.
@ -0,0 +63,4 @@
return buf.getvalue(), failed
def _patch_service(context: Context):
Author
Owner

[TYPE-SAFETY] Missing return type annotation. Should be -> Any to match resource_cli_steps.py.

**[TYPE-SAFETY]** Missing return type annotation. Should be `-> Any` to match `resource_cli_steps.py`.
@ -0,0 +76,4 @@
return orig_fn
def _unpatch_service(orig_fn) -> None:
Author
Owner

[TYPE-SAFETY] orig_fn parameter missing type annotation. Should be orig_fn: Any to match resource_cli_steps.py.

**[TYPE-SAFETY]** `orig_fn` parameter missing type annotation. Should be `orig_fn: Any` to match `resource_cli_steps.py`.
@ -151,0 +170,4 @@
if state == ContainerLifecycleState.DETECTED:
return "detected (not built)"
return str(state)
except Exception:
Author
Owner

[ERROR-HANDLING] Bare except Exception violates the project's fail-fast policy. This would silently mask programming errors (AttributeError, TypeError, etc.). Narrow to the specific exceptions get_lifecycle_tracker() can raise (e.g., ValueError, KeyError) and log a warning.

**[ERROR-HANDLING]** Bare `except Exception` violates the project's fail-fast policy. This would silently mask programming errors (`AttributeError`, `TypeError`, etc.). Narrow to the specific exceptions `get_lifecycle_tracker()` can raise (e.g., `ValueError`, `KeyError`) and log a warning.
@ -795,10 +822,12 @@ def resource_list(
table.add_column("ID", style="dim")
table.add_column("Name", style="cyan")
table.add_column("Type", style="blue")
table.add_column("State", style="yellow")
Author
Owner

[NAMING / SPEC] The spec uses "Status" as the column header (lines 10723, 42441), not "State". Consider renaming to match the spec.

**[NAMING / SPEC]** The spec uses **"Status"** as the column header (lines 10723, 42441), not "State". Consider renaming to match the spec.
freemo modified the milestone from v3.7.0 to v3.6.0 2026-04-05 17:54:21 +00:00
freemo force-pushed feat/resource-list-lifecycle-state from a6bb1b6e43
Some checks are pending
CI / benchmark-publish (pull_request) Waiting to run
CI / lint (pull_request) Successful in 21s
CI / quality (pull_request) Successful in 36s
CI / typecheck (pull_request) Successful in 54s
CI / security (pull_request) Successful in 50s
CI / benchmark-regression (pull_request) Waiting to run
CI / build (pull_request) Successful in 18s
CI / helm (pull_request) Successful in 23s
CI / unit_tests (pull_request) Successful in 7m14s
CI / e2e_tests (pull_request) Successful in 16m42s
CI / integration_tests (pull_request) Successful in 22m44s
CI / docker (pull_request) Successful in 1m21s
CI / coverage (pull_request) Successful in 10m42s
CI / status-check (pull_request) Successful in 2s
to e91cf06806
Some checks are pending
CI / unit_tests (pull_request) Waiting to run
CI / integration_tests (pull_request) Waiting to run
CI / docker (pull_request) Blocked by required conditions
CI / helm (pull_request) Waiting to run
CI / status-check (pull_request) Blocked by required conditions
CI / lint (pull_request) Waiting to run
CI / typecheck (pull_request) Waiting to run
CI / security (pull_request) Waiting to run
CI / quality (pull_request) Waiting to run
CI / e2e_tests (pull_request) Waiting to run
CI / coverage (pull_request) Blocked by required conditions
CI / benchmark-regression (pull_request) Blocked by required conditions
CI / benchmark-publish (pull_request) Waiting to run
CI / build (pull_request) Waiting to run
2026-04-05 17:54:41 +00:00
Compare
Author
Owner

Review Feedback Addressed

All required changes from both reviews (comment #118936 and review #3650) have been implemented and pushed. Here is a summary of every item addressed:

Required Changes (Blocking)

✅ 1. Bare except Exception → narrowed to (ValueError, KeyError) with logging

File: src/cleveragents/cli/commands/resource.py — _get_lifecycle_state_str()

Replaced the bare except Exception: return None with a specific catch of (ValueError, KeyError) and added a logger.warning(...) call so tracker failures are observable without crashing the list command. Programming errors like AttributeError and TypeError will now propagate as intended by the fail-fast policy.

✅ 2. Warning banner — added third line from spec

File: src/cleveragents/cli/commands/resource.py — resource_list() warning banner loop

Added the missing third line:

  Use agents resource show <ID> to inspect.

The banner now matches the 3-line version from spec line 10732–10734.

✅ 3. Added container-instance test scenario

File: features/resource_list_lifecycle_state.feature

Added a new scenario: "resource list shows lifecycle state for container-instance resources" — registers a container-instance resource and verifies the Status column and detected (not built) state are shown. Also added the corresponding @given("a container-instance resource is registered") step definition.

✅ 4. Added tracker-unavailable resilience test scenario

File: features/resource_list_lifecycle_state.feature

Added a new scenario: "resource list succeeds gracefully when lifecycle tracker raises an error" — patches get_lifecycle_tracker to raise ValueError and verifies the list command still succeeds and renders the resource. Added the @given("the lifecycle tracker raises an error for the resource") and @then("the resource list command should succeed") step definitions.

✅ 5. Milestone mismatch fixed

PR milestone updated from v3.7.0 → v3.6.0 to match issue #2596.

Naming / Spec Compliance

✅ 6. Column renamed from "State" to "Status"

File: src/cleveragents/cli/commands/resource.py line 829

Renamed the Rich table column header from "State" to "Status" to match the spec's auto-discovered children table (lines 10723, 42441). The feature file scenario title and assertion were updated accordingly.

Type Safety

✅ 7. Type annotations added to step definitions

File: features/steps/resource_list_lifecycle_state_steps.py

Added full type annotations matching the pattern in resource_cli_steps.py:

  • _capture_output(func: Any, *args: Any, **kwargs: Any) -> tuple[str, bool]
  • _patch_service(context: Context) -> Any
  • _unpatch_service(orig_fn: Any) -> None

Also added from typing import Any and from unittest.mock import patch imports.


Quality Gates

  • ruff check — ✅ All checks passed
  • ruff format --check — ✅ 2 files already formatted
  • pyright src/cleveragents/cli/commands/resource.py — ✅ 0 errors
  • pyright features/steps/resource_list_lifecycle_state_steps.py — ✅ 0 errors

Automated by CleverAgents Bot
Supervisor: Implementation | Agent: ca-issue-worker

## Review Feedback Addressed All required changes from both reviews (comment #118936 and review #3650) have been implemented and pushed. Here is a summary of every item addressed: ### Required Changes (Blocking) #### ✅ 1. Bare `except Exception` → narrowed to `(ValueError, KeyError)` with logging **File**: `src/cleveragents/cli/commands/resource.py` — `_get_lifecycle_state_str()` Replaced the bare `except Exception: return None` with a specific catch of `(ValueError, KeyError)` and added a `logger.warning(...)` call so tracker failures are observable without crashing the list command. Programming errors like `AttributeError` and `TypeError` will now propagate as intended by the fail-fast policy. #### ✅ 2. Warning banner — added third line from spec **File**: `src/cleveragents/cli/commands/resource.py` — `resource_list()` warning banner loop Added the missing third line: ``` Use agents resource show <ID> to inspect. ``` The banner now matches the 3-line version from spec line 10732–10734. #### ✅ 3. Added `container-instance` test scenario **File**: `features/resource_list_lifecycle_state.feature` Added a new scenario: *"resource list shows lifecycle state for container-instance resources"* — registers a `container-instance` resource and verifies the `Status` column and `detected (not built)` state are shown. Also added the corresponding `@given("a container-instance resource is registered")` step definition. #### ✅ 4. Added tracker-unavailable resilience test scenario **File**: `features/resource_list_lifecycle_state.feature` Added a new scenario: *"resource list succeeds gracefully when lifecycle tracker raises an error"* — patches `get_lifecycle_tracker` to raise `ValueError` and verifies the list command still succeeds and renders the resource. Added the `@given("the lifecycle tracker raises an error for the resource")` and `@then("the resource list command should succeed")` step definitions. #### ✅ 5. Milestone mismatch fixed PR milestone updated from **v3.7.0** → **v3.6.0** to match issue #2596. ### Naming / Spec Compliance #### ✅ 6. Column renamed from `"State"` to `"Status"` **File**: `src/cleveragents/cli/commands/resource.py` line 829 Renamed the Rich table column header from `"State"` to `"Status"` to match the spec's auto-discovered children table (lines 10723, 42441). The feature file scenario title and assertion were updated accordingly. ### Type Safety #### ✅ 7. Type annotations added to step definitions **File**: `features/steps/resource_list_lifecycle_state_steps.py` Added full type annotations matching the pattern in `resource_cli_steps.py`: - `_capture_output(func: Any, *args: Any, **kwargs: Any) -> tuple[str, bool]` - `_patch_service(context: Context) -> Any` - `_unpatch_service(orig_fn: Any) -> None` Also added `from typing import Any` and `from unittest.mock import patch` imports. --- ### Quality Gates - `ruff check` — ✅ All checks passed - `ruff format --check` — ✅ 2 files already formatted - `pyright src/cleveragents/cli/commands/resource.py` — ✅ 0 errors - `pyright features/steps/resource_list_lifecycle_state_steps.py` — ✅ 0 errors --- **Automated by CleverAgents Bot** Supervisor: Implementation | Agent: ca-issue-worker
freemo force-pushed feat/resource-list-lifecycle-state from e91cf06806
Some checks are pending
CI / unit_tests (pull_request) Waiting to run
CI / integration_tests (pull_request) Waiting to run
CI / docker (pull_request) Blocked by required conditions
CI / helm (pull_request) Waiting to run
CI / status-check (pull_request) Blocked by required conditions
CI / lint (pull_request) Waiting to run
CI / typecheck (pull_request) Waiting to run
CI / security (pull_request) Waiting to run
CI / quality (pull_request) Waiting to run
CI / e2e_tests (pull_request) Waiting to run
CI / coverage (pull_request) Blocked by required conditions
CI / benchmark-regression (pull_request) Blocked by required conditions
CI / benchmark-publish (pull_request) Waiting to run
CI / build (pull_request) Waiting to run
to d8a4031a69
Some checks are pending
CI / lint (pull_request) Waiting to run
CI / docker (pull_request) Blocked by required conditions
CI / typecheck (pull_request) Waiting to run
CI / security (pull_request) Waiting to run
CI / quality (pull_request) Waiting to run
CI / unit_tests (pull_request) Waiting to run
CI / benchmark-publish (pull_request) Waiting to run
CI / integration_tests (pull_request) Waiting to run
CI / e2e_tests (pull_request) Waiting to run
CI / coverage (pull_request) Blocked by required conditions
CI / benchmark-regression (pull_request) Blocked by required conditions
CI / build (pull_request) Waiting to run
CI / helm (pull_request) Waiting to run
CI / status-check (pull_request) Blocked by required conditions
2026-04-05 18:02:46 +00:00
Compare
freemo force-pushed feat/resource-list-lifecycle-state from d8a4031a69
Some checks are pending
CI / lint (pull_request) Waiting to run
CI / docker (pull_request) Blocked by required conditions
CI / typecheck (pull_request) Waiting to run
CI / security (pull_request) Waiting to run
CI / quality (pull_request) Waiting to run
CI / unit_tests (pull_request) Waiting to run
CI / benchmark-publish (pull_request) Waiting to run
CI / integration_tests (pull_request) Waiting to run
CI / e2e_tests (pull_request) Waiting to run
CI / coverage (pull_request) Blocked by required conditions
CI / benchmark-regression (pull_request) Blocked by required conditions
CI / build (pull_request) Waiting to run
CI / helm (pull_request) Waiting to run
CI / status-check (pull_request) Blocked by required conditions
to 2637b272dd
Some checks failed
CI / lint (pull_request) Successful in 39s
CI / typecheck (pull_request) Successful in 54s
CI / security (pull_request) Successful in 54s
CI / quality (pull_request) Successful in 34s
CI / build (pull_request) Successful in 18s
CI / helm (pull_request) Successful in 24s
CI / unit_tests (pull_request) Successful in 6m48s
CI / e2e_tests (pull_request) Successful in 19m50s
CI / integration_tests (pull_request) Failing after 22m57s
CI / docker (pull_request) Successful in 1m22s
CI / coverage (pull_request) Successful in 11m8s
CI / status-check (pull_request) Failing after 1s
CI / benchmark-publish (pull_request) Has been skipped
CI / benchmark-regression (pull_request) Successful in 56m59s
2026-04-05 18:13:13 +00:00
Compare
freemo left a comment

Code Review — APPROVED ✅

Reviewed PR #3297 with focus on architecture-alignment, module-boundaries, and interface-contracts.

This PR adds a lifecycle state column ("Status") to the agents resource list Rich table output for devcontainer-instance and container-instance resources, a 3-line warning banner for detected-but-not-built devcontainers, and lifecycle_state in JSON/YAML output. It also includes 12 BDD scenarios covering all lifecycle states, both container types, JSON output, warning banner behavior, and tracker-error resilience.

I verified that all issues raised in the two prior reviews (comment #118936 and review #3650) have been addressed in the latest commit.


Deep Dive: Architecture Alignment

✅ Presentation logic stays in the CLI layer: The new _get_lifecycle_state_str() helper (lines 151–178) is a presentation-layer concern — it translates domain state into a human-readable string. It is correctly placed in cli/commands/resource.py alongside the existing _resource_dict() and _resource_type_dict() helpers.

✅ Cross-layer imports are pre-existing and appropriate: The CLI module already imports get_lifecycle_tracker, rebuild_container, and stop_container from cleveragents.resource.handlers.devcontainer (lines 80–84). The new code follows this established pattern without introducing any new cross-layer dependencies.

✅ Domain model import is appropriate: Importing ContainerLifecycleState from cleveragents.domain.models.core.container_lifecycle (lines 77–79) is necessary for the CLI to interpret the DETECTED state and render it as "detected (not built)". This is a read-only use of the domain enum, which is appropriate for the presentation layer.

Deep Dive: Module Boundaries

✅ No new module boundary violations: All new code is contained within the CLI commands module and the test step definitions. No new imports cross architectural boundaries beyond what was already established.

✅ _CONTAINER_TYPES constant reuse: The module-level _CONTAINER_TYPES = frozenset({"container-instance", "devcontainer-instance"}) (line 105) is reused by the new helper, avoiding duplication. (Note: there is a pre-existing local variable shadow of _CONTAINER_TYPES on line 656 inside resource_add(), but this is not introduced by this PR.)

✅ Test isolation: The new step definitions file properly isolates its test infrastructure with _make_service, _patch_service, _unpatch_service helpers and cleans up the lifecycle tracker error patch in finally blocks.

Deep Dive: Interface Contracts

✅ Backward-compatible JSON/YAML schema extension: The _resource_dict() now includes "lifecycle_state" which is null for non-container resources (line 191). This is a backward-compatible addition — existing consumers that don't expect this field will simply ignore it, and the uniform schema (always present, null when not applicable) makes downstream parsing straightforward.

✅ Rich table column addition is non-breaking: The new "Status" column (line 829) is added between "Type" and "Kind", which is a reasonable position. Non-container resources show an empty string in this column.

✅ Warning banner matches spec: The 3-line warning banner (lines 857–866) now matches the spec's format at lines 10732–10734, including the Use agents resource show <ID> to inspect. line.

✅ Error handling contract: _get_lifecycle_state_str() catches (ValueError, KeyError) specifically (line 173) and logs a warning, returning None on failure. This follows the fail-fast principle — only expected, recoverable errors are caught; programming errors (AttributeError, TypeError, etc.) will propagate.

Standard Criteria

✅ Commit message format: Valid Conventional Changelog format with ISSUES CLOSED: #2596 footer
✅ Labels: Type/Bug label present, matching issue #2596
✅ Milestone: v3.6.0, matching issue #2596
✅ Type annotations: All new production code and step definitions are fully typed
✅ # type: ignore[import-untyped]: Used only for behave imports, consistent with established codebase pattern in resource_cli_steps.py
✅ File size: resource.py is 1561 lines — this exceeds the 500-line guideline but is a pre-existing condition, not introduced by this PR (the PR adds ~30 net lines)

Test Quality

✅ 12 BDD scenarios covering:

  • Status column header presence
  • All 4 lifecycle states (detected, running, stopped, failed)
  • Non-container resources (empty state)
  • Warning banner presence (detected) and absence (running)
  • JSON output with lifecycle_state key
  • JSON null for non-container resources
  • container-instance resource type (not just devcontainer)
  • Tracker error resilience (ValueError simulation)

✅ Proper test cleanup: Error patches are stopped in finally blocks
✅ Descriptive scenario names: Each scenario clearly states what is being tested


Observations (Non-blocking)

  1. [METADATA] PR body is empty — The PR description field is blank. CONTRIBUTING.md requires a detailed summary with a closing keyword. The commit message footer has ISSUES CLOSED: #2596, which Forgejo may use for issue linking, but the PR body should ideally contain a summary and Closes #2596 for completeness.

  2. [NAMING] Commit message doesn't match issue-prescribed message — Issue #2596 prescribes feat(cli): show devcontainer lifecycle state in agents resource list but the actual commit uses feat(cli): add devcontainer lifecycle state column to agents resource list output. Both are valid Conventional Changelog format; the prescribed message is more concise.

  3. [CODE] _CONTAINER_TYPES local variable shadow — Line 656 inside resource_add() creates a local _CONTAINER_TYPES = {"container-instance", "devcontainer-instance"} that shadows the module-level frozenset on line 105. This is pre-existing and not introduced by this PR, but could be cleaned up in a future refactor to use the module-level constant.

  4. [CODE] Duplicate test helpers — _make_service, _capture_output, _patch_service, _unpatch_service in the new step definitions file are near-identical copies from resource_cli_steps.py. Consider extracting into a shared test utilities module in a future cleanup.

  5. [SPEC] resource list spec example doesn't include Status column — As noted in prior reviews, the spec's resource list example (lines 11048–11067) doesn't show a Status column. The Status column appears only in the resource add auto-discovered children sub-table. Consider filing a spec update issue to add the Status column to the resource list example for consistency.

Decision: APPROVED ✅

All prior review issues have been addressed. The implementation is architecturally sound, respects module boundaries, maintains interface contracts, and includes comprehensive test coverage.

Note: Posted as COMMENT because Forgejo prevents self-approval. This review recommends APPROVAL.


Automated by CleverAgents Bot
Supervisor: PR Review | Agent: ca-pr-self-reviewer

## Code Review — APPROVED ✅ Reviewed PR #3297 with focus on **architecture-alignment**, **module-boundaries**, and **interface-contracts**. This PR adds a lifecycle state column ("Status") to the `agents resource list` Rich table output for `devcontainer-instance` and `container-instance` resources, a 3-line warning banner for detected-but-not-built devcontainers, and `lifecycle_state` in JSON/YAML output. It also includes 12 BDD scenarios covering all lifecycle states, both container types, JSON output, warning banner behavior, and tracker-error resilience. I verified that all issues raised in the two prior reviews (comment #118936 and review #3650) have been addressed in the latest commit. --- ### Deep Dive: Architecture Alignment ✅ **Presentation logic stays in the CLI layer**: The new `_get_lifecycle_state_str()` helper (lines 151–178) is a presentation-layer concern — it translates domain state into a human-readable string. It is correctly placed in `cli/commands/resource.py` alongside the existing `_resource_dict()` and `_resource_type_dict()` helpers. ✅ **Cross-layer imports are pre-existing and appropriate**: The CLI module already imports `get_lifecycle_tracker`, `rebuild_container`, and `stop_container` from `cleveragents.resource.handlers.devcontainer` (lines 80–84). The new code follows this established pattern without introducing any new cross-layer dependencies. ✅ **Domain model import is appropriate**: Importing `ContainerLifecycleState` from `cleveragents.domain.models.core.container_lifecycle` (lines 77–79) is necessary for the CLI to interpret the `DETECTED` state and render it as `"detected (not built)"`. This is a read-only use of the domain enum, which is appropriate for the presentation layer. ### Deep Dive: Module Boundaries ✅ **No new module boundary violations**: All new code is contained within the CLI commands module and the test step definitions. No new imports cross architectural boundaries beyond what was already established. ✅ **`_CONTAINER_TYPES` constant reuse**: The module-level `_CONTAINER_TYPES = frozenset({"container-instance", "devcontainer-instance"})` (line 105) is reused by the new helper, avoiding duplication. (Note: there is a pre-existing local variable shadow of `_CONTAINER_TYPES` on line 656 inside `resource_add()`, but this is not introduced by this PR.) ✅ **Test isolation**: The new step definitions file properly isolates its test infrastructure with `_make_service`, `_patch_service`, `_unpatch_service` helpers and cleans up the lifecycle tracker error patch in `finally` blocks. ### Deep Dive: Interface Contracts ✅ **Backward-compatible JSON/YAML schema extension**: The `_resource_dict()` now includes `"lifecycle_state"` which is `null` for non-container resources (line 191). This is a backward-compatible addition — existing consumers that don't expect this field will simply ignore it, and the uniform schema (always present, `null` when not applicable) makes downstream parsing straightforward. ✅ **Rich table column addition is non-breaking**: The new "Status" column (line 829) is added between "Type" and "Kind", which is a reasonable position. Non-container resources show an empty string in this column. ✅ **Warning banner matches spec**: The 3-line warning banner (lines 857–866) now matches the spec's format at lines 10732–10734, including the `Use agents resource show <ID> to inspect.` line. ✅ **Error handling contract**: `_get_lifecycle_state_str()` catches `(ValueError, KeyError)` specifically (line 173) and logs a warning, returning `None` on failure. This follows the fail-fast principle — only expected, recoverable errors are caught; programming errors (`AttributeError`, `TypeError`, etc.) will propagate. ### Standard Criteria ✅ **Commit message format**: Valid Conventional Changelog format with `ISSUES CLOSED: #2596` footer ✅ **Labels**: `Type/Bug` label present, matching issue #2596 ✅ **Milestone**: v3.6.0, matching issue #2596 ✅ **Type annotations**: All new production code and step definitions are fully typed ✅ **`# type: ignore[import-untyped]`**: Used only for `behave` imports, consistent with established codebase pattern in `resource_cli_steps.py` ✅ **File size**: `resource.py` is 1561 lines — this exceeds the 500-line guideline but is a pre-existing condition, not introduced by this PR (the PR adds ~30 net lines) ### Test Quality ✅ **12 BDD scenarios** covering: - Status column header presence - All 4 lifecycle states (detected, running, stopped, failed) - Non-container resources (empty state) - Warning banner presence (detected) and absence (running) - JSON output with `lifecycle_state` key - JSON `null` for non-container resources - `container-instance` resource type (not just devcontainer) - Tracker error resilience (ValueError simulation) ✅ **Proper test cleanup**: Error patches are stopped in `finally` blocks ✅ **Descriptive scenario names**: Each scenario clearly states what is being tested --- ### Observations (Non-blocking) 1. **[METADATA] PR body is empty** — The PR description field is blank. CONTRIBUTING.md requires a detailed summary with a closing keyword. The commit message footer has `ISSUES CLOSED: #2596`, which Forgejo may use for issue linking, but the PR body should ideally contain a summary and `Closes #2596` for completeness. 2. **[NAMING] Commit message doesn't match issue-prescribed message** — Issue #2596 prescribes `feat(cli): show devcontainer lifecycle state in agents resource list` but the actual commit uses `feat(cli): add devcontainer lifecycle state column to agents resource list output`. Both are valid Conventional Changelog format; the prescribed message is more concise. 3. **[CODE] `_CONTAINER_TYPES` local variable shadow** — Line 656 inside `resource_add()` creates a local `_CONTAINER_TYPES = {"container-instance", "devcontainer-instance"}` that shadows the module-level `frozenset` on line 105. This is pre-existing and not introduced by this PR, but could be cleaned up in a future refactor to use the module-level constant. 4. **[CODE] Duplicate test helpers** — `_make_service`, `_capture_output`, `_patch_service`, `_unpatch_service` in the new step definitions file are near-identical copies from `resource_cli_steps.py`. Consider extracting into a shared test utilities module in a future cleanup. 5. **[SPEC] `resource list` spec example doesn't include Status column** — As noted in prior reviews, the spec's `resource list` example (lines 11048–11067) doesn't show a Status column. The Status column appears only in the `resource add` auto-discovered children sub-table. Consider filing a spec update issue to add the Status column to the `resource list` example for consistency. **Decision: APPROVED** ✅ All prior review issues have been addressed. The implementation is architecturally sound, respects module boundaries, maintains interface contracts, and includes comprehensive test coverage. *Note: Posted as COMMENT because Forgejo prevents self-approval. This review recommends APPROVAL.* --- **Automated by CleverAgents Bot** Supervisor: PR Review | Agent: ca-pr-self-reviewer
freemo merged commit 367a272b60 into master 2026-04-05 21:07:41 +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!3297
No description provided.