feat(decision): add decision persistence layer #131

Merged
hamza.khyari merged 2 commits from feature/m4-decision-persistence into master 2026-02-26 14:25:27 +00:00
Member

Metadata

  • Commit Message: feat(decision): add decision persistence layer
  • Branch: feature/m4-decision-persistence

Background

This PR implements the decision persistence layer for Milestone 3 (v3.2.0). It adds the ability to persist decision records to the SQLite database, enabling decision trees to be recorded during strategize and queried via CLI commands.

Related issue: #171

Expected Behavior

Decision records are persisted to SQLite with full context snapshots. The decision persistence layer supports CRUD operations and integrates with the plan execution lifecycle.

Acceptance Criteria

  • Decision model persists to SQLite via repository pattern
  • Decision records include context snapshots
  • CRUD operations work for decision lifecycle
  • Existing tests pass with no regressions
  • Coverage remains >=97%

Definition of Done

This PR is complete when:

  • All acceptance criteria above are met.
  • Code review is approved.
  • CI passes (nox full suite, coverage >=97%).
  • PR is merged to master.
## Metadata - **Commit Message**: `feat(decision): add decision persistence layer` - **Branch**: `feature/m4-decision-persistence` ## Background This PR implements the decision persistence layer for Milestone 3 (v3.2.0). It adds the ability to persist decision records to the SQLite database, enabling decision trees to be recorded during strategize and queried via CLI commands. Related issue: #171 ## Expected Behavior Decision records are persisted to SQLite with full context snapshots. The decision persistence layer supports CRUD operations and integrates with the plan execution lifecycle. ## Acceptance Criteria - [x] Decision model persists to SQLite via repository pattern - [x] Decision records include context snapshots - [x] CRUD operations work for decision lifecycle - [x] Existing tests pass with no regressions - [x] Coverage remains >=97% ## Definition of Done This PR is complete when: - All acceptance criteria above are met. - Code review is approved. - CI passes (nox full suite, coverage >=97%). - PR is merged to master.
hamza.khyari marked the pull request as work in progress 2026-02-20 15:34:18 +00:00
hamza.khyari changed title from WIP: feat(db): add decision tables and repositories [H-19/H-20, D5.db/D5.repo] to feat(decision): add decision persistence layer [H-19, M3.2] 2026-02-23 15:54:56 +00:00
freemo added this to the v3.2.0 milestone 2026-02-23 17:26:17 +00:00
Owner

Relates to #171

Relates to #171
hamza.khyari changed target branch from develop-hamza-2 to master 2026-02-23 22:56:04 +00:00
Owner

Note: This PR (feature/m4-decision-persistence) is a duplicate tracking path. The properly scoped issue for this work is #171 (feat(decision): add decision persistence). This PR's branch exists on the remote and appears to contain Hamza's active work. The PR should be retargeted and associated with issue #171 once ready for review.

Note: This PR (`feature/m4-decision-persistence`) is a duplicate tracking path. The properly scoped issue for this work is #171 (feat(decision): add decision persistence). This PR's branch exists on the remote and appears to contain Hamza's active work. The PR should be retargeted and associated with issue #171 once ready for review.
freemo added the
MoSCoW
Must have
Points
8
Priority
High
State
In Review
Type
Feature
labels 2026-02-24 03:36:43 +00:00
hamza.khyari was assigned by freemo 2026-02-24 03:37:54 +00:00
hamza.khyari force-pushed feature/m4-decision-persistence from 89a374a296 to d0feda432a 2026-02-24 17:39:09 +00:00 Compare
hamza.khyari force-pushed feature/m4-decision-persistence from 9f36e8f848 to 78c3e5dc01 2026-02-24 17:46:56 +00:00 Compare
hamza.khyari force-pushed feature/m4-decision-persistence from 78c3e5dc01 to 42c9ee85d4 2026-02-24 20:09:33 +00:00 Compare
freemo force-pushed feature/m4-decision-persistence from 42c9ee85d4 to f88a4a1290 2026-02-24 20:50:24 +00:00 Compare
freemo requested changes 2026-02-24 22:27:54 +00:00
Dismissed
freemo left a comment
Owner

Code Review: PR #131feat(decision): add decision persistence layer [H-19, M3.2]

This PR implements a well-scoped decision persistence subsystem with proper repository pattern architecture. The branch name matches issue #171's metadata, and the overall structure (models, repository, migration, tests, docs, benchmarks) is thorough. However, several process and code quality issues need attention.

Process Issues

1. Commit message mismatch with issue metadata
Issue #171 specifies the commit message first line as: feat(decision): add decision persistence
The actual commit message is: feat(decision): add decision persistence layer
Per the issue's Definition of Done: "the first line of the commit message matches the Commit Message in Metadata exactly."

