Skip to main content

aidens_wake_kit/
lib.rs

1//! Wake-signal construction for P11 daemon queues.
2
3use aidens_contracts::{ArtifactId, CanonicalToolSideEffectClass, WakeSignalV1};
4use thiserror::Error;
5
6#[derive(Debug, Error)]
7pub enum WakeError {
8    #[error("wake source must not be empty")]
9    EmptySource,
10    #[error("wake signal key must not be empty")]
11    EmptySignalKey,
12}
13
14pub fn wake_signal(
15    namespace_id: ArtifactId,
16    source: impl Into<String>,
17    signal_key: impl Into<String>,
18    payload: serde_json::Value,
19    risk: CanonicalToolSideEffectClass,
20) -> Result<WakeSignalV1, WakeError> {
21    let source = source.into();
22    let signal_key = signal_key.into();
23    if source.trim().is_empty() {
24        return Err(WakeError::EmptySource);
25    }
26    if signal_key.trim().is_empty() {
27        return Err(WakeError::EmptySignalKey);
28    }
29    Ok(WakeSignalV1::new(
30        namespace_id,
31        source,
32        signal_key,
33        payload,
34        risk,
35    ))
36}
37
38#[cfg(test)]
39mod tests {
40    use super::*;
41    use aidens_contracts::DaemonNamespaceV1;
42
43    #[test]
44    fn wake_signal_identity_uses_source_key_and_payload() {
45        let ns = DaemonNamespaceV1::new("wake-test", "target/p11", "daemon");
46        let signal = wake_signal(
47            ns.namespace_id,
48            "filesystem",
49            "README.md:modified",
50            serde_json::json!({"path":"README.md"}),
51            CanonicalToolSideEffectClass::ReadOnly,
52        )
53        .unwrap();
54        assert!(signal.idempotency_key.contains("filesystem"));
55        assert!(signal.idempotency_key.contains("README.md:modified"));
56        assert!(signal.idempotency_key.contains(&signal.payload_digest));
57    }
58
59    #[test]
60    fn empty_signal_key_is_rejected() {
61        let ns = DaemonNamespaceV1::new("wake-test-empty", "target/p11", "daemon");
62        let err = wake_signal(
63            ns.namespace_id,
64            "filesystem",
65            "",
66            serde_json::json!({}),
67            CanonicalToolSideEffectClass::ReadOnly,
68        )
69        .unwrap_err();
70        assert!(matches!(err, WakeError::EmptySignalKey));
71    }
72}