fix(domain): add missing execute hook to ToolLifecycle model to satisfy spec four-stage lifecycle #3052

Merged
freemo merged 1 commit from fix/tool-lifecycle-domain-model-missing-execute-hook into master 2026-04-05 21:16:06 +00:00
Owner

Summary

Adds the missing execute hook field to the ToolLifecycle domain model, completing the four-stage lifecycle (discover / activate / execute / deactivate) as required by the specification. Without this field, any tool configuration relying on an execution hook was silently dropped, causing a divergence between the spec and the domain model.

Changes

  • src/cleveragents/domain/models/core/tool.py — Added execute: str | None = Field(default=None, description="Hook for tool execution") to the ToolLifecycle model, alongside the existing discover, activate, and deactivate fields. All four fields now follow the same str | None / Field(default=None) pattern, making the lifecycle model consistent and complete per the spec.
  • Tool.as_cli_dict() — Updated the lifecycle block rendering logic so that:
    • The lifecycle block is included in the output only when at least one hook field is set (non-None), preventing empty lifecycle blocks from appearing in serialised output.
    • When the block is rendered, the execute hook is now included alongside discover, activate, and deactivate.
  • features/tool_lifecycle_execute_hook.feature — New Behave feature file containing 8 scenarios that cover: creating a ToolLifecycle with all four hooks set, with only execute set, with execute omitted (defaulting to None), round-trip serialisation through as_cli_dict(), omission of the lifecycle block when no hooks are configured, and the TDD issue-capture scenario tagged @tdd_issue @tdd_issue_2820.
  • features/steps/tool_lifecycle_execute_hook_steps.py — New step definitions file implementing all step bindings for the feature above.

Design Decisions

  • Field pattern consistency — The execute field deliberately mirrors the existing discover, activate, and deactivate fields (str | None, Field(default=None)). Deviating from this pattern would introduce unnecessary asymmetry in the model and complicate downstream serialisation logic.
  • Conditional lifecycle block renderingas_cli_dict() omits the lifecycle key entirely when all hook fields are None. This preserves backward compatibility: tools that do not configure any lifecycle hooks continue to produce identical CLI output, and no spurious empty blocks are introduced.
  • TDD tags without @tdd_expected_fail — The issue-capture scenario uses @tdd_issue @tdd_issue_2820 but not @tdd_expected_fail, because the fix is already in place. This follows the project convention where the tag documents the issue origin without signalling an expected failure in CI.
  • No new public API surface — The change is purely additive at the model level; no existing interfaces were modified or removed, keeping the blast radius of this fix minimal.

Testing

  • Unit tests (Behave): 131 scenarios passed, 0 failed (8 new scenarios in tool_lifecycle_execute_hook.feature + 123 existing scenarios from the consolidated tool suite)
  • Type checking (Pyright): 0 errors, 0 warnings
  • Lint (Ruff): All checks passed

Modules Affected

  • src/cleveragents/domain/models/core/tool.py (ToolLifecycle model, Tool.as_cli_dict())
  • features/tool_lifecycle_execute_hook.feature (new)
  • features/steps/tool_lifecycle_execute_hook_steps.py (new)

Closes #2820


Automated by CleverAgents Bot
Supervisor: Implementation | Agent: ca-pr-api-creator

## Summary Adds the missing `execute` hook field to the `ToolLifecycle` domain model, completing the four-stage lifecycle (`discover` / `activate` / `execute` / `deactivate`) as required by the specification. Without this field, any tool configuration relying on an execution hook was silently dropped, causing a divergence between the spec and the domain model. ## Changes - **`src/cleveragents/domain/models/core/tool.py`** — Added `execute: str | None = Field(default=None, description="Hook for tool execution")` to the `ToolLifecycle` model, alongside the existing `discover`, `activate`, and `deactivate` fields. All four fields now follow the same `str | None` / `Field(default=None)` pattern, making the lifecycle model consistent and complete per the spec. - **`Tool.as_cli_dict()`** — Updated the lifecycle block rendering logic so that: - The `lifecycle` block is included in the output **only** when at least one hook field is set (non-`None`), preventing empty lifecycle blocks from appearing in serialised output. - When the block is rendered, the `execute` hook is now included alongside `discover`, `activate`, and `deactivate`. - **`features/tool_lifecycle_execute_hook.feature`** — New Behave feature file containing 8 scenarios that cover: creating a `ToolLifecycle` with all four hooks set, with only `execute` set, with `execute` omitted (defaulting to `None`), round-trip serialisation through `as_cli_dict()`, omission of the lifecycle block when no hooks are configured, and the TDD issue-capture scenario tagged `@tdd_issue @tdd_issue_2820`. - **`features/steps/tool_lifecycle_execute_hook_steps.py`** — New step definitions file implementing all step bindings for the feature above. ## Design Decisions - **Field pattern consistency** — The `execute` field deliberately mirrors the existing `discover`, `activate`, and `deactivate` fields (`str | None`, `Field(default=None)`). Deviating from this pattern would introduce unnecessary asymmetry in the model and complicate downstream serialisation logic. - **Conditional lifecycle block rendering** — `as_cli_dict()` omits the `lifecycle` key entirely when all hook fields are `None`. This preserves backward compatibility: tools that do not configure any lifecycle hooks continue to produce identical CLI output, and no spurious empty blocks are introduced. - **TDD tags without `@tdd_expected_fail`** — The issue-capture scenario uses `@tdd_issue @tdd_issue_2820` but not `@tdd_expected_fail`, because the fix is already in place. This follows the project convention where the tag documents the issue origin without signalling an expected failure in CI. - **No new public API surface** — The change is purely additive at the model level; no existing interfaces were modified or removed, keeping the blast radius of this fix minimal. ## Testing - **Unit tests (Behave):** ✅ 131 scenarios passed, 0 failed (8 new scenarios in `tool_lifecycle_execute_hook.feature` + 123 existing scenarios from the consolidated tool suite) - **Type checking (Pyright):** ✅ 0 errors, 0 warnings - **Lint (Ruff):** ✅ All checks passed ## Modules Affected - `src/cleveragents/domain/models/core/tool.py` (`ToolLifecycle` model, `Tool.as_cli_dict()`) - `features/tool_lifecycle_execute_hook.feature` (new) - `features/steps/tool_lifecycle_execute_hook_steps.py` (new) ## Related Issues Closes #2820 --- **Automated by CleverAgents Bot** Supervisor: Implementation | Agent: ca-pr-api-creator
fix(domain): add missing execute hook to ToolLifecycle model to satisfy spec four-stage lifecycle
All checks were successful
CI / lint (pull_request) Successful in 19s
CI / typecheck (pull_request) Successful in 49s
CI / quality (pull_request) Successful in 34s
CI / security (pull_request) Successful in 59s
CI / build (pull_request) Successful in 29s
CI / helm (pull_request) Successful in 24s
CI / unit_tests (pull_request) Successful in 7m0s
CI / e2e_tests (pull_request) Successful in 17m41s
CI / coverage (pull_request) Successful in 10m42s
CI / integration_tests (pull_request) Successful in 23m17s
CI / docker (pull_request) Successful in 1m21s
CI / status-check (pull_request) Successful in 1s
CI / benchmark-publish (pull_request) Has been skipped
CI / benchmark-regression (pull_request) Successful in 56m6s
7e55d522b4
- What was implemented
  - Added execute: str | None = Field(default=None, description="Hook for tool execution") to ToolLifecycle in src/cleveragents/domain/models/core/tool.py, completing the four-stage lifecycle (discover / activate / execute / deactivate) as required by the spec.
  - Updated Tool.as_cli_dict() to render the lifecycle block (including execute) when set, and to omit the lifecycle block entirely when no hooks are configured, keeping CLI output clean for tools without lifecycle hooks.
  - Created features/tool_lifecycle_execute_hook.feature with 8 Behave scenarios covering:
    - issue-capture TDD test
    - all four hooks (discover, activate, execute, deactivate)
    - execute defaults to None
    - execute set independently
    - from_config parsing
    - as_cli_dict rendering
  - Created features/steps/tool_lifecycle_execute_hook_steps.py with all step definitions implementing Given/When/Then for the scenarios.

- Key design decisions
  - The execute field follows the same pattern as the existing discover, activate, and deactivate fields: str | None with Field(default=None).
  - as_cli_dict() renders the lifecycle block only when at least one hook is set (non-None), ensuring clean output for tools that do not utilize lifecycle hooks.
  - The issue-capture TDD scenario uses @tdd_issue and @tdd_issue_2820 tags (without @tdd_expected_fail since the fix is in place), aligning with the test-driven approach described in the metadata.

- Impact and considerations
  - Changes are additive and backward-compatible; tools configured without lifecycle hooks will continue to render without a lifecycle block.
  - Introduces Behave-based acceptance tests to validate the four-stage lifecycle handling and CLI rendering.
  - Affects only ToolLifecycle modeling, CLI rendering, and associated tests; no changes to external APIs.

ISSUES CLOSED: #2820
freemo added this to the v3.7.0 milestone 2026-04-05 04:21:41 +00:00
Author
Owner

🔒 Review claimed by reviewer-pool-1 [claim-token: reviewer-pool-1-3052-1775362000]


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

🔒 Review claimed by reviewer-pool-1 [claim-token: reviewer-pool-1-3052-1775362000] --- **Automated by CleverAgents Bot** Supervisor: PR Review | Agent: ca-continuous-pr-reviewer
freemo left a comment

Review: APPROVED (posted as comment — cannot self-approve own PR via API)

Summary

This PR correctly addresses issue #2820 — the ToolLifecycle domain model was missing the execute hook, violating the specification's explicit four-stage lifecycle requirement (discover / activate / execute / deactivate).

Specification Alignment

The spec states: "A Tool is the atomic unit of execution … and a four-stage lifecycle (discover / activate / execute / deactivate)." The ToolInstance protocol in src/cleveragents/tool/lifecycle.py already implemented all four stages, but the domain model only had three. This PR closes that gap.

Code Review

ToolLifecycle model change — The new execute: str | None = Field(default=None, description="Hook for tool execution") field follows the exact same pattern as the existing discover, activate, and deactivate fields. Placement between activate and deactivate matches the spec's lifecycle ordering. The docstring update documenting the four-stage contract is a nice touch.

as_cli_dict() lifecycle rendering — On master, as_cli_dict() had no lifecycle rendering at all, so this is a new addition (not a duplication). The implementation correctly:

  • Only adds the lifecycle key when at least one hook is non-None
  • Renders hooks in spec order (discover → activate → execute → deactivate)
  • Omits individual hooks that are None

from_config() compatibility — No changes needed here since ToolLifecycle.model_validate(lc_data) automatically picks up the new field via Pydantic. The Validation subclass inherits the lifecycle rendering through super().as_cli_dict(). Both verified.

Test Quality

8 well-structured BDD scenarios covering:

  1. TDD issue capture (tagged @tdd_issue @tdd_issue_2820)
  2. All four hooks set simultaneously
  3. Default None behavior
  4. Independent execute setting (other hooks remain None)
  5. from_config parsing of execute hook
  6. from_config with execute=None preservation
  7. as_cli_dict rendering when execute is set
  8. as_cli_dict omission when no lifecycle hooks configured

Step definitions reuse existing steps from tool_model_steps.py where appropriate (the tool model should be created, the tool lifecycle discover should be "{expected}"), avoiding duplication.

Minor Note (non-blocking)

tool.py is 714 lines on this branch, exceeding the 500-line guideline. However, this is a pre-existing condition — the PR only adds ~18 lines to the model file and ~14 lines to as_cli_dict(). Not blocking on this.

Verdict

Clean, well-scoped, spec-aligned bug fix with comprehensive tests. Single atomic commit following Conventional Changelog format. PR metadata (milestone, label, closing keyword) all correct. Code is approved for merge.


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

## Review: APPROVED ✅ (posted as comment — cannot self-approve own PR via API) ### Summary This PR correctly addresses issue #2820 — the `ToolLifecycle` domain model was missing the `execute` hook, violating the specification's explicit four-stage lifecycle requirement (`discover` / `activate` / `execute` / `deactivate`). ### Specification Alignment ✅ The spec states: *"A Tool is the atomic unit of execution … and a **four-stage lifecycle** (`discover` / `activate` / `execute` / `deactivate`)."* The `ToolInstance` protocol in `src/cleveragents/tool/lifecycle.py` already implemented all four stages, but the domain model only had three. This PR closes that gap. ### Code Review **`ToolLifecycle` model change** — The new `execute: str | None = Field(default=None, description="Hook for tool execution")` field follows the exact same pattern as the existing `discover`, `activate`, and `deactivate` fields. Placement between `activate` and `deactivate` matches the spec's lifecycle ordering. The docstring update documenting the four-stage contract is a nice touch. **`as_cli_dict()` lifecycle rendering** — On master, `as_cli_dict()` had no lifecycle rendering at all, so this is a new addition (not a duplication). The implementation correctly: - Only adds the `lifecycle` key when at least one hook is non-`None` - Renders hooks in spec order (discover → activate → execute → deactivate) - Omits individual hooks that are `None` **`from_config()` compatibility** — No changes needed here since `ToolLifecycle.model_validate(lc_data)` automatically picks up the new field via Pydantic. The `Validation` subclass inherits the lifecycle rendering through `super().as_cli_dict()`. Both verified. ✅ ### Test Quality ✅ 8 well-structured BDD scenarios covering: 1. TDD issue capture (tagged `@tdd_issue @tdd_issue_2820`) 2. All four hooks set simultaneously 3. Default `None` behavior 4. Independent `execute` setting (other hooks remain `None`) 5. `from_config` parsing of `execute` hook 6. `from_config` with `execute=None` preservation 7. `as_cli_dict` rendering when `execute` is set 8. `as_cli_dict` omission when no lifecycle hooks configured Step definitions reuse existing steps from `tool_model_steps.py` where appropriate (`the tool model should be created`, `the tool lifecycle discover should be "{expected}"`), avoiding duplication. ### Minor Note (non-blocking) `tool.py` is 714 lines on this branch, exceeding the 500-line guideline. However, this is a pre-existing condition — the PR only adds ~18 lines to the model file and ~14 lines to `as_cli_dict()`. Not blocking on this. ### Verdict Clean, well-scoped, spec-aligned bug fix with comprehensive tests. Single atomic commit following Conventional Changelog format. PR metadata (milestone, label, closing keyword) all correct. Code is approved for merge. --- **Automated by CleverAgents Bot** Supervisor: PR Review | Agent: ca-pr-self-reviewer
freemo scheduled this pull request to auto merge when all checks succeed 2026-04-05 04:35:10 +00:00
Author
Owner

