Files
bzzz/IMPLEMENTATION_ROADMAP.md
anthonyrawlins b207f32d9e Implement UCXL Protocol Foundation (Phase 1)
- Add complete UCXL address parser with BNF grammar validation
- Implement temporal navigation system with bounds checking
- Create UCXI HTTP server with REST-like operations
- Add comprehensive test suite with 87 passing tests
- Integrate with existing BZZZ architecture (opt-in via config)
- Support semantic addressing with wildcards and version control

Core Features:
- UCXL address format: ucxl://agent:role@project:task/temporal/path
- Temporal segments: *^, ~~N, ^^N, *~, *~N with navigation logic
- UCXI endpoints: GET/PUT/POST/DELETE/ANNOUNCE operations
- Production-ready with error handling and graceful shutdown

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-08-08 07:38:04 +10:00

38 KiB

BZZZ v2 Implementation Roadmap: UCXL Integration

Phase 1: Foundation Implementation (Weeks 1-2)

Week 1: UCXL Address Parser Implementation

1.1 Replace existing pkg/protocol/uri.go with UCXL support

File: /pkg/protocol/ucxl_address.go

package protocol

import (
    "fmt"
    "net/url"
    "regexp"
    "strings"
    "time"
)

// UCXLAddress represents a parsed UCXL address with temporal navigation
// Grammar: ucxl://agent:role@project:task/temporal_segment/path[?query][#fragment]
type UCXLAddress struct {
    // Core semantic addressing
    Agent           string `json:"agent"`            // "gpt4", "claude", "any"
    Role            string `json:"role"`             // "architect", "reviewer", "any"
    Project         string `json:"project"`          // "bzzz", "chorus", "any"
    Task            string `json:"task"`             // "v2-migration", "auth", "any"
    
    // Temporal navigation
    TemporalSegment string `json:"temporal_segment"` // "~~", "^^", "*^", "*~", ISO8601
    
    // Resource path
    Path            string `json:"path"`             // "/decisions/architecture.json"
    
    // Standard URI components
    Query           string `json:"query,omitempty"`
    Fragment        string `json:"fragment,omitempty"`
    Raw             string `json:"raw"`
    
    // Resolved temporal information
    ResolvedTime    *time.Time `json:"resolved_time,omitempty"`
}

// Temporal navigation constants
const (
    UCXLScheme       = "ucxl"
    TemporalBackward = "~~"  // Navigate backward in time
    TemporalForward  = "^^"  // Navigate forward in time
    TemporalLatest   = "*^"  // Latest entry
    TemporalFirst    = "*~"  // First entry
    AnyWildcard      = "any" // Wildcard for any component
)

// Validation patterns for UCXL components
var (
    agentPattern     = regexp.MustCompile(`^[a-zA-Z0-9\-_]+$|^any$`)
    rolePattern      = regexp.MustCompile(`^[a-zA-Z0-9\-_]+$|^any$`)
    projectPattern   = regexp.MustCompile(`^[a-zA-Z0-9\-_]+$|^any$`)
    taskPattern      = regexp.MustCompile(`^[a-zA-Z0-9\-_]+$|^any$`)
    temporalPattern  = regexp.MustCompile(`^(~~|\^\^|\*\^|\*~|\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}.*Z?)$`)
    pathPattern      = regexp.MustCompile(`^(/[a-zA-Z0-9\-_/.]*)?$`)
)

// ParseUCXLAddress parses a UCXL URI string
func ParseUCXLAddress(uri string) (*UCXLAddress, error) {
    if uri == "" {
        return nil, fmt.Errorf("empty UCXL address")
    }
    
    if !strings.HasPrefix(uri, UCXLScheme+"://") {
        return nil, fmt.Errorf("invalid scheme: expected '%s'", UCXLScheme)
    }
    
    // Parse using standard URL parser
    parsedURL, err := url.Parse(uri)
    if err != nil {
        return nil, fmt.Errorf("failed to parse UCXL address: %w", err)
    }
    
    // Extract agent:role from user info
    userInfo := parsedURL.User
    if userInfo == nil {
        return nil, fmt.Errorf("missing agent:role information")
    }
    
    agent := userInfo.Username()
    role, hasRole := userInfo.Password()
    if !hasRole {
        return nil, fmt.Errorf("missing role information")
    }
    
    // Extract project:task from host
    hostParts := strings.Split(parsedURL.Host, ":")
    if len(hostParts) != 2 {
        return nil, fmt.Errorf("invalid project:task format")
    }
    
    project := hostParts[0]
    task := hostParts[1]
    
    // Parse temporal segment and path
    pathParts := strings.SplitN(strings.TrimPrefix(parsedURL.Path, "/"), "/", 2)
    temporalSegment := ""
    resourcePath := ""
    
    if len(pathParts) > 0 && pathParts[0] != "" {
        temporalSegment = pathParts[0]
    }
    if len(pathParts) > 1 {
        resourcePath = "/" + pathParts[1]
    }
    
    address := &UCXLAddress{
        Agent:           agent,
        Role:            role,
        Project:         project,
        Task:            task,
        TemporalSegment: temporalSegment,
        Path:            resourcePath,
        Query:           parsedURL.RawQuery,
        Fragment:        parsedURL.Fragment,
        Raw:             uri,
    }
    
    if err := address.Validate(); err != nil {
        return nil, fmt.Errorf("validation failed: %w", err)
    }
    
    return address, nil
}

