aontu

package module
v0.1.11 Latest Latest
Warning

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

Go to latest
Published: Aug 28, 2026 License: MIT Imports: 24 Imported by: 0

Documentation

Overview

Package aontu is a Go port of the Aontu JSON structure unifier.

Aontu unifies JSON-like structures using a CUE-inspired value lattice. The canonical implementation is the TypeScript code under ../ts/src; this package mirrors its core unification semantics and is validated against the shared test specs in ../test/spec (run by both implementations).

Coverage note: this port has full parity with the TypeScript language — scalars, scalar kinds, maps (nesting, merge, spreads &:, optional keys, close/open), lists (incl. &: spreads), conjunction (&), disjunction (|), preference (*), references ($.a.b / .x.a / $KEY), $name variables, the + operator, all eighteen built-in functions (upper/lower/copy/key/pref/super/type/hide/close/open/move/path and the constraint atoms min/max/above/below/neq), type/hide marks and @"file" source loading.

Index

Constants

View Source
const (
	AgentsMdBegin = "<!-- aontu:begin -->"
	AgentsMdEnd   = "<!-- aontu:end -->"
)

The markers an update rewrites between. A stanza outside them is prose someone wrote, and is left alone.

View Source
const (
	DiffAdded   = "added"
	DiffRemoved = "removed"
	DiffChanged = "changed"
)
View Source
const (
	ModuleAnnotationCanon = "com.github.rjrodger.aontu.canon"
	ModuleAnnotationMajor = "com.github.rjrodger.aontu.major"
)

ModuleAnnotationCanon and ModuleAnnotationMajor are the two facts OCI has no predefined key for. OCI asks a custom key to be the reverse DNS of a domain its author controls, and the project's own home is the only domain it has — inventing an `aontu.dev` would be a claim it cannot back.

View Source
const (
	WhyLiteral = "literal"
	WhySpread  = "spread"
	WhyRef     = "ref"
	WhyPref    = "pref"
)
View Source
const (
	QueryJSON  = "json"
	QueryCanon = "canon"
	QueryTypes = "types"
	QueryKeys  = "keys"
)
View Source
const (
	SubsumeYes       = "subsumes"
	SubsumeNo        = "does_not_subsume"
	SubsumeUndecided = "undecided"
	SubsumeError     = "error"
)

Subsume verdicts.

View Source
const (
	TrimClean     = "clean"
	TrimRedundant = "redundant"
	TrimError     = "error"
)
View Source
const (
	VetValid      = "valid"
	VetInvalid    = "invalid"
	VetIncomplete = "incomplete"
	VetError      = "error"
)

Verdicts. The report says which of four states the run reached, and the caller maps them to exit codes (cmd/aontu).

View Source
const (
	VetRoleData   = "data"
	VetRoleSchema = "schema"
)

Roles. A site is either in the data document or in the schema, and which one it is comes from PROVENANCE — the url stamped on each tree before they meet (walk.go) — not from the primary/secondary heuristic NilVal uses, which is source-order reasoning within ONE document and says nothing useful when one side is a schema and the other is data.

View Source
const DONE = -1

DONE marks a Val whose unification has fully converged.

View Source
const ModuleConfigMediaType = "application/vnd.aontu.module.v1+json"

ModuleConfigMediaType is the config media type the design fixes: an Aontu module is not an image, and the type is what tells a registry so.

View Source
const VERSION = "0.1.11"

Version is the Aontu Go module version. VERSION is the Aontu Go module version, rewritten by `make publish-go`. Spelled in caps to match ts/src/aontu.ts's exported VERSION, so the two ports name the same thing the same way. Note the two version SERIES are independent: the Go module is 0.1.x, the npm package 0.49.x.

View Source
const VetMaxErrors = 20

VetMaxErrors is the default cap on a report's finding list. Exported because the command applies it to the WHOLE report across several data files and must not carry a second copy of the number (cmd/aontu/vet.go).

Variables

This section is empty.

Functions

func AgentsMdSplice

func AgentsMdSplice(existing, stanza string) string

AgentsMdSplice puts the stanza into an existing document: replace what stands between the markers, or append when there is nothing to replace. The rest of the document is LEFT ALONE — it is someone's prose, and a generator that rewrote it would be one nobody dared run twice.

func BuiltinFuncNames

func BuiltinFuncNames() []string

BuiltinFuncNames returns the recognised built-in function names in sorted order. Exposed for tooling (e.g. LSP completion in go/lsp).

func CanonHash

func CanonHash(v Val) string

CanonHash is the canon-hash pin. Scoped to the module evaluated STANDALONE: its own include closure resolved and unified at its own root, before any consumer context — which is what makes the pin transitive (an edit two includes deep changes the unified root, hence the hash). Mirrors canonHash in ts/src/hcanon.ts.

func Hcanon

func Hcanon(v Val) string

Hcanon is the hash form of an EVALUATED Val (unify first; parse-level canon parenthesisation differs between the ports and is excluded by construction — AGENTS.md). Mirrors hcanon in ts/src/hcanon.ts.

func LockText

func LockText(entries []ModLock) string

LockText is the lockfile TEXT: canonical Aontu, one line, keys sorted. Built as source and canonicalised by the ENGINE rather than printed by hand, so "canonical form" means what the language means by it and cannot drift from it.

func ModCacheDir

func ModCacheDir() string

ModCacheDir is the content-addressed user module cache (G6 phase 2): `$XDG_CACHE_HOME/aontu/mod`, else the platform's own cache location. A host with nowhere to put one has no cache, which is a miss rather than a failure. One rule, in one place: the resolver reads this cache during evaluation and `aontu mod` writes into it, and two spellings of "where the cache is" is one bug. Mirrors modCacheDir in ts/src/mod.ts.

func ParseAssignment

func ParseAssignment(text string) (path, value string, ok bool)

ParseAssignment splits `<path>=<value>` at the FIRST `=`: a path segment is a name, and the value is arbitrary Aontu source, which may itself contain `=`. ok is false when the text is not an assignment at all.

func PolicyCompat

func PolicyCompat(src, path string) string

Subsume reports whether generalSrc subsumes specificSrc — is every instance the specific admits admitted by the general too? Both sources are evaluated fresh (single-use trees make this mandatory); the recursion runs on the finished values. The port of ts/src/subsume.ts, held to byte-identical reports by test/spec/subsume.tsv. PolicyCompat reads a document's own compatibility declaration: `$.aontu_policy.compat`, a disjunction whose default is the declared mode ("backward" | "forward" | "full" | "none"). The empty string means the key is absent, the document does not stand alone, or the value does not spell a mode. Exported for the `breaking` verb (go/cmd/aontu), which cannot reach the tree's fields itself; the canonical port keeps the same reader beside its verb (ts/src/cli.ts policyCompat).

func PolicyCompatTrust

func PolicyCompatTrust(src, path string, trust *TrustOptions) string

PolicyCompatTrust is PolicyCompat under an explicit include capability, so a verb reading a document's own policy reads it the same way it evaluates everything else.

func SarifReport

func SarifReport(report VetReport, version string) string

SarifReport renders a vet report as SARIF 2.1.0 text (a minimal profile: one run, one result per finding, the finding embedded in `properties`). The version parameter fills `tool.driver.version` — the CLI passes VERSION; the two ports' version series are independent by design.

func SetColor

func SetColor(on *bool)

SetColor forces ANSI on or off; nil restores the NO_COLOR default.

func VersionCompare

func VersionCompare(a, b string) int

VersionCompare is numeric-dotted version order: `1.10.0` is above `1.9.0`, which STRING order gets wrong, and that is the whole reason this is not a `<` on the text. A part that is not a number compares as text, after every number — a pre-release tag is below no version and above none. Mirrors versionCompare in ts/src/mod-tool.ts.

Types

type Address

type Address struct {
	Name string
	Path []string
}

Address is an entity name and, optionally, a path INSIDE that entity: `svc/auth` or `svc/auth.ports.http`. The two addressing schemes reconciled — `$.a.b` answers WHERE, an address answers WHAT, and beneath entity granularity the tree is authoritative again. The no-dots rule on ids makes the split unambiguous.

type AgentsMdOptions

type AgentsMdOptions struct {
	// Name is what the stanza should call the document. The engine
	// never reads a file; the CLI passes what the author typed.
	Name string
}

type AgentsMdReport

type AgentsMdReport struct {
	Findings []VetFinding `json:"findings"`
	OK       bool         `json:"ok"`
	Stanza   string       `json:"stanza"`
}

type Aontu