🔒 Review claimed by reviewer-pool-1 [claim-token: reviewer-pool-1-3052-1775366000]


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

🔒 Review claimed by reviewer-pool-1 [claim-token: reviewer-pool-1-3052-1775366000] --- **Automated by CleverAgents Bot** Supervisor: PR Review | Agent: ca-continuous-pr-reviewer
freemo left a comment

Review: APPROVED (posted as comment — cannot self-approve own PR via API)

Summary

This PR correctly closes the spec gap identified in #2820 — the ToolLifecycle domain model was missing the execute hook, violating the specification's explicit four-stage lifecycle requirement (discover / activate / execute / deactivate).

Specification Alignment

The spec (line 135) states: "A Tool is the atomic unit of execution … and a four-stage lifecycle (discover / activate / execute / deactivate)." The ToolInstance protocol in src/cleveragents/tool/lifecycle.py already implemented all four stages, but the domain model only had three. This PR closes that gap cleanly.

Code Review

ToolLifecycle model — The new execute: str | None = Field(default=None, description="Hook for tool execution") field follows the exact same pattern as the existing discover, activate, and deactivate fields. Placement between activate and deactivate matches the spec's lifecycle ordering. The docstring update documenting the four-stage contract is appropriate.

as_cli_dict() lifecycle rendering — This is a new addition (master had no lifecycle rendering in as_cli_dict()). The implementation correctly:

  • Only adds the lifecycle key when at least one hook is non-None
  • Renders hooks in spec order (discover → activate → execute → deactivate)
  • Omits individual hooks that are None
  • Prevents empty lifecycle blocks from appearing in serialised output

from_config() compatibility — No changes needed since ToolLifecycle.model_validate(lc_data) automatically picks up the new field via Pydantic. Verified.

Test Quality

8 well-structured BDD scenarios covering:

  1. TDD issue capture (tagged @tdd_issue @tdd_issue_2820)
  2. All four hooks set simultaneously
  3. Default None behavior
  4. Independent execute setting (other hooks remain None)
  5. from_config parsing of execute hook
  6. from_config with execute=None preservation
  7. as_cli_dict rendering when execute is set
  8. as_cli_dict omission when no lifecycle hooks configured

Step definitions correctly reuse existing steps from tool_model_steps.py where available (e.g., the tool model should be created, the tool lifecycle discover should be "{expected}"), avoiding duplication. No step definition conflicts detected.

Correctness

  • No logic errors detected
  • Boundary conditions handled (all None, single hook set, all hooks set)
  • lc_dict type annotation dict[str, str | None] is slightly broader than necessary (values are always str since we guard with is not None), but this is harmless and Pyright accepts it
  • No resource leaks, race conditions, or injection vulnerabilities

PR Metadata

  • Commit message follows Conventional Changelog: fix(domain): add missing execute hook to ToolLifecycle model to satisfy spec four-stage lifecycle
  • Single atomic commit
  • Closes #2820 present in PR body
  • Milestone: v3.7.0
  • Label: Type/Bug

Minor Note (non-blocking)

tool.py is 714 lines on this branch, exceeding the 500-line guideline. This is a pre-existing condition — the PR only adds ~32 lines. Not blocking.

CI Status

All required checks passing: lint, typecheck, security, quality, unit_tests, integration_tests, e2e_tests, coverage, status-check.

Verdict

Clean, well-scoped, spec-aligned bug fix with comprehensive tests. Approved for merge.


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

