Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Versioned facade contracts

The additive oce-api contracts describe metadata and evidence independently of a loaded engine. Existing load/export reports, diagnostic aliases, value/IO types and conditional storage aliases retain their signatures and behavior. The public surface contract and row ledger classify the exact API; pre-1.0 change control still applies.

Catalog ownership and identity

oce_api::catalog() returns facade-owned CatalogEntry values with static metadata strings and owned vectors. A caller can clone them without retaining an engine or depending directly on oce-blocks. The sole-facade consumer fixture adapts every rule payload and all Studio-shaped catalog fields under default, explicit mem and no-default feature selections. The existing companion catalog remains supported during migration.

Entries retain registry order; ports, rules, defaults and enum members retain declaration order. The projection includes canonical class paths, ordered port kinds/names, named/positional/width-driven regimes, every rule and default payload, structural-width flags, conservative statefulness and reserved lowering identities. An exhaustive dispatch inside the registry owner requires a complete adapter for each rule variant. The prior owner manifest and its exhaustive serializer remain intact.

Default-parameter ports are a metadata view; resolved instance arity can differ. Conservative statefulness is a class hint: for example, hysteresis-free comparators resolve algebraically. Reserved entries describe engine lowering identities and cannot be authored in CXF. Units, quantities, palette display policy and host ontology are not supplied by the catalog.

catalog_to_json serializes schema revision 1 as compact UTF-8 JSON with lexical object keys and one trailing LF. Arrays preserve their input order. All fields are present, with absent port names and optional rule names encoded as null. Integer payloads are JSON integers. Real bounds and literals are sixteen lowercase hexadecimal digits of the exact binary64 bits; this preserves signed zero, infinity and NaN payloads without introducing a general value codec. The function serializes caller-supplied DTOs without validating them.

CATALOG_JSON contains the packaged artifact. CATALOG_SCHEMA_REVISION and the catalog schema identify its shape. catalog_content_id hashes ASCII oce:catalog:1, one NUL byte, and every canonical JSON byte using FNV-1a-128, returning catalog:1:fnv1a128: plus 32 lowercase hex digits. All fields, rule/default payloads, flags and array order affect the tag. It is a non-security content identifier, with no authentication or engine-build compatibility guarantee. The existing registry fingerprint, state format and execution ABI do not change.

The catalog example writes the live canonical catalog, or writes every packaged descriptor when passed schemas. Schema artifacts are authored contract descriptions; repeated export checks their exact bytes, not derivation from Rust source. The catalog golden is a metadata regression artifact. A separate byte-arithmetic hash oracle and provenance note record its evidence limits.

Immutable producer evidence

Engine::load_cxf_with_receipt and Engine::export_cxf_with_receipt share the legacy operation pipelines. Their success receipts contain the legacy report and independently captured DiagnosticReceipt. into_parts separates them, so caller edits to report warnings cannot change the receipt’s provenance. Legacy entrypoints avoid this additional evidence allocation.

Failures return OperationFailure: terminal stage, completed-stage and terminal diagnostics, and the original OcError/standard error source chain. JSON, build and store errors can carry no diagnostics; terminal stage and error context still explain failure. No engine code is invented. An unloaded export retains its existing export-unsupported diagnostic. A partial export still succeeds with warnings; use the legacy report’s completeness check for emitted-document identity.

Producer stages are explicit boundary labels, not inferred from codes. Revision-1 ranks are:

RankStage
0Import: serialized admission, parse/resolution, including the CXF resolver’s internal passes
1Flatten
2AttributeUnification
3Validation
4Instantiation
5Schedule
6Semantics
7Projection
8StoreRecovery
9StoreSave
10StoreInputs
11Export

The ordering is stage rank, subject category/presence and exact UTF-8 subject text, code string, then severity rank (Error=0, Warning=1, Info=2). Absent sorts before Opaque; an empty present string differs from absence. Subjects can identify authored or synthetic nodes, classes or positional content. Current producers do not supply reliable subject provenance, so the facade preserves opaque text without URI/Unicode normalization or guessing. Hosts own authored-target mapping.

DiagnosticKey equality/order excludes display messages. Equal machine records retain multiplicity and producer-relative tie order, without a prose tie-breaker or uniqueness claim. Code strings are extensible. There is no truncation, deduplication or stable human-message promise. The existing all_diagnostics and legacy warning order remain unchanged. The receipt schema describes this separate revision.

Other contract descriptors

