schema

package
v0.4.0 Latest Latest
Warning

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

Go to latest
Published: Aug 22, 2026 License: MIT Imports: 14 Imported by: 0

Documentation

Overview

Package schema reads the GMP protocol schema DSL and compares the model it declares against the hand-written structs in commands/. Unlike internal/gmptest's runtime oracle, it never looks at a document, so it finds fields no fixture happens to exercise.

The input is vendor/XML/commands/command_*.xml, which is gitignored and AGPL-licensed; only element names, cardinalities and type names cross the boundary, and only into a report. See docs/review-2026-08.md, T-9.

Index

Constants

View Source
const (
	CatMissing     = "MISSING"       // the schema declares it, no Go field carries it
	CatExtra       = "EXTRA"         // a Go field with nothing behind it in the schema
	CatCardinality = "CARDINALITY"   // repeated-vs-slice, or an optional whose absence Go cannot express
	CatKind        = "KIND"          // an attribute modelled as an element, or the reverse
	CatOmitEmpty   = "OMITEMPTY"     // omitempty where the schema says required, or missing where it says optional
	CatType        = "TYPE"          // the Go type cannot hold the schema's lexical space
	CatDefect      = "SCHEMA-DEFECT" // the schema is wrong; nothing is asked of the Go side
)

Finding categories, in report order.

View Source
const (
	DefectTypeForT      = "type-for-t"     // <pattern><type>x</type></pattern> where <t>x</t> was meant
	DefectDanglingRef   = "dangling-e"     // <e>x</e> with no <ele> defining x
	DefectDuplicateEle  = "duplicate-ele"  // two <ele> definitions of one name in one scope
	DefectDuplicateRef  = "duplicate-ref"  // the same <e>x</e> token referenced twice in one pattern
	DefectEmptyPattern  = "empty-pattern"  // <pattern/>, declaring nothing at all
	DefectNoPattern     = "no-pattern"     // <ele> with neither <pattern> nor <type>
	DefectUndefinedType = "undefined-type" // a type name with no <type> definition
	DefectUnsupportedR  = "unsupported-r"  // <r>, a reference to a response, inside a pattern
	DefectRecursion     = "recursion-cut"  // a shared <element> that reaches itself
)

Defect classes, in the order they appear in the report.

Variables

Categories in the order the report prints them.

Functions

func LoadDroppedPaths

func LoadDroppedPaths(testdataDir string) (map[string]map[string]bool, error)

LoadDroppedPaths reads the per-fixture fidelity reports written by internal/gmptest and returns, per command, the response paths that a real document lost on the way through the Go types.

This package only reads that tree. A MISSING finding whose path appears here was reached twice over, from the schema and from a captured document, by two tools that share no code.

func Resolve

func Resolve(name string) string

Resolve follows the alias table. Unknown names are returned unchanged.

Types

type Card

type Card uint8

Card is how many times an item may appear. The DSL has exactly three cardinalities: there is no "one or more" and no minOccurs/maxOccurs.

const (
	CardRequired Card = iota // <e>x</e>
	CardOptional             // <o><e>x</e></o>, or an <attrib> without <required>1</required>
	CardRepeated             // <any><e>x</e></any>
)

The three cardinalities the DSL can express.

func (Card) String

func (c Card) String() string

type Command

type Command struct {
	Name       string
	File       string
	Request    *Node
	Response   *Node
	Defects    []Defect
	Provenance Provenance
}

Command is one command_*.xml file: the request shape, the response shape, and whatever was wrong with the file on the way through.

func Load

func Load(dir, sourceRevision string) ([]Command, error)

Load parses every command_*.xml in dir, sorted by command name, and stamps each with the provenance of the one extraction that produced them. Stamping also reads dir's sibling GMP.xml.in, so a directory of command files without that document is an error rather than a provenance-less success.

sourceRevision is the upstream gvmd tag or commit, when the caller knows it; pass "" otherwise. Load never infers it.

func LoadFile

func LoadFile(path string) ([]Command, error)

LoadFile parses one schema file. A file normally holds one <command>, but the shape allows more and nothing here assumes otherwise.

func LoadServed

func LoadServed(data []byte, sourceRevision string) ([]Command, error)

LoadServed extracts commands from a live gvmd's <help format="XML" type=""/> response (T-16b), rather than a vendored file (Load).

data must be the full raw response envelope exactly as read off the wire, e.g. via gmp.Connection.RawXML — never a HelpResponse.Text decode, which only captures bare chardata and silently loses the nested <protocol> document entirely.