// Validate validates UCXL address components
func (addr *UCXLAddress) Validate() error {
    if !agentPattern.MatchString(addr.Agent) {
        return fmt.Errorf("invalid agent: %s", addr.Agent)
    }
    if !rolePattern.MatchString(addr.Role) {
        return fmt.Errorf("invalid role: %s", addr.Role)
    }
    if !projectPattern.MatchString(addr.Project) {
        return fmt.Errorf("invalid project: %s", addr.Project)
    }
    if !taskPattern.MatchString(addr.Task) {
        return fmt.Errorf("invalid task: %s", addr.Task)
    }
    if addr.TemporalSegment != "" && !temporalPattern.MatchString(addr.TemporalSegment) {
        return fmt.Errorf("invalid temporal segment: %s", addr.TemporalSegment)
    }
    if !pathPattern.MatchString(addr.Path) {
        return fmt.Errorf("invalid path: %s", addr.Path)
    }
    return nil
}

// ResolveTemporalSegment resolves temporal navigation tokens to actual timestamps
func (addr *UCXLAddress) ResolveTemporalSegment(navigator TemporalNavigator) error {
    if addr.TemporalSegment == "" {
        return nil
    }
    
    switch addr.TemporalSegment {
    case TemporalLatest:
        timestamp, err := navigator.GetLatestTimestamp(addr)
        if err != nil {
            return err
        }
        addr.ResolvedTime = &timestamp
    case TemporalFirst:
        timestamp, err := navigator.GetFirstTimestamp(addr)
        if err != nil {
            return err
        }
        addr.ResolvedTime = &timestamp
    case TemporalBackward, TemporalForward:
        // These require context of current position
        return fmt.Errorf("relative navigation requires current context")
    default:
        // Parse as ISO8601 timestamp
        timestamp, err := time.Parse(time.RFC3339, addr.TemporalSegment)
        if err != nil {
            return fmt.Errorf("invalid timestamp format: %w", err)
        }
        addr.ResolvedTime = &timestamp
    }
    
    return nil
}

// Matches checks if this address matches another (with wildcard support)
func (addr *UCXLAddress) Matches(other *UCXLAddress) bool {
    return componentMatches(addr.Agent, other.Agent) &&
           componentMatches(addr.Role, other.Role) &&
           componentMatches(addr.Project, other.Project) &&
           componentMatches(addr.Task, other.Task) &&
           pathMatches(addr.Path, other.Path)
}

func componentMatches(a, b string) bool {
    return a == b || a == AnyWildcard || b == AnyWildcard
}

func pathMatches(a, b string) bool {
    if a == "" || b == "" {
        return true
    }
    return a == b
}

// String returns canonical string representation
func (addr *UCXLAddress) String() string {
    uri := fmt.Sprintf("%s://%s:%s@%s:%s", UCXLScheme, addr.Agent, addr.Role, addr.Project, addr.Task)
    
    if addr.TemporalSegment != "" {
        uri += "/" + addr.TemporalSegment
    }
    
    if addr.Path != "" {
        uri += addr.Path
    }
    
    if addr.Query != "" {
        uri += "?" + addr.Query
    }
    
    if addr.Fragment != "" {
        uri += "#" + addr.Fragment
    }
    
    return uri
}

// ToStorageKey generates a storage key for this address
func (addr *UCXLAddress) ToStorageKey() string {
    key := fmt.Sprintf("%s/%s/%s/%s", addr.Agent, addr.Role, addr.Project, addr.Task)
    
    if addr.ResolvedTime != nil {
        key += "/" + addr.ResolvedTime.Format(time.RFC3339)
    } else if addr.TemporalSegment != "" {
        key += "/" + addr.TemporalSegment
    }
    
    if addr.Path != "" {
        key += addr.Path
    }
    
    return key
}

1.2 Temporal Navigator Interface

File: /pkg/temporal/navigator.go

package temporal

import (
    "time"
    "github.com/anthonyrawlins/bzzz/pkg/protocol"
)

type TemporalNavigator interface {
    GetLatestTimestamp(addr *protocol.UCXLAddress) (time.Time, error)
    GetFirstTimestamp(addr *protocol.UCXLAddress) (time.Time, error)
    NavigateBackward(addr *protocol.UCXLAddress, steps int) (time.Time, error)
    NavigateForward(addr *protocol.UCXLAddress, steps int) (time.Time, error)
    GetAtTime(addr *protocol.UCXLAddress, timestamp time.Time) (*protocol.UCXLAddress, error)
}

type TemporalIndex struct {
    // Map address patterns to temporal entries
    entries map[string][]TemporalEntry
}

