Skip to Content
Numinance
Configuration

Validation and errors

What the open numi validate checks, what it deliberately leaves to the engine, the exit codes, and the real error messages you will see.

View as .mdUpdated
Available in public spec

The schemas, the loader and the open numi validate build are in the public numinance-spec. Profile resolution, floor evaluation and the commands that run a change are designed and are not in the open build.

The open validator proves that your YAML has the shape of a Numinance kind. It does not prove that your configuration is allowed, complete or safe. A CI that cannot tell the difference is a CI that lies, so the open build is built to make the difference impossible to miss.

Two validation modes

ModeCommandWhat it doesExit on a clean pass
Example validatornumi validate --files PATHChecks each YAML document against the strict schema of its kind, then the loader checks. No resolver, no floors.0
Repository validatornumi validate [path]Schema-checks every kind document under .numinance/ in the org, repository and component trees (working tree, uncommitted edits included), then stops.7

A repository run that exits 7 has not failed. Exit 7 in the open build has exactly one meaning: the schema pass succeeded and profile resolution is not available. The final line says so:

numi validate: profile resolution needs the Numinance engine build

Treat exit 7 in CI as a distinct state, not as success. If you wire the open build into a pipeline, assert the exit code you expect, and do not map 7 to green.

What is open schema-only, and what is engine-side

Open numi build (checks the shape)Engine-side resolution (designed, not in the open build)
Valid YAML, one document, size and depth limitsLoading from a pinned commit, not the working tree
Strict kind schema: no unknown fields except under extensionsMerging org, repository and component scope into one resolved profile
apiVersion, kind, metadata, spec present; scope not unspecifiedChecking floors: autonomy, residency, approvals, packs
Enums by full proto name; durations in 7200s form; digests as sha256: plus 64 hexResolving names (playbooks, toolchains, verifiers, providers) to real objects and lockfile entries
Org-only kinds and floor fields refused below the org scopeDeciding whether a document has authority (protected path or signed policy bundle)
Per-kind rules such as read_only true, ttl above zero, sorted EvalSet casesPrinting the profile digest and per-field provenance

When an authoritative engine build resolves a repository it reads a pinned commit and prints a digest with the provenance of each field. The open build cannot, and does not pretend to.

Exit codes

The stable table in the spec CLI is shared by all numi commands:

CodeMeaningSeen in the open validator
0OKClean --files pass
1Internal, and any unknown kindA panic or an error of no kind exits 1, never 0
2Usage: bad flags or arguments, or a non-empty --rev in the open buildNo path, more than one path, --files combined with --rev, --org or --component, a single file not named *.yaml or *.yml
3Invalid: schema errors, loader errorsAny document that fails
4Not found, including no kind documents foundA missing path, or a directory with no YAML
5ConflictNot produced by validate in my runs. numi init returns 5 when .numinance already has files and no --force.
6PolicyDeniedNot produced by the open validator
7UnavailableRepository mode after the schema pass
8TimeoutNot exercised

A cancel (an interrupt) exits 1, never 7. For the CLI as a whole, see commands and exit codes and numi validate.

The loader's four stages

Each document runs through four stages in order and stops at the first failure. Errors name a path or a field and never quote a value from your file, so a rejected document cannot leak its contents into logs.

StageRefuses
SizeA document over 128 KiB
YAMLMore than one document, a root that is not a mapping, anchors, aliases, merge keys, explicit tags, non-string keys, duplicate keys, nesting beyond 64 levels, more than 16384 values
SchemaA missing or unknown kind; a produced kind (ContextBundle) loaded as configuration; an unknown field; a wrong type or enum; a duration that is not in proto JSON form
Loader checksapiVersion or kind not as expected; missing metadata or spec; an empty metadata.name; a zero enum anywhere; required lists left empty; non-reverse-DNS extensions keys; then the per-kind rules (org-only, FORBID fields, unique keys, value shapes)

Anchors and aliases are refused on purpose. They are the YAML feature that makes a small file expand into a large one, and a config format that hides expansion from reviewers is a poor place for policy.

Working examples

Success on the shipped examples. This is the first command to run after installing from a clone; see install and first configuration.

From a numinance-spec checkout
go run ./cli/numi validate --files schemas/examples/SDLCProfile

The machine-readable form is a single JSON object per run, with a per-document status. For a failing document it carries the same message in an error field.