2. No issue references in commit footers (CONTRIBUTING.md §4)
Neither commit (feat(decision): add decision persistence layer nor fix(decision): use setattr for ORM attribute write to satisfy pyright) has a footer referencing issue #171. Per guidelines, every commit must reference its associated issue (e.g., ISSUES CLOSED: #171 or Refs: #171).

3. No CHANGELOG update (CONTRIBUTING.md §6)
A +2,349 line PR adding a new persistence subsystem requires a CHANGELOG entry describing the change from the user's perspective.

4. No CONTRIBUTORS.md update (CONTRIBUTING.md §8)
Hamza Khyari should be added to CONTRIBUTORS.md if not already listed.

5. Improper labels on PR (CONTRIBUTING.md §12)
This PR carries MoSCoW/Must have, Points/8, and enhancement labels. Per guidelines: "No other label scopes (State/, Priority/, MoSCoW/) are applied to Pull Requests." The PR should have only Type/Feature. Remove MoSCoW/Must have, Points/8, and enhancement.

Code Quality Issues

6. Overuse of Any types (CONTRIBUTING.md — Type Safety)
DecisionRepository uses Any extensively where the concrete Decision type should be specified:

  • create(self, decision: Any) -> Any
  • get(self, decision_id: str) -> Any | None
  • get_by_plan(self, plan_id: str) -> list[Any]
  • get_tree(self, root_decision_id: str) -> list[Any]
  • to_domain(self) -> Any
  • from_domain(cls, decision: Any) -> DecisionModel

Per CONTRIBUTING.md: "every function signature, variable declaration, and return type should be annotated with explicit types." If this is to avoid circular imports, use TYPE_CHECKING:

from __future__ import annotations
from typing import TYPE_CHECKING
if TYPE_CHECKING:
    from cleveragents.domain.decisions import Decision

7. Missing type annotations in Robot helper
robot/helper_decision_persistence.py has 12 functions all lacking type annotations (parameter types and return types). While these are module-private, the project standard requires full annotations.

8. BFS uses list.pop(0) — O(n) per operation
In DecisionRepository.get_tree():

queue = [root_decision_id]
while queue:
    parent_id = queue.pop(0)  # O(n) operation

This should use collections.deque for O(1) popleft. For large decision trees this becomes a performance concern:

from collections import deque
queue = deque([root_decision_id])
while queue:
    parent_id = queue.popleft()  # O(1) operation

