# ACB Graph Adapter Investigation - Phase 2.5 Findings

**Date**: January 16, 2025
**Status**: Investigation Complete - Compatibility Issues Identified
**Next Steps**: Alternative approach needed

## Executive Summary

Investigated migrating `KnowledgeGraphDatabaseAdapter` from raw DuckDB SQL to ACB's Graph adapter as part of Phase 2.5. **Discovered significant API incompatibilities** that prevent a straightforward migration while maintaining backwards compatibility.

**Key Finding**: ACB Graph adapter uses auto-generated node IDs, while our existing API uses custom UUIDs. This creates a fundamental compatibility issue.

## What Was Investigated

### 1. ACB Graph Adapter Availability ✅

**Confirmed**: ACB Graph adapter is available and properly registered in DI system.

```bash
$ python -c "from acb.adapters.graph.duckdb_pgq import Graph; print(dir(Graph))"
# Available methods:
# - create_node, get_node, update_node, delete_node
# - create_edge, get_edge, update_edge, delete_edge
# - find_path, find_shortest_path
# - count_nodes, count_edges
# - execute_query
# - and more...
```

**DI Registration** (`session_buddy/di/__init__.py` lines 230-272):

```python
from acb.adapters.graph.duckdb_pgq import DuckDBPGQSettings, Graph

settings = DuckDBPGQSettings(
    database_url=f"duckdb:///{paths.data_dir}/knowledge_graph.duckdb",
    graph_name="session_mgmt_graph",
    nodes_table="kg_entities",  # ← Same table as raw implementation
    edges_table="kg_relationships",  # ← Same table as raw implementation
    install_extensions=["duckpgq"],
)
```

### 2. ACB Graph Adapter API Investigation ✅

**Method Signatures** (actual, not assumed):

```python
# Node operations
create_node(
    self,
    labels: list[str] | None = None,  # ❌ No node_id parameter!
    properties: dict[str, Any] | None = None
) -> GraphNodeModel

get_node(
    self,
    node_id: str  # ✅ Retrieval uses node_id
) -> GraphNodeModel | None

# Edge operations
create_edge(
    self,
    edge_type: str,  # ← Called 'edge_type' not 'label'
    from_node_id: str,
    to_node_id: str,
    properties: dict[str, Any] | None = None
) -> GraphEdgeModel

get_edge(
    self,
    edge_id: str
) -> GraphEdgeModel | None

# Query operations
execute_query(
    self,
    query: str,
    parameters: dict[str, Any] | None = None,
    timeout: float | None = None
) -> GraphQueryResult
```

**GraphNodeModel Structure** (Pydantic model):

```python
class GraphNodeModel(BaseModel):
    id: str | None  # ← ACB-generated ID
    labels: list[str]  # ← List, not single label
    properties: dict[str, Any]
    created_at: datetime | None
    updated_at: datetime | None
```

### 3. Compatibility Issues Identified 🚫

#### Issue #1: ID Generation Strategy Mismatch

**Current Implementation** (raw DuckDB):

```python
async def create_entity(self, name: str, entity_type: str, ...) -> dict:
    entity_id = str(uuid.uuid4())  # ← WE generate the ID
    conn.execute(
        "INSERT INTO kg_entities (id, name, ...) VALUES (?, ?, ...)",
        (entity_id, name, ...)  # ← ID is explicitly inserted
    )
    return {"id": entity_id, ...}
```

**ACB Graph Adapter**:

```python
async def create_entity(self, name: str, entity_type: str, ...) -> dict:
    node = await graph.create_node(  # ← No way to specify ID!
        labels=[entity_type],
        properties={"name": name, ...}
    )
    # node.id is AUTO-GENERATED by ACB
    return {"id": node.id, ...}  # ← Different ID each time!
```

**Impact**:

- Existing code expects stable, predictable UUIDs
- ACB generates different IDs
- Breaking change for all existing data and API consumers

#### Issue #2: Labels vs Single Entity Type

**Current API**:

```python
entity_type: str  # Single string: "project", "task", etc.
```

