Flexweave
Core Concepts

Lifecycle Facts, Channels, and Signals

Understand raw facts, caller-owned transport, and projected adapter facts.

Flexweave operations emit lifecycle facts. These are mechanics-level facts such as attribute changes, ability attempts, effect execution, effect advancement, and expiration.

EventChannel is a small caller-owned transport and retention primitive. It validates event kinds, optionally retains events, and notifies listeners. Stores do not publish into channels automatically.

use flexweave::{
    AttributeChange, EventChannel, EventChannelDefinition, EventRetention,
    LifecycleEventKind, ObjectId,
};

let definition = EventChannelDefinition::new(
    "attributes/changes",
    [LifecycleEventKind::AttributeChanged],
)
.unwrap();
let mut channel = EventChannel::with_retention(definition, EventRetention::Retain);

channel
    .publish(AttributeChange {
        id: ObjectId::new(1),
        previous: Some(1.0),
        requested: 2.0,
        current: 2.0,
    })
    .unwrap();

assert_eq!(channel.drain_retained().len(), 1);

SignalProjection derives SignalFact values from effect lifecycle facts. Signals are useful when a UI, audio system, scripting layer, analytics sink, or network adapter wants a stable exported fact shape.

use flexweave::{
    EffectExecution, EffectLifecycleEvent, SignalDefinition, SignalDefinitions,
    SignalExportPolicy, SignalKind, SignalProjection, SignalRetentionPolicy,
    SignalTagMatch, Tag, TagSet,
};

#[derive(Clone, Debug, Eq, PartialEq)]
enum Atom {
    Impact,
}

#[derive(Clone, Copy, Debug, Eq, PartialEq)]
enum Payload {
    Impact,
}

let definitions = SignalDefinitions::new([SignalDefinition {
    key: "impact".to_owned(),
    signal_kind: SignalKind::Executed,
    lifecycle_event_kinds: vec![LifecycleEventKind::EffectExecuted],
    tag_match: SignalTagMatch::Any,
    payload_schema: "impact.v1".to_owned(),
    signal_payload: "adapter payload",
    channel_key: "signals/effects".to_owned(),
    category: "effects".to_owned(),
    retention: SignalRetentionPolicy::Retain,
    export: SignalExportPolicy::Export,
    debug_label: "Impact".to_owned(),
    description: "Projected effect execution".to_owned(),
}])
.unwrap();
let projection = SignalProjection::new(definitions);
let event = EffectLifecycleEvent::Executed(EffectExecution {
    active_effect_id: None,
    definition_key: Some("effects/impact".to_owned()),
    source_id: None,
    target_id: ObjectId::new(2),
    tags: TagSet::new([Tag::new([Atom::Impact])]),
    payload: Payload::Impact,
    elapsed_units: None,
});

let facts = projection.project_effect_event(&event);
assert_eq!(facts[0].key, "impact");

The layers are distinct:

  • lifecycle facts describe primitive mechanics
  • channels transport facts when caller code publishes them
  • signals project facts into adapter-oriented categories
  • application events are whatever the consumer runtime builds from those facts