contract_descriptors() returns all seven domain/revision/artifact descriptions. Catalog uses JSON Schema 2020-12. Other artifacts describe actual Rust fields and semantic limits in JSON; they do not promise new JSON wire codecs or schema-driven runtime validation.

DomainActual contract and limits
ValuesExisting Value, ValueType and ConnectorId aliases remain. Real values use bit-preserving binary64; enums retain class and ordinal. Constructor representability does not establish operation-specific validity. Connector IDs are model-local indices.
IOExisting point fields and declared static attributes; enums project to Int, strings are omitted. Current inventory classification/defaults are explicit.
ParametersExisting tune-at-rest rows and available static bounds. Absent bounds do not establish freedom from cross-parameter rules. Unit/quantity provenance is currently absent.
AssertionsRevision 2: CompletedFrame::diagnostics retains all block warnings, including Assert and other classes. Sources are currently class-level, not guaranteed instances. Repeated false Assert inputs warn each evaluation; true is silent.
Execution profileDescriptor revision 2, still fixed HostTick v1: one advance per accepted complete frame, including equal timestamps; no Modelica same-time event iteration. Descriptive, not a runtime selector or snapshot revision.

Every completed frame retains warnings. There is no public no-op-sink execution profile or engine write-back route. Load/Store side effects and commit ordering are unchanged. These descriptors add no rollback, warn-once, escalation, scheduler, equipment policy or safety guarantee. The separately documented serialized admission and replacement policy uses Import for byte refusals without adding/reordering stages or changing descriptor bytes.

Consumer migration boundary

Consumers of removed execution profiles need source migration. New adapters can depend on oce-api alone for the typed catalog and receipts. Studio retains its full source/build/features identity, catalog policy, diagnostic truncation and authored-target mapping. These are separate from the facade catalog content tag. No future OCE commit is embedded in the artifact, and this change advances no downstream source or pin. Coordinated companion removal remains later work.

The migration record distinguishes this additive contract from the earlier facade contraction. Full local tests, exact public baselines and external compiler fixtures establish bounded implementation evidence; hosted cross-architecture checks and actual downstream qualification remain separate evidence.

Closed host compatibility descriptor

CompatibilityDescriptor::current(None) captures public facade facts without an engine. Passing Some(&export_report) additionally captures the existing complete exported-document tag, calling content_id_complete() first. Any warnings return its unchanged ContentIdError::Incomplete; partial export never silently becomes absent or complete content. No export is performed implicitly. This additive artifact does not add an eighth ContractDomain or change the seven existing artifacts.

CatalogContentId and CompleteExportContentId are distinct read-only types. Hosts can borrow their unchanged tag strings with as_str() or print them. Neither accepts an authored DomainKey, an arbitrary string, or the other category. No speculative executable, generation or state-wire type is exposed. The owned descriptor survives report mutation and engine reload/drop; capture again after re-export to describe changed exported content. Capture neither observes nor changes run state.

Canonical bytes and comparison

Display / to_string() is the complete revision-1 artifact, not Debug output. UTF-8 lines occur in exactly this order, with no spaces, BOM or CR, decimal revisions without leading zeros, and one LF after every line, including the last:

LabelCovered value
oce-compatibilityDescriptor revision, exactly 1.
catalog-schemaCurrent public catalog schema revision.
catalogVerbatim current facade catalog content tag.
io-schemaPublic IO inventory contract revision, not a loaded input-definition digest.
value-schemaPublic value contract revision, not a new value codec.
parameter-schemaPublic parameter metadata contract revision, not instance parameter values.
execution-profileExactly HostTick-v1, the canonical label for fixed HostTick v1.
execution-profile-schemaPublic execution-profile descriptor revision (currently 2).
oce-api-versionExact Cargo package version, including any pre-release/build suffix.
exportVerbatim complete CXF content tag, or exactly none if no report was supplied.

The absent-export golden and complete-export golden are hand-assembled from those fields, public revisions/version and the existing independently checked tag goldens. No source normalization is claimed. Catalog FNV-1a-128 covers ASCII oce:catalog:1, NUL, then all catalog_to_json(catalog()) bytes including LF. Export FNV-1a-128 covers exactly ExportReport.bytes, without prefix or length. Both start at 0x6c62272e07bb014262b821756295c58d; each byte is XORed, then multiplied by 0x0000000001000000000000000000013b modulo 2^128. Existing tag prefixes and 32-lowercase-hex formatting stay unchanged. The new artifact adds no hash of its own.

