BUG-HUNT: [data-integrity] changeset_repository.py get_for_plan merges all changeset entries into one — loses per-changeset granularity #7502

Open
opened 2026-04-10 20:51:46 +00:00 by HAL9000 · 4 comments
Owner

Bug Report: Data Integrity — SqliteChangeSetStore.get_for_plan Returns Single Merged Changeset

Severity Assessment

  • Impact: Multiple changesets for the same plan are merged into one — callers cannot distinguish between separate changeset scopes; version history and rollback granularity are lost
  • Likelihood: High — any plan with more than one changeset affected
  • Priority: Medium

Location

  • File: src/cleveragents/infrastructure/database/changeset_repository.py
  • Function: SqliteChangeSetStore.get_for_plan
  • Lines: ~451–465
  • Category: data-integrity / incorrect-logic

Description

A plan can have multiple changesets (each call to start() creates a new one). get_for_plan merges ALL entries across ALL changesets into one synthetic SpecChangeSet, losing the per-changeset granularity. Callers expecting one SpecChangeSet per start() call will get incorrect data — a single "mega-changeset" combining all subplan scopes.

Evidence

def get_for_plan(self, plan_id: str) -> list[SpecChangeSet]:
    entries = self._entry_repo.get_entries_for_plan(plan_id)
    if not entries:
        return []
    return [
        SpecChangeSet(plan_id=plan_id, entries=entries),  # ONE changeset with ALL entries
    ]

Scenario:

  1. changeset_a = store.start(plan_id) — Scope A started
  2. changeset_b = store.start(plan_id) — Scope B started
  3. Each scope records distinct entries
  4. store.get_for_plan(plan_id) → returns [SpecChangeSet(entries=scope_A_entries + scope_B_entries)]
  5. Caller cannot distinguish what was changed in scope A vs scope B

Expected Behavior

get_for_plan should return one SpecChangeSet per start() invocation, grouped by changeset ID.

Actual Behavior

All entries across all changesets are merged into one SpecChangeSet with no changeset-level grouping.

Suggested Fix

Group entries by changeset_id and return one per group:

def get_for_plan(self, plan_id: str) -> list[SpecChangeSet]:
    entries = self._entry_repo.get_entries_for_plan(plan_id)
    if not entries:
        return []
    grouped: dict[str, list] = {}
    for entry in entries:
        grouped.setdefault(entry.changeset_id, []).append(entry)
    return [
        SpecChangeSet(plan_id=plan_id, entries=group_entries)
        for group_entries in grouped.values()
    ]

Category

data-integrity

TDD Note

After this bug issue is verified, a corresponding Type/Testing issue will be created for TDD. The test will use tags: @tdd_issue, @tdd_issue_, and @tdd_expected_fail to prove the bug exists before fixing it.


Automated by CleverAgents Bot
Supervisor: Bug Detection Pool | Agent: bug-hunt-pool-supervisor

## Bug Report: Data Integrity — `SqliteChangeSetStore.get_for_plan` Returns Single Merged Changeset ### Severity Assessment - **Impact**: Multiple changesets for the same plan are merged into one — callers cannot distinguish between separate changeset scopes; version history and rollback granularity are lost - **Likelihood**: High — any plan with more than one changeset affected - **Priority**: Medium ### Location - **File**: `src/cleveragents/infrastructure/database/changeset_repository.py` - **Function**: `SqliteChangeSetStore.get_for_plan` - **Lines**: ~451–465 - **Category**: data-integrity / incorrect-logic ### Description A plan can have multiple changesets (each call to `start()` creates a new one). `get_for_plan` merges ALL entries across ALL changesets into one synthetic `SpecChangeSet`, losing the per-changeset granularity. Callers expecting one `SpecChangeSet` per `start()` call will get incorrect data — a single "mega-changeset" combining all subplan scopes. ### Evidence ```python def get_for_plan(self, plan_id: str) -> list[SpecChangeSet]: entries = self._entry_repo.get_entries_for_plan(plan_id) if not entries: return [] return [ SpecChangeSet(plan_id=plan_id, entries=entries), # ONE changeset with ALL entries ] ``` **Scenario:** 1. `changeset_a = store.start(plan_id)` — Scope A started 2. `changeset_b = store.start(plan_id)` — Scope B started 3. Each scope records distinct entries 4. `store.get_for_plan(plan_id)` → returns `[SpecChangeSet(entries=scope_A_entries + scope_B_entries)]` 5. Caller cannot distinguish what was changed in scope A vs scope B ### Expected Behavior `get_for_plan` should return one `SpecChangeSet` per `start()` invocation, grouped by changeset ID. ### Actual Behavior All entries across all changesets are merged into one `SpecChangeSet` with no changeset-level grouping. ### Suggested Fix Group entries by `changeset_id` and return one per group: ```python def get_for_plan(self, plan_id: str) -> list[SpecChangeSet]: entries = self._entry_repo.get_entries_for_plan(plan_id) if not entries: return [] grouped: dict[str, list] = {} for entry in entries: grouped.setdefault(entry.changeset_id, []).append(entry) return [ SpecChangeSet(plan_id=plan_id, entries=group_entries) for group_entries in grouped.values() ] ``` ### Category data-integrity ### TDD Note After this bug issue is verified, a corresponding Type/Testing issue will be created for TDD. The test will use tags: @tdd_issue, @tdd_issue_<this-issue-number>, and @tdd_expected_fail to prove the bug exists before fixing it. --- **Automated by CleverAgents Bot** Supervisor: Bug Detection Pool | Agent: bug-hunt-pool-supervisor
HAL9000 added this to the v3.2.0 milestone 2026-04-10 21:39:01 +00:00
Author
Owner

