constitution

package
v0.1.0 Latest Latest
Warning

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

Go to latest
Published: Jul 6, 2026 License: MIT Imports: 11 Imported by: 0

Documentation

Overview

Package constitution is a thin exec wrapper around the sibling adr-sourced-constitution primitive's `constitution` binary (spec-lifecycle.md §7, implementation-plan.md §2.7). The seam is a runtime CLI process boundary, never a Go import: this package never imports github.com/kentra-io/adr-sourced-constitution.

Spike §12.2 findings (recorded here, not just in the build report)

`constitution deviation validate <path>` EXISTS exactly as implementation-plan.md §2.7/spec-lifecycle.md §7 item 5 describe it — confirmed by reading adr-sourced-constitution's cmd/constitution/deviation.go, internal/deviation/deviation.go, and its own cmd/constitution/testdata/script/deviation_validate.txtar (tag/commit at the time of this read). No fallback JSON re-implementation (implementation-plan.md §12 item 3's contingency) is needed. The contract, precisely:

  • It is a HIDDEN subcommand (`deviation validate`, not top-level) — stable enough to depend on (it is exercised by adr-sourced- constitution's own e2e suite) but intentionally not advertised in `constitution --help`.
  • Argument: exactly one positional <path> to a deviation.json file. Absolute or relative — relative is resolved against the process's CURRENT WORKING DIRECTORY, not the path's own location.
  • Working-directory precondition: the process must be run with its cwd set to "a constitution project root" — a directory containing both constitution.yml and constitution/adr/. This package always sets exec.Cmd.Dir explicitly (DeviationValidate's root parameter) and always passes an ABSOLUTE path for <path>, so callers never have to reason about relative-path resolution against that directory.
  • Exit codes: 0 valid (deviation.json is schema-valid, every adrId cites an ACTIVE, rule-bearing ADR, deviation ids are unique, and the summary tallies) · 1 invalid (schema/citation/tally errors, printed one per line on stderr) · 2 could not run (path unreadable, cwd is not a constitution project root, or the ADR log itself can't be read).
  • Output: on success, "deviation validate: <path> is valid" on stdout. A constitutionHash that no longer matches the live constitution/constitution.md is an ADVISORY, not a failure — printed to stderr ("constitutionHash mismatch [HIGH — stale gate]...") regardless of the exit code, including on the valid (0) path. This package folds that advisory into Result.Advisories rather than discarding it.

implementation-plan.md §2.7's spec-lifecycle.md §7.5 constitutionHash recompute does NOT need to shell out at all: Hash reimplements the identical sha256("sha256:"+hex) algorithm adr-sourced-constitution's own internal/deviation.ConstitutionHash uses, over the same constitution/constitution.md path, so lifecycle's own recompute and the value a deviation.json stamps are directly, byte-for-byte comparable without a process round-trip.

Index

Constants

View Source
const EnvBinOverride = "LIFECYCLE_CONSTITUTION_BIN"

EnvBinOverride is the documented override mechanism for the constitution binary's location, checked when no explicit override string is passed to Locate (e.g. from a future `--constitution-bin` flag). Set it to an absolute (or PATH-relative) binary path to bypass the default PATH lookup — the mechanism the M3 testscript e2e suite uses to point at a binary built fresh from source rather than requiring the companion primitive be `go install`ed on the machine running the tests.

Variables

This section is empty.

Functions

func Hash

func Hash(root string) (hash string, ok bool, err error)

Hash recomputes the sha256 of <root>/constitution/constitution.md, formatted "sha256:<hex>" — byte-identical to the algorithm adr-sourced-constitution's own internal/deviation.ConstitutionHash uses over the same file, so lifecycle's authoritative recompute (approval-state.json's constitutionHash, spec-lifecycle.md §5) and the value a deviation.json stamps (deviationConstitutionHash) are directly comparable without shelling out (doc.go's spike note).

A missing constitution.md is not an error: lifecycle can run in a project before the constitution companion primitive is initialized. Hash then returns ("", false, nil); callers decide how to treat an absent hash (spec-lifecycle.md §5's example always shows a populated constitutionHash, which presumes the companion is already set up).

func HashesEqual

func HashesEqual(a, b string) bool

HashesEqual reports whether two constitutionHash values are equal, accepting either the canonical "sha256:<hex>" form or a bare 64-hex digest, case-insensitively on the hex — mirroring adr-sourced-constitution/internal/deviation's own hashMatches/ normalizeHash (unexported there; reimplemented here since the seam is a process boundary, not a Go import — doc.go).

func Locate

func Locate(override string) (string, error)

Locate resolves the constitution binary's path. Precedence: override (a non-empty argument, reserved for a future CLI flag) wins; else the EnvBinOverride environment variable; else a PATH lookup for "constitution" (the default — the harness installs both primitives side by side, spec-lifecycle.md §7/§9.3). A value containing a path separator is stat'd directly (not looked up on PATH); a bare name is resolved via exec.LookPath so "constitution" and "./bin/constitution" both work as expected.

func MinorPin

func MinorPin(v string) (pin string, ok bool)

MinorPin derives a "<major>.<minor>.x" version pin from a reported version string v (e.g. "0.3.2" -> "0.3.x"; "v1.2.0-rc1 (abcdef)" -> "1.2.x"), for `lifecycle init` to seed lifecycle.yml's `constitution.version` from a freshly detected binary (implementation-plan.md §2.9 step e). ok=false when v isn't a dotted-numeric release build (e.g. a "(devel)" local build) or has fewer than two numeric components — init leaves the pin empty in that case rather than guess (an empty pin is always satisfied, §7 item 5: "presence, not version, is the only hard prerequisite when nothing is pinned").

func Version

func Version(bin string) (string, error)

Version runs "<bin> --version" and returns the reported version string (with the "constitution version " prefix stripped, if present).

Types

type DeviationExit

type DeviationExit int

DeviationExit mirrors `constitution deviation validate`'s exit-code contract (doc.go's spike note; ADR-0009 in the companion primitive).

const (
	DeviationValid       DeviationExit = 0
	DeviationInvalid     DeviationExit = 1
	DeviationCouldNotRun DeviationExit = 2
)

The three exit codes `constitution deviation validate` reports.

type DeviationResult

type DeviationResult struct {
	ExitCode DeviationExit
	Stdout   string
	Stderr   string
}

DeviationResult is one `constitution deviation validate` invocation's outcome: the exit code plus the captured streams (Stderr carries both the advisory staleness note, printed regardless of exit code, and — on exit 1 — the schema/citation/tally error lines).

func DeviationValidate

func DeviationValidate(bin, root, path string) (DeviationResult, error)

DeviationValidate runs `<bin> deviation validate <path>` with its working directory set to root. Per the verb's own contract (doc.go's spike note), root MUST be "a constitution project root" — a directory containing constitution.yml and constitution/adr/ — and path SHOULD be absolute so it resolves correctly regardless of root (callers are not required to pass an absolute path, but a relative one resolves against root, not the caller's own cwd, exactly like running the command by hand from that directory would).

A non-nil error means the process itself could not be started/run (e.g. bin is not executable) — distinct from DeviationCouldNotRun, which is the verb's OWN exit-2 "could not run" outcome (unreadable path, root isn't a constitution project root, ADR log unreadable) and is reported as a normal (err=nil) DeviationResult so callers can inspect Stderr for why.

func (DeviationResult) Valid

func (r DeviationResult) Valid() bool

Valid reports whether the deviation.json passed (exit 0). A valid result MAY still carry an advisory in Stderr (e.g. a stale constitutionHash) — Valid() does not inspect that.

type Preflight

type Preflight struct {
	Path    string
	Version string
	Pin     string
	// Compatible is only meaningful when Certain is true.
	Compatible bool
	// Certain is false when Version isn't a plain dotted-numeric release
	// build (e.g. a "(devel)"-tagged local build) — in that case
	// Compatible can't be evaluated, and the caller should treat this as
	// advisory-only (spec-lifecycle.md §7: "version mismatch = warning",
	// not a hard refusal — independent release cadences are expected).
	Certain bool
	// Warning is a human-readable, non-fatal note: either "version could
	// not be confirmed" (Certain=false) or "version does not satisfy the
	// pin" (Certain=true, Compatible=false). Empty when the pin is
	// unset or satisfied.
	Warning string
}

Preflight is the outcome of checking a resolved constitution binary against the lifecycle.yml `constitution: { version }` pin (spec-lifecycle.md §7 item 5/§10, implementation-plan.md §2.7).

func CheckVersion

func CheckVersion(bin, pin string) (Preflight, error)

CheckVersion resolves bin's reported version and compares it against pin (lifecycle.yml's constitution.version, e.g. "0.1.x" — an "x" wildcard component matches any value at that position). An empty pin always yields a satisfied, non-Warning result — presence, not version, is the only hard prerequisite when nothing is pinned.

Jump to

Keyboard shortcuts

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