federation

package
v0.8.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 29, 2026 License: MIT Imports: 23 Imported by: 0

Documentation

Overview

Package federation provides cross-project dependency tracking and drift detection.

Package federation provides cross-project dependency tracking and drift detection for local sibling projects. It opens sibling SQLite stores read-only and compares stored dependency state against current git HEAD.

All operations are fail-open: errors are logged and skipped, never propagated to the caller. A broken sibling never blocks the response.

The Resolver is a thin coordinator that delegates to three components:

  • DriftDetector: cross-project drift detection (drift_detector.go)
  • BrainEnricher: brain-enhanced summaries (brain_enricher.go)
  • CrossProjectSearch: entity search, BFS context, memory queries (cross_project_search.go)

Package federation — tracker.go provides Tier 1 deterministic cross-project dependency detection. It reads language manifests (go.mod, package.json, Cargo.toml) from sibling projects to build a module index, then matches import statements in local files against the index.

Detected entities are resolved against the sibling's parsed graph (not regex) to populate ToFile and VerifiedSignature — enabling graph-first drift detection from day one.

Tier 1 covers Go, TypeScript/JavaScript, and Rust — languages with deterministic import paths. Tier 2 (Brain LLM) extends coverage to ambiguous languages in Phase 5.

Package federation — tracker_brain.go provides Tier 2 brain-enhanced cross-project dependency detection. When brain (Ollama) is available, it uses LLM-powered detection for ambiguous languages that Tier 1's deterministic import matching can't handle well (Python, dynamic imports, transitive dependencies, aliased imports that don't match module names).

Key design decisions:

  • Anti-hallucination: EVERY brain-detected dep is validated against the sibling store. If the entity doesn't exist there → discarded silently.
  • Zero false positives: validation makes hallucination a false-negative (missed dep) rather than a false-positive (phantom dep).
  • Fail-open: brain unavailable → Tier 1 only. Still good for Go/TS/Rust.
  • The brain prompt is designed to produce structured JSON output that can be parsed deterministically.

Index

Constants

View Source
const FederationParallelism = 8

FederationParallelism is the max concurrent I/O operations against sibling stores. Each operation opens a SQLite file, so this bounds file descriptor and I/O pressure. Tuned for typical developer machines (8+ cores).

View Source
const SiblingQueryTimeout = 10 * time.Second

SiblingQueryTimeout is the maximum time a single sibling query may take before being cancelled. Prevents one hanging sibling from exhausting a parallelism slot indefinitely.

Variables

This section is empty.

Functions

func FindGoMod

func FindGoMod(dir string) string

FindGoMod searches for go.mod in the given directory and parent directories.

func SiblingDBPath

func SiblingDBPath(projectPath string) (string, error)

SiblingDBPath derives the store DB path for a sibling project using the same logic as store.DefaultPath.

Types

type BrainDetectedDep

type BrainDetectedDep struct {
	TargetProject string  `json:"target_project"` // federation alias
	TargetEntity  string  `json:"target_entity"`  // function/class/struct name
	ImportPath    string  `json:"import_path"`    // the import or URL reference
	Confidence    float64 `json:"confidence"`     // 0.0–1.0
}

BrainDetectedDep is a single dependency detected by the brain LLM.

type BrainDetector

type BrainDetector struct {
	// Generate calls the brain LLM with a prompt and returns the response.
	// This decouples tracker_brain from the brain package — any LLM backend
	// that implements this signature works.
	Generate func(ctx context.Context, prompt string) (string, error)
	// contains filtered or unexported fields
}

BrainDetector provides Tier 2 dependency detection using LLM analysis. It wraps a brain generate function and a resolver for validation.

func NewBrainDetector

func NewBrainDetector(generate func(ctx context.Context, prompt string) (string, error), resolver *Resolver, aliases []string) *BrainDetector

NewBrainDetector creates a Tier 2 detector. generate is the LLM function (typically brain.Client's Generate or a wrapper). If generate is nil, the detector is disabled and DetectDeps returns nil.

func (*BrainDetector) DetectDeps

func (bd *BrainDetector) DetectDeps(ctx context.Context, fileContent string, maxCodeLen int) []RawCrossDep

DetectDeps uses the brain LLM to detect cross-project dependencies in source code that Tier 1's deterministic matching may have missed. Returns only validated deps (entity exists in sibling store).

The detection flow:

  1. Build prompt with file content + sibling aliases
  2. Call brain LLM
  3. Parse JSON lines from response
  4. Filter by confidence threshold (>= 0.7)
  5. Validate each dep against sibling store (anti-hallucination)
  6. Return only validated deps

type BrainEnricher

type BrainEnricher struct {
	// contains filtered or unexported fields
}

BrainEnricher provides brain-enhanced cross-project entity summaries and drift explanations. Optional — when brain is unavailable, falls back to raw entity signatures and structural diffs.

func (*BrainEnricher) BrainDriftSummary

func (b *BrainEnricher) BrainDriftSummary(ctx context.Context, oldSig, newSig, entityName string) string

BrainDriftSummary generates a brain-enhanced drift summary for a changed entity. When brain is available and generate is set, produces a human-readable natural-language explanation. When unavailable, uses structuralSignatureDiff (the existing graph-based heuristic).

func (*BrainEnricher) GetEntitySummary

func (b *BrainEnricher) GetEntitySummary(ctx context.Context, alias, entityName string) string

GetEntitySummary returns a brain-generated summary for a sibling entity. Falls back to the entity's raw signature if brain is unavailable or has no summary. This is the cross-project context summarization path.

func (*BrainEnricher) SetBrain

func (b *BrainEnricher) SetBrain(brain BrainSummaryProvider)

SetBrain attaches a brain summary provider for cross-project summarization. Optional — when nil, cross-project summaries use raw entity signatures. Thread-safe: may be called concurrently with readers.

func (*BrainEnricher) SetBrainGenerate

func (b *BrainEnricher) SetBrainGenerate(fn func(ctx context.Context, prompt string) (string, error))

SetBrainGenerate attaches an LLM generate function for brain-enhanced drift summaries. When set and brain is available, BrainDriftSummary feeds the structural diff to the LLM for a natural-language explanation. Typically wired to the brain's ingestor LLM client. Thread-safe: may be called concurrently with readers.

type BrainSummaryProvider

type BrainSummaryProvider interface {
	Summary(projectID string, nodeID string) string
	Available() bool
}

BrainSummaryProvider retrieves brain summaries for cross-project entities. Decoupled from the brain package so federation doesn't import it directly.

type BrainTrackerAdapter

type BrainTrackerAdapter struct {
	// contains filtered or unexported fields
}

BrainTrackerAdapter implements watcher.BrainCrossProjectTracker by combining BrainDetector (LLM detection) with DeterministicDetector (entity resolution + dedup). This is the concrete type wired into the watcher.

func NewBrainTrackerAdapter

func NewBrainTrackerAdapter(brain *BrainDetector, detector *DeterministicDetector) *BrainTrackerAdapter

NewBrainTrackerAdapter creates a tracker adapter for the watcher. Returns nil if brain or detector is nil.

func (*BrainTrackerAdapter) DetectAndStoreBrain

func (a *BrainTrackerAdapter) DetectAndStoreBrain(ctx context.Context, filePath string, localStore *store.Store)

DetectAndStoreBrain implements watcher.BrainCrossProjectTracker. Reads the file, calls brain for detection, resolves and deduplicates against Tier 1 deps, then stores any new deps.

type Clock

type Clock func() time.Time

Clock is a function that returns the current time. Injected into Resolver for deterministic staleness testing.

type CrossProjectDepStatus

type CrossProjectDepStatus struct {
	Project     string `json:"project"`
	Entity      string `json:"entity"`
	File        string `json:"file"`
	Drifted     bool   `json:"drifted"`
	DiffSummary string `json:"diff_summary,omitempty"`
}

CrossProjectDepStatus is used in prepare_context enrichment.

type CrossProjectSearch

type CrossProjectSearch struct {
	// contains filtered or unexported fields
}

CrossProjectSearch handles cross-project entity lookups, BFS context carving, dependency enrichment, and memory/episode search across sibling stores. This is the component that cross-project knowledge queries call.

func (*CrossProjectSearch) EntityExists

func (s *CrossProjectSearch) EntityExists(ctx context.Context, alias string, entityName string) bool

EntityExists checks whether an entity exists in a sibling's store. Fail-open: returns false on any error.

func (*CrossProjectSearch) FindEntities

func (s *CrossProjectSearch) FindEntities(ctx context.Context, query string, aliases []string, limit int) []FederatedSearchResult

FindEntities searches sibling stores for entities matching query. If aliases is nil or empty, all siblings are searched. Errors on individual siblings are silently skipped. BUG-023: queries run in parallel via errgroup for O(1) latency.

func (*CrossProjectSearch) GetDepsForEntity

func (s *CrossProjectSearch) GetDepsForEntity(ctx context.Context, entityID string, localStore *store.Store) []CrossProjectDepStatus

GetDepsForEntity returns cross-project deps for a specific local entity. Used by prepare_context to enrich responses. Returns nil when the entity has no cross-project dependencies or the local store is unavailable.

func (*CrossProjectSearch) GetEntityContext

func (s *CrossProjectSearch) GetEntityContext(ctx context.Context, entity string, alias string, depth int) *FederatedContext

GetEntityContext loads a sibling graph and carves BFS context for an entity. This is the "full BFS" option — opt-in via projects= parameter on tools. NOT called automatically during enrichment. Returns nil on any error.

func (*CrossProjectSearch) SearchEpisodes

func (s *CrossProjectSearch) SearchEpisodes(ctx context.Context, query string, aliases []string, limit int) []FederatedEpisode

SearchEpisodes queries sibling stores' episodes tables using FTS5 search. Results are labeled with their source alias. If aliases is nil or empty, all siblings are searched. Errors on individual siblings are silently skipped. BUG-023: queries run in parallel via errgroup for O(1) latency.

func (*CrossProjectSearch) SearchMemoriesForEntity

func (s *CrossProjectSearch) SearchMemoriesForEntity(ctx context.Context, entityName string, aliases []string) []FederatedMemoryHint

SearchMemoriesForEntity searches sibling stores for episodic memories related to a specific entity. Uses graph-anchored search (node ID in affected_nodes) as the primary path — more precise than text matching. Falls back to FTS text search if no node ID is found. Returns 1-line hints for prepare_context. At most 3 hints per sibling. BUG-023: queries run in parallel via errgroup for O(1) latency.

type DeterministicDetector

type DeterministicDetector struct {
	// contains filtered or unexported fields
}

DeterministicDetector detects cross-project dependencies by matching import statements against a module index built from sibling manifests.

Thread-safe: mu protects modules so Rebuild() and DetectDeps() can run concurrently. Entity resolution goes through the Resolver which has its own synchronization.

func NewDeterministicDetector

func NewDeterministicDetector(entries []config.FederationEntry, resolver *Resolver) *DeterministicDetector

NewDeterministicDetector creates a detector and builds the module index from federation entries' manifest files. Errors reading individual manifests are logged and skipped (fail-open).

func (*DeterministicDetector) DetectAndStore

func (d *DeterministicDetector) DetectAndStore(ctx context.Context, filePath string, localStore *store.Store)

DetectAndStore scans a file for cross-project imports, resolves entities against sibling stores, and persists the results. This method satisfies the watcher.CrossProjectTracker interface. Errors are logged and skipped.

func (*DeterministicDetector) DetectDeps

func (d *DeterministicDetector) DetectDeps(ctx context.Context, filePath string, localStore *store.Store) []store.CrossProjectDep

DetectDeps scans a file for cross-project imports and resolves them against sibling graphs.

func (*DeterministicDetector) Rebuild

func (d *DeterministicDetector) Rebuild(entries []config.FederationEntry)

Rebuild replaces the module index with a fresh one built from entries. Safe to call concurrently with DetectDeps — protected by mu.

func (*DeterministicDetector) ResolveBrainDeps

func (d *DeterministicDetector) ResolveBrainDeps(
	ctx context.Context,
	brainDeps []RawCrossDep,
	tier1Deps []store.CrossProjectDep,
	filePath string,
) []store.CrossProjectDep

ResolveBrainDeps takes deps detected by the brain detector and converts them to fully populated CrossProjectDep structs with entity resolution and verified signatures. Deduplicates against existing Tier 1 deps.

func (*DeterministicDetector) StoreDeps

func (d *DeterministicDetector) StoreDeps(deps []store.CrossProjectDep, localStore *store.Store)

StoreDeps persists detected dependencies via the local store. Errors are logged and skipped (fail-open). Existing deps for the same file are cleaned up before inserting new ones.

type DiscoveredSibling

type DiscoveredSibling struct {
	Path string `json:"path"`
	Name string `json:"name"` // directory basename
	Hint string `json:"hint"` // how it was detected
}

DiscoveredSibling represents a potential federation entry found by scanning the parent directory for other Synapses-indexed projects.

func DiscoverSiblings

func DiscoverSiblings(projectRoot string) []DiscoveredSibling

DiscoverSiblings scans the parent directory of projectRoot for other directories that appear to be Synapses-indexed projects (contain synapses.json or .synapses/). Returns suggestions only — never auto-adds to federation config. Skips the current project. Timeout: 500ms max. Depth: 1 level only.

type DriftAlert

type DriftAlert struct {
	Project      string   `json:"project"`       // federation alias
	Entity       string   `json:"entity"`        // entity name in sibling
	File         string   `json:"file"`          // file in sibling
	Change       string   `json:"change"`        // "signature_changed" | "removed" | "file_deleted"
	Severity     string   `json:"severity"`      // "breaking" | "info"
	DiffSummary  string   `json:"diff_summary"`  // human-readable summary of what changed
	YourCallers  []string `json:"your_callers"`  // local entities that call this sibling entity
	OldCommit    string   `json:"old_commit"`    // commit hash at last verification
	NewCommit    string   `json:"new_commit"`    // current HEAD of sibling
	LastVerified string   `json:"last_verified"` // timestamp of last verification
}

DriftAlert represents a cross-project dependency whose sibling entity changed.

type DriftDetector

type DriftDetector struct {
	// contains filtered or unexported fields
}

DriftDetector handles cross-project dependency drift detection. It compares stored dependency signatures against current sibling state using a graph-first strategy with git-diff fallback.

func (*DriftDetector) CheckDrift

func (d *DriftDetector) CheckDrift(ctx context.Context, localStore *store.Store) []DriftAlert

CheckDrift runs drift detection across all federation entries. Results are session-cached per alias.

func (*DriftDetector) InvalidateCache

func (d *DriftDetector) InvalidateCache()

InvalidateCache clears the drift result cache.

type EntryStatus

type EntryStatus struct {
	Alias     string    `json:"alias"`
	Path      string    `json:"path"`
	Status    string    `json:"status"` // "indexed" | "stale" | "not_indexed" | "not_found" | "incompatible"
	NodeCount int       `json:"node_count,omitempty"`
	FileCount int       `json:"file_count,omitempty"`
	IndexedAt time.Time `json:"indexed_at,omitempty"`
	GitHead   string    `json:"git_head,omitempty"`
	Error     string    `json:"error,omitempty"`
}

EntryStatus describes the health of one federation entry.

type FederatedContext

type FederatedContext struct {
	Alias     string             `json:"alias"`
	Entity    string             `json:"entity"`
	NodeCount int                `json:"node_count"`
	Nodes     []graph.CarvedNode `json:"nodes"`
	Edges     []*graph.Edge      `json:"edges,omitempty"`
}

FederatedContext holds BFS context carved from a sibling's graph.

type FederatedEpisode

type FederatedEpisode struct {
	Alias   string        `json:"alias"`
	Episode store.Episode `json:"episode"`
}

FederatedEpisode wraps a store.Episode with its source project alias.

type FederatedMemoryHint

type FederatedMemoryHint struct {
	Alias   string `json:"alias"`
	Summary string `json:"summary"` // 1-line: "AuthService rewrite driven by compliance"
	Query   string `json:"query"`   // recall query to get full context
}

FederatedMemoryHint is a 1-line summary of a sibling memory relevant to an entity. Used in prepare_context's Relevant tier to hint at cross-project knowledge.

type FederatedSearchResult

type FederatedSearchResult struct {
	Alias   string               `json:"alias"`
	Results []store.SearchResult `json:"results"`
}

FederatedSearchResult groups entity search results from one sibling.

type GoModRequire

type GoModRequire struct {
	Path    string // module path (e.g., "github.com/foo/bar")
	Version string // version (e.g., "v1.2.3")
}

GoModRequire is a single require directive from go.mod.

type GoModule

type GoModule struct {
	ModulePath string            // module path (e.g., "github.com/org/repo")
	GoVersion  string            // go version (e.g., "1.21")
	Require    []GoModRequire    // required dependencies
	Replace    map[string]string // replace directives: old module → new path/module
}

GoModule represents a parsed go.mod file.

func ParseGoMod

func ParseGoMod(goModPath string) (*GoModule, error)

ParseGoMod reads and parses a go.mod file, extracting module path, require directives, and replace directives.

func (*GoModule) MatchesSibling

func (m *GoModule) MatchesSibling(importPath string, siblingModules map[string]string) (alias string, matched bool)

MatchesSibling checks if a Go import path matches a sibling project's module path. Returns the sibling alias and true if matched, or empty and false.

type ModuleDependency

type ModuleDependency struct {
	ImportPath   string // the import path as it appears in source code
	ModulePath   string // the module/package identifier
	Version      string // version string (e.g., "v1.2.3", "workspace:*")
	SiblingAlias string // federation alias if matches a sibling, or ""
	Ecosystem    string // "gomod", "npm", "pnpm"
}

ModuleDependency represents a cross-repo dependency discovered from package manifests (go.mod, package.json).

func DiscoverModuleSiblings

func DiscoverModuleSiblings(projectRoot string, entries []config.FederationEntry) []ModuleDependency

DiscoverModuleSiblings analyzes the project's dependency manifests (go.mod, package.json) and returns dependencies that match known federation siblings. This enables automatic cross-repo edge discovery without manual configuration.

projectRoot: absolute path to the project being indexed entries: federation entries from synapses.json

func FilterSiblingDeps

func FilterSiblingDeps(deps []ModuleDependency) []ModuleDependency

FilterSiblingDeps returns only dependencies that match a known federation sibling.

type NPMWorkspace

type NPMWorkspace struct {
	RootDir  string            // absolute path to monorepo root
	Packages map[string]string // package name → relative directory (e.g., "@org/auth" → "packages/auth")
}

NPMWorkspace represents a parsed monorepo workspace configuration.

func ParseNPMWorkspace

func ParseNPMWorkspace(projectRoot string) *NPMWorkspace

ParseNPMWorkspace detects and parses npm/pnpm/yarn workspace configuration from a project root. Returns nil if no workspace is detected.

func (*NPMWorkspace) MatchesWorkspacePackage

func (ws *NPMWorkspace) MatchesWorkspacePackage(importPath string) (pkgDir string, matched bool)

MatchesWorkspacePackage checks if an import path matches a workspace package. Returns the package directory and true if matched. Prefers longest package name match to avoid ambiguity with overlapping names (e.g., "@org/auth" vs "@org/auth-utils").

type RawCrossDep

type RawCrossDep struct {
	FromFile      string // local file path containing the import
	FromImport    string // the import path that matched
	ToProject     string // federation alias
	ToEntity      string // entity name referenced in the import
	DetectionTier string // "deterministic" or "brain"
}

RawCrossDep is an unverified cross-project dependency detected from import analysis. The tracker resolves these against the sibling store before converting to store.CrossProjectDep for storage.

type Resolver

type Resolver struct {
	// contains filtered or unexported fields
}

Resolver provides cross-project query capabilities over local sibling SQLite stores. Stores are opened lazily on first access and cached for the session lifetime.

Resolver is a thin coordinator that delegates to three components:

  • drift: *DriftDetector — drift detection across siblings
  • brain: *BrainEnricher — brain-enhanced summaries and explanations
  • search: *CrossProjectSearch — entity search, BFS context, memory queries

func NewResolver

func NewResolver(entries []config.FederationEntry, configDir string) *Resolver

NewResolver creates a Resolver for the given federation entries. configDir is the directory containing synapses.json (paths are already resolved to absolute by config.Load).

func NewResolverWithClock

func NewResolverWithClock(entries []config.FederationEntry, configDir string, clock Clock) *Resolver

NewResolverWithClock creates a Resolver with a custom time source. Used in tests for deterministic staleness checks.

func (*Resolver) Aliases

func (r *Resolver) Aliases() []string

Aliases returns all configured federation aliases.

func (*Resolver) BrainDriftSummary

func (r *Resolver) BrainDriftSummary(ctx context.Context, oldSig, newSig, entityName string) string

BrainDriftSummary delegates to BrainEnricher.

func (*Resolver) CachedHead

func (r *Resolver) CachedHead(ctx context.Context, alias string) string

CachedHead is the exported counterpart of cachedHead. It returns the cached git HEAD commit hash for a sibling project, fetching it fresh if not cached. Returns "" if the alias is unknown, not a git repo, or git is unavailable. Safe for concurrent use.

func (*Resolver) CheckDrift

func (r *Resolver) CheckDrift(ctx context.Context, localStore *store.Store) []DriftAlert

CheckDrift delegates to DriftDetector.

func (*Resolver) Close

func (r *Resolver) Close()

Close releases all open sibling stores.

func (*Resolver) EntityExists

func (r *Resolver) EntityExists(ctx context.Context, alias string, entityName string) bool

EntityExists delegates to CrossProjectSearch.

func (*Resolver) FindEntities

func (r *Resolver) FindEntities(ctx context.Context, query string, aliases []string, limit int) []FederatedSearchResult

FindEntities delegates to CrossProjectSearch.

func (*Resolver) GetDepsForEntity

func (r *Resolver) GetDepsForEntity(ctx context.Context, entityID string, localStore *store.Store) []CrossProjectDepStatus

GetDepsForEntity delegates to CrossProjectSearch.

func (*Resolver) GetEntityContext

func (r *Resolver) GetEntityContext(ctx context.Context, entity string, alias string, depth int) *FederatedContext

GetEntityContext delegates to CrossProjectSearch.

func (*Resolver) GetEntitySummary

func (r *Resolver) GetEntitySummary(ctx context.Context, alias, entityName string) string

GetEntitySummary delegates to BrainEnricher.

func (*Resolver) GetStore

func (r *Resolver) GetStore(alias string) *store.Store

GetStore is the exported version of getStore. Returns the cached sibling store for the alias, opening it lazily. Returns nil on any error (fail-open).

func (*Resolver) InvalidateCache

func (r *Resolver) InvalidateCache()

InvalidateCache clears all cached state — stores, drift results, git heads, and compatibility results. Existing store handles are closed.

func (*Resolver) SearchEpisodes

func (r *Resolver) SearchEpisodes(ctx context.Context, query string, aliases []string, limit int) []FederatedEpisode

SearchEpisodes delegates to CrossProjectSearch.

func (*Resolver) SearchMemoriesForEntity

func (r *Resolver) SearchMemoriesForEntity(ctx context.Context, entityName string, aliases []string) []FederatedMemoryHint

SearchMemoriesForEntity delegates to CrossProjectSearch.

func (*Resolver) SetBrain

func (r *Resolver) SetBrain(brain BrainSummaryProvider)

SetBrain delegates to BrainEnricher.

func (*Resolver) SetBrainGenerate

func (r *Resolver) SetBrainGenerate(fn func(ctx context.Context, prompt string) (string, error))

SetBrainGenerate delegates to BrainEnricher.

func (*Resolver) SetGitHead

func (r *Resolver) SetGitHead(alias, head string)

SetGitHead stores a cached HEAD commit hash for a sibling alias. Exposed so that DriftDetector can update the cache without reaching into Resolver internals (avoids lock ordering risks).

func (*Resolver) SiblingProjectID

func (r *Resolver) SiblingProjectID(alias string) string

SiblingProjectID derives the brain-compatible projectID for a sibling. Uses the same FNV32a hash of the absolute path as the main project.

func (*Resolver) Status

func (r *Resolver) Status(ctx context.Context) []EntryStatus

Status returns health info for each federation entry. Errors on individual entries are contained — a broken sibling returns a status entry with Error set, never a top-level error. Entries are checked in parallel (bounded to 8) to avoid 20×I/O latency at large federation sizes. Result ordering matches r.entries ordering.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL