Documentation
¶
Overview ¶
Package contract assembles the derived contract graph, hashes it canonically, and manages versioning / the baseline flow.
Index ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func Build ¶
func Build(in BuildInput) model.ContractVersion
Build assembles a ContractVersion from discovery output and computes its canonical hash. It assigns a fresh volatile ID and CreatedAt but leaves the baseline decision to Snapshot (version.go).
When no explicit edges are supplied (the discovery path), Build derives the issuer→consumer graph: it synthesizes a minimal Issuer record for every issuer URL that consumers trust but that no supplied Issuer covers, and one Edge per (issuer, consumer) trust relationship. The canonical hash keys edges by issuer URL + consumer StableID, so the derived graph hashes deterministically.
func Hash ¶
func Hash(v model.ContractVersion) string
Hash returns the canonical SHA-256 (hex) of a contract version, per PRD §8.1.
Determinism guarantees (AC-1: two runs against an unchanged system must produce an identical hash):
- All volatile/observation fields are excluded from the canonical form: every timestamp (CreatedAt, FirstSeenInJWKS, LastVerified, LastObservedRefresh, ...), the volatile UUID IDs, all ProbeResults, and provenance/confidence metadata (evidence about the contract, not the contract itself).
- Edges are keyed by *stable* identifiers (issuer URL + consumer StableID), never by the volatile UUID IDs they carry at runtime.
- Every slice is sorted deterministically and every inner string slice is sorted lexicographically before marshaling.
The canonical form contains no Go maps, so field/element ordering is fully determined by struct declaration order and the sorts below.
Types ¶
type Attributor ¶
type Attributor = ports.Attributor
Attributor binds a change event to its cause (a commit, a deploy, an IdP admin action). It is an alias of the shared ports.Attributor, so the contract package (consumer) and the attribution package (producer) share one interface without importing each other.
type BuildInput ¶
type BuildInput struct {
Issuers []model.Issuer
Consumers []model.Consumer
Edges []model.Edge
TriggerKind string // scheduled|deploy|commit|manual
TriggerRef string
Now time.Time
}
BuildInput is the raw material for assembling a contract version.
type SnapshotResult ¶
type SnapshotResult struct {
Version model.ContractVersion
IsBaseline bool
Unchanged bool // hash matched the latest version; no events emitted
Events []model.ChangeEvent
}
SnapshotResult reports the outcome of storing a contract version.
func Snapshot ¶
func Snapshot(ctx context.Context, st store.Store, v model.ContractVersion) (SnapshotResult, error)
Snapshot implements the mandatory baseline flow (PRD §8.2):
if no baseline exists:
mark baseline, save, emit ZERO change events
else:
if hash == latest.hash: save, no events
else: events = diff(prev, new); save version + events
Violating this produces a wall of findings on first run — the documented pilot-killer — so the zero-events-on-baseline guarantee is load-bearing.
func SnapshotWithAttribution ¶
func SnapshotWithAttribution(ctx context.Context, st store.Store, v model.ContractVersion, attr Attributor) (SnapshotResult, error)
SnapshotWithAttribution is Snapshot plus a step that attributes each emitted change event to its cause before persistence. A nil attributor is a no-op, so this is behavior-preserving for callers that don't supply one.