type Aontu struct {

	// File is an optional display name for the entry source, rendered
	// in error frames the way the TS CLI renders its entry path
	// (`--> model.aon:3:5`). Empty renders `<no-file>`, as TS does for
	// string sources. Set it when evaluating a real file, e.g. from
	// cmd/aontu.
	File string

	// Trust is the evaluation's trust profile (G5, docs/trust.md).
	// Nil means the 'system' posture, today's default.
	Trust *TrustOptions

	// IncludeText is the TEXT of every source the most recent parse
	// READ, by full path. A value's position is a byte offset into the
	// source it was parsed from, so a report that names an included
	// file honestly (finding F, use-cases/BUGS.md §25) needs that
	// file's text to turn the offset into a row and column. The
	// canonical port has no equivalent because its values carry row and
	// column directly; this port computes them on demand.
	IncludeText map[string]string

	// IncludeDeps is the include MANIFEST of the most recent parse:
	// the resolved include closure, sorted by path then capability and
	// deduplicated, so it is deterministic. Reset per parse; empty for
	// a document with no includes.
	IncludeDeps []IncludeDep

	// Graph is the DERIVED GRAPH of the most recent unification (G4
	// phase 3): the entity index and the edge set, both deterministic.
	// Reset per unification; empty for a document with no identity.
	// Mirrors `result.graph` in ts/src/aontu.ts, which stamps it on the
	// returned Val the way that port stamps `deps`.
	Graph Graph

	// ModCache is the content-addressed user module cache. Empty means
	// the platform default (`$XDG_CACHE_HOME/aontu/mod`, else
	// `$HOME/.cache/aontu/mod`); a host that names one uses it, which is
	// what makes a hermetic test possible. Not a stable embedding API.
	ModCache string

	// TrustWarn and TrustWarnRoot are the staged-flip warning window
	// (G5 phase 6, cmd/aontu only): under the 'system' posture every
	// resolution escaping TrustWarnRoot calls TrustWarn. Not a stable
	// embedding API.
	TrustWarn     func(kind, path string)
	TrustWarnRoot string
	// contains filtered or unexported fields
}

Aontu is the top-level entry point, mirroring the TypeScript Aontu class (ts/src/aontu.ts).

func New

func New() *Aontu

New creates a new Aontu instance. Relative @"file" loads resolve from the process working directory.

func NewWithBase

func NewWithBase(base string) *Aontu

NewWithBase creates an Aontu that resolves relative @"file" source loads against base, a directory. Use it when evaluating a source whose relative loads should be resolved from somewhere other than the process working directory, e.g. the directory of an entry file:

abs, _ := filepath.Abs(file)
a := aontu.NewWithBase(filepath.Dir(abs))

Absolute @"file" paths are unaffected by base.

func (*Aontu) AgentsMd

func (a *Aontu) AgentsMd(src string, opts *AgentsMdOptions) AgentsMdReport

AgentsMd is the stanza for one document. Mirrors agentsMd in ts/src/agentsmd.ts, byte for byte.

func (*Aontu) Check

func (a *Aontu) Check(src string) []Problem

Check parses and unifies src and reports every problem found, without stopping at the first. Unlike Generate it does not fail on non-concrete values — a schema such as `a:string` is valid and yields no problems. A parse (syntax) error is returned as a single Problem with Pos -1.

func (*Aontu) CheckVars

func (a *Aontu) CheckVars(src string, vars map[string]Val) []Problem

CheckVars is Check with $name variables resolved from vars.

func (*Aontu) DeprecatedAt

func (a *Aontu) DeprecatedAt(src, path string) bool

DeprecatedAt reports whether the evaluated document carries the deprecation record at the given finding path ("$.a.b"). Used by the breaking verb's --allow-deprecated-removal downgrade (G3 phase 4): the verb's package cannot reach the tree's fields itself. A source that does not evaluate answers false.

func (*Aontu) DeprecationsVars

func (a *Aontu) DeprecationsVars(src string, vars map[string]Val) []Deprecation

DeprecationsVars evaluates src (with $name variables from vars, which may be nil) and returns every sited value carrying the deprecation record — the declaration and, because the record rides meets and reference clones, every use resolving through it. A source that does not evaluate answers no deprecations: the diagnostics surface already reports why. Mirrors the walkDep pass in ts/src/lsp.ts computeDiagnostics.

func (*Aontu) Generate

func (a *Aontu) Generate(src string) (any, error)

Generate parses, unifies and generates the native output value, which must fully resolve to concrete values.

The native types are:

map        map[string]any
list       []any
string     string
integer    int64
float      float64
biginteger *math/big.Int
bigdecimal *Decimal
boolean    bool
null       nil

The last two numeric rows are the number tower's exact leaves, reached only by a `0d` literal or the NewBigInteger/NewBigDecimal constructors: a document that writes no `0d` generates exactly what it always did. Both are pointers, and both marshal as EXACT DIGITS in a raw JSON number, so encoding/json (json.Marshal, json.MarshalIndent) round-trips an exact value without loss — no conversion step and no custom encoder needed on the Go side.

func (*Aontu) GenerateVars

func (a *Aontu) GenerateVars(src string, vars map[string]Val) (any, error)

GenerateVars is Generate with $name variables resolved from vars.

func (*Aontu) Get

func (a *Aontu) Get(src, path string, opts *QueryOptions) QueryReport

Get evaluates the document, selects the node at path, and renders it. Mirrors get in ts/src/query.ts.

func (*Aontu) JSONSchema

func (a *Aontu) JSONSchema(src, at string) SchemaReport

JSONSchema exports a document as a JSON Schema. `at`, when non-empty, names the subtree to export -- the same anchor vet --at takes.

func (*Aontu) Parse

func (a *Aontu) Parse(src string) (Val, error)

Parse parses source into a Val AST, not yet unified.

NOTE: the returned Val is SINGLE-USE. Unify/Generate refine the tree in place (see unifyRoot), so do not Unify/Generate the same Val more than once and do not use it from multiple goroutines. The Unify/ Generate entry points re-parse per call, so this only matters if you hold a Parse result yourself; call Parse again for a fresh tree.

func (*Aontu) Reach

func (a *Aontu) Reach(src, from, to string, opts *ReachOptions) ReachReport

Reach answers whether `to` is reachable from `from` over the entity graph of src.

func (*Aontu) RelationCheck

func (a *Aontu) RelationCheck(src string) RelationReport

RelationCheck runs the relation checks over one document.

func (*Aontu) Spans

func (a *Aontu) Spans(src string) []ValueSpan

Spans parses and unifies src and returns a ValueSpan for every positioned non-container value in the result, so tooling can locate the value under a cursor. Returns nil on a parse error.

func (*Aontu) TrimCheck

func (a *Aontu) TrimCheck(src string) TrimReport

TrimCheck is the whole reporter: the baseline canon, then one probe per candidate entry, parent-first — and a child of a redundant parent is SKIPPED, because "remove the whole entry" already covers it and reporting both would tell the author to delete the same text twice. Mirrors trimCheck in ts/src/trim.ts.

func (*Aontu) Unify

func (a *Aontu) Unify(src string) (Val, error)

Unify parses and fully unifies source, returning the unified Val. A non-nil error is returned if parsing fails or unification produces any conflict.

func (*Aontu) UnifyVars

func (a *Aontu) UnifyVars(src string, vars map[string]Val) (Val, error)

UnifyVars is Unify with $name variables resolved from vars.

func (*Aontu) Why

func (a *Aontu) Why(src, path string) WhyReport

Why answers WHY the value at this path holds: evaluate with the provenance recorder on, select the node, and answer the ordered contributions that met there — the positive twin of G2's error report. Mirrors why in ts/src/query.ts.

type AontuError

type AontuError struct {
	Msg string

	// Code is the error code of the FIRST underlying failure (the
	// NilVal `why`, e.g. "scalar_value", "no_path", "mapval_no_gen"),
	// mirroring errs()[0].why on the TypeScript AontuError. Empty when
	// no code is known (e.g. wrapped parse errors). Codes -- unlike
	// message text -- are in cross-implementation parity, registered in
	// test/spec/errcodes.tsv and pinned by `errc` spec rows.
	Code string

	// Row and Col locate a PARSE failure, 1-based, or -1 when the
	// failure knows no position. The merge-conflict refusal and the
	// parser's own syntax failure both fill them, which is exactly
	// where the canonical port carries a position too. The validation
	// verb reports them (vet.go), so the two ports have to know the
	// same things here -- and until they both threaded the parser's
	// position through, a machine-readable report said -1:-1 for a
	// fault the human renderer drew a caret under.
	Row int
	Col int
}

