query

package
v0.1.2 Latest Latest
Warning

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

Go to latest
Published: Apr 10, 2026 License: AGPL-3.0 Imports: 14 Imported by: 0

Documentation

Overview

Package query implements the 6-stage retrieval cascade for BubbleFish Nexus. It provides query normalization (CanonicalQuery), the cascade orchestrator, and Stage 3 structured lookup. Stages 1, 2, 4, and 5 are stub pass-throughs pending later phases.

Reference: Tech Spec Section 3.4 — The 6-Stage Retrieval Cascade.

Index

Constants

View Source
const (
	DecayModeExponential = "exponential"
	DecayModeStep        = "step"
)

DecayMode constants for temporal decay reranking.

View Source
const (
	ProfileFast     = "fast"
	ProfileBalanced = "balanced"
	ProfileDeep     = "deep"
)

Retrieval profile names. Every query resolves to exactly one of these.

Reference: Tech Spec Section 3.5.

View Source
const StageFastPath = -1

StageFastPath is the sentinel RetrievalStage value used when the exact-subject fast path handles the query. It is distinct from stages 0–5 so callers can map it to the string "fast_path" in _nexus metadata.

Reference: Tech Spec Section 3.7.

Variables

This section is empty.

Functions

func FinalScore

func FinalScore(cosSim, daysElapsed float64, cfg DecayConfig) float64

FinalScore computes the temporal-decay-adjusted retrieval score.

final_score = (cos_sim * 0.7) + (recency_weight * 0.3)

cosSim must be in [0, 1]. daysElapsed is the age of the memory in days.

This function is deterministic: the same inputs always produce the same output. Reference: Tech Spec Section 3.6 (determinism invariant).

func HybridMerge

func HybridMerge(
	stage3 []destination.TranslatedPayload,
	stage4 []destination.ScoredRecord,
	maxResults int,
	decayEnabled bool,
	decayCfg DecayConfig,
	now time.Time,
) []destination.TranslatedPayload

HybridMerge implements Stage 5 of the 6-stage retrieval cascade: deduplication, temporal decay reranking, and trimming to maxResults.

It accepts Stage 3 results (structured lookup, no cosine score) and Stage 4 results (semantic retrieval, with cosine score from SemanticSearch). Records are deduplicated by payload_id; Stage 4's cosine score takes precedence over the neutral score for any record appearing in both sets.

When decayEnabled is true, temporal decay is applied using decayCfg, and records are ranked by final_score = (cos_sim * 0.7) + (recency_weight * 0.3). When decayEnabled is false, records are ranked by cosine similarity alone.

Ranking is deterministic: ties are broken by payload_id (lexicographic ascending) so the same inputs always produce the same ordering.

maxResults caps the output. Pass 0 to return all merged records.

Reference: Tech Spec Section 3.4 — Stage 5, Section 3.6.

func IsFastPath

func IsFastPath(q CanonicalQuery) bool

IsFastPath reports whether the query shape qualifies for the exact-subject fast path. The fast path is eligible when the query contains a subject filter and a limit but no free-text search (Q), no actor_type filter, and no cursor offset. This allows Nexus to bypass the full cascade and execute a direct indexed query: SELECT * FROM memories WHERE subject = ? ORDER BY timestamp DESC LIMIT ?.

The fast path is auto-selected on query shape match — no opt-in required.

Reference: Tech Spec Section 3.7.

func ProfileDecayEnabled

func ProfileDecayEnabled(profile string) bool

ProfileDecayEnabled reports whether temporal decay reranking is active for the given profile. Fast profiles disable decay entirely.

Reference: Tech Spec Section 3.5 (Temporal Decay column).

func ProfileEnabled

func ProfileEnabled(stage int, profile string) bool

ProfileEnabled reports whether the given cascade stage is enabled for the given retrieval profile. Unknown profiles are treated as balanced.

This function is the single authority for stage/profile gating. It is checked before each stage in the cascade.

Reference: Tech Spec Section 3.5.

func StageName

func StageName(stage int) string

StageName returns the human-readable stage name for use in _nexus.stage response metadata.

Reference: Tech Spec Section 3.7, Section 7.2.

func ValidProfile

func ValidProfile(p string) bool

ValidProfile reports whether p is a recognised retrieval profile name.

Types

type CanonicalQuery

type CanonicalQuery struct {
	// Destination is the target destination name.
	Destination string
	// Namespace restricts results to a specific source namespace.
	Namespace string
	// Subject is a subject filter. Empty means all subjects.
	Subject string
	// Q is a free-text content filter. Empty means no filter.
	Q string
	// Limit is the page size, clamped to [1, destination.MaxQueryLimit].
	Limit int
	// CursorOffset is the decoded integer offset from the opaque base64 cursor.
	// Zero means "first page".
	CursorOffset int
	// RawCursor is the original opaque cursor as provided by the client.
	// Stored so Stage 3 can pass it through to the underlying querier unchanged.
	RawCursor string
	// Profile is the retrieval profile: "fast", "balanced", or "deep".
	// Defaults to "balanced" when the caller does not specify one.
	Profile string
	// ActorType filters results by provenance (user, agent, system). Empty
	// means no filter. Forwarded to the querier in later phases.
	ActorType string
	// Collection is an optional collection name within the destination. When
	// set, per-collection decay overrides are resolved from
	// [destination.decay.collections.<name>].
	//
	// Reference: Tech Spec Section 3.6.
	Collection string
}

