You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
stoicheion::SignalKind is the canonical seven-domain signal type, but Semaino independently defines its domain identity three times:
alert.rs maps each variant to a numeric fingerprint discriminant.
convergence.rs repeats that numeric mapping and separately fixes storage at eight slots.
aggregator.rs defines a parallel KindKey enum for baseline ownership.
The first two copies assign known domains 0..=6 and every future variant 255. The aggregator instead folds Osint and every future variant into KindKey::Osint. Because SignalKind is #[non_exhaustive], adding a new domain does not force any of these downstream mappings to change.
Verified against mainc8e671845adca3e5b57a205d08aca31eadbc6000.
Evidence
crates/stoicheion/src/signal.rs:237-255 defines the authoritative SignalKind variants: RF, mesh, network, proximity, GPS, environmental, and OSINT.
crates/semaino/src/alert.rs:314-326 defines private kind_discriminant: known variants map to 0..=6; the wildcard maps to 255. That value participates in AlertFingerprint, so it controls alert suppression identity.
crates/semaino/src/convergence.rs:92-108 declares DOMAIN_SLOTS = 8, reserving indices 0..=6 plus one shared future-variant slot. convergence.rs:295-310 repeats the alert mapping independently.
crates/semaino/src/aggregator.rs:52-82 defines a separate seven-variant KindKey. Its wildcard maps both current Osint and every future SignalKind variant to Osint.
These identities govern three different semantics: which signals share a temporal baseline, which domains count as distinct convergence evidence, and which alerts suppress one another. A newly added domain can therefore:
contaminate the OSINT baseline;
collide with every other future domain in convergence;
collide with every other future domain in alert suppression; and
acquire different identities in different subsystems without a compiler failure.
This is not a trust-boundary mirror. All three consumers are interpreting the same in-process SignalKind fact.
Desired correction
Make the defining crate own one domain identity. A suitable shape is a SignalDomain enum plus SignalKind::domain() implemented inside stoicheion, where adding a SignalKind variant makes an exhaustive match fail to compile until its domain is assigned. If a stable numeric code is required for fingerprints or storage, make that a method of SignalDomain rather than another matcher.
Have Semaino baseline keys, convergence slots, and alert fingerprints consume that type/code. Derive bounded storage cardinality from the canonical domain set or use a keyed structure that does not require a second maintained slot count.
Done when:
one implementation maps SignalKind to domain identity;
adding a new SignalKind cannot compile until its domain identity is decided;
future domains cannot silently alias OSINT or a shared sentinel;
alert, convergence, and baseline tests use one shared domain table; and
no private seven-way SignalKind domain matcher remains in Semaino.
Finding
stoicheion::SignalKindis the canonical seven-domain signal type, but Semaino independently defines its domain identity three times:alert.rsmaps each variant to a numeric fingerprint discriminant.convergence.rsrepeats that numeric mapping and separately fixes storage at eight slots.aggregator.rsdefines a parallelKindKeyenum for baseline ownership.The first two copies assign known domains
0..=6and every future variant255. The aggregator instead foldsOsintand every future variant intoKindKey::Osint. BecauseSignalKindis#[non_exhaustive], adding a new domain does not force any of these downstream mappings to change.Verified against
mainc8e671845adca3e5b57a205d08aca31eadbc6000.Evidence
crates/stoicheion/src/signal.rs:237-255defines the authoritativeSignalKindvariants: RF, mesh, network, proximity, GPS, environmental, and OSINT.crates/semaino/src/alert.rs:314-326defines privatekind_discriminant: known variants map to0..=6; the wildcard maps to255. That value participates inAlertFingerprint, so it controls alert suppression identity.crates/semaino/src/convergence.rs:92-108declaresDOMAIN_SLOTS = 8, reserving indices0..=6plus one shared future-variant slot.convergence.rs:295-310repeats the alert mapping independently.crates/semaino/src/aggregator.rs:52-82defines a separate seven-variantKindKey. Its wildcard maps both currentOsintand every futureSignalKindvariant toOsint.Why this matters
These identities govern three different semantics: which signals share a temporal baseline, which domains count as distinct convergence evidence, and which alerts suppress one another. A newly added domain can therefore:
This is not a trust-boundary mirror. All three consumers are interpreting the same in-process
SignalKindfact.Desired correction
Make the defining crate own one domain identity. A suitable shape is a
SignalDomainenum plusSignalKind::domain()implemented insidestoicheion, where adding aSignalKindvariant makes an exhaustive match fail to compile until its domain is assigned. If a stable numeric code is required for fingerprints or storage, make that a method ofSignalDomainrather than another matcher.Have Semaino baseline keys, convergence slots, and alert fingerprints consume that type/code. Derive bounded storage cardinality from the canonical domain set or use a keyed structure that does not require a second maintained slot count.
Done when:
SignalKindto domain identity;SignalKindcannot compile until its domain identity is decided;SignalKinddomain matcher remains in Semaino.