type TemporalEntry struct {
    Timestamp time.Time                `json:"timestamp"`
    Version   int64                    `json:"version"`
    Address   *protocol.UCXLAddress    `json:"address"`
    Checksum  string                   `json:"checksum"`
}

Week 2: UCXI Interface Server

2.1 UCXI Server Implementation

File: /pkg/ucxi/server.go

package ucxi

import (
    "encoding/json"
    "net/http"
    "github.com/gorilla/mux"
    "github.com/anthonyrawlins/bzzz/pkg/protocol"
    "github.com/anthonyrawlins/bzzz/pkg/storage"
    "github.com/anthonyrawlins/bzzz/pkg/temporal"
)

type UCXIServer struct {
    contextStore    storage.ContextStore
    temporalNav     temporal.TemporalNavigator
    router          *mux.Router
    port            int
}

// Context entry structure
type ContextEntry struct {
    Address     *protocol.UCXLAddress  `json:"address"`
    Content     map[string]interface{} `json:"content"`
    Metadata    ContextMetadata        `json:"metadata"`
    Version     int64                  `json:"version"`
    Checksum    string                 `json:"checksum"`
    CreatedAt   time.Time              `json:"created_at"`
    UpdatedAt   time.Time              `json:"updated_at"`
}

type ContextMetadata struct {
    ContentType   string            `json:"content_type"`
    Size          int64             `json:"size"`
    Tags          []string          `json:"tags"`
    Provenance    string            `json:"provenance"`
    Relationships map[string]string `json:"relationships"`
}

func NewUCXIServer(store storage.ContextStore, nav temporal.TemporalNavigator, port int) *UCXIServer {
    server := &UCXIServer{
        contextStore: store,
        temporalNav:  nav,
        router:       mux.NewRouter(),
        port:         port,
    }
    server.setupRoutes()
    return server
}

func (s *UCXIServer) setupRoutes() {
    // UCXI operations
    s.router.HandleFunc("/ucxi/{agent}:{role}@{project}:{task}/{temporal}/{path:.*}", s.handleGET).Methods("GET")
    s.router.HandleFunc("/ucxi/{agent}:{role}@{project}:{task}/{temporal}/{path:.*}", s.handlePUT).Methods("PUT")
    s.router.HandleFunc("/ucxi/{agent}:{role}@{project}:{task}/{temporal}/", s.handlePOST).Methods("POST")
    s.router.HandleFunc("/ucxi/{agent}:{role}@{project}:{task}/{temporal}/{path:.*}", s.handleDELETE).Methods("DELETE")
    s.router.HandleFunc("/ucxi/announce", s.handleANNOUNCE).Methods("POST")
    
    // Extended operations
    s.router.HandleFunc("/ucxi/navigate/{direction}", s.handleNAVIGATE).Methods("GET")
    s.router.HandleFunc("/ucxi/query", s.handleQUERY).Methods("GET")
    s.router.HandleFunc("/ucxi/subscribe", s.handleSUBSCRIBE).Methods("POST")
}

func (s *UCXIServer) handleGET(w http.ResponseWriter, r *http.Request) {
    vars := mux.Vars(r)
    
    // Construct UCXL address from URL parameters
    address := &protocol.UCXLAddress{
        Agent:           vars["agent"],
        Role:            vars["role"],
        Project:         vars["project"],
        Task:            vars["task"],
        TemporalSegment: vars["temporal"],
        Path:            "/" + vars["path"],
    }
    
    // Resolve temporal navigation
    if err := address.ResolveTemporalSegment(s.temporalNav); err != nil {
        http.Error(w, err.Error(), http.StatusBadRequest)
        return
    }
    
    // Retrieve context
    entry, err := s.contextStore.Retrieve(address)
    if err != nil {
        http.Error(w, err.Error(), http.StatusNotFound)
        return
    }
    
    w.Header().Set("Content-Type", "application/json")
    json.NewEncoder(w).Encode(entry)
}

func (s *UCXIServer) handlePUT(w http.ResponseWriter, r *http.Request) {
    vars := mux.Vars(r)
    
    var entry ContextEntry
    if err := json.NewDecoder(r.Body).Decode(&entry); err != nil {
        http.Error(w, err.Error(), http.StatusBadRequest)
        return
    }
    
    // Construct address
    address := &protocol.UCXLAddress{
        Agent:           vars["agent"],
        Role:            vars["role"],
        Project:         vars["project"],
        Task:            vars["task"],
        TemporalSegment: vars["temporal"],
        Path:            "/" + vars["path"],
    }
    
    entry.Address = address
    entry.UpdatedAt = time.Now()
    
    if err := s.contextStore.Store(address, &entry); err != nil {
        http.Error(w, err.Error(), http.StatusInternalServerError)
        return
    }
    
    w.WriteHeader(http.StatusCreated)
}

// Additional handlers for POST, DELETE, ANNOUNCE, NAVIGATE, QUERY, SUBSCRIBE...