CanonicalQuery is the normalised, validated form of a query request. It is produced from raw QueryParams by Normalize and is the single input type for every cascade stage.

Limit is clamped to [1, destination.MaxQueryLimit]. CursorOffset is the decoded integer from the opaque base64 cursor. Profile defaults to "balanced" when the caller does not specify one.

func Normalize

Normalize converts raw QueryParams into a CanonicalQuery, applying defaults and enforcing invariants:

  • Limit is clamped via destination.ClampLimit (0 → 20, >200 → 200).
  • Cursor is decoded; a decode error is returned to the caller.
  • Profile defaults to "balanced" when empty.

Normalize does NOT perform policy checks — that is Stage 0's responsibility.

Reference: Tech Spec Section 3.8.

type CascadeResult

type CascadeResult struct {
	// Records is the page of memories returned by the winning stage.
	Records []destination.TranslatedPayload
	// NextCursor is the opaque base64 cursor for the next page. Empty when
	// HasMore is false.
	NextCursor string
	// HasMore is true when additional pages are available.
	HasMore bool
	// Profile is the retrieval profile that was used.
	Profile string
	// RetrievalStage is the numeric stage number that produced results.
	// Zero when Denial is set. StageFastPath (-1) when the exact-subject fast
	// path was used.
	RetrievalStage int
	// Denial is non-nil when Stage 0 blocked the request. The caller must
	// return HTTP 403 with Denial.Code as the error body.
	Denial *PolicyDenial
	// SemanticUnavailable is true when the embedding provider was not
	// configured or was unreachable. Callers should set
	// _nexus.semantic_unavailable = true in the response metadata.
	//
	// Reference: Tech Spec Section 3.4 — Stage 4, Phase 5 Behavioral Contract 4.
	SemanticUnavailable bool
	// SemanticUnavailableReason is a human-readable explanation for why semantic
	// search was skipped. Set when SemanticUnavailable is true.
	SemanticUnavailableReason string

	// FirewallResult holds the outcome of the retrieval firewall PostFilter.
	// Non-nil when the firewall is enabled and executed. The handler uses this
	// to populate the interaction record and set _nexus.retrieval_firewall_filtered.
	// Reference: Tech Spec Addendum Section A3.5.
	FirewallResult *firewall.FilterResult

	// Debug holds optional per-stage diagnostic information. Populated only
	// when the cascade is run in debug mode. Reference: Tech Spec Section 7.3.
	Debug *DebugInfo
}

CascadeResult holds the output of a completed cascade run. When Denial is non-nil the caller must return HTTP 403 — all other fields are zero-valued.

Reference: Tech Spec Section 3.4.

type CascadeRunner

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

CascadeRunner executes the 6-stage retrieval cascade. All state is held in struct fields; there are no package-level variables.

Reference: Tech Spec Section 3.4.

func New

func New(querier destination.Querier, logger *slog.Logger) *CascadeRunner

New creates a CascadeRunner backed by the provided querier. If logger is nil the default slog logger is used.

func (*CascadeRunner) Run

Run executes the 6-stage retrieval cascade for the given source policy and canonical query. Stages execute strictly in order 0 → 5. Each stage may produce results and short-circuit, pass through to the next stage, or block the request entirely (Stage 0 only).

Reference: Tech Spec Section 3.4.

func (*CascadeRunner) WithDebug

func (cr *CascadeRunner) WithDebug(enabled bool) *CascadeRunner

WithDebug enables debug mode. When true, the CascadeResult.Debug field is populated with per-stage diagnostic information. Reference: Tech Spec Section 7.3.

func (*CascadeRunner) WithDecayCounter

func (cr *CascadeRunner) WithDecayCounter(c prometheus.Counter) *CascadeRunner

WithDecayCounter attaches a Prometheus counter that is incremented each time temporal decay reranking is applied in Stage 5. Pass nil to disable.

Reference: Tech Spec Section 11.3 — bubblefish_temporal_decay_applied_total.

func (*CascadeRunner) WithDestinations

func (cr *CascadeRunner) WithDestinations(dests map[string]*config.Destination) *CascadeRunner

WithDestinations attaches the destination configuration map to the runner, enabling per-destination and per-collection temporal decay resolution in Stage 5. Returns the runner for method chaining.

Reference: Tech Spec Section 3.6.

func (*CascadeRunner) WithEmbeddingClient

func (cr *CascadeRunner) WithEmbeddingClient(c embedding.EmbeddingClient, embeddingLatency prometheus.Observer) *CascadeRunner

