Skip to content

Enable Akka serialization verification across actor tests #961

@Aaronontheweb

Description

@Aaronontheweb

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:

  1. Add a binding (proto manifest + mapper or fallback serializer entry), or
  2. 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

  • Document the verification-on-by-default convention in the Akka testing guidance (dotnet-skills:akka-testing-patterns or equivalent).
  • Add a CI/build check that flags new types in Netclaw.Actors.Sessions / Netclaw.Actors.Channels / etc. without either a serialization binding or an INoSerializationVerificationNeeded marker — at minimum a lint pass.
  • Backfill verification on existing tests that exercise 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

  • 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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions