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 StrEnumstr(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: Anytuple[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 StrEnumstr(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.pyresource_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.0v3.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.