contractv2

package
v1.0.0 Latest Latest
Warning

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

Go to latest
Published: Sep 16, 2026 License: MIT Imports: 2 Imported by: 0

Documentation

Overview

Package contractv2 declares the identity of the frozen xibodev.module/v2 behavioural Target Contract and the exact-pin check that gates it.

SCOPE. This package answers exactly one question: may the host rely on v2 behavioural guarantees when talking to this counterparty? It deliberately contains no other v2 semantics. Contract vocabulary and facility implementation are separate concerns (operator ruling), so nothing here implements approval, budgets, resume, or effects.

NOT YET WIRED, AND THAT IS NOT AN OVERSIGHT. CheckPin has no callers today, because the v1 descriptor has no contract_version field to read and v1 is immutable -- adding one would be smuggling successor semantics into a v1 exchange, which the operator ruling forbids. The gate exists first so that nothing downstream is built assuming v2 guarantees before there is a check that they were agreed to.

This repo has shipped the opposite shape twice, and both are recorded as defects: internal/view's schema-keyed views and Registry.SetEnabled are declared, documented, and have no callers. The difference is that those are unreachable BEHAVIOUR presented as available, while this is a gate waiting for a wire that does not exist yet. Stated explicitly so the next reader does not have to infer which kind it is -- an unwired thing that nobody labels looks identical to a forgotten one.

WHY A SEPARATE PACKAGE FROM modproto. xibodev.module/v1 is immutable legacy behaviour: nothing may be added to it, and tolerant decoding is not permission to smuggle successor semantics into a v1 exchange. modproto's ProtocolID versions the WIRE FORMAT. This versions BEHAVIOUR, which v1 never versioned at all -- and conflating the two is what let two sibling lanes infer behavioural guarantees from what a wire validator happened to accept.

PINNING, NOT NEGOTIATION. By operator ruling, v2 uses an exact pinned identity. Module and host each declare exactly one behavioural contract version; equal means proceed to conformance evaluation, anything else means refuse deterministically with a reason and a remedy.

Explicitly excluded, and this is the load-bearing part: version ranges, highest-common-version selection, downgrade, fallback, and pseudo- negotiation. A single-element list that merely LOOKS negotiable is excluded too. That is not a stylistic preference -- v1 shipped exactly that shape, a doc comment promising the host "selects the highest it also supports" over a membership test against one frozen constant, and a sibling lane built a versioning story on the promise before discovering it was inert. A structure that can only ever hold one value should not be shaped like a choice.

Real negotiation may be designed later, only when multiple behavioural contract versions actually coexist, a host intentionally supports more than one, and a real consumer needs runtime selection. Until then exact pinning is simpler and more truthful.

Index

Constants

View Source
const ContractID = "xibodev.module/v2"

ContractID is the behavioural contract this host implements.

Deliberately a single string and not a slice. A []string would invite "declare several and pick one", which is the shape the ruling forbids, and the type is the cheapest place to make that impossible.

Variables

This section is empty.

Functions

This section is empty.

Types

type Outcome

type Outcome int

Outcome is what the host may do with a counterparty, and there are THREE answers rather than two.

An earlier version of this package returned a single OK boolean, which made "serve this module under v1" and "refuse this module" indistinguishable to a caller. Both are "not v2", and collapsing them would have refused every v1 module the moment this gate was wired -- breaking the frozen contract's own compatibility rule (§10: v1 modules keep working; absent v2 fields fall back to v1 behaviour, never to a more permissive default).

The sibling lane found this from the other side: they permit an absent contract_version for exactly this reason and refuse present-and-wrong. Same conclusion, reached independently, and their message is what prompted the re-read that found the conflation here.

const (
	// OutcomeRefuse means the counterparty declared a behavioural contract this
	// host does not implement. It is a disagreement about what the guarantees
	// MEAN, so proceeding would apply v2 semantics to something that never
	// agreed to them.
	OutcomeRefuse Outcome = iota

	// OutcomeV1 means no behavioural contract was declared. This is a v1
	// module: it is served, with v1 behaviour, and NO v2 guarantee may be
	// relied upon. Not an error and not a refusal.
	OutcomeV1

	// OutcomeV2 means the pin matched exactly. Only this outcome permits
	// relying on a v2 behavioural guarantee.
	OutcomeV2
)

func (Outcome) String

func (o Outcome) String() string

type PinResult

type PinResult struct {
	Outcome Outcome
	Reason  string
	Remedy  string
}

PinResult reports the outcome of the contract pin check.

Reason and Remedy are separate because they answer different questions and a non-conforming counterparty needs both: what is wrong, and what to do. A refusal that says only "incompatible" sends someone to read source.

func CheckPin

func CheckPin(declared string) PinResult

CheckPin compares a counterparty's declared behavioural contract version against this host's, and is the ONLY gate through which v2 guarantees become available.

The empty string yields OutcomeV1, not a refusal. A module that declares nothing is a v1 module -- refusing it would break every module shipped today and violate the frozen contract's compatibility rule. It is still barred from every v2 guarantee, which is the part that matters: absent falls back to v1 behaviour, never to a more permissive default.

An EXPLICIT "xibodev.module/v1" is refused rather than served, and the distinction is deliberate. That string is the WIRE-FORMAT identity (modproto.ProtocolID); it is not a behavioural contract, because v1 behaviour was never versioned -- which is the entire premise of having a successor. Serving it would put a name in the conformance record that names nothing: a consumer reading "governed by xibodev.module/v1" could not tell it from a real contract identity, and §10 forbids falling back to a more permissive default. A contract name that names no guarantees IS the more permissive default. The sibling lane reached the same conclusion independently and both pins produce the same four outcomes.

Nothing here inspects capabilities, effects or artifacts. Callers MUST pass this gate before relying on any v2 behavioural guarantee; that ordering is what the falsification test in the conformance suite pins.

func (PinResult) Error

func (r PinResult) Error() error

Error renders a refusal for a caller that wants one, and nil when the module is served -- under v2 OR under v1. A v1 module is not an error condition.

func (PinResult) MayRelyOnV2

func (r PinResult) MayRelyOnV2() bool

MayRelyOnV2 reports whether v2 behavioural guarantees are available.

This is the ONLY question the conformance suite may ask before checking a v2 guarantee. It is deliberately not named OK: "ok" invites reading a served v1 module as success in the v2 sense, which is the conflation this type exists to prevent.

func (PinResult) Served

func (r PinResult) Served() bool

Served reports whether the host may talk to this module at all.

True for both v2 and v1. False only for a declared contract this host does not implement.

Jump to

Keyboard shortcuts

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