Assay-Runner Runtime Drift Projection v0.2 Contract

May 26, 2026 ยท View on GitHub

Internal projection contract slice. This page defines the current assay.runner.runtime_drift.v0.2 report shape used by the cross-runtime drift experiment. It also links the retained historical v0 schema for older committed reports. It is not a Runner archive artifact, not a policy verdict, and not a released product surface.

Runtime drift v0 answers one narrow question:

Given two Runner measured-run archives and declared projection rules,
what observed runtime surface differs, and which differences remain
after those declared projections are applied?

The report is descriptive. It reads Runner archive evidence, records raw set differences by dimension, then adds projection sub-objects for explicitly declared path and network mappings. It must not rewrite the source archives, infer semantic workload equivalence, or decide whether the drift is acceptable.

Inputs

The report consumes two Runner archives, usually one per runtime arm. Each archive may be provided as an extracted directory or .tar.gz.

SourceUsed For
manifest.jsonRun id and manifest digest anchor
capability-surface.jsonFilesystem paths, network endpoints, process execs, MCP tool surface
observation-health.jsonHealth gates copied into report provenance
correlation-report.jsonCorrelation status copied into report provenance
layers/sdk.ndjsonSDK tool events and invocation order
layers/kernel.ndjsonOpen-operation rows when kernel metadata is present

The comparator may also receive explicit projection configuration:

ConfigurationEffect
--path-alias RAW=PROJECTEDProjects an observed raw path to a declared logical path
--network-alias ENDPOINT=CLASSProjects an exact observed endpoint to a declared network class
--network-cidr CIDR=CLASSProjects an IP endpoint by CIDR to a declared network class

Projection configuration is declared input. The report must not infer it from path shapes, package names, hostnames, or provider labels.

Schema

Schema string:

assay.runner.runtime_drift.v0.2

Machine-readable schema:

schema/runtime-drift-v0.2.schema.json

Historical v0 reports remain documented by schema/runtime-drift-v0.schema.json. v0.2 is a compatible tightening of the projection sub-shape: it keeps the same report semantics but locks projection.unmatched_summary as a required {a, b} object with per-arm side, count, samples, and sample_limit fields.

The literal dotted minor suffix (v0.2) is intentional for this experimental projection contract. Consumers that parse Runner schema strings should treat the suffix as semver-like (major.minor) rather than matching only v(\d+). Other Runner archive artifacts still use bare v0 schema strings until they need a minor compatibility tightening of their own.

The current comparator emits v0.2 only. Historical v0 reports remain readable through the retained v0 schema and committed report files, but new re-renders from this comparator are not intended to reproduce v0 wire output.

Top-level fields:

FieldTypeRequiredSemantics
schemastringyesMust equal assay.runner.runtime_drift.v0.2 for new reports
archive_aobjectyesCompact reference to the first input archive
archive_bobjectyesCompact reference to the second input archive
taxonomyobjectyesRuntime/noise taxonomy vocabulary block
provenanceobjectyesReport-generation and input-archive provenance
rowsarrayyesPer-dimension drift rows
summaryobjectyesClassification counts across rows

Archive References

archive_a.path and archive_b.path are informational location anchors, not identity fields. For committed re-renders they are normally repo-root-relative paths so a reviewer can follow them in the repository. For fresh workflow captures they may be absolute paths on the capture host. Archive identity comes from manifest_digest.

Provenance Anchors

provenance.assay_commit is the capture anchor: the Assay revision that produced the input archives. provenance.render_metadata is the render anchor: the comparator revision and render context that produced the drift report from those archives. These can intentionally differ when old archives are re-rendered after a projection or schema change.

Commit anchors are bare Git object identifiers: either full SHAs or unambiguous 7-64 character lowercase hexadecimal abbreviations. The upper bound deliberately allows both SHA-1-era 40-character object IDs and SHA-256-era 64-character object IDs. render_metadata.rendered_at uses RFC3339 date-time syntax such as 2026-05-25T19:00:35Z.

This schema uses two SHA conventions:

  • Git commit anchors use bare lowercase hex because Git itself resolves full or abbreviated object IDs.
  • Content-addressed evidence digests use an algorithm prefix such as sha256:<hex> so future multi-algorithm digest handling stays explicit.

