Any Graph, wasm-constructed or not, live or disposed.
The frozen CauslEngineIdentity for that graph.
TOTAL OVER Graph, AND ONLY OVER Graph. Every Graph has an answer,
including one this module never touched; there is no undefined return to
branch on and no "ask again later" state. Anything that is not a Graph is
REFUSED with CauslNotAGraphError rather than answered, because
totality over Graph silently becoming totality over unknown is how a
forgotten await gets attributed to the TS floor.
The totality rests on an ordering fact rather than on a default:
constructWasmGraphSync is the only codepath in this package that produces
a Graph whose commits execute in Rust, and it stamps the identity before
it returns. It is the single construct shared by createCauslWasm,
createCauslWasmSync and the registry FLIP a preloaded
createCausl() routes through. So a graph carrying no stamp provably did
not come from the Rust engine, and reporting the TS floor for it is a
conclusion, not a guess.
That claim is load-bearing, so the two routes that look like
counterexamples are discharged by name here, and pinned by test in
test/graph-engine-identity-295.test.ts so the argument is executed rather
than merely asserted:
createCausl({ backend: 'auto' }) — public (../src/types.ts:762).
Pre-#122 this dispatched into ../src/auto-adapt-wrapper.ts, whose
performSwap replaces inner with a different Graph mid-life; a
graph that became something else after construction would defeat a
stamp applied at construction. #122 retired that dispatch —
../src/graph.ts:1109 now only warns and falls through to the ordinary
FLIP — and createAutoAdaptGraph has no callers left in the package.
'auto' therefore reaches the Rust engine only via
constructWasmGraphSync, and is stamped like any other FLIP graph.loadWasmBackend().__graph(): this bullet described the Phase-1
WasmBackend, which published a __graph() accessor onto a wrapped
pure-TypeScript engine, so an adopter could get a Graph out of the
loader without passing through constructWasmGraphSync and
causlEngineOf correctly reported 'typescript' for it. #279 slice
S12a deleted the wrap and the accessor with it, so the route no longer
exists. It is recorded because the 'typescript' value it justified is
retained on the union.GRAPH-SCOPED. Contrast isCauslWasmPreloaded, which reads a
process-wide slot: after one preloadCauslWasm() that predicate answers
true for every graph in the process, including the TS-floor graphs the
pre-0.5.0 engine / fallbackToTs opts returned. This function
distinguishes them.
NARROW, DON'T ASSERT. The return is a discriminated union
(CauslEngineIdentity); if (id.engine === 'rust-wasm') gives you a
non-optional bridge, and if (id.mode === 'ts-floor') gives you a
tsFloorReason. Neither needs a !.
STABLE. The returned record is frozen, and repeated calls for one graph
return the identical object, so it is safe to use as a memoisation key
(Object.is-comparable) alongside stats().nodeVersion.
NOT A LIVENESS CHECK. This reports what DID execute the graph, and keeps
reporting it after disposal. __wasmBackendForTests answers the
other question — whether a backend is still LIVE for the graph — and goes
to undefined at teardown. The two diverging after dispose() is the
intended behaviour of both, not a disagreement between them.
ONE CAVEAT, stated because it is the only way this can mislead: the stamp
lives in a module-scoped WeakMap, so it is per COPY of this module. A
host that loads @causl/causl-wasm-ts/wasm twice — a duplicated
node_modules entry, or the ESM and CJS builds side by side — will have
one copy report the TS floor for the other copy's graphs. That hazard is
not new here; the preload cache, the registry FLIP slot and the #111
teardown map all share it, and a single resolved copy is a precondition
for the package working at all.
Importing this subpath solely to call this function does NOT change which
engine createCausl() selects. The import registers the sync constructor
into the main-bundle registry slot, but that slot is only consulted when a
module is preloaded for the default bridge (isPreloadedForDefaultBridge: () => isCauslWasmPreloaded() at the registerWasmSyncEngine call below),
and the import performs no preload. It does cost the wasm chunk.
CauslNotAGraphError when graph is not a Graph.
import { causlEngineOf } from '@causl/causl-wasm-ts/wasm'
// Narrowing, not asserting: `bridge` is a BridgeId inside this branch.
const id = causlEngineOf(graph)
if (id.engine !== 'rust-wasm') {
throw new Error(`refusing to publish a benchmark run from ${id.mode}`)
}
report.attribution = { engine: id.engine, bridge: id.bridge }
#295 — ask a
Graphwhich engine executed it.