Skip to content

Latest commit

 

History

History
1566 lines (1328 loc) · 71.5 KB

spec-simulation-artifacts.md

File metadata and controls

1566 lines (1328 loc) · 71.5 KB

Simulation Artifacts

This document is the sole persistent-schema owner for workload-running simulation inputs and typed execution observations. DFG-sim, CGRA-sim, sys-sim, and mapped RTL simulation share these Artifact families while retaining their own execution semantics and time authorities.

Artifact Families

The fixed schema descriptors are:

loom.simulation_workload      1.1
loom.simulation_runtime_input 2.0
loom.simulation_execution     3.1

Each family has one typed C++ model and one canonical serializer/parser. Schema versions use X.Y: X denotes an incompatible change and Y denotes a compatible extension. Simulator-specific request, result, trace, activity, or report Artifact families are forbidden.

loom.simulation_execution 3.1 extends the optional native System memory activity of 3.0 with a required per-event shared-memory service sample on every mandatory narrow System root-lifecycle progress entry. Identity bytes are compared by exact schema version, so 3.0 bytes are simply another identity and no compatibility path reads them. It does not add a general diagnostic trace, provider payload, or replay field.

SimulationWorkload

SimulationWorkload has one closed root union:

SimulationWorkload =
    Spatial(SpatialSimulationWorkload)
  | System(SystemSimulationWorkload)
  | StructuredProgram(StructuredProgramSimulationWorkload)

The root discriminants are zero, one, and two in declaration order. Version 1.1 appends StructuredProgram; it does not renumber either loom.simulation_workload 1.0 root. The spatial root is:

SpatialSimulationWorkload {
  launch_ref: RootedGraphLaunchRef
  dense_coordinates: array<uint64>
  value_input_plan:
    total table<graph value-input ordinal, SpatialValueInputSource>
  observable_contract: SpatialObservableContract
}

SpatialValueInputSource =
    Fixed(CanonicalValueSequence)
  | Runtime

launch_ref is the one Dataflow-owned structural reference that recovers the exact Canonical Dataflow Artifact, root thread launch, static graph launch, called graph, graph ABI, memory roots, and channel context. The workload must not copy a canonical_dataflow_ref, GraphRef, graph symbol, or logical invocation record.

The dense coordinate count must equal the root thread domain rank. Every coordinate must be inside any statically known bound. One Spatial workload identifies one logical point. A finite dense application launch therefore publishes one workload per Canonical Dataflow-enumerated coordinate tuple; Mapping still consumes the unique root and its logical domain rather than treating those workload artifacts as simultaneous copies of the graph. loom.simulation_workload 1.0 admits only a dense rooted launch. A DynamicWork workload is Unsupported; a producer must not invent a string key, provisional occurrence, or channel correspondence to serialize it.

The value-input table is exactly total over graph value-input ordinals. A Fixed entry contains exactly one semantic token and makes that launch parameter part of workload identity. A Runtime entry delegates only that token to the exact SimulationRuntimeInput. Stream inputs are always concrete runtime sequences, and imported memory roots are always runtime bindings. Consequently there is no generic four-way InputSource union that repeats the value, stream, and memory planes already owned by the graph ABI.

The spatial observable contract is:

SpatialObservableContract {
  value_results: canonical set<graph value-result ordinal>
  stream_outputs: canonical set<graph stream-output ordinal>
  memories:
    canonical table<SpatialMemoryObservableTarget, MemoryObservationForm>
}

SpatialMemoryObservableTarget =
    LogicalMemory(LogicalMemoryRootOrViewRef)
  | Exposure(graph memory-result ordinal)

MemoryObservationForm =
    FullState
  | DiffFromRuntimeInput

Value and stream ordinals are owner-relative to launch_ref; their complete meanings are the corresponding GraphLaunchBoundaryTransferRef and ChannelProducerRef forms. An exposure ordinal has the complete meaning of the corresponding MemoryExposureRef. Types and shapes are recovered from the exact Dataflow owner and are never copied into the contract. Each collection is sorted by the canonical typed target key and contains no duplicates.

Graph completion is mandatory for every workload and derives from GraphLaunchBoundaryTransferRef::Done(launch_ref). It is not an optional observable selector. Intermediate completion and retirement activity belongs to execution trace or activity records rather than this contract.

The system root has the structural shape:

SystemSimulationWorkload {
  program_entry_ref: DeploymentProgramEntryRef
  value_input_plan:
    total table<program value-argument ordinal, SystemValueInputSource>
  external_value_input_plan:
    total table<input or inout DeploymentExternalInterfaceRef,
                SystemValueInputSource>
  observable_contract: SystemObservableContract
}

SystemValueInputSource =
    Fixed(CanonicalValueSequence)
  | Runtime

SystemObservableContract {
  value_results: canonical set<program value-result ordinal>
  external_value_outputs:
    canonical set<output or inout DeploymentExternalInterfaceRef>
  external_stream_outputs:
    canonical set<output or inout DeploymentExternalInterfaceRef>
  memories:
    canonical table<DeploymentExternalInterfaceRef, MemoryObservationForm>
}

The program-entry reference already carries the exact Deployment identity, so there is no second deployment_ref. The Deployment family owns both target catalogs, ordinals, and validation. Every table and selected observable must match the exact entry or external-interface kind, direction, and semantic type. Input or inout stream and memory interfaces are always supplied by SimulationRuntimeInput. Fixed or runtime value selection follows the same single-token rule as the spatial root. This schema does not copy Deployment entry or interface fields.

loom.simulation_workload 1.1 and loom.simulation_runtime_input 2.0 remain unchanged when Deployment moves from 5.1 to 6.0. Their System catalog references encode only the contextual Deployment ArtifactIdentity; neither wire admits or parses a Deployment schema descriptor. The caller supplies an already strict-imported current Deployment, and catalog-owner equality rejects an identity published under any other descriptor. The workload and input therefore cannot reinterpret a 5.1 Deployment as 6.0, and their accepted wire language does not change.

The Structured Program root supplies the source-program workload used by pre-Mapping Evaluation and compilation DSE:

StructuredProgramSimulationWorkload {
  entry_ref: StructuredEntityRef
  argument_plan:
    total table<entry ABI argument ordinal,
                StructuredProgramArgumentSource>
  observable_contract: StructuredProgramObservableContract
}

StructuredProgramArgumentSource =
    FixedValue(CanonicalValueSequence)
  | RuntimeValue
  | RuntimeMemory

StructuredProgramObservableContract {
  return_value: bool
  memories:
    canonical table<StructuredProgramMemoryTarget, MemoryObservationForm>
}

StructuredProgramMemoryTarget =
    EntryPointerArgument(entry ABI argument ordinal)
  | GlobalObject(StructuredEntityRef)

entry_ref must resolve through one exact StructuredProgramCandidateView to a defined llvm.func. Its parent identity is the sole source-program identity; the workload must not add a structured_program_ref, function symbol, module path, or operation position. Argument order, argument and return types, DataLayout, global definitions, and initial global state are recovered from that exact Structured Program and are never copied into the workload.

The argument plan is exactly total in LLVM ABI order. FixedValue and RuntimeValue are legal only for values with a canonical scalar or fixed vector semantic shape. FixedValue contains exactly one token. RuntimeMemory is legal only for an LLVM pointer argument and delegates its concrete backing object and byte offset to the exact runtime input. Raw pointer bits are never a value source. Unsupported aggregate ABI values, function pointers, or other interfaces that lack an exact provider fail closed rather than acquiring an opaque byte or property-map representation.

