feat(cli): add devcontainer lifecycle state column to agents resource list output #3297
Labels
Clear labels
auto/needs-reevaluation
controller-managed
overdue
auto/blocked-by-deps
auto/ci-timeout
auto/claimed-implementer
auto/claimed-merge
auto/claimed-reviewer
auto/driver-down
auto/invariant-violation
auto/last-attempt-tier-0
auto/last-attempt-tier-1
auto/last-attempt-tier-2
auto/last-attempt-tier-min
Automation Tracking
auto/needs-conflict-resolution
auto/needs-implementer
auto/postmortem
auto/ready-to-merge
auto/restart-throttled
auto/revert
auto/sentinel
auto/stale-inactivity
auto/unstable
Blocked
Needs Feedback
Signed-off: Owner
Signed-off: Scrum Master
Signed-off: Tech Lead
Spike
Controller deferred this PR; awaiting Phase 6+ scope-evaluator or operator re-enablement.
Auto-agents controller manages this PR/issue (see tools/controller/deploy/RUNBOOK.md). Remove this label to abandon controller management.
PR blocked by an open issue dependency. Operator must close the dep (or remove the dependency link) before the merge driver can act. Auto-cleared by merge_drive when no open deps remain.
Most recent merge cycle hit CI timeout. Driver excludes this PR while last merge_cycle row is < 30 min old; label persists thereafter as visible history.
Currently being processed by an implementer worker.
Currently being processed by the merge driver.
Currently being processed by a reviewer worker.
Merge driver heartbeat stale; pipeline halted. Closed automatically on next clean tick.
Detected master commit violating the strict merge invariant. Tracked as an issue (not a PR label); kept here for label completeness.
In-cycle escalation: most recent attempt ran at the Tier 0 slot (`tier-0`). Slot's model defined in .opencode/models/tiers.yaml.
In-cycle escalation: most recent attempt ran at the Tier 1 slot (`tier-1`). Slot's model defined in .opencode/models/tiers.yaml.
In-cycle escalation: most recent attempt ran at the Tier 2 slot (`tier-2`). Slot's model defined in .opencode/models/tiers.yaml. Gated behind IMPLEMENTER_ESCALATION_TIER2_ENABLED.
In-cycle escalation: most recent attempt ran at the Tier -1 slot (`tier-min`). Slot's model defined in .opencode/models/tiers.yaml. Suffix is ``-min`` (not ``--1``) so the Forgejo UI reads naturally.
Tracking issues used by the AI Automation system for agents to communicate and report.
Rebase conflict needs LLM conflict-resolver.
Failing CI needs implementer attention.
Documenting a driver incident or rollback.
Reviewer has APPROVED this PR and no later REQUEST_CHANGES is outstanding. The merge driver requires this label to even consider a PR for merging. Set by the reviewer worker on APPROVE; cleared on REQUEST_CHANGES.
Train repeatedly lost master-tempo races. Driver excludes via merge_cycle until cooldown elapses; label persists as visible history.
Revert PR backing out an invariant violation. Fast-tracked through the merge driver.
Sentinel PR duplicated from upstream into a personal fork by tools/duplicate_prs_to_fork.py for pipeline testing. Lives only in the fork; the canonical pipeline never sees it.
No implementer activity for N days. Flagged for human review. Auto-cleared on next push to head branch.
Repeatedly fails on current master (>= 3 ci-fail-on-rebased-sha releases in 12 h). Excluded from driver until human triage.
A ticket in a blocked state and unable to complete until some other task is completed first.
Bounty
$100
A bounty of $100 for any open-source contributor who provides a MR that solves this issue
Bounty
$1000
A bounty of $1000 for any open-source contributor who provides a MR that solves this issue
Bounty
$10000
A bounty of $10000 for any open-source contributor who provides a MR that solves this issue
Bounty
$20
A bounty of $20 for any open-source contributor who provides a MR that solves this issue
Bounty
$2000
A bounty of $2000 for any open-source contributor who provides a MR that solves this issue
Bounty
$250
A bounty of $250 for any open-source contributor who provides a MR that solves this issue
Bounty
$50
A bounty of $50 for any open-source contributor who provides a MR that solves this issue
Bounty
$500
A bounty of $500 for any open-source contributor who provides a MR that solves this issue
Bounty
$5000
A bounty of $5000 for any open-source contributor who provides a MR that solves this issue
Bounty
$750
A bounty of $750 for any open-source contributor who provides a MR that solves this issue
MoSCoW
Could have
Could have feature in order to satisfy the epic/legendary.
MoSCoW
Must have
Must have feature in order to satisfy the epic/legendary.
MoSCoW
Should have
Should have feature in order to satisfy the epic/legendary.
There are questions in the ticket that can not be completed until the project owner provides clarity.
Points
1
1 man-hours worth of work for an expert with no learning curve.
Points
13
13 man-hours worth of work for an expert with no learning curve.
Points
2
2 man-hours worth of work for an expert with no learning curve.
Points
21
21 man-hours worth of work for an expert with no learning curve.
Points
3
3 man-hours worth of work for an expert with no learning curve.
Points
34
34 man-hours worth of work for an expert with no learning curve.
Points
5
5 man-hours worth of work for an expert with no learning curve.
Points
55
55 man-hours worth of work for an expert with no learning curve.
Points
8
8 man-hours worth of work for an expert with no learning curve.
Points
88
88 man-hours worth of work for an expert with no learning curve.
Priority
Backlog
This ticket has backlogged priority and is not to be worked on yet
Priority
CI Blocker
Critical priority issue that blocks CI/CD pipeline and prevents PR merges
Priority
Critical
The priority is critical
Priority
High
The priority is high
Priority
Low
The priority is low
Priority
Medium
The priority is medium
When an epic or legendary is in review it must be signed off by owner, tech lead, and scrum master before being marked as completed.
When an epic or legendary is in review it must be signed off by owner, tech lead, and scrum master before being marked as completed.
When an epic or legendary is in review it must be signed off by owner, tech lead, and scrum master before being marked as completed.
A ticket for learning a tool or technology that is needed to be able to do future planning and design.
State
Completed
The ticket has been fully implemented, completed, and merged with the source code. This label should only be applied once a ticket is closed.
State
Duplicate
A ticket that represents the same content as an existing ticket.
State
In Progress
A ticket that is actively being developed.
State
In Review
A ticket that has had some code completed to implement but is waiting to pass peer review and is not yet merged in.
State
Paused
This ticket's work started but wasn't finished. It's on hold (likely in a feature branch) and will be resumed later, either due to a blocker or a delay.
State
Unverified
All new tickets start in this state. A developer may set it to show the ticket is unverified. This means we haven't agreed to work on it. It will either move to a verified state or be closed as wontdo.
State
Verified
The issue has been verified by a developer as legitimate. It will be worked on and verified tickets are now considered part of the backlog.
State
Wont Do
This ticket has been decided it wont be done. This may mean the bug has been determined to not be real (cant verify) or the feature is one we have decided we dont want to adopt.
Type
Automation
Any edits or discussion about the AI automated coding system.
Type
Bug
Something that doesnt work as intended.
Type
Discussion
Anytime a ticket represents a discussion about a subject and doesnt fall into one of the other categories.
Type
Documentation
An error or improvement needed in the documentation.
Type
Epic
Any first tier epic. That is, an epic which contains only issues as children and will not have sub-epics.
Type
Feature
Some new functionality not present.
Type
Legendary
A type of Epic which will contain other Epics.
Type
Refactor
A code change that restructures existing code without changing its external behavior.
Type
Support
Someone needs help using the project.
Type
Task
A generic task that doesnt fit into the other type categories.
Type
Testing
Work exclusively focusing on fixing or expanding testing.
No Label
Projects
Clear projects
No project
Assignees
aditya (Aditya Chhabra)
aleenaumair (Aleena Umair)
brent.edwards (Brent Edwards)
CoreRasurae (Luis Mendes)
drew (Drew Morris)
eugen.thaci (Eugen Thaci)
freemo (Jeffrey Phillips Freeman)
HAL9000 (HAL 9000)
HAL9001 (HAL9001)
hamza.khyari (Hamza Khyari)
hurui200320 (Rui Hu)
justin.morris
khird (Kyle Hird)
org.cleveragents
Clear assignees
No Assignees
Notifications
Due Date
No due date set.
Dependencies
No dependencies set.
Reference: cleveragents/cleveragents-core#3297
Reference in New Issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Delete Branch "feat/resource-list-lifecycle-state"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
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 listoutput 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 Exceptionviolates project error-handling policysrc/cleveragents/cli/commands/resource.py,_get_lifecycle_state_str()(line 173)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."get_lifecycle_tracker()(in_devcontainer_internals.py:54) auto-creates a tracker if none exists and only raisesValueErrorfor emptyresource_id. Catching all exceptions here would silently mask programming errors likeAttributeError,TypeError, or unexpected state corruption.except Exceptionwith a specific exception catch. Sinceget_lifecycle_trackeronly raisesValueErrorfor invalid input, catchValueErrorspecifically and log a warning:2. [SPEC] Warning banner missing third line from spec
src/cleveragents/cli/commands/resource.py(lines 853–859)Use agents resource show <ID> to inspect.line.3. [TEST] Missing test coverage for
container-instanceresourcesfeatures/resource_list_lifecycle_state.feature_get_lifecycle_state_str()helper handles bothdevcontainer-instanceANDcontainer-instanceresource types (via_CONTAINER_TYPES), but all 10 test scenarios only exercisedevcontainer-instance. There is zero test coverage forcontainer-instancelifecycle state display.container-instanceresources also display their lifecycle state correctly.4. [TEST] Missing test for tracker-unavailable/error resilience
features/resource_list_lifecycle_state.featureexceptin_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.5. [METADATA] Milestone mismatch between issue and PR
Observations (Non-blocking)
6. [SPEC-NOTE]
resource listspec example doesn't include a State columnresource listexample (lines 11048–11067) shows columns: Name, ID, Type, Phys/Virt, Children, Projects — with no State column. The State/Status column appears only in theresource addauto-discovered children sub-table (line 10723). The issue #2596 references line 10726 as justification, but that line is in theresource addsection, notresource list.resource list --allsince it displays the same resources. But the spec doesn't explicitly require it forresource list. Consider filing a spec update issue to add the State column to theresource listexample for consistency.7. [METADATA] Commit message doesn't match issue-prescribed message
feat(cli): show devcontainer lifecycle state in agents resource listfeat(cli): add devcontainer lifecycle state column to agents resource list output8. [TEST] PR body scenario count inconsistencies
9. [CODE] Duplicate helper functions in step definitions
_make_service,_capture_output,_patch_service,_unpatch_serviceinresource_list_lifecycle_state_steps.pyare near-identical copies of the same functions inresource_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_outputtype annotations missingfeatures/steps/resource_list_lifecycle_state_steps.pyline 38,_capture_output(func, *args, **kwargs)lacks type annotations for its parameters and return type. The shared version inresource_cli_steps.pyhasfunc: Any, *args: Any, **kwargs: Anywith return typetuple[str, bool]. This should match.Good Aspects
_get_lifecycle_state_str()helper from the rendering logicStrEnum—str(state)returns the lowercase value as expectedlifecycle_state: nullin JSON/YAML for non-container resources is a good schema design choiceISSUES CLOSEDfooterCloses #2596closing keywordType/Buglabel matches the issue's labelDecision: 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 — COMMENT
Reviewed PR #3297 with focus on api-consistency, naming-conventions, and specification-compliance.
This PR adds a lifecycle state column to
agents resource listoutput 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"
src/cleveragents/cli/commands/resource.py:825"State"to"Status"to match the spec, or file a spec update issue if "State" is the intended name going forward.2. [SPEC]
resource listspec example does not include a Status/State columnagents resource listRich example)resource listexample shows columns: Name, ID, Type, Phys/Virt, Children, Projects — with no Status/State column. The Status column only appears in theresource addauto-discovered children sub-table (lines 10723, 42441). Issue #2596 references line 10726 as justification, but that line is in theresource addsection, notresource list.resource list --allis a reasonable enhancement since it displays the same resources. However, the spec doesn't explicitly require it forresource list. This creates a spec divergence.resource listexample for consistency. This ensures the spec remains the source of truth.3. [ERROR-HANDLING] Bare
except Exceptionviolates fail-fast policysrc/cleveragents/cli/commands/resource.py:173_get_lifecycle_state_str()catches all exceptions withexcept 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."except Exceptionwould silently mask programming errors likeAttributeError,TypeError, or unexpected state corruption. These should propagate so they can be caught during development.get_lifecycle_tracker()can raise (e.g.,ValueError,KeyError). Log a warning for the caught exception so it's observable:4. [SPEC] Warning banner — spec inconsistency (2 vs 3 lines)
Location:
src/cleveragents/cli/commands/resource.py:853–859Issue: The spec has two different versions of the warning banner:
Use agents resource show <ID> to inspect.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
features/steps/resource_list_lifecycle_state_steps.py_capture_output(func, *args, **kwargs)— missing all parameter and return type annotations_patch_service(context: Context)— missing return type annotation_unpatch_service(orig_fn)—orig_fnmissing type annotationresource_cli_steps.pyhas proper annotations:func: Any, *args: Any, **kwargs: Any→tuple[str, bool],_patch_service(...) -> Any,_unpatch_service(orig_fn: Any) -> Noneresource_cli_steps.py.6. [API-CONSISTENCY]
_get_lifecycle_state_strusesAnyparameter typesrc/cleveragents/cli/commands/resource.py:151_get_lifecycle_state_str(resource: Any) -> str | None. UsingAnyloses type safety. If the actual type isResource(or the domain model), it should be annotated as such._resource_dict) also useAny. So this is consistent with the existing pattern in this file, but it's worth noting as a broader API consistency concern.Resourcetype 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-instanceresourcesfeatures/resource_list_lifecycle_state.feature_get_lifecycle_state_str()helper handles bothdevcontainer-instanceANDcontainer-instanceresource types (via_CONTAINER_TYPES), but all 10 test scenarios only exercisedevcontainer-instance. There is zero test coverage forcontainer-instancelifecycle state display.container-instanceresources also display their lifecycle state correctly.8. [TEST] Missing tracker-unavailable resilience test
features/resource_list_lifecycle_state.featureexceptin_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.9. [METADATA] Milestone mismatch between issue and PR
Observations (Non-blocking)
10. [NAMING] Commit message doesn't match issue-prescribed message
feat(cli): show devcontainer lifecycle state in agents resource listfeat(cli): add devcontainer lifecycle state column to agents resource list output11. [API-CONSISTENCY]
lifecycle_statefield in JSON/YAML output_resource_dict()now includeslifecycle_statewhich isnullfor non-container resources. This is a good schema design choice — usingnullrather 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_serviceare near-identical copies of functions inresource_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
Good Aspects
_get_lifecycle_state_str()helper from rendering logicStrEnum—str(state)returns the lowercase value as expectedlifecycle_state: nullin JSON/YAML for non-container resources is good schema designISSUES CLOSEDfooterCloses #2596closing keywordType/Buglabel matches the issue's labelDecision: 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_servicedef _capture_output(func, *args, **kwargs):[TYPE-SAFETY] Missing type annotations. The existing
resource_cli_steps.pyversion hasfunc: Any, *args: Any, **kwargs: Anywith return typetuple[str, bool]. This should match.@@ -0,0 +63,4 @@return buf.getvalue(), faileddef _patch_service(context: Context):[TYPE-SAFETY] Missing return type annotation. Should be
-> Anyto matchresource_cli_steps.py.@@ -0,0 +76,4 @@return orig_fndef _unpatch_service(orig_fn) -> None:[TYPE-SAFETY]
orig_fnparameter missing type annotation. Should beorig_fn: Anyto matchresource_cli_steps.py.@@ -151,0 +170,4 @@if state == ContainerLifecycleState.DETECTED:return "detected (not built)"return str(state)except Exception:[ERROR-HANDLING] Bare
except Exceptionviolates the project's fail-fast policy. This would silently mask programming errors (AttributeError,TypeError, etc.). Narrow to the specific exceptionsget_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")[NAMING / SPEC] The spec uses "Status" as the column header (lines 10723, 42441), not "State". Consider renaming to match the spec.
a6bb1b6e43toe91cf06806Review 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 loggingFile:
src/cleveragents/cli/commands/resource.py—_get_lifecycle_state_str()Replaced the bare
except Exception: return Nonewith a specific catch of(ValueError, KeyError)and added alogger.warning(...)call so tracker failures are observable without crashing the list command. Programming errors likeAttributeErrorandTypeErrorwill 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 loopAdded the missing third line:
The banner now matches the 3-line version from spec line 10732–10734.
✅ 3. Added
container-instancetest scenarioFile:
features/resource_list_lifecycle_state.featureAdded a new scenario: "resource list shows lifecycle state for container-instance resources" — registers a
container-instanceresource and verifies theStatuscolumn anddetected (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.featureAdded a new scenario: "resource list succeeds gracefully when lifecycle tracker raises an error" — patches
get_lifecycle_trackerto raiseValueErrorand 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.pyline 829Renamed 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.pyAdded 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) -> NoneAlso added
from typing import Anyandfrom unittest.mock import patchimports.Quality Gates
ruff check— ✅ All checks passedruff format --check— ✅ 2 files already formattedpyright src/cleveragents/cli/commands/resource.py— ✅ 0 errorspyright features/steps/resource_list_lifecycle_state_steps.py— ✅ 0 errorsAutomated by CleverAgents Bot
Supervisor: Implementation | Agent: ca-issue-worker
e91cf06806tod8a4031a69d8a4031a69to2637b272ddCode 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 listRich table output fordevcontainer-instanceandcontainer-instanceresources, a 3-line warning banner for detected-but-not-built devcontainers, andlifecycle_statein 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 incli/commands/resource.pyalongside 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, andstop_containerfromcleveragents.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
ContainerLifecycleStatefromcleveragents.domain.models.core.container_lifecycle(lines 77–79) is necessary for the CLI to interpret theDETECTEDstate 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_TYPESconstant 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_TYPESon line 656 insideresource_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_servicehelpers and cleans up the lifecycle tracker error patch infinallyblocks.Deep Dive: Interface Contracts
✅ Backward-compatible JSON/YAML schema extension: The
_resource_dict()now includes"lifecycle_state"which isnullfor 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,nullwhen 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, returningNoneon 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: #2596footer✅ Labels:
Type/Buglabel 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 forbehaveimports, consistent with established codebase pattern inresource_cli_steps.py✅ File size:
resource.pyis 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:
lifecycle_statekeynullfor non-container resourcescontainer-instanceresource type (not just devcontainer)✅ Proper test cleanup: Error patches are stopped in
finallyblocks✅ Descriptive scenario names: Each scenario clearly states what is being tested
Observations (Non-blocking)
[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 andCloses #2596for completeness.[NAMING] Commit message doesn't match issue-prescribed message — Issue #2596 prescribes
feat(cli): show devcontainer lifecycle state in agents resource listbut the actual commit usesfeat(cli): add devcontainer lifecycle state column to agents resource list output. Both are valid Conventional Changelog format; the prescribed message is more concise.[CODE]
_CONTAINER_TYPESlocal variable shadow — Line 656 insideresource_add()creates a local_CONTAINER_TYPES = {"container-instance", "devcontainer-instance"}that shadows the module-levelfrozenseton 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.[CODE] Duplicate test helpers —
_make_service,_capture_output,_patch_service,_unpatch_servicein the new step definitions file are near-identical copies fromresource_cli_steps.py. Consider extracting into a shared test utilities module in a future cleanup.[SPEC]
resource listspec example doesn't include Status column — As noted in prior reviews, the spec'sresource listexample (lines 11048–11067) doesn't show a Status column. The Status column appears only in theresource addauto-discovered children sub-table. Consider filing a spec update issue to add the Status column to theresource listexample 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