UAT: DecisionService._record_dependencies does not persist influence edges to decision_dependencies table — edges lost on service restart #3569

Open
opened 2026-04-05 19:50:04 +00:00 by freemo · 2 comments
Owner

Metadata

  • Branch: fix/decision-service-persist-influence-edges
  • Commit Message: fix(decision): persist influence edges to decision_dependencies table in _record_dependencies
  • Milestone: None (backlog — see note below)
  • Parent Epic: #394

Background

The DecisionService._record_dependencies() method in
src/cleveragents/application/services/decision_service.py (lines 910–933)
claims in its docstring to persist influence edges to the
decision_dependencies table when a UnitOfWork is wired, but the
implementation only stores edges in the in-memory self._dependencies dict.
No database write occurs.

Per spec §Dual Structure: Structural Tree and Influence DAG, the
decision_dependencies table is the durable store for influence edges between
decisions. When record_decision() is called with dependency_decision_ids,
each upstream→downstream edge must be persisted so that the influence DAG
survives service restarts.

Bug Report

Expected behaviour (per spec §Dual Structure: Structural Tree and Influence DAG):
Each upstream→downstream influence edge is written to the
decision_dependencies table via the UnitOfWork whenever
_record_dependencies() is called in persisted mode. After a service restart,
get_influence_edges() reconstructs the full influence DAG from the database.

Actual behaviour:
_record_dependencies() only appends to self._dependencies (in-memory
dict). No INSERT INTO decision_dependencies is executed. After a service
restart, all influence edges are lost.

Consequence:
get_influence_edges() (lines 935–957) also reads only from
self._dependencies. After a restart, CorrectionService.analyze_impact()
receives an empty influence DAG and computes an incomplete affected subtree —
missing decisions that are only reachable via influence edges, not structural
parent-child links.

Steps to reproduce:

  1. Create a DecisionService with a UnitOfWork (persisted mode).
  2. Record two decisions D1 and D2 with dependency_decision_ids=[D1.decision_id] for D2.
  3. Restart the service (create a new DecisionService instance with the same UnitOfWork).
  4. Call get_influence_edges(plan_id) — returns empty dict.
  5. Call analyze_impact() — affected subtree is incomplete (misses D2 if only reachable via influence edge).

Code locations:

  • src/cleveragents/application/services/decision_service.py, lines 910–933 (_record_dependencies)
  • src/cleveragents/application/services/decision_service.py, lines 935–957 (get_influence_edges)
  • src/cleveragents/infrastructure/database/models.py, lines 2905–2940 (DecisionDependencyModel — table exists but is never written to by DecisionService)

