Documentation
¶
Overview ¶
Package contradictions computes SpecScore Studio's contradiction detectors as pure functions over the facts a `studio index`/`studio probe` run wrote into the fact store. It reads no store and touches no network: every detector is a deterministic query over a `[]fact.Fact` slice, so the engine is entirely fixture-testable.
Feature: cli/studio/answers (REQ: contradictions-verb, REQ: status-vs-behavior-drift, REQ: same-predicate-disagreement, REQ: contradiction-facts, REQ: suppression-ignore-list)
Two detectors, partitioned by evidence class so the noise discipline holds:
- status-drift owns declared-vs-verified-behavior disagreement, in two branches — a shipped-implying `has-status` joined by subject prefix to a failing `has-verification-status` (lifecycle-vs-verification), and a same-subject+predicate `declared` object differing from a `verified-behavior` one (declared-vs-verified, e.g. a registry-declared `serves-status` 200 against a probed `down`).
- naming-conflict owns declared-vs-declared disagreement: two `declared` facts sharing a *single-valued* subject+predicate but asserting different objects from different evidence pointers (the `ext-<id>` vs `<id>-contract` class). Only predicates that are single-valued per subject (singleValuedDeclared) participate — legitimately multi-valued predicates (has-ac, contains, implemented-by, …) are excluded, or every multi-AC feature would self-"conflict" (the 5,758-item Sneat dogfood flood, 92% has-ac).
verified-behavior-vs-verified-behavior differences are supersession — a changed probe result — and are flagged by neither detector.
Index ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func FilterIgnored ¶
func FilterIgnored(items []Item, r io.Reader) (active []Item, suppressed []Suppressed)
FilterIgnored partitions items into active (not suppressed) and suppressed (matched by an ignore-list entry) results (REQ: suppression-ignore-list). The reader supplies the ignore file's content: one canonical "<refA> <refB>" pair per line (two spaces between refs), with #-prefixed comments and blank lines skipped, and an optional inline " # reason" comment after the pair whose text is carried onto the suppressed result. A nil reader is treated as an empty ignore file — all items are returned as active. The canonical pair is the same smaller-ref-first identity ToFacts uses as the contradicts fact's subject/object, so operators copy from fact queries into the ignore file.
func ToFacts ¶
ToFacts converts detected contradiction items into `contradicts` facts ready to be merged into the store via store.Merge (REQ: contradiction-facts). Each fact encodes the canonical conflict identity as its subject/object triple (the lexicographically smaller fact-ref first), carries evidence class `derived` (computed from other facts, not observed), and uses the detector id as the evidence pointer. The adapter id is "contradictions"; the adapter version is the CLI version string passed by the caller. Both observed_at and verified_at are set to the run timestamp runAt so re-runs refresh verified_at idempotently (the merge key is subject+predicate+object+class+adapter, so the same conflict yields one stable row and never duplicates).
Types ¶
type Detector ¶
type Detector string
Detector identifies which detector flagged a contradiction item — the value carried on every item and used as the evidence pointer when an item is written back as a `contradicts` fact.
const ( // StatusDrift is the status-vs-behavior-drift detector: a `declared` claim // that a `verified-behavior` observation contradicts. StatusDrift Detector = "status-drift" // NamingConflict is the same-predicate-disagreement detector: two `declared` // facts disagreeing on the same subject+predicate. NamingConflict Detector = "naming-conflict" )
type Item ¶
Item is one detected contradiction: the two facts that disagree plus the detector that flagged them. Side A is always the `declared` fact and Side B the contradicting fact (a `verified-behavior` fact for status-drift, the other `declared` fact for naming-conflict), so callers render a stable "declared vs …" order.
type Suppressed ¶
type Suppressed struct {
Item Item
// Identity is the canonical "<side-a-ref> <side-b-ref>" pair (the two
// smaller-first refs joined by two spaces), exactly the form the ignore
// file uses per line.
Identity string
// Reason is the trailing inline comment (the text after " #") on the
// matching ignore-file line, trimmed; empty when the line carried none.
Reason string
}
Suppressed is one contradiction item suppressed by an ignore-list entry (REQ: suppression-ignore-list): the item itself, the canonical "<side-a> <side-b>" identity string that matched (the exact form the ignore file uses), and the reason comment from the matching line's inline "#" comment, if any — so `--show-ignored` can report what was suppressed and why, and suppression is never silent.