Raxol. Harness. EventBoundary
(Raxol v2.6.1)
View Source
The live-session security seam: converts a live agent contract event
(atom-keyed struct/map, atom payload keys AND atom payload values --
e.g. payload: %{item_type: :tool_use}) into the fixture wire shape
Raxol.Harness.Projection.project/2 and the stall detector already
consume (atom top-level fields; payload with STRING keys and
JSON-shaped values -- exactly what Jason.encode!/1 |> Jason.decode!/1
would produce).
Security posture
A live event crosses a PROCESS boundary (Raxol.Harness.SessionLane's
subscribe/1 delivers {:session_event, session_id, event} messages
from a process this package does not control) and is therefore
untrusted input, not merely differently-shaped input. normalize/1
enforces four properties, every one load-bearing:
- No atom minting.
String.to_atom/1is never called anywhere in this module -- an attacker (or a buggy producer) who controlstype/family/payload key or value strings must never be able to grow the atom table by sending events. Every string stays a string; every already-existing atom on the INPUT side is turned into a string on the way out (never the reverse). - Unknown fields are dropped. The output map carries ONLY the
nine fields the projection/status-strip pipeline understands
(
:id,:turn_id,:ts,:family,:type,:tier,:scope,:provenance,:payload) -- anything else on the input (extra struct fields, a producer's internal bookkeeping) never reaches the surface. - Taint is never laundered.
:provenance.trustaccepts exactly:trustedand:taintedfrom the input; every other value (including an unrecognized atom,nil, or a missing key) is absorbed to:tainted-- this seam may only ever ADD taint on an ambiguous signal, never remove it. :tieris never guessed. Tier decides whether content becomes permanent transcript (Raxol.Harness.Fixture.Event's own:durable/:ephemeralsplit). Anything other than the two literal atoms:durable/:ephemeralis a hard{:error, :invalid_event}-- there is no safe default to fall back to.
:type and :family are the one deliberate exception to "never pass
untyped data through": both pass through UNCHANGED, whether the input
value is an atom or not. Raxol.Harness.Projection.Recovery's own
partitioning already treats a non-atom :type/unrecognized :family
as unrecognized and demotes it safely (N-DORM-04) -- this boundary
would only be "fixing" that by minting a fresh atom out of whatever a
hostile string claims to be, which is exactly the failure mode this
module exists to prevent.
Summary
Functions
Normalize a live event into the fixture wire shape.
Functions
Normalize a live event into the fixture wire shape.
Accepts any map, including a struct (fields are read via Map.get/2,
never struct pattern matching, so any atom-keyed struct works).
Returns {:ok, map} on success; {:error, :invalid_event} when :id,
:ts, :payload, or :tier fail their respective shape checks (see
moduledoc).