return_value may be selected only for a non-void return with a canonical semantic shape. An entry-pointer target must name a RuntimeMemory argument. A global target must resolve to an exact LLVM global object in the same Structured Program. Memory targets are sorted by their typed key, contain no duplicates, and use the shared memory observation forms. A global object uses its exact Structured Program initializer as the runtime baseline; version 1.1 does not add a second mutable-global input authority. A workload that needs a different initial global state must express that initialization in its exact entry program.

Entry retirement is mandatory and mechanically derived. It is not an optional observable field. The Structured Program root is not a test fixture: test harnesses, command-line tools, and production invocations are merely providers of concrete instances of this same Artifact contract.

Workloads own fixed problem shape, fixed launch values, and requested observables. They do not own concrete runtime values, stream contents, memory images, simulator policy, expected results, trace capture, or execution limits.

A planner may accept a canonical non-empty set of Spatial workload roots as an exact application selection. It strictly imports every workload, requires one common Canonical Dataflow owner, and mechanically projects the unique set of RootThreadLaunchRef values from their launch_ref fields. That projection does not make workload values, dense coordinates, or observable choices part of Mapping. The planner publishes the projected set through the ordinary System MappingConstraintSet owner; that constraint set remains the sole persistent Mapping coverage authority. A workload set is therefore an authoring input, not a second Mapping-scope schema.

Canonical Semantic Values

One value representation is shared by fixed workload inputs, runtime value inputs, runtime stream tokens, functional observations, and semantic trace publications:

CanonicalValueSequence {
  token_count: uint64
  lanes: array<SemanticLane>
}

SemanticLane =
    Defined(fixed-width semantic bits)
  | Poison
  | Undef

The target type is recovered from the owning workload slot, observable target, or trace token occurrence and is not serialized again. For a none token, each token has zero lanes. For a scalar, each token has one lane. For a fixed-ranked vector, each token has the product of its dimensions in canonical row-major lane order. The lane array length must therefore equal token_count * lanes_per_token; for none, that product is zero even when token_count is nonzero.

A defined integer, index, or floating lane stores the exact fixed-width software-semantic bit representation. Variant tags and bits use canonical big-endian wire order. This is serialization framing, not target memory endianness, Fabric port layout, vector packing, or a hardware representation. Host integer and floating types are never semantic authorities. Unknown lane states, wrong widths, extra lanes, and unresolved target widths are invalid.

For a first-class !llvm.ptr<AS> value, defined semantic bits are accompanied by the runtime-input-owned object ordinal and signed byte offset resolved from the same object registry used by memory-root bindings. Canonical pointer values never contain a native process address. Their exact P(AS)-bit projection is validated against the module DataLayout and must round-trip through the owning pointer codec; poison and undef carry no object target. This is a typed pointer alternative, not an integer convention or a second alias graph.

SimulationRuntimeInput

SimulationRuntimeInput uses the same root discriminant as its exact workload. The spatial root is:

SpatialSimulationRuntimeInput {
  workload_ref: exact Spatial SimulationWorkload reference
  runtime_values:
    total table<runtime graph value-input ordinal, CanonicalValueSequence>
  runtime_streams:
    total table<graph stream-input ordinal, CanonicalStreamSequence>
  memory_objects: canonical array<RuntimeMemoryObject>
  memory_root_bindings:
    total table<LogicalMemoryRootRef, RuntimeMemoryRootBinding>
}

CanonicalStreamSequence {
  values: CanonicalValueSequence
  termination: ClosedAfterLast | OpenAfterLast
}

RuntimeMemoryObject {
  byte_count: uint64
  initial_bytes: array<SemanticMemoryByte>
  pointer_values: canonical array<RuntimeMemoryPointer>
}

RuntimeMemoryPointer {
  storage_byte_offset: uint64
  address_space: uint32
  target_object_ordinal: uint64
  target_byte_offset: signed A(address_space)-bit integer
}

SemanticMemoryByte =
    Defined(uint8)
  | Poison
  | Undef

RuntimeMemoryRootBinding {
  object_ordinal: uint64
  byte_offset: uint64
}

runtime_values is exactly total over value-input ordinals whose workload source is Runtime; every sequence has exactly one token. runtime_streams is exactly total over graph stream-input ordinals. ClosedAfterLast publishes the stream close after its final token. OpenAfterLast means that no close is observed within the sequence's owning observation horizon. For runtime input, that horizon is the complete supplied input: no later token or close exists, and the first version rejects timed external arrivals rather than inventing a generic environment schedule. For execution output, the horizon ends at the execution terminal, so the same form records an open produced prefix without asserting a counterfactual future.

Every imported logical-memory root reachable from the selected launch has exactly one root binding, and no unrelated root may appear. A runtime memory object is neutral byte-addressed software storage. Its initial-byte count must equal byte_count; the exact Canonical Dataflow type, DataLayout, and root/view relations alone interpret typed accesses. This avoids choosing one aliased memref role as a privileged storage type or importing physical memory layout into the software input.

pointer_values is sorted by storage_byte_offset and contains no duplicate or overlapping stored representations. Every record covers exactly P(address_space) defined bits in initial_bytes, interpreted with the exact module DataLayout endianness, and targets an existing canonical object ordinal with an exact signed A(address_space)-bit byte offset. Re-encoding the target through the object registry must reproduce those stored representation bits. Poison or undef storage cannot carry pointer provenance. The bytes remain the content authority; this table supplies only the object provenance that a raw address representation cannot recover. loom.simulation_runtime_input 2.0 adds this table and is therefore incompatible with that family's 1.x schema.

For a launch-derived imported linear view, the runtime input still binds only the owning LogicalMemoryRootRef to an object and byte offset. The simulator resolves the Dataflow-owned launch relation and instantiates the graph formal's typed view over that same byte object. It does not serialize a native pointer, duplicate a view binding, or execute a conversion actor. Several formal views may therefore share one object ordinal while retaining their distinct exact memref element types.

Objects have no author-selected persistent IDs. Before serialization, roots that share one runtime object form an equivalence class. The canonical key for that object is the sorted non-empty list of (LogicalMemoryRootRef, byte_offset) bindings. Objects are sorted by this key and receive their zero-based object_ordinal from that order. Binding two or more roots to one ordinal expresses aliasing; no separate alias graph is serialized. Missing, empty, duplicate, out-of-range, or unreferenced objects are invalid. Overlap between two root ranges bound to the same object is legal aliasing and must not be rejected merely because their ranges intersect.

Canonical object reordering also remaps every target_object_ordinal in stored pointer records. A finalizer must not preserve draft-local ordinals or native addresses in either the bytes or provenance table.

A fresh graph allocation is not an imported runtime object. Its execution identity derives from its static LogicalMemoryRootRef and graph-invocation occurrence, and its storage is created under the owning software semantics. It therefore does not receive a workload-local object ID or root binding.

The system runtime root is:

SystemSimulationRuntimeInput {
  workload_ref: exact System SimulationWorkload reference
  runtime_entry_values:
    total table<runtime program value-argument ordinal,
                CanonicalValueSequence>
  runtime_external_values:
    total table<runtime DeploymentExternalInterfaceRef,
                CanonicalValueSequence>
  external_stream_inputs:
    total table<input or inout DeploymentExternalInterfaceRef,
                CanonicalStreamSequence>
  memory_objects: canonical array<RuntimeMemoryObject>
  memory_interface_bindings:
    total table<DeploymentExternalInterfaceRef, RuntimeMemoryRootBinding>
}

The two value tables are exactly total over Runtime selections and each sequence contains one token. Stream inputs are finite untimed sequences with the same closed/open-after-last semantics as the spatial root. Memory bindings are exactly total over every selected memory observable and every input or inout memory interface required by the entry. Their object canonicalization, aliasing, baseline, and range rules are the same as spatial memory objects.

A producer must not substitute argv arrays, device names, string-key maps, or simulator-private event records for these typed interfaces.

The Structured Program runtime root is:

StructuredProgramSimulationRuntimeInput {
  workload_ref: exact Structured Program SimulationWorkload reference
  runtime_values:
    total table<runtime-value entry argument ordinal,
                CanonicalValueSequence>
  memory_objects: canonical array<RuntimeMemoryObject>
  pointer_bindings:
    total table<runtime-memory entry argument ordinal,
                RuntimeMemoryRootBinding>
}

Every runtime value contains exactly one token of the type recovered from the entry ABI. Every RuntimeMemory argument has exactly one pointer binding and no other argument may have one. Sharing one object ordinal expresses aliasing between entry pointers. Objects are ordered by their sorted nonempty (argument ordinal, byte_offset) binding keys, exactly as spatial objects are ordered by their logical-root binding keys. Missing, duplicate, out-of-range, empty, unreferenced, or noncanonical objects and bindings are invalid. The object byte count is the finite runtime extent of that pointer input; typed accesses outside it fail execution rather than extending storage or wrapping.

The Structured Program runtime root contains no native address, argv projection, process-global state, call-path identity, profile counters, or candidate-specific graph input. Candidate-specific Spatial workloads and runtime inputs are derived only after a Canonical Dataflow Program exists and are used for exact graph replay; they do not replace this source workload in a whole-program Evaluation case.

Runtime input does not contain model timing, trace-capture policy, execution limits, Mapping repairs, physical addresses used only by a simulator, or presentation options.

Canonical Workload And Input Wire

Every displayed union assigns zero-based unsigned 32-bit discriminants in declaration order. Unsigned counts and ordinals use 64-bit big-endian values. Exact Artifact identities use their fixed 32-byte representation. Arrays and tables use a 64-bit element count followed by elements in canonical order. Nested Dataflow and Deployment references use their owning canonical encodings; this schema does not renumber them.

Records encode fields in declaration order without names, optional property maps, padding, or native C++ layout. Tables are sorted by their typed semantic keys. Parsers reject duplicate or unsorted keys, unknown variants, missing or extra fields, noncanonical bytes, unresolved references, and any cardinality or owner mismatch. JSON, MLIR text, CLI syntax, and visualization files are derived projections and cannot be accepted as identity bytes.

The version-1.1 Structured Program workload encodes root discriminant two, followed by the production StructuredEntityRef encoding, the dense argument plan, the return selector, and the canonical memory-observable table. Its runtime input encodes root discriminant two, the exact workload identity, runtime values, canonical memory objects, and pointer bindings in declaration order. The owner codecs for StructuredEntityRef, semantic values, memory bytes, and Artifact identities are reused directly; this family must not copy their formulas.

Spatial Vecadd Example

For a rooted graph launch whose value-input ordinal zero is N, whose imported logical-memory roots are A, B, and C, and whose computation is C[i] = A[i] + B[i], the workload contains:

launch_ref = exact rooted vecadd graph launch
dense_coordinates = the selected logical thread point
value_input_plan = {
  0 -> Fixed(one defined index token with value 1024)
}
observable_contract = {
  value_results = {}
  stream_outputs = {}
  memories = {
    LogicalMemory(Root(C)) -> DiffFromRuntimeInput
  }
}

The runtime input contains no runtime value or stream entries. It provides three 4096-byte objects for A, B, and C, binds each root to its object at byte offset zero, and initializes the bytes using the software DataLayout for 1024 f32 elements. The serialized object ordinals derive from the sorted root-binding keys rather than the source names A, B, and C. Binding A and B to one object ordinal would instead state that those two imported roles alias; no other record changes.

SimulationExecution Root, Coupling, And Terminal

Every model that actually runs a software workload produces one SimulationExecution with one untagged root:

SimulationExecution {
  request_ref: exact EvaluationRequest reference
  terminal: ExecutionTerminal
  functional_observations
  progress_observations
  activity_summaries (Spatial) | memory_activity? (System)
}

The root does not carry a spatial or system discriminator. The exact Request already binds the model descriptor and workload, and the workload root owns that distinction. Repeating it in the execution would create a second case-kind authority.

The C++ SpatialSimulationExecution authoring value is shared by DFG, CGRA, mapped RTL, and mapped gate-netlist models that execute a Spatial workload. Spatial names the workload-observation form, not the selected engine or fidelity. An external-HDL evaluator constructs this same value and uses the ordinary finalizer; it must not add an RTL-specific execution subtype, engine tag, or parallel serializer.

The execution also has no direct observable-contract reference. It recovers the applicable contract through:

request_ref
  -> EvaluationRequest.workload_ref
  -> SimulationWorkload observable contract

The root field order, terminal record, Spatial and System functional and progress observations, and activity summaries are closed below. Together they define the complete loom.simulation_execution 3.1 wire. The invocation-local typed Spatial diagnostic algebra defined below has no field in that Artifact root; the narrow System root-lifecycle progress sequence is a distinct mandatory observation.

The closed terminal algebra is:

ExecutionTerminal =
    Retired
  | Halted {
      finding_kind: FindingKind
      witness: registry-defined terminal-witness payload
    }
  | StoppedByLimit

Retired means the workload's completion frontier, observable obligations, and invocation-local quiescence contract have completed. Halted records a sound execution-level witness for deadlock, trap, combinational nonconvergence, or proven nontermination. StoppedByLimit records that an execution limit ended observation without such a proof.

The FindingKind registry is the sole owner of the witness payload schema. The SimulationExecution terminal is the sole owner of the concrete witness instance. There is no separate terminal_observations collection and Evaluation Evidence must not copy the witness.

The terminal wire uses zero-based u32be discriminants. Retired is the single word u32be(0). Halted is u32be(1), followed by u32be(finding_kind.ordinal), u64be(witness_byte_count), and exactly that many canonical witness bytes from the registered FindingTerminalWitnessCodec. StoppedByLimit is the single word u32be(2). A Halted decoder resolves the exact Finding descriptor, invokes its terminal-witness decoder and validator in the exact Request closure, re-encodes the adopted value, and requires byte equality. An unknown kind, missing or incomplete codec, noncanonical payload, count overflow, truncation, or trailing payload bytes is invalid.

Evaluation maps these forms exactly:

Retired        -> Completed with every mandatory terminal finding Absent
Halted         -> Completed with the corresponding mandatory terminal finding
                  Present and every other mandatory terminal finding Absent
StoppedByLimit -> CancelledOrTimeout

Every workload-running simulator descriptor declares one typed SimulationExecution output slot and the complete mandatory terminal FindingQuery set. A legal EvaluationRequest must request all of those findings. The descriptor's closed outcome-cardinality contract requires exactly one execution output for Retired and Halted. For StoppedByLimit, it alone declares whether CancelledOrTimeout may retain zero or one stopped execution. Unsupported and ExecutionFailed bind no SimulationExecution.

For the finding corresponding to a Halted terminal, EvaluationEvidence.Present carries one occurrence of:

TerminalWitnessRef {
  execution_output_slot_ref: ModelOutputSlotRef
  execution_output_ordinal: uint64
}

Simulation Artifacts owns this occurrence payload codec. Its canonical bytes are exactly u32be(execution_output_slot_ref.ordinal) followed by u64be(execution_output_ordinal). The terminal FindingKind descriptors reference this codec through their FindingOccurrenceCodec; the codec schema descriptor is exactly loom.terminal_witness_ref 1.0. They do not copy or reinterpret the fields. The containing Evidence result's FindingRequestOrdinal recovers the FindingKind, so the payload carries no kind tag, Request reference, direct SimulationExecution reference, or witness ordinal.

The reference resolves through the containing Evidence's output_bindings. Validation requires that the slot schema is SimulationExecution, the ordinal exists, the referenced execution names the same exact Request, and its terminal is Halted with the same FindingKind. The singleton terminal witness needs no additional witness ordinal. Every other mandatory terminal finding is Absent.

Capability rejection before execution is Unsupported; simulator, tool, or adapter failure is ExecutionFailed. SimulationExecution never owns normalized metrics, normalized findings, DSE decisions, or human diagnostics. Those belong only to EvaluationEvidence and its registries.

Capability whose absence is discoverable only from runtime values, such as an unordered conflicting plain-memory access or a required external consistency behavior not implemented by the exact model, also ends with Evaluation outcome Unsupported. It is not Halted and must not fabricate a SimulationExecution result. A genuine dynamic closed wait-set is Halted. A simulator, Bridge, or provider invariant violation is ExecutionFailed. Execution limits and external cancellation remain StoppedByLimit or CancelledOrTimeout according to the owning attempt and Evaluation contract. Static invalid IR, Fabric, or Mapping is rejected before execution and never becomes dynamic deadlock.

Spatial Functional Observations

The spatial workload's observable contract is the sole owner of selected targets, target order, types, and memory observation forms. A spatial execution therefore stores three positional arrays:

SpatialFunctionalObservations {
  value_results: array<ValueResultObservation>
  stream_outputs: array<CanonicalStreamSequence>
  memories: array<MemoryObservationPayload>
}

ValueResultObservation =
    Published(CanonicalValueSequence)
  | NotPublished

The arrays align exactly with the canonical value_results, stream_outputs, and memories collections recovered through the execution's Request and workload. They do not repeat graph ordinals, memory targets, types, or MemoryObservationForm tags. A published graph value contains exactly one token. A stream may contain any token count, including an empty open prefix.

The workload-selected memory form determines the corresponding payload without a second persistent discriminator:

FullState payload {
  byte_count: uint64
  bytes: array<SemanticMemoryByte>
}

DiffFromRuntimeInput payload {
  byte_count: uint64
  runs: array<MemoryDiffRun>
}

MemoryDiffRun {
  byte_offset: uint64
  changed_bytes: nonempty array<SemanticMemoryByte>
}

A full-state byte array has exactly byte_count elements. Diff runs are sorted by offset, in range, nonoverlapping, nonadjacent, and maximal. Every encoded byte differs semantically from the exact runtime baseline; adjacent changed bytes belong to one run. An empty run array uniquely means no change. Equality distinguishes Defined, Poison, and Undef states as well as defined byte values.

DiffFromRuntimeInput is legal only when the exact Dataflow target and RuntimeInput mechanically establish one unique baseline range before simulation. Request verification rejects a target without that correspondence or with a mismatched extent. A fresh allocation, dynamically unresolved exposure, MMIO effect, or other target without a runtime byte baseline must use FullState when the exact model supports snapshot semantics.

Each memory entry is the requested target-relative projection of one execution state. No execution-local memory-object ID or alias graph is added. If selected targets overlap through relations mechanically recoverable from Dataflow and RuntimeInput, finalization verifies that their overlapping semantic bytes agree. This check does not make either projection the storage authority.

All three arrays are exactly total over the selected targets for every retained execution:

  • Retired requires every value to be Published, every selected stream to be ClosedAfterLast, and every memory payload to describe final visible logical state.
  • Halted permits a value to be NotPublished and a stream to contain an open prefix. Memory payloads describe exact logical state visible at the halt coordinate.
  • a retained StoppedByLimit execution uses the same partial-observation forms at its stop coordinate.

There is no generic Complete | Partial | Unavailable wrapper. Value publication, stream closure, and memory visibility already provide the three planes' exact completion facts. The Request verifier rejects a model whose descriptor statically cannot observe a selected target. Runtime-dependent absence of required capability produces Unsupported; provider failure produces ExecutionFailed. Neither outcome creates an execution containing an unavailable placeholder.

System Functional Observations

The system workload's exact Deployment-owned catalogs and observable contract determine four positional arrays:

SystemFunctionalObservations {
  value_results: array<ValueResultObservation>
  external_value_outputs: array<ValueResultObservation>
  external_stream_outputs: array<CanonicalStreamSequence>
  memories: array<MemoryObservationPayload>
}

The arrays align with the canonical selections in SystemObservableContract and repeat no ordinals, interface references, kinds, directions, types, or memory-form tags. The Spatial definitions of ValueResultObservation, MemoryObservationPayload, full state, diff runs, and baseline eligibility apply unchanged.

Retired requires every selected value to be published, every selected stream to be closed, and every memory payload to describe final externally visible state. Halted and a retained StoppedByLimit may contain unpublished values, open stream prefixes, and memory state at the terminal coordinate. Aliased or overlapping memory projections must agree. Provider-private process exit data, argv, file descriptors, device names, and gem5 statistics are not functional observations.

Spatial Progress Observations

Every retained Spatial execution stores exactly three progress anchors:

SpatialProgressObservations {
  launch_accepted: EventCoordinate
  graph_retirement_visible: optional<EventCoordinate>
  terminal_observed: EventCoordinate
}

EventCoordinate {
  reference_cycle: ExactRatio
  delta: uint64
}

launch_accepted is the coordinate at which the rooted Spatial Launch is accepted. graph_retirement_visible is the coordinate at which the graph completion frontier becomes visible at that launch boundary. terminal_observed is the observation horizon at which the execution terminal is fixed after the last fully committed atomic transition. A stop limit cannot leave half of a transition in the retained execution.

All persistent cycle coordinates use the one canonical ExactRatio schema. An integral cycle N has the sole encoding N/1; there is no integer-or-ratio union. delta orders causal propagation within one reference cycle and never adds elapsed cycles. Coordinates compare lexicographically by exact reference_cycle and then delta, and finalization requires:

launch_accepted
  <= graph_retirement_visible, when present
  <= terminal_observed

The progress record encodes fields in declaration order. Each coordinate encodes the canonical ExactRatio numerator and denominator followed by delta, all as unsigned 64-bit big-endian values. The optional retirement anchor uses a zero-based unsigned 32-bit Absent | Present discriminant and, when present, one coordinate payload. Native layout, field names, alternate integer coordinates, and non-reduced ratios are invalid identity bytes.

Retired requires graph_retirement_visible. Halted and a retained StoppedByLimit permit it to be absent or present. For example, an execution may expose graph retirement and complete all functional observations, then halt while its mapped hardware fails to restore invocation-local quiescence. Its terminal remains Halted, its graph-retirement anchor remains present, and its terminal coordinate is later.

The progress record stores no elapsed-cycle field, cycle-count metric, wall-clock duration, event count, completion Boolean, timebase descriptor, or clock-domain copy. DFG coordinates use the AbstractCycle owned by the exact DFG timing-model descriptor. CGRA coordinates use the reference domain mechanically derived from the exact Fabric, complete SpatialMapping, and mapped Spatial Launch boundary. A relative clock schedule not hard-fixed by Fabric remains an EvaluationRequest base condition.

Evaluation derives requested timing observations from these anchors rather than copying them into the execution. A compatible retired cycle observation uses the exact reference-cycle difference from launch_accepted to graph_retirement_visible; delta is excluded. For Halted, a model may derive a censored lower bound from launch_accepted to terminal_observed only when the requested metric definition accepts that reference domain. A retained StoppedByLimit preserves its coordinates, but its CancelledOrTimeout Evidence has no normalized metric results.

System Progress Observations

SystemProgressObservations {
  program_entry_accepted: SystemEventCoordinate
  program_exit_visible: optional<SystemEventCoordinate>
  terminal_observed: SystemEventCoordinate
  root_lifecycle: array<SystemRootLifecycleObservation>
}

SystemRootLifecycleObservation {
  event: EventFamilyKey
  occurrence: uint64
  coordinate: SystemEventCoordinate
}

SystemEventCoordinate {
  gem5_tick: uint64
  delta: uint64
}

gem5_tick is the exact integer time coordinate of the gem5 EventQueue selected by the request's Gem5SimulationBinding and model binding. delta gives a deterministic commit order within one tick and does not add elapsed time. The coordinates compare lexicographically. Retired requires program_exit_visible; Halted and retained StoppedByLimit permit it to be absent or present. In every case:

program_entry_accepted
  <= program_exit_visible, when present
  <= terminal_observed

root_lifecycle is a required ordered progress field, although it may be empty when no mapped root is invoked. Each event is the canonical Dataflow EventFamilyKey for either RootThreadStart or RootThreadCompletion, derived from the exact Request's Deployment, SystemMapping, and Canonical Dataflow closure. The event key is the sole event identity. occurrence is a nonzero execution-local dynamic invocation identity assigned by the System provider; it does not redefine the event family or root.

Each entry also carries memory_occupied_ticks, the cumulative shared-memory acceptance-service integral of the same execution sampled at that event by the sole maintained service observer. Samples are non-decreasing along the ordered lifecycle and never exceed the execution's full-program occupancy when memory activity is present. The difference of two samples is therefore the exact service occupancy of the interval they bound, which is what makes an accelerated window measurable without a second observer or a derived rate. A sample is not a second time authority and never replaces the coordinate.

Lifecycle coordinates are strictly increasing across the array and lie in the closed interval from program_entry_accepted through program_exit_visible when present, otherwise through terminal_observed. A start introduces a fresh occurrence. Its completion must use the same occurrence and root, follow that start, and occur at most once. One static root may have any number of distinct occurrences. A mapped root that was never invoked has no lifecycle obligation. Retired requires every started occurrence to have completed; Halted and retained StoppedByLimit may retain started occurrences without a completion.

The System progress wire encodes the three anchors in declaration order, followed by an unsigned 64-bit big-endian lifecycle count. Each lifecycle entry contains a length-framed canonical local EventFamilyKey, the unsigned 64-bit big-endian occurrence, the coordinate's unsigned 64-bit big-endian tick and delta, and the unsigned 64-bit big-endian memory_occupied_ticks sample. Foreign Dataflow references, non-root boundary families, unmapped roots, zero or reused occurrences, completion before start, duplicate completion, non-increasing coordinates, out-of-interval coordinates, decreasing service samples, and a sample above the full-program occupancy are invalid identity bytes.

These observations do not copy a tick frequency, wall time, exit-code policy, or gem5 event priority. Evaluation derives metrics through the exact model. The root lifecycle is not a general gem5 event trace and does not admit raw provider records or diagnostic events. Raw gem5 traces remain attempt or scratch material. DFG and CGRA diagnostic traces use the current typed Spatial event algebra below only outside loom.simulation_execution 3.1 identity.

Activity Summaries

Activity summaries retain exact aggregate execution facts. They do not retain per-occurrence events, normalized metrics, probabilities, or backend-native toggle files. The closed record is:

ActivitySummary {
  window: ActivityWindow
  coverage: ActivityCoverage
  payload:
      ActorTransitions {
        transitions:
          canonical table<ActorRef, ActorTransitionCounts>
      }
    | FabricResources {
        use_counts:
          canonical table<FabricUsePatternRef, uint64>
        resource_occupancy:
          canonical table<FabricResourceStateRef,
          canonical table<CapacityDimensionKey, FabricResourceOccupancy>>
      }
    | ImplementationSignals {
        signals:
          canonical table<HardwareImplementationActivityPointRef,
                          SignalActivity>
      }
}

ActivityWindow =
    LaunchToGraphRetirement
  | LaunchToTerminal

ActivityCoverage =
    Complete
  | Partial

ActorTransitionCounts {
  committed_firings: uint64
  retired_firings: uint64
}

FabricResourceOccupancy {
  occupied_capacity_reference_cycles: ExactRatio
  peak_occupied_capacity: uint64
}

SignalActivity {
  state_residency_reference_cycles: array<ExactRatio, 4>
  transition_counts: array<uint64, 16>
}

LaunchToGraphRetirement begins immediately after launch_accepted and ends after graph_retirement_visible; it is legal only when that optional progress anchor is present. LaunchToTerminal begins immediately after launch_accepted and ends after terminal_observed. Point events at the closing anchor are included. Integrated residency uses the exact reference-cycle difference between the two anchors; delta orders causal events but contributes no duration. No activity record copies coordinates, clock domains, timebase descriptors, or elapsed-cycle metrics.

Complete and Partial describe target-inventory coverage, not temporal sampling. Every retained value in a summary must have been observed continuously and exactly across its complete selected window. Sampling, gapped capture, extrapolation, and statistical estimates remain raw material or Evaluation observations and cannot be serialized as an exact ActivitySummary.

For ActorTransitions, the complete inventory is every canonical actor in the rooted launch closure. A complete table contains one entry for every actor, including explicit zero counts. A partial table contains exactly the actors continuously observed; a missing actor is unknown, never zero. Counts aggregate all dynamic invocation occurrences of one static actor. Per-occurrence and per-cycle distinctions belong to trace. For every entry:

committed_firings >= retired_firings

For a Retired execution over LaunchToTerminal, every committed firing must also have retired. A model may retain distinct counts for a stopped or halted execution.

For FabricResources, the complete inventories are all applicable, activity-capable FabricUsePatternRef values and every capacity dimension of FabricResourceStateRef values in the exact mapped SpatialCore closure. Complete tables include explicit zero entries. Partial tables contain exactly the continuously observed targets. use_counts records selected use-pattern activations. occupied_capacity_reference_cycles is the nonnegative exact integral of occupied capacity over the selected window. peak_occupied_capacity cannot exceed the capacity owned by the referenced state and capacity dimension, and the integral cannot exceed window duration multiplied by the observed peak (and therefore cannot exceed duration multiplied by capacity). A state may own unlike dimensions, such as FIFO slots and enqueue/dequeue service; their integrals are never added or given an implicit dimension-zero denominator. Complete occupancy tables contain every dimension of every applicable state. Partial tables omit dimensions that were not continuously observed; absent dimensions are unknown. Temporary service claims are observed at grant and release. Durable queue, operand-pool, and register-FIFO residency is observed at the concrete provider state transition; an enqueue reservation is not a substitute for a resident token. The execution does not store utilization, stall cost, energy, or any other derived quantity.

For ImplementationSignals, the complete inventory is the exact activity-point catalog owned by the selected HardwareImplementation and applicable to this execution. HardwareImplementationActivityPointRef is an exact implementation-owned reference to one observable scalar signal bit. The full catalog, its deterministic order, and its correlation to Fabric are owned by HardwareImplementation, not by simulation. Until that catalog is finalized, an implementation-level producer must fail closed rather than invent names, paths, or provisional IDs.

Signal state order is fixed as T0, T1, TX, TZ. The sixteen transition counts use row-major source-state/destination-state order. Diagonal counts are zero because a transition is a state change, and the four exact residency values sum to the selected window duration. This basis permits mechanical SAIF or toggle-table projection without making HDL hierarchy names semantic. Waveforms, VCD, FSDB, raw SAIF, and simulator-native activity files remain raw owner-attempt or scratch material. No current raw-bundle Artifact schema is implied.

An activity summary must contain at least one target entry across its payload; otherwise it is omitted. activity_summaries may therefore be empty. It contains at most one summary for each (ActivityWindow, payload kind) pair and sorts by those zero-based enum discriminants. This order mechanically defines the activity_summary_ordinal used by Evaluation. Within each table, keys sort by their owner-defined canonical reference bytes.

The activity payloads and windows above remain Spatial-only because their duration-bearing fields use the selected Spatial reference cycle. System execution instead has optional memory_activity { occupied_ticks }. The schema 3.0 System wire encodes a u32 absence/presence tag and, when present, a u64 occupied-service integral after progress observations. Spatial activity encoding is unchanged.

System memory activity is the native single-memory acceptance-service busy time from ProgramEntryAccepted through ProgramExitVisible. It covers requests from every HostCore, InstructionCore, and bridge DMA producer. The fixed timing-mode platform places a zero-delay CommMonitor immediately before SimpleMemory. Its native PktRequest probe fires only after downstream acceptance, preserving packet command and size before the response mutates them. The maintained LoomMemoryServiceProbe integrates the exact bound service duration and clips any unfinished tail at program exit. Failed retries consume no service; swaps, atomic read-modify-write requests, and failed store-conditionals do consume it. Payload byte counters are not a service-occupancy surrogate.

The probe begins before the first simulation event. The supported timing CPUs and timing DMA use timing transport; functional initialization is outside the window. Atomic instructions still travel as timing packets. The probe requires timing System mode; this contract does not admit arbitrary atomic-mode transport. Missing observations remain unavailable and never become zero. Admission requires a retired positive gem5-tick window, occupied ticks no greater than that window, every root-lifecycle service sample no greater than that occupancy, and the exact same-System binding's single physical memory domain.

The same observer is sampled by the Thread Dispatch device at every root lifecycle event, so the execution retains one cumulative service integral read at two granularities: the full-program total and the per-event samples. There is no second counter and no derived rate.

projectSystemMemoryUtilization divides occupied ticks by the complete program window. projectSystemAcceleratedWindow instead reports the accelerated window: the first observed root Start tick, the last observed root Completion tick, and the difference of their service samples. Host gaps between launches stay inside that interval. The window is absent when the execution completed no root launch, so a host-only run is unmeasured rather than fully utilized; the Application owner additionally refuses a window that spans no tick, because no occupancy ratio exists over it. The bound SimpleMemory contract retains its existing finite capacity: one accepted byte consumes 73 ticks after native conversion of the default 12.8 GiB/s rate at a fixed 1ps global tick. Configuration verifies the effective native rate. Neither idle devices nor unused time disappear from either denominator. The execution stores only native occupancy; both reduced exact utilization ratios are derived. Memory service alone does not qualify application QoR; the Application owner joins it with an independent compute occupancy. Other System models may omit memory activity.

This specification is the semantic owner contract consumed by ActivityBinding.ExecutionActivity. The loom.simulation_execution 3.1 root, publisher, and importer are current owners, but Evaluation consumption also requires an activity-summary adopter, ordinal resolver, same-Request validator, and exact source-to-target lineage adapter. Until that adapter is registered, the Evaluation source form is owner-unavailable and every attempted authoring or import fails closed. Parsing the outer Evaluation wire does not prove that the adapter is available.

The summary wire encodes, in declaration order, the zero-based window, coverage, and payload discriminants as unsigned 32-bit big-endian values, followed by the selected payload. Tables encode an unsigned 64-bit big-endian count followed by sorted key/value entries. Counts and capacities are unsigned 64-bit big-endian values. Exact ratios and nested references use their sole owner-defined canonical encodings. Fabric keys are length-framed with an unsigned 64-bit byte count and the exact Fabric-local reference bytes. The capacity-dimension key is its existing unsigned 32-bit owner-local key. Each state value is a canonical dimension table, ordered by that key. Fixed-size state and transition arrays carry no redundant length. Unknown fields, duplicate keys, alternate table orders, native layout, and noncanonical ratios are invalid identity bytes.

A Spatial engine boundary has no Request or Fabric selection of its own. A boundary codec that admits Fabric activity therefore borrows the exact mapped Fabric view from its caller and fails closed when that context is absent. The Request-backed root derives the same view from its bound hardware subject.

The exact Request and typed payload determine source attachment:

  • actor references must belong to the exact rooted Dataflow launch;
  • Fabric references require an exact complete SpatialMapping for that Dataflow program and Fabric; and
  • implementation references require an exact HardwareImplementation and Mapping/Deployment lineage that reaches the same execution.

A summary whose source basis cannot be proven from the Request closure is invalid. An ActivityBinding.target is instead the destination Evaluation target to which an evaluator projects the selected summary; it is not a second source attachment. A capture request is a nonsemantic invocation binding. Enabling activity capture cannot change scheduling, outputs, terminal form, progress anchors, normalized metrics, or findings.

Invocation-Local Spatial Diagnostic Trace

loom.simulation_execution 3.1 contains no general diagnostic-trace field. Its mandatory narrow System root-lifecycle progress sequence is not a SpatialDiagnosticTrace and cannot carry the event algebra below. The current Spatial diagnostic trace is an invocation-local SpatialDiagnosticTrace: it has no Artifact identity, persistent wire, manifest, chunk, coverage claim, or Evidence reference. It may be retained only in the current attempt context or scratch material and never enters SimulationExecution or Evaluation identity.

TraceCaptureLevel = Firing | Semantic | Microarchitecture

SpatialDiagnosticTrace {
  level: TraceCaptureLevel
  frames: array<SpatialTraceFrame>
}

SpatialTraceFrame {
  coordinate: EventCoordinate
  events: nonempty canonical array<SpatialTraceEvent>
}

A trace may contain no frames. Each appended frame is nonempty, has a coordinate strictly later than the preceding frame, contains only events admitted by the selected level, and is sorted by the one canonical diagnostic event key below. No path, opaque payload, unchecked Artifact reference, or claim of complete or prefix coverage may be inferred from this diagnostic value.

Typed Diagnostic Events

Trace events use a small closed lifecycle and relation algebra over references owned by Dataflow, Fabric, Mapping, and the exact execution. They do not use a generic kind + properties record, per-operation event classes, simulator extension maps, physical Tags as software identities, or a second persistent entity catalog.

Dynamic Occurrence References

The execution-local reference families are:

GraphInvocationOccurrenceRef =
  invocation ordinal under the exact SpatialSimulationWorkload

ActorTransitionOccurrenceRef =
  (GraphInvocationOccurrenceRef, ActorRef, transition_ordinal)

TokenOccurrenceRef =
    GraphIngress(
      GraphInvocationOccurrenceRef,
      GraphIngressTokenRef,
      producer_sequence_ordinal)
  | ActorResult(
      ActorTransitionOccurrenceRef,
      result_ordinal,
      producer_sequence_ordinal)

MemoryActionOccurrenceRef =
  (ActorTransitionOccurrenceRef,
      ActorWide
    | Lane(row_major_ordinal))

PhysicalActionOccurrenceRef =
    Transition(ActorTransitionOccurrenceRef, local_action_ordinal)
  | Token(TokenOccurrenceRef, local_action_ordinal)
  | FabricUse(GraphInvocationOccurrenceRef,
              FabricUsePatternRef, occurrence_ordinal)

All ordinals are unsigned 64-bit semantic values. A graph-invocation ordinal is dense in deterministic launch-acceptance order under the exact rooted Spatial workload. ActorRef must belong to the graph selected by that invocation. Transition ordinals are dense per (GraphInvocationOccurrenceRef, ActorRef) and are allocated when a complete semantic transition is first formed, before physical admission. A pending transition can therefore be referenced while stalled. An ordinal is never cancelled, reused, or reassigned; once its transition commits, it is also the actor's firing ordinal.

