pub mod element;
pub mod id;
pub use element::Component;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ElementSource {
BuiltIn,
Plugin,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ElementShape {
Component,
InlineMarker,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ElementAuthority {
SharedOperatorAuthoritative,
GranularTrackedWork,
DerivedProjection,
Archive,
Signals,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ElementWritePolicy {
MergeOnly,
GranularOnly,
ProjectionOnly,
ArchiveOnly,
SignalReconcile,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ElementSchedulingRole {
None,
ActiveQueue,
RunnableWorkSource,
ParkedWorkSource,
ReviewGate,
CompletionArchive,
Status,
Signals,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ElementRealtimeModel {
None,
Exchange,
TrackedItems,
Queue,
Status,
Archive,
Signals,
Boundary,
Unknown,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ElementCompositionRole {
LocalOnly,
Producer,
Consumer,
Observer,
ArchiveTarget,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct ElementDescriptor {
pub name: &'static str,
pub aliases: &'static [&'static str],
pub source: ElementSource,
pub shape: ElementShape,
pub authority: ElementAuthority,
pub write_policy: ElementWritePolicy,
pub scheduling_role: ElementSchedulingRole,
pub realtime_model: ElementRealtimeModel,
pub composition_role: ElementCompositionRole,
pub realtime: bool,
}
impl ElementDescriptor {
pub fn matches_name(self, name: &str) -> bool {
self.name == name || self.aliases.contains(&name)
}
pub fn canonical_name(self, name: &str) -> Option<&'static str> {
self.matches_name(name).then_some(self.name)
}
pub fn as_registration(self) -> ElementRegistration {
ElementRegistration {
name: self.name.to_string(),
aliases: self
.aliases
.iter()
.map(|alias| (*alias).to_string())
.collect(),
source: self.source,
shape: self.shape,
authority: self.authority,
write_policy: self.write_policy,
scheduling_role: self.scheduling_role,
realtime_model: self.realtime_model,
composition_role: self.composition_role,
realtime: self.realtime,
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ElementRegistration {
pub name: String,
pub aliases: Vec<String>,
pub source: ElementSource,
pub shape: ElementShape,
pub authority: ElementAuthority,
pub write_policy: ElementWritePolicy,
pub scheduling_role: ElementSchedulingRole,
pub realtime_model: ElementRealtimeModel,
pub composition_role: ElementCompositionRole,
pub realtime: bool,
}
impl ElementRegistration {
pub fn matches_name(&self, name: &str) -> bool {
self.name == name || self.aliases.iter().any(|alias| alias == name)
}
}
pub trait ElementPlugin {
fn element_descriptors(&self) -> Vec<ElementRegistration>;
}
#[cfg(test)]
mod tests {
use super::*;
const BACKLOG: ElementDescriptor = ElementDescriptor {
name: "backlog",
aliases: &["pending"],
source: ElementSource::BuiltIn,
shape: ElementShape::Component,
authority: ElementAuthority::GranularTrackedWork,
write_policy: ElementWritePolicy::GranularOnly,
scheduling_role: ElementSchedulingRole::RunnableWorkSource,
realtime_model: ElementRealtimeModel::TrackedItems,
composition_role: ElementCompositionRole::Producer,
realtime: true,
};
#[test]
fn descriptor_matches_aliases_and_canonicalizes() {
assert!(BACKLOG.matches_name("backlog"));
assert!(BACKLOG.matches_name("pending"));
assert_eq!(BACKLOG.canonical_name("pending"), Some("backlog"));
assert_eq!(BACKLOG.canonical_name("queue"), None);
}
#[test]
fn built_in_descriptor_converts_to_plugin_registration_shape() {
let registration = BACKLOG.as_registration();
assert_eq!(registration.name, "backlog");
assert_eq!(registration.aliases, vec!["pending"]);
assert!(registration.matches_name("pending"));
}
#[test]
fn manifest_stays_pure() {
let manifest = include_str!("../Cargo.toml");
for forbidden in [
"agent-doc-orchestration",
"interprocess",
"notify",
"rusqlite",
"tmux-router",
] {
assert!(
!manifest.contains(forbidden),
"agent-doc-element must stay pure; found forbidden dependency {forbidden}"
);
}
}
}