AontuError is the error type returned by Unify/Generate.

func (*AontuError) Error

func (e *AontuError) Error() string

type ConjunctVal

type ConjunctVal struct {
	// contains filtered or unexported fields
}

ConjunctVal is the unification (&) of its terms.

func (*ConjunctVal) Canon

func (c *ConjunctVal) Canon() string

func (*ConjunctVal) Dc

func (b *ConjunctVal) Dc() int

func (*ConjunctVal) Gen

func (c *ConjunctVal) Gen(ctx *Ctx) (any, error)

func (*ConjunctVal) Nil

func (b *ConjunctVal) Nil() bool

func (*ConjunctVal) Unify

func (c *ConjunctVal) Unify(peer Val, ctx *Ctx) Val

type ConstraintVal

type ConstraintVal struct {
	// contains filtered or unexported fields
}

ConstraintVal is immutable after construction: meets build NEW residuals, so clones may share one (clonePath copies the struct shallowly, like a ScalarKindVal).

func (*ConstraintVal) Canon

func (c *ConstraintVal) Canon() string

Canon renders the fixed canonical atom order: kind, lower bound, upper bound, neq (arguments sorted), re, length, unique. Reparses to a conjunct of atoms that normalises back to this exact residual.

func (*ConstraintVal) Dc

func (b *ConstraintVal) Dc() int

func (*ConstraintVal) Gen

func (c *ConstraintVal) Gen(ctx *Ctx) (any, error)

func (*ConstraintVal) Nil

func (b *ConstraintVal) Nil() bool

func (*ConstraintVal) Unify

func (c *ConstraintVal) Unify(peer Val, ctx *Ctx) Val

type Ctx

type Ctx struct {
	// contains filtered or unexported fields
}

Ctx carries unification state: the root Val (for path resolution, once references are ported) and the collected error list.

type Decimal

type Decimal struct {
	// contains filtered or unexported fields
}

Decimal is an exact base-10 decimal value: coeff * 10^-scale.

It is IMMUTABLE, like every pointer peg in the engine (D8): clones share it and nothing mutates it in place. Every Decimal reaching a ScalarVal is in NORMAL FORM (see newDecimal), which is what makes identity a matter of comparing the two fields.

func (*Decimal) Canon

func (d *Decimal) Canon() string

Canon renders the decimal as an Aontu literal: the sign BEFORE the marker (`-0d1.5`), plain form at every magnitude (D4).

func (*Decimal) MarshalJSON

func (d *Decimal) MarshalJSON() ([]byte, error)

MarshalJSON emits the exact digits as a raw JSON number. JSON numbers are arbitrary-precision text, so nothing is lost.

This is the counterpart of what encoding/json ALREADY does for the biginteger leaf's *big.Int peg, and it is here for the same reason: without it a generated bigdecimal marshals through the struct path as `{}` — a silent corruption, and the one failure mode the exact leaves exist to eliminate. The wider generate contract (D9: native runtime types, the TypeScript exact emitter, and the API tests pinning both) is Phase 5's, and may revisit this.

func (*Decimal) String

func (d *Decimal) String() string

String renders the decimal as its plain digits (no `0d` marker), so a Decimal formats readably in Go error and debug output.

type Deprecation

type Deprecation struct {
	Pos    int
	Len    int
	Record map[string]string
}

Deprecation is one value carrying the deprecate() record after evaluation (G3 phase 4): its source position, the byte length of its canonical rendering (for a highlight range), and the record itself.

type DiffChange

type DiffChange struct {
	Kind  string `json:"kind"`
	Left  string `json:"left,omitempty"`
	Path  string `json:"path"`
	Right string `json:"right,omitempty"`
}

type DiffOptions

type DiffOptions struct {
	// At compares at this path of both documents, rather than at the
	// root.
	At        string
	LeftPath  string
	RightPath string
}

type DiffReport

type DiffReport struct {
	Changes  []DiffChange `json:"changes"`
	Findings []VetFinding `json:"findings"`
	OK       bool         `json:"ok"`
	// Same is true when nothing moved: the two documents mean the same
	// thing.
	Same bool `json:"same"`
}

func Diff

func Diff(leftSrc, rightSrc string, opts *DiffOptions) DiffReport

Diff compares two documents. Each is evaluated on its own — a document that does not stand up has no meaning to compare, and the report says so rather than diffing a wreck. Mirrors diff in ts/src/diff.ts.

type DisjunctVal

type DisjunctVal struct {
	// contains filtered or unexported fields
}

DisjunctVal is the choice (|) between its members. Conjunction distributes over disjunction: unifying with a peer tries the peer against each member, dropping members that fail.

func (*DisjunctVal) Canon

func (d *DisjunctVal) Canon() string

func (*DisjunctVal) Dc

func (b *DisjunctVal) Dc() int

func (*DisjunctVal) Gen

func (d *DisjunctVal) Gen(ctx *Ctx) (any, error)

AN UNRESOLVED DISJUNCTION IS NOT A VALUE (ADR-007). The twin of DisjunctVal.gen in ts/src/val/DisjunctVal.ts; the full note is there. The short of it: generation used to FOLD the surviving members together with Unify and emit the result, which is a value in no branch of the disjunction (`({x:1}|{y:2}) & {z:3}` generated `{x:1,y:2,z:3}`) and reported an unresolved enum as a scalar CONFLICT -- so vet, which keeps incomplete-class findings, filtered it out and answered valid on a missing required field (use-cases/BUGS.md §13).

func (*DisjunctVal) Nil

func (b *DisjunctVal) Nil() bool

func (*DisjunctVal) Unify

func (d *DisjunctVal) Unify(peer Val, ctx *Ctx) Val

type Edge

type Edge struct {
	// From is the entity the link is INSIDE — the nearest identified
	// ancestor, or "" for a link outside every entity. This is the
	// entity/component distinction: a node without an id is a component
	// of its nearest identified ancestor.
	From string `json:"from"`
	// Key is the RELATION: the nearest map key on the way down from the
	// entity, so a link inside a list (`dependsOn: [&: refer(),
	// svc/auth]`) is an edge under `dependsOn` rather than under `0`.
	Key string `json:"key"`
	// To is the address, as the link spells it.
	To string `json:"to"`
	// At is where the link is, as a `$.dotted.path`.
	At string `json:"at"`
}

Edge is one checked link.

type EntityEntry

type EntityEntry struct {
	ID    string   `json:"id"`
	Paths []string `json:"paths"`
}

EntityEntry is one id and every tree path that holds it. More than one path is the normal case: the merge puts the entity's value at every position that declared it.

type ExpectVal

type ExpectVal struct {
	// contains filtered or unexported fields
}

