UAT: decision_dependencies influence edges not persisted to database — DecisionService._record_dependencies() only updates in-memory dict #5899

Open
opened 2026-04-09 11:37:42 +00:00 by HAL9000 · 0 comments
Owner

Summary

DecisionService._record_dependencies() records influence edges (upstream decision → downstream decision) only in the in-memory _dependencies dict. When a UnitOfWork is wired for database persistence, these edges are never written to the decision_dependencies table. The DecisionRepository has no create_dependency method, and _record_dependencies never calls any persistence layer.

What Was Tested

  • Code-level analysis of DecisionService._record_dependencies() in decision_service.py
  • Code-level analysis of DecisionRepository in repositories.py
  • Code-level analysis of DecisionDependencyModel in models.py
  • Review of DecisionService.get_influence_edges() — only reads from in-memory dict

Expected Behavior (from spec)

Per DecisionService.record_decision() docstring:

When dependency_decision_ids is provided, each upstream decision ID is recorded as an influence edge in the decision_dependencies store. This populates the influence DAG used by CorrectionService._compute_affected_subtree() to determine which downstream decisions are transitively affected by a correction.

The decision_dependencies table exists in the DB schema (DecisionDependencyModel in models.py) with proper foreign keys and indexes. It is designed to persist these edges.

Actual Behavior

_record_dependencies() in decision_service.py:

def _record_dependencies(
    self,
    decision_id: str,
    upstream_ids: list[str],
) -> None:
    for upstream_id in upstream_ids:
        if not upstream_id or not upstream_id.strip():
            continue
        self._dependencies.setdefault(upstream_id, []).append(decision_id)
        self._logger.debug(
            "decision.dependency_recorded",
            source=upstream_id,
            target=decision_id,
        )

This method only updates self._dependencies (an in-memory dict). There is no call to ctx.decisions.create_dependency() or any equivalent. The DecisionRepository class has no method for persisting dependency edges.

get_influence_edges() also only reads from self._dependencies:

def get_influence_edges(self, plan_id: str) -> dict[str, list[str]]:
    plan_decision_ids = set(self._plan_decisions.get(plan_id, []))
    edges: dict[str, list[str]] = {}
    for source, targets in self._dependencies.items():
        ...
    return edges

After a service restart, all dependency edges are lost.

Code Locations

  • src/cleveragents/application/services/decision_service.py, _record_dependencies() and get_influence_edges()
  • src/cleveragents/infrastructure/database/repositories.py, DecisionRepository — no create_dependency method
  • src/cleveragents/infrastructure/database/models.py, DecisionDependencyModel — table exists but is never written to

Impact

  • Decision influence DAG is lost on service restart
  • CorrectionService._compute_affected_subtree() will return empty results after restart, causing corrections to miss affected downstream decisions
  • The correction model's "selective subtree recomputation" feature is broken across process boundaries
  • The decision_dependencies table is dead code — it exists in the schema but is never populated

Automated by CleverAgents Bot
Supervisor: UAT Testing | Agent: uat-tester

## Summary `DecisionService._record_dependencies()` records influence edges (upstream decision → downstream decision) only in the in-memory `_dependencies` dict. When a `UnitOfWork` is wired for database persistence, these edges are **never written to the `decision_dependencies` table**. The `DecisionRepository` has no `create_dependency` method, and `_record_dependencies` never calls any persistence layer. ## What Was Tested - Code-level analysis of `DecisionService._record_dependencies()` in `decision_service.py` - Code-level analysis of `DecisionRepository` in `repositories.py` - Code-level analysis of `DecisionDependencyModel` in `models.py` - Review of `DecisionService.get_influence_edges()` — only reads from in-memory dict ## Expected Behavior (from spec) Per `DecisionService.record_decision()` docstring: > When `dependency_decision_ids` is provided, each upstream decision ID is recorded as an influence edge in the `decision_dependencies` store. This populates the influence DAG used by `CorrectionService._compute_affected_subtree()` to determine which downstream decisions are transitively affected by a correction. The `decision_dependencies` table exists in the DB schema (`DecisionDependencyModel` in `models.py`) with proper foreign keys and indexes. It is designed to persist these edges. ## Actual Behavior `_record_dependencies()` in `decision_service.py`: ```python def _record_dependencies( self, decision_id: str, upstream_ids: list[str], ) -> None: for upstream_id in upstream_ids: if not upstream_id or not upstream_id.strip(): continue self._dependencies.setdefault(upstream_id, []).append(decision_id) self._logger.debug( "decision.dependency_recorded", source=upstream_id, target=decision_id, ) ``` This method **only updates `self._dependencies`** (an in-memory dict). There is no call to `ctx.decisions.create_dependency()` or any equivalent. The `DecisionRepository` class has no method for persisting dependency edges. `get_influence_edges()` also only reads from `self._dependencies`: ```python def get_influence_edges(self, plan_id: str) -> dict[str, list[str]]: plan_decision_ids = set(self._plan_decisions.get(plan_id, [])) edges: dict[str, list[str]] = {} for source, targets in self._dependencies.items(): ... return edges ``` After a service restart, all dependency edges are lost. ## Code Locations - `src/cleveragents/application/services/decision_service.py`, `_record_dependencies()` and `get_influence_edges()` - `src/cleveragents/infrastructure/database/repositories.py`, `DecisionRepository` — no `create_dependency` method - `src/cleveragents/infrastructure/database/models.py`, `DecisionDependencyModel` — table exists but is never written to ## Impact - Decision influence DAG is lost on service restart - `CorrectionService._compute_affected_subtree()` will return empty results after restart, causing corrections to miss affected downstream decisions - The correction model's "selective subtree recomputation" feature is broken across process boundaries - The `decision_dependencies` table is dead code — it exists in the schema but is never populated --- **Automated by CleverAgents Bot** Supervisor: UAT Testing | Agent: uat-tester
Sign in to join this conversation.
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.

Reference
cleveragents/cleveragents-core#5899
No description provided.