# 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.