Signal lifecycle
Signals are the export boundary, a deterministic, self-contained snapshot of one operation's trust posture, ready to leave the system through a connector.
Signal lifecycle
SignalEngine.generate(...) projects any combination of existing runtime outputs into deterministic SignalEvents wrapped in a SignalExport. It is strictly a generation layer: no networking, no HTTP, no queues, no telemetry, and no communication with WIW. It reads only already-safe serialized fields and duplicates no upstream logic.
flowchart TD IN["Any of: evidence · trust · identitySignal lifecycle, deterministic projection into a portable signal. Source: signals/engine.py.
trust_profile · passport · reputation"] --> G["SignalEngine.generate(...)"] G --> H{"any usable data?"} H -->|no| E0["SignalExport (signal_count 0, signals empty)"] H -->|yes| PJ["project fields with precedence
trust > identity > profile > passport"] PJ --> SID["signal_id = 'sig_' + sha256(type|agent|evidence|receipt|prov|passport|reputation)[:16]"] SID --> EVT["one consolidated SignalEvent"] EVT --> XID["export_id = 'sigx_' + sha256(signal_ids)[:16]"] XID --> EX["SignalExport (signal_count 1)"]
When any input carries data, the engine emits a single consolidated SignalEvent that flattens the operation's ids and posture (trust/reputation scores, compliance status, risk/quality levels, provider/runtime/platform). Field selection uses a fixed precedence, for scores and levels, trust > identity > profile > passport. When no input has data, the export is empty (signal_count 0) rather than an error.
Content-addressed determinism
signal_id= sig_ + SHA-256 oversignal_type | agent_id | evidence_id | receipt_id | provenance_id | passport_id | reputation_id(first 16 hex). No timestamp is in the hash, so the same operation always yields the same signal id.export_id= sigx_ + SHA-256 over the contained signal ids.created_atis injectable viaclock: the only non-deterministic field, and it is outside the id hash by design.
Endpoint & composition
POST /api/v1/signals/export is a thin transport. If evidence is supplied (and truthy, an empty {} is treated as absent), it composes the chain Evidence → Trust → Identity → Trust Profile → Passport → Reputation → SignalExport, but any explicitly supplied layer takes precedence and is never recomputed. The response is the full SignalExport dict.
connectors/) wraps a SignalExport into a ConnectorPayload addressed to a target (WIW, SIEM, data lake, OEM/white-label, analytics, archive), but it too is generation-only: no networking, no queues. The signal lifecycle ends at a portable, deterministic artifact.