Status: frozen corrected T001 v0.1 candidate — MV-CORE-T001-C001
This document is the integration authority for later parallel work. Git and committed artifacts are authoritative; chat history is not. Any change to this contract requires a separately authorized bounded task labelled CONTRACT CHANGE. Future work must not change it silently.
C001 is the explicitly authorized CONTRACT CHANGE / bounded correction of the
pre-Final-Gate T001 candidate at 1c6229dd416d776011b013b637ab2508b463d582. It is not
the T001 Final Gate. The corrected required authority fields and canonicalization below
supersede that unreleased candidate; old candidate documents missing those fields fail
closed. There is no automatic migration and no general permission to change published
contracts. See C001_VERIFICATION.md for the correction/test mapping.
| Namespace | Ownership |
|---|---|
MemoryValidator.Core.Identity |
Typed identities and material configuration canonicalization |
MemoryValidator.Core.Contracts |
Version headers, status enums, configuration and module envelopes |
MemoryValidator.Core.State |
Run manifest, generation guard, and explicit state machine |
MemoryValidator.Core.Persistence |
Durable authority store and file-promotion adapter boundary |
MemoryValidator.Core.Recovery |
Recovery decisions derived from committed authority |
MemoryValidator.Core.Evidence |
Immutable observation, provenance, tool, and integrity contracts |
MemoryValidator.Core.Findings |
Evidence-backed interpretations; never recommendations |
MemoryValidator.Core.Invariants |
Typed domain errors and cross-contract validation |
MemoryValidator.Core.Serialization |
The one JSON profile and bounded canonicalization rules |
Future collectors and tool/benchmark adapters own namespaces outside
MemoryValidator.Core.*. They consume Core contracts; Core never references them.
Identity, version headers, and status enums are foundational. Evidence and Findings depend on typed identities and version headers; ModuleResult may carry independent Evidence proof. State composes those contracts. Persistence composes State plus Serialization. Recovery reads through the locked file Persistence boundary. Adapters may depend inward on Core; Core must not depend outward on adapters, UI, CLI, network, hardware APIs, or tool SDKs.
The Core uses the .NET BCL. A new runtime dependency requires a separately reviewed license, purpose, exact version, and necessity decision.
RunId: unique execution identity,run_<guid-n>.GenerationId: unique generation identity,gen_<guid-n>.ModuleRunId: unique module execution identity,mod_<guid-n>.EvidenceId: unique observation identity,evd_<guid-n>.FindingId: unique interpretation identity,fnd_<guid-n>.ConfigurationId: deterministic content identity,cfg_<sha256>.
The Run also persists generation_sequence (zero-based, at most 2,147,483,646),
generation_lineage (unique IDs in authority-owned progression order), and
authority_revision (nonnegative Int64, never reset on generation change). Evidence,
ModuleResult, and Finding carry the generation sequence as part of ownership.
retired_evidence_ids prevents an Evidence identity from being rebound after its
generation's current observations are retired. This is an identity ledger, not a
historical Evidence store. Uniqueness enforcement is within the Run's persisted lineage;
independent Run stores are not a global identity registry.
GUID text is 32 lowercase hexadecimal characters with no separators. SHA-256 text is 64 lowercase hexadecimal characters. Default/uninitialized identity structs are invalid.
Identity material must never include hostname, username, IP, MAC, MachineGuid, disk serial, Windows key, email, or another personal/device-unique identifier.
ConfigurationId hashes UTF-8 JSON produced by MV-CONFIG-C14N-0.1:
- Fields are emitted in this exact order:
memory_capacity_bytes,module_count,channel_count,memory_technology,configured_data_rate_mt_per_second, andprimary_timings. memory_technologyuses .NET 10 Unicode whitespace trimming, Unicode NFC, invariant uppercase, then NFC again. Null/blank or ill-formed Unicode is rejected. Internal whitespace is retained; compatibility normalization (NFKC) is not used.- Integers use invariant base-10 JSON numbers with no exponent, leading plus, or unnecessary leading zeros in canonical output.
primary_timingsis either JSON null or an object ordered ascas_latency,ras_to_cas_delay,row_precharge,active_to_precharge.- The technology value emits only ASCII letters, digits, space, underscore, hyphen,
and period literally. Every other UTF-16 code unit is escaped as
\uXXXXwith uppercase hexadecimal; a supplementary character uses its two surrogate escapes. This allow-list is explicit and does not depend on the encoder's changing block list. - JSON has no insignificant whitespace or BOM. SHA-256 is computed over those exact
UTF-8 bytes. Required nullable
primary_timingsis always emitted; missing is invalid, whereas null is a distinct documented material configuration.
Only these documented, non-private material fields participate. A change to normalized
material must change ConfigurationId; logically equivalent normalized strings retain
the same ID. Producer/schema versions do not participate.
JSON enum values use uppercase snake case.
ExecutionStatus: SUCCESS, ERROR, TIMEOUT, SKIPPED.
DiagnosticStatus: PASS, FAIL, REVIEW, UNKNOWN, CAPACITY_FAIL.
They are independent dimensions. ERROR, TIMEOUT, and other execution outcomes do
not imply diagnostic FAIL. After execution ERROR or TIMEOUT, absent independent
diagnostic Evidence, the diagnostic status must be UNKNOWN.
Every constructor, factory, and deserializer rejects undefined status enums. ERROR
and TIMEOUT require error metadata. A non-UNKNOWN diagnosis after either failure
requires a nonempty independent_diagnostic_evidence bundle, not merely an Evidence ID.
Each bundled observation must be valid, uniquely referenced in evidence_ids, owned by
the same Run/generation ID/sequence/configuration/ModuleRun, and observed no later than
execution completion. At authority append/reload it must exactly match already committed
Evidence, including all known metadata. All result references must belong to that
ModuleRun. Error metadata is never diagnostic proof. Core validates this evidence-backed
producer claim; it does not infer a hardware diagnosis from payloads or execute a
diagnostic/recommendation engine.
Every persisted public contract has top-level schema_name, schema_version, and
producer_version. ModuleResult additionally binds run_id, generation_id,
generation_sequence, configuration_id, and module_run_id; both statuses; UTC
start/completion; duration; Evidence references; optional typed error; is_partial;
and optional independent diagnostic Evidence (absent means an empty bundle; null is
invalid). Nullable tool and error may be absent or explicit null and are omitted
when null on write. Required metrics and collection fields cannot be null.
A failed or partial module result is additive. It cannot replace the run manifest or erase unrelated committed Evidence.
IRunAuthorityStore is the authoritative mutation boundary. Every durable mutation
accepts expectedGeneration, expectedGenerationSequence, and expectedRevision.
The store acquires its local exclusive file lock, reloads committed authority, checks
all three exact preconditions inside that same serialized boundary, and rejects stale
input before mutation or a temporary write. Every successful mutation advances revision
exactly once. A generation restart additionally advances sequence exactly once, appends
one never-used GenerationId, and retains retired Evidence identities. The revision does
not restart at zero. File-lock contention retries for a bounded ten seconds using a
monotonic elapsed-time clock; it does not choose authority by timestamp.
New authority must be CREATED, sequence 0, revision 0, one lineage ID, and empty
current/retired artifact collections. An already advanced or FINALIZED snapshot cannot
be imported through Create. FINALIZED rejects every further durable mutation,
including append operations, generation changes, and configuration changes.
Persistence writes a complete immutable snapshot:
serialize -> same-directory temp -> Flush(true) -> read/deserialize/validate -> promote -> reopen actual destination -> validate and byte-compare
Existing authority uses File.Replace with a backup; first authority uses same-directory
File.Move. Reads and recovery consult only the configured authority path. .tmp.*,
.bak, and .lock artifacts are never authority.
The actual destination must match the validated durable candidate bytes exactly before success is reported. A no-op promotion, valid-but-different replacement, missing file, or corrupt destination fails closed. A post-promotion failure may have changed the destination; it does not prove rollback. Backup deletion occurs only after verification, and a retained backup is never automatically selected. Reserved temp/backup/lock paths cannot be configured as an authority path.
IAuthorityFilePromoter isolates filesystem promotion for fault testing and platform
adaptation. Implementations must preserve the previous destination when reporting a
failed promotion. No other T001 adapter exists. Future collectors and benchmark adapters
must return versioned Core contracts and may not mutate authority directly. Promotion
failure is an execution/persistence failure; the destination must be reloaded and
validated before further use.
Recovery's public entry point is AuthorityRecoveryService(FileRunAuthorityStore).
It accepts expected RunId, generation ID/sequence, revision, and requested configuration,
loads and assesses the committed destination under one file lock, and returns that
authority identity in its assessment. The policy and assessment constructor are internal;
an arbitrary in-memory manifest or arbitrary store implementation cannot authorize
RESUME_ALLOWED. Assessments are snapshots, not permission to bypass a later mutation's
CAS. No recovery method executes a process or hardware action.
Names are lowercase dotted tokens:
memoryvalidator.run-manifestmemoryvalidator.configurationmemoryvalidator.module-resultmemoryvalidator.evidencememoryvalidator.finding
T001 supports contract version 0.1 exactly. C001 readers fail closed on unrecognized
fields rather than perform lossy authoritative rewrites. A later optional additive field
requires explicitly coordinated reader/writer support; it is not silently skipped.
A removal, rename, type change, enum semantic change, required-field addition, canonicalization change, or
meaning change is breaking and requires a new version plus CONTRACT CHANGE authorization.
Unsupported schema names or versions fail closed. T001 has no migration engine.
- UTF-8 JSON, snake_case property names, uppercase snake-case enum strings.
- Persisted contract strings and metric names must contain well-formed UTF-16 before serialization; isolated high or low surrogates are rejected rather than rewritten as U+FFFD. A v0.1 nonblank string contains at least one code unit outside this explicit .NET 10 whitespace set: U+0009..U+000D, U+0020, U+0085, U+00A0, U+1680, U+2000..U+200A, U+2028, U+2029, U+202F, U+205F, and U+3000. U+FEFF is not whitespace in this contract.
- Enum integers, undefined names, case variants, and padded names are rejected.
- Required constructor parameters are enforced.
- Comments, trailing commas, and duplicate object property names are rejected.
- Null optional properties may be omitted.
- Unknown properties fail closed at every typed level; payload JSON and named metric entries are explicitly open data, not unknown contract fields.
- Schema name/version checks run for all five standalone persisted contract types as well as manifest children. No manifest-only compatibility shortcut exists.
- Bounded integral JSON numbers are accepted only when mathematically exact (for
example
2.0and2e0read as 2); canonical writes use integer notation. Decimal fields must be exactly representable without rounding, truncation, or underflow. Schemas express the same Int32/Int64/UInt64 bounds and decimal coefficient/scale limits. - Callers must use
CoreJson; alternate serializer defaults are not authoritative.
Authority contract failures use typed CoreContractException subclasses and stable codes,
including STALE_GENERATION, STALE_GENERATION_SEQUENCE, STALE_AUTHORITY_REVISION,
GENERATION_ID_REUSE, ILLEGAL_STATE_TRANSITION, UNSUPPORTED_SCHEMA_VERSION,
PERSISTENCE_PROMOTION_FAILED, and AUTHORITY_COMMIT_VERIFICATION_FAILED. Preconditions
and candidate validation reject before promotion. Post-promotion verification failure
has the distinct no-success/no-assumed-rollback semantics described above. Standalone
JSON shape/lexical errors may surface JsonException; the file authority boundary wraps
them as contract validation failures. Tool/process failure is an execution fact, not a
hardware diagnosis.
Persisted times are DateTimeOffset values with an explicit zero UTC offset and JSON
RFC 3339 representation with uppercase T and Z or +00:00, within DateTimeOffset's
year range 0001 through 9999, seconds 00 through 59, and at most seven fractional
digits. Generic RFC 3339 year-zero and leap-second spellings are intentionally excluded
because they are not representable by the v0.1 runtime type. Naive/local timestamps,
-00:00, and non-zero offsets are rejected. Duration is rounded from exact integer
ticks to elapsed milliseconds, midpoint away from zero, and must agree with
start/completion. Evidence observation cannot follow its commit; child
commits/completions/creation cannot follow the containing authority snapshot. No
authority ordering is inferred from wall-clock time.
Configuration uses MV-CONFIG-C14N-0.1. Evidence observation integrity uses
MV-JSON-C14N-0.1: object property names sort by ordinal UTF-16 code-unit order, arrays retain
order, duplicate object names are rejected, insignificant whitespace is removed, and
JSON number lexical spelling is material. Evidence hashes a fixed object containing
sorted metrics and canonical payload, using SHA-256 lowercase hex.
This is bounded canonicalization, not a claim of RFC 8785 compliance. Changing either canonicalization rule is a breaking contract change.