check_compatible requires exact field equality and returns the first CompatibilityMismatch in canonical order: DescriptorRevision, CatalogSchema, CatalogContent, IoSchema, ValueSchema, ParameterSchema, ExecutionProfile (label or descriptor revision), Build (package version), ExportPresence, ExportContent. Either unsupported descriptor revision refuses, even if equal. There is no SemVer range, wildcard, fallback or coercion. Two absent exports agree only on absence; hosts needing content identity separately require presence. Persisted receipts are canonical bytes, not parsed OCE objects: compare exactly against a newly captured descriptor, refusing unknown revisions, changed/missing/extra fields and all byte differences. OCE supplies no receipt parser.

Limits and security

The only build fact is the public oce-api package version. Default, explicit mem and no-default selections intentionally share the same descriptor because their supported package behavior is equivalent. Compiler, source commit, dependency lock, target, codegen and binary identity are not captured. In particular, unpublished same-version builds can disagree while these facts agree. Hosts retain full source/build qualification. Matching descriptors are necessary public-fact checks, not sufficient execution equivalence, cross-platform numerical evidence, restore eligibility or release-to-release compatibility. io() inventory is not input_definitions(); these revisions do not identify either model’s actual IO. LoadReport.model_id remains diagnostic authored/synthetic identity, never a compatibility key.

FNV is non-cryptographic; collision resistance, authenticity and authorization are not supplied. ExportReport is mutable: an empty warning list at capture is not authenticated producer provenance or CXF revalidation. Hosts may hash/sign canonical bytes themselves and own freshness, trust, generation fencing and equipment policy. OCE is not a signing/PKI authority. State/manifest bytes, executable fingerprints, generation tokens and native frame sequence are absent and remain private where currently private. Snapshots, restore, frames and admission limits retain their existing rules.

Complete-frame preparation adoption

Engine::input_definitions and Engine::prepare_frame add the preparation part of the complete-frame contract. Discover inputs from the owned exact-type definitions, not io().iter().filter(In): that point projection includes internal driven points, omits strings and projects enums to Int. Supply every canonical definition once with a real host observation. The definition’s exact inclusive bounds are schema domains, not input values or defaults. Missing values are refused rather than seeded or read from the Store.

Replace old per-value staging with one complete borrowed-key list passed to prepare_frame(time, entries). Preparation returns an owned opaque PreparedInputFrame without staging the loop’s valid prefix. The plan carries all fan-out targets and exact native values, but no Store handles or public connector indices. There is no serializable plan or reusable schema/cache object. Refresh discovery after successful load/reconfiguration; old plans are invalid after reload or dirty resume, including same-byte reload and same-value edits. Clean resume and compatible restore alone preserve the context, while an advanced clock can make the submitted time ineligible.

Do not replace execution with preparation. Pass the owned plan to engine.execute_frame(plan) for one complete transition and an owned CompletedFrame. The old execution methods and supporting types have been removed, without aliases. Hosts own quality, freshness, scheduling, persistence and actuation; neither missing observations nor duplicate names are silently accepted.

The public tests, stateful preservation matrix, and private plan/lifecycle census establish the bounded current preparation evidence. Execution, shared-core and frame-only contraction evidence make PC-033 through PC-035 current. The assertion and execution descriptors are now revision 2; other descriptors, catalog identity, state formats, HostTick v1, stable-release status and downstream pins are unchanged.

Complete-frame execution adoption

Collect host observations, call prepare_frame, then move the plan into execute_frame. The latter rechecks readiness, incarnation, model time and sequence capacity before staging anything. Any ordinary returned error preserves the full engine image and consumes no accepted position, although the Rust plan is moved. On success, retain or clone the returned result rather than relying on latest-state inspection. Read time(), sequence(), outputs() and diagnostics(); there is no serialization API.

The result contains lexical root boundary identities and native typed values, not every internal output connector or durable column. Distinct declared outputs may share a driver; pass-throughs occur once. Warning records retain emission order and producer source semantics. No pointer, Store handle, schedule, deployment token or durable replay identity is exposed. Sequence starts at one, counts successful native frames only and never resets during this Engine’s lifetime, even on reload or checkpoint rewind. Equal-time success is another transition, never an idempotent retry.

Hosts decide whether to execute and what to do with completed values; Store/actuation follow outside this API. Sibling consumers need to migrate; no sibling source or pin is changed or qualified here. See the execution contract and evidence.

The single frame path retains the private HostTick evaluation/refresh implementation. Host loops submit complete frames and own cadence and trace capture. get_output and watch are latest-state, non-receipt views, including internal points. There is no raw output view or Store write helper. Parity evidence is limited to equivalent complete schedules, not arbitrary legacy workflows.