Skip to content

Version-1 identities ​

Metewand assigns stable identities to canonical resources and typed domain records. An identity has this canonical lowercase spelling:

text
mw1-<kind>-<64 lowercase hexadecimal SHA-256 digits>

The digest is computed as:

text
SHA-256(UTF-8(kind) || NUL || canonical-representation)

The representation is canonical JSON in Metewand's restricted version-1 domain. It never depends on a Rust serialization layout. Record representations are objects containing a numeric version field with value 1; canonical resources use {"version":1,"value":<resource>}. The version is the identity representation version, not a package version.

metewand-core::identity exposes:

  • identify_record, which returns an IdentifiedRecord<T>;
  • record_id, which hashes a borrowed identity-ready record;
  • canonical_identity_bytes, which exposes the exact compatibility bytes;
  • run_attempt_id, which identifies a reserved slot and retry before its terminal record exists, using the existing attempt representation;
  • identify_canonical, which identifies a typed, validated canonical resource; and
  • typed Display, FromStr, Serialize, and Deserialize implementations for RecordId<T>.

Programmatically constructed records are checked again at the identity boundary. An integer outside the safe JSON range, for example, is rejected instead of receiving an implementation-specific hash.

The read-only repository loader constructs canonical resources before calling this generic identity API. A repository schema resource contains its logical path, canonical document, and the path and canonical document of every repository-local schema reachable through $ref; cycles are deduplicated. A validated problem-contract resource replaces schema paths with those resolved schema identities and binds each reference-case path to a content identity. Source-bundle resources use the deterministic filesystem inventory documented in Source bundles. These resolved resource representations ensure that a transitive schema, fixture, or worker-source change invalidates the definition and logical identities that depend on it.

Kind registry ​

Each Rust marker or record type has one stable kind. Artifact roles remain distinct Rust types but deliberately share the artifact content kind, so identical artifact contents have one content address.

KindRust type or marker
schemaSchemaResource
problem-contractProblemContractResource
source-bundleSourceBundleResource
artifactSourceBundleArtifact, DatasetArtifact, ResultArtifact, MetricsArtifact
environment-definitionEnvironmentDefinitionRecord
worker-definitionWorkerDefinitionRecord
dataset-definitionDatasetDefinitionRecord
problem-definitionProblemDefinitionRecord
implementation-definitionImplementationDefinitionRecord
execution-policyExecutionPolicyRecord
observation-policyObservationPolicyRecord
dataset-configurationDatasetConfigurationRecord
problem-configurationProblemConfigurationRecord
implementation-configurationImplementationConfigurationRecord
dataset-derivationDatasetDerivationRecord
dataset-instanceDatasetInstanceRecord
problem-instanceProblemInstanceRecord
logical-candidateLogicalCandidateRecord
logical-specificationOneShotLogicalSpecificationRecord
logical-observation-slotLogicalObservationSlotRecord
logical-attempt-slotLogicalAttemptSlotRecord
resolved-environmentResolvedEnvironmentRecord
resolved-launchResolvedLaunchRecord
executor-definitionExecutorDefinitionRecord
resolved-workerResolvedWorkerRecord
resolved-specificationResolvedOneShotSpecificationRecord
resolved-observation-slotResolvedObservationSlotRecord
resolved-attempt-slotResolvedAttemptSlotRecord
observationRunObservationRecord
attemptRunAttemptRecord
diagnosticinspection::DiagnosticResource

Parsing an identity through RecordId<T> verifies the kind associated with T; a schema ID therefore cannot be parsed as an environment-definition ID.

Persisted failure diagnostics use the canonical resource value {"code":...,"message":...,"details":...}; missing details are null. Attempt IDs, paths to stored records, and navigation links are excluded. The diagnostic vectors define exact canonical bytes and IDs. This additive kind retains IDENTITY_VERSION = 1 and does not change existing identity transcripts. See inspection for lookup and evidence availability.

Representation rules ​

All record fields listed below accompany "version":1 in the top-level object. Optional values are represented explicitly as null. Names, paths, enumerations, and other strings use their validated public spellings. Ordered arguments and other semantic sequences remain arrays. Sets—currently an implementation's declared problem contracts and capabilities—are sorted before canonicalization. JSON objects, including environment-variable maps, are ordered by canonical JSON rather than insertion order.

Dependencies are always full typed identity strings. A RecordId<T> is never encoded as bare digest bytes or debug output. This makes each parent a Merkle node: replacing a dependency with its newly computed ID changes every parent that transitively names it without coupling unrelated records.