Phase 2: Decision Graph & SLURP Integration (Weeks 3-6)

Week 3-4: Decision Node Schema

3.1 Decision Node Structure

File: /pkg/decisions/schema.go

package decisions

import (
    "time"
    "github.com/anthonyrawlins/bzzz/pkg/protocol"
)

// DecisionNode represents a structured decision for SLURP ingestion
type DecisionNode struct {
    DecisionID    string             `json:"decision_id"`
    UCXLAddress   string             `json:"ucxl_address"`
    Timestamp     time.Time          `json:"timestamp"`
    AgentID       string             `json:"agent_id"`
    DecisionType  string             `json:"decision_type"`
    Context       DecisionContext    `json:"context"`
    Justification Justification      `json:"justification"`
    Citations     []Citation         `json:"citations"`
    Impacts       []Impact           `json:"impacts"`
    Metadata      DecisionMetadata   `json:"metadata"`
}

type DecisionContext struct {
    Project     string                 `json:"project"`
    Task        string                 `json:"task"`
    Scope       string                 `json:"scope"`
    Phase       string                 `json:"phase"`
    Environment string                 `json:"environment"`
    Constraints map[string]interface{} `json:"constraints"`
}

type Justification struct {
    Reasoning              string                 `json:"reasoning"`
    AlternativesConsidered []Alternative          `json:"alternatives_considered"`
    Criteria               []string               `json:"criteria"`
    Confidence             float64                `json:"confidence"`
    RiskAssessment         RiskAssessment         `json:"risk_assessment"`
    TradeOffs              map[string]interface{} `json:"trade_offs"`
}

type Alternative struct {
    Name        string                 `json:"name"`
    Description string                 `json:"description"`
    Pros        []string               `json:"pros"`
    Cons        []string               `json:"cons"`
    Score       float64                `json:"score"`
    Rejected    bool                   `json:"rejected"`
    Reason      string                 `json:"reason"`
    Metadata    map[string]interface{} `json:"metadata"`
}

type Citation struct {
    Type         string  `json:"type"`         // "justified_by", "references", "contradicts", "extends"
    UCXLAddress  string  `json:"ucxl_address"`
    Relevance    string  `json:"relevance"`    // "high", "medium", "low"
    Excerpt      string  `json:"excerpt"`
    Strength     float64 `json:"strength"`     // 0.0 - 1.0
    Verified     bool    `json:"verified"`
    VerifiedAt   *time.Time `json:"verified_at,omitempty"`
}

type Impact struct {
    Type         string                 `json:"type"` // "replaces", "modifies", "creates", "deprecates"
    UCXLAddress  string                 `json:"ucxl_address"`
    Reason       string                 `json:"reason"`
    Severity     string                 `json:"severity"` // "low", "medium", "high", "breaking"
    Affected     []string               `json:"affected"`
    Migration    *MigrationInfo         `json:"migration,omitempty"`
    Metadata     map[string]interface{} `json:"metadata"`
}

type MigrationInfo struct {
    Required     bool   `json:"required"`
    Automated    bool   `json:"automated"`
    Instructions string `json:"instructions"`
    Timeline     string `json:"timeline"`
}

type RiskAssessment struct {
    Level       string            `json:"level"`        // "low", "medium", "high"
    Factors     []string          `json:"factors"`
    Mitigation  []string          `json:"mitigation"`
    Monitoring  []string          `json:"monitoring"`
    Escalation  *EscalationInfo   `json:"escalation,omitempty"`
}

type EscalationInfo struct {
    Triggers    []string `json:"triggers"`
    Contacts    []string `json:"contacts"`
    Procedures  []string `json:"procedures"`
}

type DecisionMetadata struct {
    SourceRepository string            `json:"source_repository"`
    CommitSHA        string            `json:"commit_sha"`
    PullRequestID    string            `json:"pull_request_id"`
    ReviewedBy       []string          `json:"reviewed_by"`
    ApprovedBy       []string          `json:"approved_by"`
    Tags             []string          `json:"tags"`
    Priority         int               `json:"priority"`
    Visibility       string            `json:"visibility"` // "public", "internal", "private"
    ExpiresAt        *time.Time        `json:"expires_at,omitempty"`
    CustomFields     map[string]interface{} `json:"custom_fields"`
}

// Decision types enumeration
const (
    DecisionTypeArchitecture    = "architecture_choice"
    DecisionTypeImplementation  = "implementation_approach"
    DecisionTypeTechnology      = "technology_selection"
    DecisionTypeProcess         = "process_definition"
    DecisionTypeAPI             = "api_design"
    DecisionTypeDataModel       = "data_model_design"
    DecisionTypeSecurity        = "security_requirement"
    DecisionTypeDeployment      = "deployment_strategy"
    DecisionTypeRollback        = "rollback_decision"
    DecisionTypeDeprecation     = "deprecation_notice"
)

// Citation types enumeration
const (
    CitationJustifiedBy = "justified_by"
    CitationReferences  = "references"
    CitationContradicts = "contradicts"
    CitationExtends     = "extends"
    CitationSupersedes  = "supersedes"
)

