use corpora_core::{Diagnostic, Facet, Graph, Impl, Status};
use crate::Rule;
pub struct HeldDecision;
impl Rule for HeldDecision {
fn code(&self) -> &'static str {
"HELD"
}
fn check(&self, g: &Graph, out: &mut Vec<Diagnostic>) {
for r in g.records() {
let Facet::Decision(d) = &r.facet else { continue };
if d.status == Status::Accepted
&& d.implementation == Some(Impl::Absent)
&& d.realized_by.is_empty()
{
let id = r.id.as_ref().map(|i| i.0.as_str()).unwrap_or("<no-id>");
out.push(Diagnostic::warn(
"HELD",
&r.path,
format!("{id} accepted but unrealized and unscheduled"),
));
}
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use corpora_core::*;
use std::sync::Arc;
fn decision(id: &str, status: Status, implementation: Option<Impl>, realized: Vec<Id>) -> Record {
Record::minimal(
Some(Id(id.into())),
DocPath(format!("{id}.md")),
Kind::Decision,
Lifecycle::Current,
Authority::Normative,
Facet::Decision(DecisionFacet {
status,
date: Date("2026-06-21".into()),
implementation,
fork: None,
realized_by: realized,
}),
)
}
#[test]
fn flags_unrealized_unscheduled() {
let held = decision("D1", Status::Accepted, Some(Impl::Absent), vec![]);
let scheduled = decision("D2", Status::Accepted, Some(Impl::Absent), vec![Id("roadmap.v0".into())]);
let done = decision("D3", Status::Accepted, Some(Impl::Implemented), vec![]);
let (g, _) = Graph::build(vec![Arc::new(held), Arc::new(scheduled), Arc::new(done)]);
let mut out = Vec::new();
HeldDecision.check(&g, &mut out);
assert_eq!(out.len(), 1);
assert_eq!(out[0].code, "HELD");
}
}