The version-1 record fields are:

RecordIdentity fields
Environment definitionname, and backend-specific definition
Worker definitionrunner-specific launch, ordered args, environment ID, and optional protocol transport
Dataset definitionname, optional parameter-schema ID, optional canonical defaults, output-schema ID, and kind-specific definition
Problem definitionname, contract ID, optional canonical defaults, and evaluator definition
Implementation definitionname, worker definition, sorted problem-definition IDs, optional parameter-schema ID, optional canonical defaults, and sorted capabilities
Execution policyname and every fully defaulted resource, isolation, timing, and ordering field
Observation policyname and observation kind
Dataset configurationdefinition ID, canonical parameters, and the numeric and full-digest seed record
Problem configurationdefinition ID and canonical parameters
Implementation configurationdefinition ID, canonical parameters, and selected environment-definition ID
Dataset instanceconfiguration ID, artifact ID, and output-schema ID
Problem instancedataset-instance ID and problem-configuration ID
Logical candidatethe three configuration IDs and the two policy IDs
Logical specificationone_shot kind, candidate ID, scientific budget, implementation-repetition index, and implementation seed record
Logical observation slotlogical-specification ID and measurement index
Logical attempt slotlogical-specification ID, typed warm-up or measured role, and scheduling-priority digest
Resolved environmentenvironment-definition ID and canonical backend fingerprint
Resolved launchresolved-environment ID, exact program, ordered arguments, allowlisted environment map, and working-directory convention
Executor definitionexecutor kind and canonical configuration
Resolved workeroptional source-bundle artifact ID, resolved-environment ID, and resolved-launch ID
Resolved specificationone_shot kind, logical-specification ID, problem-instance ID, implementation and evaluator resolutions, executor ID, wire-protocol version, and execution-semantics version
Resolved observation slotlogical-slot ID and resolved-specification ID
Resolved attempt slotlogical-slot ID and resolved-specification ID
Observationresolved-slot ID, producing-attempt ID, result and metric artifact references, timings, and completion status
Attemptresolved-slot ID and retry index

Nested definitions use the same field representation as their standalone record, without a second nested version. Raw SHA-256 values use 64 lowercase hexadecimal digits. Durations use an object with integral seconds and nanoseconds fields, which avoids floating-point unit conversions.

The attempt identity intentionally names the execution position rather than its terminal state. Metewand needs that ID before an observation can name its producing attempt, while an attempt outcome may itself name that observation. Including both edges would create a cyclic hash definition. Outcome, timestamps, diagnostics, and provenance remain in immutable attempt and observation records, but provenance-only values do not alter their identities. This also ensures that opaque provenance cannot introduce a workspace, staging, cache, or ephemeral absolute path into an identity. Wall-clock timestamps are never identity inputs.

Conformance vectors ​

fixtures/identities/v1.json pins the canonical representation, kind, and identity of every version-1 resource and record in one complete dependency graph. The fixture is language-neutral so each SDK can verify the same bytes and digests.

The Rust conformance tests rebuild that graph with object members, set-valued problem contracts, and environment variables supplied in different orders and require every identity to remain unchanged. They also change each graph node in turn and require exactly its transitive dependents to change. The manifest and local-tree suites separately prove that an unrelated experiment and filesystem enumeration order do not perturb existing component identities.

Example ​

The fully defaulted execution policy in the Rust conformance test has these exact canonical bytes:

json
{"cpus":1,"enforcement":"best_effort","max_concurrency":1,"memory":null,"name":"default","network":false,"primary_time":"timed_wall_time","run_order":"sequential","threads":null,"timeout":null,"timing_scope":"prepare_and_execute","version":1,"warmup_runs":0,"worker_reuse":false}

With the execution-policy domain separator, its identity is:

text
mw1-execution-policy-a7cb0d75d97d065c897a3858debfb8cea2769abb7ab7d5cb80eda49eeffbf486

Changing any representation or kind is a compatibility change and requires an explicit review of IDENTITY_VERSION.

Dataset construction uses the new dataset-derivation kind without changing existing transcripts. See Dataset materialization for its input fields and exact conformance vector. Output hashes are recorded separately and never participate in the construction identity.

The concurrency bound is an explicit execution-policy member, including its serial default of 1. Scheduling documents the expanded policy representation, execution semantics version 2, and the review of the compatibility constants.

Released under the MIT or Apache-2.0 license.