Add comprehensive BACKBEAT timing integration to BUBBLE decision tracking

Major BACKBEAT integration implementation:
- Created sophisticated BACKBEAT integration module for decision operations
- Added beat-aware decision bundle generation with complexity-based estimation
- Implemented phase-based tracking (traversing → scoring → summarizing)
- Enhanced API with BACKBEAT metrics and monitoring endpoints
- Added graceful fallback when BACKBEAT infrastructure unavailable
- Switched from RocksDB to SQLite for better compatibility

Key features:
- Beat synchronization with 2 BPM global tempo grid
- Decision operation complexity estimation and beat budgeting
- Real-time operation status tracking with NATS messaging
- Enhanced decision bundle responses with intelligent analysis
- BACKBEAT metrics API for operational monitoring
- Comprehensive error handling and timeout management

API endpoints:
- POST /decision/bundle - Generate decision bundles with BACKBEAT timing
- GET /backbeat/metrics - View real-time BACKBEAT metrics
- GET /backbeat/operations - Monitor active decision operations

Technical implementation:
- Go backend with NATS messaging for distributed coordination
- SQLite storage with decision metadata and provenance tracking
- Beat-aware timing for all decision bundle operations
- Resource cleanup and graceful connection management
- Production-ready with environment-based configuration

This completes BUBBLE's integration into the CHORUS 2.0.0 BACKBEAT ecosystem.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
anthonyrawlins
2025-09-06 13:04:23 +10:00
parent 013e0dc3f0
commit 31b36260ad
8 changed files with 695 additions and 99 deletions

View File

@@ -0,0 +1,78 @@
package storage
import (
"encoding/json"
"gitea.deepblack.cloud/chorus/bubble/models"
"github.com/tecbot/gorocksdb"
)
// RocksDBStore is an implementation of the Storage interface using RocksDB.
type RocksDBStore struct {
DB *gorocksdb.DB
}
// NewRocksDBStore creates and initializes a new RocksDB database.
func NewRocksDBStore(dbPath string) (*RocksDBStore, error) {
opts := gorocksdb.NewDefaultOptions()
opts.SetCreateIfMissing(true)
db, err := gorocksdb.OpenDb(opts, dbPath)
if err != nil {
return nil, err
}
return &RocksDBStore{DB: db}, nil
}
// GetDecisionMetadata retrieves a decision's metadata from RocksDB.
func (r *RocksDBStore) GetDecisionMetadata(drID string) (*models.DecisionRecordSummary, error) {
ro := gorocksdb.NewDefaultReadOptions()
// Keys are stored as "meta:<id>"
key := []byte("meta:" + drID)
slice, err := r.DB.Get(ro, key)
if err != nil {
return nil, err
}
defer slice.Free()
if !slice.Exists() {
return nil, nil // Not found
}
var summary models.DecisionRecordSummary
if err := json.Unmarshal(slice.Data(), &summary); err != nil {
return nil, err
}
return &summary, nil
}
// GetAncestors retrieves a decision's ancestor IDs from RocksDB.
func (r *RocksDBStore) GetAncestors(drID string) ([]string, error) {
ro := gorocksdb.NewDefaultReadOptions()
// Keys are stored as "rev:<id>"
key := []byte("rev:" + drID)
slice, err := r.DB.Get(ro, key)
if err != nil {
return nil, err
}
defer slice.Free()
if !slice.Exists() {
return nil, nil // Not found, no ancestors
}
var ancestorIDs []string
if err := json.Unmarshal(slice.Data(), &ancestorIDs); err != nil {
return nil, err
}
return ancestorIDs, nil
}
// Close closes the RocksDB database connection.
func (r *RocksDBStore) Close() {
if r.DB != nil {
r.DB.Close()
}
}