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
- Variables
- func LoadDroppedPaths(testdataDir string) (map[string]map[string]bool, error)
- func Resolve(name string) string
- type Card
- type Command
- type Comparer
- type Defect
- type ExtractionMethod
- type Finding
- type GoNode
- type GoRoot
- type Inventory
- type Kind
- type Node
- type Provenance
- type Report
- type Result
- type ScalarRow
Constants ¶
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.
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 ¶
var Categories = []string{CatMissing, CatExtra, CatCardinality, CatKind, CatOmitEmpty, CatType, CatDefect}
Categories in the order the report prints them.
Functions ¶
func LoadDroppedPaths ¶
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.
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.
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 ¶
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 ¶
LoadFile parses one schema file. A file normally holds one <command>, but the shape allows more and nothing here assumes otherwise.
func LoadServed ¶
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.
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.
type Defect ¶
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 ¶
IsScalarGo reports whether the Go type holds a value rather than a subtree.
func (*GoNode) ZeroIsMeaningful ¶
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.
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.
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.
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.
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.
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 ¶
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.