Subtasks

  • Add a DecisionDependencyRepository method (or use the existing UoW pattern) to insert a row into decision_dependencies for each upstream→downstream edge
  • Update _record_dependencies(): when self._persisted is True, write each edge to the decision_dependencies table via the UnitOfWork in addition to updating self._dependencies
  • Update get_influence_edges(): when self._persisted is True, query the decision_dependencies table (via the UnitOfWork) instead of (or merged with) the in-memory dict, so that edges survive restarts
  • Write BDD scenarios (Behave/Gherkin) in features/ covering: (a) edges are persisted on record_decision, (b) edges are recovered after service restart, (c) CorrectionService.analyze_impact() returns the full affected subtree when influence edges exist only in the DB
  • Add Robot Framework integration test in robot/ verifying end-to-end: record → restart → get_influence_edgesanalyze_impact returns complete subtree
  • Ensure all new code passes nox -e typecheck (Pyright, no # type: ignore)
  • Ensure nox -e lint passes with no new violations
  • Verify nox -e coverage_report remains ≥ 97%

Definition of Done

  • All subtasks above are checked off
  • _record_dependencies() writes influence edges to decision_dependencies table when in persisted mode
  • get_influence_edges() reads from decision_dependencies table when in persisted mode, returning correct edges after a service restart
  • CorrectionService.analyze_impact() returns the complete affected subtree (including decisions reachable only via influence edges) after a service restart
  • BDD unit test scenarios pass (nox -e unit_tests)
  • Robot Framework integration tests pass (nox -e integration_tests)
  • All nox stages pass (nox)
  • Coverage ≥ 97%
  • Work is committed using the exact branch and commit message from the Metadata section above
  • A pull request has been created, reviewed (≥ 2 approvals), and merged

Backlog note: This issue was discovered during autonomous operation
on milestone v3.2.0. It does not block milestone completion and has been
placed in the backlog for human review and future milestone assignment.


Automated by CleverAgents Bot
Supervisor: Acting on behalf of: UAT Testing | Agent: ca-new-issue-creator

## Metadata - **Branch**: `fix/decision-service-persist-influence-edges` - **Commit Message**: `fix(decision): persist influence edges to decision_dependencies table in _record_dependencies` - **Milestone**: None (backlog — see note below) - **Parent Epic**: #394 ## Background The `DecisionService._record_dependencies()` method in `src/cleveragents/application/services/decision_service.py` (lines 910–933) claims in its docstring to persist influence edges to the `decision_dependencies` table when a `UnitOfWork` is wired, but the implementation only stores edges in the in-memory `self._dependencies` dict. No database write occurs. Per spec §**Dual Structure: Structural Tree and Influence DAG**, the `decision_dependencies` table is the durable store for influence edges between decisions. When `record_decision()` is called with `dependency_decision_ids`, each upstream→downstream edge must be persisted so that the influence DAG survives service restarts. ## Bug Report **Expected behaviour** (per spec §Dual Structure: Structural Tree and Influence DAG): Each upstream→downstream influence edge is written to the `decision_dependencies` table via the `UnitOfWork` whenever `_record_dependencies()` is called in persisted mode. After a service restart, `get_influence_edges()` reconstructs the full influence DAG from the database. **Actual behaviour**: `_record_dependencies()` only appends to `self._dependencies` (in-memory dict). No `INSERT INTO decision_dependencies` is executed. After a service restart, all influence edges are lost. **Consequence**: `get_influence_edges()` (lines 935–957) also reads only from `self._dependencies`. After a restart, `CorrectionService.analyze_impact()` receives an empty influence DAG and computes an incomplete affected subtree — missing decisions that are only reachable via influence edges, not structural parent-child links. **Steps to reproduce**: 1. Create a `DecisionService` with a `UnitOfWork` (persisted mode). 2. Record two decisions D1 and D2 with `dependency_decision_ids=[D1.decision_id]` for D2. 3. Restart the service (create a new `DecisionService` instance with the same `UnitOfWork`). 4. Call `get_influence_edges(plan_id)` — returns empty dict. 5. Call `analyze_impact()` — affected subtree is incomplete (misses D2 if only reachable via influence edge). **Code locations**: - `src/cleveragents/application/services/decision_service.py`, lines 910–933 (`_record_dependencies`) - `src/cleveragents/application/services/decision_service.py`, lines 935–957 (`get_influence_edges`) - `src/cleveragents/infrastructure/database/models.py`, lines 2905–2940 (`DecisionDependencyModel` — table exists but is never written to by `DecisionService`) ## Subtasks - [ ] Add a `DecisionDependencyRepository` method (or use the existing UoW pattern) to insert a row into `decision_dependencies` for each upstream→downstream edge - [ ] Update `_record_dependencies()`: when `self._persisted` is `True`, write each edge to the `decision_dependencies` table via the `UnitOfWork` in addition to updating `self._dependencies` - [ ] Update `get_influence_edges()`: when `self._persisted` is `True`, query the `decision_dependencies` table (via the `UnitOfWork`) instead of (or merged with) the in-memory dict, so that edges survive restarts - [ ] Write BDD scenarios (Behave/Gherkin) in `features/` covering: (a) edges are persisted on `record_decision`, (b) edges are recovered after service restart, (c) `CorrectionService.analyze_impact()` returns the full affected subtree when influence edges exist only in the DB - [ ] Add Robot Framework integration test in `robot/` verifying end-to-end: record → restart → `get_influence_edges` → `analyze_impact` returns complete subtree - [ ] Ensure all new code passes `nox -e typecheck` (Pyright, no `# type: ignore`) - [ ] Ensure `nox -e lint` passes with no new violations - [ ] Verify `nox -e coverage_report` remains ≥ 97% ## Definition of Done - [ ] All subtasks above are checked off - [ ] `_record_dependencies()` writes influence edges to `decision_dependencies` table when in persisted mode - [ ] `get_influence_edges()` reads from `decision_dependencies` table when in persisted mode, returning correct edges after a service restart - [ ] `CorrectionService.analyze_impact()` returns the complete affected subtree (including decisions reachable only via influence edges) after a service restart - [ ] BDD unit test scenarios pass (`nox -e unit_tests`) - [ ] Robot Framework integration tests pass (`nox -e integration_tests`) - [ ] All nox stages pass (`nox`) - [ ] Coverage ≥ 97% - [ ] Work is committed using the exact branch and commit message from the Metadata section above - [ ] A pull request has been created, reviewed (≥ 2 approvals), and merged > **Backlog note:** This issue was discovered during autonomous operation > on milestone v3.2.0. It does not block milestone completion and has been > placed in the backlog for human review and future milestone assignment. --- **Automated by CleverAgents Bot** Supervisor: Acting on behalf of: UAT Testing | Agent: ca-new-issue-creator
freemo added this to the v3.4.0 milestone 2026-04-05 20:04:15 +00:00
Author
Owner

Issue triaged by project owner:

  • State: Verified
  • Priority: High — Data persistence bug causing influence edges to be lost on service restart. This directly impacts CorrectionService.analyze_impact() correctness, producing incomplete affected subtrees. Per spec §Dual Structure: Structural Tree and Influence DAG, the decision_dependencies table is the durable store and must be written to.
  • Milestone: v3.4.0
  • Story Points: 3 — M — Requires adding repository write logic, updating two methods, and writing BDD + Robot Framework tests. Clear fix path with well-defined scope.
  • MoSCoW: Should Have — The influence DAG persistence is important for decision pipeline integrity. The spec explicitly requires durable storage of influence edges. However, the issue itself notes it does not block milestone completion, and the in-memory path works within a single session.
  • Parent Epic: #394 (dependency link already exists)

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

Issue triaged by project owner: - **State**: Verified - **Priority**: High — Data persistence bug causing influence edges to be lost on service restart. This directly impacts `CorrectionService.analyze_impact()` correctness, producing incomplete affected subtrees. Per spec §Dual Structure: Structural Tree and Influence DAG, the `decision_dependencies` table is the durable store and must be written to. - **Milestone**: v3.4.0 - **Story Points**: 3 — M — Requires adding repository write logic, updating two methods, and writing BDD + Robot Framework tests. Clear fix path with well-defined scope. - **MoSCoW**: Should Have — The influence DAG persistence is important for decision pipeline integrity. The spec explicitly requires durable storage of influence edges. However, the issue itself notes it does not block milestone completion, and the in-memory path works within a single session. - **Parent Epic**: #394 (dependency link already exists) --- **Automated by CleverAgents Bot** Supervisor: Project Owner | Agent: ca-project-owner
freemo removed this from the v3.4.0 milestone 2026-04-06 21:04:24 +00:00
HAL9000 self-assigned this 2026-04-08 18:51:55 +00:00
HAL9000 added this to the v3.7.0 milestone 2026-04-08 18:51:55 +00:00
Owner

Issue assigned to @HAL9000 and milestone set to v3.7.0.

Milestone Rationale: DecisionService persistence of influence edges is part of the decision management system. v3.7.0 covers advanced service features.

Assignment Rationale: Default assignment to HAL9000 to maintain velocity.


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

Issue assigned to @HAL9000 and milestone set to **v3.7.0**. **Milestone Rationale**: DecisionService persistence of influence edges is part of the decision management system. v3.7.0 covers advanced service features. **Assignment Rationale**: Default assignment to HAL9000 to maintain velocity. --- **Automated by CleverAgents Bot** Supervisor: Project Owner | Agent: project-owner
Sign in to join this conversation.
No milestone
No project
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Blocks
#394 Epic: Decision Framework
cleveragents/cleveragents-core
Reference
cleveragents/cleveragents-core#3569
No description provided.