## Review: APPROVED ✅ (posted as comment — cannot self-approve own PR via API) ### Summary This PR correctly closes the spec gap identified in #2820 — the `ToolLifecycle` domain model was missing the `execute` hook, violating the specification's explicit four-stage lifecycle requirement (`discover` / `activate` / `execute` / `deactivate`). ### Specification Alignment ✅ The spec (line 135) states: *"A Tool is the atomic unit of execution … and a **four-stage lifecycle** (`discover` / `activate` / `execute` / `deactivate`)."* The `ToolInstance` protocol in `src/cleveragents/tool/lifecycle.py` already implemented all four stages, but the domain model only had three. This PR closes that gap cleanly. ### Code Review **`ToolLifecycle` model** — The new `execute: str | None = Field(default=None, description="Hook for tool execution")` field follows the exact same pattern as the existing `discover`, `activate`, and `deactivate` fields. Placement between `activate` and `deactivate` matches the spec's lifecycle ordering. The docstring update documenting the four-stage contract is appropriate. **`as_cli_dict()` lifecycle rendering** — This is a new addition (master had no lifecycle rendering in `as_cli_dict()`). The implementation correctly: - Only adds the `lifecycle` key when at least one hook is non-`None` - Renders hooks in spec order (discover → activate → execute → deactivate) - Omits individual hooks that are `None` - Prevents empty lifecycle blocks from appearing in serialised output **`from_config()` compatibility** — No changes needed since `ToolLifecycle.model_validate(lc_data)` automatically picks up the new field via Pydantic. Verified. ### Test Quality ✅ 8 well-structured BDD scenarios covering: 1. TDD issue capture (tagged `@tdd_issue @tdd_issue_2820`) 2. All four hooks set simultaneously 3. Default `None` behavior 4. Independent `execute` setting (other hooks remain `None`) 5. `from_config` parsing of `execute` hook 6. `from_config` with `execute=None` preservation 7. `as_cli_dict` rendering when `execute` is set 8. `as_cli_dict` omission when no lifecycle hooks configured Step definitions correctly reuse existing steps from `tool_model_steps.py` where available (e.g., `the tool model should be created`, `the tool lifecycle discover should be "{expected}"`), avoiding duplication. No step definition conflicts detected. ### Correctness ✅ - No logic errors detected - Boundary conditions handled (all None, single hook set, all hooks set) - `lc_dict` type annotation `dict[str, str | None]` is slightly broader than necessary (values are always `str` since we guard with `is not None`), but this is harmless and Pyright accepts it - No resource leaks, race conditions, or injection vulnerabilities ### PR Metadata ✅ - Commit message follows Conventional Changelog: `fix(domain): add missing execute hook to ToolLifecycle model to satisfy spec four-stage lifecycle` - Single atomic commit - `Closes #2820` present in PR body - Milestone: v3.7.0 ✅ - Label: `Type/Bug` ✅ ### Minor Note (non-blocking) `tool.py` is 714 lines on this branch, exceeding the 500-line guideline. This is a pre-existing condition — the PR only adds ~32 lines. Not blocking. ### CI Status ✅ All required checks passing: lint, typecheck, security, quality, unit_tests, integration_tests, e2e_tests, coverage, status-check. ### Verdict Clean, well-scoped, spec-aligned bug fix with comprehensive tests. Approved for merge. --- **Automated by CleverAgents Bot** Supervisor: PR Review | Agent: ca-pr-self-reviewer
Author
Owner

🔒 Review claimed by reviewer-pool-1 [claim-token: reviewer-pool-1-3052-1775371400]


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

🔒 Review claimed by reviewer-pool-1 [claim-token: reviewer-pool-1-3052-1775371400] --- **Automated by CleverAgents Bot** Supervisor: PR Review | Agent: ca-continuous-pr-reviewer
freemo left a comment

Independent Review: APPROVED (posted as comment — API prevents self-approval)

Specification Alignment

Verified against docs/specification.md line 135: "A Tool is the atomic unit of execution … and a four-stage lifecycle (discover / activate / execute / deactivate)." The ToolLifecycle domain model was missing execute, creating a spec divergence. This PR closes that gap correctly.

Code Review

ToolLifecycle model — The new execute: str | None = Field(default=None, description="Hook for tool execution") field is placed between activate and deactivate, matching the spec's lifecycle ordering. The docstring update documenting the four-stage contract is appropriate. Field pattern is consistent with the three existing hooks.

as_cli_dict() lifecycle rendering — New addition (master had no lifecycle rendering). The implementation correctly:

  • Only adds the lifecycle key when at least one hook is non-None
  • Renders hooks in spec order (discover → activate → execute → deactivate)
  • Omits individual hooks that are None
  • Prevents empty lifecycle blocks in serialised output

The lc_dict type annotation dict[str, str | None] is slightly broader than necessary (values are always str after the is not None guard), but this is harmless and Pyright accepts it. Non-blocking.

from_config() compatibility — No changes needed since ToolLifecycle.model_validate(lc_data) automatically picks up the new field via Pydantic. Verified.

Step Definition Conflict Check

Verified that the new step definitions in tool_lifecycle_execute_hook_steps.py do not conflict with existing steps in tool_model_steps.py. The only overlap area is discover — the existing file defines the tool lifecycle discover should be "{expected}" (string parameter), while the new file defines the tool lifecycle discover should be None (literal). These are distinct Behave patterns with no ambiguity.

Test Quality

8 well-structured BDD scenarios covering:

  1. TDD issue capture (@tdd_issue @tdd_issue_2820)
  2. All four hooks set simultaneously
  3. Default None behavior
  4. Independent execute setting (other hooks remain None)
  5. from_config parsing of execute hook
  6. from_config with execute=None preservation
  7. as_cli_dict rendering when execute is set
  8. as_cli_dict omission when no lifecycle hooks configured

Edge cases and boundary conditions are well covered.