// Validation methods
func (dn *DecisionNode) Validate() error {
    if dn.DecisionID == "" {
        return fmt.Errorf("decision_id is required")
    }
    
    if dn.UCXLAddress == "" {
        return fmt.Errorf("ucxl_address is required")
    }
    
    if _, err := protocol.ParseUCXLAddress(dn.UCXLAddress); err != nil {
        return fmt.Errorf("invalid ucxl_address: %w", err)
    }
    
    if dn.AgentID == "" {
        return fmt.Errorf("agent_id is required")
    }
    
    if dn.DecisionType == "" {
        return fmt.Errorf("decision_type is required")
    }
    
    // Validate citations
    for i, citation := range dn.Citations {
        if citation.UCXLAddress == "" {
            return fmt.Errorf("citation[%d] missing ucxl_address", i)
        }
        
        if _, err := protocol.ParseUCXLAddress(citation.UCXLAddress); err != nil {
            return fmt.Errorf("citation[%d] invalid ucxl_address: %w", i, err)
        }
    }
    
    return nil
}

func (dn *DecisionNode) GenerateID() string {
    hash := sha256.Sum256([]byte(dn.UCXLAddress + dn.AgentID + dn.Timestamp.Format(time.RFC3339)))
    return fmt.Sprintf("%x", hash)[:16]
}

Week 5-6: SLURP Integration

5.1 SLURP Client Implementation

File: /pkg/integration/slurp_client.go

package integration

import (
    "bytes"
    "encoding/json"
    "fmt"
    "net/http"
    "time"
    "github.com/anthonyrawlins/bzzz/pkg/decisions"
)

type SLURPClient struct {
    baseURL    string
    apiKey     string
    httpClient *http.Client
    batchSize  int
    timeout    time.Duration
}

type SLURPPublishRequest struct {
    Decisions []decisions.DecisionNode `json:"decisions"`
    Source    string                   `json:"source"`
    Version   string                   `json:"version"`
    Timestamp time.Time                `json:"timestamp"`
}

type SLURPPublishResponse struct {
    Accepted []string `json:"accepted"`
    Rejected []string `json:"rejected"`
    Errors   []string `json:"errors"`
}

func NewSLURPClient(baseURL, apiKey string) *SLURPClient {
    return &SLURPClient{
        baseURL: baseURL,
        apiKey:  apiKey,
        httpClient: &http.Client{
            Timeout: 30 * time.Second,
        },
        batchSize: 10,
        timeout:   30 * time.Second,
    }
}

func (sc *SLURPClient) PublishDecisions(nodes []decisions.DecisionNode) (*SLURPPublishResponse, error) {
    // Validate all decisions before publishing
    for i, node := range nodes {
        if err := node.Validate(); err != nil {
            return nil, fmt.Errorf("decision[%d] validation failed: %w", i, err)
        }
    }
    
    request := SLURPPublishRequest{
        Decisions: nodes,
        Source:    "bzzz-v2",
        Version:   "2.0.0",
        Timestamp: time.Now(),
    }
    
    jsonData, err := json.Marshal(request)
    if err != nil {
        return nil, fmt.Errorf("failed to marshal request: %w", err)
    }
    
    req, err := http.NewRequest("POST", sc.baseURL+"/api/v1/decisions", bytes.NewBuffer(jsonData))
    if err != nil {
        return nil, fmt.Errorf("failed to create request: %w", err)
    }
    
    req.Header.Set("Content-Type", "application/json")
    req.Header.Set("Authorization", "Bearer "+sc.apiKey)
    req.Header.Set("User-Agent", "bzzz-v2/2.0.0")
    
    resp, err := sc.httpClient.Do(req)
    if err != nil {
        return nil, fmt.Errorf("failed to send request: %w", err)
    }
    defer resp.Body.Close()
    
    if resp.StatusCode != http.StatusOK {
        return nil, fmt.Errorf("SLURP API error: %d", resp.StatusCode)
    }
    
    var response SLURPPublishResponse
    if err := json.NewDecoder(resp.Body).Decode(&response); err != nil {
        return nil, fmt.Errorf("failed to decode response: %w", err)
    }
    
    return &response, nil
}

func (sc *SLURPClient) QueryDecisions(query string) ([]decisions.DecisionNode, error) {
    req, err := http.NewRequest("GET", sc.baseURL+"/api/v1/decisions/query", nil)
    if err != nil {
        return nil, err
    }
    
    q := req.URL.Query()
    q.Add("q", query)
    req.URL.RawQuery = q.Encode()
    
    req.Header.Set("Authorization", "Bearer "+sc.apiKey)
    
    resp, err := sc.httpClient.Do(req)
    if err != nil {
        return nil, err
    }
    defer resp.Body.Close()
    
    var nodes []decisions.DecisionNode
    if err := json.NewDecoder(resp.Body).Decode(&nodes); err != nil {
        return nil, err
    }
    
    return nodes, nil
}