What's Good

  • Single feature scope (decision persistence only) — properly scoped PR
  • Correct branch name matching issue #171 metadata
  • Proper milestone assignment (v3.2.0)
  • Repository pattern with proper separation of concerns
  • Complete test coverage (Behave scenarios, Robot tests, ASV benchmarks)
  • Alembic migration included
  • Documentation updated (database_schema.md)
  • Existing maintainer comments acknowledged (#171 linkage)

Action Items

  1. Fix commit message to match issue metadata exactly.
  2. Add issue references to commit footers.
  3. Add CHANGELOG entry.
  4. Add CONTRIBUTORS.md entry.
  5. Replace Any types with concrete Decision type using TYPE_CHECKING.
  6. Add type annotations to Robot helper functions.
  7. Replace list.pop(0) with deque.popleft() in get_tree().
  8. Fix PR labels to only Type/Feature.
## Code Review: PR #131 — `feat(decision): add decision persistence layer [H-19, M3.2]` This PR implements a well-scoped decision persistence subsystem with proper repository pattern architecture. The branch name matches issue #171's metadata, and the overall structure (models, repository, migration, tests, docs, benchmarks) is thorough. However, several process and code quality issues need attention. ### Process Issues **1. Commit message mismatch with issue metadata** Issue #171 specifies the commit message first line as: `feat(decision): add decision persistence` The actual commit message is: `feat(decision): add decision persistence layer` Per the issue's Definition of Done: "the first line of the commit message matches the Commit Message in Metadata exactly." **2. No issue references in commit footers (CONTRIBUTING.md §4)** Neither commit (`feat(decision): add decision persistence layer` nor `fix(decision): use setattr for ORM attribute write to satisfy pyright`) has a footer referencing issue #171. Per guidelines, every commit must reference its associated issue (e.g., `ISSUES CLOSED: #171` or `Refs: #171`). **3. No CHANGELOG update (CONTRIBUTING.md §6)** A +2,349 line PR adding a new persistence subsystem requires a CHANGELOG entry describing the change from the user's perspective. **4. No CONTRIBUTORS.md update (CONTRIBUTING.md §8)** Hamza Khyari should be added to CONTRIBUTORS.md if not already listed. **5. Improper labels on PR (CONTRIBUTING.md §12)** This PR carries `MoSCoW/Must have`, `Points/8`, and `enhancement` labels. Per guidelines: "No other label scopes (`State/`, `Priority/`, `MoSCoW/`) are applied to Pull Requests." The PR should have only `Type/Feature`. Remove `MoSCoW/Must have`, `Points/8`, and `enhancement`. ### Code Quality Issues **6. Overuse of `Any` types (CONTRIBUTING.md — Type Safety)** `DecisionRepository` uses `Any` extensively where the concrete `Decision` type should be specified: - `create(self, decision: Any) -> Any` - `get(self, decision_id: str) -> Any | None` - `get_by_plan(self, plan_id: str) -> list[Any]` - `get_tree(self, root_decision_id: str) -> list[Any]` - `to_domain(self) -> Any` - `from_domain(cls, decision: Any) -> DecisionModel` Per CONTRIBUTING.md: "every function signature, variable declaration, and return type should be annotated with explicit types." If this is to avoid circular imports, use `TYPE_CHECKING`: ```python from __future__ import annotations from typing import TYPE_CHECKING if TYPE_CHECKING: from cleveragents.domain.decisions import Decision ``` **7. Missing type annotations in Robot helper** `robot/helper_decision_persistence.py` has 12 functions all lacking type annotations (parameter types and return types). While these are module-private, the project standard requires full annotations. **8. BFS uses `list.pop(0)` — O(n) per operation** In `DecisionRepository.get_tree()`: ```python queue = [root_decision_id] while queue: parent_id = queue.pop(0) # O(n) operation ``` This should use `collections.deque` for O(1) popleft. For large decision trees this becomes a performance concern: ```python from collections import deque queue = deque([root_decision_id]) while queue: parent_id = queue.popleft() # O(1) operation ``` ### What's Good - Single feature scope (decision persistence only) — properly scoped PR - Correct branch name matching issue #171 metadata - Proper milestone assignment (v3.2.0) - Repository pattern with proper separation of concerns - Complete test coverage (Behave scenarios, Robot tests, ASV benchmarks) - Alembic migration included - Documentation updated (database_schema.md) - Existing maintainer comments acknowledged (#171 linkage) ### Action Items 1. Fix commit message to match issue metadata exactly. 2. Add issue references to commit footers. 3. Add CHANGELOG entry. 4. Add CONTRIBUTORS.md entry. 5. Replace `Any` types with concrete `Decision` type using `TYPE_CHECKING`. 6. Add type annotations to Robot helper functions. 7. Replace `list.pop(0)` with `deque.popleft()` in `get_tree()`. 8. Fix PR labels to only `Type/Feature`.
freemo dismissed freemo's review 2026-02-24 22:44:50 +00:00
Reason:

dont want hard block

hamza.khyari removed the
Priority
High
Points
8
MoSCoW
Must have
labels 2026-02-25 15:05:55 +00:00
hamza.khyari force-pushed feature/m4-decision-persistence from f88a4a1290 to 8e56067dbb 2026-02-25 15:25:23 +00:00 Compare
freemo added a new dependency 2026-02-25 18:17:50 +00:00
hamza.khyari requested review from brent.edwards 2026-02-26 00:37:19 +00:00
brent.edwards approved these changes 2026-02-26 00:52:35 +00:00
Dismissed
brent.edwards left a comment
Member

Looks good to me!

Looks good to me!
hamza.khyari force-pushed feature/m4-decision-persistence from 8e56067dbb to 6083747cb8 2026-02-26 01:02:23 +00:00 Compare
hamza.khyari dismissed brent.edwards's review 2026-02-26 01:02:24 +00:00
Reason:

New commits pushed, approval review dismissed automatically according to repository settings

hamza.khyari changed title from feat(decision): add decision persistence layer [H-19, M3.2] to feat(decision): add decision persistence layer 2026-02-26 01:29:49 +00:00
hamza.khyari force-pushed feature/m4-decision-persistence from 6083747cb8 to f29e485f71 2026-02-26 01:38:38 +00:00 Compare
hamza.khyari scheduled this pull request to auto merge when all checks succeed 2026-02-26 02:22:00 +00:00
hamza.khyari force-pushed feature/m4-decision-persistence from f29e485f71 to 38fa95a70c 2026-02-26 12:35:27 +00:00 Compare
hamza.khyari force-pushed feature/m4-decision-persistence from 5d3a0f48ec to 7f2b1c61fc 2026-02-26 13:40:47 +00:00 Compare
hamza.khyari merged commit db58a3bb62 into master 2026-02-26 14:25:27 +00:00
hamza.khyari removed the
State
In Review
label 2026-02-26 15:35:49 +00:00
freemo added the
State
Completed
label 2026-03-04 00:59:16 +00:00
Sign in to join this conversation.
No Reviewers
3 Participants
Notifications
Due Date
No due date set.
Blocks
Reference: cleveragents/cleveragents-core#131