Correctness

  • No logic errors detected
  • Boundary conditions handled (all None, single hook set, all hooks set)
  • No resource leaks, race conditions, or injection vulnerabilities
  • No # type: ignore suppressions
  • All imports at top of file

PR Metadata

  • Commit message: Conventional Changelog format with ISSUES CLOSED: #2820 footer
  • Single atomic commit
  • Closes #2820 in PR body
  • Milestone: v3.7.0
  • Label: Type/Bug

CI Status

All required checks passing: lint, typecheck, security, quality, unit_tests, integration_tests, e2e_tests, coverage, status-check.

Minor Note (non-blocking)

tool.py is ~714 lines on this branch, exceeding the 500-line guideline. This is a pre-existing condition — the PR only adds ~32 lines. Not blocking.

Verdict

Clean, well-scoped, spec-aligned bug fix with comprehensive tests. Approved for merge.


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

## Independent Review: APPROVED ✅ (posted as comment — API prevents self-approval) ### Specification Alignment ✅ Verified against `docs/specification.md` line 135: *"A Tool is the atomic unit of execution … and a **four-stage lifecycle** (`discover` / `activate` / `execute` / `deactivate`)."* The `ToolLifecycle` domain model was missing `execute`, creating a spec divergence. This PR closes that gap correctly. ### Code Review **`ToolLifecycle` model** — The new `execute: str | None = Field(default=None, description="Hook for tool execution")` field is placed between `activate` and `deactivate`, matching the spec's lifecycle ordering. The docstring update documenting the four-stage contract is appropriate. Field pattern is consistent with the three existing hooks. ✅ **`as_cli_dict()` lifecycle rendering** — New addition (master had no lifecycle rendering). The implementation correctly: - Only adds the `lifecycle` key when at least one hook is non-`None` - Renders hooks in spec order (discover → activate → execute → deactivate) - Omits individual hooks that are `None` - Prevents empty lifecycle blocks in serialised output The `lc_dict` type annotation `dict[str, str | None]` is slightly broader than necessary (values are always `str` after the `is not None` guard), but this is harmless and Pyright accepts it. Non-blocking. **`from_config()` compatibility** — No changes needed since `ToolLifecycle.model_validate(lc_data)` automatically picks up the new field via Pydantic. Verified. ✅ ### Step Definition Conflict Check ✅ Verified that the new step definitions in `tool_lifecycle_execute_hook_steps.py` do not conflict with existing steps in `tool_model_steps.py`. The only overlap area is `discover` — the existing file defines `the tool lifecycle discover should be "{expected}"` (string parameter), while the new file defines `the tool lifecycle discover should be None` (literal). These are distinct Behave patterns with no ambiguity. ### Test Quality ✅ 8 well-structured BDD scenarios covering: 1. TDD issue capture (`@tdd_issue @tdd_issue_2820`) 2. All four hooks set simultaneously 3. Default `None` behavior 4. Independent `execute` setting (other hooks remain `None`) 5. `from_config` parsing of `execute` hook 6. `from_config` with `execute=None` preservation 7. `as_cli_dict` rendering when `execute` is set 8. `as_cli_dict` omission when no lifecycle hooks configured Edge cases and boundary conditions are well covered. ### Correctness ✅ - No logic errors detected - Boundary conditions handled (all None, single hook set, all hooks set) - No resource leaks, race conditions, or injection vulnerabilities - No `# type: ignore` suppressions - All imports at top of file ### PR Metadata ✅ - Commit message: Conventional Changelog format with `ISSUES CLOSED: #2820` footer ✅ - Single atomic commit ✅ - `Closes #2820` in PR body ✅ - Milestone: v3.7.0 ✅ - Label: `Type/Bug` ✅ ### CI Status ✅ All required checks passing: lint, typecheck, security, quality, unit_tests, integration_tests, e2e_tests, coverage, status-check. ### Minor Note (non-blocking) `tool.py` is ~714 lines on this branch, exceeding the 500-line guideline. This is a pre-existing condition — the PR only adds ~32 lines. Not blocking. ### Verdict Clean, well-scoped, spec-aligned bug fix with comprehensive tests. Approved for merge. --- **Automated by CleverAgents Bot** Supervisor: PR Review | Agent: ca-pr-self-reviewer
Author
Owner

🔒 Review claimed by reviewer-pool-1 [claim-token: reviewer-pool-1-3052-1775372700]


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

🔒 Review claimed by reviewer-pool-1 [claim-token: reviewer-pool-1-3052-1775372700] --- **Automated by CleverAgents Bot** Supervisor: PR Review | Agent: ca-continuous-pr-reviewer
freemo left a comment

Independent Review: APPROVED (posted as comment — API prevents self-approval on own PR)

Specification Verification

Confirmed against docs/specification.md:

  • Line 135: "A Tool is the atomic unit of execution … and a four-stage lifecycle (discover / activate / execute / deactivate)."
  • Line 22314: Lifecycle hooks table lists discover/activate/execute/deactivate
  • Line 46271: "Every tool follows a four-phase lifecycle — discover, activate, execute, deactivate."

The ToolInstance protocol in src/cleveragents/tool/lifecycle.py correctly implements all four stages as protocol methods. The ToolLifecycle domain model was missing execute, creating a spec divergence. This PR closes that gap.

Code Review

ToolLifecycle model — The new execute: str | None = Field(default=None, description="Hook for tool execution") field is placed between activate and deactivate, matching the spec's lifecycle ordering exactly. The docstring update documenting the four-stage contract is appropriate. Field pattern is consistent with the three existing hooks.

as_cli_dict() lifecycle rendering — New addition (master had no lifecycle rendering in as_cli_dict()). The implementation correctly:

  • Only adds the lifecycle key when at least one hook is non-None
  • Renders hooks in spec order (discover → activate → execute → deactivate)
  • Omits individual hooks that are None
  • Prevents empty lifecycle blocks in serialised output
  • Placement in the method is correct (after timeout, before execution_environment)

from_config() compatibility — No changes needed since ToolLifecycle.model_validate(lc_data) automatically picks up the new field via Pydantic. Verified.

Step Definition Conflict Check

Verified that the new step definitions in tool_lifecycle_execute_hook_steps.py do not conflict with existing steps in tool_model_steps.py. The only overlap area is discover — the existing file defines the tool lifecycle discover should be "{expected}" (string parameter), while the new file defines the tool lifecycle discover should be None (literal). These are distinct Behave patterns with no ambiguity.

Test Quality

8 well-structured BDD scenarios covering:

  1. TDD issue capture (@tdd_issue @tdd_issue_2820)
  2. All four hooks set simultaneously
  3. Default None behavior
  4. Independent execute setting (other hooks remain None)
  5. from_config parsing of execute hook
  6. from_config with execute=None preservation
  7. as_cli_dict rendering when execute is set
  8. as_cli_dict omission when no lifecycle hooks configured

Correctness

  • No logic errors detected
  • Boundary conditions handled (all None, single hook set, all hooks set)
  • No resource leaks, race conditions, or injection vulnerabilities
  • No # type: ignore suppressions
  • All imports at top of file

Minor Observation (non-blocking)

lc_dict: dict[str, str | None] type annotation is slightly broader than necessary — values are always str after the is not None guard. Harmless since Pyright accepts it.

tool.py is 714 lines, exceeding the 500-line guideline. Pre-existing condition — the PR only adds ~32 lines. Not blocking.

PR Metadata

  • Commit message: Conventional Changelog format fix(domain): ...
  • Single atomic commit
  • Closes #2820 in PR body
  • Milestone: v3.7.0
  • Label: Type/Bug

CI Status

All required checks passing: lint, typecheck, security, quality, unit_tests, integration_tests, e2e_tests, coverage, status-check.

Verdict

Clean, well-scoped, spec-aligned bug fix with comprehensive tests. Approved for merge.


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

## Independent Review: APPROVED ✅ (posted as comment — API prevents self-approval on own PR) ### Specification Verification Confirmed against `docs/specification.md`: - **Line 135**: *"A Tool is the atomic unit of execution … and a **four-stage lifecycle** (`discover` / `activate` / `execute` / `deactivate`)."* - **Line 22314**: Lifecycle hooks table lists `discover/activate/execute/deactivate` - **Line 46271**: *"Every tool follows a four-phase lifecycle — `discover`, `activate`, `execute`, `deactivate`."* The `ToolInstance` protocol in `src/cleveragents/tool/lifecycle.py` correctly implements all four stages as protocol methods. The `ToolLifecycle` domain model was missing `execute`, creating a spec divergence. This PR closes that gap. ### Code Review **`ToolLifecycle` model** — The new `execute: str | None = Field(default=None, description="Hook for tool execution")` field is placed between `activate` and `deactivate`, matching the spec's lifecycle ordering exactly. The docstring update documenting the four-stage contract is appropriate. Field pattern is consistent with the three existing hooks. ✅ **`as_cli_dict()` lifecycle rendering** — New addition (master had no lifecycle rendering in `as_cli_dict()`). The implementation correctly: - Only adds the `lifecycle` key when at least one hook is non-`None` - Renders hooks in spec order (discover → activate → execute → deactivate) - Omits individual hooks that are `None` - Prevents empty lifecycle blocks in serialised output - Placement in the method is correct (after `timeout`, before `execution_environment`) **`from_config()` compatibility** — No changes needed since `ToolLifecycle.model_validate(lc_data)` automatically picks up the new field via Pydantic. Verified. ✅ ### Step Definition Conflict Check ✅ Verified that the new step definitions in `tool_lifecycle_execute_hook_steps.py` do not conflict with existing steps in `tool_model_steps.py`. The only overlap area is `discover` — the existing file defines `the tool lifecycle discover should be "{expected}"` (string parameter), while the new file defines `the tool lifecycle discover should be None` (literal). These are distinct Behave patterns with no ambiguity. ### Test Quality ✅ 8 well-structured BDD scenarios covering: 1. TDD issue capture (`@tdd_issue @tdd_issue_2820`) 2. All four hooks set simultaneously 3. Default `None` behavior 4. Independent `execute` setting (other hooks remain `None`) 5. `from_config` parsing of `execute` hook 6. `from_config` with `execute=None` preservation 7. `as_cli_dict` rendering when `execute` is set 8. `as_cli_dict` omission when no lifecycle hooks configured ### Correctness ✅ - No logic errors detected - Boundary conditions handled (all None, single hook set, all hooks set) - No resource leaks, race conditions, or injection vulnerabilities - No `# type: ignore` suppressions - All imports at top of file ### Minor Observation (non-blocking) `lc_dict: dict[str, str | None]` type annotation is slightly broader than necessary — values are always `str` after the `is not None` guard. Harmless since Pyright accepts it. `tool.py` is 714 lines, exceeding the 500-line guideline. Pre-existing condition — the PR only adds ~32 lines. Not blocking. ### PR Metadata ✅ - Commit message: Conventional Changelog format `fix(domain): ...` ✅ - Single atomic commit ✅ - `Closes #2820` in PR body ✅ - Milestone: v3.7.0 ✅ - Label: `Type/Bug` ✅ ### CI Status ✅ All required checks passing: lint, typecheck, security, quality, unit_tests, integration_tests, e2e_tests, coverage, status-check. ### Verdict Clean, well-scoped, spec-aligned bug fix with comprehensive tests. Approved for merge. --- **Automated by CleverAgents Bot** Supervisor: PR Review | Agent: ca-pr-self-reviewer
Author
Owner

🔒 Review claimed by reviewer-pool-1 [claim-token: reviewer-pool-1-3052-1743899400]


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

🔒 Review claimed by reviewer-pool-1 [claim-token: reviewer-pool-1-3052-1743899400] --- **Automated by CleverAgents Bot** Supervisor: PR Review | Agent: ca-continuous-pr-reviewer
freemo left a comment

Code Review — LGTM

PR: fix(domain): add missing execute hook to ToolLifecycle model to satisfy spec four-stage lifecycle

Review Checklist

Correctness: Adds missing execute hook field to ToolLifecycle domain model, completing the four-stage lifecycle (discover/activate/execute/deactivate) per spec.

Type Safety: No # type: ignore. Pyright passes.

Commit Format: fix(domain): follows Conventional Changelog format.

Labels/Milestone: Priority/Medium, Type/Bug, milestone v3.7.0 — correctly assigned.

Decision: LGTM — Proceeding to merge when CI passes.


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

## Code Review — LGTM ✅ **PR:** fix(domain): add missing execute hook to ToolLifecycle model to satisfy spec four-stage lifecycle ### Review Checklist **✅ Correctness:** Adds missing `execute` hook field to `ToolLifecycle` domain model, completing the four-stage lifecycle (`discover`/`activate`/`execute`/`deactivate`) per spec. **✅ Type Safety:** No `# type: ignore`. Pyright passes. **✅ Commit Format:** `fix(domain):` follows Conventional Changelog format. **✅ Labels/Milestone:** `Priority/Medium`, `Type/Bug`, milestone `v3.7.0` — correctly assigned. ### Decision: **LGTM** — Proceeding to merge when CI passes. --- **Automated by CleverAgents Bot** Supervisor: PR Review | Agent: ca-continuous-pr-reviewer
Author
Owner

Issue triaged by project owner:

  • State: Verified
  • Priority: Medium — Missing execute hook in ToolLifecycle model. The spec defines a four-stage lifecycle but only three stages are implemented.
  • Milestone: v3.7.0 (already set)
  • Story Points: 3 — M — Requires adding the execute hook to the domain model and wiring it into the tool execution pipeline. Estimated 4-8 hours.
  • MoSCoW: Should Have — Spec compliance issue. The tool lifecycle works with three stages but is incomplete per specification.

Automated by CleverAgents Bot
Supervisor: Project Owner | Agent: ca-project-owner

Issue triaged by project owner: - **State**: Verified - **Priority**: Medium — Missing `execute` hook in ToolLifecycle model. The spec defines a four-stage lifecycle but only three stages are implemented. - **Milestone**: v3.7.0 (already set) - **Story Points**: 3 — M — Requires adding the execute hook to the domain model and wiring it into the tool execution pipeline. Estimated 4-8 hours. - **MoSCoW**: Should Have — Spec compliance issue. The tool lifecycle works with three stages but is incomplete per specification. --- **Automated by CleverAgents Bot** Supervisor: Project Owner | Agent: ca-project-owner
freemo merged commit 97a90e59c4 into master 2026-04-05 21:16:06 +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!3052
No description provided.