Phase 3: Agent Integration & Testing (Weeks 7-8)

Week 7: GPT-4 Agent UCXL Integration

7.1 Updated MCP Tools

File: /mcp-server/src/tools/ucxi-tools.ts

import { Tool } from "@modelcontextprotocol/sdk/types.js";

export const ucxiTools: Record<string, Tool> = {
  ucxi_get: {
    name: "ucxi_get",
    description: "Retrieve context from UCXL address with temporal navigation",
    inputSchema: {
      type: "object",
      properties: {
        address: {
          type: "string",
          description: "UCXL address (e.g., ucxl://gpt4:architect@bzzz:v2/*^/decisions.json)"
        },
        temporal: {
          type: "string",
          enum: ["~~", "^^", "*^", "*~"],
          description: "Temporal navigation: ~~ (back), ^^ (forward), *^ (latest), *~ (first)"
        }
      },
      required: ["address"]
    }
  },

  ucxi_put: {
    name: "ucxi_put",
    description: "Store context at UCXL address",
    inputSchema: {
      type: "object",
      properties: {
        address: {
          type: "string",
          description: "UCXL address where to store context"
        },
        content: {
          type: "object",
          description: "Context content to store"
        },
        metadata: {
          type: "object",
          properties: {
            content_type: { type: "string" },
            tags: { type: "array", items: { type: "string" } },
            provenance: { type: "string" }
          },
          description: "Context metadata"
        }
      },
      required: ["address", "content"]
    }
  },

  ucxi_publish_decision: {
    name: "ucxi_publish_decision",
    description: "Publish a structured decision to SLURP via UCXI",
    inputSchema: {
      type: "object",
      properties: {
        decision_type: {
          type: "string",
          enum: ["architecture_choice", "implementation_approach", "technology_selection", "api_design"],
          description: "Type of decision being published"
        },
        reasoning: {
          type: "string",
          description: "Detailed reasoning for the decision"
        },
        alternatives: {
          type: "array",
          items: {
            type: "object",
            properties: {
              name: { type: "string" },
              description: { type: "string" },
              pros: { type: "array", items: { type: "string" } },
              cons: { type: "array", items: { type: "string" } },
              rejected: { type: "boolean" },
              reason: { type: "string" }
            }
          },
          description: "Alternative approaches considered"
        },
        citations: {
          type: "array",
          items: {
            type: "object",
            properties: {
              type: { type: "string", enum: ["justified_by", "references", "contradicts"] },
              ucxl_address: { type: "string" },
              relevance: { type: "string", enum: ["high", "medium", "low"] },
              excerpt: { type: "string" }
            }
          },
          description: "Citations supporting the decision"
        },
        impacts: {
          type: "array",
          items: {
            type: "object",
            properties: {
              type: { type: "string", enum: ["replaces", "modifies", "creates", "deprecates"] },
              ucxl_address: { type: "string" },
              reason: { type: "string" },
              severity: { type: "string", enum: ["low", "medium", "high", "breaking"] }
            }
          },
          description: "Impacts of this decision"
        }
      },
      required: ["decision_type", "reasoning"]
    }
  },

  ucxi_query: {
    name: "ucxi_query",
    description: "Query contexts matching UCXL address pattern",
    inputSchema: {
      type: "object",
      properties: {
        pattern: {
          type: "string",
          description: "UCXL address pattern with wildcards (e.g., any:architect@bzzz:*)"
        },
        temporal_range: {
          type: "object",
          properties: {
            start: { type: "string", format: "date-time" },
            end: { type: "string", format: "date-time" }
          },
          description: "Temporal range for search"
        },
        content_filter: {
          type: "string",
          description: "Full-text search filter for content"
        }
      },
      required: ["pattern"]
    }
  },

  ucxi_navigate: {
    name: "ucxi_navigate",
    description: "Navigate temporally through context history",
    inputSchema: {
      type: "object",
      properties: {
        current_address: {
          type: "string",
          description: "Current UCXL address position"
        },
        direction: {
          type: "string",
          enum: ["~~", "^^"],
          description: "Navigation direction: ~~ (backward) or ^^ (forward)"
        },
        steps: {
          type: "integer",
          default: 1,
          description: "Number of temporal steps to navigate"
        }
      },
      required: ["current_address", "direction"]
    }
  },

  ucxi_announce: {
    name: "ucxi_announce",
    description: "Announce context availability to P2P network",
    inputSchema: {
      type: "object",
      properties: {
        address: {
          type: "string",
          description: "UCXL address to announce"
        },
        capabilities: {
          type: "array",
          items: { type: "string" },
          description: "Agent capabilities (roles, specializations)"
        },
        metadata: {
          type: "object",
          description: "Additional metadata about the context"
        }
      },
      required: ["address"]
    }
  }
};