$ numi validate --files schemas/examples/SDLCProfile
revision: "files"
ok       file "org-baseline.yaml" SDLCProfile "org-baseline"
ok       file "payments-api.yaml" SDLCProfile "payments-api"
(exit 0)

$ numi validate --files --json ok.yaml
{"status":"ok","revision":"files","documents":[{"scope":"file","path":"ok.yaml","kind":"BudgetPolicy","name":"x","status":"ok"}]}
(exit 0)

$ numi validate --files --json bad/doc.yaml      # KnowledgeConnection with read_only: false
{"status":"invalid","revision":"files","documents":[{"scope":"file","path":"doc.yaml","status":"invalid","error":"kind: invalid: a value of numinance.kinds.v1.KnowledgeConnectionSpec.read_only fails its check"}]}
(exit 3)

$ numi validate .                                # a repository with one LanguageToolchain under .numinance/policy/
revision: "working tree (uncommitted changes included)"
ok       repo ".numinance/policy/go-1.27.yaml" LanguageToolchain "go-1.27"
numi validate: profile resolution needs the Numinance engine build
(exit 7)

$ numi validate --files missing-dir
numi validate: path not found
(exit 4)

$ numi validate --files empty-dir
revision: "files"
numi validate: no kind documents found
(exit 4)

$ numi validate --files
numi validate: --files needs exactly one path
usage: numi validate [--rev REV] [--org DIR] [--component ROOT] [--json] [path]
       numi validate --files [--json] path
  ...
(exit 2)
✓ verifiedOpen numi build run against edited copies and example files; the quoted paths are scratch copies· numinance-spec @ 3c74d59 · 2026-11-09

(The usage text above is shortened at the dots; the tool prints the full flag list.)

Common mistakes

Every message below was produced by editing a copy of a real example or a minimal document and running the open build. All exit 3 unless noted.

MistakeMessage
A misspelt or unknown fieldkind: does not match the kind schema: schema: value does not match (violations: 1): \"/spec/verifier\": additionalProperties
An enum written short (HIGH) or with an invalid member... \"/spec/rules/0/severity\": enum
A missing required field the schema can see... \"/spec/counsel_status\": required
A required list left emptykind: invalid: numinance.kinds.v1.LanguageToolchainSpec.verifiers is empty
A duration as 4h or 2hkind: does not match the kind schema: a value is not in protobuf JSON form
An org-only kind at another scopekind: invalid: ControlPack is org-scoped only
A floor set below the orgkind: invalid: numinance.kinds.v1.ResidencyPolicySpec.floors is set only at the org scope
metadata.scope left unspecifiedkind: invalid: numinance.kinds.v1.Metadata.scope is SCOPE_UNSPECIFIED
Wrong apiVersion (here numinance.dev/v2)kind: invalid: apiVersion is not numinance.dev/v1
No speckind: invalid: spec is missing
A kind name that does not exist (Widget)kind: unknown kind
A YAML anchorkind: unsupported YAML: line 4: anchor
A duplicated keykind: duplicate key: line 6
A produced kind in the configuration treekind: produced kind: ContextBundle is not configuration
An alpha kind in repository modekind: alpha kind is not enabled: EvalSet
A non-reverse-DNS extensions keykind: invalid: a key of numinance.kinds.v1.IndexerPlugin.extensions is not reverse-DNS
A single file not named *.yaml or *.yml (exit 2)numi validate: a file must be named *.yaml or *.yml
A backup such as ok.yaml.bak inside a directorynumi validate: ok.yaml.bak: a file name mentioning .yaml or .yml must end in lowercase .yaml or .yml
--files together with --rev (exit 2)numi validate: --files excludes --rev, --org and --component

The file-name rule is strict by design: in --files mode, a stray config.yaml.bak or config.YAML is an error, not an ignored file, because an ignored policy file is how a reviewed rule quietly stops being checked. Other names, such as README.md~, are ignored.

What a pass does not prove

  • That the file is where policy will look for it. Authority comes from a protected path or a signed policy bundle. A document that decodes has no authority by decoding.
  • That a name you wrote exists. provider, verifier, playbook and knowledge values are references, resolved later against declared providers and the lockfile.
  • That a floor holds. Cross-document checks such as a pack that tightens an org floor are resolution, not validation.
  • That an extension is installed, signed or allowed. See registry and trust.
  • That your change is safe. Verification, policy and evidence do that at run time, in the designed runtime.

Troubleshooting

Next steps

On this page