sourceRevision identifies the server that served data — in practice its resolved container image digest (internal/dockerstack), since GMP exposes no build version of its own.

func Parse

func Parse(data []byte, name string) ([]Command, error)

Parse reads a <protocol> document. name is used only in reports.

type Comparer

type Comparer struct {
	// Dropped is per-command the set of paths the fidelity corpus saw a real
	// document lose. Optional: an empty map just means no cross-references.
	Dropped map[string]map[string]bool

	// OnOptionalScalar, if set, is called once per matched leaf where the
	// schema declares CardOptional and both sides are scalar (no children on
	// either side). Used by the optional-scalar inventory to record every
	// such field without a second tree walk.
	OnOptionalScalar func(cmd, side string, s *Node, g *GoNode, path string)
}

Comparer holds the corroborating evidence a diff is run against.

func (*Comparer) Compare

func (c *Comparer) Compare(cmd Command, req, resp GoRoot) Result

Compare diffs one command's schema shape against its Go types. Either root may be zero, which is itself reported.

type Defect

type Defect struct {
	Class  string
	Path   string
	Detail string
}

Defect is a place where the schema does not say what it means. These are upstream bugs, not transcription errors, and the report keeps them in their own category so the two are never confused.

type ExtractionMethod

type ExtractionMethod string

ExtractionMethod is how a schema document reached the parser.

const (
	// ExtractionFile reads a vendored file from disk — Load's method.
	ExtractionFile ExtractionMethod = "file"
	// ExtractionServed reads a document served by a live gvmd — LoadServed's
	// method, since T-16b the primary route for refreshing testdata/schema.
	ExtractionServed ExtractionMethod = "served"
)

type Finding

type Finding struct {
	Command  string
	Side     string // "request" or "response"
	Category string
	Path     string
	Detail   string

	// Confirmed marks a finding the fidelity corpus independently reached:
	// the same path is DROPPED when a real document round-trips. Two oracles
	// built on different evidence agreeing is the strongest signal here.
	Confirmed bool

	// Suppressed findings are counted and explained but not treated as struct
	// bugs — see suppressRequestOverConstraint.
	Suppressed bool
	Reason     string
}

Finding is one disagreement between the schema and the structs.

type GoNode

type GoNode struct {
	Name      string // the XML name, not the Go name
	GoName    string
	Kind      Kind
	Card      Card
	Pointer   bool
	Slice     bool
	OmitEmpty bool
	GoType    string
	Synthetic bool // an `a>b` wrapper: no Go field of its own
	Children  []*GoNode

	// Chardata is set when the struct captures the element's text through a
	// `,chardata` field, which means the element is a leaf carrying a value
	// even though it is modelled as a struct.
	Chardata bool
	// CatchAll is set when the struct has a `,any` field, so unknown children
	// are captured rather than dropped and EXTRA/MISSING mean less.
	CatchAll bool

	// OverrideReason is non-empty when this leaf's struct tag carries a
	// gmpoverride tag: either a real, evidence-backed protocol field the
	// schema's own declared pattern does not produce (see internal/codegen's
	// FieldOverrides), or a struct-typed field whose own chardata was
	// relocated elsewhere (see internal/codegen's FieldSuppressions and
	// checkChardata's missing-chardata case).
	OverrideReason string
	// ChardataOverrideReason is OverrideReason's chardata counterpart. A
	// `,chardata` field sets Chardata on its *parent* node rather than
	// creating a child of its own (see addField), so the override reason has
	// to live there too.
	ChardataOverrideReason string
}

GoNode is one Go struct field, or a synthetic wrapper standing in for the intermediate element in an `a>b` tag path.

func (*GoNode) IsScalarGo

func (n *GoNode) IsScalarGo() bool

IsScalarGo reports whether the Go type holds a value rather than a subtree.

func (*GoNode) Path

func (n *GoNode) Path(parent string) string

Path is where the Go node sits under parent, in fidelity-report syntax.

func (*GoNode) ZeroIsMeaningful

func (n *GoNode) ZeroIsMeaningful() bool

ZeroIsMeaningful reports whether the Go zero value of this field is a legal wire value, which is what makes `omitempty` on a non-pointer lossy. A "0" severity and an absent severity are different facts; an empty string and an absent string are, in this protocol, not.

type GoRoot

type GoRoot struct {
	// TypeName is the Go type, for report lines that must be traceable back
	// to a declaration.
	TypeName string
	Root     *GoNode
}

GoRoot is the model of one command's request or response type.

func ModelOf

func ModelOf(v any) GoRoot