// Handler implementations
export async function handleUCXITool(name: string, args: any): Promise<any> {
  const ucxiServerURL = process.env.UCXI_SERVER_URL || "http://localhost:8080";
  
  switch (name) {
    case "ucxi_get":
      return await ucxiGet(ucxiServerURL, args.address, args.temporal);
      
    case "ucxi_put":
      return await ucxiPut(ucxiServerURL, args.address, args.content, args.metadata);
      
    case "ucxi_publish_decision":
      return await ucxiPublishDecision(ucxiServerURL, args);
      
    case "ucxi_query":
      return await ucxiQuery(ucxiServerURL, args.pattern, args.temporal_range, args.content_filter);
      
    case "ucxi_navigate":
      return await ucxiNavigate(ucxiServerURL, args.current_address, args.direction, args.steps);
      
    case "ucxi_announce":
      return await ucxiAnnounce(ucxiServerURL, args.address, args.capabilities, args.metadata);
      
    default:
      throw new Error(`Unknown UCXI tool: ${name}`);
  }
}

async function ucxiGet(serverURL: string, address: string, temporal?: string): Promise<any> {
  const url = new URL(`/ucxi/${address}`, serverURL);
  if (temporal) {
    url.searchParams.set('temporal', temporal);
  }
  
  const response = await fetch(url.toString());
  if (!response.ok) {
    throw new Error(`UCXI GET failed: ${response.status}`);
  }
  
  return await response.json();
}

async function ucxiPublishDecision(serverURL: string, decision: any): Promise<any> {
  const response = await fetch(`${serverURL}/ucxi/decisions/publish`, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json'
    },
    body: JSON.stringify(decision)
  });
  
  if (!response.ok) {
    throw new Error(`Decision publishing failed: ${response.status}`);
  }
  
  return await response.json();
}

Week 8: Integration Testing

8.1 End-to-End Test Suite

File: /test/integration/ucxl_e2e_test.go

package integration

import (
    "testing"
    "time"
    "github.com/stretchr/testify/assert"
    "github.com/anthonyrawlins/bzzz/pkg/protocol"
    "github.com/anthonyrawlins/bzzz/pkg/ucxi"
    "github.com/anthonyrawlins/bzzz/pkg/decisions"
)