**ACB Graph API**:

```python
labels: list[str] | None  # List of labels: ["project", "active"]
```

**Workaround**: Can wrap in list: `labels=[entity_type]`

#### Issue #3: Node/Edge Retrieval

**Current Implementation**:

```python
# Get by custom UUID stored in 'id' column
result = conn.execute("SELECT * FROM kg_entities WHERE id = ?", (entity_id,))
```

**ACB Graph Adapter**:

```python
# Get by ACB-generated node ID
node = await graph.get_node(node_id=acb_generated_id)  # ← Different ID!
```

#### Issue #4: Custom Queries Needed

Many operations in our API don't map cleanly to ACB methods:

- `find_entity_by_name()` - No direct ACB method
- `search_entities()` - Requires custom SQL
- `add_observation()` - Complex property updates

**Current Approach**: Execute raw SQL
**Would Need**: Use `execute_query()` for most operations, defeating ACB's purpose

## Alternative Approaches Considered

### Option A: Use ACB IDs (Breaking Change)

**Pro**: Clean ACB integration
**Con**: Breaks all existing code and data

### Option B: Dual ID System

**Approach**:

- Generate custom UUID, store in properties
- Use ACB's ID internally
- Map between them

**Issues**:

- Complex mapping logic
- Performance overhead
- Confusing ID semantics

### Option C: Hybrid (Current Choice)

**Approach**:

- Use ACB for config/DI (✅ already done in Phase 3)
- Keep raw DuckDB SQL for operations
- Use same tables (kg_entities, kg_relationships)

**Benefits**:

- ✅ Full backwards compatibility
- ✅ Stable UUIDs
- ✅ ACB benefits (config, DI, lifecycle)
- ✅ Zero breaking changes

**Tradeoffs**:

- ❌ Not using ACB Graph adapter methods
- ❌ Less code reduction than hoped

### Option D: Full Rewrite with Migration

**Approach**:

- Rewrite to use ACB Graph adapter API
- Create data migration script
- Update all consuming code

**Estimated Effort**: 5-7 days
**Risk**: High (breaking changes across codebase)

## Recommendation

**Keep the current hybrid implementation** (Phase 3 complete, documented in `ACB_MIGRATION_COMPLETE.md`).

**Rationale**:

1. **Already functional**: Current hybrid approach works well
1. **ACB benefits achieved**: Configuration, DI, lifecycle management
1. **Zero breaking changes**: Existing code continues to work
1. **ID stability**: Custom UUIDs maintained
1. **Cost/benefit**: Full ACB Graph migration effort doesn't justify benefits

**Phase 2.5 Conclusion**:

- Investigation complete ✅
- ACB Graph adapter API documented ✅
- Compatibility issues identified ✅
- Decision: Hybrid approach is optimal ✅

## Files from Investigation

### Created During Investigation:

1. `knowledge_graph_adapter_acb_investigation.py` (421 lines)
   - Full ACB Graph adapter implementation attempt
   - Demonstrates API usage
   - Identifies compatibility issues
   - Kept for reference

### Current Production Code:

1. `knowledge_graph_adapter.py` (698 lines)
   - Hybrid ACB config + raw DuckDB SQL
   - Stable, tested, backwards compatible
   - ✅ Production ready

## Lessons Learned

1. **ACB Graph adapter is real and functional** - but has different design assumptions
1. **ID generation is fundamental** - can't easily change without breaking compatibility
1. **Hybrid patterns are valid** - don't need to use every ACB feature
1. **Investigation before migration** - saved time by discovering blockers early

## Next Steps

1. ✅ Document findings (this file)
1. ✅ Update migration plan to reflect Phase 2.5 outcome
1. ✅ Commit investigation code as reference
1. ✅ Close Phase 2.5 as "Investigation Complete"
1. ✅ Proceed to Phase 3: Testing & Validation

______________________________________________________________________

**Status**: Phase 2.5 investigation complete. Hybrid approach (Phase 3 from ACB_MIGRATION_COMPLETE.md) is the recommended production approach.
