201 lines
6.5 KiB
Go
201 lines
6.5 KiB
Go
package epistemics
|
|
|
|
import (
|
|
"errors"
|
|
"strings"
|
|
)
|
|
|
|
var ErrCitationEvidenceMismatch = errors.New("citation evidence does not match source chain")
|
|
|
|
type ResearchPlanID string
|
|
type SourceID string
|
|
type SourceSnapshotID string
|
|
type SourceExcerptID string
|
|
type CitationID string
|
|
type FreshnessState string
|
|
type CoverageState string
|
|
type ConflictState string
|
|
type EvidenceKind string
|
|
type ResearchFindingState string
|
|
type ReliabilityState string
|
|
|
|
const (
|
|
FreshnessCurrent FreshnessState = "CURRENT"
|
|
FreshnessStale FreshnessState = "STALE"
|
|
FreshnessUnknown FreshnessState = "UNKNOWN"
|
|
CoverageComplete CoverageState = "COMPLETE"
|
|
CoveragePartial CoverageState = "PARTIAL"
|
|
CoverageUnknown CoverageState = "UNKNOWN"
|
|
ConflictNone ConflictState = "NONE"
|
|
ConflictPresent ConflictState = "PRESENT"
|
|
ConflictUnknown ConflictState = "UNKNOWN"
|
|
EvidenceObserved EvidenceKind = "OBSERVED"
|
|
EvidenceAssumed EvidenceKind = "ASSUMED"
|
|
FindingSupported ResearchFindingState = "SUPPORTED"
|
|
FindingStale ResearchFindingState = "STALE"
|
|
FindingConflicted ResearchFindingState = "CONFLICTED"
|
|
FindingUnknown ResearchFindingState = "UNKNOWN"
|
|
ReliabilityCurrent ReliabilityState = "CURRENT"
|
|
ReliabilityAging ReliabilityState = "AGING"
|
|
ReliabilityUnknown ReliabilityState = "UNKNOWN"
|
|
)
|
|
|
|
type ResearchPlan struct {
|
|
ID ResearchPlanID
|
|
Question string
|
|
SourceClasses []string
|
|
FreshnessPolicy string
|
|
CreatedAtUnixMillis int64
|
|
}
|
|
|
|
type Source struct {
|
|
ID SourceID
|
|
Kind string
|
|
Locator string
|
|
Title string
|
|
Publisher string
|
|
}
|
|
|
|
type SourceReliabilityAssessment struct {
|
|
SourceRef string
|
|
DomainRef string
|
|
Freshness FreshnessState
|
|
HistoryScoreMillis int64
|
|
ReliabilityScoreMillis int64
|
|
State ReliabilityState
|
|
EvidenceRefs []string
|
|
AssessedAtUnixMillis int64
|
|
}
|
|
|
|
func (a SourceReliabilityAssessment) Valid() bool {
|
|
return a.SourceRef != "" && a.DomainRef != "" && a.Freshness != "" && a.HistoryScoreMillis >= 0 && a.HistoryScoreMillis <= 1000 && a.ReliabilityScoreMillis >= 0 && a.ReliabilityScoreMillis <= 1000 && a.State != "" && a.AssessedAtUnixMillis > 0
|
|
}
|
|
|
|
type SourceSnapshot struct {
|
|
ID SourceSnapshotID
|
|
SourceID SourceID
|
|
ContentDigest string
|
|
CapturedAtUnixMillis int64
|
|
Freshness FreshnessState
|
|
}
|
|
|
|
type SourceExcerpt struct {
|
|
ID SourceExcerptID
|
|
SnapshotID SourceSnapshotID
|
|
Text string
|
|
Start int64
|
|
End int64
|
|
}
|
|
|
|
type Citation struct {
|
|
ID CitationID
|
|
ExcerptID SourceExcerptID
|
|
Evidence EvidenceKind
|
|
Coverage CoverageState
|
|
Conflict ConflictState
|
|
ResolvedAtUnixMillis int64
|
|
}
|
|
|
|
// ResearchCandidate is read-only evidence returned by a connector. The
|
|
// connector supplies the immutable snapshot and exact excerpt; the evaluator
|
|
// never fetches, rewrites or invents either one.
|
|
type ResearchCandidate struct {
|
|
PropositionKey string
|
|
Statement string
|
|
Source Source
|
|
Snapshot SourceSnapshot
|
|
Excerpt SourceExcerpt
|
|
Evidence EvidenceKind
|
|
Coverage CoverageState
|
|
Conflict ConflictState
|
|
}
|
|
|
|
type ResearchFinding struct {
|
|
PropositionKey string
|
|
Statement string
|
|
Claim Claim
|
|
Citations []Citation
|
|
Source Source
|
|
Excerpt SourceExcerpt
|
|
State ResearchFindingState
|
|
Reason string
|
|
}
|
|
|
|
type ResearchResult struct {
|
|
PlanID ResearchPlanID
|
|
Findings []ResearchFinding
|
|
EvaluatedAtUnixMillis int64
|
|
}
|
|
|
|
// ResearchEvaluationRequest carries immutable evidence from a read-only
|
|
// connector to the evaluator. The runtime never fetches or mutates a source
|
|
// from this contract.
|
|
type ResearchEvaluationRequest struct {
|
|
Plan ResearchPlan
|
|
Candidates []ResearchCandidate
|
|
}
|
|
|
|
type RepositoryResearchRequest struct {
|
|
Plan ResearchPlan
|
|
PropositionKey string
|
|
SourceID SourceID
|
|
Path string
|
|
Statement string
|
|
}
|
|
|
|
type WebResearchRequest struct {
|
|
Plan ResearchPlan
|
|
PropositionKey string
|
|
SourceID SourceID
|
|
URL string
|
|
Title string
|
|
Statement string
|
|
}
|
|
|
|
// WebSearchRequest asks the research runtime to discover bounded source
|
|
// evidence for a human question. The provider is configured by the runtime;
|
|
// the caller supplies meaning, not a provider URL or model choice.
|
|
type WebSearchRequest struct {
|
|
Plan ResearchPlan
|
|
PropositionKey string
|
|
Query string
|
|
}
|
|
|
|
// ResolveCitation creates evidence only when all identifiers form one exact
|
|
// source chain. It deliberately does not fetch, infer or rewrite source text.
|
|
func ResolveCitation(source Source, snapshot SourceSnapshot, excerpt SourceExcerpt, evidence EvidenceKind, coverage CoverageState, conflict ConflictState, resolvedAtUnixMillis int64) (Citation, error) {
|
|
if source.ID == "" || strings.TrimSpace(source.Locator) == "" || snapshot.SourceID != source.ID || excerpt.SnapshotID != snapshot.ID || excerpt.Validate() != nil || resolvedAtUnixMillis < 1 || evidence == "" || coverage == "" || conflict == "" {
|
|
return Citation{}, ErrCitationEvidenceMismatch
|
|
}
|
|
citation := Citation{ID: CitationID("citation:" + string(excerpt.ID)), ExcerptID: excerpt.ID, Evidence: evidence, Coverage: coverage, Conflict: conflict, ResolvedAtUnixMillis: resolvedAtUnixMillis}
|
|
return citation, citation.Validate()
|
|
}
|
|
|
|
func (p ResearchPlan) Validate() error {
|
|
if p.ID == "" || strings.TrimSpace(p.Question) == "" || len(p.SourceClasses) == 0 || strings.TrimSpace(p.FreshnessPolicy) == "" {
|
|
return errors.New("research plan requires question, source classes and freshness policy")
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (s SourceSnapshot) Validate() error {
|
|
if s.ID == "" || s.SourceID == "" || strings.TrimSpace(s.ContentDigest) == "" || s.CapturedAtUnixMillis < 1 || s.Freshness == "" {
|
|
return errors.New("source snapshot requires source, digest, capture time and freshness")
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (e SourceExcerpt) Validate() error {
|
|
if e.ID == "" || e.SnapshotID == "" || strings.TrimSpace(e.Text) == "" || e.Start < 0 || e.End < e.Start {
|
|
return errors.New("source excerpt requires snapshot, text and valid offsets")
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (c Citation) Validate() error {
|
|
if c.ID == "" || c.ExcerptID == "" || c.Evidence == "" || c.Coverage == "" || c.Conflict == "" || c.ResolvedAtUnixMillis < 1 {
|
|
return errors.New("citation requires exact excerpt, evidence, coverage, conflict and resolution time")
|
|
}
|
|
return nil
|
|
}
|