ExpectVal is the exact port of ts/src/val/ExpectVal.ts (issue #27): the marker a map creates when a PEER key arrives whose value is not generable on its own — a kind, top, a var, a constraint residual — most commonly a spread template field applied to a child that never receives a concrete value (`m:{&:{r:string} a:{}}`). The bag's Gen distinguishes this residue as mapval_spread_required / listval_spread_required (versus the generic *_no_gen), and the expectation escapes to a real value the moment a concrete peer arrives (see Unify).

Created ONLY by the MapVal peer-key loop (TS handleExpectedVal is called from MapVal.unify alone), so a list child is never an ExpectVal and listval_spread_required stays exactly as reachable as it is in TypeScript: registered vocabulary, no raise site today.

func (*ExpectVal) Canon

func (e *ExpectVal) Canon() string

Canon is THE EXPECTATION ITSELF — the peg the peer must satisfy — exactly as in TS. It used to render as nothing, so a map holding an expect for key r canoned as `{"r":}`: text that is not a document and could not be reparsed, breaking canon's round-trip contract in both engines (issue #43).

Not `top`, which was the first fix here and was wrong. An ExpectVal is created for EVERY peer-introduced non-generable key, not just for `&:` spread children — `m:{x:1} m:{y:string}` makes one at y with no spread in sight — so rendering `top` erased the `string` and the canon reparsed into a document that accepts values the original rejects. A canon that silently drops a constraint is worse than one that fails to parse.

func (*ExpectVal) Dc

func (b *ExpectVal) Dc() int

func (*ExpectVal) Gen

func (e *ExpectVal) Gen(ctx *Ctx) (any, error)

Gen is unreachable: BagVal-level Gen intercepts an expect child (the *_spread_required branch) before ever calling child.Gen, for optional and required keys alike — the same interception order as TS BagVal.gen, whose ExpectVal.gen is likewise dead code. Silent, mirroring the FuncVal.Gen pattern for never-generated residue.

func (*ExpectVal) Nil

func (b *ExpectVal) Nil() bool

func (*ExpectVal) Unify

func (e *ExpectVal) Unify(peer Val, ctx *Ctx) Val

Unify mirrors TS ExpectVal.unify: accumulate concrete peers, meet them with the expectation, and ESCAPE to the united value as soon as it is generable (`m:{&:{r:string} a:{r:x}}` resolves a.r to "x"). Until then the expect itself stays, done.

PURE, deliberately (the unequal-spread crosswire, BUGS.md §6-§7, mirroring ts/src/val/ExpectVal.ts). The old body accumulated e.peer IN PLACE — invisible while an expectation only lived at one destination, but the spread-combination meet (MapVal.Unify) bakes an ExpectVal INTO the combined template, and a path-independent template is SHARED across every destination (spreadCloneFor). One stateful node in a shared template unified each sibling's own data with the next sibling's. An expectation that must keep accumulated state now answers with a NEW node, leaving the shared template untouched.

type FuncVal

type FuncVal struct {
	// contains filtered or unexported fields
}

FuncVal is a built-in function call (e.g. `upper(x)`). It follows the FuncBaseVal pattern (ts/src/val/FuncBaseVal.ts): operands are resolved to done, then resolve() computes the result; otherwise it defers.

func (*FuncVal) Canon

func (f *FuncVal) Canon() string

func (*FuncVal) Dc

func (b *FuncVal) Dc() int

func (*FuncVal) Gen

func (f *FuncVal) Gen(ctx *Ctx) (any, error)

func (*FuncVal) Nil

func (b *FuncVal) Nil() bool

func (*FuncVal) Unify

func (f *FuncVal) Unify(peer Val, ctx *Ctx) Val

type Graph

type Graph struct {
	Entities []EntityEntry `json:"entities"`
	Edges    []Edge        `json:"edges"`
}

Graph is an evaluated document's entity index and edge set.

func GraphOf

func GraphOf(root Val) Graph

GraphOf is the graph of an evaluated tree. Walks POSITIONS, not values: two positions of one entity share a value object after the merge, so a walk guarded by object identity would find the entity once and miss every other place it is declared. The guard is therefore the ancestor chain — which is what a cycle actually is.

type IncludeDep

type IncludeDep struct {
	Path       string
	Capability string
}

IncludeDep is one entry of the include manifest: a resolved include's absolute path and the capability that resolved it ("mem" or "file"). The manifest is hermeticity clause 1's "file set" made observable (docs/trust.md); content hashing and pinning stay with G6.

type Kind

type Kind int

Kind enumerates the scalar kinds (type constraints).

The numeric kinds form a small lattice (docs/design/number-tower.md):

number                pure supertype: the set of all numeric values
|- integer            int64-window exact
|- float              IEEE-754 binary64
|- biginteger         unbounded exact integer   (opt-in via 0d)
|- bigdecimal         exact base-10 decimal     (opt-in via 0d)

KindNumber is a SUPERTYPE only: it names no representation and is carried by a ScalarKindVal (the `number` keyword) alone — a concrete ScalarVal always carries a numeric LEAF kind. The leaves are pairwise disjoint: `5 & 0d5` is an error, exactly as `1 & 1.0` is, because a cross-leaf result would have to pick a kind (D2).

const (
	KindTop Kind = iota
	KindNil
	KindString
	// KindNumber is the numeric supertype; it is never a ScalarVal kind.
	KindNumber
	// Numeric leaves. Keep contiguous, and extend numericLeafKinds when
	// adding one.
	KindInteger
	KindFloat
	KindBigInteger
	KindBigDecimal
	KindBoolean
	KindNull
)

func (Kind) String

func (k Kind) String() string

type ListVal

type ListVal struct {
	// contains filtered or unexported fields
}

ListVal is an ordered list of element Vals. Unification is element-wise by index; a longer peer extends the result.

func (*ListVal) Canon

func (l *ListVal) Canon() string

func (*ListVal) Dc

func (b *ListVal) Dc() int

func (*ListVal) Gen

func (l *ListVal) Gen(ctx *Ctx) (any, error)

func (*ListVal) Nil

func (b *ListVal) Nil() bool

func (*ListVal) Unify

func (l *ListVal) Unify(peer Val, ctx *Ctx) Val

type MapVal

type MapVal struct {
	// contains filtered or unexported fields
}

MapVal is an ordered map of string keys to child Vals. Insertion order is preserved for canon output and generation.

func (*MapVal) Canon

func (m *MapVal) Canon() string

func (*MapVal) Dc

func (b *MapVal) Dc() int

func (*MapVal) Gen

func (m *MapVal) Gen(ctx *Ctx) (any, error)

func (*MapVal) Nil

func (b *MapVal) Nil() bool

func (*MapVal) Unify

func (m *MapVal) Unify(peer Val, ctx *Ctx) Val

type ModLock

type ModLock struct {
	// Canon is the canon-hash of the module as it is in the local store.
	Canon string `json:"canon"`
	// Mod is the module path and major, as an import spells it.
	Mod string `json:"mod"`
	// Oci is the registry digest, carried over from a previous
	// lockfile. Empty when nothing has ever fetched this module: the
	// OCI pin is the registry's word, and only a fetch can hear it.
	Oci string `json:"oci"`
	// V is the selected version.
	V string `json:"v"`
}

ModLock is one entry of the lockfile, and of a tidy report. Field order is LEXICOGRAPHIC, the canonical emitter's order.

type ModManifestReport

type ModManifestReport struct {
	Annotations map[string]string `json:"annotations"`
	Canon       string            `json:"canon"`
	Config      string            `json:"config"`
	Files       []string          `json:"files"`
	Findings    []VetFinding      `json:"findings"`
	Missing     []string          `json:"missing"`
	Mod         string            `json:"mod"`
	Verdict     string            `json:"verdict"`
	Version     string            `json:"version"`
}

ModManifestReport is the OCI artifact description a publish would push, and the gate's verdict on whether it may be.

func ModManifest

func ModManifest(root, against string) ModManifestReport

ModManifest is `aontu mod manifest`: the OCI artifact description a publish would push, and the gate that decides whether it may be. against is the prior version's module directory, or empty for no gate.

type ModMismatch

type ModMismatch struct {
	Got  string `json:"got"`
	Mod  string `json:"mod"`
	Want string `json:"want"`
}

ModMismatch is one locked module whose store no longer means what the lockfile pins. Got is empty when the store holds something that does not evaluate at all.

type ModTidyReport

type ModTidyReport struct {
	Lock    []ModLock `json:"lock"`
	Missing []string  `json:"missing"`
	// Unevaluable names the modules present in a store which DO NOT
	// EVALUATE standalone, sorted. A pin is what a module MEANS, so
	// there is nothing to pin here and the lockfile is left alone.
	Unevaluable []string `json:"unevaluable"`
	Verdict     string   `json:"verdict"`
}

ModTidyReport is the result of `aontu mod tidy`.

func ModTidy

func ModTidy(root, cache string) ModTidyReport

ModTidy resolves the closure by MVS and rewrites the lockfile.

type ModVendorReport

type ModVendorReport struct {
	Missing  []string `json:"missing"`
	Vendored []string `json:"vendored"`
	Verdict  string   `json:"verdict"`
}

ModVendorReport is the result of `aontu mod vendor`.

func ModVendor

func ModVendor(root, cache string) ModVendorReport

ModVendor materialises the locked closure into `aon_vendor/`.

type ModVerifyReport

type ModVerifyReport struct {
	// Mismatched is what the lockfile pins against what the store now
	// means, for each module that does not match, sorted by module.
	Mismatched []ModMismatch `json:"mismatched"`
	Missing    []string      `json:"missing"`
	// Unlocked names the dependencies the project declares that the
	// lockfile does not name, sorted. A tidy is what fills them in.
	Unlocked []string `json:"unlocked"`
	Verdict  string   `json:"verdict"`
	// Verified names the locked modules that still mean what is pinned.
	Verified []string `json:"verified"`
}

ModVerifyReport is the result of `aontu mod verify`.

func ModVerify

func ModVerify(root, cache string) ModVerifyReport

ModVerify asks whether every locked module still MEANS what the lockfile pins. Recompute and compare, and CHANGE NOTHING.

The verb exists because ModTidy cannot answer this question. Tidy recomputes and REWRITES by design -- a pin is what a module means now -- so tampering with a vendored module and running tidy makes the lockfile agree with the tampering, `verdict: ok`, and the next evaluation passes. That is correct for the job tidy does and useless as a gate, which left a CI job that tidies before evaluating with no integrity protection at all (use-cases/BUGS.md §32). Verification is a question; answering it must not be an edit. Mirrors modVerify in ts/src/mod-tool.ts.

type ModuleRef

type ModuleRef struct {
	// Path is the module path WITHOUT the major.
	Path string
	// Major is the major version, from the `@N` suffix.
	Major int
	// Hash is the inline canon-hash pin, if the import froze one.
	Hash string
}

ModuleRef is a module import, as the string spells it.

type NilVal

type NilVal struct {
	// contains filtered or unexported fields
}

NilVal represents a unification failure (bottom). It carries enough context to render the "Cannot unify value: X with value: Y" message that the shared error specs assert on.

func (*NilVal) Canon

func (n *NilVal) Canon() string

func (*NilVal) Class

func (n *NilVal) Class() string

Class is the code's class from the shared registry (test/spec/errcodes.tsv): conflict | incomplete | reference | parse | budget | internal. Mirrors the NilVal.class getter in TS.

func (*NilVal) Dc

func (b *NilVal) Dc() int

func (*NilVal) FullMessage

func (n *NilVal) FullMessage(src, file string) string

FullMessage renders the failure the way the canonical TypeScript implementation renders a THROWN error (descErr, ts/src/err.ts): the `[aontu/<code>]` marker, the "Cannot <attempt> value(s) at path <path>" headline, the (parameterised) hint, and one located source frame per operand — byte-matched to the TS output, ANSI colouring included. Used by the AontuError paths (unify/generate); the LSP/Problem surface keeps the short Message below, mirroring TS's own split (descErr vs the LSP's nilMessage). src is the entry source text for row/col mapping and excerpts (ctx.src); frames for values loaded from includes fall back to it, as TS's resolveSrc falls back when a site's file cannot be read.