Runtime drift v0 uses a required-but-nullable convention for provenance: schema-critical keys are present even when the caller does not know the value yet. A present null means "unknown/not supplied"; absence means the report does not satisfy the v0 shape.

Contract Principles

  1. Raw evidence is preserved. only_in_a, only_in_b, and in_both in each row are raw observed values from the source archives.
  2. Projection is additive. A row may carry a projection object, but projection output never replaces the raw row values.
  3. Projection rules are named. Applied projections carry rules, compact mappings, confidence, relation, and taxonomy class information.
  4. Unknowns stay visible. Values without a declared rule remain raw or unknown; they are not collapsed into a convenient class.
  5. Health is copied, not reinterpreted. Observation health and correlation status appear in provenance; runtime drift v0 does not recalculate capture health.
  6. Provenance anchors the comparison. Input manifest digests, Runner schema versions, kernel metadata, eBPF object digest, workflow URL, capture commit, and render metadata are report metadata when available.
  7. Policy acceptability is out of scope. A runtime-induced row is evidence shape, not a policy failure.

Dimensions

v0 defines these rows:

DimensionSource
filesystem_paths_touchedcapability_surface.filesystem_paths
kernel_file_operationslayers/kernel.ndjson open metadata, when present
network_endpointscapability_surface.network_endpoints
process_execscapability_surface.process_execs
sdk_tool_eventslayers/sdk.ndjson tool events
mcp_tool_surfacecapability_surface.mcp_tools
tool_invocation_orderlayers/sdk.ndjson tool_call_started sequence

The classification labels are:

LabelMeaning
task-inducedThe dimension overlaps completely between arms
provider-inducedNon-shared values match a provider-host whitelist
runtime-inducedNon-shared values are observed and not provider-attributed
inconclusiveOne side lacks data for the dimension

Classification is intentionally conservative. It describes observed surface shape; it is not a root-cause proof.

Projection Sub-Objects

Rows that support projection carry a projection object.

Projection SchemaApplies To
assay.runner.path_projection.v0Filesystem paths and operation-aware file values such as read:/path
assay.runner.network_projection.v0Network endpoints and CIDR-matched IP endpoints
assay.runner.projection_not_applied.v0Sentinel for dimensions with no v0 projector

Each projection object references:

  • assay.runner.runtime_noise_taxonomy.v0 for class vocabulary;
  • declared rule names for applied mappings;
  • per-value claim_level such as raw_observed, projected_equivalent, or inconclusive;
  • machine-readable non_claims.

Rows without an applicable projection carry the assay.runner.projection_not_applied.v0 sentinel with status=not_applied so downstream consumers do not confuse absence of projection with a parser failure.

The v0.2 projection convention keeps mappings compact: it lists declared projected mappings, not every unmatched raw value. Unmatched raw values are summarized in unmatched_summary with per-arm counts and small samples. The full raw values remain in each row's only_in_a, only_in_b, and in_both sets.

Operation-aware path values use the shape op:/absolute/path before projection, for example read:/tmp/run/workdir/input.txt. The projection applies only to the absolute path suffix and preserves the operation prefix. Other colon-separated strings, such as URI-like values or relative op:path values, are treated as one raw value.

Non-Claims

Runtime drift v0 inherits the projection non-claims from the projection roadmap:

CodeMeaning
projection_no_raw_evidence_rewriteRaw observed evidence is preserved and remains source of truth
projection_no_semantic_workload_equivalenceMatching projected values do not prove the workloads are semantically identical
projection_no_policy_acceptability_verdictThe report does not decide whether drift is acceptable
projection_unknowns_preservedUnknown or unclassified values are not collapsed into a class
projection_no_heuristic_noise_taxonomyThe report does not apply undeclared heuristic taxonomy rules

Provenance carries its own non-claims for metadata fields, including that metadata is not a policy verdict and unknowns are preserved.

Relationship To Other Runner Contracts

  • artifacts-v0.md remains the primary archive evidence contract. Runtime drift v0 reads those artifacts; it does not replace them.
  • cross-runtime-diff-v0.md remains the narrow Phase 2C capability-surface projection with work-dir prefix canonicalization only.
  • projection-roadmap.md tracks follow-up projection layers and kernel event expansion.