Use case
A message in this framework crosses up to three boundaries, and each has different semantics:
| Boundary |
Mechanism |
What arrives |
| In-process |
reference |
the same object; prototype intact, methods work |
| Worker hop |
bare postMessage → structured clone |
a plain object — prototype gone, methods gone; a non-cloneable field throws DataCloneError |
| Cluster wire |
the serializer |
different rules again, depending on the registered serializer and tag definitions |
The worker path is src/runtime/worker/NodeWorkerBackend.ts:96 (this.native.postMessage(value, transfer)) and src/worker/WorkerBroker.ts:102. No serializer is involved; the runtime's structured clone algorithm is.
The test suite exercises the first boundary almost exclusively. So a message type can be green locally, degrade silently across a worker hop, and fail on the wire — and the middle case is the dangerous one, because it produces no error at all. A class instance sent to a worker arrives as a plain object. It does not throw. It fails later, as a match arm that does not fire, a ts-pattern .exhaustive() that throws somewhere unrelated, or a method that is undefined.
There are zero occurrences of structuredClone or DataCloneError anywhere in src/. Nothing in the framework detects, reports, or documents this transition.
Proposed shape
A test-only mode that forces every local delivery through the boundary semantics it would meet in production, so the failure surfaces at development time rather than the first time somebody enables WorkerCluster or joins a second node.
- Serializer round-trip mode. Every local
tell is encoded and decoded before delivery. A message with no serializer binding throws immediately, naming the type and the sending actor.
- Structured-clone mode. The JavaScript-specific half, and the more valuable one. Apply
structuredClone to the payload and report when the round-trip is lossy — specifically when the input had a prototype other than Object.prototype and the output does not. That is the silent case, and it is mechanically detectable.
- Off by default, on in the testkit. The natural default is enabled for
TestKit and disabled in production, since the cost is real. It must be switchable both ways: a user should be able to run their own suite with it off, and to enable it in a staging build.
- Configuration follows the established precedence, and the key must be reachable from
ConfigKeys and read by something in src/ per the dead-key rule.
Worth deciding at implementation time: whether the two modes are one setting with levels or two independent switches. They catch different defects — one a hard failure, the other a silent degradation — which argues for independent.
Acceptance
Verification status
Confirmed by reading and search. grep -rn "structuredClone\|DataCloneError" over src/ returns nothing. The worker send path was read at src/runtime/worker/NodeWorkerBackend.ts:96 and src/worker/WorkerBroker.ts:102; neither consults a serializer. grep for a serialize-messages-style switch across src/config/Reference.ts and src/config/ConfigKeys.ts returns nothing. The structured-clone prototype behaviour is specified by the HTML structured-clone algorithm and is not framework-specific.
Use case
A message in this framework crosses up to three boundaries, and each has different semantics:
postMessage→ structured cloneDataCloneErrorThe worker path is
src/runtime/worker/NodeWorkerBackend.ts:96(this.native.postMessage(value, transfer)) andsrc/worker/WorkerBroker.ts:102. No serializer is involved; the runtime's structured clone algorithm is.The test suite exercises the first boundary almost exclusively. So a message type can be green locally, degrade silently across a worker hop, and fail on the wire — and the middle case is the dangerous one, because it produces no error at all. A class instance sent to a worker arrives as a plain object. It does not throw. It fails later, as a
matcharm that does not fire, ats-pattern.exhaustive()that throws somewhere unrelated, or a method that isundefined.There are zero occurrences of
structuredCloneorDataCloneErroranywhere insrc/. Nothing in the framework detects, reports, or documents this transition.Proposed shape
A test-only mode that forces every local delivery through the boundary semantics it would meet in production, so the failure surfaces at development time rather than the first time somebody enables
WorkerClusteror joins a second node.tellis encoded and decoded before delivery. A message with no serializer binding throws immediately, naming the type and the sending actor.structuredCloneto the payload and report when the round-trip is lossy — specifically when the input had a prototype other thanObject.prototypeand the output does not. That is the silent case, and it is mechanically detectable.TestKitand disabled in production, since the cost is real. It must be switchable both ways: a user should be able to run their own suite with it off, and to enable it in a staging build.ConfigKeysand read by something insrc/per the dead-key rule.Worth deciding at implementation time: whether the two modes are one setting with levels or two independent switches. They catch different defects — one a hard failure, the other a silent degradation — which argues for independent.
Acceptance
structuredCloneand reports the message type.TestKit, disabled in production, switchable both ways.Verification status
Confirmed by reading and search.
grep -rn "structuredClone\|DataCloneError"oversrc/returns nothing. The worker send path was read atsrc/runtime/worker/NodeWorkerBackend.ts:96andsrc/worker/WorkerBroker.ts:102; neither consults a serializer.grepfor aserialize-messages-style switch acrosssrc/config/Reference.tsandsrc/config/ConfigKeys.tsreturns nothing. The structured-clone prototype behaviour is specified by the HTML structured-clone algorithm and is not framework-specific.