contradictions

package
v0.37.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 19, 2026 License: Apache-2.0 Imports: 5 Imported by: 0

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

func ToFacts(items []Item, runAt, cliVersion string) []fact.Fact

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

type Item struct {
	Detector Detector
	A        fact.Fact
	B        fact.Fact
}

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.

func Detect

func Detect(facts []fact.Fact) []Item

Detect runs both detectors over the given facts and returns every contradiction item in a deterministic order (status-drift items first, then naming-conflict, each internally sorted). It is pure: no store, no network.

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.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL