Skip to main content

khive_pack_code/
pack.rs

1//! `CodePack` struct, `Pack` impl, self-registration factory, and `PackRuntime` impl.
2
3use std::sync::Arc;
4
5use async_trait::async_trait;
6use serde_json::Value;
7
8use khive_runtime::pack::PackRuntime;
9use khive_runtime::{
10    KhiveRuntime, KindHook, NamespaceToken, NoteKindSpec, RuntimeError, SchemaPlan, VerbRegistry,
11};
12use khive_types::{EdgeEndpointRule, HandlerDef, Pack};
13
14use crate::hook::FindingHook;
15use crate::vocab::{CODE_EDGE_RULES, CODE_NOTE_KIND_SPECS};
16
17/// Code ontology pack — additive edge rules over four concept subtypes plus
18/// the `finding` audit-observation note kind. No verbs (ADR-085 D1).
19pub struct CodePack {
20    #[allow(dead_code)]
21    runtime: KhiveRuntime,
22}
23
24impl Pack for CodePack {
25    const NAME: &'static str = "code";
26    const NOTE_KINDS: &'static [&'static str] = &["finding"];
27    const ENTITY_KINDS: &'static [&'static str] = &[];
28    const HANDLERS: &'static [HandlerDef] = &[];
29    const EDGE_RULES: &'static [EdgeEndpointRule] = &CODE_EDGE_RULES;
30    const REQUIRES: &'static [&'static str] = &["kg"];
31    const NOTE_KIND_SPECS: &'static [NoteKindSpec] = &CODE_NOTE_KIND_SPECS;
32    const SCHEMA_PLAN: Option<khive_runtime::PackSchemaPlan> = None;
33}
34
35impl CodePack {
36    pub fn new(runtime: KhiveRuntime) -> Self {
37        Self { runtime }
38    }
39}
40
41// ── inventory self-registration ───────────────────────────────────────────────
42
43struct CodePackFactory;
44
45impl khive_runtime::PackFactory for CodePackFactory {
46    fn name(&self) -> &'static str {
47        "code"
48    }
49
50    fn requires(&self) -> &'static [&'static str] {
51        &["kg"]
52    }
53
54    fn create(&self, runtime: KhiveRuntime) -> Box<dyn khive_runtime::PackRuntime> {
55        Box::new(CodePack::new(runtime))
56    }
57}
58
59inventory::submit! { khive_runtime::PackRegistration(&CodePackFactory) }
60
61#[async_trait]
62impl PackRuntime for CodePack {
63    fn name(&self) -> &str {
64        <CodePack as Pack>::NAME
65    }
66
67    fn note_kinds(&self) -> &'static [&'static str] {
68        <CodePack as Pack>::NOTE_KINDS
69    }
70
71    fn entity_kinds(&self) -> &'static [&'static str] {
72        <CodePack as Pack>::ENTITY_KINDS
73    }
74
75    fn handlers(&self) -> &'static [HandlerDef] {
76        <CodePack as Pack>::HANDLERS
77    }
78
79    fn edge_rules(&self) -> &'static [EdgeEndpointRule] {
80        <CodePack as Pack>::EDGE_RULES
81    }
82
83    fn requires(&self) -> &'static [&'static str] {
84        <CodePack as Pack>::REQUIRES
85    }
86
87    fn note_kind_specs(&self) -> &'static [NoteKindSpec] {
88        <CodePack as Pack>::NOTE_KIND_SPECS
89    }
90
91    fn schema_plan(&self) -> SchemaPlan {
92        SchemaPlan {
93            pack: "code",
94            statements: &[],
95        }
96    }
97
98    fn kind_hook(&self, kind: &str) -> Option<Arc<dyn KindHook>> {
99        match kind {
100            "finding" => Some(Arc::new(FindingHook)),
101            _ => None,
102        }
103    }
104
105    async fn dispatch(
106        &self,
107        verb: &str,
108        _params: Value,
109        _registry: &VerbRegistry,
110        _token: &NamespaceToken,
111    ) -> Result<Value, RuntimeError> {
112        Err(RuntimeError::InvalidInput(format!(
113            "code pack does not handle verb {verb:?}"
114        )))
115    }
116}
117
118#[cfg(test)]
119mod tests {
120    use khive_types::Pack;
121
122    use super::CodePack;
123
124    #[test]
125    fn code_pack_declares_adr085_metadata() {
126        assert_eq!(<CodePack as Pack>::NAME, "code");
127        assert_eq!(<CodePack as Pack>::NOTE_KINDS, &["finding"]);
128        assert!(<CodePack as Pack>::ENTITY_KINDS.is_empty());
129        assert!(<CodePack as Pack>::HANDLERS.is_empty());
130        assert_eq!(<CodePack as Pack>::REQUIRES, &["kg"]);
131        assert!(<CodePack as Pack>::SCHEMA_PLAN.is_none());
132    }
133}