Skip to main content

knowdit_kg_model/db/
semantic_finding_link.rs

1//! KG-side `(semantic_node, audit_finding)` edge — one row per pair
2//! emitted by the link agent. The agent produces a strength label
3//! per pair AND a free-form evidence rationale; both land here. The
4//! composite primary key `(semantic_node_id, audit_finding_id)`
5//! enforces uniqueness without needing a separate UNIQUE index.
6//!
7//! See `plan_link.md` §5.1 and §6.2 for the rubric definition that
8//! drives the `strength` value.
9
10use sea_orm::entity::prelude::*;
11
12#[sea_orm::model]
13#[derive(Clone, Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize, DeriveEntityModel)]
14#[sea_orm(table_name = "semantic_finding_link")]
15pub struct Model {
16    #[sea_orm(primary_key, auto_increment = false)]
17    pub semantic_node_id: i32,
18    #[sea_orm(primary_key, auto_increment = false)]
19    pub audit_finding_id: i32,
20    /// Link agent's strength tier for this pair (High / Medium / Low).
21    /// Indexed so downstream read APIs can filter by strength.rank()
22    /// efficiently.
23    #[sea_orm(indexed)]
24    pub strength: crate::link_strength::LinkStrength,
25    /// Free-form rationale the agent emitted alongside the strength
26    /// label. Length floors are enforced at the agent tool handler
27    /// (40+ chars for High/Medium, 15+ for Low). Useful for human
28    /// audit and downstream prompt-building consumers.
29    #[sea_orm(column_type = "Text")]
30    pub evidence: String,
31
32    #[sea_orm(belongs_to, from = "semantic_node_id", to = "id")]
33    pub semantic_node: Option<super::semantic_node::Entity>,
34    #[sea_orm(belongs_to, from = "audit_finding_id", to = "id")]
35    pub audit_finding: Option<super::audit_finding::Entity>,
36}
37
38impl ActiveModelBehavior for ActiveModel {}