func (*NilVal) Gen

func (n *NilVal) Gen(ctx *Ctx) (any, error)

func (*NilVal) Headline

func (n *NilVal) Headline() string

Headline is the first line of the full message: the `[aontu/<code>]` marker, the attempt and the path. It is the ONE line of prose the two ports hold to byte parity (the frames below it excerpt source, and the short Message is each port's own), which is why the validation verb reports it rather than Message -- a vet report crossing between the ports must read the same in both (vet.go).

func (*NilVal) Message

func (n *NilVal) Message() string

Message renders the human-readable failure message. The phrasing of the "Cannot <attempt> value: ..." line is kept compatible with the canonical TypeScript LSP diagnostic text (nilMessage, ts/src/lsp.ts); the thrown-error surface uses FullMessage above.

func (*NilVal) Nil

func (n *NilVal) Nil() bool

func (*NilVal) Path

func (n *NilVal) Path() string

Path is the `$.a.b` location the failure is reported at.

The path comes from the primary operand, as TS NilVal.make copies av.path onto the nil. A nil with NO operands -- one raised about a construct rather than about a failed meet, such as the refused negation in `a:-0x_1` -- keeps the path setPaths gave it where it sits in the tree; reading only the (absent) primary reported every one of them at the root (issue #39).

func (*NilVal) Unify

func (n *NilVal) Unify(peer Val, ctx *Ctx) Val

type PatchOptions

type PatchOptions struct {
	// The include capability this document evaluates under (G5,
	// docs/trust.md). Nil means today's default.
	Trust *TrustOptions

	// Where each document CAME FROM, so relative `@"file"` loads
	// inside them resolve from their own directories.
	EntryPath   string
	OverlayPath string
	// InPlace rewrites a pinned literal where the author wrote it,
	// instead of appending a line that contradicts it. Opt-in:
	// appending is non-destructive and in-place editing is not.
	InPlace bool
}

type PatchReplacement

type PatchReplacement struct {
	Col  int    `json:"col"`
	File string `json:"file"`
	From string `json:"from"`
	Path string `json:"path"`
	Row  int    `json:"row"`
	To   string `json:"to"`
}

PatchReplacement is one literal rewritten where it was written. From and To are SOURCE TEXT, not values: replacing `0x1F` with `31` is a different edit from replacing it with `0x1F`, and only the spelling says which.

LEXICOGRAPHIC field order, as everywhere the two emitters must agree byte for byte.

type PatchReport

type PatchReport struct {
	// Appended is the added lines alone, in order.
	Appended []string     `json:"appended"`
	Findings []VetFinding `json:"findings"`
	// Overlay is the overlay text as it would stand after the
	// assignments. The caller writes it — an engine that touched the
	// filesystem could not be used by a server.
	Overlay string `json:"overlay"`
	// Replaced is the in-place replacements made, in the order the
	// assignments were given (NOT the order they were applied to the
	// text, which is back-to-front so earlier offsets stay valid).
	// Empty unless InPlace was asked for.
	Replaced []PatchReplacement `json:"replaced"`
	Verdict  string             `json:"verdict"`
}

func Patch

func Patch(
	entrySrc, overlaySrc string, assignments []string, opts *PatchOptions,
) PatchReport

Patch appends the assignments to the overlay and answers what the result holds. Mirrors patch in ts/src/patch.ts.

type PlaceVal

type PlaceVal struct {
	// contains filtered or unexported fields
}

PlaceVal is the hole.

func (*PlaceVal) Canon

func (p *PlaceVal) Canon() string

func (*PlaceVal) Dc

func (b *PlaceVal) Dc() int

func (*PlaceVal) Gen

func (p *PlaceVal) Gen(ctx *Ctx) (any, error)

Silent, exactly as TopVal.Gen is: the enclosing bag decides whether an unfilled hole is an error (a direct child) or dropped (under a pref or optional subtree).

func (*PlaceVal) Nil

func (b *PlaceVal) Nil() bool

func (*PlaceVal) Unify

func (p *PlaceVal) Unify(peer Val, ctx *Ctx) Val

type PlusOpVal

type PlusOpVal struct {
	// contains filtered or unexported fields
}

PlusOpVal is the `+` operator: string concatenation, numeric addition or boolean or. Ported from ts/src/val/PlusOpVal.ts and OpBaseVal.ts. Operands are resolved to done before the operation runs; an operation that cannot yet run defers across fixpoint passes.

func (*PlusOpVal) Canon

func (o *PlusOpVal) Canon() string

func (*PlusOpVal) Dc

func (b *PlusOpVal) Dc() int

func (*PlusOpVal) Gen

func (o *PlusOpVal) Gen(ctx *Ctx) (any, error)

func (*PlusOpVal) Nil

func (b *PlusOpVal) Nil() bool

func (*PlusOpVal) Unify

func (o *PlusOpVal) Unify(peer Val, ctx *Ctx) Val

type PrefVal

type PrefVal struct {
	// contains filtered or unexported fields
}

PrefVal marks a preferred (default) value, written `*x`. Within a disjunct it is selected over non-preferred members during generation; unified against a concrete peer it yields the peer when the peer narrows it, otherwise the preferred value wins.

func (*PrefVal) Canon

func (p *PrefVal) Canon() string

func (*PrefVal) Dc

func (b *PrefVal) Dc() int

func (*PrefVal) Gen

func (p *PrefVal) Gen(ctx *Ctx) (any, error)

func (*PrefVal) Nil

func (b *PrefVal) Nil() bool

func (*PrefVal) Unify

func (p *PrefVal) Unify(peer Val, ctx *Ctx) Val

type Problem

type Problem struct {
	// Pos is the byte offset into the source of the offending value, or
	// -1 when no position is known.
	Pos int

	// Len is the byte length of the offending value's SOURCE TEXT
	// (always >= 1), used to size the diagnostic range. Bytes, not
	// UTF-16 units, because it is added to the byte offset Pos before
	// the pair is converted (go/lsp/lsp.go idx.position).
	//
	// The canonical form is the FALLBACK, not the measure: canon is not
	// source text, so sizing `0x1F` (canon `31`) by canon underlines two
	// characters of a four-character literal. Where a value carries no
	// stamped source text -- one propagated onto a result rather than
	// written by a document -- canon is all there is, and an approximate
	// underline still beats none. A REPORT never guesses this way; see
	// the note on VetSite.Len.
	Len int

	// Why is the engine error code (e.g. "scalar_value", "no_path",
	// "unknown_function").
	Why string

	// Class is Why's class from the shared registry
	// (test/spec/errcodes.tsv): conflict | incomplete | reference |
	// parse | budget | internal.
	Class string

	// Message is the human-readable error message.
	Message string
}

Problem describes a single source problem found by Check: a NilVal (unification conflict, unresolved reference, unknown function, …) present in the unified result tree. It carries the source byte offset so tooling — notably the LSP server in ../go/lsp — can render editor diagnostics. A valid but non-concrete document (e.g. a bare `a:string` schema) yields no Problems: only genuine errors become NilVals.

type Provenance

type Provenance struct {
	// contains filtered or unexported fields
}

Provenance is the recorder itself. Mirrors the class in ts/src/provenance.ts.

type QueryOptions

type QueryOptions struct {
	View  string
	Depth int
}

QueryOptions are Get's knobs. Depth counts levels of structure kept below the selected node; everything deeper renders as `top`. Zero means "no limit" (the TypeScript side spells that undefined).

type QueryReport

type QueryReport struct {
	Findings []VetFinding `json:"findings"`
	OK       bool         `json:"ok"`
	Out      string       `json:"out"`
}

QueryReport is the whole answer: the rendered slice, or G2-shaped findings. Get invents no error format (G7's own rule).

type ReachOptions

type ReachOptions struct {
	// Relation follows only edges under this relation. Empty means
	// follow every edge, which is the whole graph and the commoner
	// question.
	Relation string
}

ReachOptions mirrors ReachOptions in ts/src/reach.ts.

type ReachReport

type ReachReport struct {
	Verdict ReachVerdict `json:"verdict"`

	// Path is the path found, as entity names from the source to the
	// destination, both included. Present ONLY on `reaches`: a path is
	// the evidence for the answer, and there is no evidence for a
	// negative one.
	Path []string `json:"path,omitempty"`

	// Errors is WHY the graph could not be looked at, in vet's finding
	// shape. Present ONLY on `error`.
	Errors []VetFinding `json:"errors,omitempty"`
}

ReachReport is the answer for one document, mirroring ReachReport in ts/src/reach.ts field for field.

type ReachVerdict

type ReachVerdict = string

ReachVerdict is reaches | unreachable | error.

type RefVal

type RefVal struct {
	// contains filtered or unexported fields
}

RefVal is a path reference (e.g. `$.a.b`, `.x.a`, `x.a`). It resolves against the root during the fixpoint unification loop. Ported from ts/src/val/RefVal.ts.

func (*RefVal) Canon

func (rv *RefVal) Canon() string

func (*RefVal) Dc

func (b *RefVal) Dc() int

func (*RefVal) Gen

func (rv *RefVal) Gen(ctx *Ctx) (any, error)

func (*RefVal) Nil

func (b *RefVal) Nil() bool

func (*RefVal) Unify

func (rv *RefVal) Unify(peer Val, ctx *Ctx) Val

type ReferVal

type ReferVal struct {
	// contains filtered or unexported fields
}

ReferVal is what `refer(t)` RESOLVES to: the residual constraint, carrying the type to flow and — once it has met a string — the address to flow it into. A separate value from the function for the reason every residual is: the function is written once and the constraint is met many times, and only the constraint has state worth carrying. Mirrors ReferVal in ts/src/val/ReferFuncVal.ts.

func (*ReferVal) Canon

func (r *ReferVal) Canon() string

func (*ReferVal) Dc

func (b *ReferVal) Dc() int

func (*ReferVal) Gen

func (r *ReferVal) Gen(ctx *Ctx) (any, error)

func (*ReferVal) Nil

func (b *ReferVal) Nil() bool

func (*ReferVal) Unify

func (r *ReferVal) Unify(peer Val, ctx *Ctx) Val

type RelationFinding

type RelationFinding struct {
	// At is where the offending edge is written, as a `$.dotted.path`.
	At   string `json:"at"`
	Code string `json:"code"`
	// Detail is, for a cycle, the entities it runs through in the order
	// the walk found them, closing back on the first; for a missing
	// inverse, the two ends and the relation that should have mirrored
	// it.
	Detail []string `json:"detail"`
	// Relation the finding is about.
	Relation string `json:"relation"`
}

RelationFinding is one broken relation property. Field order is LEXICOGRAPHIC, the canonical emitter's order — the TypeScript port's exactJSON sorts keys, and a report is read by a machine that diffs it.

type RelationReport

type RelationReport struct {
	// Errors is WHY the graph could not be looked at, in the same
	// finding shape Vet reports in (the review's finding F). Findings is
	// about the GRAPH and stays that way; a document that does not stand
	// up has no graph to have findings about, and an `error` verdict
	// used to arrive with an empty list -- something is wrong, and
	// nothing about what. Present ONLY on an `error` verdict.
	Errors   []VetFinding      `json:"errors,omitempty"`
	Findings []RelationFinding `json:"findings"`
	Verdict  string            `json:"verdict"`
}

RelationReport is the relation checks for one document.

type ScalarKindVal

type ScalarKindVal struct {
	// contains filtered or unexported fields
}

ScalarKindVal is a type constraint (e.g. string, number) — a scalar kind without a concrete value.

func (*ScalarKindVal) Canon

func (k *ScalarKindVal) Canon() string

func (*ScalarKindVal) Dc

func (b *ScalarKindVal) Dc() int

func (*ScalarKindVal) Gen

func (k *ScalarKindVal) Gen(ctx *Ctx) (any, error)

func (*ScalarKindVal) Nil

func (b *ScalarKindVal) Nil() bool

func (*ScalarKindVal) Unify

func (k *ScalarKindVal) Unify(peer Val, ctx *Ctx) Val

type ScalarVal

type ScalarVal struct {
	// contains filtered or unexported fields
}

ScalarVal is a concrete scalar literal: a native value tagged with its Kind. peg holds string | int64 | float64 | bool | nil, or one of the tower's exact pegs: *big.Int (biginteger) and *Decimal (bigdecimal).

The two exact pegs are POINTERS, and pointers are IMMUTABLE here (D8): clones share them and nothing mutates them in place. That also means `==` on a peg is an ADDRESS comparison for those kinds — every identity test must go through scalarPegSame instead (D2).

func (*ScalarVal) Canon

func (s *ScalarVal) Canon() string

func (*ScalarVal) Dc

func (b *ScalarVal) Dc() int

func (*ScalarVal) Gen

func (s *ScalarVal) Gen(ctx *Ctx) (any, error)

Gen returns the NATIVE Go value for this scalar: string, int64 (integer), float64 (float), bool, nil — and, for the tower's exact leaves, *big.Int (biginteger) and *Decimal (bigdecimal).

The two exact leaves are POINTERS, and that is a requirement rather than a convenience (D9): a non-pointer big.Int sitting in an `any` marshals as `{}`, silently emitting an empty object where an exact number should be. As pointers, encoding/json calls their MarshalJSON and both reach JSON as EXACT DIGITS in a raw JSON number — JSON numbers are arbitrary-precision text, so nothing is lost on the way out. (Only JavaScript's serialiser needs help here, which is why the canonical port ships its own emitter.)

Byte-exact serialisation cannot check any of this on its own: a biginteger and an integer can produce the SAME text while generate returned the wrong runtime type. The concrete types above are pinned by TestGenerateNativeExactTypes.

func (*ScalarVal) Nil

func (b *ScalarVal) Nil() bool

func (*ScalarVal) Unify

func (s *ScalarVal) Unify(peer Val, ctx *Ctx) Val

type SchemaLoss

type SchemaLoss struct {
	// Construct is the Aontu construct's own name, so a reader can grep
	// their source for it.
	Construct string `json:"construct"`
	// Path is the `$.a.b` spelling every other report uses.
	Path string `json:"path"`
	// Reason is one sentence: why JSON Schema cannot say it, and what
	// the schema says instead.
	Reason string `json:"reason"`
}

SchemaLoss is one construct the schema could not carry.

type SchemaReport

type SchemaReport struct {
	// Errors carries WHY the run could not be made, in vet's finding
	// shape. Present only on an error verdict.
	Errors []VetFinding `json:"errors,omitempty"`
	// Lossy names every construct that could not be carried, in document
	// order.
	Lossy []SchemaLoss `json:"lossy"`
	// Schema is the JSON Schema document; empty on error.
	Schema map[string]any `json:"schema"`
	// Verdict: ok everything carried, lossy the schema is a WEAKER
	// statement than the model, error the document does not stand up.
	Verdict string `json:"verdict"`
}

SchemaReport is the result of an export.

type SubsumeOptions

type SubsumeOptions struct {
	// The include capability both documents evaluate under (G5,
	// docs/trust.md). Nil means today's default.
	Trust *TrustOptions

	Profile     string // "values" | "defaults" (default) | "gen"
	At          string // compare at this path of both documents
	GeneralURL  string // provenance label for general sites
	SpecificURL string // provenance label for specific sites
	// Where each document CAME FROM, so a relative `@"file"` load
	// inside it resolves from its own directory — vet's
	// SchemaPath/DataPath precedent, one per document because they
	// need not live together.
	GeneralPath  string
	SpecificPath string
}

SubsumeOptions are the query's knobs; the zero value compares under the `defaults` profile at the roots.

type SubsumeReport

type SubsumeReport struct {
	Findings []VetFinding `json:"findings"`
	Verdict  string       `json:"verdict"`
}

SubsumeReport is the whole answer: one verdict, and the findings behind it.

func Subsume

func Subsume(generalSrc, specificSrc string, opts *SubsumeOptions) SubsumeReport

type TopVal

type TopVal struct {
	// contains filtered or unexported fields
}

TopVal is the unit of the lattice: unifying with TOP yields the other operand. There is conceptually only one TOP.

func (*TopVal) Canon

func (t *TopVal) Canon() string

func (*TopVal) Dc

func (b *TopVal) Dc() int

func (*TopVal) Gen

func (t *TopVal) Gen(ctx *Ctx) (any, error)

func (*TopVal) Nil

func (b *TopVal) Nil() bool

func (*TopVal) Unify

func (t *TopVal) Unify(peer Val, ctx *Ctx) Val

type TrimReport

type TrimReport struct {
	// Errors is WHY the run could not be made, in the same finding shape
	// Vet reports in (the review's finding F). An `error` verdict used
	// to arrive with an empty report -- something is wrong with the
	// document, and nothing about what -- which is the one answer a
	// repair loop cannot act on. Present ONLY on an `error` verdict, so
	// a clean report stays exactly the two fields it always was.
	Errors    []VetFinding `json:"errors,omitempty"`
	Redundant []string     `json:"redundant"`
	Verdict   string       `json:"verdict"`
}

TrimReport is the whole answer: one verdict, and the redundant paths.

type TrustBudget

type TrustBudget struct {
	Passes int // fixpoint passes (default 9)
	Depth  int // structural recursion depth (default 1000)
}

TrustBudget bounds evaluation work (G5 trust profile, docs/trust.md): integer counts of engine events, never wall-clock. Zero means the default — the shared spec-visible constants test/spec/budget.tsv pins in both ports.

type TrustOptions

type TrustOptions struct {
	IncludeNone bool              // @"..." is always denied
	IncludeMem  map[string]string // a virtual file set only
	IncludeRoot string            // real files, realpath-confined below this root
	Budget      TrustBudget
}

TrustOptions is the trust profile (G5, docs/trust.md): what an evaluation may read, and how much work it may do. The zero value is the 'system' posture — today's unconfined default. At most one of the Include fields should be set; the mirror of the canonical port's `trust.include` union ('none' | { mem } | { root } | 'system').

type Val

type Val interface {
	// Canon returns the canonical, source-like representation.
	Canon() string

	// Gen produces the native Go value for output (JSON generation).
	// A non-nil error means the value could not be generated (e.g. an
	// unresolved type, conjunct or nil).
	Gen(ctx *Ctx) (any, error)

	// Unify combines this Val with peer, returning the result. The
	// result is a NilVal (Nil() == true) when they cannot unify.
	Unify(peer Val, ctx *Ctx) Val

	// Dc reports the done-counter; DONE means fully resolved.
	Dc() int

	// Nil reports whether this Val is a Nil (unification failure).
	Nil() bool
	// contains filtered or unexported methods
}

Val is the interface implemented by every value in the lattice.

func NewBigDecimal

func NewBigDecimal(s string) (Val, error)

NewBigDecimal returns a bigdecimal scalar value — the tower's exact base-10 decimal leaf — from an exact decimal STRING: an optional sign, an optional `0d` marker, digits, an optional fraction and an optional exponent ("1.5", "-0.10", "0d1e3", "5"). The value is normalised exactly as a literal is (D4), so NewBigDecimal("0.10") and NewBigDecimal("1e-1") are the same value, and an integral one keeps its single decimal place — NewBigDecimal("5") canons as `0d5.0`, a bigdecimal, because here the CONSTRUCTOR picks the leaf where a literal's source text would.

A string is the argument type on purpose: a Go float64 has already rounded before the library can inspect it, so accepting one would smuggle an inexact value into an exact leaf (D8).

It returns an error for a malformed string, and for one outside the exactness budget (D6: at most 4096 coefficient digits and an absolute scale of at most 4096) — the same refusal a literal gets, since programmatic construction obeys the same contract.

func NewBigInteger

func NewBigInteger(n *big.Int) Val

NewBigInteger returns a biginteger scalar value — the tower's unbounded exact integer leaf, the same leaf a `0d123` literal builds.

The argument is COPIED, and the copy is never mutated afterwards, so a caller may keep using (and mutating) the big.Int it passed in. A nil argument is zero. This is the exact-input construction contract of D8: exact values above 2^53 enter through this constructor or through a `0d` literal, never by rounding an inexact one.

func NewBoolean

func NewBoolean(b bool) Val

NewBoolean returns a boolean scalar value.

func NewInteger

func NewInteger(i int64) Val

NewInteger returns an integer scalar value.

D8 — PROGRAMMATIC CONSTRUCTION OBEYS THE SAME STORAGE CONTRACT AS A LITERAL. An int64 that a binary64 cannot carry exactly (9007199254740993, 2^63-1, …) is REFUSED rather than stored, exactly as the equivalent literal is refused by D7. Without this the API is a hole straight through the tower's storage rule: Go's integer leaf is an int64 and the canonical TypeScript port's is a double, so `NewInteger(9007199254740993)` would be exact here and silently `…992` there — a parity divergence no parse-time rule can see, because no literal can express it.

THE RULE IS EXACTNESS, NOT MAGNITUDE. Every power of two in the window is fine however large, math.MinInt64 (-2^63) among them; what fails is an int64 that would have to CHANGE to be stored.

A refusal is a nil VALUE, not a panic and not a second return: aontu errors are values, so the refusal flows through unification and surfaces at Generate with the same "not exactly representable" hint the literal gets. That also keeps the signature — this is a narrowing of what the function accepts, not a change to how it is called.

Use NewBigInteger for an exact integer of any size.

func NewList

func NewList(elems []Val) Val

NewList returns a list value from the given elements.

func NewMap

func NewMap(fields map[string]Val) Val

NewMap returns a map value built from fields. Keys are inserted in sorted order so canonical output is deterministic (Go map iteration order is otherwise unspecified). A nil or empty map yields an empty map value.

func NewNull

func NewNull() Val

NewNull returns a null scalar value.

func NewNumber

func NewNumber(f float64) Val

NewNumber returns a scalar value of the `float` kind — the IEEE-754 binary64 leaf of the number lattice. (The name is kept for API compatibility; the kind it builds is KindFloat, not the KindNumber supertype, which no concrete value carries.)

func NewScalarKind

func NewScalarKind(k Kind) Val

NewScalarKind returns a scalar-kind (type constraint) value — the equivalent of bare `string`, `number`, `integer`, `float`, `biginteger`, `bigdecimal` or `boolean` in source. Use the exported Kind constants: KindString, KindBoolean, KindNull, and the numeric lattice KindNumber (the supertype, admitting any numeric leaf) with its leaves KindInteger, KindFloat, KindBigInteger and KindBigDecimal.

func NewString

func NewString(s string) Val

NewString returns a string scalar value.

type ValueSpan

type ValueSpan struct {
	Pos   int
	Len   int
	Canon string
	Kind  string
	// Path is where the value sits in the document, for the hover
	// provenance G7 phase 7 appends. Empty for a value with no path
	// (the root, or a value the walk reached through a shared clone).
	Path []string
}

ValueSpan locates a concrete value in source: the byte offset and the byte length of its source text, plus its canon and a short kind label. Containers (maps/lists) are excluded — their source span is not reliably reconstructable from a single position — so spans describe scalars, scalar kinds, references, etc. Used for LSP hover (go/lsp).

type VarVal

type VarVal struct {
	// contains filtered or unexported fields
}

VarVal is a variable reference (e.g. `$name`). Full variable lookup is ported later; for now it resolves only via RefVal special names.

func (*VarVal) Canon

func (vv *VarVal) Canon() string

func (*VarVal) Dc

func (b *VarVal) Dc() int

func (*VarVal) Gen

func (vv *VarVal) Gen(ctx *Ctx) (any, error)

func (*VarVal) Nil

func (b *VarVal) Nil() bool

func (*VarVal) Unify

func (vv *VarVal) Unify(peer Val, ctx *Ctx) Val

type VetFinding

type VetFinding struct {
	Actual   *string `json:"actual,omitempty"`
	Class    string  `json:"class"`
	Code     string  `json:"code"`
	Expected *string `json:"expected,omitempty"`
	// THE REPAIR, not just the diagnosis. Message is one line by design
	// -- it is the headline, and the frames under it are for a human at
	// a terminal -- but for several codes the part that says what to DO
	// about the failure lived only in those frames, so a machine reader
	// (an agent, a CI annotation, an editor) got the complaint and none
	// of the cure. `0d` is the clearest case: the engine refuses a
	// lossy integer literal and the hint names the exact-decimal escape
	// that fixes it. Populated from the shared hints table (go/hints.go,
	// mirroring ts/src/hints.ts) whenever the code has one; absent when
	// it does not (the report-layer compat_* codes, notably, carry no
	// hint text).
	//
	// Excluded from spec goldens for the same reason Message is: it is
	// prose, it is long, and the two ports hold it to the byte through
	// the message tests instead of through every vet row.
	Hint *string `json:"hint,omitempty"`

	Message  string    `json:"message"`
	Note     *string   `json:"note,omitempty"`
	Path     string    `json:"path"`
	Severity string    `json:"severity"`
	Sites    []VetSite `json:"sites"`
}

VetFinding is one thing that does not hold. The optional fields are POINTERS so an absent one is omitted and a present-but-empty one is written: `omitempty` on a plain string cannot tell those apart, and the canonical emitter drops only what is undefined.

type VetOptions

type VetOptions struct {
	At      string // validate against this path of the schema
	Closed  bool   // close() the anchor for this run
	Partial bool   // residue is not a failure
	// MaxErrors caps the finding list; 0 (and anything below it) means
	// the default of 20. The canonical engine can tell an EXPLICIT zero
	// from an absent option and would report nothing for it; a Go zero
	// value cannot, and a cap of zero is not a thing to ask for -- the
	// command line refuses it too (`--max-errors 0` is a usage error in
	// both ports).
	MaxErrors int
	SchemaURL string // provenance label for schema sites
	DataURL   string // provenance label for data sites

	// SchemaPath and DataPath are where each document CAME FROM, used
	// to resolve its relative `@"file"` loads -- the FILE path, as the
	// canonical port's `{path}` option takes it, not the directory
	// (this side does the Dir() itself). Vet takes two documents from
	// its caller rather than from the filesystem, so it cannot know
	// this: without it a modular schema resolved its includes against
	// the process working directory, which fails outside that
	// directory and, worse, silently reads a same-named file that
	// happens to sit there. The two documents get their OWN bases,
	// because they need not live in the same place.
	// The include capability both documents evaluate under (G5,
	// docs/trust.md). Nil means today's default.
	Trust *TrustOptions

	SchemaPath string
	DataPath   string
}

VetOptions are the run's knobs. A zero value is the default run: the whole schema as the anchor, open, strict about residue, capped at 20 findings, with the documents labelled "schema" and "data".

type VetReport

type VetReport struct {
	Findings  []VetFinding `json:"findings"`
	Truncated bool         `json:"truncated"`
	Verdict   string       `json:"verdict"`
}

VetReport is the whole answer: one verdict, and the findings behind it (capped, with truncation declared rather than silent).

func Vet

func Vet(schemaSrc, dataSrc string, opts *VetOptions) VetReport

Vet validates dataSrc against schemaSrc.

Never fails for findings: a contradiction in the data is DATA, and the caller gets a report. An unusable schema is a VERDICT (`error`) rather than an error return for the same reason — "the schema is broken" is a fact the agent loop needs to branch on, not an exceptional condition — which leaves nothing for an error return to carry, so there is none.

A package-level function rather than a method, mirroring the canonical export: vet takes its two documents from the caller, not from the filesystem, so an Aontu's base directory has nothing to say about them.

type VetSite

type VetSite struct {
	Col int `json:"col"`
	// File is ALWAYS present, and empty when the value belongs to
	// neither document -- one unification minted, rather than one
	// either document wrote. A consumer reads `file` without a presence
	// check; the canonical port coerces the same way.
	File string `json:"file"`
	// Len is the extent in UTF-16 code units, or -1 when unknown -- the
	// same "unknown" Row and Col already use.
	//
	// THIS IS WHAT MAKES A FINDING REPAIRABLE. Value is the CANON, not
	// the source text: `port: 0x1F` reports canon `31` at column 7, so a
	// consumer replacing (col, len(value)) writes `port: 5x1F` and
	// corrupts the document. With Len the span is (col, 4) and the
	// replacement is exact.
	//
	// NEVER GUESSED. Where the span is unknown this is -1 and a consumer
	// must not edit -- unlike the LSP, which falls back to canon because
	// a wonky highlight is cosmetic while a wrong edit is a lost file
	// (Problem.Len, go/check.go). See ts/src/site.ts for what the extent
	// covers, and note the LEXICOGRAPHIC field order this sits in.
	Len  int    `json:"len"`
	Role string `json:"role"`
	Row  int    `json:"row"`
	// Src is the SOURCE TEXT the span covers, empty when unknown.
	//
	// This is what makes the span SELF-VERIFYING, and it is not the same
	// as Value. For a scalar the two differ by normalisation -- `0x1F`
	// has Src `0x1F` and Value (canon) `31`. For a COMPOUND the span
	// names the opening token only, exactly as Row and Col always have:
	// a constraint `min(1)` reports Src `min`, and a reference `$.b`
	// reports Src `$`.
	//
	// So a consumer must read the document at (Row, Col, Len), compare
	// it to Src, and REFUSE when they differ -- and, seeing `min` where
	// it expected `min(1)`, refuse rather than replace the name and
	// orphan the arguments. Without this field that mistake is
	// undetectable.
	Src   string `json:"src"`
	Value string `json:"value"`
}

VetSite locates one side of a finding. The JSON field order is LEXICOGRAPHIC because the canonical emitter sorts object keys (exactJSON, ts/src/exactjson.ts) while Go's encoder writes struct fields in declaration order: the two agree only if the declaration is already sorted.

type WhyConjunct

type WhyConjunct struct {
	Canon string  `json:"canon"`
	Role  string  `json:"role"`
	Site  WhySite `json:"site"`
	// Src is the SOURCE TEXT this contribution was written as.
	//
	// Canon is the value; Src is the spelling. They are not the same
	// thing, and the difference is the whole reason this record exists:
	// `port: 0x1F` contributes canon `31` from source `0x1F`, so a
	// reader told only the canon cannot find, verify or replace what was
	// actually written. Empty when the contribution occupies no source
	// -- a value unification minted rather than a document wrote.
	//
	// LEXICOGRAPHIC field order, as everywhere the two emitters must
	// agree byte for byte: src sorts after site.
	Src string `json:"src"`
}

type WhyRecord

type WhyRecord struct {
	Conjuncts []WhyConjunct `json:"conjuncts"`
	Path      string        `json:"path"`
	Value     string        `json:"value"`
}

type WhyReport

type WhyReport struct {
	Findings []VetFinding `json:"findings"`
	OK       bool         `json:"ok"`
	Record   *WhyRecord   `json:"record,omitempty"`
}

WhyReport is the whole answer: the record, or G2-shaped findings.

type WhySite

type WhySite struct {
	Col  int    `json:"col"`
	File string `json:"file"`
	// Len is the extent in UTF-16 code units, or -1 when unknown. The
	// same field, and the same meaning, as VetSite.Len (go/vet.go).
	Len int `json:"len"`
	Row int `json:"row"`
}

WhySite is the G2 site object, minus its data/schema role: a contribution's role is its own, and a `why` run has one document.

Directories

Path Synopsis
cmd
aontu command
Command aontu is the command-line interface for the Aontu unifier.
Command aontu is the command-line interface for the Aontu unifier.
aontu-lsp command
Command aontu-lsp is the Aontu Language Server.
Command aontu-lsp is the Aontu Language Server.
Package lsp is the Aontu Language Server library.
Package lsp is the Aontu Language Server library.
scripts
covmerge command
Command covmerge unions two or more Go text coverage profiles (mode: set) into one, so the unit-test profile and the GOCOVERDIR integration-run profile of the command binaries can be reported as a single figure.
Command covmerge unions two or more Go text coverage profiles (mode: set) into one, so the unit-test profile and the GOCOVERDIR integration-run profile of the command binaries can be reported as a single figure.

Jump to

Keyboard shortcuts

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