Summary
Turn on Akka's SerializeAllMessages / SerializeAllCreators (or the equivalent Akka.Hosting.TestKit knobs) for every actor-touching test, and mark non-serializable internal messages with INoSerializationVerificationNeeded. This catches missing serialization-bindings at test time instead of in production.
Motivating example
Today MemoriesDistilledV2 (added recently in SessionMemoryObserverActor.cs) is being created at runtime but isn't in NetclawAkkaHostingExtensions.WithNetclawSerialization's boundTypes list, isn't in NetclawProtobufSerializer.TypeToManifest, and has no NetclawProtoMapper mapping. Three sessions in a 4-minute window today logged:
[ERR] Rejected to persist event type [Netclaw.Actors.Sessions.MemoriesDistilledV2]
... due to [No serializer binding found for type MemoriesDistilledV2.
Configure a binding in 'akka.actor.serialization-bindings' or set
'akka.actor.serialization-settings.allow-unregistered-types = true'
to use the default fallback.]
The type compiles, the actor wires up, the existing tests pass — but the moment the production persistence journal sees the type, Akka rejects it. Strict serialization is doing its job at runtime; tests just don't exercise it.
Proposal
For every Akka.Hosting.TestKit test class touching actors:
- Enable serialization verification on the
ActorSystem (write + roundtrip on every message).
- For messages that legitimately don't need serialization (in-process control messages, command DSL types that never cross an actor boundary), mark with
INoSerializationVerificationNeeded and document why.
For new types intended to be persisted or remoted, the test author must either:
- Add a binding (proto manifest + mapper or fallback serializer entry), or
- Mark the type with
INoSerializationVerificationNeeded if it'll never be serialized.
Either choice forces the question to be answered at code-review / CI time, not at 4 a.m. on production.
Why this matters
Akka's strict serialization is a real safety rail — it's the difference between "schema drift fails loudly" and "schema drift silently writes garbage." Without verification at test time, the rail is only enforced in production, which is the worst place to find the gap.
Acceptance criteria
Out of scope
- Choosing between
SerializeAllMessages (broad) vs. a narrower opt-in. The narrowest viable scope that still catches missing bindings is fine.
- Migrating any existing serializer choices. This is about coverage, not changing what's serialized how.
Summary
Turn on Akka's
SerializeAllMessages/SerializeAllCreators(or the equivalentAkka.Hosting.TestKitknobs) for every actor-touching test, and mark non-serializable internal messages withINoSerializationVerificationNeeded. This catches missingserialization-bindingsat test time instead of in production.Motivating example
Today
MemoriesDistilledV2(added recently inSessionMemoryObserverActor.cs) is being created at runtime but isn't inNetclawAkkaHostingExtensions.WithNetclawSerialization'sboundTypeslist, isn't inNetclawProtobufSerializer.TypeToManifest, and has noNetclawProtoMappermapping. Three sessions in a 4-minute window today logged:The type compiles, the actor wires up, the existing tests pass — but the moment the production persistence journal sees the type, Akka rejects it. Strict serialization is doing its job at runtime; tests just don't exercise it.
Proposal
For every
Akka.Hosting.TestKittest class touching actors:ActorSystem(write + roundtrip on every message).INoSerializationVerificationNeededand document why.For new types intended to be persisted or remoted, the test author must either:
INoSerializationVerificationNeededif it'll never be serialized.Either choice forces the question to be answered at code-review / CI time, not at 4 a.m. on production.
Why this matters
Akka's strict serialization is a real safety rail — it's the difference between "schema drift fails loudly" and "schema drift silently writes garbage." Without verification at test time, the rail is only enforced in production, which is the worst place to find the gap.
Acceptance criteria
dotnet-skills:akka-testing-patternsor equivalent).Netclaw.Actors.Sessions/Netclaw.Actors.Channels/ etc. without either a serialization binding or anINoSerializationVerificationNeededmarker — at minimum a lint pass.LlmSessionActor,SessionMemoryObserverActor, channel binding actors, reminders, and sub-agents. Each test class enables verification or documents why it's excluded.MemoriesDistilledV2(and any sibling types added since the last serialization-binding refresh) gets its binding added with a regression test that fails loudly if it ever goes missing again.Out of scope
SerializeAllMessages(broad) vs. a narrower opt-in. The narrowest viable scope that still catches missing bindings is fine.