WithEmbeddingClient attaches an EmbeddingClient to the runner, enabling Stage 2 (semantic cache) and Stage 4 (semantic retrieval). A nil client is valid and results in graceful degradation: Stages 2+4 are skipped and CascadeResult.SemanticUnavailable is set to true.

embeddingLatency is an optional prometheus.Observer for recording embedding call duration. Pass nil to disable metric recording.

Reference: Tech Spec Section 3.4 — Stage 4, Phase 5 Behavioral Contract 5.

func (*CascadeRunner) WithExactCache

func (cr *CascadeRunner) WithExactCache(c *cache.ExactCache) *CascadeRunner

WithExactCache attaches an ExactCache to the runner, enabling Stage 1 retrieval. Returns the runner for method chaining.

Reference: Tech Spec Section 3.4 — Stage 1.

func (*CascadeRunner) WithFirewall

func (cr *CascadeRunner) WithFirewall(fw *firewall.RetrievalFirewall) *CascadeRunner

WithFirewall attaches a RetrievalFirewall to the runner, enabling pre-query tier/namespace checks in Stage 0 and post-retrieval label/tier filtering after Stage 5. When fw is nil or not enabled, all firewall logic is skipped.

Reference: Tech Spec Addendum Section A3.5.

func (*CascadeRunner) WithRetrievalConfig

func (cr *CascadeRunner) WithRetrievalConfig(cfg config.RetrievalConfig) *CascadeRunner

WithRetrievalConfig injects the global retrieval configuration used to determine the over-sample factor and default temporal decay parameters. Returns the runner for method chaining.

Reference: Tech Spec Section 3.5, Section 3.6.

func (*CascadeRunner) WithSemanticCache

func (cr *CascadeRunner) WithSemanticCache(c *cache.SemanticCache) *CascadeRunner

WithSemanticCache attaches a SemanticCache to the runner, enabling Stage 2 semantic cache retrieval. Returns the runner for method chaining.

Reference: Tech Spec Section 3.4 — Stage 2.

type DebugInfo

type DebugInfo struct {
	StagesHit           []string           `json:"stages_hit"`
	CandidatesPerStage  map[string]int     `json:"candidates_per_stage"`
	PerStageLatencyMs   map[string]float64 `json:"per_stage_latency_ms"`
	CacheHit            bool               `json:"cache_hit"`
	CacheType           string             `json:"cache_type"`
	TemporalDecayConfig struct {
		Mode             string  `json:"mode"`
		HalfLifeDays     float64 `json:"half_life_days"`
		OverSampleFactor int     `json:"over_sample_factor"`
	} `json:"temporal_decay_config"`
	TotalLatencyMs float64 `json:"total_latency_ms"`
}

DebugInfo holds per-stage diagnostic data for the _nexus.debug response. Reference: Tech Spec Section 7.3.

type DecayConfig

type DecayConfig struct {
	// Enabled is true when temporal decay reranking should be applied.
	Enabled bool
	// HalfLifeDays is the number of days after which a memory's recency weight
	// is halved. Must be > 0 when Enabled is true.
	HalfLifeDays float64
	// Mode is "exponential" (default) or "step".
	Mode string
	// StepThresholdDays is the cut-off for step mode: entries older than this
	// threshold receive a weight of 0.1. Only used when Mode = "step".
	StepThresholdDays float64
}

DecayConfig is the resolved temporal decay configuration for a single query. Produced by ResolveDecay; never mutated after construction.

Reference: Tech Spec Section 3.6.

func ResolveDecay

func ResolveDecay(global config.RetrievalConfig, destDecay config.DestinationDecayConfig, collection string, srcDecay config.PolicyDecayConfig, profile string) DecayConfig

ResolveDecay resolves the effective DecayConfig for a query by applying the tiered precedence rules defined in Tech Spec Section 3.6:

  1. Global: [retrieval] section in daemon.toml (RetrievalConfig).
  2. Per-destination: [destination.decay] section in destination TOML.
  3. Per-collection: [destination.decay.collections.<name>] override.

Source policy ([source.policy.decay]) is applied as an additional override after the destination tiers. The most specific non-zero value wins. A zero HalfLifeDays or empty Mode at a given tier falls through to the next tier.

When no tier has TimeDecay enabled, Enabled = false and decay is skipped.

Reference: Tech Spec Section 3.6.

type PolicyDenial

type PolicyDenial struct {
	// Code is the machine-readable error code sent to the client.
	Code string
	// Reason is the human-readable explanation sent to the client.
	Reason string
}

PolicyDenial is returned by Stage 0 when a query request is blocked by policy. The caller (typically the HTTP handler) should translate Code into an appropriate HTTP 403 response.

Reference: Tech Spec Section 3.4 — Stage 0.

func (*PolicyDenial) Error

func (d *PolicyDenial) Error() string

Error implements the error interface so PolicyDenial can be used as an error.

Jump to

Keyboard shortcuts

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