stemedb/sdk/go/steme/query.go
jordan c59066949a feat: Add quickstart "Beyond Hello World" sections with Skeptic and Layered endpoints
- Add Layered() method to Go SDK for per-source-class consensus queries
- Add LayeredQueryParams, LayeredResult, TierResolution types to Go SDK
- Create conflict example demonstrating Skeptic and Layered endpoints
- Update quickstart.md with sections 6 (conflict detection) and 7 (authority tiers)
- Remove tracked Go binary and add data/ to .gitignore

The new quickstart sections demonstrate Episteme's differentiating features:
- Skeptic endpoint shows "Trust but Verify" conflict analysis
- Layered endpoint shows per-tier resolution (Clinical vs Anecdotal)

Note: Pre-existing large files flagged by pre-commit hook (technical debt from prior sessions)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-01 21:00:59 -07:00

478 lines
14 KiB
Go

package steme
// QueryParams defines parameters for querying assertions.
//
// All fields are optional. Use QueryBuilder for fluent construction.
type QueryParams struct {
// Filter by subject entity
Subject *string `json:"subject,omitempty"`
// Filter by predicate/relation
Predicate *string `json:"predicate,omitempty"`
// Filter by lifecycle stage
Lifecycle *LifecycleStage `json:"lifecycle,omitempty"`
// Filter by epoch (hex-encoded)
Epoch *string `json:"epoch,omitempty"`
// Apply a lens for conflict resolution
Lens *Lens `json:"lens,omitempty"`
// Maximum number of results to return (defaults to 100)
Limit int `json:"limit,omitempty"`
// Filter by visual similarity (hex-encoded pHash, 16 chars).
// Returns assertions whose visual_hash has hamming distance <= VisualThreshold.
VisualNear *string `json:"visual_near,omitempty"`
// Maximum hamming distance for visual matching (0-64, default: 8).
// Lower values require closer visual similarity.
VisualThreshold *uint32 `json:"visual_threshold,omitempty"`
}
// QueryBuilder provides a fluent API for building query parameters.
type QueryBuilder struct {
params QueryParams
}
// NewQuery creates a new query builder.
//
// Example:
//
// params := steme.NewQuery().
// WithSubject("Tesla_Inc").
// WithPredicate("has_revenue").
// WithLens(steme.LensConsensus).
// WithLimit(10).
// Build()
func NewQuery() *QueryBuilder {
return &QueryBuilder{
params: QueryParams{
Limit: 100, // Default limit
},
}
}
// WithSubject filters by subject entity.
func (b *QueryBuilder) WithSubject(subject string) *QueryBuilder {
b.params.Subject = &subject
return b
}
// WithPredicate filters by predicate/relation.
func (b *QueryBuilder) WithPredicate(predicate string) *QueryBuilder {
b.params.Predicate = &predicate
return b
}
// WithLifecycle filters by lifecycle stage.
func (b *QueryBuilder) WithLifecycle(lifecycle LifecycleStage) *QueryBuilder {
b.params.Lifecycle = &lifecycle
return b
}
// WithEpoch filters by epoch (hex-encoded, 32 bytes).
func (b *QueryBuilder) WithEpoch(epochHex string) *QueryBuilder {
b.params.Epoch = &epochHex
return b
}
// WithLens applies a conflict resolution lens.
func (b *QueryBuilder) WithLens(lens Lens) *QueryBuilder {
b.params.Lens = &lens
return b
}
// WithLimit sets the maximum number of results.
func (b *QueryBuilder) WithLimit(limit int) *QueryBuilder {
b.params.Limit = limit
return b
}
// WithVisualNear filters by visual similarity to a reference pHash.
//
// This enables finding assertions with visually similar screenshots or images.
// The hash should be a hex-encoded 8-byte perceptual hash (16 characters).
//
// The threshold is the maximum hamming distance (0-64, default: 8):
// - 0: Exact match only
// - 8: ~12.5% bit difference, catches resizing/compression
// - 16: ~25% bit difference, more lenient
//
// Assertions without a visual_hash are excluded from results.
//
// Example:
//
// params := steme.NewQuery().
// WithSubject("Tesla_10K").
// WithVisualNear("a3f2b1c4d5e6f708", 5).
// Build()
func (b *QueryBuilder) WithVisualNear(hash string, threshold uint32) *QueryBuilder {
b.params.VisualNear = &hash
b.params.VisualThreshold = &threshold
return b
}
// Build returns the constructed QueryParams.
func (b *QueryBuilder) Build() QueryParams {
return b.params
}
// QueryResult represents the response from a query operation.
type QueryResult struct {
// Matching assertions
Assertions []AssertionResponse `json:"assertions"`
// Total number of results returned
TotalCount int `json:"total_count"`
// Whether there are more results beyond the limit
HasMore bool `json:"has_more"`
}
// AssertionResponse represents a single assertion in query results.
type AssertionResponse struct {
// Content-addressed hash of this assertion (hex-encoded)
Hash string `json:"hash"`
// The subject entity
Subject string `json:"subject"`
// The predicate/relation
Predicate string `json:"predicate"`
// The object value
Object ObjectValue `json:"object"`
// Confidence score (0.0 to 1.0)
Confidence float64 `json:"confidence"`
// Hash of parent assertion (hex-encoded, optional)
ParentHash *string `json:"parent_hash,omitempty"`
// Hash of source evidence (hex-encoded)
SourceHash string `json:"source_hash"`
// Source authority tier
SourceClass SourceClass `json:"source_class"`
// Perceptual hash for visual anchoring (hex-encoded, optional)
VisualHash *string `json:"visual_hash,omitempty"`
// Epoch ID (hex-encoded, optional)
Epoch *string `json:"epoch,omitempty"`
// Lifecycle stage
Lifecycle LifecycleStage `json:"lifecycle"`
// Agent signatures
Signatures []SignatureEntry `json:"signatures"`
// Creation timestamp (Unix epoch)
Timestamp uint64 `json:"timestamp"`
// Semantic embedding vector (optional)
Vector []float32 `json:"vector,omitempty"`
}
// CreateResponse represents the response from a create operation.
type CreateResponse struct {
// Content-addressed hash of the created resource (hex-encoded)
Hash string `json:"hash"`
// Status message
Status string `json:"status"`
}
// SkepticQueryParams defines parameters for the skeptic endpoint.
type SkepticQueryParams struct {
// Subject entity to analyze (required)
Subject string `json:"subject"`
// Predicate/relation to analyze (required)
Predicate string `json:"predicate"`
}
// SkepticResult represents the "Trust but Verify" response.
//
// Unlike QueryResult which picks a winner, SkepticResult shows all
// competing claims with their relative weights.
type SkepticResult struct {
// The subject that was queried
Subject string `json:"subject"`
// The predicate that was queried
Predicate string `json:"predicate"`
// Overall resolution status
Status ResolutionStatus `json:"status"`
// Conflict score (0.0 = unanimous, 1.0 = chaos)
ConflictScore float64 `json:"conflict_score"`
// All distinct claims, ranked by weight_share descending
Claims []ClaimSummary `json:"claims"`
// Total number of candidate assertions considered
CandidatesCount int `json:"candidates_count"`
// Unix timestamp when this view was computed
ComputedAt uint64 `json:"computed_at"`
// Which lens was used (always "Skeptic")
LensName string `json:"lens_name"`
}
// ClaimSummary represents a single competing claim.
type ClaimSummary struct {
// The claimed value
Value ObjectValue `json:"value"`
// Normalized weight (0.0 to 1.0) relative to all claims
WeightShare float64 `json:"weight_share"`
// Number of assertions making this exact claim
AssertionCount uint32 `json:"assertion_count"`
// Hash of the representative assertion (hex-encoded)
RepresentativeHash string `json:"representative_hash"`
// Source provenance
Source SourceSummary `json:"source"`
// Agents supporting this claim
SupportingAgents []AgentSummary `json:"supporting_agents"`
}
// SourceSummary provides minimal source info for provenance.
type SourceSummary struct {
// Hash of the source document (hex-encoded)
SourceHash string `json:"source_hash"`
// Visual anchor hash (hex-encoded, optional)
VisualHash *string `json:"visual_hash,omitempty"`
}
// AgentSummary provides minimal agent info for attribution.
type AgentSummary struct {
// Agent's public key (hex-encoded)
AgentID string `json:"agent_id"`
// Trust score at query time (0.0 to 1.0)
TrustScore float64 `json:"trust_score"`
}
// LayeredQueryParams defines parameters for the layered consensus endpoint.
type LayeredQueryParams struct {
// Subject entity to analyze (required)
Subject string `json:"subject"`
// Predicate/relation to analyze (required)
Predicate string `json:"predicate"`
}
// LayeredResult represents the response from a layered consensus query.
//
// Provides per-tier resolution results plus an overall winner.
// Use this to see "What does Tier 0 (FDA) say? What does Tier 5 (Reddit) say?"
type LayeredResult struct {
// The subject that was queried
Subject string `json:"subject"`
// The predicate that was queried
Predicate string `json:"predicate"`
// Per-tier consensus results, ordered by tier (0 = highest authority first)
// Only tiers with at least one candidate are included.
Tiers []TierResolution `json:"tiers"`
// Overall winner: winner from the highest-authority tier that has candidates
OverallWinner *AssertionResponse `json:"overall_winner,omitempty"`
// Cross-tier disagreement score (0.0 = tiers agree, 1.0 = tiers disagree)
OverallConflictScore float64 `json:"overall_conflict_score"`
// Total candidates considered across all tiers
TotalCandidates int `json:"total_candidates"`
// Unix timestamp when this view was computed
ComputedAt uint64 `json:"computed_at"`
// Which lens was used (always "LayeredConsensus")
LensName string `json:"lens_name"`
}
// TierResolution represents the consensus within a single source class tier.
type TierResolution struct {
// The tier number (0-5). Lower = higher authority.
Tier int `json:"tier"`
// The source class for this tier
SourceClass SourceClass `json:"source_class"`
// The winning assertion from within-tier consensus, if any candidates
Winner *AssertionResponse `json:"winner,omitempty"`
// Number of candidates in this tier
CandidatesCount int `json:"candidates_count"`
// Within-tier conflict score (0.0 = unanimous, 1.0 = max conflict)
ConflictScore float64 `json:"conflict_score"`
// Within-tier resolution confidence (0.0 to 1.0)
ResolutionConfidence float64 `json:"resolution_confidence"`
}
// TraceParams defines parameters for tracing agent queries.
//
// Used to debug "Why did the agent think that?" for incident investigation.
type TraceParams struct {
// Agent public key to trace (hex-encoded, 32 bytes) - required
AgentID string `json:"agent_id"`
// Start of time range (Unix timestamp) - required
From string `json:"from"`
// End of time range (Unix timestamp, defaults to now)
To string `json:"to,omitempty"`
// Filter by subject pattern (e.g., "Tesla*", "auth/*")
Subject string `json:"subject,omitempty"`
// Maximum number of results (default: 100)
Limit int `json:"limit,omitempty"`
}
// TraceResult represents the response from a trace operation.
type TraceResult struct {
// Matching query audit records
Audits []QueryAuditRecord `json:"audits"`
// Total number of results returned
TotalCount int `json:"total_count"`
// Agent ID that was traced (hex-encoded)
AgentID string `json:"agent_id"`
// Time range start (Unix timestamp)
FromTimestamp uint64 `json:"from_timestamp"`
// Time range end (Unix timestamp)
ToTimestamp uint64 `json:"to_timestamp"`
}
// QueryAuditRecord represents a single query audit entry.
type QueryAuditRecord struct {
// Unique identifier for this query (hex-encoded, 32 bytes)
QueryID string `json:"query_id"`
// Agent public key who made the query (hex-encoded, optional)
AgentID *string `json:"agent_id,omitempty"`
// Unix timestamp when the query was executed
Timestamp uint64 `json:"timestamp"`
// Query parameters that were used
Params QueryParamsAudit `json:"params"`
// Hash of the winning assertion (hex-encoded, optional)
ResultHash *string `json:"result_hash,omitempty"`
// Confidence score of the result
ResultConfidence float32 `json:"result_confidence"`
// Assertions that contributed to the result
ContributingAssertions []ContributingAssertion `json:"contributing_assertions"`
}
// QueryParamsAudit represents the parameters used in a query.
type QueryParamsAudit struct {
// Subject filter (optional)
Subject *string `json:"subject,omitempty"`
// Predicate filter (optional)
Predicate *string `json:"predicate,omitempty"`
// Lifecycle filter (optional)
Lifecycle *LifecycleStage `json:"lifecycle,omitempty"`
// Epoch filter (hex-encoded, optional)
Epoch *string `json:"epoch,omitempty"`
// Lens used (optional)
Lens *Lens `json:"lens,omitempty"`
}
// ContributingAssertion represents an assertion that contributed to a query result.
type ContributingAssertion struct {
// Hash of the assertion (hex-encoded)
AssertionHash string `json:"assertion_hash"`
// Weight in the resolution (1.0 for winner)
Weight float32 `json:"weight"`
// Hash of the source evidence (hex-encoded)
SourceHash string `json:"source_hash"`
// Lifecycle stage of the assertion
Lifecycle LifecycleStage `json:"lifecycle"`
}
// SupersessionType defines how an assertion is being superseded.
type SupersessionType string
const (
// SupersessionInvalidate means the old assertion was factually incorrect.
SupersessionInvalidate SupersessionType = "Invalidate"
// SupersessionTemporal means the old assertion was correct but now outdated.
SupersessionTemporal SupersessionType = "Temporal"
// SupersessionRefinement means the old assertion was a simplification.
SupersessionRefinement SupersessionType = "Refinement"
// SupersessionRequiresReview means the old assertion needs human review.
SupersessionRequiresReview SupersessionType = "RequiresReview"
// SupersessionAdditive means the new assertion adds context without invalidating.
SupersessionAdditive SupersessionType = "Additive"
)
// SupersedeParams defines parameters for creating a supersession.
type SupersedeParams struct {
// Hash of the assertion being superseded (hex-encoded, 32 bytes)
TargetHash string `json:"target_hash"`
// How the target is being superseded
SupersessionType SupersessionType `json:"supersession_type"`
// Human-readable explanation (for audit trail)
Reason string `json:"reason"`
// Hash of the replacement assertion (hex-encoded, optional)
// None for RequiresReview or pure invalidation.
NewHash string `json:"new_hash,omitempty"`
// Public key of the agent creating the supersession (hex-encoded, 32 bytes)
AgentID string `json:"agent_id"`
// Signature over the supersession content (hex-encoded, 64 bytes)
Signature string `json:"signature"`
}
// SupersedeResult represents the response from a supersede operation.
type SupersedeResult struct {
// Status message
Status string `json:"status"`
// Hash of the target assertion that was superseded (hex-encoded)
TargetHash string `json:"target_hash"`
// Type of supersession applied
SupersessionType SupersessionType `json:"supersession_type"`
// Unix timestamp when the supersession was recorded
Timestamp uint64 `json:"timestamp"`
}