Skip to content

Signal Schema v4 (0.4.0) ​

Schema v4 is Ayni's current serialized run-artifact contract. It adds explicit execution provenance to the v3 envelope and closes the finding wire: every non-empty offender is an identified, directly verifiable finding. Current Ayni produces, parses, and compares only 0.4.0; it does not convert historical artifacts.

The implementation authorities are core/src/signal.rs for the envelope, completion, rows, and validation; core/src/finding.rs for finding identity and verification metadata; and core/src/comparison.rs for explicit comparison. For the stable six-signal vocabulary, see the signal index.

Serialized envelope ​

RunArtifact serializes one flat top-level object. Every field below is required unless its rule says otherwise.

FieldJSON typeContract
schema_versionstringExactly 0.4.0.
generated_atstringCaller-supplied generation timestamp.
ayni_versionstringAyni version that produced the artifact.
invocationobjectcommand, ordered languages, and optional scope.
outputobjectformat and destination strings.
config_pathstringPolicy path used by the invocation.
repository_rootstringRepository root used by the invocation.
execution_modemanaged | hostExecution path. Host and managed evidence are not comparable.
contract_digeststringLowercase sha256:<64 hex> digest of the exact policy bytes.
environment_lock_fingerprintstringRequired for managed evidence and forbidden for host evidence.
source_fingerprintstringLowercase SHA-256 fingerprint of the measured workspace. In a Git checkout, tracked and unignored untracked entries are fingerprinted while ignored output is omitted; managed evidence also omits exact prepared outputs. Non-Git host execution fingerprints the host-visible workspace.
tool_versionsarraySorted, unique { tool, version } records. Managed evidence requires at least one locked version; host evidence may be empty.
completionobjectReconciled target and row-set completion evidence.
aggregateobjectCanonical summary derived from completion and rows.
applied_thresholdsarrayCanonical row-order projection of applied budgets.
rowsarraySignal rows described below.
offender_summariesarrayCanonical row-order offender summaries; rows without offenders are omitted.
failure_summariesarrayCanonical command-failure summaries; omitted when empty.

Language values are rust, go, node, python, and kotlin. A scope has required workspace_root and optional path, package, and file strings.

Completion ​

completion has these fields:

FieldTypeContract
scoperepository | requestedRepository-wide completion or an explicitly focused request. Requested evidence never establishes repository completion.
statecomplete | incompleteWhether every expected target emitted its full requested row set.
expected_targetsu64Configured targets after valid command selection.
detected_targetsu64Expected targets detected by their adapters.
completed_targetsu64Targets that emitted every requested row, regardless of pass/fail.
skipped_targetsu64Exactly expected_targets - completed_targets.
issuesarrayOne ordered issue per skipped target.

An issue contains language, configured_root, stage, and message. stage is detection, resolution, selection, scheduling, or collection. Detection issues account exactly for expected-but-undetected targets; all other issues account for detected targets that did not complete. Consequently, issues.length == skipped_targets.

A complete artifact has no skipped targets or issues. An incomplete artifact has at least one of each. Core also requires unique (language, configured root, signal kind) row keys. A complete repository artifact must represent exactly its completed target count, and every represented target must have the same non-empty signal-kind set. These are structural wire guarantees; the in-process policy plan is not reconstructed from an artifact.

Canonical derived views ​

aggregate contains status (pass or fail), total_rows, passing_rows, failing_rows, warning_offenders, and failing_offenders. All counts are u64. Status is pass only when completion is complete, a non-empty expected target set produced rows, and every row passes. An incomplete artifact always aggregates to fail.

Each applied_thresholds entry contains the row's kind, language, scope, and budget, in row order.

Each non-empty offender_summaries entry contains kind, language, scope, total, warning_count, and failing_count, in row order. Test offenders are failures; other kinds use their level.

Each failure_summaries entry contains kind, language, scope, category, classification, command, cwd, optional exit_code, and message, once for every row result with a command failure.

On input, core derives all four views again and rejects any mismatch.

Rows and payloads ​

Every row contains kind, language, scope, pass, result, budget, and offenders. result and budget are internally tagged with kind; offenders is { "kind": <kind>, "items": [...] }. All four kind tags must match. Schema v4 has no implicit prior-artifact delta.

Optional fields below are omitted when null.

test ​

ObjectFields
resulttotal_tests, passed, failed (u64); optional duration_ms; runner; optional command failure
budgetEmpty object; tests have no numeric budget.
finding payloadoptional file, optional line, message, optional test_name

Successful execution that discovers zero tests is a failing row with an actionable finding, not a command failure.

coverage ​

