- Add `content: Option<String>` to SourceRecord with rkyv schema evolution (LegacySourceRecord compat deserializer for backward compatibility) - Add MAX_SOURCE_CONTENT_LEN (1MB) limit with API validation - Strip content from list responses, include in single-source GET - Update Go SDK RegisterSourceRequest with Content field - FCM pipeline extracts PDF text via pdftotext and passes to registration - Dashboard impact panel fetches and displays source content with expand/collapse - Add feed endpoint, dashboard feed panel, and signed assertion support - Update data-structures.md, API docs, and storage docs Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
481 lines
14 KiB
Go
481 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"`
|
|
|
|
// Free-text narrative explaining methodology, limitations, bias, and caveats (optional)
|
|
Narrative *string `json:"narrative,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"`
|
|
}
|