Issue triaged by project owner:

  • State: Verified
  • Priority: High — Data integrity bug in validation/repository layer that directly impacts M3 milestone functionality (Decisions + Validations)
  • Milestone: v3.2.0 (M3: Decisions + Validations) — This component is core to the validation and decision recording features
  • Story Points: 3 (M) — Bug fix with clear reproduction path and suggested fix
  • MoSCoW: Must Have — Validation and data integrity are required for M3 acceptance criteria
  • Type: Bug

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

Issue triaged by project owner: - **State**: Verified - **Priority**: High — Data integrity bug in validation/repository layer that directly impacts M3 milestone functionality (Decisions + Validations) - **Milestone**: v3.2.0 (M3: Decisions + Validations) — This component is core to the validation and decision recording features - **Story Points**: 3 (M) — Bug fix with clear reproduction path and suggested fix - **MoSCoW**: Must Have — Validation and data integrity are required for M3 acceptance criteria - **Type**: Bug --- **Automated by CleverAgents Bot** Supervisor: Project Owner | Agent: project-owner-pool-supervisor
Author
Owner

Implementation Note

Status: Implementation Starting

Escalation Tier: Tier 1 (haiku)

Worker Tag: [AUTO-IMP-ISSUE-7502]

Scope

This implementation will address the get_for_plan method to properly group changesets by changeset_id instead of merging all entries into a single consolidated entry.

Work Description

  • Fix the changeset grouping logic in the get_for_plan method
  • Ensure each changeset maintains its own identity and is not merged with others
  • Preserve individual changeset metadata and relationships

Posted by Issue Note Writer Bot

## Implementation Note **Status:** Implementation Starting **Escalation Tier:** Tier 1 (haiku) **Worker Tag:** [AUTO-IMP-ISSUE-7502] ### Scope This implementation will address the `get_for_plan` method to properly group changesets by `changeset_id` instead of merging all entries into a single consolidated entry. ### Work Description - Fix the changeset grouping logic in the `get_for_plan` method - Ensure each changeset maintains its own identity and is not merged with others - Preserve individual changeset metadata and relationships --- *Posted by Issue Note Writer Bot*
Author
Owner

PR #8194 has been opened to fix this issue: #8194

This issue is blocked by PR #8194 — it will be closed automatically when the PR is merged via Closes #7502.


Automated by CleverAgents Bot
Agent: pr-creator

PR #8194 has been opened to fix this issue: https://git.cleverthis.com/cleveragents/cleveragents-core/pulls/8194 This issue is blocked by PR #8194 — it will be closed automatically when the PR is merged via `Closes #7502`. --- **Automated by CleverAgents Bot** Agent: pr-creator
Author
Owner

Implementation Complete ✓

Escalation Tier: Tier 1 (haiku)
Worker Tag: [AUTO-IMP-ISSUE-7502]

Summary

Implementation of the changeset grouping functionality has been successfully completed and is ready for review.

Changes Implemented

  1. ChangeSetEntryRepository Enhancement

    • Added get_entries_for_plan_grouped() method to support retrieving entries grouped by changeset_id
    • Enables efficient batch processing of changeset entries
  2. SqliteChangeSetStore Modification

    • Updated get_for_plan() method to properly group entries by changeset_id
    • Ensures multiple changesets are returned as separate, distinct objects
    • Maintains data integrity and proper changeset isolation
  3. Test Coverage

    • Added comprehensive test scenario to verify multiple changesets are returned separately
    • Validates grouping logic and changeset independence

Quality Assurance

  • All changes follow the standards outlined in CONTRIBUTING.md
  • Code adheres to project conventions and best practices
  • Test coverage validates expected behavior

Next Steps

PR #8194 has been created and is ready for review. Please proceed with code review and merge when appropriate.


Posted by Issue Note Writer Bot

## Implementation Complete ✓ **Escalation Tier:** Tier 1 (haiku) **Worker Tag:** [AUTO-IMP-ISSUE-7502] ### Summary Implementation of the changeset grouping functionality has been successfully completed and is ready for review. ### Changes Implemented 1. **ChangeSetEntryRepository Enhancement** - Added `get_entries_for_plan_grouped()` method to support retrieving entries grouped by changeset_id - Enables efficient batch processing of changeset entries 2. **SqliteChangeSetStore Modification** - Updated `get_for_plan()` method to properly group entries by changeset_id - Ensures multiple changesets are returned as separate, distinct objects - Maintains data integrity and proper changeset isolation 3. **Test Coverage** - Added comprehensive test scenario to verify multiple changesets are returned separately - Validates grouping logic and changeset independence ### Quality Assurance - All changes follow the standards outlined in CONTRIBUTING.md - Code adheres to project conventions and best practices - Test coverage validates expected behavior ### Next Steps **PR #8194** has been created and is ready for review. Please proceed with code review and merge when appropriate. --- *Posted by Issue Note Writer Bot*
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.

Dependencies

No dependencies set.

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