Documentation
¶
Overview ¶
Package graph implements the typed property graph the scan engine expands: content-addressed nodes, typed relations, positional props and the single writer that applies operator deltas. See docs/DESIGN.md.
Index ¶
- Constants
- func Selection(ids []string) (set map[string]bool, exclude bool, err error)
- type Analysis
- func (a *Analysis) Assertions(id NodeID) []Assertion
- func (a *Analysis) Depth(id NodeID) int
- func (a *Analysis) Edges() []*Edge
- func (a *Analysis) Existence(id NodeID) Existence
- func (a *Analysis) InClosure(id NodeID) bool
- func (a *Analysis) Incoming(id NodeID, rel string) []*Edge
- func (a *Analysis) Ledger() []LedgerRow
- func (a *Analysis) Node(id NodeID) (*Node, bool)
- func (a *Analysis) Nodes() []*Node
- func (a *Analysis) Outgoing(id NodeID, rel string) []*Edge
- func (a *Analysis) Rejections() []Rejection
- func (a *Analysis) Score(id NodeID, key string) (float64, bool)
- func (a *Analysis) Scores(id NodeID) []ScoreRow
- func (a *Analysis) Status(id NodeID, op string) (Status, bool)
- func (a *Analysis) Statuses(id NodeID) []StatusRow
- func (a *Analysis) Truncations() []RunTruncation
- type Analyzer
- type Assertion
- type BeliefModel
- type Budgets
- type Cache
- type CacheKey
- type Canonical
- type Capability
- type Class
- type Condition
- type Delta
- type Edge
- type EdgeID
- type EdgeRef
- type EdgeView
- type Effects
- type Existence
- type Field
- type FieldDef
- type Finding
- type Graph
- func (g *Graph) AddFindings(f ...Finding)
- func (g *Graph) Analyze() *Analysis
- func (g *Graph) Apply(by Provenance, subject NodeID, d Delta) Result
- func (g *Graph) Assertions(id NodeID) []Assertion
- func (g *Graph) Belief(id NodeID) float64
- func (g *Graph) Decline(typeName, rawKey string, depth int, belief float64, r Reason, by Provenance) error
- func (g *Graph) Depth(id NodeID) int
- func (g *Graph) Edge(id EdgeID) (*Edge, bool)
- func (g *Graph) Edges() []*Edge
- func (g *Graph) Findings() []Finding
- func (g *Graph) InClosure(id NodeID) bool
- func (g *Graph) InScope(id NodeID) bool
- func (g *Graph) Ledger() []LedgerRow
- func (g *Graph) Live(id NodeID) bool
- func (g *Graph) Node(id NodeID) (*Node, bool)
- func (g *Graph) Nodes() []*Node
- func (g *Graph) NoteTruncation(r Reason, round int, detail string)
- func (g *Graph) Observers() []string
- func (g *Graph) Parent(id NodeID) (NodeID, string, bool)
- func (g *Graph) Rejections() []Rejection
- func (g *Graph) Risk(id NodeID) Severity
- func (g *Graph) RunAnalyzers(ctx context.Context, analyzers []Analyzer) error
- func (g *Graph) Score(id NodeID, key string) (float64, bool)
- func (g *Graph) Seed(typeName, rawKey string) (NodeID, error)
- func (g *Graph) SeedID() NodeID
- func (g *Graph) SetBeliefModel(m BeliefModel)
- func (g *Graph) SetBudgets(b Budgets)
- func (g *Graph) SetFrontier(n int)
- func (g *Graph) SetObservers(ids []string)
- func (g *Graph) SetScope(types []string)
- func (g *Graph) SetScore(id NodeID, key string, v float64)
- func (g *Graph) SetStatus(id NodeID, op string, s Status)
- func (g *Graph) Status(id NodeID, op string) (Status, bool)
- func (g *Graph) Truncations() []RunTruncation
- type Kind
- type LedgerRef
- type LedgerRow
- type Limiter
- type Limits
- type MergePolicy
- type Node
- type NodeID
- type NodeRef
- type NodeType
- type NodeTypeDef
- type OpBinding
- type Operator
- type Outcome
- type Plan
- type PlanInput
- type PropSet
- type Props
- type Provenance
- type Reads
- type Reason
- type Registry
- type RejectKind
- type Rejection
- type Rel
- type RelDef
- type Result
- type RunTruncation
- type Scheduler
- type ScoreRow
- type SeedSpec
- type Selector
- type Severity
- type State
- type Status
- type StatusRow
- type Trigger
- type Value
- type View
Constants ¶
const ExcludePrefix = "^"
ExcludePrefix marks an id as one to remove rather than keep (§12.10).
'^' rather than '-' because "-whois" is indistinguishable from a flag to an argument parser, and rather than '!' or '~' because both are shell metacharacters that would need quoting.
const VariantRel = "VARIANT_OF"
VariantRel is the relation name that marks a generated variation.
Variables ¶
This section is empty.
Functions ¶
func Selection ¶
Selection reports the ids a --algorithm/--collect selection names and whether it names them to exclude.
Exported for the callers that have to re-examine a selection after the plan is compiled. SelectOperators promises that an id the user named is never silently dropped, but it can only keep that promise over the set it is handed: compilation prunes operators the seed type cannot reach, afterwards, and a named operator lost there is lost just as quietly.
Types ¶
type Analysis ¶
type Analysis struct {
// contains filtered or unexported fields
}
Analysis is the read-only surface analyzers get. It exposes nodes, edges, status, provenance, plugin scores and the truncation ledger — but not the engine's belief.
Withholding belief is what makes "the execution model never contributes to a reported number" true by construction rather than by convention: an analyzer that could read it could launder it into a Severity and no reviewer would spot it. A plugin score is different — it describes the entity, not the traversal — so those are visible.
func (*Analysis) Assertions ¶
func (*Analysis) Existence ¶
Existence rolls a node's statuses up. Three values, not two: collapsing "confirmed absent" into "unregistered" discards the distinction the whole status vocabulary exists to preserve — a variant nobody could resolve is not a variant proven free.
func (*Analysis) Incoming ¶
Incoming returns edges pointing at a node, optionally filtered by relation. Analyzers need this to cluster: "which variants share this IP" is an in-edge query, and it is only answerable because infrastructure is nodes.
func (*Analysis) Rejections ¶
func (*Analysis) Scores ¶
Scores enumerates a node's plugin-model scores, sorted by key. Engine belief is deliberately absent — see the type comment.
func (*Analysis) Statuses ¶
Statuses enumerates a node's recorded outcomes, sorted by operator. Status(id, op) answers a question you already know to ask; a report has to enumerate, and iterating the side table directly would expose map order.
func (*Analysis) Truncations ¶
func (a *Analysis) Truncations() []RunTruncation
type Analyzer ¶
Analyzer runs once, over the whole graph, after expansion stops — for any reason, including an interrupt. There is exactly one lifetime.
type Assertion ¶
type Assertion struct {
Field string
Value Value
By Provenance
Won bool
}
Assertion is one operator's claim about a field, retained whether or not it won the merge. Disagreement between two sources is signal, not noise.
type BeliefModel ¶
type BeliefModel interface {
// Initial is the seed's prior and starting state, the seed having no parent.
Initial() (float64, State)
// Step is the forward filtering step: the parent's state pushed through the
// relation that admitted this node, then conditioned on its props. It
// returns the child's scalar belief and the state its own children inherit.
//
// parent is whatever this model returned for the parent node, or nil if the
// parent has none yet; a model must treat nil as its initial state.
Step(parent State, rel string, v View) (float64, State)
}
BeliefModel scores a node for execution control only: frontier ordering, pruning and operator gating. It never contributes to a reported number, which is why analyzers cannot see belief at all.
Belief is a pure function of the parent's belief and the node's props as of the current barrier. Nothing here reaches sideways into the graph, so the same run recomputes the same values in the same order.
type Cache ¶
type Cache struct {
// contains filtered or unexported fields
}
Cache stores operator results. The key covers everything the operator reads, so a hit is only served when nothing it depends on has changed.
A hit still occupies its round: the delta is applied at the same point a live call's would be, so a warm run and a cold run produce the same rounds, the same barriers and the same graph. A cache that short-circuited the round structure would make plan pinning depend on cache state.
func (*Cache) Put ¶
Put stores a result. Transient failures are never cached — the scheduler filters those before calling.
func (*Cache) SetResourceConfig ¶
SetResourceConfig records the config digest for a resource class — the nameservers for dns, the registry URL and token for npm, the proxy and UA policy for http.
type Canonical ¶
Canonical normalizes a raw key into the single form the graph converges on. Returning an error refuses the candidate outright.
type Capability ¶
type Capability uint8
Capability classifies what may be done to a node type. Nameable is necessary but not sufficient for variant expansion — eligibility also requires seed-closure membership, which the applier enforces.
const ( // Nameable types can be the root of variant generation. Nameable Capability = iota + 1 // Observed types are only ever discovered, never varied. Observed )
func (Capability) String ¶
func (c Capability) String() string
type Class ¶
type Class uint8
Class is a relation's edge class. It decides depth accounting and whether an edge extends the seed closure. The dividing line is whether producing the edge required a network call.
type Condition ¶
type Condition interface {
// contains filtered or unexported methods
}
Condition is an extra requirement on the matched node. Conditions are data conditions, never producer dependencies: "there is an IP", not "the ip operator has run".
func BeliefAbove ¶
BeliefAbove requires the execution model's belief to clear a threshold. It is evaluated only at a barrier, never during delta-driven re-dispatch, so it takes no part in the read-set digest.
type Delta ¶
Delta is everything one operator produced. Operators never mutate the graph; they return a Delta and the applier is the single writer. Deltas are additive only — nothing removes a node, edge or prop — which is what makes the graph monotonic within a run and a delta safely replayable.
type EdgeView ¶
type EdgeView struct {
Rel string
To NodeRef
ToID NodeID
// contains filtered or unexported fields
}
EdgeView is one edge as an operator sees it: the far node and the edge's own props. Relation props carry data operators need — VARIANT_OF holds the algorithm and edit distance — which bare neighbour nodes would hide.
type Effects ¶
Effects declares everything an operator may produce. It covers relations and props, not just node types, so plan compilation can see a prop-only operator and can detect a Where nothing in the plan will ever satisfy.
type Existence ¶
type Existence uint8
Existence is the three-valued rollup of a node's observation statuses.
type Field ¶
type Field struct {
// contains filtered or unexported fields
}
Field is a resolved handle to a declared field. Operators obtain one at registration, so an unknown name fails then rather than returning a per-access boolean at runtime.
type FieldDef ¶
type FieldDef struct {
Name string
Kind Kind
Merge MergePolicy
Deprecated bool
}
FieldDef declares one field of a node or relation type. Order in the declaring slice is the field's stable index and part of the on-disk contract: fields are append-only, and removal is by tombstone (Deprecated).
type Finding ¶
type Finding struct {
Kind string
Severity Severity
Nodes []NodeID // admitted nodes this concerns
Declined []LedgerRef // ledger rows this concerns
Summary string
Evidence []Provenance
}
Finding is an analyzer's conclusion.
type Graph ¶
type Graph struct {
// contains filtered or unexported fields
}
Graph is the applier and the single writer. It is not safe for concurrent use; the scheduler serialises deltas through it.
func (*Graph) AddFindings ¶
Findings stores an analyzer's conclusions in the side table.
func (*Graph) Apply ¶
func (g *Graph) Apply(by Provenance, subject NodeID, d Delta) Result
Apply applies one operator's delta. subject is the node the operator ran on; nodes it emits inherit that depth, and edges adjust it by their class.
func (*Graph) Assertions ¶
Assertions returns every claim made about a node's fields, winning or not.
func (*Graph) Decline ¶
func (g *Graph) Decline(typeName, rawKey string, depth int, belief float64, r Reason, by Provenance) error
Decline records a candidate the engine refused to admit, and denies it thereafter. Truncation of every kind lands here, which is what makes "pruning is irreversible" true even when a second operator finds the same candidate later.
func (*Graph) Findings ¶
Findings returns every finding, most severe first, then stably by kind and summary so two runs render identically.
func (*Graph) InClosure ¶
InClosure reports seed-closure membership: the seed plus everything reachable from it by structural edges. Only members may root variant generation.
func (*Graph) InScope ¶
InScope reports whether a node may root a variant under the current scope. The scheduler uses it to skip dispatching variant operators it knows will be rejected; the rejection in the applier remains the invariant.
func (*Graph) Nodes ¶
Nodes returns every admitted node sorted by (type, key) — the canonical report order, and what makes two runs byte-comparable.
func (*Graph) NoteTruncation ¶
NoteTruncation records a run-level limit.
func (*Graph) Observers ¶
Observers returns the registered observer set, sorted.
It exists so the set can be persisted with the scan. Existence is computed from it, so a graph rebuilt without it answers differently from the run that produced it — the same bytes yielding two different verdicts, which is the one thing this store exists to rule out.
func (*Graph) Rejections ¶
Rejections returns every invariant violation refused so far.
func (*Graph) Risk ¶
Risk is the maximum severity among findings referencing a node. It is what --filter risk>N and --fail-on select on, and the only user-facing score in the system.
func (*Graph) RunAnalyzers ¶
RunAnalyzers runs every analyzer once and records their findings.
func (*Graph) Seed ¶
Seed admits the target node at depth 0 and opens the seed closure. It is the only admission that does not descend from an existing node.
func (*Graph) SeedID ¶
Seed returns the target node. The seed cannot be inferred from the graph: structural edges cost no depth, so a composite target puts several nodes at depth 0 inside the closure and "the one at depth 0" names no single node.
func (*Graph) SetBeliefModel ¶
func (g *Graph) SetBeliefModel(m BeliefModel)
SetBeliefModel installs the execution model.
func (*Graph) SetBudgets ¶
SetBudgets caps admissions. Exceeding a budget declines the candidate to the truncation ledger rather than dropping it silently.
func (*Graph) SetFrontier ¶
SetFrontier caps how many nodes may be admitted in one round. Zero is unbounded.
The cap applies in admission order, which the scheduler has already made deterministic — work is sorted by (depth, type, key, operator) and applied in that order rather than in completion order — so the same scan truncates at the same place on every run.
DESIGN §8 specifies the survivors as the prefix of candidates sorted by (-belief, depth, type, key). While the belief model is uniform those two orderings are the same list, so this is that rule with the constant factored out. A model that returns anything other than 1 makes them differ, and at that point the frontier has to become a queue drained at the barrier rather than a counter checked at admission.
func (*Graph) SetObservers ¶
SetObservers names the operators whose status attests to a node's existence (§9): those that actually looked something up.
The distinction is load-bearing and was missing. Existence rolls up "did any operator return ok", and a decomposer returns ok when it successfully *parses* a name — which says nothing about whether that name exists. Without this, every syntactically valid variant read as live, so "-google.com" and "'oogle.com" were reported as live typosquats on the strength of having been parsed, with every DNS and whois lookup against them empty.
Membership is "the operator declared a rate-limit resource", i.e. it talks to something outside the process. A pure computation cannot attest to existence no matter what it returns.
func (*Graph) SetScope ¶
SetScope restricts which node types may root a variant. An empty or nil list means every Nameable type in the seed closure, which is the default.
This is the CLI's scope positional (§12), and it is enforced here rather than only at dispatch for the same reason the closure rule is: dispatch-side gating is an optimization an operator can be written around, while an applier rejection is an invariant it cannot. Scope that was merely validated and printed — compiled into the plan, shown by --explain, and then ignored by execution — would make `typo username bob@example.com` silently identical to the unscoped run, which is the one thing the positional exists to prevent.
func (*Graph) SetScore ¶
SetScore records a plugin model's judgement about an entity. Scores are side table state, not props: as props they would make every node's CID depend on a model version and break cross-run diffing the moment anything is retrained.
func (*Graph) SetStatus ¶
SetStatus records the terminal outcome of a (node, operator) pair. Skipped is not terminal and does not close the pair.
func (*Graph) Truncations ¶
func (g *Graph) Truncations() []RunTruncation
Truncations returns run-level limits that bound this expansion.
type Kind ¶
type Kind uint8
Kind is the closed set of value kinds a prop may hold. Keeping it closed is what lets props encode deterministically; see docs/DESIGN.md §1.3.
type LedgerRow ¶
type LedgerRow struct {
Type string
Key string // canonical
Depth int
Belief float64
Reason Reason
By Provenance
}
LedgerRow records a candidate the engine declined to admit. The ledger is reported like any other section — a truncated graph that reads as complete is a correctness bug — and it doubles as a denylist, so a later operator re-emitting the same candidate cannot quietly resurrect it.
type Limiter ¶
type Limiter struct {
// contains filtered or unexported fields
}
Limiter throttles operator calls per resource class. A single global delay is meaningless once one run talks to DNS, whois, npm, PyPI and GitHub at once: the limit protecting the strictest service would throttle everything else to the same crawl.
This is the operator-declared layer. Per-host limiting belongs beneath it in the transport.
func NewLimiter ¶
func NewLimiter() *Limiter
type Limits ¶
type Limits struct {
MaxDepth int // observation hops from the seed
MaxRounds int // backstop for a type-flow that never converges
Revisions int // per-pair re-runs; default 3
Attempts int // per-pair attempts within a round; default 2
Workers int // concurrent operator calls; default 1
NodeBudget int // global admitted-node cap
TypeBudget map[string]int // per-type admitted-node cap
Frontier int // cap on candidates admitted per round
// OpTimeout bounds one Exec call. Zero means unbounded. It lives here
// rather than inside each operator so a slow resource cannot stall a round
// past the scheduler's knowledge — an operator holding its own private
// deadline is one the barrier cannot reason about.
OpTimeout time.Duration
}
Limits bound expansion. Zero means unbounded except where noted.
type MergePolicy ¶
type MergePolicy struct {
// contains filtered or unexported fields
}
MergePolicy resolves competing assertions of the same field. Resolution must not depend on arrival order — under concurrent dispatch that would be decided by network timing. See docs/DESIGN.md §1.4.
func Precedence ¶
func Precedence(operators ...string) MergePolicy
Precedence declares operator ids in priority order, highest first. Operators not listed rank behind every listed one, and ties break on lowest id.
type Node ¶
Node is an admitted graph node. It carries no provenance, status or findings: those live in side tables, so that two identical scans produce identical content addresses.
type NodeID ¶
type NodeID [32]byte
NodeID is a node's stable identity: hash(type, canonical key). It is fixed for the node's whole life and is what the scheduler, seen-set, cache, edges and side tables key on. It is deliberately *not* the content address — props accumulate, so the CID changes while the identity does not.
type NodeRef ¶
NodeRef is how an operator names a node. It carries a *raw* key: operators cannot compute a NodeID because canonicalization belongs to the registry and the applier, and letting a plugin mint an identity is how convergence quietly breaks.
type NodeType ¶
type NodeType struct {
// contains filtered or unexported fields
}
NodeType is a registered node type handle.
func (*NodeType) Cap ¶
func (t *NodeType) Cap() Capability
type NodeTypeDef ¶
type NodeTypeDef struct {
Name string
Cap Capability
Version int
Canonical Canonical
Fields []FieldDef
}
NodeTypeDef declares a node type. Version rises only when Fields is appended to or a field is tombstoned.
type OpBinding ¶
type OpBinding struct {
Id string `json:"id"`
Version int `json:"version"`
Resource string `json:"resource,omitempty"`
OnTypes []string `json:"on_types,omitempty"`
OnCaps []string `json:"on_caps,omitempty"`
Where []string `json:"where,omitempty"`
Reads Reads `json:"reads"`
Emits Effects `json:"emits"`
Config map[string]string `json:"config,omitempty"`
Models []string `json:"models,omitempty"`
// Dead marks an operator whose Where can never be satisfied by anything
// this plan produces. It is listed, not run, and not fatal: usually it
// means the user narrowed scope.
Dead bool `json:"dead,omitempty"`
DeadWhy string `json:"dead_why,omitempty"`
}
OpBinding is one operator as the plan sees it. This is the single definition; §5 and §10.6 of the design refer to it rather than restating it.
type Operator ¶
type Operator interface {
Id() string
Version() int
Trigger() Trigger
Emits() Effects
// Resource names the rate-limit class this operator's calls belong to.
Resource() string
// Exec does the work. The Outcome is the operator's own judgement of what
// happened — an authoritative absence is Empty, not Failed — because how a
// lookup failed is itself the finding.
//
// ctx carries the round deadline and the interrupt. An operator that makes
// network calls must pass it down: without it the scheduler can only cancel
// *between* attempts, so Ctrl-C waits for an in-flight whois rather than
// stopping at the round boundary (§6.2, §12.4). Pure operators may ignore it.
Exec(ctx context.Context, v View) (Delta, Outcome)
}
Operator is a unit of work bound to a pattern in the graph.
func SelectOperators ¶
SelectOperators filters a set by id, for --algorithm and --collect.
nil or empty every operator "dns", "ptr" only these "^whois" everything except this
The two forms cannot be mixed in one call. A precedence rule between "keep only these" and "drop these" would have to be memorised to be used safely, and the combination expresses nothing the two forms cannot express separately.
An unknown id is an error rather than a silent omission. A run that quietly dropped half of what the user asked for — or, worse, selected nothing and reported a clean result — would present doing nothing as a finding of nothing.
type Outcome ¶
Outcome is what an operator reports alongside its delta. The status is the operator's own judgement: NXDOMAIN is StatusEmpty, not StatusFailed, and the difference is the signal a squatting scanner exists to collect.
type Plan ¶
type Plan struct {
Hash string `json:"hash"`
Seed SeedSpec `json:"seed"`
Operators []OpBinding `json:"operators"`
Model string `json:"model,omitempty"` // engine model CID
Limits Limits `json:"limits"`
// Pruned lists operators dropped as unreachable from the seed. Recording
// them is what keeps a narrow plan from reading like a complete one.
Pruned []string `json:"pruned,omitempty"`
// contains filtered or unexported fields
}
Plan is the compiled, inspectable, pinnable answer to "what will this do?".
func Compile ¶
Compile turns a registry, a seed and an operator set into a plan.
Pruning is reachability over the type-flow graph, not a topological walk: that graph is cyclic, so reachability is transitive closure. It is an over-approximation because Emits is a *may*, not a *must*, and the plan says so rather than implying certainty.
func (*Plan) Explain ¶
Explain renders the plan: the type flow in SCC-condensed layers, then the operators, then anything dead or pruned.
type PlanInput ¶
type PlanInput struct {
Seed SeedSpec
Limits Limits
Model string // engine model CID
Config map[string]map[string]string // operator id -> flag values
Models map[string][]string // operator id -> model CIDs
}
PlanInput is everything compilation needs besides the operators themselves.
type PropSet ¶
PropSet is a single field assertion against a node or an edge. Exactly one of Node or Edge must be set. Every prop write goes through this so the field's merge policy applies uniformly.
type Props ¶
type Props struct {
// contains filtered or unexported fields
}
Props holds one value per declared field, addressed positionally. Order is a property of the type rather than something imposed at encode time, so identical values encode identically by construction.
type Provenance ¶
Provenance records who asserted something and when. It is kept out of the content-addressed form so identical scans produce identical CIDs.
type Reads ¶
Reads declares the props and relations an operator consumes. It does double duty: it scopes the View, and it is the input to the read-set digest that decides re-dispatch and cache validity.
type Reason ¶
type Reason uint8
Reason explains why a candidate was declined.
const ( // ReasonBelief — below the execution model's threshold. ReasonBelief Reason = iota + 1 // ReasonBudget — a per-type or global node budget was exhausted. ReasonBudget // ReasonFrontier — the in-flight candidate bound was reached. ReasonFrontier // ReasonRoundCap — the round cap was hit. ReasonRoundCap // ReasonDeadline — the round deadline passed before it could be admitted. ReasonDeadline )
type Registry ¶
type Registry struct {
// contains filtered or unexported fields
}
Registry holds every registered node and relation type. It is not safe for concurrent registration; register during init, then read.
func NewRegistry ¶
func NewRegistry() *Registry
func (*Registry) AddType ¶
func (r *Registry) AddType(d NodeTypeDef) (*NodeType, error)
AddType registers a node type.
type RejectKind ¶
type RejectKind uint8
RejectKind classifies an invariant violation. Unlike a ledger row, a rejection does not deny the candidate forever: a node refused as the source of a VARIANT_OF edge may still be admitted legitimately by another edge.
const ( // RejectCanonical — the key could not be canonicalized. RejectCanonical RejectKind = iota + 1 // RejectUnknownType — no such node type is registered. RejectUnknownType // RejectUnknownRel — no such relation is registered. RejectUnknownRel // RejectUnknownField — the field is not declared by the target's type. RejectUnknownField // RejectKindMismatch — the value's kind is not the field's kind. RejectKindMismatch // RejectClosure — a variant edge whose source is outside the seed closure. RejectClosure // RejectSelfVariant — a variant edge whose source and target canonicalize // to the same node. RejectSelfVariant // RejectScope — a variant edge whose source type the run's scope excludes. // Distinct from RejectClosure: the node is a legitimate variant root, the // user simply asked for a narrower scan, and conflating the two would make // a scoped run look like an invariant violation. RejectScope // RejectDenied — the candidate is in the truncation ledger. RejectDenied // RejectMissingNode — an edge or prop referenced a node that was refused. RejectMissingNode )
func (RejectKind) String ¶
func (k RejectKind) String() string
type Rejection ¶
type Rejection struct {
Kind RejectKind
Type string
Key string
Rel string
Field string
Detail string
By Provenance
}
Rejection records one refused item from a delta.
type Rel ¶
type Rel struct {
// contains filtered or unexported fields
}
Rel is a registered relation handle.
type RelDef ¶
RelDef declares a relation type. Relations carry their own ordered field list, encoded exactly like a node's.
type RunTruncation ¶
RunTruncation is a run-level limit that bound expansion, as opposed to a per-candidate ledger row. Hitting the round cap is reported like any other truncation: a truncated graph that reads as complete is a correctness bug.
type Scheduler ¶
type Scheduler struct {
// Stats, for progress and tests.
Dispatched int
CacheHits int
Retries int
Rounds int
// contains filtered or unexported fields
}
Scheduler drives expansion. It responds to three kinds of event — a delta applied, a timer for a retriable failure, and a round barrier — and every irreversible decision happens at a barrier.
func NewScheduler ¶
NewScheduler binds a scheduler to a graph and an operator set.
type SeedSpec ¶
type SeedSpec struct {
Type string `json:"type"`
Key string `json:"key"` // canonical
Scope []string `json:"scope"` // nameable types to vary; empty means all in closure
}
SeedSpec is the target a plan was compiled for.
type Selector ¶
type Selector struct {
Types []string
Caps []Capability
}
Selector chooses which nodes an operator binds to, by type or by capability. Binding by capability is what lets one omission algorithm cover every Nameable type instead of being registered once per type.
type Severity ¶
type Severity uint8
Severity is an ordered, named level. It is deliberately not a bare int: `--fail-on high` has to mean the same thing in every release, and an integer scale drifts silently the first time someone inserts a level.
func ParseSeverity ¶
ParseSeverity resolves a level name, for --fail-on.
type State ¶
type State any
State is a model's latent state, carried between a parent and its children. The graph stores and forwards it without ever inspecting it.
It exists because §10.1 specifies a hidden Markov model, and forward filtering in an HMM propagates a *distribution over latent states* — a vector. An earlier version of this interface passed the parent's scalar belief instead, which forced a model to reconstruct a plausible distribution from one number and collapse it again on the way out. That round trip is exact for a two-state model and lossy for three or more, so the interface silently answered §16's open question about state cardinality as "two" — not by anyone's decision, but as a consequence of a type signature. Numbers from a larger model would have looked entirely reasonable and been wrong.
The scalar is still what the engine ranks and gates on; the state is the model's own business.
type Status ¶
type Status uint8
Status is the terminal outcome of one (node, operator) pair. How a lookup failed is itself the finding: NXDOMAIN proves a name is free, a timeout proves nothing at all, and collapsing the two would discard the signal a squatting scanner exists to collect.
const ( // StatusOK means the operator learned something positive. StatusOK Status = iota + 1 // StatusEmpty means it authoritatively determined absence. StatusEmpty // StatusFailed means the lookup itself broke. StatusFailed // StatusTimeout means nothing was learned. StatusTimeout // StatusSkipped means it was never attempted. Unlike the others this is // not terminal: a pair gated off at one barrier may run at a later one. StatusSkipped )
type Value ¶
type Value struct {
// contains filtered or unexported fields
}
Value is a typed prop value. Times are held as Unix nanoseconds so the encoded form is an integer and carries no location or formatting.
type View ¶
type View interface {
// ID is the matched node's identity.
ID() NodeID
// Type is the matched node's type name.
Type() string
// Key is the matched node's canonical key.
Key() string
// Depth is the node's observation distance from the seed.
Depth() int
// Prop returns a declared field's value, and whether it is set. Reading an
// undeclared field always reports unset.
Prop(field string) (Value, bool)
// Edges returns outgoing edges of a declared relation, with their props.
// Reading an undeclared relation always returns nothing.
Edges(rel string) []EdgeView
// Ref names this node for use in a Delta.
Ref() NodeRef
}
View is what an operator sees: the matched node, and exactly the props and relations its trigger declared it reads. Both are filtered, not just relations — the read-set digest is built from the same declaration, so a field an operator could read without declaring could change without changing the digest, and the operator would be served a stale cached result forever.