ObjectFields
resultoptional percent, line_percent, branch_percent (finite 0–100); engine; status; optional command failure
budgetOptional numeric line_percent_warn, line_percent_fail, branch_percent_warn, and branch_percent_fail; no other fields.
finding payloadfile, optional line, value, level (warn or fail)

Headline selection prefers percent, then line_percent, then branch_percent.

size ​

ObjectFields
resultmax_lines, total_files, warn_count, fail_count (u64); optional command failure
budgetrules array of { glob, warn, fail }; empty failure-path budgets and the focused legacy warn/fail pair are accepted; no other fields.
finding payloadfile, value, warn, fail, level

complexity ​

ObjectFields
resultengine, method, measured_functions, finite non-negative max_fn_cyclomatic, optional finite non-negative max_fn_cognitive, warn_count, fail_count, optional command failure
budgetOptional fn_cyclomatic and fn_cognitive, each { warn, fail }; no other fields.
finding payloadfile, line, function, cyclomatic, optional cognitive, level

deps ​

ObjectFields
resultcrate_count, edge_count, violation_count (u64); optional command failure
budgetOptional forbidden map from source patterns to destination-pattern arrays; no other fields.
finding payloadfrom, to, rule, level

mutation ​

ObjectFields
resultengine, killed, survived, timeout, optional finite 0–100 score, optional command failure
budgetOptional boolean enabled; no other fields.
finding payloadoptional file, optional line, mutation_kind, message, level

A command failure contains category, classification, command, cwd, optional exit_code, and message.

The row's pass value is validated against its typed result and fail-level findings. Passing rows cannot carry a command failure or fail-level finding. Test counts must reconcile, percentages and other floating metrics must be finite and in their documented ranges, and mutation counts must describe real parsed measurement.

Findings and verification commands ​

Every non-empty offenders.items entry is a flat finding. It combines the signal-specific payload above with:

json
{
  "id": "ayni:finding:v1:sha256:<64 lowercase hex characters>",
  "verification": {
    "command": "ayni verify size --config './.ayni.toml' --language rust --root '.' --file 'src/lib.rs'"
  }
}

id and verification are siblings of the payload fields. A serialized finding must contain exactly a rendered command; adapter-internal selector targets never appear on the wire. Raw historical offenders, partially materialized findings, duplicate IDs within a row, short finding vectors, mismatched finding kinds, and finding payloads that differ from their row's canonical offenders are rejected during serialization and deserialization.

The identity input is a versioned, length-prefixed canonical representation of language, signal kind, and stable semantic payload fields:

  • test: relative file, line, and test name; message only when all three are absent;
  • coverage: relative file and optional line;
  • size: relative file;
  • complexity: relative file, line, and function;
  • deps: source, destination, and rule; and
  • mutation: relative file, line, mutation kind, and message.

Paths are lexical, slash-normalized, and relative to the checkout root. Severity, thresholds, measurements, output order, checkout location, timestamps, and verification commands do not affect identity. Exact semantic duplicates are removed before IDs are assigned. IDs use the complete SHA-256 digest and are never truncated.

The CLI renders the narrowest adapter-supported verification target with the artifact's config, explicit language, and exact normalized root. Arguments are POSIX-shell single quoted, including safe handling of embedded single quotes. Consumers should copy the command exactly rather than synthesize selectors.

Explicit artifact comparison ​

ayni results compare --baseline <artifact> --candidate <artifact> [--output human|json] reads exactly two named files and writes no history or repository state. Both inputs must be valid, complete schema-v4 managed artifacts. Host artifacts are rejected because their toolchain is not locked.

Before row matching, core requires identical execution_mode, ayni_version, contract_digest, environment_lock_fingerprint, and tool_versions. source_fingerprint may differ because comparison exists to evaluate source changes.

Rows match by kind, language, and optional relative scope.path, scope.package, and scope.file. Workspace roots, repository roots, artifact locations, timestamps, invocation output mode, and Git state do not participate.

The deterministic comparison document uses comparison schema 0.1.0 and contains artifact_schema_version plus sorted matched, changed, added, and removed collections. A matched row changes only when its pass value, typed numeric result metrics, or finding-ID set changes. Presentation metadata, tool labels inside results, finding order, and verification command text do not create a row change after provenance compatibility succeeds.

Compatibility and failure behavior ​

Consumers must select this contract only for schema_version: "0.4.0". Current core rejects v1, v2, and v3 artifacts, missing provenance or completion, legacy offenders, invalid row/finding alignment, and non-canonical summaries. There is no fallback or migration payload.

Terminal and Markdown reports display completion separately from row pass counts. Completion issues account for targets that did not finish; a typed command-failure row can still count as completed when the full requested row set was emitted.