ModelOf reflects v, which must be a pointer to a struct with an XMLName field, into the same shape the parser produces for the schema.

type Inventory

type Inventory struct {
	Rows []ScalarRow
}

Inventory is the full corpus of optional scalar leaves, built by wiring Comparer.OnOptionalScalar into a full pass over every adopted command.

func (Inventory) String

func (inv Inventory) String() string

String renders the inventory deterministically: sorted by command, then side, then path, with nothing environment-dependent in the output.

type Kind

type Kind uint8

Kind separates XML attributes from child elements. The DSL is unambiguous about this: <attrib> is an attribute, everything else is an element.

const (
	KindElement Kind = iota
	KindAttribute
)

The two node kinds.

func (Kind) String

func (k Kind) String() string

type Node

type Node struct {
	Name     string
	Kind     Kind
	Card     Card
	InChoice bool // reached through <or>; its cardinality is advisory
	Type     string
	Alts     []string
	Children []*Node

	// Chardata marks mixed content: real children and/or attributes AND bare
	// text of its own. The DSL spells this two ways — bare identifier text
	// next to an <attrib> or <e> (see bareChardata), or an explicit <t>/<type>
	// next to an <e> (e.g. config/nvt_count in command_get_configs.xml) —
	// and either way Type still carries the text's lexical type.
	Chardata bool

	// PatchReason is set only on a node internal/codegen's ApplySchemaPatches
	// spliced in, never by the parser itself, so `omitempty` keeps committed
	// Stage-A snapshots byte-identical. It lets a patched node's evidence
	// follow through to the generated field's gmpoverride tag, so a
	// schema-patched field doesn't surface as an unexplained EXTRA finding.
	PatchReason string `json:",omitempty"`
}

Node is one element or attribute in a command's declared shape.

func (*Node) Path

func (n *Node) Path(parent string) string

Path returns the node's location under parent, in the same syntax the fidelity reports in internal/gmptest use, so findings can be cross-checked against them by string equality.

type Provenance

type Provenance struct {
	Method ExtractionMethod
	// Source identifies the upstream document independently of the local
	// vendor path.
	Source string
	// SourceRevision is the upstream tag or commit, when known; supplied
	// explicitly to Load, never inferred.
	SourceRevision string
	// SourceSHA256 is the hex SHA-256 of the source document's bytes as read.
	// It identifies what the parsed files were split from; it does not attest
	// them, since nothing binds split.py's output back to it — that's
	// ParsedSHA256's job.
	SourceSHA256 string
	// ParsedSHA256 is the hex SHA-256 over the command_*.xml files Load
	// actually read, so an edited or stale split fails drift detection instead
	// of riding along under an unchanged SourceSHA256.
	ParsedSHA256 string
	// DeclaredVersion is the document's own <version> value, verbatim. Under
	// file-based extraction this is GMP.xml.in's literal, unsubstituted
	// "@GMP_VERSION@" CMake template token, not a real version number.
	DeclaredVersion string
	ExtractedAt     time.Time
}

Provenance records the single extraction that produced a batch of Commands. This is schema provenance, not runtime provenance — see docs/review-2026-08.md, T-16a.

type Report

type Report struct {
	SchemaDir string
	Results   []Result
	// Skipped names commands present in the schema with no Go type, and Go
	// types with no schema file. Both are drift, and both belong in the totals.
	SchemaOnly []string
	GoOnly     []string
}

Report renders the conformance report. The report is the deliverable, so it leads with the totals a reviewer needs to judge scale and only then goes per-command.

func (Report) String

func (r Report) String() string

String renders the whole report. Output is deterministic: every list is sorted and nothing carries a timestamp or a path outside the repository.

type Result

type Result struct {
	Command  string
	File     string
	Findings []Finding
	// Compared is false when no Go type exists for the command at all.
	Compared bool
}

Result is one command's comparison.

func (Result) Conformant

func (r Result) Conformant() bool

Conformant reports whether the command has no actionable findings. Schema defects and suppressed findings do not count against it: neither asks for a change to commands/.

type ScalarRow

type ScalarRow struct {
	Command    string
	Side       string // "request" or "response"
	Path       string
	SchemaType string
	Alts       []string // non-empty for <alts>-constrained (enum-like) fields
	GoType     string
	Pointer    bool
	OmitEmpty  bool
}

ScalarRow is one schema-optional scalar leaf: a field with no children on either side, where the schema declares CardOptional. T-24's audit exists to answer, for every such field, whether its legal wire domain includes the Go zero value and, if so, whether the generated type is a pointer.

Jump to

Keyboard shortcuts

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