Producer sequence ordinals are dense in the ordered Dataflow sequence emitted by one graph-ingress or actor-result endpoint. result_ordinal must name a token-plane result owned by the referenced actor. ActorWide names one scalar, plain-vector, WholePayload, or fence memory action. Lane is used only for an active PerLane memory action and names its canonical row-major software lane. Inactive lanes create no lane action. An all-zero masked vector memory transition creates no MemoryActionOccurrenceRef or MemoryLinearized event, although its actor commit, publication, and retirement lifecycle remains visible at the selected levels.

local_action_ordinal names a fixed position in the canonical static physical-action skeleton mechanically derived for one transition or token by the exact Fabric and complete SpatialMapping. A transport skeleton orders produced actions, selected traversal steps including durable-storage positions, then consumed endpoint actions. Storage positions remain in that static skeleton, while their dynamic actions use FabricUse. Emitted token-owned action ordinals therefore need not be dense; removing a storage action from token ownership never renumbers other actions. The ordinal is not a resource ID, raw route index, Physical Tag, instruction slot, or simulator container position.

FabricUse.occurrence_ordinal is dense from zero per exact (GraphInvocationOccurrenceRef, FabricUsePatternRef) in accepted physical request order. A request keeps the same occurrence through grant and retirement. The existing resource-use lifecycle supplies this ordinal; trace capture allocates no separate counter. FIFO enqueue, dequeue, simultaneous dequeue/enqueue, and internal offer-advance actions use this owner-relative identity. A simultaneous action is one atomic Fabric use with one lifecycle, even when it consumes and produces different token occurrences. An internal offer advance moves no token, and repeated advances remain distinct physical occurrences. The occurrence's exact use pattern is also the sole source of its PhysicalRequested target; a disagreeing target is invalid.

These occurrence references are local to one SimulationExecution; none is a Dataflow entity, Mapping entity, or independently referenceable Artifact object.

Event Algebra

The closed event union is:

SpatialTraceEvent =
    ActorCommitted(ActorTransitionOccurrenceRef)
  | ActorRetired(ActorTransitionOccurrenceRef)
  | TokenPublished(
      TokenOccurrenceRef,
      value: CanonicalValueSequence)
  | MemoryLinearized(
      MemoryActionOccurrenceRef,
      reads_from: optional<MemoryVersionRef>,
      modification_predecessor: optional<MemoryVersionRef>,
      sequentially_consistent_predecessor:
        optional<MemoryActionOccurrenceRef>)
  | PhysicalRequested(
      PhysicalActionOccurrenceRef,
      target: PhysicalActionTarget)
  | PhysicalGranted(PhysicalActionOccurrenceRef)
  | PhysicalRetired(PhysicalActionOccurrenceRef)

MemoryVersionRef =
    Initial
  | WrittenBy(MemoryActionOccurrenceRef)

PhysicalActionTarget =
    Use(FabricUsePatternRef)
  | Transfer(
      traversals: nonempty canonical set<FabricPhysicalTraversalRef>,
      use_patterns: canonical set<FabricUsePatternRef>)

Every TokenPublished.value contains exactly one semantic token. Its type is recovered from the referenced endpoint and is not repeated. A none token has token_count = 1 and an empty lane array. Defined bits, poison, undef, fixed vector lane order, and width validation use the sole CanonicalValueSequence contract above. Semantic capture never has a capture_values switch. These occurrence values and the execution's terminal functional observations have one owner, SimulationExecution, and must agree wherever their horizons overlap. Graph-ingress publications likewise agree with the exact workload and runtime input. The trace supplies occurrence history; it does not redefine the terminal value or stream projection.

MemoryLinearized records only primitive dynamic relations that cannot be recovered from program order and the exact actor contract:

  • an atomic load has reads_from;
  • an atomic store has modification_predecessor;
  • an atomic RMW and a successful compare-exchange have both;
  • a failed compare-exchange has only reads_from;
  • plain accesses and fences have neither object relation; and
  • a seq_cst operation or fence names its predecessor in the exact sequentially-consistent order when one exists.

Initial is relative to the exact dynamic atomic object of the containing action. WrittenBy must name an action that writes that same object. A PerLane actor emits one relation record for each active lane; scalar, plain-vector, WholePayload, and fence actors use ActorWide. The actor contract and outcome determine which optional fields are required or forbidden. Modification order, reads-from, and the sequentially-consistent predecessor are diagnostic primitive relations. Synchronizes-with, happens-before, release visibility, and acquire visibility are derived mechanically and must not be copied into the trace.

PhysicalActionTarget::Use names one Fabric-owned atomic use pattern. Transfer names the exact selected directed traversal set and the canonical set of Fabric-owned use patterns acquired by that one atomic action. A direct contention-free point transfer has an empty pattern set. A traversal with one resource pattern has a singleton set. A broadcast carries all branch traversals and every per-traversal pattern joined by its derived atomic activation. Compute, memory, and Fabric-owned storage actions use Use. The pattern set is the execution-local projection of the exact Fabric, traversals, and complete SpatialMapping; it is not a second grouping authority. A producer cannot omit a selected pattern, merge unrelated actions, or invent another resource grouping.

There is no independent stall, queue-change, occupancy, state-transition, Tag, configuration, or blocker event. The interval from PhysicalRequested to PhysicalGranted is the exact stall interval; equal coordinates mean no stall. The referenced Fabric use-pattern contract and exact execution derive resource-state and queue effects. PhysicalRetired closes the action. A prefix, Halted, or retained StoppedByLimit execution may end with a request or grant still open, but a Retired execution cannot retain an unretired required physical action.

CGRA Transport Activation

A logical Dataflow net is a token-identity and completion domain, not one global handshake activation. CGRA execution derives its concrete publication instances from the complete SpatialMapping:

  • every ordinary sink is one publication instance; and
  • all logical operand queues matching one exact Temporal PE ingress and Physical Tag form one atomic publication instance.

Each instance independently owns terminal arrival, consumed ResourceUse actions, capacity reservation, commit, and sink publication. A blocked ordinary sink cannot prevent another routed branch from publishing. Conversely, members of one operand-queue match group cannot reserve, enqueue, or publish independently. A publication instance is physically accepted when each member has either entered its first selected durable FIFO/RegFIFO or completed sink publication. Once every instance is accepted, the producer transfer completes and its causal physical claim may retire. The source binding continues to apply backpressure to a later firing until the prior token finishes its full downstream route. Final delivery of every instance emits exactly one logical TokenPublished event.

A buffered route traversal dequeues against the next durable boundaries, not against every final sink of the logical net. The frozen route DAG mechanically derives the first downstream storage nodes and the final sinks reachable without another storage boundary. Dequeue atomically reserves capacity in all such downstream storage nodes and checks readiness only for the unbuffered sink set. The reservation is consumed by the corresponding enqueue. Waiting for all final sinks would erase the FIFO's progress contract; dequeuing without the reservation would invent an implicit network buffer. Runtime state does not become another route or grouping authority.

Physical acquisition is event-driven. A request denied by Fabric arbitration remains parked without scheduling empty reference-cycle polls. Releasing a claim envelope reactivates the exact parked request set at that release frame. If no resource, compute, memory, or transport event can reactivate a pending request, the execution is quiescent and must expose a closed-wait witness rather than consume its work budget with empty frames.

Capture Levels

Each variant has one fixed minimum level:

Firing:
  ActorCommitted
  ActorRetired

Semantic:
  every Firing event
  TokenPublished
  MemoryLinearized

Microarchitecture:
  every Semantic event
  PhysicalRequested
  PhysicalGranted
  PhysicalRetired

A retained level contains every covered event whose minimum level is no greater than that level. There is no event-local level, filter DSL, or independent flag combination. DFG-sim supports Firing and Semantic; a request for Microarchitecture is Unsupported. CGRA-sim supports all three when the exact {Dataflow, Fabric, complete SpatialMapping} closure provides the required physical references. System and mapped-RTL diagnostic production do not create new event variants. System diagnostic trace capture is unsupported in the current contract. Mapped RTL may emit this invocation-local Spatial algebra only when its exact Deployment and HardwareImplementation activity catalog provide a total correlation to the required Dataflow, Fabric, and Mapping references; otherwise trace capture, not workload execution, is Unsupported.

Launch, graph-retirement, and terminal markers are not SpatialTraceEvent variants. They are mechanically projected from SpatialProgressObservations. A viewer may render those markers together with a firing replay, but neither producer nor viewer serializes duplicate boundary events.

Canonical Diagnostic Ordering And Validation

The seven SpatialTraceEvent variants use zero-based declaration-order discriminants for capture-level membership and canonical diagnostic keys. There is no persistent event-record encoding. References and values remain typed invocation-local values, and their owner-defined canonical bytes are used only where required to construct the deterministic key.

Physical occurrence arms use declaration-order discriminants: Transition is zero, Token is one, and FabricUse is two. The first two retain their existing canonical key bytes: discriminant, canonical transition or token reference, then the unsigned 64-bit local action ordinal. FabricUse encodes its discriminant, invocation ordinal, Fabric-owner canonical use-pattern bytes, and unsigned 64-bit occurrence ordinal. Resource plan slots never enter this key.

The canonical event key is:

(event discriminant, canonical primary occurrence reference)

The primary reference is the transition for actor lifecycle events, token for publication, memory action for linearization, and physical action for physical lifecycle events. Observational payload is excluded. Events in one frame sort lexicographically by this key, and a duplicate key is invalid. Distinct physical lifecycle phases remain distinct because their discriminants differ. This order is serialization only; it does not define causality, arbitration, memory order, or physical progress.

Finalization validates at least:

  • every occurrence belongs to the exact Request, Spatial workload, rooted graph invocation, and execution horizon;
  • transition and producer-sequence ordinals are dense, deterministic, and consistent with actor commit, retirement, and ordered-token publication;
  • ActorCommitted precedes or equals ActorRetired, and every published result or memory action belongs to the named transition; a complete Firing projection of a Retired execution contains one retirement for every committed transition;
  • token result ordinal, type, semantic width, lane count, and one-token cardinality are exact;
  • memory relation fields match the actor kind, outcome, granularity, exact dynamic atomic object, and valid acyclic or total order required by the software contract;
  • physical targets belong to the exact Fabric and selected complete SpatialMapping, transfer traversals belong to the selected route, and any use pattern admits the claimed atomic grouping;
  • each physical action follows request, grant, retirement order without a missing request or duplicate lifecycle event;
  • a higher capture level contains the exact lower-level projection over the same covered interval;
  • token publications agree with input and functional-observation projections, and any activity-summary facts observed in the diagnostic trace agree over their shared horizon without treating omitted events as a coverage claim; and
  • no string key, property map, opaque extension payload, event-local coordinate, simulator-private ID, or copied owner fact appears.

For example, a mapped vector add may retain:

(5,0) PhysicalRequested(action7, Use(vector_add_pattern))
(7,0) PhysicalGranted(action7)
(7,1) ActorCommitted(add_transition3)
(8,0) TokenPublished(add_result9, one vector<4xf32> token)
(8,0) ActorRetired(add_transition3)
(8,0) PhysicalRetired(action7)

The two-cycle stall is derived from request and grant. For release/acquire, the trace can retain:

MemoryLinearized(
  store_action,
  modification_predecessor = Initial)
MemoryLinearized(
  load_action,
  reads_from = WrittenBy(store_action))

The exact contracts, program order, and reads-from relation derive synchronizes-with and happens-before; the trace does not serialize them.

Diagnostic capture is a nonsemantic invocation binding. Enabling it may change execution cost and scratch material, but must not change scheduling, outputs, terminal form, cycle count, metrics, findings, or Artifact identity. The current attempt context may retain the request and diagnostic value; no persistent record may claim trace order, coverage, or completeness.

Ownership And Coupling

EvaluationRequest.workload_ref and runtime_input_ref contain exact Artifact references. A SimulationExecution refers only to that exact Request and recovers both inputs and the workload observable contract through it rather than copying their references. EvaluationEvidence refers to the Request and binds the execution through the descriptor-owned output slot without copying its observations or terminal witness. A terminal finding occurrence uses the output-binding-relative TerminalWitnessRef. The execution never refers to Evidence, so the content-identity graph is acyclic.

Architecture-only RTL or EDA checks do not execute a workload and therefore must not create an empty SimulationExecution.

Anchor Verification

Stable workload/input anchors cover RootedGraphLaunchRef ownership, dense coordinate rank, total value-source classification, exact runtime-table complements, value and stream cardinality, semantic lane states, mandatory completion derivation, observable target validity, canonical object ordering, two imported roots aliasing one object, and rejection of physical layout or arbitrary object identity. One vecadd case covers fixed N, runtime A/B/C, and a visible diff of C.

System workload/input anchors cover exact Deployment entry and interface references, fixed versus runtime value complements, finite external streams, memory aliasing and baselines, direction/kind/type rejection, and absence of an argv or string-key escape. One host entry with a value, stream, and memory interface is sufficient.

Execution anchors separately cover the single untagged root, Request-only coupling, typed output slot and ordinal resolution, mandatory terminal-finding totality, the closed terminal algebra and outcome cardinality, witness ownership and reference validation, runtime-dependent Unsupported versus Halted and ExecutionFailed, spatial functional-array alignment, terminal- specific value and stream completeness, unique memory-diff runs, baseline eligibility, alias-overlap agreement, and rejection of normalized results inside SimulationExecution; canonical integral and fractional progress coordinates; progress ordering; terminal-specific graph-retirement presence; terminal observation only after an atomic transition; and metric derivation that excludes delta.

System execution anchors cover positional functional arrays, retired versus partial publication, exact gem5 tick ordering, mandatory program-exit presence for Retired, canonical root event-family ownership, globally ordered root lifecycle coordinates, occurrence reuse and duplicate rejection, start-before-completion, repeated occurrences of one root, legality of an unstarted mapped root, and closure of every started occurrence at Retired.

Activity anchors cover the two progress-defined windows, rejection of a missing retirement anchor, complete versus partial target inventories, missing-is-unknown semantics, one summary per window and payload kind, canonical collection order, actor commit/retirement monotonicity, Fabric capacity bounds, four-state signal residency/transition invariants, exact Request-lineage attachment, and capture noninterference. One actor case, one Fabric resource case, and one four-state signal case are sufficient; tests do not build a cross-product over windows, coverage, actors, resource kinds, or signals.

Diagnostic-trace anchors cover the three capture levels, seven event variants, typed occurrence references, nonempty canonically ordered frames, strictly increasing coordinates, duplicate-key rejection, and capture noninterference. Persistent loom.simulation_execution 3.1 import admits only the narrow System root-lifecycle progress field and rejects any general trace, manifest, chunk, coverage, path, or opaque diagnostic field.

Tests do not pin report layouts, simulator class hierarchies, broad workload matrices, every finding kind, every witness payload, every partial-output combination, arbitrary clock ratios, compression formats, or chunk sizes.