func TestUCXLE2E(t *testing.T) {
    // Start UCXI server
    server := setupTestServer(t)
    defer server.Close()
    
    t.Run("AddressParsingAndResolution", func(t *testing.T) {
        // Test UCXL address parsing
        addr, err := protocol.ParseUCXLAddress("ucxl://gpt4:architect@bzzz:v2/*^/decisions/protocol.json")
        assert.NoError(t, err)
        assert.Equal(t, "gpt4", addr.Agent)
        assert.Equal(t, "architect", addr.Role)
        assert.Equal(t, "bzzz", addr.Project)
        assert.Equal(t, "v2", addr.Task)
        assert.Equal(t, "*^", addr.TemporalSegment)
        assert.Equal(t, "/decisions/protocol.json", addr.Path)
        
        // Test storage key generation
        storageKey := addr.ToStorageKey()
        assert.Contains(t, storageKey, "gpt4/architect/bzzz/v2")
    })
    
    t.Run("TemporalNavigation", func(t *testing.T) {
        // Create temporal sequence
        baseAddr := "ucxl://gpt4:architect@bzzz:v2"
        
        // Store contexts at different times
        times := []time.Time{
            time.Now().Add(-2 * time.Hour),
            time.Now().Add(-1 * time.Hour),
            time.Now(),
        }
        
        for i, timestamp := range times {
            addr := fmt.Sprintf("%s/%s/decisions/protocol.json", baseAddr, timestamp.Format(time.RFC3339))
            content := map[string]interface{}{
                "version": i + 1,
                "decision": fmt.Sprintf("Protocol decision v%d", i+1),
            }
            
            err := storeContext(server, addr, content)
            assert.NoError(t, err)
        }
        
        // Test latest navigation (*^)
        latestAddr := fmt.Sprintf("%s/*^/decisions/protocol.json", baseAddr)
        entry, err := getContext(server, latestAddr)
        assert.NoError(t, err)
        assert.Equal(t, 3, entry.Content["version"])
        
        // Test first navigation (*~)
        firstAddr := fmt.Sprintf("%s/*~/decisions/protocol.json", baseAddr)
        entry, err = getContext(server, firstAddr)
        assert.NoError(t, err)
        assert.Equal(t, 1, entry.Content["version"])
    })
    
    t.Run("DecisionPublishing", func(t *testing.T) {
        // Create decision node
        decision := &decisions.DecisionNode{
            DecisionID:   "test-decision-001",
            UCXLAddress:  "ucxl://gpt4:architect@bzzz:v2/2025-08-07T14:30:00Z/decisions/architecture.json",
            Timestamp:    time.Now(),
            AgentID:      "gpt4-test-agent",
            DecisionType: decisions.DecisionTypeArchitecture,
            Context: decisions.DecisionContext{
                Project: "bzzz",
                Task:    "v2-migration",
                Scope:   "protocol-selection",
            },
            Justification: decisions.Justification{
                Reasoning: "UCXL provides superior semantic addressing and temporal navigation capabilities",
                AlternativesConsidered: []decisions.Alternative{
                    {
                        Name:        "Extend bzzz:// protocol",
                        Description: "Add temporal navigation to existing protocol",
                        Pros:        []string{"Minimal changes", "Backward compatibility"},
                        Cons:        []string{"Limited semantic expressiveness", "Technical debt"},
                        Rejected:    true,
                        Reason:      "Insufficient semantic richness for complex context addressing",
                    },
                },
                Criteria:   []string{"semantic_richness", "temporal_navigation", "ecosystem_compatibility"},
                Confidence: 0.9,
            },
            Citations: []decisions.Citation{
                {
                    Type:         decisions.CitationJustifiedBy,
                    UCXLAddress:  "ucxl://any:any@chorus:requirements/*~/analysis.md",
                    Relevance:    "high",
                    Excerpt:      "System must support temporal context navigation for audit trails",
                    Strength:     0.95,
                },
            },
            Impacts: []decisions.Impact{
                {
                    Type:         "replaces",
                    UCXLAddress:  "ucxl://any:any@bzzz:v1/*^/protocol.go",
                    Reason:       "Migrating from bzzz:// to ucxl:// addressing scheme",
                    Severity:     "breaking",
                    Affected:     []string{"protocol", "addressing", "navigation"},
                },
            },
        }
        
        // Validate decision
        err := decision.Validate()
        assert.NoError(t, err)
        
        // Test decision publishing to SLURP
        slurpClient := setupMockSLURPClient(t)
        response, err := slurpClient.PublishDecisions([]decisions.DecisionNode{*decision})
        assert.NoError(t, err)
        assert.Contains(t, response.Accepted, decision.DecisionID)
    })
    
    t.Run("P2PResolution", func(t *testing.T) {
        // Test distributed address resolution
        addr := "ucxl://any:architect@bzzz:*/*^/decisions"
        
        // Query should return contexts from multiple agents
        entries, err := queryContexts(server, addr)
        assert.NoError(t, err)
        assert.Greater(t, len(entries), 0)
        
        // Test wildcard matching
        for _, entry := range entries {
            assert.Equal(t, "architect", entry.Address.Role)
            assert.Equal(t, "bzzz", entry.Address.Project)
        }
    })
    
    t.Run("CitationValidation", func(t *testing.T) {
        // Test citation chain validation
        validator := decisions.NewCitationValidator(server.ContextStore)
        
        decision := &decisions.DecisionNode{
            Citations: []decisions.Citation{
                {
                    Type:         decisions.CitationJustifiedBy,
                    UCXLAddress:  "ucxl://nonexistent:agent@invalid:project/*^/missing.json",
                    Relevance:    "high",
                },
            },
        }
        
        err := validator.ValidateCitations(decision)
        assert.Error(t, err) // Should fail due to nonexistent citation
        
        // Test valid citation
        decision.Citations[0].UCXLAddress = "ucxl://gpt4:architect@bzzz:v2/*^/requirements.json"
        
        // Store the referenced context
        storeContext(server, decision.Citations[0].UCXLAddress, map[string]interface{}{
            "requirement": "temporal navigation support",
        })
        
        err = validator.ValidateCitations(decision)
        assert.NoError(t, err)
    })
}

Database Schema & Storage

Context Storage Schema (BadgerDB)

// Storage keys
const (
    ContextKeyPrefix    = "ctx:"     // ctx:agent/role/project/task/timestamp/path
    TemporalKeyPrefix   = "tmp:"     // tmp:agent/role/project/task -> []TemporalEntry
    IndexKeyPrefix      = "idx:"     // idx:field:value -> []address
    MetadataKeyPrefix   = "meta:"    // meta:address -> ContextMetadata
)

// Indexed fields for efficient querying
var IndexedFields = []string{
    "agent", "role", "project", "task", 
    "content_type", "tags", "timestamp",
}

// Key generation functions
func GenerateContextKey(addr *protocol.UCXLAddress) string {
    return ContextKeyPrefix + addr.ToStorageKey()
}

func GenerateTemporalKey(addr *protocol.UCXLAddress) string {
    return fmt.Sprintf("%s%s/%s/%s/%s", 
        TemporalKeyPrefix, addr.Agent, addr.Role, addr.Project, addr.Task)
}

This implementation roadmap provides the complete foundation for transforming BZZZ v2 into a UCXL-based semantic context publishing system while maintaining its distributed P2P architecture and integrating seamlessly with the CHORUS infrastructure.

Key Files Created:

  • /home/tony/chorus/project-queues/active/BZZZ/BZZZ_V2_UCXL_DEVELOPMENT_PLAN.md
  • /home/tony/chorus/project-queues/active/BZZZ/TECHNICAL_ARCHITECTURE.md
  • /home/tony/chorus/project-queues/active/BZZZ/IMPLEMENTATION_ROADMAP.md

The roadmap shows exactly how to implement UCXL address parsing, temporal navigation, decision node publishing to SLURP, P2P DHT resolution, and MCP integration with detailed code examples and test suites.