use std::collections::BTreeSet;
use std::env;
use std::fmt::Write as _;
use std::io::IsTerminal;
use serde::Serialize;
use crate::config::env_registry::{EnvVar, is_set, read, read_os};
use crate::core::agent_detect::{AgentInventoryReport, InstalledAgentDetectionReport};
use crate::core::capabilities::CapabilitiesReport;
use crate::core::check::CheckReport;
use crate::core::context::ContextPackOutputOptions;
use crate::core::curate::{
CurateApplyReport, CurateCandidatesReport, CurateDispositionReport, CurateReviewReport,
CurateShowReport, CurateValidateReport, ReflectionIngestReport, ReflectionProposeReport,
};
use crate::core::degraded_aggregation::{
AggregatedDegradation, DegradationAggregationInput, aggregate_degraded_entries,
};
use crate::core::degraded_honesty::{RepairCommandKind, classify_repair_command};
use crate::core::doctor::{
CheckResult, CheckSeverity, CheckTier, DependencyBlockedFeature, DependencyContractEntry,
DependencyDiagnosticsReport, DependencyFeatureProfile, DependencyOptionalFeatureProfile,
DependencySource, DoctorMeshAutoEnrollmentReport, DoctorReport, FixPlan,
FrankenDependencyHealth, FrankenHealthReport, IntegrityCanaryReport, IntegrityDiagnosticCheck,
IntegrityDiagnosticDegradation, IntegrityDiagnosticsReport,
};
use crate::core::health::{
HealthReport, HealthScorecardReport, StructuralHealthDegradation, StructuralHealthReport,
};
use crate::core::memory::{
MemoryDetails, MemoryHistoryReport, MemoryListReport, MemoryShowReport, memory_validity,
};
use crate::core::outcome::{OutcomeQuarantineListReport, OutcomeQuarantineReviewReport};
use crate::core::quarantine::{QuarantineDegradation, QuarantineEntry, QuarantineReport};
use crate::core::recorder::RECORDER_EVENTS_LIST_SCHEMA_V1;
use crate::core::rule::{
PlaybookExtractReport, RULE_ADD_SCHEMA_V1, RULE_LIST_SCHEMA_V1, RULE_MARK_SCHEMA_V1,
RULE_SHOW_SCHEMA_V1, RULE_UPDATE_SCHEMA_V1, RuleAddReport, RuleListReport, RuleMarkReport,
RuleProtectReport, RuleShowReport, RuleUpdateReport,
};
use crate::core::status::{
DegradationReport, MeshStorageStatusReport, StatusReport, StatusSkylineReport,
};
use crate::core::store_integrity::{StoreIntegrityReport, StoreIntegrityStatus};
use crate::core::swarm_brief::{RchWorkerPressureObservation, RchWorkerPressureReport};
use crate::core::tailscale_probe::{TailscaleLocalReport, TailscaleProbeDegradation};
use crate::core::why::WhyReport;
use crate::core::{BuildProvenanceDegradation, VERSION_PROVENANCE_SCHEMA_V1, VersionReport};
use crate::eval::{EvaluationReport, EvaluationStatus, FixtureListEntry, ScenarioValidationResult};
use crate::models::decision::{DecisionPlane, DecisionPlaneMetadata, DecisionRecord};
use crate::models::{
DomainError, ERROR_SCHEMA_V2, InstallCheckReport, InstallPlanReport, PACK_SCHEMA_V2,
ProducerMetadata, RESPONSE_SCHEMA_V0, RESPONSE_SCHEMA_V2, RecoveryAction, RecoveryKind,
degraded_recovery_actions,
};
use crate::pack::{
ConflictEntry, ConsensusEntry, ConsensusProducer, ContextResponse, ContextResponseDegradation,
ContextResponsePagination, ContextResponseSeverity, PACK_BUDGET_TOO_SMALL_CODE,
PACK_CONCURRENT_LIMIT_REACHED_CODE, PackAdmissionPosture, PackAdvisoryBanner, PackAdvisoryNote,
PackAssemblySlo, PackEvidenceItem, PackFreshnessAnchorFacet, PackFreshnessFacet,
PackItemProvenance, PackOmission, PackOmissionMetrics, PackQualityMetrics, PackSectionMetric,
PackSelectedItem, PackSelectionAudit, PackSelectionStep, RenderedPackProvenance,
};
use crate::policy::{redact_secret_like_content, redaction_placeholder};
use crate::steward::{
MAINTENANCE_JOB_LIST_SCHEMA_V1, MAINTENANCE_JOB_ROW_SCHEMA_V1, MAINTENANCE_JOB_SHOW_SCHEMA_V1,
MAINTENANCE_RUN_SCHEMA_V1, MAINTENANCE_STATUS_SCHEMA_V1,
};
pub mod governor;
pub mod jsonl_export;
pub(crate) mod markdown;
pub mod streaming;
pub use crate::models::DegradationSeverity;
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
pub enum Renderer {
#[default]
Human,
Json,
Toon,
Jsonl,
Compact,
Hook,
Markdown,
}
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
pub enum ResponseSchemaVersion {
V0,
#[default]
V1,
}
impl Renderer {
#[must_use]
pub const fn as_str(self) -> &'static str {
match self {
Self::Human => "human",
Self::Json => "json",
Self::Toon => "toon",
Self::Jsonl => "jsonl",
Self::Compact => "compact",
Self::Hook => "hook",
Self::Markdown => "markdown",
}
}
#[must_use]
pub const fn is_machine_readable(self) -> bool {
matches!(self, Self::Json | Self::Jsonl | Self::Compact | Self::Hook)
}
}
/// Field profile controls the verbosity of JSON output.
///
/// - `Minimal`: IDs, status, version only — bare minimum for scripting
/// - `Summary`: + top-level metrics and counts
/// - `Standard`: + arrays with items, but without verbose details
/// - `Full`: everything including provenance, why, debug info
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
pub enum FieldProfile {
Minimal,
Summary,
#[default]
Standard,
Full,
}
impl FieldProfile {
#[must_use]
pub const fn as_str(self) -> &'static str {
match self {
Self::Minimal => "minimal",
Self::Summary => "summary",
Self::Standard => "standard",
Self::Full => "full",
}
}
#[must_use]
pub const fn include_arrays(self) -> bool {
matches!(self, Self::Standard | Self::Full)
}
#[must_use]
pub const fn include_summary_metrics(self) -> bool {
!matches!(self, Self::Minimal)
}
#[must_use]
pub const fn include_verbose_details(self) -> bool {
matches!(self, Self::Full)
}
#[must_use]
pub const fn include_provenance(self) -> bool {
matches!(self, Self::Full)
}
}
/// Parsed selector for the global `--fields` flag.
///
/// A selector may be a preset (`minimal`, `summary`, `standard`, `full`), an
/// explicit field list (`docId,score,source`), or a preset plus additions
/// (`minimal,why`). Field names are canonical response keys and are applied to
/// the `data` payload only; envelope fields always remain present.
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct FieldSelector {
raw: String,
preset: Option<FieldProfile>,
explicit_fields: Vec<String>,
conflicting_presets: Vec<String>,
}
impl FieldSelector {
#[must_use]
pub fn parse(raw: &str) -> Self {
let mut preset = None;
let mut explicit_fields = Vec::new();
let mut conflicting_presets = Vec::new();
for token in raw
.split(',')
.map(str::trim)
.filter(|token| !token.is_empty())
{
if let Some(value) = token.strip_prefix("preset=") {
if let Some(profile) = parse_field_profile(value) {
if preset.replace(profile).is_some() {
conflicting_presets.push(token.to_string());
}
} else {
explicit_fields.push(token.to_string());
}
} else if let Some(profile) = parse_field_profile(token) {
if preset.is_none() {
preset = Some(profile);
} else {
conflicting_presets.push(token.to_string());
}
} else {
explicit_fields.push(token.to_string());
}
}
Self {
raw: raw.trim().to_string(),
preset,
explicit_fields,
conflicting_presets,
}
}
#[must_use]
pub fn standard() -> Self {
Self {
raw: "standard".to_string(),
preset: Some(FieldProfile::Standard),
explicit_fields: Vec::new(),
conflicting_presets: Vec::new(),
}
}
#[must_use]
pub fn raw(&self) -> &str {
&self.raw
}
#[must_use]
pub const fn preset(&self) -> FieldProfile {
match self.preset {
Some(profile) => profile,
None => FieldProfile::Standard,
}
}
#[must_use]
pub fn render_profile(&self) -> FieldProfile {
if self.needs_full_render() {
FieldProfile::Full
} else {
self.preset()
}
}
#[must_use]
pub fn needs_full_render(&self) -> bool {
!self.explicit_fields.is_empty() || self.preset.is_none()
}
#[must_use]
pub fn has_conflicting_presets(&self) -> bool {
!self.conflicting_presets.is_empty()
}
}
impl Default for FieldSelector {
fn default() -> Self {
Self::standard()
}
}
impl std::str::FromStr for FieldSelector {
type Err = String;
fn from_str(raw: &str) -> Result<Self, Self::Err> {
Ok(Self::parse(raw))
}
}
fn parse_field_profile(raw: &str) -> Option<FieldProfile> {
match raw.trim().to_ascii_lowercase().as_str() {
"minimal" => Some(FieldProfile::Minimal),
"summary" => Some(FieldProfile::Summary),
"standard" => Some(FieldProfile::Standard),
"full" | "*" => Some(FieldProfile::Full),
_ => None,
}
}
const FIELD_PRESETS_AVAILABLE: &[&str] = &["minimal", "summary", "standard", "full"];
/// Cards output profile (EE-341).
///
/// Controls which cards are included in structured output:
/// - `None`: No cards in output (minimal response)
/// - `Summary`: One-line card summaries only
/// - `Math`: Include mathematical artifacts and certificates
/// - `Full`: All cards with full provenance and explanations
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
pub enum CardsProfile {
None,
Summary,
#[default]
Math,
Full,
}
impl CardsProfile {
#[must_use]
pub const fn as_str(self) -> &'static str {
match self {
Self::None => "none",
Self::Summary => "summary",
Self::Math => "math",
Self::Full => "full",
}
}
#[must_use]
pub const fn include_cards(self) -> bool {
!matches!(self, Self::None)
}
#[must_use]
pub const fn include_math(self) -> bool {
matches!(self, Self::Math | Self::Full)
}
#[must_use]
pub const fn include_provenance(self) -> bool {
matches!(self, Self::Full)
}
}
/// Schema identifier for cards output.
pub const CARDS_SCHEMA_V1: &str = "ee.cards.v1";
/// MCP protocol version advertised by the optional stdio adapter.
pub const MCP_PROTOCOL_VERSION: &str = "2024-11-05";
/// Schema identifier for the MCP manifest data payload.
pub const MCP_MANIFEST_SCHEMA_V1: &str = "ee.mcp.manifest.v1";
/// Schema identifier for the environment attestation payload.
pub const ENVIRONMENT_ATTESTATION_SCHEMA_V1: &str = "ee.environment_attestation.v1";
/// Schema identifier for CI proof-lane queue and artifact freshness snapshots.
pub const CI_PROOF_LANE_SNAPSHOT_SCHEMA_V1: &str = "ee.ci_proof_lane_snapshot.v1";
/// Schema identifier for source-bound remote build artifact manifests.
pub const REMOTE_BUILD_ARTIFACT_MANIFEST_SCHEMA_V1: &str = "ee.remote_build_artifact_manifest.v1";
/// Schema identifier for consumer verification of remote artifact manifests.
pub const REMOTE_BUILD_ARTIFACT_VERIFICATION_SCHEMA_V1: &str =
"ee.remote_build_artifact_manifest.verification.v1";
/// Schema identifier for proof-broker fingerprints and ledger rows.
pub const PROOF_BROKER_SCHEMA_V1: &str = "ee.proof_broker.v1";
/// A single card in structured output.
#[derive(Clone, Debug)]
pub struct Card {
pub id: String,
pub kind: CardKind,
pub title: String,
pub summary: Option<String>,
pub math: Option<CardMath>,
pub provenance: Option<String>,
}
impl Card {
#[must_use]
pub fn new(id: impl Into<String>, kind: CardKind, title: impl Into<String>) -> Self {
Self {
id: id.into(),
kind,
title: title.into(),
summary: None,
math: None,
provenance: None,
}
}
pub fn with_summary(mut self, summary: impl Into<String>) -> Self {
self.summary = Some(summary.into());
self
}
pub fn with_math(mut self, math: CardMath) -> Self {
self.math = Some(math);
self
}
pub fn with_provenance(mut self, provenance: impl Into<String>) -> Self {
self.provenance = Some(provenance.into());
self
}
#[must_use]
pub fn to_json(&self, profile: CardsProfile) -> String {
let mut b = JsonBuilder::with_capacity(256);
b.field_str("id", &self.id);
b.field_str("kind", self.kind.as_str());
b.field_str("title", &self.title);
if profile.include_cards() {
if let Some(ref summary) = self.summary {
b.field_str("summary", summary);
}
}
if profile.include_math() {
if let Some(ref math) = self.math {
b.field_raw("math", &math.to_json());
}
}
if profile.include_provenance() {
if let Some(ref prov) = self.provenance {
b.field_str("provenance", prov);
}
}
b.finish()
}
}
/// Kind of card.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum CardKind {
Certificate,
Artifact,
Audit,
Risk,
Lifecycle,
Recommendation,
}
impl CardKind {
#[must_use]
pub const fn as_str(self) -> &'static str {
match self {
Self::Certificate => "certificate",
Self::Artifact => "artifact",
Self::Audit => "audit",
Self::Risk => "risk",
Self::Lifecycle => "lifecycle",
Self::Recommendation => "recommendation",
}
}
}
/// Mathematical content in a card.
#[derive(Clone, Debug)]
pub struct CardMath {
pub formula: Option<String>,
pub value: Option<f64>,
pub confidence: Option<f64>,
pub unit: Option<String>,
pub substituted_values: Option<String>,
pub intuition: Option<String>,
pub assumptions: Vec<String>,
pub decision_change: Option<String>,
}
impl CardMath {
#[must_use]
pub fn new() -> Self {
Self {
formula: None,
value: None,
confidence: None,
unit: None,
substituted_values: None,
intuition: None,
assumptions: Vec::new(),
decision_change: None,
}
}
pub fn with_value(mut self, value: f64) -> Self {
self.value = Some(value);
self
}
pub fn with_confidence(mut self, confidence: f64) -> Self {
self.confidence = Some(confidence);
self
}
pub fn with_formula(mut self, formula: impl Into<String>) -> Self {
self.formula = Some(formula.into());
self
}
pub fn with_unit(mut self, unit: impl Into<String>) -> Self {
self.unit = Some(unit.into());
self
}
pub fn with_substituted_values(mut self, values: impl Into<String>) -> Self {
self.substituted_values = Some(values.into());
self
}
pub fn with_intuition(mut self, intuition: impl Into<String>) -> Self {
self.intuition = Some(intuition.into());
self
}
pub fn with_assumption(mut self, assumption: impl Into<String>) -> Self {
self.assumptions.push(assumption.into());
self
}
pub fn with_decision_change(mut self, decision_change: impl Into<String>) -> Self {
self.decision_change = Some(decision_change.into());
self
}
#[must_use]
pub fn to_json(&self) -> String {
let mut b = JsonBuilder::new();
if let Some(ref formula) = self.formula {
b.field_str("formula", formula);
}
if let Some(value) = self.value {
b.field_raw("value", &json_number(value, 6));
}
if let Some(confidence) = self.confidence {
b.field_raw("confidence", &json_number(confidence, 4));
}
if let Some(ref unit) = self.unit {
b.field_str("unit", unit);
}
if let Some(ref values) = self.substituted_values {
b.field_str("substitutedValues", values);
}
if let Some(ref intuition) = self.intuition {
b.field_str("intuition", intuition);
}
if !self.assumptions.is_empty() {
b.field_raw(
"assumptions",
&string_array_json(self.assumptions.iter().map(String::as_str)),
);
}
if let Some(ref decision_change) = self.decision_change {
b.field_str("decisionChange", decision_change);
}
b.finish()
}
}
impl Default for CardMath {
fn default() -> Self {
Self::new()
}
}
/// Create a selection score math card showing the weighted combination formula.
#[must_use]
pub fn selection_score_card(confidence: f32, utility: f32, importance: f32, score: f32) -> Card {
let formula = "score = α·confidence + β·utility + γ·importance";
let computation = format!(
"score = 0.40×{confidence:.2} + 0.35×{utility:.2} + 0.25×{importance:.2} = {score:.3}"
);
let math = CardMath::new()
.with_formula(formula)
.with_value(score as f64)
.with_confidence(confidence as f64)
.with_substituted_values(computation.clone())
.with_intuition("Higher confidence, utility, and importance raise the selected score.")
.with_assumption("Weights are fixed for this certificate profile.")
.with_decision_change(
"A lower confidence or utility value could move this item below the cutoff.",
);
Card::new(
"card_selection_score",
CardKind::Certificate,
"Selection Score Computation",
)
.with_summary(computation)
.with_math(math)
}
/// Create a relevance score math card showing semantic/lexical fusion.
#[must_use]
pub fn relevance_score_card(
semantic: f32,
lexical: f32,
fused: f32,
rank: u32,
rrf_k: u32,
) -> Card {
let rrf_formula = format!("RRF(d) = Σ(1 / (k + rank(d))), k={rrf_k}");
let summary =
format!("Rank {rank}: semantic={semantic:.3}, lexical={lexical:.3} → fused={fused:.4}");
let math = CardMath::new()
.with_formula(rrf_formula)
.with_value(fused as f64)
.with_substituted_values(summary.clone())
.with_intuition("Documents ranked well by either retriever gain fused relevance.")
.with_assumption("Semantic and lexical ranks are stable for the same index generation.")
.with_decision_change("A worse semantic or lexical rank would lower fused relevance.");
Card::new(
"card_relevance_score",
CardKind::Certificate,
"Relevance Score (RRF Fusion)",
)
.with_summary(summary)
.with_math(math)
}
/// Create a utility decay math card showing temporal decay computation.
#[must_use]
pub fn utility_decay_card(
base_utility: f32,
age_days: u32,
decay_rate: f32,
current_utility: f32,
) -> Card {
let formula = "utility(t) = base · exp(-λ·t)";
let computation = format!(
"utility = {base_utility:.3} × exp(-{decay_rate:.4} × {age_days}) = {current_utility:.3}"
);
let math = CardMath::new()
.with_formula(formula)
.with_value(current_utility as f64)
.with_unit("utility units".to_string())
.with_substituted_values(computation.clone())
.with_intuition("Older memories lose utility unless their base value is high enough.")
.with_assumption("The decay rate is fixed for the active policy.")
.with_decision_change("A lower age or decay rate would preserve more utility.");
Card::new(
"card_utility_decay",
CardKind::Certificate,
"Utility Temporal Decay",
)
.with_summary(computation)
.with_math(math)
}
/// Create a trust score math card showing weighted trust class contribution.
#[must_use]
pub fn trust_score_card(
trust_class: &str,
trust_weight: f32,
confidence: f32,
combined: f32,
) -> Card {
let formula = "trust = class_weight × confidence";
let computation =
format!("trust({trust_class}) = {trust_weight:.2} × {confidence:.2} = {combined:.3}");
let math = CardMath::new()
.with_formula(formula)
.with_value(combined as f64)
.with_confidence(confidence as f64)
.with_substituted_values(computation.clone())
.with_intuition("Higher-trust sources contribute more strongly to selection.")
.with_assumption("Trust class weights are policy-controlled and deterministic.")
.with_decision_change("A lower trust class weight could demote this memory.");
Card::new(
"card_trust_score",
CardKind::Certificate,
"Trust Score Computation",
)
.with_summary(computation)
.with_math(math)
}
/// Create a pack budget math card showing token budget utilization.
#[must_use]
pub fn pack_budget_card(
used_tokens: u32,
max_tokens: u32,
item_count: u32,
omitted_count: u32,
) -> Card {
let utilization = if max_tokens == 0 {
f64::NAN
} else {
(used_tokens as f64 / max_tokens as f64) * 100.0
};
let utilization_label = if utilization.is_finite() {
format!("{utilization:.1}%")
} else {
"unavailable".to_string()
};
let formula = "utilization = used_tokens / max_tokens";
let summary = format!(
"{used_tokens}/{max_tokens} tokens ({utilization_label}), \
{item_count} items packed, {omitted_count} omitted"
);
let math = CardMath::new()
.with_formula(formula)
.with_value(utilization)
.with_unit("%".to_string())
.with_substituted_values(summary.clone())
.with_intuition("Higher utilization means less room remains for additional memories.")
.with_assumption("Token estimates use the active deterministic estimator.")
.with_decision_change("A larger max token budget could admit omitted items.");
Card::new("card_pack_budget", CardKind::Audit, "Pack Token Budget")
.with_summary(summary)
.with_math(math)
}
/// Create a diversity penalty math card showing MMR-style diversity score.
#[must_use]
pub fn diversity_penalty_card(
base_score: f32,
diversity_penalty: f32,
final_score: f32,
similar_items: u32,
) -> Card {
let formula = "final = base - λ·max_sim(selected)";
let computation = format!(
"final = {base_score:.3} - {diversity_penalty:.3} = {final_score:.3} \
({similar_items} similar items penalized)"
);
let math = CardMath::new()
.with_formula(formula)
.with_value(final_score as f64)
.with_substituted_values(computation.clone())
.with_intuition("Redundant memories lose score so the pack covers more distinct evidence.")
.with_assumption("Similarity is computed against already selected items.")
.with_decision_change("Less overlap with selected memories would reduce the penalty.");
Card::new(
"card_diversity_penalty",
CardKind::Certificate,
"Diversity Penalty (MMR)",
)
.with_summary(computation)
.with_math(math)
}
// ============================================================================
// EE-374: Graveyard recommendation cards
// ============================================================================
/// Priority level for graveyard recommendations.
#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd)]
pub enum GraveyardPriority {
Low,
Medium,
High,
Critical,
}
impl GraveyardPriority {
#[must_use]
pub const fn as_str(self) -> &'static str {
match self {
Self::Low => "low",
Self::Medium => "medium",
Self::High => "high",
Self::Critical => "critical",
}
}
#[must_use]
pub const fn all() -> [Self; 4] {
[Self::Low, Self::Medium, Self::High, Self::Critical]
}
}
/// Type of graveyard recommendation.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum GraveyardRecommendationType {
/// Claim has not been verified recently.
StaleClaim,
/// Claim has no associated demo.
MissingDemo,
/// Recent verification attempt failed.
FailedVerification,
/// Claim is a candidate for uplift/promotion.
UpliftCandidate,
/// Demo output has drifted from expected.
OutputDrift,
/// Claim depends on deprecated feature.
DeprecatedDependency,
}
impl GraveyardRecommendationType {
#[must_use]
pub const fn as_str(self) -> &'static str {
match self {
Self::StaleClaim => "stale_claim",
Self::MissingDemo => "missing_demo",
Self::FailedVerification => "failed_verification",
Self::UpliftCandidate => "uplift_candidate",
Self::OutputDrift => "output_drift",
Self::DeprecatedDependency => "deprecated_dependency",
}
}
#[must_use]
pub const fn all() -> [Self; 6] {
[
Self::StaleClaim,
Self::MissingDemo,
Self::FailedVerification,
Self::UpliftCandidate,
Self::OutputDrift,
Self::DeprecatedDependency,
]
}
#[must_use]
pub const fn default_priority(self) -> GraveyardPriority {
match self {
Self::StaleClaim => GraveyardPriority::Medium,
Self::MissingDemo => GraveyardPriority::High,
Self::FailedVerification => GraveyardPriority::Critical,
Self::UpliftCandidate => GraveyardPriority::Low,
Self::OutputDrift => GraveyardPriority::High,
Self::DeprecatedDependency => GraveyardPriority::Medium,
}
}
}
/// Create a stale claim recommendation card.
#[must_use]
pub fn graveyard_stale_claim_card(
claim_id: &str,
days_since_verification: u32,
stale_threshold_days: u32,
) -> Card {
let summary = format!(
"Claim {} has not been verified in {} days (threshold: {} days). \
Run `ee claim verify {}` to update verification status.",
claim_id, days_since_verification, stale_threshold_days, claim_id
);
Card::new(
format!("card_graveyard_stale_{}", claim_id),
CardKind::Recommendation,
"Stale Claim Verification",
)
.with_summary(summary)
}
/// Create a missing demo recommendation card.
#[must_use]
pub fn graveyard_missing_demo_card(claim_id: &str, claim_title: &str) -> Card {
let summary = format!(
"Claim '{}' ({}) has no associated demo. \
Add a demo to demo.yaml with claim_id: {} to make this claim executable.",
claim_title, claim_id, claim_id
);
Card::new(
format!("card_graveyard_missing_demo_{}", claim_id),
CardKind::Recommendation,
"Missing Demo for Claim",
)
.with_summary(summary)
}
/// Create a failed verification recommendation card.
#[must_use]
pub fn graveyard_failed_verification_card(
claim_id: &str,
failure_reason: &str,
last_attempt: &str,
) -> Card {
let summary = format!(
"Claim {} verification failed on {}: {}. \
Review and fix the underlying issue, then re-run verification.",
claim_id, last_attempt, failure_reason
);
Card::new(
format!("card_graveyard_failed_{}", claim_id),
CardKind::Recommendation,
"Failed Verification",
)
.with_summary(summary)
}
/// Create an uplift candidate recommendation card.
#[must_use]
pub fn graveyard_uplift_candidate_card(
claim_id: &str,
consecutive_passes: u32,
confidence_score: f32,
) -> Card {
let summary = format!(
"Claim {} has passed verification {} consecutive times with {:.1}% confidence. \
Consider promoting to 'verified' status.",
claim_id,
consecutive_passes,
confidence_score * 100.0
);
Card::new(
format!("card_graveyard_uplift_{}", claim_id),
CardKind::Recommendation,
"Uplift Candidate",
)
.with_summary(summary)
.with_math(
CardMath::new()
.with_formula("confidence = consecutive_pass_signal")
.with_value(confidence_score as f64)
.with_unit("confidence")
.with_substituted_values(format!(
"consecutive_passes={consecutive_passes}, confidence={confidence_score:.3}"
))
.with_intuition("Repeated successful verification raises promotion confidence.")
.with_assumption("Recent verification attempts are comparable.")
.with_decision_change("A new failed verification would block promotion."),
)
}
/// Create an output drift recommendation card.
#[must_use]
pub fn graveyard_output_drift_card(
demo_id: &str,
expected_hash: &str,
actual_hash: &str,
drift_percentage: f32,
) -> Card {
let summary = format!(
"Demo {} output has drifted {:.1}% from expected. \
Expected hash: {}..., actual: {}... \
Update expected values or investigate regression.",
demo_id,
drift_percentage * 100.0,
&expected_hash[..8.min(expected_hash.len())],
&actual_hash[..8.min(actual_hash.len())]
);
Card::new(
format!("card_graveyard_drift_{}", demo_id),
CardKind::Recommendation,
"Output Drift Detected",
)
.with_summary(summary)
.with_math(
CardMath::new()
.with_formula("drift = changed_output_bytes / expected_output_bytes")
.with_value(drift_percentage as f64)
.with_unit("drift")
.with_substituted_values(format!("drift={drift_percentage:.3}"))
.with_intuition("Large output drift can indicate a changed contract.")
.with_assumption("Expected and actual hashes refer to the same demo.")
.with_decision_change(
"Refreshing the expected artifact after review would clear drift.",
),
)
}
/// Create a deprecated dependency recommendation card.
#[must_use]
pub fn graveyard_deprecated_dependency_card(
claim_id: &str,
deprecated_feature: &str,
replacement: Option<&str>,
) -> Card {
let summary = if let Some(repl) = replacement {
format!(
"Claim {} depends on deprecated feature '{}'. \
Migrate to '{}' before the feature is removed.",
claim_id, deprecated_feature, repl
)
} else {
format!(
"Claim {} depends on deprecated feature '{}'. \
Review and remove this dependency.",
claim_id, deprecated_feature
)
};
Card::new(
format!("card_graveyard_deprecated_{}", claim_id),
CardKind::Recommendation,
"Deprecated Dependency",
)
.with_summary(summary)
}
/// Render a cards array for JSON output.
#[must_use]
pub fn render_cards_json(cards: &[Card], profile: CardsProfile) -> String {
if !profile.include_cards() || cards.is_empty() {
return "[]".to_string();
}
let mut result = String::from("[");
for (i, card) in cards.iter().enumerate() {
if i > 0 {
result.push(',');
}
result.push_str(&card.to_json(profile));
}
result.push(']');
result
}
#[derive(Clone, Copy, Debug)]
pub struct OutputContext {
pub renderer: Renderer,
pub field_profile: FieldProfile,
pub is_tty: bool,
pub color_enabled: bool,
}
#[derive(Clone, Debug, Default, Eq, PartialEq)]
struct OutputEnvironment {
ee_json: Option<String>,
ee_output_format: Option<String>,
ee_format: Option<String>,
ee_disable_toon: Option<String>,
toon_default_format: Option<String>,
ee_agent_mode: Option<String>,
ee_hook_mode: Option<String>,
no_color: Option<String>,
ee_no_color: Option<String>,
force_color: Option<String>,
}
impl OutputEnvironment {
fn from_process_env() -> Self {
Self {
ee_json: read(EnvVar::Json),
ee_output_format: read(EnvVar::OutputFormat),
ee_format: read(EnvVar::Format),
ee_disable_toon: read(EnvVar::DisableToon),
toon_default_format: env::var("TOON_DEFAULT_FORMAT").ok(),
ee_agent_mode: read(EnvVar::AgentMode),
ee_hook_mode: read(EnvVar::HookMode),
no_color: env::var("NO_COLOR").ok(),
ee_no_color: read(EnvVar::NoColor),
force_color: env::var("FORCE_COLOR").ok(),
}
}
}
fn env_flag_truthy(value: Option<&str>) -> bool {
value.is_some_and(|raw| {
let trimmed = raw.trim();
!(trimmed.is_empty()
|| trimmed == "0"
|| trimmed.eq_ignore_ascii_case("false")
|| trimmed.eq_ignore_ascii_case("no")
|| trimmed.eq_ignore_ascii_case("off"))
})
}
#[must_use]
pub fn toon_output_available() -> bool {
!env_flag_truthy(read(EnvVar::DisableToon).as_deref())
}
fn renderer_from_env_value(value: &str) -> Option<Renderer> {
match value.trim().to_ascii_lowercase().as_str() {
"human" => Some(Renderer::Human),
"json" => Some(Renderer::Json),
"toon" => Some(Renderer::Toon),
"jsonl" => Some(Renderer::Jsonl),
"compact" => Some(Renderer::Compact),
"hook" => Some(Renderer::Hook),
"markdown" | "md" => Some(Renderer::Markdown),
_ => None,
}
}
/// Renderer requested purely by environment variables, or `None` when no
/// output-selecting variable is set.
///
/// Precedence matches [`OutputContext::detect`]: `EE_JSON` / `EE_AGENT_MODE`
/// force JSON, then `EE_HOOK_MODE` forces hook, then `EE_OUTPUT_FORMAT`,
/// `EE_FORMAT`, and `TOON_DEFAULT_FORMAT` are consulted in that order. A
/// TOON selection degrades to JSON when `EE_DISABLE_TOON` is truthy.
///
/// Explicit CLI flags always outrank this: the argv-injection layer in
/// `main.rs` only consults it when no `--json` / `--robot` / `--format`
/// flag is present.
#[must_use]
pub fn renderer_requested_by_env() -> Option<Renderer> {
renderer_requested_by_environment(&OutputEnvironment::from_process_env())
}
fn renderer_requested_by_environment(environment: &OutputEnvironment) -> Option<Renderer> {
let renderer = if env_flag_truthy(environment.ee_json.as_deref())
|| env_flag_truthy(environment.ee_agent_mode.as_deref())
{
Renderer::Json
} else if env_flag_truthy(environment.ee_hook_mode.as_deref()) {
Renderer::Hook
} else if let Some(renderer) = environment
.ee_output_format
.as_deref()
.and_then(renderer_from_env_value)
{
renderer
} else if let Some(renderer) = environment
.ee_format
.as_deref()
.and_then(renderer_from_env_value)
{
renderer
} else if let Some(renderer) = environment
.toon_default_format
.as_deref()
.and_then(renderer_from_env_value)
{
renderer
} else {
return None;
};
if matches!(renderer, Renderer::Toon) && env_flag_truthy(environment.ee_disable_toon.as_deref())
{
return Some(Renderer::Json);
}
Some(renderer)
}
impl OutputContext {
#[must_use]
pub fn detect() -> Self {
Self::detect_with_hints(false, false, None)
}
#[must_use]
pub fn detect_with_hints(
json_flag: bool,
robot_flag: bool,
format_override: Option<Renderer>,
) -> Self {
let is_tty = std::io::stdout().is_terminal();
Self::detect_with_environment(
json_flag,
robot_flag,
format_override,
is_tty,
&OutputEnvironment::from_process_env(),
)
}
fn detect_with_environment(
json_flag: bool,
robot_flag: bool,
format_override: Option<Renderer>,
is_tty: bool,
environment: &OutputEnvironment,
) -> Self {
let no_color = environment.no_color.is_some() || environment.ee_no_color.is_some();
let force_color = env_flag_truthy(environment.force_color.as_deref());
let renderer = if let Some(r) = format_override {
r
} else if json_flag || robot_flag {
Renderer::Json
} else {
renderer_requested_by_environment(environment).unwrap_or(Renderer::Human)
};
let renderer = if matches!(renderer, Renderer::Toon)
&& env_flag_truthy(environment.ee_disable_toon.as_deref())
{
Renderer::Json
} else {
renderer
};
let color_enabled = (is_tty || force_color) && !no_color && !renderer.is_machine_readable();
Self {
renderer,
field_profile: FieldProfile::Standard,
is_tty,
color_enabled,
}
}
#[must_use]
pub fn with_field_profile(mut self, profile: FieldProfile) -> Self {
self.field_profile = profile;
self
}
#[must_use]
pub const fn is_machine_output(&self) -> bool {
self.renderer.is_machine_readable()
}
}
/// A single degradation notice in the ee.response.v2 envelope.
///
/// Degradation notices tell consumers that the response is valid but
/// incomplete or limited in some way. The repair field suggests how to
/// resolve the degradation.
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Degradation {
pub code: String,
pub severity: DegradationSeverity,
pub message: String,
pub repair: String,
}
impl Degradation {
#[must_use]
pub fn new(
code: impl Into<String>,
severity: DegradationSeverity,
message: impl Into<String>,
repair: impl Into<String>,
) -> Self {
Self {
code: code.into(),
severity,
message: message.into(),
repair: repair.into(),
}
}
#[must_use]
pub fn to_json(&self) -> String {
let mut b = JsonBuilder::new();
b.field_str("code", &self.code);
b.field_str("severity", self.severity.as_str());
b.field_str("message", &self.message);
b.field_str("repair", &self.repair);
b.finish()
}
}
pub struct JsonBuilder {
buffer: String,
first: bool,
}
impl JsonBuilder {
#[must_use]
pub fn new() -> Self {
Self {
buffer: String::from("{"),
first: true,
}
}
#[must_use]
pub fn with_capacity(capacity: usize) -> Self {
let mut buffer = String::with_capacity(capacity);
buffer.push('{');
Self {
buffer,
first: true,
}
}
pub fn field_str(&mut self, key: &str, value: &str) -> &mut Self {
self.separator();
self.buffer.push('"');
self.buffer.push_str(key);
self.buffer.push_str("\":\"");
self.buffer.push_str(&escape_json_string(value));
self.buffer.push('"');
self
}
pub fn field_raw(&mut self, key: &str, raw_json: &str) -> &mut Self {
self.separator();
self.buffer.push('"');
self.buffer.push_str(key);
self.buffer.push_str("\":");
self.buffer.push_str(raw_json);
self
}
pub fn field_bool(&mut self, key: &str, value: bool) -> &mut Self {
self.field_raw(key, if value { "true" } else { "false" })
}
pub fn field_u32(&mut self, key: &str, value: u32) -> &mut Self {
self.separator();
self.buffer.push('"');
self.buffer.push_str(key);
self.buffer.push_str("\":");
self.buffer.push_str(&value.to_string());
self
}
pub fn field_i32(&mut self, key: &str, value: i32) -> &mut Self {
self.separator();
self.buffer.push('"');
self.buffer.push_str(key);
self.buffer.push_str("\":");
self.buffer.push_str(&value.to_string());
self
}
pub fn field_object<F>(&mut self, key: &str, build: F) -> &mut Self
where
F: FnOnce(&mut JsonBuilder),
{
let mut nested = JsonBuilder::new();
build(&mut nested);
let nested_json = nested.finish();
self.field_raw(key, &nested_json)
}
pub fn field_array_of_objects<T, F>(&mut self, key: &str, items: &[T], build: F) -> &mut Self
where
F: Fn(&mut JsonBuilder, &T),
{
self.separator();
self.buffer.push('"');
self.buffer.push_str(key);
self.buffer.push_str("\":[");
for (i, item) in items.iter().enumerate() {
if i > 0 {
self.buffer.push(',');
}
let mut nested = JsonBuilder::new();
build(&mut nested, item);
self.buffer.push_str(&nested.finish());
}
self.buffer.push(']');
self
}
pub fn field_array_of_objects_chained<A, B, F, G>(
&mut self,
key: &str,
first_items: &[A],
second_items: &[B],
build_first: F,
build_second: G,
) -> &mut Self
where
F: Fn(&mut JsonBuilder, &A),
G: Fn(&mut JsonBuilder, &B),
{
self.separator();
self.buffer.push('"');
self.buffer.push_str(key);
self.buffer.push_str("\":[");
let mut wrote_item = false;
for item in first_items {
if wrote_item {
self.buffer.push(',');
}
let mut nested = JsonBuilder::new();
build_first(&mut nested, item);
self.buffer.push_str(&nested.finish());
wrote_item = true;
}
for item in second_items {
if wrote_item {
self.buffer.push(',');
}
let mut nested = JsonBuilder::new();
build_second(&mut nested, item);
self.buffer.push_str(&nested.finish());
wrote_item = true;
}
self.buffer.push(']');
self
}
pub fn field_array_of_strings(&mut self, key: &str, items: &[String]) -> &mut Self {
self.separator();
self.buffer.push('"');
self.buffer.push_str(key);
self.buffer.push_str("\":[");
for (i, item) in items.iter().enumerate() {
if i > 0 {
self.buffer.push(',');
}
self.buffer.push('"');
self.buffer.push_str(&escape_json_string(item));
self.buffer.push('"');
}
self.buffer.push(']');
self
}
pub fn field_array_of_strs(&mut self, key: &str, items: &[&str]) -> &mut Self {
self.separator();
self.buffer.push('"');
self.buffer.push_str(key);
self.buffer.push_str("\":[");
for (i, item) in items.iter().enumerate() {
if i > 0 {
self.buffer.push(',');
}
self.buffer.push('"');
self.buffer.push_str(&escape_json_string(item));
self.buffer.push('"');
}
self.buffer.push(']');
self
}
fn separator(&mut self) {
if self.first {
self.first = false;
} else {
self.buffer.push(',');
}
}
#[must_use]
pub fn finish(mut self) -> String {
self.buffer.push('}');
self.buffer
}
}
impl Default for JsonBuilder {
fn default() -> Self {
Self::new()
}
}
/// Convert a current `ee.response.v2` envelope into the retained v0 shape.
#[must_use]
pub fn render_response_json_for_schema_version(
json: &str,
schema_version: ResponseSchemaVersion,
) -> String {
match schema_version {
ResponseSchemaVersion::V1 => json.to_owned(),
ResponseSchemaVersion::V0 => render_response_json_v0(json),
}
}
fn render_response_json_v0(json: &str) -> String {
let Ok(value) = serde_json::from_str::<serde_json::Value>(json) else {
return json.to_owned();
};
let Some(object) = value.as_object() else {
return json.to_owned();
};
if object.get("schema").and_then(serde_json::Value::as_str) != Some(RESPONSE_SCHEMA_V2) {
return json.to_owned();
}
let mut b = JsonBuilder::with_capacity(json.len());
b.field_str("schema", RESPONSE_SCHEMA_V0);
b.field_bool(
"ok",
object
.get("success")
.and_then(serde_json::Value::as_bool)
.unwrap_or(true),
);
if let Some(fields) = object.get("fields") {
b.field_raw("fields", &fields.to_string());
}
if let Some(data) = object.get("data") {
b.field_raw("result", &data.to_string());
}
if let Some(meta) = object.get("meta") {
b.field_raw("meta", &meta.to_string());
}
b.finish()
}
/// Apply a parsed `--fields` selector to a JSON response envelope.
pub fn apply_field_selector_to_json(
json: &str,
selector: &FieldSelector,
) -> Result<String, DomainError> {
if selector.has_conflicting_presets() {
return Err(conflicting_presets_error(selector));
}
let mut value = match serde_json::from_str::<serde_json::Value>(json) {
Ok(value) => value,
Err(_) => return Ok(json.to_owned()),
};
let Some(object) = value.as_object_mut() else {
return Ok(json.to_owned());
};
if object.get("schema").and_then(serde_json::Value::as_str) != Some(RESPONSE_SCHEMA_V2) {
return Ok(json.to_owned());
}
let Some(data) = object
.get_mut("data")
.and_then(serde_json::Value::as_object_mut)
else {
return Ok(json.to_owned());
};
// The response carries the command name in `data.command` for most surfaces,
// but newer schema-first responses (e.g. swarm brief/next-action/work-packet)
// emit only `data.schema = "ee.swarm.brief.v1"` without a duplicate `command`
// field. Fall back to deriving the command from the schema so the preset
// dispatch finds the right per-command field list. Without this fallback,
// preset_fields_for_command would hit the default arm whose summary preset
// is `["command", "version", "status", "summary", "count", "schema"]` —
// none of which exist at the top level of a swarm brief response.
let command_owned;
let command = match data.get("command").and_then(serde_json::Value::as_str) {
Some(name) => name,
None => {
command_owned = data
.get("schema")
.and_then(serde_json::Value::as_str)
.map(command_name_from_schema)
.unwrap_or_default();
command_owned.as_str()
}
};
let requested_fields = requested_fields_for_selector(command, selector);
if requested_fields.is_empty() {
return Ok(json.to_owned());
}
let accepted_fields = collect_field_names(data);
if !requested_fields.iter().any(|field| field == "*") {
if let Some(rejected) = requested_fields
.iter()
.filter(|field| {
selector
.explicit_fields
.iter()
.any(|explicit| explicit == *field)
})
.find(|field| !accepted_fields.contains(field.as_str()))
{
return Err(unknown_field_error(rejected, &accepted_fields));
}
}
let selected = requested_fields
.iter()
.map(String::as_str)
.collect::<BTreeSet<_>>();
let filtered = filter_selected_data(data, &selected);
*data = filtered;
object.insert(
"fields".to_string(),
serde_json::Value::String(selector.raw().to_string()),
);
serde_json::to_string(&value).map_err(|error| DomainError::Usage {
message: format!("Failed to render selected fields: {error}."),
repair: Some("Use --fields full and report the serialization failure.".to_string()),
})
}
fn filter_selected_data(
data: &serde_json::Map<String, serde_json::Value>,
selected: &BTreeSet<&str>,
) -> serde_json::Map<String, serde_json::Value> {
if selected.contains("*") {
return data.clone();
}
let root_selected = data
.keys()
.filter(|key| selected.contains(key.as_str()))
.map(String::as_str)
.collect::<BTreeSet<_>>();
let child_selected = selected
.iter()
.copied()
.filter(|field| !root_selected.contains(field))
.collect::<BTreeSet<_>>();
let mut filtered = serde_json::Map::new();
for (key, child) in data {
if selected.contains(key.as_str()) {
let child = if child_selected.is_empty() {
child.clone()
} else {
filter_selected_fields(child, &child_selected).unwrap_or_else(|| child.clone())
};
filtered.insert(key.clone(), child);
} else if !child_selected.is_empty()
&& let Some(filtered_child) = filter_selected_fields(child, &child_selected)
{
filtered.insert(key.clone(), filtered_child);
}
}
filtered
}
fn requested_fields_for_selector(command: &str, selector: &FieldSelector) -> Vec<String> {
let mut fields = Vec::new();
if let Some(preset) = selector.preset {
fields.extend(
preset_fields_for_command(command, preset)
.iter()
.map(|field| (*field).to_string()),
);
}
for field in &selector.explicit_fields {
if !fields.iter().any(|existing| existing == field) {
fields.push(field.clone());
}
}
fields
}
/// Return the canonical field names for a command/preset pair.
#[must_use]
pub fn field_preset_names_for_command(
command: &str,
preset: FieldProfile,
) -> &'static [&'static str] {
preset_fields_for_command(command, preset)
}
/// Derive a `preset_fields_for_command` lookup key from a response's data
/// schema constant. Used when the response doesn't carry a `data.command`
/// field (e.g. swarm surfaces). Returns the empty string when the schema
/// doesn't map to a known command — the caller then falls through to the
/// default preset arm.
fn command_name_from_schema(schema: &str) -> String {
// Map known data-schema constants → preset_fields_for_command key.
// Conservative: only known mappings are handled; unknown schemas fall
// through to the empty-string default-arm path. Add new entries as new
// schema-first response shapes are introduced.
// Schema naming is inconsistent across surfaces — `ee.swarm.brief.v1` uses
// dots while `ee.swarm_next_action.v1` and `ee.swarm_work_packet.v1` use
// underscores. Accept both forms; the production emit values are what
// matters.
match schema {
"ee.learn.gaps.v1" => "learn gaps".to_string(),
"ee.session_budget.plan.v1" => "session-budget plan".to_string(),
"ee.decide.record.v1" => "decide record".to_string(),
"ee.decide.list.v1" => "decide list".to_string(),
"ee.decide.revisit.v1" => "decide revisit".to_string(),
"ee.toolchain_provenance.v1" => "diag toolchain-provenance".to_string(),
"ee.ask.v1" => "ask".to_string(),
"ee.recall.v1" => "recall".to_string(),
"ee.swarm.brief.v1" | "ee.swarm_brief.v1" => "swarm brief".to_string(),
"ee.swarm.next_action.v1" | "ee.swarm.next-action.v1" | "ee.swarm_next_action.v1" => {
"swarm next-action".to_string()
}
"ee.swarm.repair_plan.v1" | "ee.swarm.repair-plan.v1" | "ee.swarm_repair_plan.v1" => {
"swarm repair-plan".to_string()
}
"ee.swarm.work_packet.v1" | "ee.swarm.work-packet.v1" | "ee.swarm_work_packet.v1" => {
"swarm work-packet".to_string()
}
"ee.swarm.work_packet.claim_gate.v1"
| "ee.swarm.work-packet.claim-gate.v1"
| "ee.swarm_work_packet_claim_gate.v1" => "swarm work-packet claim-gate".to_string(),
_ => String::new(),
}
}
fn preset_fields_for_command(command: &str, preset: FieldProfile) -> &'static [&'static str] {
match command {
"search" => match preset {
FieldProfile::Minimal => &["embed_backend", "memoryId", "docId", "score", "source"],
FieldProfile::Summary => &[
"query",
"status",
"embed_backend",
"resultCount",
"memoryId",
"docId",
"score",
"source",
],
FieldProfile::Standard => &[
"query",
"status",
"embed_backend",
"resultCount",
"results",
"memoryId",
"docId",
"score",
"source",
"why",
"provenance",
"indexFreshness",
"degraded",
"errors",
"metrics",
"elapsedMs",
],
FieldProfile::Full => &["*"],
},
"context" | "pack" => match preset {
FieldProfile::Minimal => &["command", "embed_backend", "query", "hash"],
FieldProfile::Summary => &[
"command",
"embed_backend",
"request",
"pack",
"budget",
"quality",
"pagination",
"degraded",
],
FieldProfile::Standard => &[
"command",
"embed_backend",
"request",
"pack",
"items",
"pagination",
"degraded",
],
FieldProfile::Full => &["*"],
},
"learn gaps" => match preset {
FieldProfile::Minimal => &["schema", "workspaceId", "clusterCount"],
FieldProfile::Summary => &[
"schema",
"workspaceId",
"retentionDays",
"effectiveSince",
"scannedMissCount",
"clusterCount",
"gaps",
"degraded",
],
FieldProfile::Standard => &[
"schema",
"success",
"workspaceId",
"retentionDays",
"requestedSince",
"effectiveSince",
"scannedMissCount",
"clusterCount",
"gaps",
"degraded",
"generatedAt",
],
FieldProfile::Full => &["*"],
},
"curate doctor" => match preset {
FieldProfile::Minimal => &["schema", "command", "summary"],
FieldProfile::Summary => &[
"schema",
"command",
"version",
"workspaceId",
"filter",
"summary",
"degraded",
"trend",
"nextActions",
],
FieldProfile::Standard => &[
"schema",
"command",
"version",
"workspaceId",
"workspacePath",
"databasePath",
"generatedAt",
"filter",
"summary",
"queue",
"degraded",
"trend",
"nextActions",
],
FieldProfile::Full => &["*"],
},
"session-budget plan" => match preset {
FieldProfile::Minimal => &["schema", "advisory", "recommendation"],
FieldProfile::Summary => &[
"schema",
"workspaceFingerprint",
"advisory",
"taskHint",
"recommendation",
"fallbacks",
"refusals",
"ledgerSummary",
],
FieldProfile::Standard => &[
"schema",
"generatedAt",
"workspaceFingerprint",
"advisory",
"taskHint",
"recommendation",
"fallbacks",
"refusals",
"ledgerSummary",
],
FieldProfile::Full => &["*"],
},
"decide record" => match preset {
FieldProfile::Minimal => &["schema", "version", "status", "dryRun", "persisted"],
FieldProfile::Summary => &[
"schema",
"version",
"status",
"dryRun",
"persisted",
"workspaceId",
"decision",
"superseded",
],
FieldProfile::Standard => &[
"schema",
"version",
"status",
"dryRun",
"persisted",
"workspaceId",
"databasePath",
"decision",
"superseded",
"memoryAuditId",
"memoryIndexJobId",
"linkAuditId",
"expireAuditId",
"subscribe",
],
FieldProfile::Full => &["*"],
},
"decide list" => match preset {
FieldProfile::Minimal => &["schema", "version", "returnedCount", "truncated"],
FieldProfile::Summary => &[
"schema",
"version",
"about",
"includeSuperseded",
"totalCount",
"returnedCount",
"truncated",
],
FieldProfile::Standard => &[
"schema",
"version",
"workspaceId",
"databasePath",
"about",
"includeSuperseded",
"totalCount",
"returnedCount",
"truncated",
"decisions",
"subscribe",
],
FieldProfile::Full => &["*"],
},
"decide revisit" => match preset {
FieldProfile::Minimal => &[
"schema",
"version",
"dueCount",
"returnedCount",
"truncated",
],
FieldProfile::Summary => &[
"schema",
"version",
"now",
"warningDays",
"windowEnd",
"dueCount",
"returnedCount",
"truncated",
],
FieldProfile::Standard => &[
"schema",
"version",
"workspaceId",
"databasePath",
"now",
"warningDays",
"windowEnd",
"dueCount",
"returnedCount",
"truncated",
"decisions",
"subscribe",
],
FieldProfile::Full => &["*"],
},
"diag toolchain-provenance" => match preset {
FieldProfile::Minimal => &[
"schema",
"workspaceFingerprint",
"redactionStatus",
"degraded",
],
FieldProfile::Summary => &[
"schema",
"collectedAt",
"workspaceFingerprint",
"redactionStatus",
"tools",
"degraded",
],
FieldProfile::Standard => &[
"schema",
"collectedAt",
"workspaceFingerprint",
"redactionStatus",
"tools",
"scriptHashes",
"degraded",
],
FieldProfile::Full => &["*"],
},
"ask" => match preset {
FieldProfile::Minimal => &[
"schema",
"question",
"abstained",
"answerText",
"confidence",
"citations",
],
FieldProfile::Summary => &[
"schema",
"question",
"abstained",
"answerText",
"confidence",
"confidenceComponents",
"citations",
"candidatesScanned",
"nearestEvidence",
"counterfactualHint",
"queryAssist",
],
FieldProfile::Standard => &[
"schema",
"question",
"abstained",
"answerText",
"confidence",
"confidenceComponents",
"citations",
"sides",
"nearestEvidence",
"counterfactualHint",
"candidatesScanned",
"queryAssist",
],
FieldProfile::Full => &["*"],
},
"recall" => match preset {
FieldProfile::Minimal => &["schema", "query", "memoryId", "score"],
FieldProfile::Summary => &[
"schema",
"query",
"totalMatched",
"truncated",
"memoryId",
"level",
"kind",
"contentPreview",
"score",
"freshnessState",
],
FieldProfile::Standard => &[
"schema",
"query",
"items",
"indexGeneration",
"dbGeneration",
"totalMatched",
"truncated",
"droppedCount",
"continuationCursor",
"memoryId",
"level",
"kind",
"contentPreview",
"tags",
"score",
"scoreComponents",
"freshnessState",
"provenance",
"anchor",
"repair",
],
FieldProfile::Full => &["*"],
},
"orient" => match preset {
FieldProfile::Minimal => &["command", "embed_backend", "task", "workspace"],
FieldProfile::Summary => &[
"command",
"embed_backend",
"task",
"workspace",
"doctor",
"workspaceHygiene",
"pack",
"degraded",
],
FieldProfile::Standard => &[
"command",
"embed_backend",
"task",
"workspace",
"swarmBrief",
"doctor",
"install",
"workspaceHygiene",
"pack",
"nextCommands",
"degraded",
],
FieldProfile::Full => &["*"],
},
"status" => match preset {
FieldProfile::Minimal => &["command", "version", "workspace"],
FieldProfile::Summary => &[
"command",
"version",
"workspace",
"posture",
"singleFlight",
"writeGroupCommit",
"flightRecorder",
"qos",
"rchWorkerPressure",
"verificationPosture",
"verificationLedger",
"hostCalibration",
"search",
"capabilities",
],
FieldProfile::Standard => &[
"command",
"version",
"workspace",
"posture",
"singleFlight",
"writeGroupCommit",
"flightRecorder",
"qos",
"rchWorkerPressure",
"verificationPosture",
"verificationLedger",
"hostCalibration",
"capabilities",
"runtime",
"read_pool",
"wal",
"shardFanout",
"packBudgetBuckets",
"memoryHealth",
"curationHealth",
"feedbackHealth",
"graphCompute",
"graphSnapshotArtifact",
"search",
"derivedAssets",
"agentInventory",
"degraded",
],
FieldProfile::Full => &["*"],
},
"memory show" => match preset {
FieldProfile::Minimal => &["command", "version", "found", "is_tombstoned"],
FieldProfile::Summary => &[
"command",
"version",
"found",
"is_tombstoned",
"id",
"level",
"kind",
],
FieldProfile::Standard => &[
"command",
"version",
"found",
"is_tombstoned",
"memory",
"error",
],
FieldProfile::Full => &["*"],
},
"memory list" => match preset {
FieldProfile::Minimal => &["command", "version", "id", "level", "kind"],
FieldProfile::Summary => &[
"command",
"version",
"total_count",
"truncated",
"id",
"level",
"kind",
"content",
],
FieldProfile::Standard => &[
"command",
"version",
"memories",
"total_count",
"truncated",
"filter",
"error",
],
FieldProfile::Full => &["*"],
},
"capabilities" => match preset {
FieldProfile::Minimal => &["command", "version"],
FieldProfile::Summary => &["command", "version", "summary"],
FieldProfile::Standard => &[
"command",
"version",
"subsystems",
"features",
"commands",
"binaries",
"envOverrides",
"output",
"summary",
],
FieldProfile::Full => &["*"],
},
"doctor" => match preset {
FieldProfile::Minimal => &["command", "version", "posture", "healthy"],
// The QoS active-lane summary is a compact block built for lean
// agent views; the read_pool/qos contract pins it into summary and
// standard (tests/contracts/read_pool_status_schema.rs).
FieldProfile::Summary => &["command", "version", "posture", "healthy", "qos"],
FieldProfile::Standard => {
&["command", "version", "posture", "healthy", "checks", "qos"]
}
FieldProfile::Full => &["*"],
},
"health" | "check" => match preset {
FieldProfile::Minimal => &["command", "version", "verdict"],
FieldProfile::Summary => &["command", "version", "verdict", "summary", "subsystems"],
FieldProfile::Standard | FieldProfile::Full => &["*"],
},
"import cass" => match preset {
FieldProfile::Minimal => &["schema", "command", "status"],
FieldProfile::Summary => &[
"schema",
"command",
"status",
"sessionsDiscovered",
"sessionsImported",
"sessionsSkipped",
"spansImported",
],
FieldProfile::Standard => &[
"schema",
"command",
"workspacePath",
"databasePath",
"sourceId",
"ledgerId",
"dryRun",
"since",
"sessionsDiscovered",
"sessionsImported",
"sessionsSkipped",
"spansImported",
"indexJobsQueued",
"indexRequiredAction",
"status",
"sessions",
],
FieldProfile::Full => &["*"],
},
"export" => match preset {
FieldProfile::Minimal => &["command", "version", "status", "manifestPath"],
FieldProfile::Summary => &[
"command",
"version",
"status",
"counts",
"verificationStatus",
"degraded",
],
FieldProfile::Standard => &[
"schema",
"command",
"version",
"status",
"dryRun",
"workspacePath",
"workspaceId",
"databasePath",
"outputPath",
"manifestPath",
"recordsPath",
"manifestHash",
"recordsHash",
"redactionLevel",
"exportScope",
"counts",
"provenance",
"verificationStatus",
"artifacts",
"degraded",
],
FieldProfile::Full => &["*"],
},
"curate candidates" => match preset {
FieldProfile::Minimal => &["command", "version", "returnedCount", "candidateId"],
FieldProfile::Summary => &[
"command",
"version",
"totalCount",
"returnedCount",
"limit",
"offset",
"truncated",
"nextAction",
],
FieldProfile::Standard => &[
"command",
"version",
"totalCount",
"returnedCount",
"limit",
"offset",
"truncated",
"durableMutation",
"filter",
"candidates",
"degraded",
"nextAction",
],
FieldProfile::Full => &["*"],
},
"graph export" => match preset {
FieldProfile::Minimal => &["command", "version", "status"],
FieldProfile::Summary => &[
"command",
"version",
"status",
"format",
"nodeCount",
"edgeCount",
"degraded",
],
FieldProfile::Standard => &[
"command",
"version",
"status",
"format",
"workspaceId",
"graphType",
"snapshot",
"graph",
"nodeCount",
"edgeCount",
"artifact",
"degraded",
],
FieldProfile::Full => &["*"],
},
// Swarm surfaces (brief, next-action, work-packet) don't carry a top-level
// `command`/`version`/`status` envelope — their data field is a structured
// swarm report keyed by `workspace`, `sources`, etc. The default preset arm
// would reject `command` as unknown for these commands; provide explicit
// preset field lists derived from the actual response shape.
// Swarm presets reference ONLY always-present fields — the strict
// `accepted_fields` validator rejects any requested field not found in
// the actual response, and many swarm fields (`recommendations`, `bv`,
// `gitAhead`, ...) are absent when their underlying source is filtered
// out (e.g. `--sources host-profile`). Standard/Full fall back to `*`
// for "no filtering" semantics; the operator gets the full envelope.
"swarm brief" => match preset {
FieldProfile::Minimal => &["schema", "workspace", "redactionStatus"],
FieldProfile::Summary => &[
"schema",
"workspace",
"redactionStatus",
"sources",
"dirtyFiles",
"recentCommits",
"beads",
"fileReservations",
"fileSurfaceRisks",
"readyReservationPressure",
"stalledBeadLiveness",
"inbox",
"threads",
"resourcePressure",
"hostProfile",
"agentInventory",
"toolchainProvenance",
"recommendations",
"degraded",
],
FieldProfile::Standard | FieldProfile::Full => &["*"],
},
"swarm next-action" => match preset {
FieldProfile::Minimal => &["schema", "workspace", "redactionStatus"],
FieldProfile::Summary => &["schema", "workspace", "redactionStatus", "degraded"],
FieldProfile::Standard | FieldProfile::Full => &["*"],
},
"swarm work-packet" => match preset {
FieldProfile::Minimal => &["schema", "workspace", "redactionStatus"],
FieldProfile::Summary => &["schema", "workspace", "redactionStatus", "degraded"],
FieldProfile::Standard | FieldProfile::Full => &["*"],
},
"swarm work-packet claim-gate" => match preset {
FieldProfile::Minimal => &[
"schema",
"workspace",
"redactionStatus",
"verdict",
"safeToClaim",
],
FieldProfile::Summary => &[
"schema",
"workspace",
"redactionStatus",
"requestedCandidateId",
"verdict",
"safeToClaim",
"selectedCandidate",
"sourceAuthority",
"actionableQueue",
"resourceAdmission",
"unsafeReasons",
"staleReasons",
"degradedCodes",
"nextCommandActions",
"claimCommandAction",
"recoveryActions",
],
FieldProfile::Standard | FieldProfile::Full => &["*"],
},
"swarm repair-plan" => match preset {
FieldProfile::Minimal => &["schema", "workspace", "redactionStatus"],
FieldProfile::Summary => &["schema", "workspace", "redactionStatus", "degraded"],
FieldProfile::Standard | FieldProfile::Full => &["*"],
},
// `remember`/`note` responses expose `memory_id`/`memoryId` (and `persisted`,
// `index_status`) but no top-level `id`/`status`/`summary`/`count`. The default
// arm below would request `id`, which `collect_field_names` never finds on a
// remember response, so `--fields minimal`/`summary` errored with
// `usage_unknown_field`. Provide a dedicated arm whose presets reference only
// fields that actually exist on the response (and prefer the camelCase
// `memoryId` so minimal output drops the duplicate snake_case key).
"remember" | "note" => match preset {
FieldProfile::Minimal => &[
"command",
"version",
"memoryId",
"persisted",
"index_status",
],
FieldProfile::Summary => &[
"command",
"version",
"memoryId",
"level",
"kind",
"confidence",
"tags",
"content",
"persisted",
"index_status",
"audit_id",
"degraded",
],
FieldProfile::Standard | FieldProfile::Full => &["*"],
},
_ => match preset {
FieldProfile::Minimal => &["command", "version", "status", "id", "schema"],
FieldProfile::Summary => {
&["command", "version", "status", "summary", "count", "schema"]
}
FieldProfile::Standard | FieldProfile::Full => &["*"],
},
}
}
/// Collect every field name reachable inside a response `data` object.
///
/// Takes the map by reference rather than a `Value` so the caller does not
/// have to deep-clone an entire response payload (packs run to megabytes)
/// just to enumerate its key names.
fn collect_field_names(object: &serde_json::Map<String, serde_json::Value>) -> BTreeSet<String> {
let mut fields = BTreeSet::new();
for (key, child) in object {
fields.insert(key.clone());
collect_field_names_inner(child, &mut fields);
}
fields
}
fn collect_field_names_inner(value: &serde_json::Value, fields: &mut BTreeSet<String>) {
match value {
serde_json::Value::Object(object) => {
for (key, child) in object {
fields.insert(key.clone());
collect_field_names_inner(child, fields);
}
}
serde_json::Value::Array(items) => {
for item in items {
collect_field_names_inner(item, fields);
}
}
_ => {}
}
}
fn filter_selected_fields(
value: &serde_json::Value,
selected: &BTreeSet<&str>,
) -> Option<serde_json::Value> {
if selected.contains("*") {
return Some(value.clone());
}
match value {
serde_json::Value::Object(object) => {
let mut filtered = serde_json::Map::new();
for (key, child) in object {
if selected.contains(key.as_str()) {
filtered.insert(key.clone(), child.clone());
} else if let Some(filtered_child) = filter_selected_fields(child, selected) {
filtered.insert(key.clone(), filtered_child);
}
}
(!filtered.is_empty()).then_some(serde_json::Value::Object(filtered))
}
serde_json::Value::Array(items) => {
let filtered = items
.iter()
.filter_map(|item| filter_selected_fields(item, selected))
.collect::<Vec<_>>();
(!filtered.is_empty()).then_some(serde_json::Value::Array(filtered))
}
_ => None,
}
}
fn unknown_field_error(rejected: &str, accepted_fields: &BTreeSet<String>) -> DomainError {
let accepted = accepted_fields.iter().cloned().collect::<Vec<_>>();
let details = serde_json::json!({
"failureModeCode": "usage_unknown_field",
"rejectedField": rejected,
"acceptedFields": accepted,
"presetsAvailable": FIELD_PRESETS_AVAILABLE,
"recovery": [{
"priority": 1,
"kind": "command",
"command": "ee schema list --json",
"reason": "Inspect canonical response schemas and accepted field names."
}]
});
DomainError::UsageCodeWithDetails {
code: "usage_unknown_field",
message: format!("Unknown field `{rejected}` in --fields flag."),
repair: Some("Run `ee schema list --json` and choose a canonical field name.".to_string()),
details_json: details.to_string(),
}
}
fn conflicting_presets_error(selector: &FieldSelector) -> DomainError {
let details = serde_json::json!({
"failureModeCode": "usage_conflicting_presets",
"selector": selector.raw(),
"conflictingPresets": &selector.conflicting_presets,
"presetsAvailable": FIELD_PRESETS_AVAILABLE,
"recovery": [{
"priority": 1,
"kind": "flag",
"flag": "--fields",
"valueHint": "preset=<one-preset>,fieldA,fieldB or fieldA,fieldB",
"reason": "Use one preset plus optional explicit field additions, or omit presets for an explicit field list."
}]
});
DomainError::UsageCodeWithDetails {
code: "usage_conflicting_presets",
message: "Conflicting --fields presets were provided.".to_string(),
repair: Some(
"Use one preset, for example `--fields preset=standard,why`, or use an explicit field list."
.to_string(),
),
details_json: details.to_string(),
}
}
pub struct ResponseEnvelope {
builder: JsonBuilder,
degraded_written: bool,
inferred_degraded_json: Option<String>,
}
impl ResponseEnvelope {
#[must_use]
pub fn success() -> Self {
let mut builder = JsonBuilder::with_capacity(256);
builder.field_str("schema", RESPONSE_SCHEMA_V2);
builder.field_bool("success", true);
Self {
builder,
degraded_written: false,
inferred_degraded_json: None,
}
}
#[must_use]
pub fn failure() -> Self {
let mut builder = JsonBuilder::with_capacity(256);
builder.field_str("schema", RESPONSE_SCHEMA_V2);
builder.field_bool("success", false);
Self {
builder,
degraded_written: false,
inferred_degraded_json: None,
}
}
pub fn data<F>(mut self, build: F) -> Self
where
F: FnOnce(&mut JsonBuilder),
{
let mut data = JsonBuilder::new();
build(&mut data);
let raw_json = data.finish();
self.inferred_degraded_json = response_degraded_from_data_raw(&raw_json);
self.builder.field_raw("data", &raw_json);
self
}
pub fn data_raw(mut self, raw_json: &str) -> Self {
self.inferred_degraded_json = response_degraded_from_data_raw(raw_json);
self.builder.field_raw("data", raw_json);
self
}
pub fn degraded_array<T, F>(mut self, items: &[T], build: F) -> Self
where
F: Fn(&mut JsonBuilder, &T),
{
self.builder
.field_array_of_objects("degraded", items, build);
self.degraded_written = true;
self
}
#[must_use]
pub fn finish(mut self) -> String {
if !self.degraded_written {
self.builder.field_raw(
"degraded",
self.inferred_degraded_json.as_deref().unwrap_or("[]"),
);
}
self.builder.finish()
}
}
fn response_degraded_from_data_raw(raw_json: &str) -> Option<String> {
if !raw_json.contains("\"degraded\"") {
return None;
}
let data: serde_json::Value = serde_json::from_str(raw_json).ok()?;
let degraded = response_degraded_from_data(&data);
serde_json::to_string(°raded).ok()
}
/// Normalize report-local degradations into the closed top-level
/// `ee.response.v2` degradation schema.
///
/// Entries with invalid required fields are omitted rather than emitting a
/// response that contradicts its schema. Valid siblings are still mirrored.
/// Optional report-only or malformed fields are omitted; the original report
/// data remains untouched.
#[must_use]
pub fn response_degraded_from_data(data: &serde_json::Value) -> serde_json::Value {
let Some(degraded) = data.get("degraded").and_then(serde_json::Value::as_array) else {
return serde_json::json!([]);
};
let normalized = degraded
.iter()
.filter_map(normalize_response_degradation)
.collect();
serde_json::Value::Array(normalized)
}
fn normalize_response_degradation(value: &serde_json::Value) -> Option<serde_json::Value> {
let source = value.as_object()?;
let code = source.get("code")?.as_str()?;
let severity = DegradationSeverity::parse(source.get("severity")?.as_str()?)?;
let message = source.get("message")?.as_str()?;
let mut normalized = serde_json::Map::new();
normalized.insert(
"code".to_string(),
serde_json::Value::String(code.to_string()),
);
normalized.insert(
"severity".to_string(),
serde_json::Value::String(severity.as_str().to_owned()),
);
normalized.insert(
"message".to_string(),
serde_json::Value::String(message.to_string()),
);
// `repair` is the canonical envelope key. Data payloads that name their
// action `nextAction` (backup/export degradations) canonicalize into
// `repair` here so the envelope mirror never silently drops the action.
if let Some(repair) = source
.get("repair")
.or_else(|| source.get("nextAction"))
.and_then(serde_json::Value::as_str)
{
normalized.insert(
"repair".to_string(),
serde_json::Value::String(repair.to_string()),
);
}
if let Some(repair_kind) = source
.get("repairKind")
.and_then(serde_json::Value::as_str)
.filter(|repair_kind| {
matches!(
*repair_kind,
"actionable" | "template" | "placeholder" | "unknown" | "empty"
)
})
{
normalized.insert(
"repairKind".to_string(),
serde_json::Value::String(repair_kind.to_string()),
);
}
if let Some(sources) = source.get("sources").and_then(serde_json::Value::as_array)
&& sources.iter().all(serde_json::Value::is_string)
{
normalized.insert(
"sources".to_string(),
serde_json::Value::Array(sources.clone()),
);
}
if let Some(details) = source.get("details").and_then(serde_json::Value::as_object) {
normalized.insert(
"details".to_string(),
serde_json::Value::Object(details.clone()),
);
}
Some(serde_json::Value::Object(normalized))
}
// ============================================================================
// Output Size Diagnostics (EE-335)
//
// Compare JSON and TOON output sizes to help understand token savings.
// Tokens are estimated using a simple heuristic (words * 4/3).
// ============================================================================
/// Schema identifier for output size diagnostic.
pub const OUTPUT_SIZE_DIAGNOSTIC_SCHEMA_V1: &str = "ee.output_size_diagnostic.v1";
/// Output size diagnostic comparing JSON and TOON representations.
#[derive(Clone, Debug, PartialEq)]
pub struct OutputSizeDiagnostic {
pub json_bytes: usize,
pub toon_bytes: usize,
pub json_estimated_tokens: usize,
pub toon_estimated_tokens: usize,
pub byte_savings: i64,
pub token_savings: i64,
pub compression_ratio: f64,
}
impl OutputSizeDiagnostic {
/// Compute size diagnostic from JSON string.
#[must_use]
pub fn from_json(json: &str) -> Self {
let toon = render_toon_from_json(json);
Self::from_pair(json, &toon)
}
/// Compute size diagnostic from JSON and TOON pair.
#[must_use]
pub fn from_pair(json: &str, toon: &str) -> Self {
let json_bytes = json.len();
let toon_bytes = toon.len();
let json_estimated_tokens = estimate_tokens(json);
let toon_estimated_tokens = estimate_tokens(toon);
let byte_savings = json_bytes as i64 - toon_bytes as i64;
let token_savings = json_estimated_tokens as i64 - toon_estimated_tokens as i64;
let compression_ratio = if json_bytes > 0 {
toon_bytes as f64 / json_bytes as f64
} else {
1.0
};
Self {
json_bytes,
toon_bytes,
json_estimated_tokens,
toon_estimated_tokens,
byte_savings,
token_savings,
compression_ratio,
}
}
/// Render as JSON.
#[must_use]
pub fn to_json(&self) -> String {
let mut b = JsonBuilder::with_capacity(256);
b.field_str("schema", OUTPUT_SIZE_DIAGNOSTIC_SCHEMA_V1);
b.field_object("json", |j| {
j.field_raw("bytes", &self.json_bytes.to_string());
j.field_raw("estimatedTokens", &self.json_estimated_tokens.to_string());
});
b.field_object("toon", |t| {
t.field_raw("bytes", &self.toon_bytes.to_string());
t.field_raw("estimatedTokens", &self.toon_estimated_tokens.to_string());
});
b.field_object("savings", |s| {
s.field_raw("bytes", &self.byte_savings.to_string());
s.field_raw("tokens", &self.token_savings.to_string());
s.field_raw(
"compressionRatio",
&format!("{:.3}", self.compression_ratio),
);
});
b.finish()
}
/// Render as human-readable text.
#[must_use]
pub fn to_human(&self) -> String {
let savings_pct = if self.json_bytes > 0 {
(1.0 - self.compression_ratio) * 100.0
} else {
0.0
};
format!(
"Output Size Diagnostic\n\
─────────────────────────────────────\n\
JSON: {:>8} bytes {:>6} tokens\n\
TOON: {:>8} bytes {:>6} tokens\n\
─────────────────────────────────────\n\
Savings: {:>+6} bytes {:>+5} tokens ({:.1}%)\n",
self.json_bytes,
self.json_estimated_tokens,
self.toon_bytes,
self.toon_estimated_tokens,
self.byte_savings,
self.token_savings,
savings_pct,
)
}
}
/// Estimate token count using the same cl100k_base BPE encoder the pack
/// budget enforcer uses (eidetic_engine_cli-aitk). Routes through
/// `crate::pack::estimate_tokens_default` so JSON-vs-TOON size diagnostics
/// quote the same tokens-per-payload values an `ee context` budget would
/// see.
fn estimate_tokens(text: &str) -> usize {
crate::pack::estimate_tokens_default(text) as usize
}
/// Compute size diagnostics for representative payloads.
#[must_use]
pub fn compute_representative_size_diagnostics() -> Vec<(&'static str, OutputSizeDiagnostic)> {
use crate::core::health::HealthReport;
use crate::core::status::StatusReport;
let mut diagnostics = Vec::new();
// Status report
let status = StatusReport::gather();
let status_json = render_status_json(&status);
diagnostics.push(("status", OutputSizeDiagnostic::from_json(&status_json)));
// Health report
let health = HealthReport::gather();
let health_json = render_health_json(&health);
diagnostics.push(("health", OutputSizeDiagnostic::from_json(&health_json)));
diagnostics
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct ContextJsonRenderOptions {
pub include_rendered_text: bool,
pub include_skipped: bool,
pub include_meta: bool,
pub include_verbose_meta: bool,
/// Bead bd-17c65.5.2 (E2): when `false` (the default), per-response
/// `degraded[]` filters out signals whose [`crate::pack::DegradedCategory`]
/// indicates they do not affect this response (build-time feature
/// gaps, workspace-state conditions). When `true` (`--include-non-affecting-degradations`
/// flag), every signal surfaces regardless of category — the
/// pre-E2 verbose behavior, useful for diagnostic mode and the
/// loud-baseline golden snapshot.
pub include_non_affecting_degradations: bool,
/// Transitional N5.1 compatibility path for consumers explicitly asking for
/// the old field name during the one-release rename window.
pub include_legacy_selection_certificate: bool,
}
impl Default for ContextJsonRenderOptions {
fn default() -> Self {
Self {
include_rendered_text: true,
include_skipped: true,
include_meta: true,
include_verbose_meta: false,
include_non_affecting_degradations: false,
include_legacy_selection_certificate: is_set(EnvVar::LegacySelectionCertificate),
}
}
}
impl From<ContextPackOutputOptions> for ContextJsonRenderOptions {
fn from(options: ContextPackOutputOptions) -> Self {
Self {
include_rendered_text: options.include_rendered_text,
include_skipped: options.include_skipped,
include_meta: options.include_meta,
include_verbose_meta: options.include_verbose_meta,
include_non_affecting_degradations: options.include_non_affecting_degradations,
include_legacy_selection_certificate: is_set(EnvVar::LegacySelectionCertificate),
}
}
}
/// Render a context response as JSON (ee.response.v2 envelope).
#[must_use]
pub fn render_context_response_json(response: &ContextResponse) -> String {
render_context_response_json_with_options(response, ContextJsonRenderOptions::default())
}
/// Render a context response as JSON with caller-selected optional fields.
#[must_use]
pub fn render_context_response_json_with_options(
response: &ContextResponse,
options: ContextJsonRenderOptions,
) -> String {
if let Some(cached_json) = &response.cached_json {
return context_response_cached_json_with_top_level_degraded(cached_json);
}
let rendered_text = options.include_rendered_text.then(|| {
render_context_response_markdown_with_options(
response,
options.include_non_affecting_degradations,
)
});
// Keep the top-level ee.response.v2 envelope and data.degraded in lockstep.
// Both apply the same default filter for non-affecting degradation signals.
let filtered_degraded = || {
response.data.degraded.iter().filter(|d| {
options.include_non_affecting_degradations || d.category().included_by_default()
})
};
let aggregated_degraded = aggregate_context_degraded(filtered_degraded());
let mut b = JsonBuilder::with_capacity(2048 + rendered_text.as_ref().map_or(0, String::len));
b.field_str("schema", response.schema);
b.field_bool("success", response.success);
b.field_object("data", |d| {
d.field_str("command", response.data.command);
d.field_str(
"embed_backend",
response.data.embed_backend.as_str(),
);
d.field_object("request", |request| {
request.field_str("query", &response.data.request.query);
request.field_str("profile", response.data.request.profile.as_str());
request.field_u32("maxTokens", response.data.request.budget.max_tokens());
request.field_u32("candidatePool", response.data.request.candidate_pool);
if let Some(max_results) = response.data.request.max_results {
request.field_u32("maxResults", max_results);
}
if let Some(scope_stats) = &response.data.scope_stats {
request.field_str("memoryScope", scope_stats.scope_applied.as_str());
request.field_bool("strictScope", scope_stats.strict_scope);
}
let sections = string_array_json(
response
.data
.request
.sections
.iter()
.map(|section| section.as_str()),
);
request.field_raw("sections", §ions);
});
if let Some(scope_stats) = &response.data.scope_stats {
d.field_raw("scopeStats", &scope_stats.data_json().to_string());
}
d.field_array_of_objects("consensus", &response.data.consensus, build_consensus_entry);
d.field_array_of_objects("conflicts", &response.data.conflicts, build_conflict_entry);
d.field_object("pack", |pack| {
pack.field_str("schema", PACK_SCHEMA_V2);
pack.field_str("query", &response.data.pack.query);
match &response.data.pack.hash {
Some(hash) => pack.field_str("hash", hash),
None => pack.field_raw("hash", "null"),
};
if let Some(text) = &rendered_text {
pack.field_str("text", text);
}
if options.include_meta {
pack.field_object("meta", |meta| {
meta.field_object("algorithm", |algorithm| {
build_pack_algorithm_metadata(
algorithm,
&response.data.pack.selection_audit,
);
});
if options.include_verbose_meta {
meta.field_object("selectionFormula", |formula| {
formula.field_str(
"summary",
"Strict MMR greedily selects positive marginal-gain items first; optional coverage fill admits redundant but still relevant memories while budget remains.",
);
formula.field_str(
"coverageFillPolicy",
"selected_in=coverage_fill only when include_coverage_fill is active and relevance >= floor",
);
});
}
meta.field_raw(
"coverageFillCount",
&response.data.pack.coverage_fill_count().to_string(),
);
meta.field_raw(
"producer",
&ProducerMetadata::context_pack(None, None).to_json_string_lossy(),
);
});
}
pack.field_object("budget", |budget| {
budget.field_u32("maxTokens", response.data.pack.budget.max_tokens());
budget.field_u32("usedTokens", response.data.pack.used_tokens);
budget.field_raw(
"utilization",
&score_json(
response.data.pack.used_tokens as f32
/ response.data.pack.budget.max_tokens() as f32,
),
);
if let Some(adaptive_budget) = &response.data.adaptive_budget {
budget.field_str("schema", adaptive_budget.schema);
budget.field_bool("adaptive", adaptive_budget.adaptive);
budget.field_u32("baseTokens", adaptive_budget.base_tokens);
budget.field_u32("computedTokens", adaptive_budget.computed_tokens);
budget.field_raw(
"multiplier",
&serde_json::to_string(&adaptive_budget.multiplier)
.unwrap_or_else(|_| "null".to_string()),
);
budget.field_raw(
"classifierContributions",
&serde_json::to_string(&adaptive_budget.classifier_contributions)
.unwrap_or_else(|_| "null".to_string()),
);
}
});
if let Some(slo) = &response.data.slo {
pack.field_object("slo", |slo_obj| {
build_pack_assembly_slo(slo_obj, slo);
});
}
let advisory_banner = context_advisory_banner_with_aggregated_degraded(
response,
filtered_degraded(),
);
pack.field_object("advisoryBanner", |banner| {
build_pack_advisory_banner(banner, &advisory_banner);
});
let quality_metrics = response.data.pack.quality_metrics();
pack.field_object("quality", |quality| {
build_pack_quality_metrics(quality, &quality_metrics);
});
pack.field_object("selectionAudit", |audit| {
build_pack_selection_audit(audit, &response.data.pack.selection_audit);
});
if let Some(coordination) = &response.data.coordination {
if let Ok(coordination_json) = serde_json::to_string(coordination) {
pack.field_raw("coordination", &coordination_json);
}
}
if let Some(mesh) = &response.data.mesh {
if let Ok(mesh_json) = serde_json::to_string(mesh) {
pack.field_raw("mesh", &mesh_json);
}
}
if let Some(pack_dna) = &response.data.pack_dna {
pack.field_raw("packDna", &pack_dna.to_string());
}
if let Some(agent_profile) = &response.data.agent_profile {
pack.field_raw("agentProfile", &agent_profile.to_string());
}
if options.include_legacy_selection_certificate {
pack.field_object("deprecation", |deprecation| {
deprecation.field_str("deprecatedField", "selectionCertificate");
deprecation.field_str("replacementField", "selectionAudit");
deprecation.field_str("removalRelease", "0.3.0");
deprecation.field_str(
"message",
"selectionCertificate was renamed to selectionAudit by ADR 0031.",
);
});
pack.field_object("selectionCertificate", |legacy| {
build_pack_selection_audit(legacy, &response.data.pack.selection_audit);
});
}
// Bead bd-17c65.1.1 (A1 phase 1): consolidate per-item data from the
// four parallel pack structures (`items[]`, `selectionAudit
// .selected_items[]`, `selectionAudit.steps[]`,
// `provenanceFooter.entries[]`) onto each `items[]` entry. The
// legacy selected structures no longer emit in JSON. After phase
// 2, an agent reading `items[i]` gets the union of fields and no
// longer has to walk three more arrays to find tokenCost /
// feasibility / step trace data.
let selected_by_rank: std::collections::BTreeMap<u32, &PackSelectedItem> = response
.data
.pack
.selection_audit
.selected_items
.iter()
.map(|s| (s.rank, s))
.collect();
let step_by_rank: std::collections::BTreeMap<u32, &PackSelectionStep> = response
.data
.pack
.selection_audit
.steps
.iter()
.map(|s| (s.rank, s))
.collect();
let footer = response.data.pack.provenance_footer();
let footer_by_rank: std::collections::BTreeMap<u32, &PackItemProvenance> =
footer.entries.iter().map(|e| (e.rank, e)).collect();
pack.field_array_of_objects_chained(
"items",
&response.data.pack.items,
&response.data.pack.evidence_items,
|obj, item| {
obj.field_u32("rank", item.rank);
obj.field_str("memoryId", &item.memory_id.to_string());
obj.field_str("section", item.section.as_str());
obj.field_str("content", &item.content);
if !item.redactions.is_empty() {
obj.field_bool("contentRedacted", true);
}
obj.field_u32("estimatedTokens", item.estimated_tokens);
obj.field_object("scores", |scores| {
scores.field_raw("relevance", &score_json(item.relevance.into_inner()));
scores.field_raw("utility", &score_json(item.utility.into_inner()));
if let Some(proximity_to_seed) = item.proximity_to_seed {
scores.field_raw("proximityToSeed", &score_json(proximity_to_seed));
}
// A1 phase 1: surface marginalGain / objectiveValue from the
// selection-step trace so agents don't have to cross-reference
// selectionAudit.steps[] by rank.
if let Some(step) = step_by_rank.get(&item.rank) {
scores.field_raw("marginalGain", &score_json(step.marginal_gain));
scores.field_raw("objectiveValue", &score_json(step.objective_value));
}
});
obj.field_object("trust", |trust| {
trust.field_str("class", item.trust.class.as_str());
match item.trust.subclass.as_deref() {
Some(subclass) => trust.field_str("subclass", subclass),
None => trust.field_raw("subclass", "null"),
};
trust.field_str("posture", item.trust.posture().as_str());
});
if let Some(provenance) = crate::pack::team_pack_provenance_json(&item.trust) {
obj.field_raw("teamProvenance", &provenance);
}
let provenance = item.rendered_provenance();
obj.field_array_of_objects("provenance", &provenance, build_rendered_provenance);
if !item.freshness_facets.is_empty() {
obj.field_array_of_objects(
"freshnessFacets",
&item.freshness_facets,
build_pack_freshness_facet,
);
}
if !item.redactions.is_empty() {
obj.field_array_of_objects(
"redactions",
&item.redactions,
|redaction_obj, redaction| {
redaction_obj.field_str("reason", redaction.reason);
redaction_obj.field_str("placeholder", &redaction.placeholder);
},
);
}
obj.field_str("why", &item.why);
obj.field_str("selectedIn", item.selected_in.as_str());
if let Some(score_breakdown) = item.score_breakdown {
obj.field_object("selection", |selection| {
selection.field_object("scoreBreakdown", |breakdown| {
breakdown
.field_raw("textScore", &score_json(score_breakdown.text_score));
breakdown
.field_raw("pprScore", &score_json(score_breakdown.ppr_score));
breakdown.field_raw(
"combinedScore",
&score_json(score_breakdown.combined_score),
);
});
});
}
if item.lifecycle.is_some() || item.tombstoned_at.is_some() {
obj.field_object("lifecycle", |lifecycle| {
match (&item.tombstoned_at, &item.lifecycle) {
(Some(_), _) => lifecycle.field_str("status", "tombstoned"),
(None, Some(item_lifecycle)) => {
lifecycle.field_str("status", &item_lifecycle.validity_status)
}
(None, None) => lifecycle.field_str("status", "unknown"),
};
if let Some(item_lifecycle) = &item.lifecycle {
lifecycle.field_str(
"validity_status",
&item_lifecycle.validity_status,
);
lifecycle.field_str(
"validity_window_kind",
&item_lifecycle.validity_window_kind,
);
field_optional_str(
lifecycle,
"valid_from",
item_lifecycle.valid_from.as_deref(),
);
field_optional_str(
lifecycle,
"valid_to",
item_lifecycle.valid_to.as_deref(),
);
}
if let Some(tombstoned_at) = &item.tombstoned_at {
lifecycle.field_str("tombstonedAt", tombstoned_at);
}
});
}
if let Some(diversity_key) = &item.diversity_key {
obj.field_str("diversityKey", diversity_key);
}
// A1 phase 1: surface feasibility + tokenCost from the
// audit's selected_items[] lookup so agents reading items[]
// don't have to chase selectionAudit.selectedItems
// for per-item budget feasibility.
if let Some(selected) = selected_by_rank.get(&item.rank) {
obj.field_u32("tokenCost", selected.token_cost);
obj.field_bool("feasible", selected.feasible);
}
// A1 phase 1: surface coveredFeatures from the step trace so
// diversity-coverage reasoning is co-located with the rest of
// the item's selection rationale.
if let Some(step) = step_by_rank.get(&item.rank) {
obj.field_raw(
"coveredFeatures",
&string_array_json(step.covered_features.iter()),
);
}
// A1 phase 1: surface sourceIndex from provenanceFooter.entries[]
// so callers don't have to join the footer array on rank.
if let Some(footer_entry) = footer_by_rank.get(&item.rank) {
obj.field_u32("sourceIndex", footer_entry.source_index);
}
},
build_pack_evidence_item,
);
pack.field_raw(
"skippedTotal",
&response.data.pack.skipped_total().to_string(),
);
if options.include_skipped {
let skipped = response.data.pack.skipped_for_output();
pack.field_array_of_objects("skipped", &skipped, |obj, omission| {
build_pack_skipped_item(obj, omission);
});
}
// Bead bd-2pe1z (A1 phase 2): drop provenanceFooter.entries[]. Each
// entry's sourceIndex is now emitted inline on the matching
// items[] entry (A1 phase 1). The summary fields (memoryCount,
// sourceCount, schemes) remain — they are aggregate stats with no
// per-item home.
pack.field_object("provenanceFooter", |obj| {
obj.field_raw("memoryCount", &footer.memory_count.to_string());
if footer.evidence_count > 0 {
obj.field_raw("evidenceCount", &footer.evidence_count.to_string());
}
obj.field_raw("sourceCount", &footer.source_count.to_string());
obj.field_raw(
"schemes",
&string_array_json(footer.schemes.iter()),
);
});
});
if let Some(pagination) = &response.data.pagination {
d.field_object("pagination", |pagination_obj| {
build_context_response_pagination(pagination_obj, pagination);
});
}
d.field_array_of_objects("degraded", &aggregated_degraded, build_aggregated_degradation);
});
b.field_array_of_objects(
"degraded",
&aggregated_degraded,
build_aggregated_degradation,
);
b.finish()
}
fn build_pack_evidence_item(obj: &mut JsonBuilder, item: &PackEvidenceItem) {
obj.field_u32("rank", item.rank);
obj.field_str("entityKind", "evidence_span");
obj.field_str("evidenceSpanId", &item.evidence_id);
obj.field_str("entityRevision", &item.entity_revision);
obj.field_str("sessionId", &item.session_id);
obj.field_u32("startLine", item.start_line);
obj.field_u32("endLine", item.end_line);
obj.field_str("section", item.section.as_str());
obj.field_str("content", &item.content);
obj.field_u32("estimatedTokens", item.estimated_tokens);
obj.field_object("scores", |scores| {
scores.field_raw("relevance", &score_json(item.relevance.into_inner()));
scores.field_raw("utility", &score_json(item.utility.into_inner()));
});
obj.field_object("trust", |trust| {
trust.field_str("class", item.trust.class.as_str());
match item.trust.subclass.as_deref() {
Some(subclass) => trust.field_str("subclass", subclass),
None => trust.field_raw("subclass", "null"),
};
trust.field_str("posture", item.trust.posture().as_str());
});
let provenance = item.rendered_provenance();
obj.field_array_of_objects("provenance", &provenance, build_rendered_provenance);
obj.field_u32("sourceIndex", 1);
obj.field_str("why", &item.why);
obj.field_str("selectedIn", "direct_evidence");
obj.field_u32("tokenCost", item.estimated_tokens);
obj.field_bool("feasible", true);
}
fn context_response_cached_json_with_top_level_degraded(cached_json: &str) -> String {
let Ok(mut value) = serde_json::from_str::<serde_json::Value>(cached_json) else {
return cached_json.to_owned();
};
if value.get("schema").and_then(serde_json::Value::as_str) != Some(RESPONSE_SCHEMA_V2) {
return cached_json.to_owned();
}
let Some(object) = value.as_object_mut() else {
return cached_json.to_owned();
};
if !object.contains_key("degraded") {
let degraded = object
.get("data")
.map(response_degraded_from_data)
.unwrap_or_else(|| serde_json::json!([]));
object.insert("degraded".to_string(), degraded);
}
serde_json::to_string(&value).unwrap_or_else(|_| cached_json.to_owned())
}
fn build_context_response_pagination(
obj: &mut JsonBuilder,
pagination: &ContextResponsePagination,
) {
obj.field_u32("offset", pagination.offset);
obj.field_u32("limit", pagination.limit);
obj.field_u32("total", pagination.total);
obj.field_bool("hasMore", pagination.has_more);
field_optional_str(obj, "nextCursor", pagination.next_cursor.as_deref());
}
#[must_use]
pub fn render_context_response_binary_with_options(
response: &ContextResponse,
options: ContextJsonRenderOptions,
) -> Vec<u8> {
let canonical_json = render_context_response_json_with_options(response, options);
crate::pack::binary::serialize_context_response_binary(response, &canonical_json)
}
fn build_consensus_entry(obj: &mut JsonBuilder, entry: &ConsensusEntry) {
obj.field_str("schema", entry.schema);
obj.field_str("subjectFingerprint", &entry.subject_fingerprint);
obj.field_str("subjectSummary", &entry.subject_summary);
obj.field_raw("agreementScore", &score_json(entry.agreement_score));
obj.field_raw(
"memberMemoryIds",
&string_array_json(entry.member_memory_ids.iter().map(ToString::to_string)),
);
obj.field_array_of_objects(
"memberProducers",
&entry.member_producers,
build_consensus_producer,
);
obj.field_raw(
"semanticSimilarityMin",
&score_json(entry.semantic_similarity_min),
);
field_optional_str(obj, "firstRecordedAt", entry.first_recorded_at.as_deref());
field_optional_str(obj, "lastReinforcedAt", entry.last_reinforced_at.as_deref());
}
fn build_consensus_producer(obj: &mut JsonBuilder, producer: &ConsensusProducer) {
field_optional_str(obj, "agentName", producer.agent_name.as_deref());
obj.field_str("trustClass", producer.trust_class.as_str());
}
fn build_conflict_entry(obj: &mut JsonBuilder, entry: &ConflictEntry) {
obj.field_str("schema", entry.schema);
obj.field_str("subjectFingerprint", &entry.subject_fingerprint);
obj.field_str("kind", entry.kind.as_str());
obj.field_raw(
"conflictingMemoryIds",
&string_array_json(entry.conflicting_memory_ids.iter().map(ToString::to_string)),
);
obj.field_raw(
"evidencePointers",
&string_array_json(entry.evidence_pointers.iter()),
);
field_optional_str(obj, "earliestAt", entry.earliest_at.as_deref());
field_optional_str(obj, "latestAt", entry.latest_at.as_deref());
obj.field_str("recommendedAction", entry.recommended_action.as_str());
}
/// Render a context response as human-readable text.
#[must_use]
pub fn render_context_response_human(response: &ContextResponse) -> String {
let mut output = String::new();
output.push_str(&format!("ee pack \"{}\"\n\n", response.data.request.query));
output.push_str(&format!(
"Profile: {} | Budget: {}/{} tokens | Pack hash: {}\nembed_backend: {}\n\n",
response.data.request.profile.as_str(),
response.data.pack.used_tokens,
response.data.pack.budget.max_tokens(),
context_pack_hash(response),
response.data.embed_backend.as_str()
));
let advisory_banner =
context_advisory_banner_with_aggregated_degraded(response, response.data.degraded.iter());
output.push_str(&format!(
"Advisory: {} — {}\n\n",
advisory_banner.status.as_str(),
advisory_banner.summary
));
if !advisory_banner.notes.is_empty() {
output.push_str("Advisory notes:\n");
for note in &advisory_banner.notes {
output.push_str(&format!(
" [{}] {}: {}\n",
note.severity.as_str(),
note.code,
note.message
));
}
output.push('\n');
}
if response.data.pack.items.is_empty() {
output.push_str("No items in pack.\n");
} else {
output.push_str("Items:\n");
for item in &response.data.pack.items {
output.push_str(&format!(
" {}. [{}] {} ({}t)\n",
item.rank,
item.section.as_str(),
item.memory_id,
item.estimated_tokens
));
}
}
let degraded = aggregate_context_degraded(response.data.degraded.iter());
if !degraded.is_empty() {
output.push_str("\nDegraded:\n");
for d in °raded {
output.push_str(&format!(" [{}] {}\n", d.severity, d.message));
if !d.repair.is_empty() {
output.push_str(&format!(" Next: {}\n", d.repair));
}
output.push_str(&format!(" Sources: {}\n", d.sources.join(", ")));
}
}
output.push_str("\nNext:\n ee pack --json \"<query>\"\n");
output
}
/// Render a context response as TOON.
#[must_use]
pub fn render_context_response_toon(response: &ContextResponse) -> String {
render_toon_from_json(&render_context_response_json(response))
}
/// Render a context response as JSON Lines.
///
/// The first line is pack-level metadata, each item gets one independent
/// line, and the final line carries omitted/degraded summary counts. Every
/// line repeats the pack hash so streaming consumers can correlate partial
/// reads back to the canonical pack record.
#[must_use]
pub fn render_context_response_jsonl(response: &ContextResponse) -> String {
let mut lines = Vec::with_capacity(response.data.pack.items.len() + 2);
let mut header = JsonBuilder::with_capacity(256);
header.field_str("schema", "ee.context.jsonl.header.v1");
header.field_str("packHash", context_pack_hash(response));
header.field_str("query", &response.data.request.query);
header.field_u32("usedTokens", response.data.pack.used_tokens);
header.field_u32("maxTokens", response.data.pack.budget.max_tokens());
header.field_raw("itemCount", &response.data.pack.items.len().to_string());
lines.push(header.finish());
for item in &response.data.pack.items {
let provenance = item.rendered_provenance();
let mut line = JsonBuilder::with_capacity(384 + item.content.len());
line.field_str("schema", "ee.context.jsonl.item.v1");
line.field_str("packHash", context_pack_hash(response));
line.field_u32("rank", item.rank);
line.field_str("memoryId", &item.memory_id.to_string());
line.field_str("section", item.section.as_str());
line.field_str("content", &item.content);
if !item.redactions.is_empty() {
line.field_bool("contentRedacted", true);
}
line.field_u32("estimatedTokens", item.estimated_tokens);
line.field_str("why", &item.why);
line.field_str("selectedIn", item.selected_in.as_str());
if let Some(team_provenance) = crate::pack::team_pack_provenance_json(&item.trust) {
line.field_raw("teamProvenance", &team_provenance);
}
line.field_array_of_objects("provenance", &provenance, build_rendered_provenance);
lines.push(line.finish());
}
let mut footer = JsonBuilder::with_capacity(192);
footer.field_str("schema", "ee.context.jsonl.footer.v1");
footer.field_str("packHash", context_pack_hash(response));
footer.field_raw(
"skippedTotal",
&response.data.pack.skipped_total().to_string(),
);
let degraded = aggregate_context_degraded(response.data.degraded.iter());
footer.field_raw("degradedCount", °raded.len().to_string());
lines.push(footer.finish());
lines.join("\n")
}
/// Render a terse, single-line context response for shell hooks.
#[must_use]
pub fn render_context_response_compact(response: &ContextResponse) -> String {
format!(
"{}\t{}/{}\t{}\t{}",
compact_field(&response.data.request.query),
response.data.pack.items.len(),
response.data.pack.budget.max_tokens(),
compact_field(&top_context_item_ids(response)),
context_pack_hash(response)
)
}
/// Render the stable hook contract consumed by agent harness integrations.
#[must_use]
pub fn render_context_response_hook(response: &ContextResponse) -> String {
let mut b = JsonBuilder::with_capacity(512);
b.field_str("schema", "ee.hook.context_pack.v1");
b.field_str("pack_id", context_pack_hash(response));
b.field_raw("total_tokens", &response.data.pack.used_tokens.to_string());
b.field_array_of_objects("items", &response.data.pack.items, |obj, item| {
obj.field_str("id", &item.memory_id.to_string());
obj.field_str("content", &item.content);
obj.field_u32("tokens", item.estimated_tokens);
});
// Bead bd-17c65.5.2 (E2): the hook surface mirrors the JSON
// contract — non-affecting signals are filtered out by default
// so a downstream hook consumer (claude-code PreToolUse, etc.)
// sees only signals the current response was actually affected
// by. Hook callers that need the verbose surface should pipe the
// raw `ee context --json --include-non-affecting-degradations`
// instead of the hook envelope.
let filtered_hook_degraded = response
.data
.degraded
.iter()
.filter(|d| d.category().included_by_default());
let degraded = aggregate_context_degraded(filtered_hook_degraded);
b.field_array_of_objects("degraded", °raded, build_aggregated_degradation);
b.finish()
}
/// Render a Mermaid graph projection of the canonical context pack.
#[must_use]
pub fn render_context_response_mermaid(response: &ContextResponse) -> String {
let mut output = String::new();
output.push_str(&format!("%% pack.hash: {}\n", context_pack_hash(response)));
output.push_str(&format!("%% pack.schema: {}\n", response.schema));
output.push_str("graph TD\n");
output.push_str(&format!(
" pack[\"{}\"]\n",
escape_mermaid_label(&format!("context pack: {}", response.data.request.query))
));
let mut source_nodes = std::collections::BTreeSet::new();
for item in &response.data.pack.items {
let item_node = mermaid_node_id("mem", &item.memory_id.to_string());
output.push_str(&format!(
" {item_node}[\"{}\"]\n",
escape_mermaid_label(&format!("{}: {}", item.rank, item.memory_id))
));
output.push_str(&format!(" pack --> {item_node}\n"));
for provenance in item.rendered_provenance() {
let source_node = mermaid_node_id("src", &provenance.uri);
if source_nodes.insert(source_node.clone()) {
output.push_str(&format!(
" {source_node}[\"{}\"]\n",
escape_mermaid_label(&provenance.label)
));
}
output.push_str(&format!(" {item_node} --> {source_node}\n"));
}
}
if response.data.pack.items.is_empty() {
output.push_str(" empty[\"no items selected\"]\n");
output.push_str(" pack --> empty\n");
}
output
}
/// Render a context response as Markdown.
///
/// Produces a structured Markdown document suitable for direct inclusion
/// in agent context windows or documentation. Sections are organized by
/// pack section, with provenance and why explanations preserved.
#[must_use]
pub fn render_context_response_markdown(response: &ContextResponse) -> String {
// Standalone callers keep the full degradation set (include_non_affecting =
// true) so existing markdown surfaces and the dual-render parity contract
// stay byte-identical. The JSON data.pack.text path (bd-2v6r0) instead
// threads the caller's include_non_affecting_degradations flag so the
// rendered text honors the same default-emission filter as data.degraded[].
render_context_response_markdown_with_options(response, true)
}
/// Render the context response markdown, optionally dropping non-affecting
/// degradation signals (workspace-state and build-time-gap categories) from the
/// `## Degradations` section. When `include_non_affecting` is false the rendered
/// text honors the same default-emission contract as the per-response
/// `degraded[]` array (bd-2v6r0 / bd-17c65.5.2): an agent reading the pack text
/// sees only the signals that actually affected this response.
#[must_use]
pub fn render_context_response_markdown_with_options(
response: &ContextResponse,
include_non_affecting: bool,
) -> String {
let filtered = response
.data
.degraded
.iter()
.filter(|entry| include_non_affecting || entry.category().included_by_default());
let degraded = aggregate_context_degraded_as_response(filtered);
let mut markdown =
crate::pack::render_context_response_markdown_with_degraded(response, °raded);
if let Some(heading_end) = markdown.find("\n\n") {
markdown.insert_str(
heading_end + 2,
&format!(
"**embed_backend:** `{}`\n\n",
response.data.embed_backend.as_str()
),
);
}
if let Some(pack_dna) = &response.data.pack_dna {
insert_context_pack_dna_markdown(&mut markdown, pack_dna);
}
markdown
}
fn insert_context_pack_dna_markdown(markdown: &mut String, pack_dna: &serde_json::Value) {
let pack_dna_markdown = render_pack_dna_markdown(pack_dna);
let block = format!("\n{pack_dna_markdown}");
if let Some(footer_start) = markdown.find("\n---\n\n*Generated by ") {
markdown.insert_str(footer_start, &block);
} else {
markdown.push_str(&block);
}
}
fn context_pack_hash(response: &ContextResponse) -> &str {
response.data.pack.hash.as_deref().unwrap_or("absent")
}
fn context_advisory_banner_with_aggregated_degraded<'a, I>(
response: &ContextResponse,
degraded: I,
) -> PackAdvisoryBanner
where
I: IntoIterator<Item = &'a ContextResponseDegradation>,
{
let degraded = aggregate_context_degraded_as_response(degraded);
response.data.advisory_banner_for_degraded(°raded)
}
fn aggregate_context_degraded<'a, I>(degraded: I) -> Vec<AggregatedDegradation>
where
I: IntoIterator<Item = &'a ContextResponseDegradation>,
{
aggregate_degraded_entries(degraded.into_iter().map(|entry| {
DegradationAggregationInput::new(
context_degradation_source(&entry.code),
entry.code.clone(),
entry.severity.as_str(),
entry.message.clone(),
entry.repair.clone().unwrap_or_default(),
)
}))
}
fn aggregate_context_degraded_as_response<'a, I>(degraded: I) -> Vec<ContextResponseDegradation>
where
I: IntoIterator<Item = &'a ContextResponseDegradation>,
{
aggregate_context_degraded(degraded)
.into_iter()
.filter_map(|entry| {
ContextResponseDegradation::new(
entry.code,
context_severity_from_str(&entry.severity),
entry.message,
(!entry.repair.is_empty()).then_some(entry.repair),
)
.ok()
})
.collect()
}
fn build_aggregated_degradation(obj: &mut JsonBuilder, degraded: &AggregatedDegradation) {
obj.field_str("code", °raded.code);
obj.field_str("severity", °raded.severity);
obj.field_str("message", °raded.message);
if !degraded.repair.is_empty() {
build_repair_fields(obj, °raded.repair);
}
obj.field_raw(
"sources",
&string_array_json(degraded.sources.iter().map(String::as_str)),
);
let recovery_actions = degraded_recovery_actions_for_code(°raded.code);
if !recovery_actions.is_empty() {
obj.field_object("details", |details| {
details.field_array_of_objects(
"recovery",
&recovery_actions,
build_recovery_action_fields,
);
});
}
}
fn build_repair_fields(obj: &mut JsonBuilder, repair: &str) {
obj.field_str("repair", repair);
obj.field_str("repairKind", repair_command_kind_name(repair));
}
fn repair_command_kind_name(repair: &str) -> &'static str {
match classify_repair_command(repair) {
RepairCommandKind::Actionable => "actionable",
RepairCommandKind::Template => "template",
RepairCommandKind::Placeholder => "placeholder",
RepairCommandKind::Unknown => "unknown",
RepairCommandKind::Empty => "empty",
}
}
fn degraded_recovery_actions_for_code(code: &str) -> Vec<RecoveryAction> {
if code == PACK_BUDGET_TOO_SMALL_CODE {
return pack_budget_too_small_recovery_actions();
}
if code == PACK_CONCURRENT_LIMIT_REACHED_CODE {
return pack_concurrent_limit_reached_recovery_actions();
}
degraded_recovery_actions(code)
}
fn pack_budget_too_small_recovery_actions() -> Vec<RecoveryAction> {
vec![
RecoveryAction::flag(
1,
"--max-tokens",
"8000",
"Most common cause; raise budget until a section fits.",
),
RecoveryAction::flag(
2,
"--profile",
"compact",
"Switch to the lowest-quota profile if budget can't be raised.",
),
RecoveryAction::broaden(
3,
"Candidate pool may be too narrow; broaden query text or relax EQL tag filters.",
),
]
}
fn pack_concurrent_limit_reached_recovery_actions() -> Vec<RecoveryAction> {
vec![
RecoveryAction {
priority: 1,
kind: RecoveryKind::Narrow,
rationale:
"Honor admission.retryAfterMs before retrying the same deterministic context call."
.to_owned(),
env_name: None,
value_hint: None,
config_path: None,
config_key: None,
flag_name: None,
command: None,
results_in: None,
example: None,
},
RecoveryAction::flag(
2,
"--resource-profile",
"swarm_heavy",
"Use the higher-cap profile only when the host has capacity for more concurrent pack assembly.",
),
RecoveryAction {
priority: 3,
kind: RecoveryKind::Seed,
rationale:
"Prewarm cache entries before the next burst so foreground context calls do less pack work."
.to_owned(),
env_name: None,
value_hint: None,
config_path: None,
config_key: None,
flag_name: None,
command: None,
results_in: None,
example: Some("ee cache prewarm --from-hotset latest --profile lean --json".to_owned()),
},
]
}
fn build_recovery_action_fields(obj: &mut JsonBuilder, action: &RecoveryAction) {
let safety = action.safety();
obj.field_u32("priority", u32::from(action.priority));
obj.field_str("kind", action.kind.as_str());
obj.field_str("rationale", &action.rationale);
obj.field_str("riskClass", safety.risk_class.as_str());
if let Some(preflight_command) = &safety.preflight_command {
obj.field_str("preflightCommand", preflight_command);
}
obj.field_bool("requiresHumanApproval", safety.requires_human_approval);
obj.field_bool("mutatesExternalState", safety.mutates_external_state);
obj.field_bool("mutatesTrackerState", safety.mutates_tracker_state);
obj.field_str("privacyClass", safety.privacy_class);
if let Some(manual_step) = safety.manual_step {
obj.field_str("manualStep", manual_step);
}
if !safety.evidence.is_empty() {
obj.field_array_of_strs("evidence", &safety.evidence);
}
if !safety.preconditions.is_empty() {
obj.field_array_of_strs("preconditions", &safety.preconditions);
}
if let Some(name) = &action.env_name {
obj.field_str("envName", name);
}
if let Some(hint) = &action.value_hint {
obj.field_str("valueHint", hint);
}
if let Some(path) = &action.config_path {
obj.field_str("configPath", path);
}
if let Some(key) = &action.config_key {
obj.field_str("configKey", key);
}
if let Some(flag) = &action.flag_name {
obj.field_str("flagName", flag);
}
if let Some(command) = &action.command {
obj.field_str("command", command);
}
if let Some(results) = &action.results_in {
obj.field_str("resultsIn", results);
}
if let Some(example) = &action.example {
obj.field_str("example", example);
}
}
fn aggregate_status_degradations(
source: &'static str,
degraded: &[DegradationReport],
) -> Vec<AggregatedDegradation> {
aggregate_degraded_entries(degraded.iter().map(|entry| {
DegradationAggregationInput::new(
source,
entry.code,
entry.severity,
entry.message,
entry.repair,
)
}))
}
fn aggregate_tailscale_status_degradations(
degraded: &[TailscaleProbeDegradation],
) -> Vec<AggregatedDegradation> {
aggregate_degraded_entries(degraded.iter().map(|entry| {
DegradationAggregationInput::new(
"tailscale_status",
entry.code,
entry.severity,
entry.message.as_str(),
entry.repair,
)
}))
}
fn aggregate_shard_fanout_status_degradations(
degraded: &[crate::db::shard::ShardFanoutDegradation],
) -> Vec<AggregatedDegradation> {
aggregate_degraded_entries(degraded.iter().map(|entry| {
DegradationAggregationInput::new(
"shard_fanout",
entry.code,
entry.severity,
entry.message,
entry.repair,
)
}))
}
fn aggregate_qos_status_degradations(
degraded: &[crate::core::qos::QosRegistryDegradation],
) -> Vec<AggregatedDegradation> {
aggregate_degraded_entries(degraded.iter().map(|entry| {
DegradationAggregationInput::new(
"qos_registry",
entry.code.as_str(),
entry.severity.as_str(),
entry.message.as_str(),
entry.repair.as_str(),
)
}))
}
fn aggregate_build_provenance_degradations(
degraded: &[BuildProvenanceDegradation],
) -> Vec<AggregatedDegradation> {
aggregate_degraded_entries(degraded.iter().map(|entry| {
DegradationAggregationInput::new(
"build",
entry.code,
entry.severity,
entry.message,
entry.repair,
)
}))
}
fn aggregate_agent_inventory_degradations(
degraded: &[crate::core::agent_detect::AgentInventoryDegradation],
) -> Vec<AggregatedDegradation> {
aggregate_degraded_entries(degraded.iter().map(|entry| {
DegradationAggregationInput::new(
"agent_detection",
entry.code.clone(),
entry.severity,
entry.message.clone(),
entry.repair,
)
}))
}
fn aggregate_integrity_degradations(
degraded: &[IntegrityDiagnosticDegradation],
) -> Vec<AggregatedDegradation> {
aggregate_degraded_entries(degraded.iter().map(|entry| {
DegradationAggregationInput::new(
"integrity",
entry.code,
entry.severity,
entry.message.clone(),
entry.repair.unwrap_or_default(),
)
}))
}
fn aggregate_quarantine_degradations(
degraded: &[QuarantineDegradation],
) -> Vec<AggregatedDegradation> {
aggregate_degraded_entries(degraded.iter().map(|entry| {
DegradationAggregationInput::new(
"quarantine",
entry.code,
entry.severity,
entry.message.clone(),
entry.repair,
)
}))
}
fn aggregate_structural_health_degradations(
degraded: &[StructuralHealthDegradation],
) -> Vec<AggregatedDegradation> {
aggregate_degraded_entries(degraded.iter().map(|entry| {
DegradationAggregationInput::new(
"structural_health",
entry.code.clone(),
entry.severity.clone(),
entry.message.clone(),
entry.repair.clone().unwrap_or_default(),
)
}))
}
fn context_degradation_source(code: &str) -> &'static str {
if matches!(code, "query_unknown_field") {
"request"
} else if code.starts_with("index_")
|| code.starts_with("search_")
|| code.contains("_recall")
|| code.contains("_filtered")
{
"search"
} else if code.starts_with("pack_")
|| code.starts_with("consensus_")
|| code.starts_with("conflict_")
{
"pack"
} else {
"context"
}
}
fn context_severity_from_str(severity: &str) -> ContextResponseSeverity {
ContextResponseSeverity::parse_lossy(severity)
}
fn top_context_item_ids(response: &ContextResponse) -> String {
let ids = response
.data
.pack
.items
.iter()
.take(3)
.map(|item| item.memory_id.to_string())
.collect::<Vec<_>>();
if ids.is_empty() {
"-".to_owned()
} else {
ids.join(",")
}
}
fn compact_field(value: &str) -> String {
value
.chars()
.map(|character| match character {
'\t' | '\n' | '\r' => ' ',
other => other,
})
.collect()
}
fn mermaid_node_id(prefix: &str, value: &str) -> String {
let mut id = String::with_capacity(prefix.len() + value.len() + 1);
id.push_str(prefix);
id.push('_');
for character in value.chars() {
if character.is_ascii_alphanumeric() {
id.push(character);
} else {
id.push('_');
}
}
id
}
fn build_pack_advisory_banner(obj: &mut JsonBuilder, banner: &PackAdvisoryBanner) {
obj.field_str("status", banner.status.as_str());
obj.field_str("summary", &banner.summary);
obj.field_raw(
"authoritativeCount",
&banner.authoritative_count.to_string(),
);
obj.field_raw("advisoryCount", &banner.advisory_count.to_string());
obj.field_raw("legacyCount", &banner.legacy_count.to_string());
obj.field_raw("degradationCount", &banner.degradation_count.to_string());
obj.field_array_of_objects("notes", &banner.notes, build_pack_advisory_note);
}
fn build_pack_advisory_note(obj: &mut JsonBuilder, note: &PackAdvisoryNote) {
obj.field_str("code", note.code);
obj.field_str("severity", note.severity.as_str());
obj.field_str("message", ¬e.message);
obj.field_raw(
"memoryIds",
&string_array_json(note.memory_ids.iter().map(String::as_str)),
);
obj.field_str("action", note.action);
}
fn build_pack_quality_metrics(obj: &mut JsonBuilder, metrics: &PackQualityMetrics) {
obj.field_raw("itemCount", &metrics.item_count.to_string());
obj.field_raw("omittedCount", &metrics.omitted_count.to_string());
obj.field_u32("usedTokens", metrics.used_tokens);
obj.field_u32("maxTokens", metrics.max_tokens);
obj.field_raw("budgetUtilization", &score_json(metrics.budget_utilization));
obj.field_raw("averageRelevance", &score_json(metrics.average_relevance));
obj.field_raw("averageUtility", &score_json(metrics.average_utility));
obj.field_raw(
"provenanceSourceCount",
&metrics.provenance_source_count.to_string(),
);
obj.field_raw(
"provenanceSourcesPerItem",
&score_json(metrics.provenance_sources_per_item),
);
obj.field_bool("provenanceComplete", metrics.provenance_complete);
obj.field_raw(
"coverageFillCount",
&metrics.coverage_fill_count.to_string(),
);
obj.field_array_of_objects("sections", &metrics.sections, build_pack_section_metric);
obj.field_object("omissions", |omissions| {
build_pack_omission_metrics(omissions, &metrics.omissions);
});
}
fn build_pack_section_metric(obj: &mut JsonBuilder, metric: &PackSectionMetric) {
obj.field_str("section", metric.section.as_str());
obj.field_raw("itemCount", &metric.item_count.to_string());
obj.field_u32("usedTokens", metric.used_tokens);
}
fn build_pack_omission_metrics(obj: &mut JsonBuilder, metrics: &PackOmissionMetrics) {
obj.field_raw(
"tokenBudgetExceeded",
&metrics.token_budget_exceeded.to_string(),
);
obj.field_raw(
"redundantCandidates",
&metrics.redundant_candidates.to_string(),
);
obj.field_raw(
"belowRelevanceFloor",
&metrics.below_relevance_floor.to_string(),
);
}
fn build_pack_assembly_slo(obj: &mut JsonBuilder, slo: &PackAssemblySlo) {
obj.field_str("schema", slo.schema);
obj.field_str("profile", slo.profile.as_str());
obj.field_object("budgetClass", |budget| {
budget.field_raw(
"candidatesScannedMax",
&slo.budget_class.candidates_scanned_max.to_string(),
);
budget.field_raw(
"graphTraversalMaxEdges",
&slo.budget_class.graph_traversal_max_edges.to_string(),
);
budget.field_raw(
"elapsedMsTarget",
&slo.budget_class.elapsed_ms_target.to_string(),
);
budget.field_raw(
"elapsedMsWarning",
&slo.budget_class.elapsed_ms_warning.to_string(),
);
budget.field_raw(
"elapsedMsFailure",
&slo.budget_class.elapsed_ms_failure.to_string(),
);
budget.field_raw(
"concurrentPackMax",
&slo.budget_class.concurrent_pack_max.to_string(),
);
});
match &slo.admission {
Some(admission) => {
obj.field_object("admission", |admission_obj| {
build_pack_admission_posture(admission_obj, admission);
});
}
None => {
obj.field_raw("admission", "null");
}
};
obj.field_object("actuals", |actuals| {
actuals.field_raw("candidateCount", &slo.actuals.candidate_count.to_string());
actuals.field_raw("scannedCount", &slo.actuals.scanned_count.to_string());
match slo.actuals.index_generation {
Some(generation) => actuals.field_raw("indexGeneration", &generation.to_string()),
None => actuals.field_raw("indexGeneration", "null"),
};
match slo.actuals.graph_generation {
Some(generation) => actuals.field_raw("graphGeneration", &generation.to_string()),
None => actuals.field_raw("graphGeneration", "null"),
};
actuals.field_raw(
"graphEdgesTraversed",
&slo.actuals.graph_edges_traversed.to_string(),
);
actuals.field_raw("elapsedMs", &slo.actuals.elapsed_ms.to_string());
actuals.field_raw(
"memoryBytesPeak",
&slo.actuals.memory_bytes_peak.to_string(),
);
});
obj.field_str("status", slo.status.as_str());
obj.field_array_of_objects("degradations", &slo.degradations, |entry_obj, entry| {
entry_obj.field_str("code", entry.code);
entry_obj.field_str("severity", entry.severity.as_str());
entry_obj.field_str("message", &entry.message);
match &entry.repair {
Some(repair) => entry_obj.field_str("repair", repair),
None => entry_obj.field_raw("repair", "null"),
};
});
}
fn build_pack_admission_posture(obj: &mut JsonBuilder, posture: &PackAdmissionPosture) {
obj.field_str("outcome", posture.outcome.as_str());
obj.field_raw("queueDepth", &posture.queue_depth.to_string());
obj.field_raw(
"concurrentPackMax",
&posture.concurrent_pack_max.to_string(),
);
match posture.retry_after_ms {
Some(retry_after_ms) => obj.field_raw("retryAfterMs", &retry_after_ms.to_string()),
None => obj.field_raw("retryAfterMs", "null"),
};
obj.field_raw("waitedMs", &posture.waited_ms.to_string());
}
fn build_pack_algorithm_metadata(obj: &mut JsonBuilder, audit: &PackSelectionAudit) {
obj.field_str("profile", audit.profile.as_str());
obj.field_str("objective", audit.objective.as_str());
obj.field_str("algorithmId", audit.algorithm_id);
obj.field_str("algorithmDescription", audit.algorithm_description);
obj.field_str(
"scoringFormula",
"unit_score(field)=clamp(field, 0.0, 1.0) for finite fields, otherwise 0.0",
);
obj.field_object("properties", |properties| {
properties.field_bool("monotone", audit.monotone);
properties.field_bool("submodular", audit.submodular);
});
}
fn build_pack_selection_audit(obj: &mut JsonBuilder, audit: &PackSelectionAudit) {
obj.field_str("profile", audit.profile.as_str());
obj.field_str("objective", audit.objective.as_str());
obj.field_str("algorithmId", audit.algorithm_id);
obj.field_str("algorithmDescription", audit.algorithm_description);
obj.field_raw("candidateCount", &audit.candidate_count.to_string());
obj.field_raw("selectedCount", &audit.selected_count.to_string());
obj.field_raw("omittedCount", &audit.omitted_count.to_string());
obj.field_u32("budgetLimit", audit.budget_limit);
obj.field_u32("budgetUsed", audit.budget_used);
obj.field_raw(
"totalObjectiveValue",
&score_json(audit.total_objective_value),
);
obj.field_bool("monotone", audit.monotone);
obj.field_bool("submodular", audit.submodular);
// Bead bd-17c65.1.5 (A5): selectionAudit.rejectedFrontier[] moved
// to the canonical pack.skipped[] list beside selected pack.items[].
}
// Bead bd-2pe1z (A1 phase 2): build_pack_selected_item and
// build_pack_selection_step are no longer wired into the certificate JSON
// because their per-item fields are now emitted inline on each items[]
// entry. Kept as dead code under #[allow] so the per-item-shape helpers
// remain available if a future surface needs them (e.g. ee pack replay)
// without re-deriving the formatting.
#[allow(dead_code)]
fn build_pack_selected_item(obj: &mut JsonBuilder, item: &PackSelectedItem) {
obj.field_u32("rank", item.rank);
obj.field_str("memoryId", &item.memory_id.to_string());
obj.field_u32("tokenCost", item.token_cost);
obj.field_bool("feasible", item.feasible);
}
fn build_pack_skipped_item(obj: &mut JsonBuilder, item: &PackOmission) {
obj.field_str("memoryId", &item.memory_id.to_string());
obj.field_u32("tokens", item.estimated_tokens);
obj.field_str("reason", item.reason.as_str());
obj.field_str("rejectedAt", item.rejected_at.as_str());
obj.field_bool("feasible", item.feasible);
if let Some(could_fit_with_budget) = item.could_fit_with_budget {
obj.field_u32("couldFitWithBudget", could_fit_with_budget);
}
}
#[allow(dead_code)]
fn build_pack_selection_step(obj: &mut JsonBuilder, step: &PackSelectionStep) {
obj.field_u32("rank", step.rank);
obj.field_str("memoryId", &step.memory_id.to_string());
obj.field_raw("marginalGain", &score_json(step.marginal_gain));
obj.field_raw("objectiveValue", &score_json(step.objective_value));
obj.field_u32("tokenCost", step.token_cost);
obj.field_bool("feasible", step.feasible);
obj.field_raw(
"coveredFeatures",
&string_array_json(step.covered_features.iter()),
);
}
fn build_rendered_provenance(obj: &mut JsonBuilder, source: &RenderedPackProvenance) {
obj.field_str("uri", &source.uri);
obj.field_str("scheme", &source.scheme);
obj.field_str("label", &source.label);
if let Some(locator) = &source.locator {
obj.field_str("locator", locator);
}
obj.field_str("note", &source.note);
}
fn build_pack_freshness_facet(obj: &mut JsonBuilder, facet: &PackFreshnessFacet) {
obj.field_str("kind", &facet.kind);
obj.field_str("freshness", &facet.freshness);
obj.field_bool("staleAnchor", facet.stale_anchor);
obj.field_str("driftStatus", &facet.drift_status);
obj.field_str("severity", &facet.severity);
obj.field_str("topReason", &facet.top_reason);
obj.field_raw(
"degradedCode",
&serde_json::to_string(&facet.degraded_code).unwrap_or_else(|_| "null".to_owned()),
);
obj.field_str("revalidationCommand", &facet.revalidation_command);
obj.field_raw(
"capturedAtCommit",
&serde_json::to_string(&facet.captured_at_commit).unwrap_or_else(|_| "null".to_owned()),
);
obj.field_raw(
"currentCommit",
&serde_json::to_string(&facet.current_commit).unwrap_or_else(|_| "null".to_owned()),
);
obj.field_raw(
"commitDistance",
&facet
.commit_distance
.map_or_else(|| "null".to_owned(), |distance| distance.to_string()),
);
obj.field_raw(
"changedRegions",
&string_array_json(facet.changed_regions.iter()),
);
obj.field_array_of_objects("anchors", &facet.anchors, build_pack_freshness_anchor_facet);
}
fn build_pack_freshness_anchor_facet(obj: &mut JsonBuilder, anchor: &PackFreshnessAnchorFacet) {
obj.field_str("anchorKind", &anchor.anchor_kind);
obj.field_str("anchorValueHash", &anchor.anchor_value_hash);
obj.field_str("redactedAnchorValue", &anchor.redacted_anchor_value);
obj.field_str("capturedSpanHash", &anchor.captured_span_hash);
obj.field_str("freshnessState", &anchor.freshness_state);
obj.field_str("freshness", &anchor.freshness);
obj.field_raw("generation", &anchor.generation.to_string());
obj.field_bool("staleAnchor", anchor.stale_anchor);
}
#[allow(dead_code)]
fn build_item_provenance(obj: &mut JsonBuilder, entry: &PackItemProvenance) {
obj.field_u32("rank", entry.rank);
obj.field_str("memoryId", &entry.memory_id.to_string());
obj.field_u32("sourceIndex", entry.source_index);
obj.field_object("source", |source| {
build_rendered_provenance(source, &entry.source);
});
}
fn json_number(value: f64, precision: usize) -> String {
if value.is_finite() {
format!("{value:.precision$}")
} else {
"null".to_string()
}
}
fn score_json(score: f32) -> String {
json_number(f64::from(score), 6)
}
fn string_array_json<I, S>(values: I) -> String
where
I: IntoIterator<Item = S>,
S: AsRef<str>,
{
let mut output = String::from("[");
for (index, value) in values.into_iter().enumerate() {
if index > 0 {
output.push(',');
}
output.push('"');
output.push_str(&escape_json_string(value.as_ref()));
output.push('"');
}
output.push(']');
output
}
/// Render a status report as JSON (ee.response.v2 envelope).
#[must_use]
pub fn render_status_json(report: &StatusReport) -> String {
let mut b = JsonBuilder::with_capacity(512);
let degraded = aggregate_status_degradations("status", &report.degradations);
b.field_str("schema", RESPONSE_SCHEMA_V2);
b.field_bool("success", true);
b.field_object("data", |d| {
d.field_str("command", "status");
d.field_str("version", report.version);
if let Some(workspace) = report.workspace.as_ref() {
render_workspace_status_json(d, workspace);
}
render_status_posture_json(d, &report.posture);
d.field_object("capabilities", |c| {
c.field_str("runtime", report.capabilities.runtime.as_str());
c.field_str("storage", report.capabilities.storage.as_str());
c.field_str("search", report.capabilities.search.as_str());
c.field_str("mesh", report.capabilities.mesh.as_str());
c.field_object("output", |output| {
output.field_str("toon", report.capabilities.output_toon.as_str());
});
c.field_str(
"agentDetection",
report.capabilities.agent_detection.as_str(),
);
});
d.field_object("runtime", |r| {
r.field_str("engine", report.runtime.engine);
r.field_str("profile", report.runtime.profile);
r.field_raw("workerThreads", &report.runtime.worker_threads.to_string());
r.field_str("asyncBoundary", report.runtime.async_boundary);
});
render_read_pool_status_json(d, &report.read_pool);
render_write_group_commit_status_json(d, &report.write_group_commit);
render_wal_status_json(d, &report.wal);
render_shard_fanout_status_json(d, &report.shard_fanout);
render_pack_budget_buckets_json(d, &report.pack_budget_buckets);
render_qos_status_json(d, &report.qos_posture, false);
render_rch_worker_pressure_json(d, &report.rch_worker_pressure);
render_verification_posture_json(d, &report.verification_posture);
render_rch_verify_ledger_status_json(d, &report.verification_ledger);
render_host_calibration_posture_json(d, report.host_calibration.as_ref());
render_memory_health_json(d, &report.memory_health);
render_curation_health_json(d, &report.curation_health);
render_feedback_health_json(d, &report.feedback_health);
render_singleflight_posture_json(d, &report.singleflight_posture);
render_flight_recorder_status_json(d, &report.flight_recorder);
render_graph_compute_json(d, &report.graph_compute);
render_graph_snapshot_artifact_json(d, &report.graph_snapshot_artifact);
render_search_status_json(d, &report.lexical_ram_tier);
render_derived_assets_json(d, &report.derived_assets, true);
render_mesh_status_json(
d,
report.mesh_storage.as_ref(),
report.tailscale_local.as_ref(),
);
render_agent_inventory_json(d, "agentInventory", &report.agent_inventory, false);
d.field_array_of_objects("degraded", °raded, build_aggregated_degradation);
});
b.field_array_of_objects("degraded", °raded, build_aggregated_degradation);
b.finish()
}
/// Render the status skyline report as JSON (ee.response.v2 envelope).
#[must_use]
pub fn render_status_skyline_json(report: &StatusSkylineReport) -> String {
let mut b = JsonBuilder::with_capacity(512);
let degraded = aggregate_status_degradations("skyline", &report.degraded);
b.field_str("schema", RESPONSE_SCHEMA_V2);
b.field_bool("success", true);
b.field_object("data", |d| {
render_status_skyline_data_json(d, report, °raded);
});
b.field_array_of_objects("degraded", °raded, build_aggregated_degradation);
b.finish()
}
fn render_status_skyline_data_json(
parent: &mut JsonBuilder,
report: &StatusSkylineReport,
degraded: &[AggregatedDegradation],
) {
parent.field_str("command", "status --skyline");
parent.field_str("schema", report.schema);
parent.field_raw("snapshotVersion", &report.snapshot_version.to_string());
parent.field_object("summary", |summary| {
summary.field_raw(
"communityCount",
&report.summary.community_count.to_string(),
);
match report.summary.highest_risk_community_id.as_deref() {
Some(community_id) => summary.field_str("highestRiskCommunityId", community_id),
None => summary.field_raw("highestRiskCommunityId", "null"),
};
summary.field_raw(
"loadBearingMemoryCount",
&report.summary.load_bearing_memory_count.to_string(),
);
summary.field_raw(
"staleCommunityCount",
&report.summary.stale_community_count.to_string(),
);
});
parent.field_array_of_objects("skyline", &report.skyline, |obj, community| {
obj.field_str("communityId", &community.community_id);
obj.field_raw("memoryCount", &community.memory_count.to_string());
obj.field_raw("meanTrust", &score_json(community.mean_trust));
obj.field_raw("meanAgeDays", &score_json(community.mean_age_days));
obj.field_u32("onionLayer", community.onion_layer);
obj.field_str("structuralHealth", &community.structural_health);
});
parent.field_array_of_objects("degraded", degraded, build_aggregated_degradation);
}
fn render_status_posture_json(
parent: &mut JsonBuilder,
posture: &crate::models::posture::WorkspacePostureReport,
) {
parent.field_object("posture", |p| {
p.field_str("overall", posture.overall.as_str());
render_status_workspace_posture_json(p, posture);
p.field_object("thisOperation", |operation| {
operation.field_str("status", posture.this_operation.status.as_str());
operation.field_raw(
"subsystemsUsed",
&string_array_json(posture.this_operation.subsystems_used.iter().copied()),
);
operation.field_raw(
"subsystemsSkipped",
&string_array_json(posture.this_operation.subsystems_skipped.iter().copied()),
);
operation.field_raw(
"degradationsApplied",
&string_array_json(posture.this_operation.degradations_applied.iter().copied()),
);
});
p.field_array_of_objects("subsystems", &posture.subsystems, |obj, subsystem| {
obj.field_str("id", subsystem.id);
obj.field_str("status", subsystem.status.as_str());
obj.field_u32("checksPassed", subsystem.checks_passed);
field_optional_str(obj, "reason", subsystem.reason);
field_optional_str(obj, "fallback", subsystem.fallback);
});
});
}
fn render_singleflight_posture_json(
parent: &mut JsonBuilder,
report: &crate::models::SingleFlightPostureReport,
) {
parent.field_object("singleFlight", |sf| {
sf.field_str("schema", &report.schema);
sf.field_str("status", &report.status);
sf.field_u32("configuredSurfaceCount", report.configured_surface_count);
sf.field_u32("activeLeaderCount", report.active_leader_count);
sf.field_raw("leaderStartCount", &report.leader_start_count.to_string());
sf.field_raw("followerWaitCount", &report.follower_wait_count.to_string());
sf.field_raw(
"followerTimeoutCount",
&report.follower_timeout_count.to_string(),
);
sf.field_raw(
"leaderFailureCount",
&report.leader_failure_count.to_string(),
);
sf.field_raw("reusedResultCount", &report.reused_result_count.to_string());
sf.field_array_of_objects("surfaces", &report.surfaces, |obj, surface| {
obj.field_str("surface", surface.surface.as_str());
obj.field_str("status", &surface.status);
obj.field_bool("configured", surface.configured);
obj.field_u32("activeLeaderCount", surface.active_leader_count);
obj.field_raw("leaderStartCount", &surface.leader_start_count.to_string());
obj.field_raw(
"completedLeaderCount",
&surface.completed_leader_count.to_string(),
);
obj.field_raw(
"followerJoinCount",
&surface.follower_join_count.to_string(),
);
obj.field_raw(
"followerTimeoutCount",
&surface.follower_timeout_count.to_string(),
);
obj.field_raw(
"leaderFailureCount",
&surface.leader_failure_count.to_string(),
);
obj.field_raw(
"reusedResultCount",
&surface.reused_result_count.to_string(),
);
obj.field_raw(
"statePoisonedCount",
&surface.state_poisoned_count.to_string(),
);
obj.field_raw(
"followerTimeoutMs",
&surface.follower_timeout_ms.to_string(),
);
match &surface.last_key {
Some(last_key) => {
obj.field_object("lastKey", |last| {
last.field_str("keyHash", &last_key.key_hash);
last.field_raw(
"workspaceGeneration",
&last_key.workspace_generation.to_string(),
);
field_optional_u64(last, "indexGeneration", last_key.index_generation);
field_optional_u64(last, "graphGeneration", last_key.graph_generation);
});
}
None => {
obj.field_raw("lastKey", "null");
}
}
obj.field_str("suggestedAction", &surface.suggested_action);
});
});
}
fn render_flight_recorder_status_json(
parent: &mut JsonBuilder,
report: &crate::core::status::FlightRecorderStatusReport,
) {
parent.field_object("flightRecorder", |recorder| {
recorder.field_str("schema", report.schema);
recorder.field_str("status", report.posture.as_str());
recorder.field_bool("enabled", report.enabled);
recorder.field_bool("writing", report.writing);
recorder.field_str("directory", &report.directory.display().to_string());
recorder.field_u32("retentionDays", report.retention_days);
recorder.field_raw("maxBytes", &report.max_bytes.to_string());
recorder.field_str("redactionLevel", report.redaction_level);
field_optional_str(recorder, "reason", report.reason);
field_optional_str(recorder, "repair", report.repair);
});
}
fn render_rch_worker_pressure_json(parent: &mut JsonBuilder, report: &RchWorkerPressureReport) {
parent.field_object("rchWorkerPressure", |pressure| {
pressure.field_str("schema", report.schema);
pressure.field_str("status", &report.status);
pressure.field_raw("workerCount", &report.worker_count.to_string());
pressure.field_raw("usableWorkerCount", &report.usable_worker_count.to_string());
pressure.field_raw(
"blockedWorkerCount",
&report.blocked_worker_count.to_string(),
);
pressure.field_raw("staleWorkerCount", &report.stale_worker_count.to_string());
pressure.field_raw(
"unknownWorkerCount",
&report.unknown_worker_count.to_string(),
);
pressure.field_array_of_objects("workers", &report.workers, render_rch_worker_json);
});
}
fn render_verification_posture_json(
parent: &mut JsonBuilder,
report: &crate::core::verify::VerificationPostureReport,
) {
let rendered = serde_json::to_string(report).unwrap_or_else(|_| {
r#"{"schema":"ee.verification.posture.v1","status":"serialization_failed","windowHours":24,"recordCount":0,"recentRunCount":0,"staleRunCount":0,"unknownAgeCount":0,"recentReusableRunCount":0,"inFlightEquivalentCommandCount":0,"advisoryCounts":{"remoteSuccess":0,"remoteFailed":0,"remoteInFlight":0,"localDisallowed":0,"topologyBlocked":0,"missingArtifactManifest":0},"evidenceHealth":{"ledgerAvailable":false,"status":"unavailable","malformedTimestampCount":0,"missingArtifactManifestCount":0,"localDisallowedCount":0,"topologyBlockedCount":0,"issueCount":1,"reason":"serialization_failed"},"recoveryActions":[]}"#
.to_owned()
});
parent.field_raw("verificationPosture", &rendered);
}
fn render_rch_verify_ledger_status_json(
parent: &mut JsonBuilder,
report: &crate::core::verify_ledger::RchVerifyLedgerStatusReport,
) {
let rendered = serde_json::to_string(report).unwrap_or_else(|_| {
r#"{"schema":"ee.rch.verify.ledger_status.v1","status":"serialization_failed","ledgerAvailable":false,"activeBlockerCount":0,"localFallbackRefused":false,"localFallbackRefusedCount":0,"oldestRetryAfter":null,"newestRetryAfter":null,"blockerRefs":[],"recoveryActions":[]}"#
.to_owned()
});
parent.field_raw("verificationLedger", &rendered);
}
fn render_host_calibration_posture_json(
parent: &mut JsonBuilder,
report: Option<&crate::core::budget_delta_recommender::HostCalibrationPostureReport>,
) {
if let Some(report) = report {
let rendered = serde_json::to_string(report).unwrap_or_else(|_| {
r#"{"schema":"ee.host_calibration.posture.v1","status":"serialization_failed"}"#
.to_owned()
});
parent.field_raw("hostCalibration", &rendered);
} else {
parent.field_object("hostCalibration", |calibration| {
calibration.field_str(
"schema",
crate::core::budget_delta_recommender::HOST_CALIBRATION_POSTURE_SCHEMA_V1,
);
calibration.field_str("status", "not_collected");
calibration.field_str(
"repair",
"Run `ee status --workspace . --json --fields standard` to collect host calibration.",
);
});
}
}
fn render_rch_worker_json(parent: &mut JsonBuilder, worker: &RchWorkerPressureObservation) {
parent.field_str("workerId", &worker.worker_id);
parent.field_str("pressureState", &worker.pressure_state);
parent.field_str("confidence", &worker.confidence);
parent.field_str("reasonCode", &worker.reason_code);
field_optional_u64(parent, "freeGb", worker.free_gb);
field_optional_u64(parent, "freeRatioBps", worker.free_ratio_bps);
parent.field_str("telemetryFreshness", &worker.telemetry_freshness);
parent.field_str("admissionImpact", &worker.admission_impact);
}
fn render_status_workspace_posture_json(
parent: &mut JsonBuilder,
posture: &crate::models::posture::WorkspacePostureReport,
) {
parent.field_object("workspace", |workspace| {
if let Some(storage) = posture
.subsystems
.iter()
.find(|subsystem| subsystem.id == "storage")
{
render_posture_subsystem_object(workspace, "storage", storage);
}
});
}
fn render_posture_subsystem_object(
parent: &mut JsonBuilder,
field_name: &str,
subsystem: &crate::models::posture::SubsystemPostureReport,
) {
parent.field_object(field_name, |obj| {
obj.field_str("status", subsystem.status.as_str());
obj.field_u32("checksPassed", subsystem.checks_passed);
field_optional_str(obj, "reason", subsystem.reason);
field_optional_str(obj, "fallback", subsystem.fallback);
});
}
fn render_workspace_status_json(
parent: &mut JsonBuilder,
workspace: &crate::core::status::WorkspaceStatusReport,
) {
parent.field_object("workspace", |w| {
w.field_str("source", workspace.source.as_str());
w.field_str("root", &workspace.root.to_string_lossy());
w.field_str("configDir", &workspace.config_dir.to_string_lossy());
w.field_bool("markerPresent", workspace.marker_present);
w.field_str("canonicalRoot", &workspace.canonical_root.to_string_lossy());
w.field_str("fingerprint", &workspace.fingerprint);
w.field_str("scopeKind", &workspace.scope_kind);
if let Some(repository_root) = workspace.repository_root.as_ref() {
w.field_str("repositoryRoot", &repository_root.to_string_lossy());
} else {
w.field_raw("repositoryRoot", "null");
}
if let Some(repository_fingerprint) = workspace.repository_fingerprint.as_ref() {
w.field_str("repositoryFingerprint", repository_fingerprint);
} else {
w.field_raw("repositoryFingerprint", "null");
}
if let Some(subproject_path) = workspace.subproject_path.as_ref() {
w.field_str("subprojectPath", &subproject_path.to_string_lossy());
} else {
w.field_raw("subprojectPath", "null");
}
w.field_array_of_objects("diagnostics", &workspace.diagnostics, |obj, diagnostic| {
obj.field_str("code", diagnostic.code);
obj.field_str("severity", diagnostic.severity.as_str());
obj.field_str("message", &diagnostic.message);
obj.field_str("repair", &diagnostic.repair);
if let Some(source) = diagnostic.selected_source {
obj.field_str("selectedSource", source.as_str());
}
if let Some(root) = diagnostic.selected_root.as_ref() {
obj.field_str("selectedRoot", &root.to_string_lossy());
}
if let Some(source) = diagnostic.conflicting_source {
obj.field_str("conflictingSource", source.as_str());
}
if let Some(root) = diagnostic.conflicting_root.as_ref() {
obj.field_str("conflictingRoot", &root.to_string_lossy());
}
if !diagnostic.marker_roots.is_empty() {
let marker_roots = diagnostic
.marker_roots
.iter()
.map(|root| root.to_string_lossy().into_owned())
.collect::<Vec<_>>();
obj.field_raw(
"markerRoots",
&string_array_json(marker_roots.iter().map(String::as_str)),
);
}
});
});
}
fn render_read_pool_status_json(
parent: &mut JsonBuilder,
report: &crate::core::status::ReadPoolStatusReport,
) {
parent.field_object("read_pool", |pool| {
pool.field_raw("active", &report.active.to_string());
pool.field_raw("idle", &report.idle.to_string());
pool.field_raw("active_pins", &report.active_pins.to_string());
pool.field_raw("expired_pins", &report.expired_pins.to_string());
pool.field_raw("max_seen", &report.max_seen.to_string());
pool.field_raw("drops", &report.drops.to_string());
pool.field_raw("release_failures", &report.release_failures.to_string());
pool.field_raw(
"ad_hoc_bypass_count",
&report.ad_hoc_bypass_count.to_string(),
);
pool.field_object("acquire_wait", |wait| {
wait.field_raw("samples", &report.acquire_wait.samples.to_string());
wait.field_raw("p50_ns", &report.acquire_wait.p50_ns.to_string());
wait.field_raw("p99_ns", &report.acquire_wait.p99_ns.to_string());
});
match report.checkpoint_blocked_by.as_ref() {
Some(blocker) => {
pool.field_object("checkpoint_blocked_by", |entry| {
entry.field_raw("pin_id", &blocker.pin_id.to_string());
field_optional_u64(entry, "slot_id", blocker.slot_id);
field_optional_str(entry, "workflow_id", blocker.workflow_id.as_deref());
field_optional_str(entry, "request_id", blocker.request_id.as_deref());
field_optional_str(entry, "workspace_id", blocker.workspace_id.as_deref());
entry.field_raw("age_ms", &blocker.age_ms.to_string());
entry.field_raw(
"max_pin_duration_ms",
&blocker.max_pin_duration_ms.to_string(),
);
entry.field_bool("poisoned", blocker.poisoned);
entry.field_str(
"release_state",
snapshot_pin_release_state_str(blocker.release_state),
);
});
}
None => {
pool.field_raw("checkpoint_blocked_by", "null");
}
}
});
}
fn render_write_group_commit_status_json(
parent: &mut JsonBuilder,
report: &crate::core::write_owner::WriteGroupCommitTelemetry,
) {
parent.field_object("writeGroupCommit", |write| {
write.field_str("schema", report.schema);
write.field_str("generatedAt", &report.generated_at);
write.field_bool("enabled", report.enabled);
write.field_str("redactionStatus", report.redaction_status);
write.field_raw("batches", &report.batches.to_string());
write.field_raw("writesCoalesced", &report.writes_coalesced.to_string());
write.field_raw("avgBatchSize", &score_json(report.avg_batch_size as f32));
write.field_raw("fsyncCount", &report.fsync_count.to_string());
write.field_raw("fsyncSaved", &report.fsync_saved.to_string());
write.field_raw(
"commitLatencyP50Us",
&report.commit_latency_p50_us.to_string(),
);
write.field_raw(
"commitLatencyP99Us",
&report.commit_latency_p99_us.to_string(),
);
write.field_raw("fallbackCount", &report.fallback_count.to_string());
write.field_object("fallbackReasons", |reasons| {
reasons.field_raw("disabled", &report.fallback_reasons.disabled.to_string());
reasons.field_raw("degraded", &report.fallback_reasons.degraded.to_string());
reasons.field_raw("oversized", &report.fallback_reasons.oversized.to_string());
reasons.field_raw(
"single_writer",
&report.fallback_reasons.single_writer.to_string(),
);
});
});
}
fn snapshot_pin_release_state_str(
state: crate::db::read_pool::SnapshotPinReleaseState,
) -> &'static str {
use crate::db::read_pool::SnapshotPinReleaseState;
match state {
SnapshotPinReleaseState::Active => "active",
SnapshotPinReleaseState::Expired => "expired",
SnapshotPinReleaseState::Poisoned => "poisoned",
}
}
fn render_wal_status_json(parent: &mut JsonBuilder, report: &crate::core::status::WalStatusReport) {
parent.field_object("wal", |wal| {
wal.field_raw("bytes", &report.bytes.to_string());
wal.field_raw("frames", &report.frames.to_string());
wal.field_raw("page_size", &report.page_size.to_string());
wal.field_raw(
"checkpoint_threshold_bytes",
&report.checkpoint_threshold_bytes.to_string(),
);
});
}
fn render_shard_fanout_status_json(
parent: &mut JsonBuilder,
report: &crate::db::shard::ShardFanoutStatusReport,
) {
parent.field_object("shardFanout", |shard| {
shard.field_str("schema", report.schema);
shard.field_bool("enabled", report.enabled);
shard.field_str("posture", report.posture.as_str());
field_optional_str(shard, "workspaceId", report.workspace_id.as_deref());
field_optional_path(shard, "workspaceRoot", report.workspace_root.as_deref());
field_optional_path(
shard,
"legacyDatabasePath",
report.legacy_database_path.as_deref(),
);
shard.field_str("dataRoot", &report.data_root.to_string_lossy());
shard.field_str("shardRoot", &report.shard_root.to_string_lossy());
shard.field_str("catalogPath", &report.catalog_path.to_string_lossy());
field_optional_path(shard, "shardPath", report.shard_path.as_deref());
field_optional_str(shard, "shardId", report.shard_id.as_deref());
shard.field_bool("catalogExists", report.catalog_exists);
shard.field_bool("shardExists", report.shard_exists);
shard.field_object("catalogContract", |contract| {
contract.field_raw(
"schemaVersion",
&report.catalog_contract.schema_version.to_string(),
);
contract
.field_array_of_strs("requiredFields", &report.catalog_contract.required_fields);
});
field_optional_u64(shard, "shardGeneration", report.shard_generation);
shard.field_str("migrationState", report.migration_state);
shard.field_array_of_objects(
"lastVerifiedHashes",
&report.last_verified_hashes,
|obj, hash| {
obj.field_str("name", hash.name);
field_optional_str(obj, "value", hash.value.as_deref());
},
);
shard.field_array_of_objects("recovery", &report.recovery, |obj, action| {
obj.field_raw("priority", &action.priority.to_string());
obj.field_str("kind", action.kind);
obj.field_str("command", action.command);
});
let aggregated_degraded = aggregate_shard_fanout_status_degradations(&report.degraded);
shard.field_array_of_objects(
"degraded",
&aggregated_degraded,
build_aggregated_degradation,
);
});
}
fn render_pack_budget_buckets_json(
parent: &mut JsonBuilder,
report: &crate::core::status::PackBudgetBucketReport,
) {
parent.field_object("packBudgetBuckets", |budget| {
budget.field_str("schema", report.schema);
budget.field_u32("windowHours", report.window_hours);
budget.field_u32("totalInvocations", report.total_invocations);
budget.field_u32("adaptiveInvocations", report.adaptive_invocations);
budget.field_u32("nonAdaptiveInvocations", report.non_adaptive_invocations);
budget.field_object("buckets", |buckets| {
buckets.field_u32("below1k", report.below_one_k);
buckets.field_u32("oneTo2k", report.one_to_two_k);
buckets.field_u32("twoTo4k", report.two_to_four_k);
buckets.field_u32("fourTo8k", report.four_to_eight_k);
buckets.field_u32("eightKPlus", report.eight_k_plus);
});
});
}
fn render_qos_status_json(
parent: &mut JsonBuilder,
report: &crate::core::qos::QosLaneSummary,
include_records: bool,
) {
parent.field_object("qos", |qos| {
qos.field_str("schema", &report.schema);
qos.field_str("workspaceHash", &report.workspace_hash);
qos.field_u32("foregroundActiveCount", report.foreground_active_count);
qos.field_u32("backgroundActiveCount", report.background_active_count);
qos.field_u32("verificationActiveCount", report.verification_active_count);
qos.field_u32("maintenanceActiveCount", report.maintenance_active_count);
qos.field_u32("staleIgnoredCount", report.stale_ignored_count);
qos.field_bool("foregroundPressure", report.foreground_active_count > 0);
qos.field_bool("backgroundWorkActive", report.background_active_count > 0);
qos.field_bool("registryHealthy", report.degraded.is_empty());
if include_records {
qos.field_array_of_objects("activeRecords", &report.active_records, |obj, record| {
render_qos_lane_record_json(obj, record);
});
}
let degraded = aggregate_qos_status_degradations(&report.degraded);
qos.field_array_of_objects("degraded", °raded, build_aggregated_degradation);
});
}
fn render_qos_lane_record_json(parent: &mut JsonBuilder, record: &crate::core::qos::QosLaneRecord) {
parent.field_str("schema", &record.schema);
parent.field_str("recordId", &record.record_id);
parent.field_str("workspaceHash", &record.workspace_hash);
parent.field_str("lane", record.lane.as_str());
parent.field_str("commandClass", &record.command_class);
match record.process_id {
Some(process_id) => parent.field_u32("processId", process_id),
None => parent.field_raw("processId", "null"),
};
field_optional_str(parent, "profileLabel", record.profile_label.as_deref());
field_optional_str(parent, "budgetLabel", record.budget_label.as_deref());
field_optional_str(parent, "requestHash", record.request_hash.as_deref());
parent.field_raw("startedAtEpochMs", &record.started_at_epoch_ms.to_string());
parent.field_raw("deadlineEpochMs", &record.deadline_epoch_ms.to_string());
parent.field_raw("ttlMs", &record.ttl_ms.to_string());
parent.field_str("status", record.status.as_str());
}
fn render_mesh_status_json(
parent: &mut JsonBuilder,
storage: Option<&MeshStorageStatusReport>,
tailscale: Option<&TailscaleLocalReport>,
) {
if storage.is_none() && tailscale.is_none() {
return;
}
parent.field_object("mesh", |mesh| {
if let Some(storage) = storage {
render_mesh_storage_status_json(mesh, storage);
}
if let Some(tailscale) = tailscale {
render_tailscale_local_status_json(mesh, tailscale);
}
});
}
fn render_mesh_storage_status_json(parent: &mut JsonBuilder, report: &MeshStorageStatusReport) {
parent.field_object("storage", |storage| {
storage.field_str("schema", "ee.mesh.storage_status.v1");
storage.field_u32("peerCount", report.peer_count);
storage.field_u32("cursorCount", report.cursor_count);
storage.field_u32("importedEventCount", report.imported_event_count);
storage.field_u32(
"policyDecisionEventCount",
report.policy_decision_event_count,
);
storage.field_u32("policyFailureEventCount", report.policy_failure_event_count);
storage.field_u32("mappedMemoryCount", report.mapped_memory_count);
storage.field_u32("cachedBodyCount", report.cached_body_count);
storage.field_bool("hasRows", report.has_rows());
});
}
fn render_tailscale_local_status_json(parent: &mut JsonBuilder, report: &TailscaleLocalReport) {
parent.field_object("tailscale", |tailscale| {
tailscale.field_str("schema", report.schema);
tailscale.field_bool("installed", report.installed);
tailscale.field_bool("daemonReachable", report.daemon_reachable);
tailscale.field_bool("authenticated", report.authenticated);
tailscale.field_bool("binaryAuthentic", report.binary_authentic);
if let Some(version_raw) = report.binary_version_raw.as_deref() {
tailscale.field_str("binaryVersionRaw", version_raw);
}
if let Some(path) = report.binary_absolute_path.as_ref() {
tailscale.field_str("binaryAbsolutePath", &path.display().to_string());
}
if let Some(shields_up) = report.shields_up {
tailscale.field_bool("shieldsUp", shields_up);
}
if let Some(tailnet_id) = report.tailnet_id.as_deref() {
tailscale.field_str("tailnetId", tailnet_id);
}
if let Some(tailnet_display_name) = report.tailnet_display_name.as_deref() {
tailscale.field_str("tailnetDisplayName", tailnet_display_name);
}
if let Some(self_node_key) = report.self_node_key.as_deref() {
tailscale.field_str("selfNodeKey", self_node_key);
}
if let Some(self_tailscale_ip) = report.self_tailscale_ip.as_deref() {
tailscale.field_str("selfTailscaleIp", self_tailscale_ip);
}
if let Some(self_magic_dns_name) = report.self_magic_dns_name.as_deref() {
tailscale.field_str("selfMagicDnsName", self_magic_dns_name);
}
tailscale.field_array_of_strings("selfAdvertisedTags", &report.self_advertised_tags);
tailscale.field_array_of_objects("peers", &report.peers, |peer_object, peer| {
peer_object.field_str("peerNodeKey", &peer.node_key);
peer_object.field_array_of_strings("peerTailscaleIps", &peer.tailscale_ips);
if let Some(magic_dns_name) = peer.magic_dns_name.as_deref() {
peer_object.field_str("peerMagicDnsName", magic_dns_name);
}
if let Some(hostname) = peer.hostname.as_deref() {
peer_object.field_str("peerHostname", hostname);
}
peer_object.field_array_of_strings("peerAdvertisedTags", &peer.advertised_tags);
if let Some(online) = peer.online {
peer_object.field_bool("online", online);
}
});
if let Some(version) = report.version.as_deref() {
tailscale.field_str("version", version);
}
tailscale.field_str("probeMethod", report.probe_method.as_str());
tailscale.field_raw("probeElapsedMs", &report.probe_elapsed_ms.to_string());
tailscale.field_str("platform", report.platform.as_str());
let degraded = aggregate_tailscale_status_degradations(&report.degradations);
tailscale.field_array_of_objects("degraded", °raded, build_aggregated_degradation);
});
}
fn render_memory_health_json(
parent: &mut JsonBuilder,
health: &crate::core::status::MemoryHealthReport,
) {
parent.field_object("memoryHealth", |h| {
h.field_str("status", health.status.as_str());
h.field_u32("totalCount", health.total_count);
h.field_u32("activeCount", health.active_count);
h.field_u32("tombstonedCount", health.tombstoned_count);
h.field_u32("staleCount", health.stale_count);
field_optional_score(h, "healthScore", health.health_score);
match health.average_confidence {
Some(c) => h.field_raw("averageConfidence", &format!("{c:.2}")),
None => h.field_raw("averageConfidence", "null"),
};
match health.provenance_coverage {
Some(c) => h.field_raw("provenanceCoverage", &format!("{c:.2}")),
None => h.field_raw("provenanceCoverage", "null"),
};
h.field_object("scoreComponents", |components| {
if let Some(score) = health.score_components {
field_optional_score(components, "activeRatio", Some(score.active_ratio));
field_optional_score(components, "freshnessScore", Some(score.freshness_score));
components.field_str("sourcedFrom", score.freshness_sourced_from);
field_optional_score(components, "confidenceScore", Some(score.confidence_score));
field_optional_score(components, "provenanceScore", Some(score.provenance_score));
field_optional_score(
components,
"tombstonePenalty",
Some(score.tombstone_penalty),
);
} else {
field_optional_score(components, "activeRatio", None);
field_optional_score(components, "freshnessScore", None);
components.field_raw("sourcedFrom", "null");
field_optional_score(components, "confidenceScore", None);
field_optional_score(components, "provenanceScore", None);
field_optional_score(components, "tombstonePenalty", None);
}
});
});
}
fn render_curation_health_json(
parent: &mut JsonBuilder,
health: &crate::core::status::CurationHealthReport,
) {
parent.field_object("curationHealth", |h| {
h.field_str("status", health.status.as_str());
h.field_u32("totalCount", health.total_count);
h.field_u32("pendingCount", health.pending_count);
h.field_u32("acceptedCount", health.accepted_count);
h.field_u32("snoozedCount", health.snoozed_count);
h.field_u32("rejectedCount", health.rejected_count);
h.field_u32("dueCount", health.due_count);
h.field_u32("promptCount", health.prompt_count);
h.field_u32("escalationCount", health.escalation_count);
h.field_u32("blockedCount", health.blocked_count);
h.field_u32("policyCount", health.policy_count);
h.field_u32("autoPromoteEnabledCount", health.auto_promote_enabled_count);
match health.oldest_pending_age_days {
Some(days) => h.field_raw("oldestPendingAgeDays", &days.to_string()),
None => h.field_raw("oldestPendingAgeDays", "null"),
};
match health.mean_review_latency_days {
Some(days) => h.field_raw("meanReviewLatencyDays", &days.to_string()),
None => h.field_raw("meanReviewLatencyDays", "null"),
};
match health.next_scheduled_at.as_deref() {
Some(next) => h.field_str("nextScheduledAt", next),
None => h.field_raw("nextScheduledAt", "null"),
};
});
}
fn render_feedback_health_json(
parent: &mut JsonBuilder,
health: &crate::core::status::FeedbackHealthReport,
) {
parent.field_object("feedbackHealth", |h| {
h.field_str("status", health.status.as_str());
h.field_u32(
"harmfulPerSourcePerHour",
health.harmful_per_source_per_hour,
);
h.field_u32(
"harmfulBurstWindowSeconds",
health.harmful_burst_window_seconds,
);
h.field_array_of_objects(
"perSourceHarmfulCounts",
&health.per_source_harmful_counts,
|obj, source| {
let source_id = redact_memory_output_provenance_uri(&source.source_id);
obj.field_str("sourceId", &source_id);
obj.field_u32("harmfulCount", source.harmful_count);
},
);
h.field_u32("quarantineQueueDepth", health.quarantine_queue_depth);
h.field_u32("protectedRuleCount", health.protected_rule_count);
match health.last_inversion_event.as_deref() {
Some(event) => h.field_str("lastInversionEvent", event),
None => h.field_raw("lastInversionEvent", "null"),
};
h.field_str("nextDeterministicAction", &health.next_deterministic_action);
});
}
fn field_optional_score(builder: &mut JsonBuilder, key: &str, score: Option<f32>) {
match score {
Some(score) => builder.field_raw(key, &format!("{score:.2}")),
None => builder.field_raw(key, "null"),
};
}
fn render_derived_assets_json(
parent: &mut JsonBuilder,
assets: &[crate::core::status::DerivedAssetReport],
include_repair: bool,
) {
parent.field_array_of_objects("derivedAssets", assets, |obj, asset| {
obj.field_str("name", asset.name);
obj.field_str("kind", asset.kind);
obj.field_str("status", asset.status.as_str());
match asset.source_high_watermark {
Some(value) => obj.field_raw("sourceHighWatermark", &value.to_string()),
None => obj.field_raw("sourceHighWatermark", "null"),
};
match asset.asset_high_watermark {
Some(value) => obj.field_raw("assetHighWatermark", &value.to_string()),
None => obj.field_raw("assetHighWatermark", "null"),
};
match asset.high_watermark_lag {
Some(value) => obj.field_raw("highWatermarkLag", &value.to_string()),
None => obj.field_raw("highWatermarkLag", "null"),
};
obj.field_str("path", asset.path);
obj.field_object("freshness", |freshness| {
freshness.field_str("schema", asset.freshness.schema);
freshness.field_str("verdict", asset.freshness.verdict.as_str());
freshness.field_str("dependencyHash", &asset.freshness.dependency_hash);
freshness.field_str(
"sourceDependencyHash",
&asset.freshness.source_dependency_hash,
);
freshness.field_str("configHash", &asset.freshness.config_hash);
freshness.field_str("featureFlagsHash", &asset.freshness.feature_flags_hash);
match asset.freshness.input_manifest_hash.as_deref() {
Some(value) => freshness.field_str("inputManifestHash", value),
None => freshness.field_raw("inputManifestHash", "null"),
};
freshness.field_array_of_strs("invalidates", &asset.freshness.invalidates);
freshness.field_str("repairAction", asset.freshness.repair_action);
});
if asset.name == "graph_snapshot_artifact" {
match asset.last_built_at.as_deref() {
Some(value) => obj.field_str("lastBuiltAt", value),
None => obj.field_raw("lastBuiltAt", "null"),
};
}
if let Some(memory_graph) = asset.memory_graph.as_ref() {
obj.field_object("memoryGraph", |graph| {
graph.field_raw("nodeCount", &memory_graph.node_count.to_string());
graph.field_raw("edgeCount", &memory_graph.edge_count.to_string());
graph.field_raw("generation", &memory_graph.generation.to_string());
graph.field_bool("matchesDbGeneration", memory_graph.matches_db_generation);
graph.field_str("availability", memory_graph.availability);
});
}
if include_repair && let Some(repair) = asset.repair {
obj.field_str("repair", repair);
}
});
}
fn render_search_status_json(
parent: &mut JsonBuilder,
lexical_ram_tier: &crate::search::lexical_ram_tier::LexicalRamTierResult,
) {
parent.field_object("search", |search| {
search.field_object("lexicalRamTier", |tier| {
tier.field_str("schema", lexical_ram_tier.schema);
tier.field_str("collectionStatus", lexical_ram_tier.collection_status);
tier.field_str(
"platform",
lexical_ram_tier_platform_name(lexical_ram_tier.platform),
);
tier.field_bool("supported", lexical_ram_tier.supported);
tier.field_bool("enabled", lexical_ram_tier.enabled);
tier.field_bool("attempted", lexical_ram_tier.attempted);
tier.field_bool("succeeded", lexical_ram_tier.succeeded);
tier.field_bool("hugepagesRequested", lexical_ram_tier.hugepages_requested);
tier.field_bool("hugepagesGranted", lexical_ram_tier.hugepages_granted);
tier.field_bool("populateRequested", lexical_ram_tier.populate_requested);
tier.field_raw("bytesMmapped", &lexical_ram_tier.bytes_mmapped.to_string());
tier.field_raw(
"bytesWarmloaded",
&lexical_ram_tier.bytes_warmloaded.to_string(),
);
tier.field_raw(
"pageFaultsPre",
&lexical_ram_tier.page_faults_pre.to_string(),
);
tier.field_raw(
"pageFaultsPost",
&lexical_ram_tier.page_faults_post.to_string(),
);
tier.field_str(
"fallbackPath",
lexical_ram_tier_fallback_name(lexical_ram_tier.fallback_path),
);
match lexical_ram_tier.index_path.as_deref() {
Some(path) => {
let index_path = path.to_string_lossy();
tier.field_str("indexPath", index_path.as_ref())
}
None => tier.field_raw("indexPath", "null"),
};
match lexical_ram_tier.index_revision.as_ref() {
Some(revision) => tier.field_str("indexRevision", revision.as_str()),
None => tier.field_raw("indexRevision", "null"),
};
tier.field_array_of_strings("degradedCodes", &lexical_ram_tier.degraded_codes);
});
});
}
fn lexical_ram_tier_platform_name(
platform: crate::search::lexical_ram_tier::LexicalRamTierPlatform,
) -> &'static str {
match platform {
crate::search::lexical_ram_tier::LexicalRamTierPlatform::NotCollected => "not_collected",
crate::search::lexical_ram_tier::LexicalRamTierPlatform::Linux => "linux",
crate::search::lexical_ram_tier::LexicalRamTierPlatform::MacosLimited => "macos_limited",
crate::search::lexical_ram_tier::LexicalRamTierPlatform::WindowsLimited => {
"windows_limited"
}
crate::search::lexical_ram_tier::LexicalRamTierPlatform::OtherUnsupported => {
"other_unsupported"
}
}
}
fn lexical_ram_tier_fallback_name(
fallback: crate::search::lexical_ram_tier::LexicalRamTierFallbackPath,
) -> &'static str {
match fallback {
crate::search::lexical_ram_tier::LexicalRamTierFallbackPath::None => "none",
crate::search::lexical_ram_tier::LexicalRamTierFallbackPath::HeapWarmload => {
"heap_warmload"
}
crate::search::lexical_ram_tier::LexicalRamTierFallbackPath::MadviseWillneed => {
"madvise_willneed"
}
crate::search::lexical_ram_tier::LexicalRamTierFallbackPath::HeapOnly => "heap_only",
crate::search::lexical_ram_tier::LexicalRamTierFallbackPath::DisabledByOperator => {
"disabled_by_operator"
}
}
}
fn render_graph_compute_json(
parent: &mut JsonBuilder,
report: &crate::core::status::GraphComputeReport,
) {
parent.field_object("graphCompute", |graph| {
graph.field_str("status", report.status.as_str());
graph.field_raw(
"availableAlgorithms",
&string_array_json(report.available_algorithms.iter().copied()),
);
graph.field_bool("liveComputeSupported", report.live_compute_supported);
graph.field_str("fnxRuntimeVersion", report.fnx_runtime_version);
graph.field_object("resultCache", |cache| {
cache.field_str("status", report.result_cache.status);
cache.field_raw(
"cachedResultCount",
&report.result_cache.cached_result_count.to_string(),
);
cache.field_raw(
"observedComputeCount",
&report.result_cache.observed_compute_count.to_string(),
);
match report.result_cache.cache_hit_rate_basis_points {
Some(value) => cache.field_raw(
"cacheHitRate",
&format!("{:.4}", f64::from(value) / 10_000.0),
),
None => cache.field_raw("cacheHitRate", "null"),
};
});
match report.last_used_at.as_deref() {
Some(value) => graph.field_str("lastUsedAt", value),
None => graph.field_raw("lastUsedAt", "null"),
};
});
}
fn render_graph_snapshot_artifact_json(
parent: &mut JsonBuilder,
report: &crate::core::status::GraphSnapshotArtifactReport,
) {
parent.field_object("graphSnapshotArtifact", |snapshot| {
snapshot.field_str("status", report.status.as_str());
match report.last_built_at.as_deref() {
Some(value) => snapshot.field_str("lastBuiltAt", value),
None => snapshot.field_raw("lastBuiltAt", "null"),
};
match report.snapshot_path {
Some(value) => snapshot.field_str("snapshotPath", value),
None => snapshot.field_raw("snapshotPath", "null"),
};
match report.snapshot_generation {
Some(value) => snapshot.field_raw("snapshotGeneration", &value.to_string()),
None => snapshot.field_raw("snapshotGeneration", "null"),
};
snapshot.field_object("memoryGraph", |graph| {
graph.field_raw("nodeCount", &report.memory_graph.node_count.to_string());
graph.field_raw("edgeCount", &report.memory_graph.edge_count.to_string());
graph.field_raw("generation", &report.memory_graph.generation.to_string());
graph.field_bool(
"matchesDbGeneration",
report.memory_graph.matches_db_generation,
);
graph.field_str("availability", report.memory_graph.availability);
});
snapshot.field_str("nextRefreshVia", report.next_refresh_via);
});
}
fn render_agent_inventory_json(
parent: &mut JsonBuilder,
field_name: &str,
inventory: &AgentInventoryReport,
include_agents: bool,
) {
parent.field_object(field_name, |agent| {
agent.field_str("schema", inventory.schema);
agent.field_str("status", inventory.status.as_str());
agent.field_u32("formatVersion", inventory.format_version);
agent.field_object("summary", |summary| {
summary.field_u32("detectedCount", inventory.summary.detected_count as u32);
summary.field_u32("totalCount", inventory.summary.total_count as u32);
});
agent.field_str("inspectionCommand", inventory.inspection_command);
if include_agents {
agent.field_array_of_objects(
"installedAgents",
&inventory.installed_agents,
|obj, item| {
obj.field_str("slug", &item.slug);
obj.field_bool("detected", item.detected);
obj.field_raw("evidence", &strings_to_json_array(&item.evidence));
obj.field_raw("rootPaths", &strings_to_json_array(&item.root_paths));
},
);
}
let degraded = aggregate_agent_inventory_degradations(&inventory.degraded);
agent.field_array_of_objects("degraded", °raded, build_aggregated_degradation);
});
}
/// Render a status report as JSON with optional timing metadata.
///
/// When `timing` is provided, adds a `meta` object with timing fields.
#[must_use]
pub fn render_status_json_with_meta(
report: &StatusReport,
timing: Option<&crate::models::DiagnosticTiming>,
) -> String {
let mut b = JsonBuilder::with_capacity(1024);
let degraded = aggregate_status_degradations("status", &report.degradations);
b.field_str("schema", RESPONSE_SCHEMA_V2);
b.field_bool("success", true);
b.field_object("data", |d| {
d.field_str("command", "status");
d.field_str("version", report.version);
if let Some(workspace) = report.workspace.as_ref() {
render_workspace_status_json(d, workspace);
}
render_status_posture_json(d, &report.posture);
d.field_object("capabilities", |c| {
c.field_str("runtime", report.capabilities.runtime.as_str());
c.field_str("storage", report.capabilities.storage.as_str());
c.field_str("search", report.capabilities.search.as_str());
c.field_str("mesh", report.capabilities.mesh.as_str());
c.field_str(
"agentDetection",
report.capabilities.agent_detection.as_str(),
);
});
d.field_object("runtime", |r| {
r.field_str("engine", report.runtime.engine);
r.field_str("profile", report.runtime.profile);
r.field_raw("workerThreads", &report.runtime.worker_threads.to_string());
r.field_str("asyncBoundary", report.runtime.async_boundary);
});
render_read_pool_status_json(d, &report.read_pool);
render_write_group_commit_status_json(d, &report.write_group_commit);
render_wal_status_json(d, &report.wal);
render_shard_fanout_status_json(d, &report.shard_fanout);
render_pack_budget_buckets_json(d, &report.pack_budget_buckets);
render_memory_health_json(d, &report.memory_health);
render_flight_recorder_status_json(d, &report.flight_recorder);
render_verification_posture_json(d, &report.verification_posture);
render_rch_verify_ledger_status_json(d, &report.verification_ledger);
render_graph_compute_json(d, &report.graph_compute);
render_graph_snapshot_artifact_json(d, &report.graph_snapshot_artifact);
render_search_status_json(d, &report.lexical_ram_tier);
render_derived_assets_json(d, &report.derived_assets, true);
render_mesh_status_json(
d,
report.mesh_storage.as_ref(),
report.tailscale_local.as_ref(),
);
render_agent_inventory_json(d, "agentInventory", &report.agent_inventory, false);
d.field_array_of_objects("degraded", °raded, build_aggregated_degradation);
});
if let Some(t) = timing {
b.field_object("meta", |m| {
m.field_object("timing", |tm| {
tm.field_raw("elapsedMs", &format!("{:.3}", t.elapsed_ms));
if !t.phases.is_empty() {
tm.field_array_of_objects("phases", &t.phases, |obj, phase| {
obj.field_str("name", phase.name);
obj.field_raw("durationMs", &format!("{:.3}", phase.duration_ms));
});
}
});
});
}
b.field_array_of_objects("degraded", °raded, build_aggregated_degradation);
b.finish()
}
/// Render a status report as human-readable text.
#[must_use]
pub fn render_status_human(report: &StatusReport) -> String {
let workspace_line = report
.workspace
.as_ref()
.map_or_else(String::new, |workspace| {
let diagnostics = workspace.diagnostics.len();
format!(
"workspace: {} ({}; {} diagnostic{})\n",
workspace.root.display(),
workspace.source.as_str(),
diagnostics,
if diagnostics == 1 { "" } else { "s" }
)
});
format!(
"ee status\n\n{}storage: {}\nshard fanout: {}\nsearch: {}\nmesh: {}\nagent detection: {}\nrch worker pressure: {} (usable: {}, blocked: {})\nverification posture: {} (recent reusable: {}, stale: {}, in flight: {})\nverification ledger: {} (active blockers: {}, local fallback refused: {})\nruntime: {} ({} {})\n\nNext:\n ee status --json\n",
workspace_line,
report.capabilities.storage.as_str(),
report.shard_fanout.posture.as_str(),
report.capabilities.search.as_str(),
report.capabilities.mesh.as_str(),
report.capabilities.agent_detection.as_str(),
report.rch_worker_pressure.status,
report.rch_worker_pressure.usable_worker_count,
report.rch_worker_pressure.blocked_worker_count,
report.verification_posture.status,
report.verification_posture.recent_reusable_run_count,
report.verification_posture.stale_run_count,
report
.verification_posture
.in_flight_equivalent_command_count,
report.verification_ledger.status,
report.verification_ledger.active_blocker_count,
report.verification_ledger.local_fallback_refused,
report.capabilities.runtime.as_str(),
report.runtime.engine,
report.runtime.profile
)
}
/// Render the status skyline report as compact human-readable text.
#[must_use]
pub fn render_status_skyline_human(report: &StatusSkylineReport) -> String {
let mut output = String::new();
let _ = writeln!(output, "ee status --skyline");
let _ = writeln!(output);
let _ = writeln!(output, "schema: {}", report.schema);
let _ = writeln!(output, "communities: {}", report.summary.community_count);
let _ = writeln!(
output,
"load-bearing memories: {}",
report.summary.load_bearing_memory_count
);
let _ = writeln!(
output,
"stale communities: {}",
report.summary.stale_community_count
);
match report.summary.highest_risk_community_id.as_deref() {
Some(community_id) => {
let _ = writeln!(output, "highest-risk community: {community_id}");
}
None => {
let _ = writeln!(output, "highest-risk community: none");
}
}
let _ = writeln!(output);
let _ = writeln!(output, "Skyline:");
if report.skyline.is_empty() {
let _ = writeln!(output, " [no skyline communities available]");
} else {
for community in &report.skyline {
let filled = usize::min(community.memory_count, 20);
let bar = "#".repeat(filled);
let empty = ".".repeat(20_usize.saturating_sub(filled));
let _ = writeln!(
output,
" {} [{}{}] memories={} trust={:.2} age={:.1}d onion={} health={}",
community.community_id,
bar,
empty,
community.memory_count,
community.mean_trust,
community.mean_age_days,
community.onion_layer,
community.structural_health
);
}
}
let degraded = aggregate_status_degradations("skyline", &report.degraded);
if !degraded.is_empty() {
let _ = writeln!(output);
let _ = writeln!(output, "Degraded:");
for degraded in °raded {
let _ = writeln!(
output,
" [{}] {}: {}",
degraded.severity, degraded.code, degraded.message
);
}
}
output
}
/// Render the status skyline report as TOON.
#[must_use]
pub fn render_status_skyline_toon(report: &StatusSkylineReport) -> String {
render_toon_from_json(&render_status_skyline_json(report))
}
/// Render the status skyline report as Markdown.
#[must_use]
pub fn render_status_skyline_markdown(report: &StatusSkylineReport) -> String {
let mut output = String::new();
let _ = writeln!(output, "# Status Skyline");
let _ = writeln!(output);
let _ = writeln!(output, "- Schema: `{}`", report.schema);
let _ = writeln!(output, "- Communities: {}", report.summary.community_count);
let _ = writeln!(
output,
"- Load-bearing memories: {}",
report.summary.load_bearing_memory_count
);
let _ = writeln!(
output,
"- Stale communities: {}",
report.summary.stale_community_count
);
match report.summary.highest_risk_community_id.as_deref() {
Some(community_id) => {
let _ = writeln!(output, "- Highest-risk community: `{community_id}`");
}
None => {
let _ = writeln!(output, "- Highest-risk community: none");
}
}
let _ = writeln!(output);
let _ = writeln!(output, "## Communities");
if report.skyline.is_empty() {
let _ = writeln!(output);
let _ = writeln!(output, "- No skyline communities available.");
} else {
for community in &report.skyline {
let filled = usize::min(community.memory_count, 20);
let bar = "#".repeat(filled);
let empty = ".".repeat(20_usize.saturating_sub(filled));
let _ = writeln!(
output,
"- `{}` [{}{}] memories={} trust={:.2} age={:.1}d onion={} health=`{}`",
community.community_id,
bar,
empty,
community.memory_count,
community.mean_trust,
community.mean_age_days,
community.onion_layer,
community.structural_health
);
}
}
let degraded = aggregate_status_degradations("skyline", &report.degraded);
if !degraded.is_empty() {
let _ = writeln!(output);
let _ = writeln!(output, "## Degraded");
for degraded in °raded {
let _ = writeln!(
output,
"- **{}** `{}`: {}",
degraded.severity, degraded.code, degraded.message
);
}
}
output
}
/// Render a status report as TOON (Terse Object Output Notation).
#[must_use]
pub fn render_status_toon(report: &StatusReport) -> String {
render_status_toon_filtered(report, FieldProfile::Standard)
}
/// Render a status report as TOON with field filtering.
#[must_use]
pub fn render_status_toon_filtered(report: &StatusReport, profile: FieldProfile) -> String {
render_toon_from_json(&render_status_json_filtered(report, profile))
}
/// Render a doctor report as JSON (ee.response.v2 envelope).
#[must_use]
pub fn render_doctor_json(report: &DoctorReport) -> String {
let mut b = JsonBuilder::with_capacity(512);
let mesh_auto_enrollment = render_doctor_mesh_auto_enrollment_json();
b.field_str("schema", RESPONSE_SCHEMA_V2);
// bd-2xdom Gap 4: envelope `success` means "command ran", not "system is healthy".
// System state is in `data.posture` (canonical, 5-state enum) and `data.healthy`
// (deprecated boolean kept for v0.1→v0.2 transition).
b.field_bool("success", true);
b.field_raw("degraded", "[]");
b.field_object("data", |d| {
d.field_str("command", "doctor");
d.field_str("version", report.version);
// Bead bd-17c65.5.1 (E1) — three-state posture. `healthy` is
// kept alongside for the v0.1 → v0.2 transition window.
d.field_str("posture", report.posture.as_str());
d.field_bool("healthy", report.overall_healthy);
render_singleflight_posture_json(d, &report.singleflight_posture);
render_flight_recorder_status_json(d, &report.flight_recorder);
render_qos_status_json(d, &report.qos_posture, false);
render_rch_worker_pressure_json(d, &report.rch_worker_pressure);
render_verification_posture_json(d, &report.verification_posture);
render_rch_verify_ledger_status_json(d, &report.verification_ledger);
render_host_calibration_posture_json(d, report.host_calibration.as_ref());
d.field_raw("meshAutoEnrollment", &mesh_auto_enrollment);
render_doctor_advisories_json(d, &report.checks, true, true);
d.field_array_of_objects("checks", &report.checks, |obj, check| {
render_doctor_check_json(obj, check, true, true);
});
});
b.finish()
}
/// Render the default compact doctor report as JSON (ee.response.v2 envelope).
///
/// The default doctor surface is meant for high-frequency agent readiness checks.
/// Keep detailed worker, mesh, verification, and host-calibration diagnostics on
/// `ee doctor --full`; this renderer exposes only the core verdict, actionable
/// core repairs, and a one-line advisory summary.
#[must_use]
pub fn render_doctor_concise_json(report: &DoctorReport) -> String {
let core_checks = report
.checks
.iter()
.filter(|check| check.tier == CheckTier::Core)
.collect::<Vec<_>>();
let actionable = core_checks
.iter()
.copied()
.filter(|check| !check.severity.is_healthy())
.collect::<Vec<_>>();
let advisory_counts = DoctorAdvisoryCounts::from_checks(&report.checks);
let advisory_summary = doctor_advisory_summary_line(advisory_counts);
let permanent_capability_gaps = report
.checks
.iter()
.filter(|check| doctor_advisory_is_permanent(check))
.collect::<Vec<_>>();
let mut b = JsonBuilder::with_capacity(384);
b.field_str("schema", RESPONSE_SCHEMA_V2);
b.field_bool("success", true);
b.field_raw("degraded", "[]");
b.field_str("fields", "doctor_concise");
b.field_object("data", |d| {
d.field_str("command", "doctor");
d.field_str("mode", "concise");
d.field_str("version", report.version);
d.field_str("posture", report.posture.as_str());
d.field_bool("healthy", report.overall_healthy);
d.field_str("fullCommand", "ee doctor --full --json");
d.field_array_of_objects("coreChecks", &core_checks, |obj, check| {
render_doctor_check_json(obj, check, true, false);
});
d.field_array_of_objects("actionable", &actionable, |obj, check| {
render_doctor_check_json(obj, check, true, true);
});
d.field_object("advisorySummary", |summary| {
summary.field_raw("total", &advisory_counts.total.to_string());
summary.field_raw("ok", &advisory_counts.ok.to_string());
summary.field_raw("warning", &advisory_counts.warning.to_string());
summary.field_raw("error", &advisory_counts.error.to_string());
summary.field_raw("nonOk", &advisory_counts.non_ok().to_string());
summary.field_str("summary", &advisory_summary);
summary.field_str("fullCommand", "ee doctor --full --json");
});
d.field_array_of_objects(
"permanentCapabilityGaps",
&permanent_capability_gaps,
|obj, check| {
render_doctor_check_json(obj, check, true, true);
obj.field_bool("permanent", true);
},
);
});
b.finish()
}
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
struct DoctorAdvisoryCounts {
total: usize,
ok: usize,
warning: usize,
error: usize,
}
impl DoctorAdvisoryCounts {
fn from_checks(checks: &[CheckResult]) -> Self {
let mut counts = Self::default();
for check in checks
.iter()
.filter(|check| check.tier == CheckTier::Advisory)
{
counts.total += 1;
match check.severity {
CheckSeverity::Ok => counts.ok += 1,
CheckSeverity::Warning => counts.warning += 1,
CheckSeverity::Error => counts.error += 1,
}
}
counts
}
const fn non_ok(self) -> usize {
self.warning + self.error
}
}
fn doctor_advisory_summary_line(counts: DoctorAdvisoryCounts) -> String {
if counts.total == 0 {
return "advisories: none; full report: ee doctor --full --json".to_owned();
}
if counts.non_ok() == 0 {
return format!(
"advisories: {}/{} ok; full report: ee doctor --full --json",
counts.ok, counts.total
);
}
format!(
"advisories: {} non-ok of {}; full report: ee doctor --full --json",
counts.non_ok(),
counts.total
)
}
fn render_doctor_advisories_json(
parent: &mut JsonBuilder,
checks: &[CheckResult],
include_message: bool,
include_verbose_details: bool,
) {
let advisories = checks
.iter()
.filter(|check| check.tier == CheckTier::Advisory && !check.severity.is_healthy())
.collect::<Vec<_>>();
parent.field_array_of_objects("advisories", &advisories, |obj, check| {
render_doctor_check_json(obj, check, include_message, include_verbose_details);
if doctor_advisory_is_permanent(check) {
obj.field_bool("permanent", true);
}
});
}
fn doctor_advisory_is_permanent(check: &CheckResult) -> bool {
check.tier == CheckTier::Advisory && check.is_permanent_capability_gap()
}
fn render_doctor_check_json(
obj: &mut JsonBuilder,
check: &CheckResult,
include_message: bool,
include_verbose_details: bool,
) {
obj.field_str("name", check.name);
obj.field_str("tier", check.tier.as_str());
obj.field_str("severity", check.severity.as_str());
if include_message {
obj.field_str("message", &check.message);
}
if include_verbose_details {
if let Some(code) = check.error_code {
obj.field_str("errorCode", code.id);
}
if let Some(repair) = check.repair {
obj.field_str("repair", repair);
}
}
}
/// Render a doctor report as human-readable text.
#[must_use]
pub fn render_doctor_human(report: &DoctorReport) -> String {
let mut output = String::from("ee doctor\n\n");
let mesh_auto_enrollment = DoctorMeshAutoEnrollmentReport::gather(
crate::core::status::default_workspace_path().as_deref(),
);
for check in &report.checks {
let icon = match check.severity {
crate::core::doctor::CheckSeverity::Ok => "✓",
crate::core::doctor::CheckSeverity::Warning => "⚠",
crate::core::doctor::CheckSeverity::Error => "✗",
};
output.push_str(&format!("{} {}: {}\n", icon, check.name, check.message));
if let Some(repair) = check.repair {
output.push_str(&format!(" repair: {}\n", repair));
}
}
output.push_str(&format!(
"single-flight: {} (active leaders: {}, follower waits: {}, timeouts: {})\n",
report.singleflight_posture.status,
report.singleflight_posture.active_leader_count,
report.singleflight_posture.follower_wait_count,
report.singleflight_posture.follower_timeout_count
));
output.push_str(&format!(
"flight recorder: {} (retention: {}d, max bytes: {}, redaction: {})\n",
report.flight_recorder.posture.as_str(),
report.flight_recorder.retention_days,
report.flight_recorder.max_bytes,
report.flight_recorder.redaction_level
));
output.push_str(&format!(
"qos: foreground active {}, background active {}, verification active {}, maintenance active {}, registry {}\n",
report.qos_posture.foreground_active_count,
report.qos_posture.background_active_count,
report.qos_posture.verification_active_count,
report.qos_posture.maintenance_active_count,
if report.qos_posture.degraded.is_empty() {
"healthy"
} else {
"degraded"
}
));
output.push_str(&format!(
"rch worker pressure: {} (usable: {}, blocked: {}, stale: {}, unknown: {})\n",
report.rch_worker_pressure.status,
report.rch_worker_pressure.usable_worker_count,
report.rch_worker_pressure.blocked_worker_count,
report.rch_worker_pressure.stale_worker_count,
report.rch_worker_pressure.unknown_worker_count
));
output.push_str(&format!(
"verification posture: {} (recent reusable: {}, stale: {}, in flight: {})\n",
report.verification_posture.status,
report.verification_posture.recent_reusable_run_count,
report.verification_posture.stale_run_count,
report
.verification_posture
.in_flight_equivalent_command_count
));
output.push_str(&format!(
"verification ledger: {} (active blockers: {}, local fallback refused: {})\n",
report.verification_ledger.status,
report.verification_ledger.active_blocker_count,
report.verification_ledger.local_fallback_refused
));
output.push_str(&format!(
"mesh auto-enrollment: {} (ok: {}, warning: {}, fail: {}, skipped: {}, actions: {})\n",
mesh_auto_enrollment.posture,
mesh_auto_enrollment.categorized_summary.ok,
mesh_auto_enrollment.categorized_summary.warning,
mesh_auto_enrollment.categorized_summary.fail,
mesh_auto_enrollment.categorized_summary.skipped,
mesh_auto_enrollment.action_graph.actions.len()
));
if report.overall_healthy {
output.push_str("\nAll checks passed.\n");
} else {
output.push_str("\nSome checks failed. Run suggested repairs to fix issues.\n");
}
output
}
/// Render the default compact doctor report as human-readable text.
#[must_use]
pub fn render_doctor_concise_human(report: &DoctorReport) -> String {
let counts = DoctorAdvisoryCounts::from_checks(&report.checks);
let mut output = String::from("ee doctor\n\n");
let _ = writeln!(
output,
"posture: {} (healthy: {})",
report.posture.as_str(),
report.overall_healthy
);
output.push_str("core:\n");
for check in report
.checks
.iter()
.filter(|check| check.tier == CheckTier::Core)
{
let _ = writeln!(output, " - {}: {}", check.name, check.severity.as_str());
}
let actionable = report
.checks
.iter()
.filter(|check| check.tier == CheckTier::Core && !check.severity.is_healthy())
.collect::<Vec<_>>();
if !actionable.is_empty() {
output.push_str("actionable:\n");
for check in actionable {
let _ = writeln!(output, " - {}: {}", check.name, check.message);
if let Some(repair) = check.repair {
let _ = writeln!(output, " repair: {repair}");
}
}
}
let _ = writeln!(output, "{}", doctor_advisory_summary_line(counts));
let permanent_capability_gaps = report
.checks
.iter()
.filter(|check| doctor_advisory_is_permanent(check))
.collect::<Vec<_>>();
if !permanent_capability_gaps.is_empty() {
output.push_str("permanent capability gaps:\n");
for check in permanent_capability_gaps {
let _ = writeln!(output, " - {}: {}", check.name, check.message);
if let Some(repair) = check.repair {
let _ = writeln!(output, " repair: {repair}");
}
}
}
output.push_str("full: ee doctor --full --json\n");
output
}
fn render_doctor_mesh_auto_enrollment_json() -> String {
let workspace_path = crate::core::status::default_workspace_path();
let report = DoctorMeshAutoEnrollmentReport::gather(workspace_path.as_deref());
serde_json::to_string(&report).unwrap_or_else(|_| {
format!(
"{{\"schema\":\"{}\",\"enabled\":false,\"posture\":\"skipped\",\"workspacePath\":\".\",\"checks\":[],\"categorizedSummary\":{{\"ok\":0,\"warning\":0,\"fail\":0,\"skipped\":0,\"total\":0}},\"actionGraph\":{{\"schema\":\"ee.repair_action_graph.v1\",\"actions\":[],\"topologicallyOrderedExecution\":[],\"parallelizableGroups\":[],\"estimatedTotalDurationSeconds\":0}},\"degraded\":[]}}",
crate::core::doctor::DOCTOR_MESH_AUTO_ENROLLMENT_SCHEMA_V1
)
})
}
/// Render a doctor report as TOON.
#[must_use]
pub fn render_doctor_toon(report: &DoctorReport) -> String {
render_toon_from_json(&render_doctor_json(report))
}
/// Render the default compact doctor report as TOON.
#[must_use]
pub fn render_doctor_concise_toon(report: &DoctorReport) -> String {
render_toon_from_json(&render_doctor_concise_json(report))
}
/// Render a doctor report as a deterministic Mermaid diagram.
#[must_use]
pub fn render_doctor_mermaid(report: &DoctorReport) -> String {
let mut output = String::from("flowchart TD\n");
let summary = if report.overall_healthy {
"ee doctor: healthy"
} else {
"ee doctor: needs repair"
};
output.push_str(&format!(
" doctor[\"{}\"]\n",
escape_mermaid_label(summary)
));
for (index, check) in report.checks.iter().enumerate() {
let node_id = format!("check{}", index + 1);
let label = format!("{}: {}", check.name, check.severity.as_str());
output.push_str(&format!(
" {}[\"{}\"]\n",
node_id,
escape_mermaid_label(&label)
));
output.push_str(&format!(" doctor --> {}\n", node_id));
if let Some(repair) = check.repair {
let repair_id = format!("repair{}", index + 1);
output.push_str(&format!(
" {}[\"{}\"]\n",
repair_id,
escape_mermaid_label(repair)
));
output.push_str(&format!(" {} -. repair .-> {}\n", node_id, repair_id));
}
}
output
}
/// Render a why report as the canonical machine-readable response envelope.
#[must_use]
pub fn render_why_json(report: &WhyReport) -> String {
let storage = report.storage.as_ref().map(|storage| {
serde_json::json!({
"origin": &storage.origin,
"trustClass": &storage.trust_class,
"trustSubclass": &storage.trust_subclass,
"provenanceUri": &storage.provenance_uri,
"workflowId": &storage.workflow_id,
"createdAt": &storage.created_at,
"validFrom": &storage.valid_from,
"validTo": &storage.valid_to,
"validityStatus": &storage.validity_status,
"validityWindowKind": &storage.validity_window_kind,
})
});
let retrieval = report.retrieval.as_ref().map(|retrieval| {
serde_json::json!({
"confidence": why_score_json_value(retrieval.confidence),
"utility": why_score_json_value(retrieval.utility),
"importance": why_score_json_value(retrieval.importance),
"tags": &retrieval.tags,
"level": &retrieval.level,
"kind": &retrieval.kind,
})
});
let graph_retrieval = report.graph_retrieval.as_ref().map(|graph| {
let snapshot = graph.source.snapshot.as_ref().map(|snapshot| {
serde_json::json!({
"id": &snapshot.id,
"schemaVersion": &snapshot.schema_version,
"snapshotVersion": snapshot.snapshot_version,
"sourceGeneration": snapshot.source_generation,
"status": &snapshot.status,
"contentHash": &snapshot.content_hash,
"createdAt": &snapshot.created_at,
})
});
let degraded = why_degraded_json("why_graph_retrieval", &graph.degraded);
let hits = graph.hits.as_ref().map(|hits| {
serde_json::json!({
"schema": &hits.schema,
"authority": {
"raw": why_graph_score_json_value(hits.authority.raw),
"normalized": why_graph_score_json_value(hits.authority.normalized),
"rank": hits.authority.rank,
"percentile": hits.authority.percentile.map(why_graph_score_json_value),
},
"hub": {
"raw": why_graph_score_json_value(hits.hub.raw),
"normalized": why_graph_score_json_value(hits.hub.normalized),
"rank": hits.hub.rank,
"percentile": hits.hub.percentile.map(why_graph_score_json_value),
},
"roleLabel": &hits.role_label,
"roleRationale": &hits.role_rationale,
})
});
serde_json::json!({
"status": &graph.status,
"source": {
"kind": &graph.source.kind,
"workspaceId": &graph.source.workspace_id,
"graphType": &graph.source.graph_type,
"snapshot": snapshot,
},
"centralityScore": why_graph_score_json_value(graph.centrality_score),
"authorityScore": why_graph_score_json_value(graph.authority_score),
"hubScore": why_graph_score_json_value(graph.hub_score),
"hits": hits,
"communityId": &graph.community_id,
"distanceToQuerySeed": graph.distance_to_query_seed,
"sameClusterAsTopResult": graph.same_cluster_as_top_result,
"evidenceSupportCount": graph.evidence_support_count,
"contradictionCount": graph.contradiction_count,
"orphanPenalty": why_graph_score_json_value(graph.orphan_penalty),
"staleBridgePenalty": why_graph_score_json_value(graph.stale_bridge_penalty),
"pagerank": {
"raw": why_graph_score_json_value(graph.pagerank.raw),
"normalized": why_graph_score_json_value(graph.pagerank.normalized),
"rank": graph.pagerank.rank,
"weight": why_graph_score_json_value(graph.pagerank.weight),
"contribution": why_graph_score_json_value(graph.pagerank.contribution),
"formula": &graph.pagerank.formula,
},
"betweenness": {
"raw": why_graph_score_json_value(graph.betweenness.raw),
"normalized": why_graph_score_json_value(graph.betweenness.normalized),
"rank": graph.betweenness.rank,
"weight": why_graph_score_json_value(graph.betweenness.weight),
"contribution": why_graph_score_json_value(graph.betweenness.contribution),
"formula": &graph.betweenness.formula,
},
"labels": &graph.labels,
"reasons": &graph.reasons,
"centralityFormula": &graph.centrality_formula,
"orphanPenaltyFormula": &graph.orphan_penalty_formula,
"staleBridgePenaltyFormula": &graph.stale_bridge_penalty_formula,
"degraded": degraded,
})
});
let selection = report.selection.as_ref().map(|selection| {
let pack = selection.latest_pack_selection.as_ref().map(|pack| {
let mut value = serde_json::json!({
"packId": &pack.pack_id,
"query": &pack.query,
"profile": &pack.profile,
"rank": pack.rank,
"section": &pack.section,
"estimatedTokens": pack.estimated_tokens,
"relevance": why_score_json_value(pack.relevance),
"utility": why_score_json_value(pack.utility),
"why": &pack.why,
"packHash": &pack.pack_hash,
"ledgerHash": &pack.ledger_hash,
"ledgerStatus": &pack.ledger_status,
"ledgerStorage": &pack.ledger_storage,
"selectedAt": &pack.selected_at,
});
if let Some(snapshot) = &pack.attempt_family_multiplicity
&& let Some(object) = value.as_object_mut()
{
object.insert("attemptFamilyMultiplicity".to_owned(), snapshot.clone());
}
value
});
serde_json::json!({
"selectionScore": why_score_json_value(selection.selection_score),
"aboveConfidenceThreshold": selection.above_confidence_threshold,
"isActive": selection.is_active,
"scoreBreakdown": &selection.score_breakdown,
"latestPackSelection": pack,
})
});
let lifecycle = report.lifecycle.as_ref().map(|lifecycle| {
serde_json::json!({
"status": &lifecycle.status,
"tombstoned_at": &lifecycle.tombstoned_at,
"tombstoned_reason": &lifecycle.tombstoned_reason,
})
});
let agent_profile = report.agent_profile.as_ref().map(|profile| {
serde_json::json!({
"schema": &profile.schema,
"agentName": &profile.agent_name,
"agentNameHash": &profile.agent_name_hash,
"helpfulCount": profile.helpful_count,
"harmfulCount": profile.harmful_count,
"ignoredCount": profile.ignored_count,
"observedOutcomes": profile.observed_outcomes,
"bias": why_graph_score_json_value(profile.bias),
"maxBiasMagnitude": why_graph_score_json_value(profile.max_bias_magnitude),
"coldStart": profile.cold_start,
"coldStartThreshold": profile.cold_start_threshold,
"lastSeenAt": &profile.last_seen_at,
})
});
let bayes_posterior = report.bayes_posterior.as_ref().map(|posterior| {
serde_json::json!({
"schema": "ee.bayes.posterior.v1",
"alpha": why_posterior_json_value(posterior.alpha),
"beta": why_posterior_json_value(posterior.beta),
"mean": why_posterior_json_value(posterior.mean),
"effectiveSampleSize": why_posterior_json_value(posterior.effective_sample_size),
"credibleInterval90": why_posterior_interval_json_value(posterior.credible_interval_90, 0.90),
"credibleInterval50": why_posterior_interval_json_value(posterior.credible_interval_50, 0.50),
})
});
let confidence_intervals = report.confidence_intervals.as_ref().map(|intervals| {
let prediction_set = intervals
.prediction_set
.iter()
.map(|entry| {
serde_json::json!({
"memoryId": &entry.memory_id,
"rank": entry.rank,
"source": &entry.source,
"score": why_score_json_value(entry.score),
"nonconformityScore": why_score_json_value(entry.nonconformity_score),
"included": entry.included,
})
})
.collect::<Vec<_>>();
serde_json::json!({
"schema": &intervals.schema,
"method": &intervals.method,
"coverageGuarantee": why_score_json_value(intervals.coverage_guarantee),
"alpha": why_score_json_value(intervals.alpha),
"targetMemoryId": &intervals.target_memory_id,
"scoreInterval": [
why_score_json_value(intervals.score_interval[0]),
why_score_json_value(intervals.score_interval[1]),
],
"nonconformityQuantile": why_score_json_value(intervals.nonconformity_quantile),
"calibrationSampleCount": intervals.calibration_sample_count,
"calibrationStatus": &intervals.calibration_status,
"predictionSet": prediction_set,
})
});
let counterfactual_influence = report.counterfactual_influence.as_ref().map(|influence| {
let top_positive = influence
.top_positive
.iter()
.map(why_influence_entry_json)
.collect::<Vec<_>>();
let top_negative = influence
.top_negative
.iter()
.map(why_influence_entry_json)
.collect::<Vec<_>>();
let entries = influence
.entries
.iter()
.map(why_influence_entry_json)
.collect::<Vec<_>>();
serde_json::json!({
"schema": &influence.schema,
"method": &influence.method,
"targetMemoryId": &influence.target_memory_id,
"baselineTopScore": why_score_json_value(influence.baseline_top_score),
"approximationErrorRatio": why_score_json_value(influence.approximation_error_ratio),
"totalAbsoluteInfluence": why_score_json_value(influence.total_absolute_influence),
"topPositive": top_positive,
"topNegative": top_negative,
"entries": entries,
})
});
let degraded = why_degraded_json("why", &report.degraded);
let contradictions: Vec<serde_json::Value> = report
.contradictions
.iter()
.map(|contradiction| {
serde_json::json!({
"eventId": &contradiction.event_id,
"weight": why_score_json_value(contradiction.weight),
"sourceType": &contradiction.source_type,
"reason": &contradiction.reason,
"createdAt": &contradiction.created_at,
"applied": contradiction.applied,
})
})
.collect();
let links: Vec<serde_json::Value> = report
.links
.iter()
.map(|link| {
serde_json::json!({
"linkId": &link.link_id,
"linkedMemoryId": &link.linked_memory_id,
"relation": &link.relation,
"direction": &link.direction,
"confidence": why_score_json_value(link.confidence),
"weight": why_score_json_value(link.weight),
"evidenceCount": link.evidence_count,
"source": &link.source,
"createdAt": &link.created_at,
})
})
.collect();
let history = report.history.as_ref().map(|history| {
let entries: Vec<serde_json::Value> = history
.entries
.iter()
.map(|entry| {
serde_json::json!({
"auditId": entry.audit_id,
"timestamp": entry.timestamp,
"actor": entry.actor,
"action": entry.action,
"details": entry.details,
})
})
.collect();
serde_json::json!({
"entries": entries,
"totalCount": history.total_count,
"truncated": history.truncated,
})
});
let verification_evidence = serde_json::to_value(&report.verification_evidence)
.unwrap_or_else(|_| serde_json::json!([]));
let coordination_fallback_evidence: Vec<serde_json::Value> = report
.coordination_fallback_evidence
.iter()
.map(|evidence| {
serde_json::json!({
"sourceSchema": &evidence.source_schema,
"evidenceId": &evidence.evidence_id,
"status": &evidence.status,
"sourceKind": &evidence.source_kind,
"reasonCode": &evidence.reason_code,
"capturedAt": &evidence.captured_at,
"contentHash": &evidence.content_hash,
"linkedBeadIds": &evidence.linked_bead_ids,
"linkedVerificationIds": &evidence.linked_verification_ids,
"linkedSupportBundleIds": &evidence.linked_support_bundle_ids,
})
})
.collect();
let load_bearing = report.load_bearing.as_ref().map(|load_bearing| {
let citing_rules = load_bearing
.citing_rules
.iter()
.map(|rule| {
serde_json::json!({
"ruleId": &rule.rule_id,
"relation": &rule.relation,
})
})
.collect::<Vec<_>>();
serde_json::json!({
"isLoadBearing": load_bearing.is_load_bearing,
"loadBearingScore": load_bearing
.load_bearing_score
.map(why_graph_score_json_value)
.unwrap_or(serde_json::Value::Null),
"authorityRank": load_bearing.authority_rank,
"citingRuleCount": load_bearing.citing_rule_count,
"citingRules": citing_rules,
"interpretation": &load_bearing.interpretation,
"evidence": {
"schema": &load_bearing.evidence.schema,
"algorithm": &load_bearing.evidence.algorithm,
"projection": &load_bearing.evidence.projection,
"snapshotVersion": load_bearing.evidence.snapshot_version,
},
"rationale": &load_bearing.rationale,
})
});
let mut json = serde_json::json!({
"schema": RESPONSE_SCHEMA_V2,
"success": true,
"data": {
"command": "why",
"version": report.version,
"memoryId": report.entity.is_none().then_some(&report.memory_id),
"found": report.found,
"content": &report.content,
"storage": storage,
"retrieval": retrieval,
"graphRetrievalFeatures": graph_retrieval,
"selection": selection,
"agentProfile": agent_profile,
"bayesPosterior": bayes_posterior,
"lifecycle": lifecycle,
"contradictions": contradictions,
"links": links,
"history": history,
"verificationEvidence": verification_evidence,
"coordinationFallbackEvidence": coordination_fallback_evidence,
"attestationBundle": report.attestation_manifest.clone(),
"degraded": degraded.clone(),
},
"degraded": degraded,
});
if let Some(entity) = &report.entity
&& let Some(data) = json
.get_mut("data")
.and_then(serde_json::Value::as_object_mut)
{
data.insert(
"entity".to_owned(),
serde_json::json!({
"kind": &entity.kind,
"id": &entity.id,
"revision": &entity.revision,
"details": &entity.details,
}),
);
}
if let Some(load_bearing) = load_bearing
&& let Some(data) = json
.get_mut("data")
.and_then(serde_json::Value::as_object_mut)
{
data.insert(
"graph".to_owned(),
serde_json::json!({
"loadBearing": load_bearing,
}),
);
}
if let Some(causal_explanation) = &report.causal_explanation {
if let Some(data) = json
.get_mut("data")
.and_then(serde_json::Value::as_object_mut)
{
data.insert("causalExplanation".to_owned(), causal_explanation.clone());
}
}
if let Some(revision_lineage) = &report.revision_lineage {
if let Some(data) = json
.get_mut("data")
.and_then(serde_json::Value::as_object_mut)
{
data.insert("revisionLineage".to_owned(), revision_lineage.clone());
}
}
if let Some(seal) = &report.seal {
if let Some(data) = json
.get_mut("data")
.and_then(serde_json::Value::as_object_mut)
{
data.insert("seal".to_owned(), seal.clone());
}
}
if let Some(team_provenance) = &report.team_provenance
&& let Some(data) = json
.get_mut("data")
.and_then(serde_json::Value::as_object_mut)
{
data.insert("teamProvenance".to_owned(), team_provenance.to_json());
}
if let Some(elevation) = &report.elevation
&& let Some(data) = json
.get_mut("data")
.and_then(serde_json::Value::as_object_mut)
{
data.insert("elevation".to_owned(), elevation.to_json());
}
if let Some(confidence_intervals) = confidence_intervals
&& let Some(data) = json
.get_mut("data")
.and_then(serde_json::Value::as_object_mut)
{
data.insert("confidenceIntervals".to_owned(), confidence_intervals);
}
if let Some(counterfactual_influence) = counterfactual_influence
&& let Some(data) = json
.get_mut("data")
.and_then(serde_json::Value::as_object_mut)
{
data.insert(
"counterfactualInfluence".to_owned(),
counterfactual_influence,
);
}
json.to_string()
}
fn why_degraded_json(
source: &'static str,
degraded: &[crate::core::why::WhyDegradation],
) -> Vec<serde_json::Value> {
aggregate_degraded_entries(degraded.iter().map(|entry| {
DegradationAggregationInput::new(
source,
entry.code,
entry.severity,
entry.message.as_str(),
entry.repair.as_deref().unwrap_or_default(),
)
}))
.into_iter()
.map(|entry| {
serde_json::json!({
"code": entry.code,
"severity": entry.severity,
"message": entry.message,
"repair": entry.repair,
"sources": entry.sources,
})
})
.collect()
}
fn why_influence_entry_json(
entry: &crate::core::influence::WhyInfluenceEntry,
) -> serde_json::Value {
serde_json::json!({
"memoryId": &entry.memory_id,
"rank": entry.rank,
"relation": &entry.relation,
"baselineScore": why_score_json_value(entry.baseline_score),
"leaveOneOutScore": why_score_json_value(entry.leave_one_out_score),
"influenceDelta": why_score_json_value(entry.influence_delta),
"absoluteInfluence": why_score_json_value(entry.absolute_influence),
"direction": entry.direction,
})
}
fn why_score_json_value(value: f32) -> serde_json::Value {
let rounded = (f64::from(value) * 10_000.0).round() / 10_000.0;
serde_json::Number::from_f64(rounded).map_or(serde_json::Value::Null, serde_json::Value::Number)
}
fn why_graph_score_json_value(value: f64) -> serde_json::Value {
let rounded = if value.is_finite() {
(value * 10_000.0).round() / 10_000.0
} else {
return serde_json::Value::Null;
};
serde_json::Number::from_f64(rounded).map_or(serde_json::Value::Null, serde_json::Value::Number)
}
fn why_posterior_json_value(value: f64) -> serde_json::Value {
let rounded = if value.is_finite() {
(value * 1_000_000.0).round() / 1_000_000.0
} else {
return serde_json::Value::Null;
};
serde_json::Number::from_f64(rounded).map_or(serde_json::Value::Null, serde_json::Value::Number)
}
fn why_posterior_interval_json_value(
interval: Option<(f64, f64)>,
level: f64,
) -> serde_json::Value {
let Some((lower, upper)) = interval else {
return serde_json::Value::Null;
};
serde_json::json!({
"lower": why_posterior_json_value(lower),
"upper": why_posterior_json_value(upper),
"level": why_posterior_json_value(level),
})
}
/// Render a why report as a deterministic Mermaid diagram.
#[must_use]
pub fn render_why_mermaid(report: &WhyReport) -> String {
let mut output = String::from("flowchart TD\n");
output.push_str(&format!(
" memory[\"memory: {}\"]\n",
escape_mermaid_label(&report.memory_id)
));
if let Some(storage) = &report.storage {
let label = format!("storage: {} / {}", storage.origin, storage.trust_class);
output.push_str(&format!(
" storage[\"{}\"]\n",
escape_mermaid_label(&label)
));
output.push_str(" memory --> storage\n");
}
if let Some(retrieval) = &report.retrieval {
let label = format!(
"retrieval: {} {} confidence {:.2}",
retrieval.level, retrieval.kind, retrieval.confidence
);
output.push_str(&format!(
" retrieval[\"{}\"]\n",
escape_mermaid_label(&label)
));
if report.storage.is_some() {
output.push_str(" storage --> retrieval\n");
} else {
output.push_str(" memory --> retrieval\n");
}
}
if let Some(selection) = &report.selection {
let label = format!(
"selection: score {:.2}, active {}",
selection.selection_score, selection.is_active
);
output.push_str(&format!(
" selection[\"{}\"]\n",
escape_mermaid_label(&label)
));
if report.retrieval.is_some() {
output.push_str(" retrieval --> selection\n");
} else {
output.push_str(" memory --> selection\n");
}
if let Some(pack) = &selection.latest_pack_selection {
let pack_label = format!("pack: {} rank {}", pack.pack_id, pack.rank);
output.push_str(&format!(
" pack[\"{}\"]\n",
escape_mermaid_label(&pack_label)
));
output.push_str(" selection --> pack\n");
}
}
for (index, link) in report.links.iter().enumerate() {
let node_id = format!("link{}", index + 1);
let label = format!(
"{} {} {}",
link.direction, link.relation, link.linked_memory_id
);
output.push_str(&format!(
" {}[\"{}\"]\n",
node_id,
escape_mermaid_label(&label)
));
output.push_str(&format!(" memory --> {}\n", node_id));
}
for (index, trace) in report.rationale_traces.iter().enumerate() {
let node_id = format!("rationale{}", index + 1);
let label = format!(
"rationale: {} {} {}",
trace.kind, trace.posture, trace.summary
);
output.push_str(&format!(
" {}[\"{}\"]\n",
node_id,
escape_mermaid_label(&label)
));
output.push_str(&format!(" memory --> {}\n", node_id));
}
for (index, degraded) in report.degraded.iter().enumerate() {
let node_id = format!("degraded{}", index + 1);
let label = format!("degraded: {} ({})", degraded.code, degraded.severity);
output.push_str(&format!(
" {}[\"{}\"]\n",
node_id,
escape_mermaid_label(&label)
));
output.push_str(&format!(" memory -.-> {}\n", node_id));
}
output
}
/// Render a fix plan as JSON (ee.response.v2 envelope).
#[must_use]
pub fn render_fix_plan_json(plan: &FixPlan) -> String {
let mut b = JsonBuilder::with_capacity(512);
b.field_str("schema", RESPONSE_SCHEMA_V2);
b.field_bool("success", true);
b.field_object("data", |d| {
d.field_str("command", "doctor");
d.field_str("mode", "fix-plan");
d.field_str("version", plan.version);
d.field_raw("totalIssues", &plan.total_issues.to_string());
d.field_raw("fixableIssues", &plan.fixable_issues.to_string());
d.field_array_of_objects("steps", &plan.steps, |obj, step| {
obj.field_raw("order", &step.order.to_string());
obj.field_str("subsystem", step.subsystem);
obj.field_str("severity", step.severity.as_str());
obj.field_str("issue", &step.issue);
if let Some(code) = step.error_code {
obj.field_str("errorCode", code.id);
}
obj.field_str("command", step.command);
});
d.field_object("cassImportGuidance", |guidance| {
guidance.field_str("status", plan.cass_import_guidance.status.as_str());
guidance.field_raw(
"detectedAgentCount",
&plan.cass_import_guidance.detected_agent_count.to_string(),
);
guidance.field_raw(
"detectedRootCount",
&plan.cass_import_guidance.detected_root_count.to_string(),
);
guidance.field_str("message", &plan.cass_import_guidance.message);
guidance.field_array_of_objects(
"roots",
&plan.cass_import_guidance.roots,
|obj, root| {
obj.field_str("connector", &root.connector);
obj.field_str("rootPath", &root.root_path);
obj.field_str("guidance", &root.guidance);
},
);
guidance.field_array_of_strings(
"suggestedCommands",
&plan.cass_import_guidance.suggested_commands,
);
});
let mut all_suggested: Vec<String> = plan
.steps
.iter()
.map(|step| step.command.to_string())
.collect();
all_suggested.extend(plan.cass_import_guidance.suggested_commands.iter().cloned());
d.field_array_of_strings("suggestedCommands", &all_suggested);
});
b.field_raw("degraded", "[]");
b.finish()
}
/// Render a fix plan as human-readable text.
#[must_use]
pub fn render_fix_plan_human(plan: &FixPlan) -> String {
let mut output = String::from("ee doctor --fix-plan\n\n");
if plan.is_empty() {
output.push_str("No issues to fix. All subsystems are healthy.\n");
} else {
output.push_str(&format!(
"Found {} issue(s), {} fixable:\n\n",
plan.total_issues, plan.fixable_issues
));
for step in &plan.steps {
output.push_str(&format!(
"{}. [{}] {}\n Issue: {}\n Fix: {}\n\n",
step.order,
step.subsystem,
step.severity.as_str().to_uppercase(),
step.issue,
step.command
));
}
if plan.fixable_issues > 0 {
output.push_str("Run commands in order to resolve issues.\n");
}
}
output.push_str("\nCASS import guidance:\n");
output.push_str(&format!(
" Status: {}\n",
plan.cass_import_guidance.status.as_str()
));
output.push_str(&format!(
" Message: {}\n",
plan.cass_import_guidance.message
));
if !plan.cass_import_guidance.roots.is_empty() {
output.push_str(" Detected roots:\n");
for root in &plan.cass_import_guidance.roots {
output.push_str(&format!(" - {}: {}\n", root.connector, root.root_path));
}
}
if !plan.cass_import_guidance.suggested_commands.is_empty() {
output.push_str(" Suggested commands:\n");
for command in &plan.cass_import_guidance.suggested_commands {
output.push_str(&format!(" {command}\n"));
}
}
output
}
/// Render a fix plan as TOON.
#[must_use]
pub fn render_fix_plan_toon(plan: &FixPlan) -> String {
render_toon_from_json(&render_fix_plan_json(plan))
}
/// Render dependency diagnostics as JSON (ee.response.v2 envelope).
#[must_use]
pub fn render_dependency_diagnostics_json(report: &DependencyDiagnosticsReport) -> String {
let degraded_entries = dependency_contract_degraded_entries(report);
let degraded = aggregate_dependency_contract_degradations(°raded_entries);
let mut b = JsonBuilder::with_capacity(4096);
b.field_str("schema", RESPONSE_SCHEMA_V2);
b.field_bool("success", report.summary.forbidden_default_hit_count == 0);
b.field_object("data", |d| {
d.field_str("command", "diag dependencies");
d.field_str("version", report.version);
d.field_str("schema", report.schema);
d.field_raw("matrixRevision", &report.matrix_revision.to_string());
d.field_object("source", |source| {
source.field_str("bead", report.source_bead);
source.field_str("planItem", report.source_plan_item);
});
d.field_str("defaultFeatureProfile", report.default_feature_profile);
render_dependency_diagnostics_summary(d, report);
d.field_array_of_strs("forbiddenCrates", report.forbidden_crates);
let capability_gap_entries = dependency_contract_capability_gap_entries(report);
d.field_array_of_objects("capabilityGaps", &capability_gap_entries, |obj, entry| {
render_dependency_contract_capability_gap(obj, entry);
});
d.field_array_of_objects("degraded", °raded, |obj, entry| {
render_dependency_contract_degradation(obj, entry);
});
d.field_array_of_objects("entries", report.entries, render_dependency_contract_entry);
d.field_object("driftPolicy", |policy| {
policy.field_str(
"cargoUpdateDryRun",
report.drift_policy.cargo_update_dry_run,
);
policy.field_array_of_strs("failConditions", report.drift_policy.fail_conditions);
policy.field_str(
"runtimeDiagnosticOwner",
report.drift_policy.runtime_diagnostic_owner,
);
});
});
b.field_array_of_objects("degraded", °raded, |obj, entry| {
render_dependency_contract_degradation(obj, entry);
});
b.finish()
}
/// Render dependency diagnostics as human-readable text.
#[must_use]
pub fn render_dependency_diagnostics_human(report: &DependencyDiagnosticsReport) -> String {
let mut output = String::from("ee diag dependencies\n\n");
output.push_str(&format!(
"matrix: revision {} ({}/{})\n",
report.matrix_revision, report.source_bead, report.source_plan_item
));
output.push_str(&format!(
"dependencies: {} total, {} default-enabled, {} forbidden default hits\n",
report.summary.total_dependencies,
report.summary.default_enabled_count,
report.summary.forbidden_default_hit_count
));
output.push_str(&format!(
"blocked feature gates: {}\n\n",
report.summary.blocked_feature_count
));
for entry in report.entries {
output.push_str(&format!(
"- {} [{}] {} via {}\n",
entry.name, entry.owning_surface, entry.status, entry.diagnostic_command
));
}
output
}
/// Render dependency diagnostics as TOON.
#[must_use]
pub fn render_dependency_diagnostics_toon(report: &DependencyDiagnosticsReport) -> String {
render_toon_from_json(&render_dependency_diagnostics_json(report))
}
/// Render integrity diagnostics as JSON (ee.response.v2 envelope).
#[must_use]
pub fn render_integrity_diagnostics_json(report: &IntegrityDiagnosticsReport) -> String {
let degraded = aggregate_integrity_degradations(&report.degraded);
let mut b = JsonBuilder::with_capacity(2048);
b.field_str("schema", RESPONSE_SCHEMA_V2);
b.field_bool("success", report.success());
b.field_object("data", |d| {
d.field_str("command", "diag integrity");
d.field_str("version", report.version);
d.field_str("schema", report.schema);
d.field_str("status", report.status.as_str());
d.field_str("workspaceId", &report.workspace_id);
d.field_str("databasePath", &report.database_path.to_string_lossy());
d.field_u32("sampleSize", report.sample_size);
d.field_array_of_objects("checks", &report.checks, build_integrity_check);
d.field_object("provenanceSample", |sample| {
match report.provenance_sample.as_ref() {
Some(provenance) => build_provenance_sample(sample, provenance),
None => build_provenance_sample_not_collected(
sample,
&report.workspace_id,
report.sample_size,
),
}
});
d.field_object("canary", |canary| {
build_integrity_canary(canary, &report.canary)
});
d.field_array_of_objects("degraded", °raded, build_aggregated_degradation);
});
b.field_array_of_objects("degraded", °raded, build_aggregated_degradation);
b.finish()
}
fn build_integrity_check(obj: &mut JsonBuilder, check: &IntegrityDiagnosticCheck) {
obj.field_str("name", check.name);
obj.field_str("severity", check.severity.as_str());
obj.field_str("message", &check.message);
field_optional_str(obj, "repair", check.repair);
}
fn build_provenance_sample(
obj: &mut JsonBuilder,
report: &crate::db::ProvenanceSampleVerificationReport,
) {
obj.field_str("status", "collected");
obj.field_str("workspaceId", &report.workspace_id);
obj.field_u32("requestedSampleSize", report.requested_sample_size);
obj.field_u32("checkedCount", report.checked_count);
obj.field_u32("verifiedCount", report.verified_count);
obj.field_u32("missingCount", report.missing_count);
obj.field_u32("mismatchCount", report.mismatch_count);
obj.field_array_of_objects("records", &report.records, build_provenance_record);
}
fn build_provenance_sample_not_collected(
obj: &mut JsonBuilder,
workspace_id: &str,
requested_sample_size: u32,
) {
obj.field_str("status", "not_collected");
obj.field_str("workspaceId", workspace_id);
obj.field_u32("requestedSampleSize", requested_sample_size);
obj.field_str(
"message",
"No provenance sample was collected for this diagnostic run.",
);
}
fn build_provenance_record(
obj: &mut JsonBuilder,
record: &crate::db::ProvenanceVerificationRecord,
) {
obj.field_str("memoryId", &record.memory_id);
field_optional_str(obj, "storedHash", record.stored_hash.as_deref());
obj.field_str("expectedHash", &record.expected_hash);
obj.field_str("status", &record.status);
obj.field_str("verifiedAt", &record.verified_at);
obj.field_str("note", &record.note);
}
fn build_integrity_canary(obj: &mut JsonBuilder, canary: &IntegrityCanaryReport) {
obj.field_bool("requested", canary.requested);
obj.field_bool("dryRun", canary.dry_run);
obj.field_str("memoryId", canary.memory_id);
obj.field_str("status", canary.status.as_str());
obj.field_str("message", &canary.message);
field_optional_str(obj, "repair", canary.repair);
}
/// Render integrity diagnostics as human-readable text.
#[must_use]
pub fn render_integrity_diagnostics_human(report: &IntegrityDiagnosticsReport) -> String {
let mut output = format!(
"ee diag integrity (v{})\n\nStatus: {}\nDatabase: {}\n\n",
report.version,
report.status.as_str(),
report.database_path.display()
);
output.push_str("Checks:\n");
for check in &report.checks {
output.push_str(&format!(
" [{}] {}: {}\n",
check.severity.as_str(),
check.name,
check.message
));
}
output.push_str(&format!(
"\nCanary: {} ({})\n",
report.canary.status.as_str(),
report.canary.memory_id
));
if let Some(sample) = report.provenance_sample.as_ref() {
output.push_str(&format!(
"Provenance sample: {} checked, {} verified, {} missing, {} mismatched\n",
sample.checked_count,
sample.verified_count,
sample.missing_count,
sample.mismatch_count
));
}
output.push_str("\nNext:\n ee diag integrity --json\n");
output
}
/// Render integrity diagnostics as TOON.
#[must_use]
pub fn render_integrity_diagnostics_toon(report: &IntegrityDiagnosticsReport) -> String {
render_toon_from_json(&render_integrity_diagnostics_json(report))
}
/// Render franken-stack doctor health as JSON (ee.response.v2 envelope).
#[must_use]
pub fn render_franken_health_json(report: &FrankenHealthReport) -> String {
let mut b = JsonBuilder::with_capacity(4096);
b.field_str("schema", RESPONSE_SCHEMA_V2);
b.field_bool("success", report.healthy);
b.field_object("data", |d| {
d.field_str("command", "doctor");
d.field_str("mode", "franken-health");
d.field_str("version", report.version);
d.field_str("schema", report.schema);
d.field_bool("healthy", report.healthy);
d.field_object("summary", |summary| {
summary.field_raw(
"totalDependencies",
&report.summary.total_dependencies.to_string(),
);
summary.field_raw("readyCount", &report.summary.ready_count.to_string());
summary.field_raw(
"featureGatedCount",
&report.summary.feature_gated_count.to_string(),
);
summary.field_raw(
"notLinkedCount",
&report.summary.not_linked_count.to_string(),
);
summary.field_raw(
"defaultEnabledCount",
&report.summary.default_enabled_count.to_string(),
);
summary.field_raw(
"localSourceCount",
&report.summary.local_source_count.to_string(),
);
summary.field_raw(
"forbiddenDefaultHitCount",
&report.summary.forbidden_default_hit_count.to_string(),
);
summary.field_raw(
"blockedFeatureCount",
&report.summary.blocked_feature_count.to_string(),
);
});
d.field_array_of_objects("dependencies", &report.dependencies, |obj, dependency| {
render_franken_dependency_health(obj, dependency);
});
});
b.field_raw("degraded", "[]");
b.finish()
}
/// Render franken-stack doctor health as human-readable text.
#[must_use]
pub fn render_franken_health_human(report: &FrankenHealthReport) -> String {
let mut output = String::from("ee doctor --franken-health\n\n");
output.push_str(&format!(
"healthy: {}\nready: {}/{}\nfeature-gated: {}\nblocked feature gates: {}\n\n",
report.healthy,
report.summary.ready_count,
report.summary.total_dependencies,
report.summary.feature_gated_count,
report.summary.blocked_feature_count
));
for dependency in &report.dependencies {
output.push_str(&format!(
"- {} [{}]: {} ({})\n",
dependency.name, dependency.owning_surface, dependency.readiness, dependency.status
));
}
output
}
/// Render franken-stack doctor health as TOON.
#[must_use]
pub fn render_franken_health_toon(report: &FrankenHealthReport) -> String {
render_toon_from_json(&render_franken_health_json(report))
}
fn render_dependency_diagnostics_summary(
d: &mut JsonBuilder,
report: &DependencyDiagnosticsReport,
) {
d.field_object("summary", |summary| {
summary.field_raw(
"totalDependencies",
&report.summary.total_dependencies.to_string(),
);
summary.field_raw(
"acceptedDefaultCount",
&report.summary.accepted_default_count.to_string(),
);
summary.field_raw(
"acceptedExternalCount",
&report.summary.accepted_external_count.to_string(),
);
summary.field_raw(
"optionalFeatureGatedCount",
&report.summary.optional_feature_gated_count.to_string(),
);
summary.field_raw(
"plannedNotLinkedCount",
&report.summary.planned_not_linked_count.to_string(),
);
summary.field_raw(
"defaultEnabledCount",
&report.summary.default_enabled_count.to_string(),
);
summary.field_raw(
"forbiddenDefaultHitCount",
&report.summary.forbidden_default_hit_count.to_string(),
);
summary.field_raw(
"blockedFeatureCount",
&report.summary.blocked_feature_count.to_string(),
);
});
}
fn dependency_contract_degraded_entries(
report: &DependencyDiagnosticsReport,
) -> Vec<DependencyContractEntry> {
report
.entries
.iter()
.copied()
.filter(|entry| {
entry.readiness() != "ready" && !dependency_contract_is_build_time_gap(entry)
})
.collect()
}
#[derive(Clone, Debug, Eq, PartialEq)]
struct DependencyContractDegradation {
aggregate: AggregatedDegradation,
dependencies: Vec<&'static str>,
owning_surfaces: Vec<&'static str>,
statuses: Vec<&'static str>,
readiness: Vec<&'static str>,
diagnostic_commands: Vec<&'static str>,
}
fn aggregate_dependency_contract_degradations(
entries: &[DependencyContractEntry],
) -> Vec<DependencyContractDegradation> {
aggregate_degraded_entries(entries.iter().copied().map(|entry| {
DegradationAggregationInput::new(
"dependency_contract",
entry.degradation_code,
"medium",
dependency_contract_degradation_message(&entry),
dependency_contract_degradation_repair(&entry),
)
}))
.into_iter()
.map(|aggregate| {
let matching: Vec<DependencyContractEntry> = entries
.iter()
.copied()
.filter(|entry| entry.degradation_code == aggregate.code)
.collect();
DependencyContractDegradation {
aggregate,
dependencies: unique_dependency_contract_values(&matching, |entry| entry.name),
owning_surfaces: unique_dependency_contract_values(&matching, |entry| {
entry.owning_surface
}),
statuses: unique_dependency_contract_values(&matching, |entry| entry.status),
readiness: unique_dependency_contract_values(&matching, |entry| entry.readiness()),
diagnostic_commands: unique_dependency_contract_values(&matching, |entry| {
entry.diagnostic_command
}),
}
})
.collect()
}
fn unique_dependency_contract_values<F>(
entries: &[DependencyContractEntry],
mut value: F,
) -> Vec<&'static str>
where
F: FnMut(DependencyContractEntry) -> &'static str,
{
entries
.iter()
.copied()
.map(&mut value)
.collect::<BTreeSet<_>>()
.into_iter()
.collect()
}
fn dependency_contract_capability_gap_entries(
report: &DependencyDiagnosticsReport,
) -> Vec<DependencyContractEntry> {
report
.entries
.iter()
.copied()
.filter(|entry| {
entry.readiness() != "ready" && dependency_contract_is_build_time_gap(entry)
})
.collect()
}
fn dependency_contract_is_build_time_gap(entry: &DependencyContractEntry) -> bool {
matches!(
entry.degradation_code,
"diagram_backend_unavailable" | "mcp_unavailable"
)
}
fn render_dependency_contract_capability_gap(
obj: &mut JsonBuilder,
entry: &DependencyContractEntry,
) {
obj.field_str("code", entry.degradation_code);
obj.field_str("severity", "medium");
obj.field_str("message", &dependency_contract_degradation_message(entry));
obj.field_str("repair", &dependency_contract_degradation_repair(entry));
obj.field_str("dependency", entry.name);
obj.field_str("owningSurface", entry.owning_surface);
obj.field_str("status", entry.status);
obj.field_str("readiness", entry.readiness());
obj.field_str("diagnosticCommand", entry.diagnostic_command);
obj.field_str("capabilitiesCommand", "ee capabilities --json");
}
fn render_dependency_contract_degradation(
obj: &mut JsonBuilder,
entry: &DependencyContractDegradation,
) {
build_aggregated_degradation(obj, &entry.aggregate);
if !entry.dependencies.is_empty() {
obj.field_object("details", |details| {
details.field_array_of_strs("dependencies", &entry.dependencies);
details.field_array_of_strs("owningSurfaces", &entry.owning_surfaces);
details.field_array_of_strs("statuses", &entry.statuses);
details.field_array_of_strs("readiness", &entry.readiness);
details.field_array_of_strs("diagnosticCommands", &entry.diagnostic_commands);
});
}
}
fn dependency_contract_degradation_message(entry: &DependencyContractEntry) -> String {
match entry.degradation_code {
"diagram_backend_unavailable" => format!(
"Diagram backend dependency {} is unavailable; plain Mermaid/text output remains available.",
entry.name
),
"graph_unavailable" => format!(
"Graph dependency {} is feature-gated; graph analytics are unavailable until the optional profile is enabled.",
entry.name
),
"mcp_unavailable" => format!(
"MCP adapter dependency {} is unavailable because the optional MCP surface is planned but not linked.",
entry.name
),
_ => format!(
"Dependency {} for {} is unavailable with readiness {}.",
entry.name,
entry.owning_surface,
entry.readiness()
),
}
}
fn dependency_contract_degradation_repair(entry: &DependencyContractEntry) -> String {
match entry.degradation_code {
"diagram_backend_unavailable" => {
"Use plain Mermaid output until the FrankenMermaid adapter contract is linked and audited."
.to_string()
}
"graph_unavailable" => {
"Enable the accepted graph optional feature profile and rerun ee diag graph --json."
.to_string()
}
"mcp_unavailable" => {
"Enable the mcp feature only after the MCP dependency audit passes; inspect ee diag dependencies --json."
.to_string()
}
_ => format!(
"Inspect {} and satisfy the dependency contract before enabling {}.",
entry.diagnostic_command, entry.owning_surface
),
}
}
fn render_dependency_contract_entry(obj: &mut JsonBuilder, entry: &DependencyContractEntry) {
obj.field_str("name", entry.name);
obj.field_str("kind", entry.kind);
obj.field_str("owningSurface", entry.owning_surface);
obj.field_str("status", entry.status);
obj.field_str("readiness", entry.readiness());
obj.field_bool("enabledByDefault", entry.enabled_by_default);
render_dependency_source(obj, "source", &entry.source);
render_dependency_feature_profile(obj, "defaultFeatureProfile", &entry.default_feature_profile);
obj.field_array_of_objects(
"optionalFeatureProfiles",
entry.optional_feature_profiles,
render_optional_feature_profile,
);
obj.field_array_of_objects(
"blockedFeatures",
entry.blocked_features,
render_blocked_feature,
);
obj.field_array_of_strs(
"forbiddenTransitiveDependencies",
entry.forbidden_transitive_dependencies,
);
obj.field_str("minimumSmokeTest", entry.minimum_smoke_test);
obj.field_str("degradationCode", entry.degradation_code);
obj.field_array_of_strs("statusFields", entry.status_fields);
obj.field_str("diagnosticCommand", entry.diagnostic_command);
obj.field_str("releasePinDecision", entry.release_pin_decision);
}
fn render_franken_dependency_health(obj: &mut JsonBuilder, dependency: &FrankenDependencyHealth) {
obj.field_str("name", dependency.name);
obj.field_str("owningSurface", dependency.owning_surface);
obj.field_str("status", dependency.status);
obj.field_str("readiness", dependency.readiness);
obj.field_bool("enabledByDefault", dependency.enabled_by_default);
render_dependency_source(obj, "source", &dependency.source);
render_dependency_feature_profile(
obj,
"defaultFeatureProfile",
&dependency.default_feature_profile,
);
obj.field_array_of_objects(
"blockedFeatures",
dependency.blocked_features,
render_blocked_feature,
);
obj.field_array_of_strs(
"forbiddenTransitiveDependencies",
dependency.forbidden_transitive_dependencies,
);
obj.field_str("degradationCode", dependency.degradation_code);
obj.field_str("diagnosticCommand", dependency.diagnostic_command);
obj.field_str("minimumSmokeTest", dependency.minimum_smoke_test);
obj.field_str("releasePinDecision", dependency.release_pin_decision);
}
fn render_dependency_source(obj: &mut JsonBuilder, key: &str, source: &DependencySource) {
obj.field_object(key, |source_json| {
source_json.field_str("kind", source.kind);
source_json.field_str("version", source.version);
source_json.field_str("path", source.path);
});
}
fn render_dependency_feature_profile(
obj: &mut JsonBuilder,
key: &str,
profile: &DependencyFeatureProfile,
) {
obj.field_object(key, |profile_json| {
profile_json.field_bool("defaultFeatures", profile.default_features);
profile_json.field_array_of_strs("features", profile.features);
});
}
fn render_optional_feature_profile(
obj: &mut JsonBuilder,
profile: &DependencyOptionalFeatureProfile,
) {
obj.field_str("name", profile.name);
obj.field_array_of_strs("features", profile.features);
obj.field_str("status", profile.status);
}
fn render_blocked_feature(obj: &mut JsonBuilder, feature: &DependencyBlockedFeature) {
obj.field_str("name", feature.name);
obj.field_array_of_strs("forbiddenCrates", feature.forbidden_crates);
obj.field_str("action", feature.action);
}
/// Render a quarantine report as JSON (ee.response.v2 envelope).
#[must_use]
pub fn render_quarantine_json(report: &QuarantineReport) -> String {
let degraded = aggregate_quarantine_degradations(&report.degraded);
let mut b = JsonBuilder::with_capacity(1024);
b.field_str("schema", RESPONSE_SCHEMA_V2);
b.field_bool("success", true);
b.field_object("data", |d| {
d.field_str("command", "diag quarantine");
d.field_str("version", report.version);
d.field_str("storageStatus", report.storage_status.as_str());
if let Some(workspace_path) = &report.workspace_path {
d.field_str("workspacePath", workspace_path);
}
if let Some(database_path) = &report.database_path {
d.field_str("databasePath", database_path);
}
d.field_object("summary", |s| {
s.field_raw(
"quarantinedCount",
&report.summary.quarantined_count.to_string(),
);
s.field_raw("atRiskCount", &report.summary.at_risk_count.to_string());
s.field_raw("blockedCount", &report.summary.blocked_count.to_string());
s.field_raw("totalSources", &report.summary.total_sources.to_string());
s.field_raw("healthyCount", &report.summary.healthy_count.to_string());
});
d.field_array_of_objects(
"quarantinedSources",
&report.quarantined_sources,
build_quarantine_entry,
);
d.field_array_of_objects(
"atRiskSources",
&report.at_risk_sources,
build_quarantine_entry,
);
d.field_array_of_objects(
"blockedSources",
&report.blocked_sources,
build_quarantine_entry,
);
d.field_array_of_objects("degraded", °raded, build_aggregated_degradation);
});
b.field_array_of_objects("degraded", °raded, build_aggregated_degradation);
b.finish()
}
fn build_quarantine_entry(obj: &mut JsonBuilder, entry: &QuarantineEntry) {
let source_id = redact_quarantine_source_uri(&entry.source_id);
obj.field_str("sourceId", &source_id);
obj.field_str("advisory", entry.advisory.as_str());
obj.field_raw("effectiveTrust", &format!("{:.4}", entry.effective_trust));
obj.field_raw("decayFactor", &format!("{:.4}", entry.decay_factor));
obj.field_raw("negativeRate", &format!("{:.4}", entry.negative_rate));
obj.field_raw("negativeCount", &entry.negative_count.to_string());
obj.field_raw("totalImports", &entry.total_imports.to_string());
obj.field_str("message", &entry.message);
obj.field_bool("permitsImport", entry.permits_import);
obj.field_bool("requiresValidation", entry.requires_validation);
}
/// Render a quarantine report as human-readable text.
#[must_use]
pub fn render_quarantine_human(report: &QuarantineReport) -> String {
let mut output = format!("ee diag quarantine (v{})\n\n", report.version);
output.push_str(&format!("Storage: {}\n", report.storage_status.as_str()));
if let Some(workspace_path) = &report.workspace_path {
output.push_str(&format!("Workspace: {workspace_path}\n"));
}
if let Some(database_path) = &report.database_path {
output.push_str(&format!("Database: {database_path}\n"));
}
let degraded = aggregate_quarantine_degradations(&report.degraded);
if !degraded.is_empty() {
output.push('\n');
output.push_str("Degraded:\n");
for degraded in °raded {
output.push_str(&format!(
" {}: {}\n repair: {}\n",
degraded.code, degraded.message, degraded.repair
));
}
}
if !report.has_issues() {
output.push('\n');
output.push_str("No sources require attention.\n");
output.push_str(&format!(
"Tracked: {} sources, {} healthy\n\n",
report.summary.total_sources, report.summary.healthy_count
));
output.push_str("Next:\n ee diag quarantine --json\n");
return output;
}
output.push_str(&format!(
"Summary: {} quarantined, {} at risk, {} blocked\n\n",
report.summary.quarantined_count,
report.summary.at_risk_count,
report.summary.blocked_count
));
if !report.blocked_sources.is_empty() {
output.push_str("Blocked Sources:\n");
for entry in &report.blocked_sources {
let source_id = redact_quarantine_source_uri(&entry.source_id);
output.push_str(&format!(
" ✗ {} (trust {:.2})\n {}\n",
source_id, entry.effective_trust, entry.message
));
}
output.push('\n');
}
if !report.quarantined_sources.is_empty() {
output.push_str("Quarantined Sources:\n");
for entry in &report.quarantined_sources {
let source_id = redact_quarantine_source_uri(&entry.source_id);
output.push_str(&format!(
" ⚠ {} (trust {:.2}, decay {:.2})\n {}\n",
source_id, entry.effective_trust, entry.decay_factor, entry.message
));
}
output.push('\n');
}
if !report.at_risk_sources.is_empty() {
output.push_str("At-Risk Sources:\n");
for entry in &report.at_risk_sources {
let source_id = redact_quarantine_source_uri(&entry.source_id);
output.push_str(&format!(
" ◐ {} (trust {:.2})\n {}\n",
source_id, entry.effective_trust, entry.message
));
}
output.push('\n');
}
output.push_str("Next:\n ee diag quarantine --json\n ee import cass --dry-run --json\n");
output
}
/// Render a quarantine report as TOON.
#[must_use]
pub fn render_quarantine_toon(report: &QuarantineReport) -> String {
render_toon_from_json(&render_quarantine_json(report))
}
/// Render a single quarantine entry as JSON (ee.response.v2 envelope).
#[must_use]
pub fn render_quarantine_entry_json(entry: &crate::db::StoredTrustQuarantine) -> String {
let source_uri = redact_quarantine_source_uri(&entry.source_uri);
let reason = redact_quarantine_source_uri(&entry.reason);
let mut b = JsonBuilder::with_capacity(512);
b.field_str("schema", RESPONSE_SCHEMA_V2);
b.field_bool("success", true);
b.field_object("data", |d| {
d.field_str("command", "diag quarantine show");
d.field_str("sourceUri", &source_uri);
d.field_str("status", &entry.status);
d.field_str("firstEventAt", &entry.first_event_at);
d.field_str("lastEventAt", &entry.last_event_at);
d.field_raw("harmfulEventCount", &entry.harmful_event_count.to_string());
if let Some(quarantined_until) = &entry.quarantined_until {
d.field_str("quarantinedUntil", quarantined_until);
}
d.field_str("reason", &reason);
d.field_str("createdAt", &entry.created_at);
d.field_str("updatedAt", &entry.updated_at);
});
b.field_raw("degraded", "[]");
b.finish()
}
/// Render a single quarantine entry as human-readable text.
#[must_use]
pub fn render_quarantine_entry_human(entry: &crate::db::StoredTrustQuarantine) -> String {
let source_uri = redact_quarantine_source_uri(&entry.source_uri);
let reason = redact_quarantine_source_uri(&entry.reason);
let mut output = "ee diag quarantine show\n\n".to_string();
output.push_str(&format!("Source: {source_uri}\n"));
output.push_str(&format!("Status: {}\n", entry.status));
output.push_str(&format!("Harmful events: {}\n", entry.harmful_event_count));
output.push_str(&format!("First event: {}\n", entry.first_event_at));
output.push_str(&format!("Last event: {}\n", entry.last_event_at));
if let Some(quarantined_until) = &entry.quarantined_until {
output.push_str(&format!("Quarantined until: {quarantined_until}\n"));
}
output.push_str(&format!("Reason: {reason}\n"));
output.push_str(&format!("\nRecord created: {}\n", entry.created_at));
output.push_str(&format!("Record updated: {}\n", entry.updated_at));
output.push_str("\nNext:\n ee diag quarantine list --json\n");
output
}
/// Render a single quarantine entry as TOON.
#[must_use]
pub fn render_quarantine_entry_toon(entry: &crate::db::StoredTrustQuarantine) -> String {
render_toon_from_json(&render_quarantine_entry_json(entry))
}
fn redact_quarantine_source_uri(value: &str) -> String {
redact_memory_output_provenance_uri(value)
}
// ============================================================================
// EE-243: Graph Diagnostic Output
// ============================================================================
/// Render a graph diagnostic report as JSON (ee.response.v2 envelope).
#[must_use]
pub fn render_graph_diag_json(readiness: &crate::graph::GraphModuleReadiness) -> String {
use crate::models::CapabilityStatus;
let capabilities: Vec<serde_json::Value> = readiness
.capabilities()
.iter()
.map(|cap| {
serde_json::json!({
"name": cap.name().as_str(),
"surface": cap.surface().as_str(),
"status": match cap.status() {
CapabilityStatus::Ready => "ready",
CapabilityStatus::Pending => "pending",
CapabilityStatus::Degraded => "degraded",
CapabilityStatus::Unimplemented => "unimplemented",
},
"repair": cap.repair(),
})
})
.collect();
let status = match readiness.status() {
CapabilityStatus::Ready => "ready",
CapabilityStatus::Pending => "pending",
CapabilityStatus::Degraded => "degraded",
CapabilityStatus::Unimplemented => "unimplemented",
};
serde_json::json!({
"schema": RESPONSE_SCHEMA_V2,
"success": readiness.status() == CapabilityStatus::Ready,
"data": {
"command": "diag graph",
"subsystem": readiness.subsystem(),
"contract": readiness.contract(),
"graphEngine": readiness.graph_engine(),
"status": status,
"capabilityCount": capabilities.len(),
"readyCount": readiness.capabilities().iter().filter(|c| c.status() == CapabilityStatus::Ready).count(),
"pendingCount": readiness.capabilities().iter().filter(|c| c.status() == CapabilityStatus::Pending).count(),
"capabilities": capabilities,
},
"degraded": [],
})
.to_string()
}
/// Render a graph diagnostic report as human-readable text.
#[must_use]
pub fn render_graph_diag_human(readiness: &crate::graph::GraphModuleReadiness) -> String {
use crate::models::CapabilityStatus;
let mut output = String::new();
output.push_str("Graph Module Diagnostics\n\n");
let status_str = match readiness.status() {
CapabilityStatus::Ready => "ready",
CapabilityStatus::Pending => "pending",
CapabilityStatus::Degraded => "degraded",
CapabilityStatus::Unimplemented => "unimplemented",
};
output.push_str(&format!("Status: {status_str}\n"));
output.push_str(&format!("Contract: {}\n", readiness.contract()));
output.push_str(&format!("Engine: {}\n\n", readiness.graph_engine()));
output.push_str("Capabilities:\n");
for cap in readiness.capabilities() {
let status = match cap.status() {
CapabilityStatus::Ready => "[ready]",
CapabilityStatus::Pending => "[pending]",
CapabilityStatus::Degraded => "[degraded]",
CapabilityStatus::Unimplemented => "[unimplemented]",
};
output.push_str(&format!(
" {} {} ({})\n",
status,
cap.name().as_str(),
cap.surface().as_str()
));
if cap.status() != CapabilityStatus::Ready {
output.push_str(&format!(" Next: {}\n", cap.repair()));
}
}
output
}
/// Render a graph diagnostic report as TOON.
#[must_use]
pub fn render_graph_diag_toon(readiness: &crate::graph::GraphModuleReadiness) -> String {
render_toon_from_json(&render_graph_diag_json(readiness))
}
/// Render a streams diagnostic report as JSON (ee.response.v2 envelope).
#[must_use]
pub fn render_streams_json(report: &crate::core::streams::StreamsReport) -> String {
let mut b = JsonBuilder::with_capacity(512);
b.field_str("schema", RESPONSE_SCHEMA_V2);
b.field_bool("success", report.is_healthy());
b.field_object("data", |d| {
d.field_str("command", "diag streams");
d.field_str("version", report.version);
d.field_bool("stdoutIsolated", report.stdout_isolated);
d.field_bool("stderrReceivedProbe", report.stderr_received_probe);
d.field_str("stderrProbeMessage", &report.stderr_probe_message);
d.field_bool("healthy", report.is_healthy());
});
b.field_raw("degraded", "[]");
b.finish()
}
/// Render a streams diagnostic report as human-readable text.
#[must_use]
pub fn render_streams_human(report: &crate::core::streams::StreamsReport) -> String {
let mut output = format!("ee diag streams (v{})\n\n", report.version);
if report.is_healthy() {
output.push_str("Stream separation: OK\n\n");
output.push_str(" stdout: isolated for machine data\n");
output.push_str(" stderr: received diagnostic probe\n\n");
output.push_str("This confirms that stdout contains only machine-readable data\n");
output
.push_str("and stderr receives diagnostics, as required for agent-native operation.\n");
} else {
output.push_str("Stream separation: FAILED\n\n");
if !report.stdout_isolated {
output.push_str(" ✗ stdout is not isolated\n");
}
if !report.stderr_received_probe {
output.push_str(" ✗ stderr did not receive probe\n");
}
output.push_str("\nNext:\n Check for stderr redirection or write failures.\n");
}
output
}
/// Render a streams diagnostic report as TOON.
#[must_use]
pub fn render_streams_toon(report: &crate::core::streams::StreamsReport) -> String {
render_toon_from_json(&render_streams_json(report))
}
/// Render a check report as JSON (ee.response.v2 envelope).
#[must_use]
pub fn render_check_json(report: &CheckReport) -> String {
let mut b = JsonBuilder::with_capacity(512);
b.field_str("schema", RESPONSE_SCHEMA_V2);
b.field_bool("success", report.posture.is_usable());
b.field_object("data", |d| {
d.field_str("command", "check");
d.field_str("version", report.version);
d.field_str("posture", report.posture.as_str());
d.field_bool("workspaceInitialized", report.workspace_initialized);
d.field_bool("databaseReady", report.database_ready);
d.field_bool("searchReady", report.search_ready);
d.field_bool("runtimeReady", report.runtime_ready);
d.field_array_of_objects(
"suggestedActions",
&report.suggested_actions,
|obj, action| {
obj.field_raw("priority", &action.priority.to_string());
obj.field_str("command", action.command);
obj.field_str("reason", action.reason);
},
);
});
b.field_raw("degraded", "[]");
b.finish()
}
/// Render a check report as human-readable text.
#[must_use]
pub fn render_check_human(report: &CheckReport) -> String {
let mut output = format!("ee check\n\nposture: {}\n\n", report.posture.as_str());
output.push_str(&format!(
"workspace: {}\ndatabase: {}\nsearch: {}\nruntime: {}\n",
if report.workspace_initialized {
"initialized"
} else {
"not initialized"
},
if report.database_ready {
"ready"
} else {
"not ready"
},
if report.search_ready {
"ready"
} else {
"not ready"
},
if report.runtime_ready {
"ready"
} else {
"not ready"
},
));
if !report.suggested_actions.is_empty() {
output.push_str("\nNext:\n");
for action in &report.suggested_actions {
output.push_str(&format!(" {} — {}\n", action.command, action.reason));
}
}
output
}
/// Render a check report as TOON.
#[must_use]
pub fn render_check_toon(report: &CheckReport) -> String {
render_toon_from_json(&render_check_json(report))
}
/// Render a health report as JSON (ee.response.v2 envelope).
#[must_use]
pub fn render_health_json(report: &HealthReport) -> String {
let mut b = JsonBuilder::with_capacity(512);
b.field_str("schema", RESPONSE_SCHEMA_V2);
b.field_bool("success", report.verdict.is_healthy());
b.field_object("data", |d| {
d.field_str("command", "health");
d.field_str("version", report.version);
d.field_str("verdict", report.verdict.as_str());
d.field_object("subsystems", |s| {
s.field_bool("runtime", report.runtime_ok);
s.field_bool("storage", report.storage_ok);
s.field_bool("search", report.search_ok);
});
d.field_object("summary", |s| {
s.field_raw("issueCount", &report.issue_count().to_string());
s.field_raw("highSeverity", &report.high_severity_count().to_string());
s.field_raw(
"mediumSeverity",
&report.medium_severity_count().to_string(),
);
});
d.field_array_of_objects("issues", &report.issues, |obj, issue| {
obj.field_str("subsystem", issue.subsystem);
obj.field_str("code", issue.code);
obj.field_str("severity", issue.severity);
obj.field_str("message", issue.message);
});
});
b.field_raw("degraded", "[]");
b.finish()
}
/// Render a health report as human-readable text.
#[must_use]
pub fn render_health_human(report: &HealthReport) -> String {
let mut output = format!(
"ee health (v{})\n\nVerdict: {}\n\n",
report.version,
report.verdict.as_str().to_uppercase()
);
output.push_str("Subsystems:\n");
output.push_str(&format!(
" runtime: {}\n storage: {}\n search: {}\n",
if report.runtime_ok { "ok" } else { "not ok" },
if report.storage_ok { "ok" } else { "not ok" },
if report.search_ok { "ok" } else { "not ok" },
));
if !report.issues.is_empty() {
output.push_str(&format!("\nIssues ({}):\n", report.issue_count()));
for issue in &report.issues {
output.push_str(&format!(
" [{}] {} — {}\n",
issue.severity, issue.subsystem, issue.message
));
}
}
output.push_str("\nNext:\n ee health --json\n ee doctor\n");
output
}
/// Render a health report as TOON.
#[must_use]
pub fn render_health_toon(report: &HealthReport) -> String {
render_toon_from_json(&render_health_json(report))
}
/// Render the opt-in structural health surface as canonical JSON wrapped
/// in the `ee.response.v2` envelope (bd-34ivx).
///
/// The inner data block is the existing `StructuralHealthReport` shape
/// (with degradations aggregated). Consumers that previously parsed the
/// bare report at the top level must now look at `.data`; the report's
/// own `schema` id remains intact inside `.data.schema`.
#[must_use]
pub fn render_structural_health_json(report: &StructuralHealthReport) -> String {
let mut report = report.clone();
report.degraded = aggregate_structural_health_degradations(&report.degraded)
.into_iter()
.map(|entry| StructuralHealthDegradation {
code: entry.code,
severity: entry.severity,
message: entry.message,
repair: (!entry.repair.is_empty()).then_some(entry.repair),
})
.collect();
let Ok(report_value) = serde_json::to_value(&report) else {
return r#"{"schema":"ee.error.v2","error":{"code":"serialization_failed","message":"Failed to serialize response","severity":"high","details":{"recovery":[]},"nonRecoverable":false}}"#.to_owned();
};
let degraded = response_degraded_from_data(&report_value);
serde_json::json!({
"schema": RESPONSE_SCHEMA_V2,
"success": true,
"data": report_value,
"degraded": degraded,
})
.to_string()
}
/// Render the opt-in structural health surface as human-readable text.
#[must_use]
pub fn render_structural_health_human(report: &StructuralHealthReport) -> String {
let mut output = format!(
"ee health structural\n\nStatus: {}\nK-truss max k: {}\nSupport memories: {}\nContradiction clusters: {}\n",
report.summary.status,
report.summary.k_truss_max_k,
report.summary.support_subgraph_memory_count,
report.summary.contradiction_cluster_count,
);
let degraded = aggregate_structural_health_degradations(&report.degraded);
if !degraded.is_empty() {
output.push_str("\nDegraded:\n");
for degraded in °raded {
output.push_str(&format!(
" [{}] {} - {}\n",
degraded.severity, degraded.code, degraded.message
));
}
}
output.push_str("\nNext:\n ee health --robot-insights --json\n");
output
}
/// Render the opt-in structural health surface as Markdown.
#[must_use]
pub fn render_structural_health_markdown(report: &StructuralHealthReport) -> String {
let mut output = String::new();
let _ = writeln!(output, "# Structural Health");
let _ = writeln!(output);
let _ = writeln!(output, "- Schema: `{}`", report.schema);
let _ = writeln!(output, "- Snapshot version: {}", report.snapshot_version);
let _ = writeln!(output, "- Status: `{}`", report.summary.status);
let _ = writeln!(output, "- K-truss max k: {}", report.k_truss.max_k);
let _ = writeln!(
output,
"- Support memories: {}",
report.k_truss.support_subgraph_memory_count
);
let _ = writeln!(
output,
"- Contradiction clusters: {}",
report.contradiction_clusters.len()
);
let _ = writeln!(
output,
"- Recommended command: `{}`",
report.summary.recommended_command
);
if !report.k_truss.top_members.is_empty() {
let _ = writeln!(output);
let _ = writeln!(output, "## K-Truss Members");
for member in &report.k_truss.top_members {
let _ = writeln!(
output,
"- `{}` k={} triangleSupport={}",
member.memory_id, member.k, member.triangle_support
);
}
}
if !report.contradiction_clusters.is_empty() {
let _ = writeln!(output);
let _ = writeln!(output, "## Contradiction Clusters");
for cluster in &report.contradiction_clusters {
let examples = if cluster.example_memory_ids.is_empty() {
"none".to_string()
} else {
cluster.example_memory_ids.join(", ")
};
let _ = writeln!(
output,
"- `{}` memories={} density={:.6} severity=`{}` examples={} action=`{}`",
cluster.cluster_id,
cluster.memory_count,
cluster.contradiction_density,
cluster.severity,
examples,
cluster.suggested_action
);
}
}
let degraded = aggregate_structural_health_degradations(&report.degraded);
if !degraded.is_empty() {
let _ = writeln!(output);
let _ = writeln!(output, "## Degraded");
for degraded in °raded {
let _ = writeln!(
output,
"- **{}** `{}`: {}",
degraded.severity, degraded.code, degraded.message
);
if !degraded.repair.is_empty() {
let _ = writeln!(output, " - Repair: `{}`", degraded.repair);
}
}
}
output
}
/// Render the opt-in structural health surface as TOON.
#[must_use]
pub fn render_structural_health_toon(report: &StructuralHealthReport) -> String {
render_toon_from_json(&render_structural_health_json(report))
}
/// Render the memory-health scorecard as canonical JSON wrapped in the
/// `ee.response.v2` envelope.
#[must_use]
pub fn render_health_scorecard_json(report: &HealthScorecardReport) -> String {
match serde_json::to_string(report) {
Ok(raw) => ResponseEnvelope::success().data_raw(&raw).finish(),
Err(_) => r#"{"schema":"ee.error.v2","error":{"code":"serialization_failed","message":"Failed to serialize response","severity":"high","details":{"recovery":[]},"nonRecoverable":false}}"#.to_owned(),
}
}
#[must_use]
pub fn render_health_scorecard_toon(report: &HealthScorecardReport) -> String {
render_toon_from_json(&render_health_scorecard_json(report))
}
#[must_use]
pub fn render_health_scorecard_human(report: &HealthScorecardReport) -> String {
let mut output = format!(
"ee health scorecard\n\nScore: {} ({})\nTrend: {}",
report.score, report.status, report.trend.direction
);
if let Some(previous) = report.trend.previous_score {
let _ = write!(
output,
" ({} -> {}, delta {:+})",
previous, report.trend.current_score, report.trend.delta
);
}
output.push('\n');
output.push_str("\nSub-scores:\n");
for sub_score in &report.sub_scores {
output.push_str(&format!(
" {:<10} {:>3} {} - {}\n",
sub_score.name, sub_score.score, sub_score.status, sub_score.rationale
));
}
if !report.top_actions.is_empty() {
output.push_str("\nTop actions:\n");
for action in &report.top_actions {
output.push_str(&format!(
" {}. {} - {}\n {}\n",
action.rank, action.title, action.reason, action.command
));
}
}
if !report.degraded.is_empty() {
output.push_str("\nDegraded signals:\n");
for degraded in &report.degraded {
output.push_str(&format!(
" [{}] {} - {}\n",
degraded.severity, degraded.code, degraded.message
));
}
}
output
}
fn render_schema_value_json(value: &serde_json::Value) -> String {
serde_json::to_string(value)
.unwrap_or_else(|_| r#"{"schema":"ee.error.v2","error":{"code":"serialization_failed","message":"Failed to serialize response","severity":"high","details":{"recovery":[]},"nonRecoverable":false}}"#.to_owned())
}
fn json_object_field<'a>(
value: &'a serde_json::Value,
field: &str,
) -> Option<&'a serde_json::Value> {
value.as_object().and_then(|object| object.get(field))
}
fn json_field_string<'a>(value: &'a serde_json::Value, field: &str) -> Option<&'a str> {
json_object_field(value, field).and_then(serde_json::Value::as_str)
}
fn json_markdown_value(value: Option<&serde_json::Value>) -> String {
match value {
None | Some(serde_json::Value::Null) => "unavailable".to_owned(),
Some(serde_json::Value::String(value)) => value.clone(),
Some(serde_json::Value::Bool(value)) => value.to_string(),
Some(serde_json::Value::Number(value)) => value.to_string(),
Some(value) => render_schema_value_json(value),
}
}
fn json_string_list(value: Option<&serde_json::Value>) -> String {
value
.and_then(serde_json::Value::as_array)
.map(|items| {
items
.iter()
.map(|item| {
item.as_str()
.map(ToOwned::to_owned)
.unwrap_or_else(|| json_markdown_value(Some(item)))
})
.collect::<Vec<_>>()
.join(", ")
})
.filter(|items| !items.is_empty())
.unwrap_or_else(|| "none".to_owned())
}
fn render_json_degraded_markdown(output: &mut String, degraded: Option<&serde_json::Value>) {
let Some(degraded) = degraded.and_then(serde_json::Value::as_array) else {
return;
};
if degraded.is_empty() {
return;
}
let _ = writeln!(output);
let _ = writeln!(output, "## Degraded");
for entry in degraded {
let severity = json_field_string(entry, "severity").unwrap_or("unknown");
let code = json_field_string(entry, "code").unwrap_or("unknown");
let message = json_field_string(entry, "message").unwrap_or("degraded");
let _ = writeln!(output, "- **{severity}** `{code}`: {message}");
if let Some(repair) = json_field_string(entry, "repair").filter(|repair| !repair.is_empty())
{
let _ = writeln!(output, " - Repair: `{repair}`");
}
}
}
/// Render a Pack DNA block as canonical JSON.
#[must_use]
pub fn render_pack_dna_json(pack_dna: &serde_json::Value) -> String {
render_schema_value_json(pack_dna)
}
/// Render a Pack DNA block as TOON.
#[must_use]
pub fn render_pack_dna_toon(pack_dna: &serde_json::Value) -> String {
render_toon_from_json(&render_pack_dna_json(pack_dna))
}
/// Render a Pack DNA block as Markdown.
#[must_use]
pub fn render_pack_dna_markdown(pack_dna: &serde_json::Value) -> String {
let dominator = json_object_field(pack_dna, "voronoiDominator");
let community = json_object_field(pack_dna, "communityOfMass");
let ego = json_object_field(pack_dna, "egoSubgraph");
let ppr_neighbors = json_object_field(pack_dna, "pprNeighbors")
.and_then(serde_json::Value::as_array)
.map(Vec::as_slice)
.unwrap_or(&[]);
let node_count = ego
.and_then(|value| json_object_field(value, "nodes"))
.and_then(serde_json::Value::as_array)
.map_or(0, Vec::len);
let edge_count = ego
.and_then(|value| json_object_field(value, "edges"))
.and_then(serde_json::Value::as_array)
.map_or(0, Vec::len);
let mut output = String::new();
let _ = writeln!(output, "# Pack DNA");
let _ = writeln!(output);
let _ = writeln!(
output,
"- Schema: `{}`",
json_field_string(pack_dna, "schema").unwrap_or("ee.context.pack_dna.v1")
);
let _ = writeln!(
output,
"- Snapshot version: {}",
json_markdown_value(json_object_field(pack_dna, "snapshotVersion"))
);
let _ = writeln!(
output,
"- Voronoi dominator: `{}` distance={} reason={}",
dominator
.and_then(|value| json_field_string(value, "memoryId"))
.unwrap_or("unavailable"),
json_markdown_value(dominator.and_then(|value| json_object_field(value, "distance"))),
json_markdown_value(dominator.and_then(|value| json_object_field(value, "reason")))
);
let _ = writeln!(
output,
"- Community of mass: `{}` mass={} topMemoryIds={}",
community
.and_then(|value| json_field_string(value, "communityId"))
.unwrap_or("unavailable"),
json_markdown_value(community.and_then(|value| json_object_field(value, "mass"))),
json_string_list(community.and_then(|value| json_object_field(value, "topMemoryIds")))
);
let _ = writeln!(
output,
"- Ego subgraph: nodes={} edges={}",
node_count, edge_count
);
if !ppr_neighbors.is_empty() {
let _ = writeln!(output);
let _ = writeln!(output, "## PPR Neighbors");
for neighbor in ppr_neighbors {
let _ = writeln!(
output,
"- rank={} `{}` score={}",
json_markdown_value(json_object_field(neighbor, "rank")),
json_field_string(neighbor, "memoryId").unwrap_or("unavailable"),
json_markdown_value(json_object_field(neighbor, "score"))
);
}
}
render_json_degraded_markdown(&mut output, json_object_field(pack_dna, "degraded"));
output
}
/// Render a causal `ee why` explanation block as canonical JSON.
#[must_use]
pub fn render_why_causal_json(causal: &serde_json::Value) -> String {
render_schema_value_json(causal)
}
/// Render a causal `ee why` explanation block as TOON.
#[must_use]
pub fn render_why_causal_toon(causal: &serde_json::Value) -> String {
render_toon_from_json(&render_why_causal_json(causal))
}
/// Render a causal `ee why` explanation block as Markdown.
#[must_use]
pub fn render_why_causal_markdown(causal: &serde_json::Value) -> String {
let paths = json_object_field(causal, "paths")
.and_then(serde_json::Value::as_array)
.map(Vec::as_slice)
.unwrap_or(&[]);
let mut output = String::new();
let _ = writeln!(output, "# Why Causal");
let _ = writeln!(output);
let _ = writeln!(
output,
"- Schema: `{}`",
json_field_string(causal, "schema").unwrap_or("ee.why.causal.v1")
);
let _ = writeln!(
output,
"- Memory: `{}`",
json_field_string(causal, "memoryId").unwrap_or("unavailable")
);
let _ = writeln!(
output,
"- Snapshot version: {}",
json_markdown_value(json_object_field(causal, "snapshotVersion"))
);
let _ = writeln!(
output,
"- Min cut: {}",
json_markdown_value(json_object_field(causal, "minCut"))
);
if !paths.is_empty() {
let _ = writeln!(output);
let _ = writeln!(output, "## Paths");
for path in paths {
let _ = writeln!(
output,
"- rank={} `{}` -> `{}` edges={} totalContribution={}",
json_markdown_value(json_object_field(path, "rank")),
json_field_string(path, "sourceMemoryId").unwrap_or("unavailable"),
json_field_string(path, "targetMemoryId").unwrap_or("unavailable"),
json_markdown_value(json_object_field(path, "edgeCount")),
json_markdown_value(json_object_field(path, "totalContribution"))
);
if let Some(steps) = json_object_field(path, "steps")
.and_then(serde_json::Value::as_array)
.filter(|steps| !steps.is_empty())
{
for step in steps {
let _ = writeln!(
output,
" - `{}` -> `{}` relation=`{}` contribution={}",
json_field_string(step, "source").unwrap_or("unavailable"),
json_field_string(step, "target").unwrap_or("unavailable"),
json_field_string(step, "relation").unwrap_or("unspecified"),
json_markdown_value(json_object_field(step, "contributionScore"))
);
}
}
}
}
render_json_degraded_markdown(&mut output, json_object_field(causal, "degraded"));
output
}
/// Render a memory impact analysis block as canonical JSON.
#[must_use]
pub fn render_memory_impact_analysis_json(impact: &serde_json::Value) -> String {
render_schema_value_json(impact)
}
/// Render a memory impact analysis block as TOON.
#[must_use]
pub fn render_memory_impact_analysis_toon(impact: &serde_json::Value) -> String {
render_toon_from_json(&render_memory_impact_analysis_json(impact))
}
/// Render a memory impact analysis block as Markdown.
#[must_use]
pub fn render_memory_impact_analysis_markdown(impact: &serde_json::Value) -> String {
let analysis = json_object_field(impact, "impactAnalysis");
let lineage = json_object_field(impact, "revisionLineage")
.and_then(serde_json::Value::as_array)
.map(Vec::as_slice)
.unwrap_or(&[]);
let frontiers = json_object_field(impact, "frontiers")
.and_then(serde_json::Value::as_array)
.map(Vec::as_slice)
.unwrap_or(&[]);
let mut output = String::new();
let _ = writeln!(output, "# Memory Impact Analysis");
let _ = writeln!(output);
let _ = writeln!(
output,
"- Schema: `{}`",
json_field_string(impact, "schema").unwrap_or("ee.memory.impact_analysis.v1")
);
let _ = writeln!(
output,
"- Memory: `{}`",
json_field_string(impact, "memoryId").unwrap_or("unavailable")
);
let _ = writeln!(
output,
"- Snapshot version: {}",
json_markdown_value(json_object_field(impact, "snapshotVersion"))
);
let _ = writeln!(
output,
"- Affected memories: {}",
json_markdown_value(
analysis.and_then(|value| json_object_field(value, "affectedMemoryCount"))
)
);
let _ = writeln!(
output,
"- Immediate dominator: `{}`",
analysis
.and_then(|value| json_field_string(value, "immediateDominator"))
.unwrap_or("none")
);
let _ = writeln!(
output,
"- Validation status: `{}`",
analysis
.and_then(|value| json_field_string(value, "validationStatus"))
.unwrap_or("unavailable")
);
let _ = writeln!(
output,
"- Dominance frontier: {}",
json_string_list(analysis.and_then(|value| json_object_field(value, "dominanceFrontier")))
);
if !lineage.is_empty() {
let _ = writeln!(output);
let _ = writeln!(output, "## Revision Lineage");
for item in lineage {
let _ = writeln!(
output,
"- `{}` logical=`{}` depth={} relation=`{}`",
json_field_string(item, "memoryId").unwrap_or("unavailable"),
json_field_string(item, "logicalId").unwrap_or("unavailable"),
json_markdown_value(json_object_field(item, "depth")),
json_field_string(item, "relation").unwrap_or("unavailable")
);
}
}
if !frontiers.is_empty() {
let _ = writeln!(output);
let _ = writeln!(output, "## Frontiers");
for frontier in frontiers {
let _ = writeln!(
output,
"- `{}` size={} affected={}",
json_field_string(frontier, "memoryId").unwrap_or("unavailable"),
json_markdown_value(json_object_field(frontier, "dominanceFrontierSize")),
json_string_list(json_object_field(frontier, "affectedMemoryIds"))
);
}
}
render_json_degraded_markdown(&mut output, json_object_field(impact, "degraded"));
output
}
/// Render a proximity report as canonical JSON.
#[must_use]
pub fn render_proximity_json(report: &crate::graph::gomory_hu::ProximityReport) -> String {
serde_json::to_string(report).unwrap_or_else(|_| {
r#"{"schema":"ee.error.v2","error":{"code":"serialization_failed","message":"Failed to serialize response","severity":"high","details":{"recovery":[]},"nonRecoverable":false}}"#.to_string()
})
}
/// Render a proximity report as TOON.
#[must_use]
pub fn render_proximity_toon(report: &crate::graph::gomory_hu::ProximityReport) -> String {
render_toon_from_json(&render_proximity_json(report))
}
/// Render a proximity report as Markdown.
#[must_use]
pub fn render_proximity_markdown(report: &crate::graph::gomory_hu::ProximityReport) -> String {
let min_cut = report
.min_cut
.map(|value| format!("{value:.6}"))
.unwrap_or_else(|| "unavailable".to_string());
let tree_path = report
.tree_path
.as_ref()
.map(|nodes| nodes.join(" -> "))
.unwrap_or_else(|| "unavailable".to_string());
let mut output = String::new();
let _ = writeln!(output, "# Proximity");
let _ = writeln!(output);
let _ = writeln!(output, "- Schema: `{}`", report.schema);
let _ = writeln!(output, "- Memory A: `{}`", report.memory_a);
let _ = writeln!(output, "- Memory B: `{}`", report.memory_b);
let _ = writeln!(output, "- Snapshot version: {}", report.snapshot_version);
let _ = writeln!(output, "- Interpretation: `{}`", report.interpretation);
let _ = writeln!(output, "- Min cut: {min_cut}");
let _ = writeln!(output, "- Tree path: {tree_path}");
if !report.degraded.is_empty() {
let _ = writeln!(output);
let _ = writeln!(output, "## Degraded");
for degraded in &report.degraded {
let _ = writeln!(
output,
"- **{}** `{}`: {}",
degraded.severity, degraded.code, degraded.message
);
if let Some(repair) = degraded.repair.as_deref() {
let _ = writeln!(output, " - Repair: `{repair}`");
}
}
}
output
}
/// Render a memory show report as JSON (ee.response.v2 envelope).
#[must_use]
pub fn render_memory_show_json(report: &MemoryShowReport) -> String {
let mut b = JsonBuilder::with_capacity(1024);
b.field_str("schema", RESPONSE_SCHEMA_V2);
b.field_bool("success", report.found && report.error.is_none());
b.field_object("data", |d| {
d.field_str("command", "memory show");
d.field_str("version", report.version);
d.field_bool("found", report.found);
d.field_bool("is_tombstoned", report.is_tombstoned);
if let Some(ref details) = report.memory {
d.field_str("memoryId", &details.memory.id);
d.field_object("memory", |m| {
render_memory_fields(m, details);
});
}
if let Some(ref err) = report.error {
d.field_str("error", err);
}
});
b.field_raw("degraded", "[]");
b.finish()
}
/// Render memory fields into a JSON builder.
fn render_memory_fields(b: &mut JsonBuilder, details: &MemoryDetails) {
let mem = &details.memory;
b.field_str("id", &mem.id);
b.field_str("memoryId", &mem.id);
b.field_str("workspace_id", &mem.workspace_id);
b.field_str("level", &mem.level);
b.field_str("kind", &mem.kind);
b.field_str("content", &mem.content);
field_optional_str(b, "workflow_id", mem.workflow_id.as_deref());
b.field_raw("confidence", &format!("{:.4}", mem.confidence));
b.field_raw("utility", &format!("{:.4}", mem.utility));
b.field_raw("importance", &format!("{:.4}", mem.importance));
if let Some(ref uri) = mem.provenance_uri {
b.field_str("provenance_uri", &redact_local_memory_provenance_uri(uri));
}
b.field_str("trust_class", &mem.trust_class);
if let Some(ref sub) = mem.trust_subclass {
b.field_str("trust_subclass", sub);
}
b.field_str("created_at", &mem.created_at);
b.field_str("updated_at", &mem.updated_at);
if let Some(ref ts) = mem.tombstoned_at {
b.field_str("tombstoned_at", ts);
}
let validity = memory_validity(&mem.valid_from, &mem.valid_to);
field_optional_str(b, "valid_from", validity.valid_from.as_deref());
field_optional_str(b, "valid_to", validity.valid_to.as_deref());
b.field_str("validity_status", &validity.status);
b.field_str("validity_window_kind", &validity.window_kind);
if let Some(ref typed_fields) = details.typed_fields {
b.field_raw("typedFields", &typed_fields.to_string());
}
b.field_array_of_objects("tags", &details.tags, |obj, tag| {
obj.field_str("name", tag);
});
}
/// Render a memory show report as human-readable text.
#[must_use]
pub fn render_memory_show_human(report: &MemoryShowReport) -> String {
if let Some(ref err) = report.error {
return format!("error: {err}\n");
}
if !report.found {
return "Memory not found.\n".to_string();
}
let details = match &report.memory {
Some(d) => d,
None => return "Memory not found.\n".to_string(),
};
let mem = &details.memory;
let mut output = format!("Memory: {}\n\n", mem.id);
output.push_str(&format!(" Level: {}\n", mem.level));
output.push_str(&format!(" Kind: {}\n", mem.kind));
output.push_str(&format!(" Content:\n {}\n", mem.content));
if let Some(ref workflow_id) = mem.workflow_id {
output.push_str(&format!(" Workflow: {workflow_id}\n"));
}
output.push_str(&format!(
" Scores: confidence={:.2}, utility={:.2}, importance={:.2}\n",
mem.confidence, mem.utility, mem.importance
));
output.push_str(&format!(" Trust: {}", mem.trust_class));
if let Some(ref sub) = mem.trust_subclass {
output.push_str(&format!(" ({})", sub));
}
output.push('\n');
if let Some(ref uri) = mem.provenance_uri {
output.push_str(&format!(
" Provenance: {}\n",
redact_local_memory_provenance_uri(uri)
));
}
output.push_str(&format!(" Created: {}\n", mem.created_at));
output.push_str(&format!(" Updated: {}\n", mem.updated_at));
if let Some(ref ts) = mem.tombstoned_at {
output.push_str(&format!(" Tombstoned: {}\n", ts));
}
let validity = memory_validity(&mem.valid_from, &mem.valid_to);
output.push_str(&format!(
" Validity: {} ({})\n",
validity.status, validity.window_kind
));
if let Some(ref ts) = validity.valid_from {
output.push_str(&format!(" From: {ts}\n"));
}
if let Some(ref ts) = validity.valid_to {
output.push_str(&format!(" To: {ts}\n"));
}
if !details.tags.is_empty() {
output.push_str(&format!(" Tags: {}\n", details.tags.join(", ")));
}
output
}
/// Render a memory show report as TOON.
#[must_use]
pub fn render_memory_show_toon(report: &MemoryShowReport) -> String {
render_toon_from_json(&render_memory_show_json(report))
}
/// Render a memory list report as JSON (ee.response.v2 envelope).
#[must_use]
pub fn render_memory_list_json(report: &MemoryListReport) -> String {
let mut b = JsonBuilder::with_capacity(2048);
b.field_str("schema", RESPONSE_SCHEMA_V2);
b.field_bool("success", report.error.is_none());
b.field_object("data", |d| {
d.field_str("command", "memory list");
d.field_str("version", report.version);
d.field_u32("total_count", report.total_count);
d.field_bool("truncated", report.truncated);
d.field_object("filter", |f| {
if let Some(ref level) = report.filter.level {
f.field_str("level", level);
}
if let Some(ref tag) = report.filter.tag {
f.field_str("tag", tag);
}
f.field_bool("include_tombstoned", report.filter.include_tombstoned);
});
d.field_array_of_objects("memories", &report.memories, |obj, m| {
obj.field_str("id", &m.id);
obj.field_str("level", &m.level);
obj.field_str("kind", &m.kind);
obj.field_str("content", &m.content);
obj.field_bool("content_truncated", m.content_truncated);
obj.field_raw("confidence", &format!("{:.4}", m.confidence));
if let Some(ref uri) = m.provenance_uri {
obj.field_str("provenance_uri", &redact_local_memory_provenance_uri(uri));
}
obj.field_bool("is_tombstoned", m.is_tombstoned);
field_optional_str(obj, "valid_from", m.valid_from.as_deref());
field_optional_str(obj, "valid_to", m.valid_to.as_deref());
obj.field_str("validity_status", &m.validity_status);
obj.field_str("validity_window_kind", &m.validity_window_kind);
obj.field_str("created_at", &m.created_at);
});
if let Some(ref err) = report.error {
d.field_str("error", err);
}
});
b.field_raw("degraded", "[]");
b.finish()
}
#[must_use]
pub fn render_memory_drift_report_json(
report: &crate::core::memory_drift::MemoryDriftReport,
) -> String {
let data = serde_json::to_value(report).unwrap_or_else(|_| serde_json::json!({}));
let degraded = response_degraded_from_data(&data);
serde_json::json!({
"schema": "ee.response.v2",
"success": true,
"data": data,
"degraded": degraded,
})
.to_string()
}
#[must_use]
pub fn render_memory_drift_report_human(
report: &crate::core::memory_drift::MemoryDriftReport,
) -> String {
let mut output = format!("Memory drift report: {}\n", report.mode.as_str());
output.push_str(&format!(
"Total: {} current={} changed={} missing={} unverifiable={}\n",
report.summary.total_memories,
report.summary.current,
report.summary.changed,
report.summary.missing_source,
report.summary.unverifiable
));
for item in report.items.iter().take(20) {
output.push_str(&format!(
" {} {} {} {}\n",
item.memory_id,
item.drift_status.as_str(),
item.severity,
item.top_reason
));
}
if report.items.len() > 20 {
output.push_str(&format!(
" ... {} additional item(s) omitted from human output\n",
report.items.len() - 20
));
}
if !report.degraded.is_empty() {
output.push_str("Degraded:\n");
for degraded in &report.degraded {
output.push_str(&format!(
" {} [{}] {}\n",
degraded.code, degraded.severity, degraded.message
));
}
}
output
}
#[must_use]
pub fn render_memory_drift_report_toon(
report: &crate::core::memory_drift::MemoryDriftReport,
) -> String {
render_toon_from_json(&render_memory_drift_report_json(report))
}
fn redact_memory_output_provenance_uri(value: &str) -> String {
let redacted_paths = redact_memory_output_path_like_segments(value);
redact_memory_output_secret_like_segments(&redacted_paths)
}
fn redact_local_memory_provenance_uri(value: &str) -> String {
redact_memory_output_secret_like_segments(value)
}
fn redact_memory_output_path_like_segments(value: &str) -> String {
let mut output = String::with_capacity(value.len());
let mut cursor = 0;
while cursor < value.len() {
let Some((relative_index, _)) = value[cursor..].char_indices().find(|(_, c)| *c == '/')
else {
output.push_str(&value[cursor..]);
break;
};
let start = cursor + relative_index;
if !memory_output_path_starts_sensitive_segment(&value[start..]) {
output.push_str(&value[cursor..=start]);
cursor = start + 1;
continue;
}
output.push_str(&value[cursor..start]);
output.push_str("[REDACTED_PATH]");
cursor = value[start..]
.char_indices()
.find_map(|(index, c)| memory_output_path_boundary(c).then_some(start + index))
.unwrap_or(value.len());
}
output
}
fn memory_output_path_starts_sensitive_segment(value: &str) -> bool {
const PREFIXES: &[&str] = &[
"/Users/",
"/Volumes/",
"/private/",
"/var/",
"/tmp/",
"/home/",
"/data/",
"/dp/",
"/workspace/",
"/repo/",
"/etc/",
];
PREFIXES.iter().any(|prefix| value.starts_with(prefix))
}
fn memory_output_path_boundary(c: char) -> bool {
c.is_whitespace() || matches!(c, '?' | '#' | '"' | '\'' | ')' | ']' | '}' | ',' | ';')
}
fn redact_memory_output_secret_like_segments(value: &str) -> String {
let mut output = String::with_capacity(value.len());
let mut cursor = 0;
while cursor < value.len() {
let lower = value[cursor..].to_ascii_lowercase();
let Some((relative_start, key_len)) = memory_output_next_secret_key(&lower) else {
output.push_str(&value[cursor..]);
break;
};
let value_start = cursor + relative_start + key_len;
output.push_str(&value[cursor..value_start]);
output.push_str("[REDACTED:secret]");
cursor = value[value_start..]
.char_indices()
.find_map(|(index, c)| memory_output_secret_boundary(c).then_some(value_start + index))
.unwrap_or(value.len());
}
output
}
fn memory_output_next_secret_key(value: &str) -> Option<(usize, usize)> {
const KEYS: &[&str] = &[
"api_key=",
"apikey=",
"access_token=",
"auth_token=",
"token=",
"secret=",
"password=",
"passwd=",
];
KEYS.iter()
.filter_map(|key| value.find(key).map(|index| (index, key.len())))
.min_by_key(|(index, _)| *index)
}
fn memory_output_secret_boundary(c: char) -> bool {
c.is_whitespace() || matches!(c, '&' | '"' | '\'' | ')' | ']' | '}' | ',' | ';')
}
/// Render a memory list report as human-readable text.
#[must_use]
pub fn render_memory_list_human(report: &MemoryListReport) -> String {
if let Some(ref err) = report.error {
return format!("error: {err}\n");
}
let mut output = format!("Memories ({} total", report.total_count);
if report.truncated {
output.push_str(", showing first batch");
}
output.push_str(")\n\n");
if report.memories.is_empty() {
output.push_str(" No memories found.\n");
return output;
}
for m in &report.memories {
output.push_str(&format!(" {} [{}] {}\n", m.id, m.level, m.kind));
output.push_str(&format!(" {}\n", m.content));
output.push_str(&format!(
" confidence={:.2}, created={}, validity={} ({})\n",
m.confidence, m.created_at, m.validity_status, m.validity_window_kind
));
if m.is_tombstoned {
output.push_str(" [TOMBSTONED]\n");
}
output.push('\n');
}
output.push_str("Next:\n ee memory show <ID>\n");
output
}
/// Render a memory list report as TOON.
#[must_use]
pub fn render_memory_list_toon(report: &MemoryListReport) -> String {
render_toon_from_json(&render_memory_list_json(report))
}
/// Render a memory history report as JSON (ee.response.v2 envelope).
#[must_use]
pub fn render_memory_history_json(report: &MemoryHistoryReport) -> String {
let mut b = JsonBuilder::with_capacity(2048);
b.field_str("schema", RESPONSE_SCHEMA_V2);
b.field_bool("success", report.error.is_none());
b.field_object("data", |d| {
d.field_str("command", "memory history");
d.field_str("version", report.version);
d.field_str("memory_id", &report.memory_id);
d.field_bool("memory_exists", report.memory_exists);
d.field_bool("is_tombstoned", report.is_tombstoned);
d.field_u32("total_count", report.total_count);
d.field_bool("truncated", report.truncated);
d.field_array_of_objects("entries", &report.entries, |obj, e| {
obj.field_str("audit_id", &e.audit_id);
obj.field_str("timestamp", &e.timestamp);
if let Some(ref actor) = e.actor {
obj.field_str("actor", actor);
}
obj.field_str("action", &e.action);
if let Some(ref details) = e.details {
obj.field_raw("details", &audit_details_json_fragment(details));
}
});
if let Some(ref err) = report.error {
d.field_str("error", err);
}
});
b.field_raw("degraded", "[]");
b.finish()
}
fn audit_details_json_fragment(details: &str) -> String {
serde_json::from_str::<serde_json::Value>(details).map_or_else(
|_| json_string_fragment(details),
|value| serde_json::to_string(&value).unwrap_or_else(|_| json_string_fragment(details)),
)
}
fn json_string_fragment(value: &str) -> String {
let mut output = String::with_capacity(value.len() + 2);
output.push('"');
output.push_str(&escape_json_string(value));
output.push('"');
output
}
/// Render a memory history report as human-readable text.
#[must_use]
pub fn render_memory_history_human(report: &MemoryHistoryReport) -> String {
if let Some(ref err) = report.error {
return format!("error: {err}\n");
}
if !report.memory_exists {
return format!("Memory not found: {}\n", report.memory_id);
}
let mut output = format!(
"History for {} ({} entries",
report.memory_id, report.total_count
);
if report.truncated {
output.push_str(", showing first batch");
}
output.push_str(")\n");
if report.is_tombstoned {
output.push_str(" [TOMBSTONED]\n");
}
output.push('\n');
if report.entries.is_empty() {
output.push_str(" No history entries found.\n");
return output;
}
for e in &report.entries {
output.push_str(&format!(" {} [{}]\n", e.timestamp, e.action));
if let Some(ref actor) = e.actor {
output.push_str(&format!(" actor: {actor}\n"));
}
if let Some(ref details) = e.details {
output.push_str(&format!(" details: {details}\n"));
}
output.push_str(&format!(" audit_id: {}\n\n", e.audit_id));
}
output
}
/// Render a memory history report as a deterministic Mermaid diagram.
#[must_use]
pub fn render_memory_history_mermaid(report: &MemoryHistoryReport) -> String {
let mut output = String::from("flowchart TD\n");
output.push_str(&format!(
" %% command: memory history (memoryId={}, entries={}, total={}, truncated={})\n",
escape_mermaid_label(&report.memory_id),
report.entries.len(),
report.total_count,
report.truncated
));
if report.is_tombstoned {
output.push_str(" %% tombstoned: true\n");
}
output.push_str(&format!(
" memory[\"memory: {}\"]\n",
escape_mermaid_label(&report.memory_id)
));
if report.entries.is_empty() {
output.push_str(" empty[\"no history entries\"]\n");
output.push_str(" memory -.-> empty\n");
return output;
}
for (index, entry) in report.entries.iter().enumerate() {
let node_id = format!("history{}", index + 1);
let label = format!("{}: {}", entry.timestamp, entry.action);
output.push_str(&format!(
" {}[\"{}\"]\n",
node_id,
escape_mermaid_label(&label)
));
output.push_str(&format!(" {} -->|records| memory\n", node_id));
output.push_str(&format!(
" %% audit_id[{}]: {}\n",
index + 1,
escape_mermaid_label(&entry.audit_id)
));
if let Some(actor) = &entry.actor {
output.push_str(&format!(
" %% actor[{}]: {}\n",
index + 1,
escape_mermaid_label(actor)
));
}
if let Some(details) = &entry.details {
output.push_str(&format!(
" %% details[{}]: {}\n",
index + 1,
escape_mermaid_label(details)
));
}
}
for index in 0..report.entries.len().saturating_sub(1) {
output.push_str(&format!(
" history{} -->|older| history{}\n",
index + 1,
index + 2
));
}
if report.truncated {
output.push_str(
" %% limited output: audit history was truncated; rerun with a higher --limit for more entries\n",
);
}
output
}
/// Render a memory history report as TOON.
#[must_use]
pub fn render_memory_history_toon(report: &MemoryHistoryReport) -> String {
render_toon_from_json(&render_memory_history_json(report))
}
/// Render a procedural rule add report as JSON (`ee.response.v2` envelope).
#[must_use]
pub fn render_rule_add_json(report: &RuleAddReport) -> String {
ResponseEnvelope::success()
.data_raw(&report.data_json())
.finish()
}
/// Render a procedural rule add report as human-readable text.
#[must_use]
pub fn render_rule_add_human(report: &RuleAddReport) -> String {
report.human_summary()
}
/// Render a procedural rule add report as TOON.
#[must_use]
pub fn render_rule_add_toon(report: &RuleAddReport) -> String {
render_toon_from_json(&render_rule_add_json(report))
}
/// Render a procedural rule list report as JSON (`ee.response.v2` envelope).
#[must_use]
pub fn render_rule_list_json(report: &RuleListReport) -> String {
ResponseEnvelope::success()
.data_raw(&report.data_json())
.finish()
}
/// Render a procedural rule list report as human-readable text.
#[must_use]
pub fn render_rule_list_human(report: &RuleListReport) -> String {
report.human_summary()
}
/// Render a procedural rule list report as TOON.
#[must_use]
pub fn render_rule_list_toon(report: &RuleListReport) -> String {
render_toon_from_json(&render_rule_list_json(report))
}
/// Render a procedural rule show report as JSON (`ee.response.v2` envelope).
#[must_use]
pub fn render_rule_show_json(report: &RuleShowReport) -> String {
ResponseEnvelope::success()
.data_raw(&report.data_json())
.finish()
}
/// Render a procedural rule show report as human-readable text.
#[must_use]
pub fn render_rule_show_human(report: &RuleShowReport) -> String {
report.human_summary()
}
/// Render a procedural rule show report as TOON.
#[must_use]
pub fn render_rule_show_toon(report: &RuleShowReport) -> String {
render_toon_from_json(&render_rule_show_json(report))
}
/// Render a procedural rule mark report as JSON (`ee.response.v2` envelope).
#[must_use]
pub fn render_rule_mark_json(report: &RuleMarkReport) -> String {
ResponseEnvelope::success()
.data_raw(&report.data_json())
.finish()
}
/// Render a procedural rule mark report as human-readable text.
#[must_use]
pub fn render_rule_mark_human(report: &RuleMarkReport) -> String {
report.human_summary()
}
/// Render a procedural rule mark report as TOON.
#[must_use]
pub fn render_rule_mark_toon(report: &RuleMarkReport) -> String {
render_toon_from_json(&render_rule_mark_json(report))
}
/// Render a procedural rule protection report as JSON (`ee.response.v2` envelope).
#[must_use]
pub fn render_rule_protect_json(report: &RuleProtectReport) -> String {
ResponseEnvelope::success()
.data_raw(&report.data_json())
.finish()
}
/// Render a procedural rule protection report as human-readable text.
#[must_use]
pub fn render_rule_protect_human(report: &RuleProtectReport) -> String {
report.human_summary()
}
/// Render a procedural rule protection report as TOON.
#[must_use]
pub fn render_rule_protect_toon(report: &RuleProtectReport) -> String {
render_toon_from_json(&render_rule_protect_json(report))
}
/// Render a procedural rule update report as JSON (`ee.response.v2` envelope).
#[must_use]
pub fn render_rule_update_json(report: &RuleUpdateReport) -> String {
ResponseEnvelope::success()
.data_raw(&report.data_json())
.finish()
}
/// Render a procedural rule update report as human-readable text.
#[must_use]
pub fn render_rule_update_human(report: &RuleUpdateReport) -> String {
report.human_summary()
}
/// Render a procedural rule update report as TOON.
#[must_use]
pub fn render_rule_update_toon(report: &RuleUpdateReport) -> String {
render_toon_from_json(&render_rule_update_json(report))
}
/// Render a playbook extraction report as JSON (`ee.response.v2` envelope).
#[must_use]
pub fn render_playbook_extract_json(report: &PlaybookExtractReport) -> String {
ResponseEnvelope::success()
.data_raw(&report.data_json())
.finish()
}
/// Render a playbook extraction report as human-readable text.
#[must_use]
pub fn render_playbook_extract_human(report: &PlaybookExtractReport) -> String {
report.human_summary()
}
/// Render a playbook extraction report as TOON.
#[must_use]
pub fn render_playbook_extract_toon(report: &PlaybookExtractReport) -> String {
render_toon_from_json(&render_playbook_extract_json(report))
}
/// Render a feedback quarantine list report as JSON (`ee.response.v2` envelope).
#[must_use]
pub fn render_outcome_quarantine_list_json(report: &OutcomeQuarantineListReport) -> String {
ResponseEnvelope::success()
.data_raw(&report.data_json())
.finish()
}
/// Render a feedback quarantine list report as human-readable text.
#[must_use]
pub fn render_outcome_quarantine_list_human(report: &OutcomeQuarantineListReport) -> String {
report.human_summary()
}
/// Render a feedback quarantine list report as TOON.
#[must_use]
pub fn render_outcome_quarantine_list_toon(report: &OutcomeQuarantineListReport) -> String {
render_toon_from_json(&render_outcome_quarantine_list_json(report))
}
/// Render a feedback quarantine review report as JSON (`ee.response.v2` envelope).
#[must_use]
pub fn render_outcome_quarantine_review_json(report: &OutcomeQuarantineReviewReport) -> String {
ResponseEnvelope::success()
.data_raw(&report.data_json())
.finish()
}
/// Render a feedback quarantine review report as human-readable text.
#[must_use]
pub fn render_outcome_quarantine_review_human(report: &OutcomeQuarantineReviewReport) -> String {
report.human_summary()
}
/// Render a feedback quarantine review report as TOON.
#[must_use]
pub fn render_outcome_quarantine_review_toon(report: &OutcomeQuarantineReviewReport) -> String {
render_toon_from_json(&render_outcome_quarantine_review_json(report))
}
/// Render a curation candidate list report as JSON (`ee.response.v2` envelope).
#[must_use]
pub fn render_curate_candidates_json(report: &CurateCandidatesReport) -> String {
ResponseEnvelope::success()
.data_raw(&report.data_json())
.finish()
}
/// Render a curation candidate list report as human-readable text.
#[must_use]
pub fn render_curate_candidates_human(report: &CurateCandidatesReport) -> String {
report.human_summary()
}
/// Render a curation candidate list report as TOON.
#[must_use]
pub fn render_curate_candidates_toon(report: &CurateCandidatesReport) -> String {
render_toon_from_json(&render_curate_candidates_json(report))
}
/// Render a curation validation report as JSON (`ee.response.v2` envelope).
#[must_use]
pub fn render_curate_validate_json(report: &CurateValidateReport) -> String {
ResponseEnvelope::success()
.data_raw(&report.data_json())
.finish()
}
/// Render a curation validation report as human-readable text.
#[must_use]
pub fn render_curate_validate_human(report: &CurateValidateReport) -> String {
report.human_summary()
}
/// Render a curation validation report as TOON.
#[must_use]
pub fn render_curate_validate_toon(report: &CurateValidateReport) -> String {
render_toon_from_json(&render_curate_validate_json(report))
}
/// Render a reflection proposal report as JSON (`ee.response.v2` envelope).
#[must_use]
pub fn render_reflect_propose_json(report: &ReflectionProposeReport) -> String {
let data_raw = serde_json::to_string(report)
.unwrap_or_else(|_| r#"{"schema":"ee.reflect.propose.v1"}"#.to_owned());
ResponseEnvelope::success().data_raw(&data_raw).finish()
}
/// Render a reflection proposal report as TOON.
#[must_use]
pub fn render_reflect_propose_toon(report: &ReflectionProposeReport) -> String {
render_toon_from_json(&render_reflect_propose_json(report))
}
/// Render a reflection result ingest report as JSON (`ee.response.v2` envelope).
#[must_use]
pub fn render_reflect_ingest_json(report: &ReflectionIngestReport) -> String {
let data_raw = serde_json::to_string(report)
.unwrap_or_else(|_| r#"{"schema":"ee.reflect.ingest.v1"}"#.to_owned());
ResponseEnvelope::success().data_raw(&data_raw).finish()
}
/// Render a reflection result ingest report as TOON.
#[must_use]
pub fn render_reflect_ingest_toon(report: &ReflectionIngestReport) -> String {
render_toon_from_json(&render_reflect_ingest_json(report))
}
/// Render a curation apply report as JSON (`ee.response.v2` envelope).
#[must_use]
pub fn render_curate_apply_json(report: &CurateApplyReport) -> String {
ResponseEnvelope::success()
.data_raw(&report.data_json())
.finish()
}
/// Render a curation apply report as human-readable text.
#[must_use]
pub fn render_curate_apply_human(report: &CurateApplyReport) -> String {
report.human_summary()
}
/// Render a curation apply report as TOON.
#[must_use]
pub fn render_curate_apply_toon(report: &CurateApplyReport) -> String {
render_toon_from_json(&render_curate_apply_json(report))
}
/// Render a curation show/preview report as JSON (`ee.response.v2` envelope).
#[must_use]
pub fn render_curate_show_json(report: &CurateShowReport) -> String {
ResponseEnvelope::success()
.data_raw(&report.data_json())
.finish()
}
/// Render a curation show/preview report as human-readable text.
#[must_use]
pub fn render_curate_show_human(report: &CurateShowReport) -> String {
let mut lines = Vec::new();
lines.push(format!(
"Curation candidate {} ({})",
report.candidate.id, report.candidate.candidate_type
));
lines.push(format!(
" status: {} review_state: {}",
report.candidate.status, report.candidate.review_state
));
if let Some(target) = report.candidate.target_memory_id.as_deref() {
lines.push(format!(" targetMemoryId: {target}"));
} else {
lines.push(" targetMemoryId: (none — create-derived candidate)".to_owned());
}
if let Some(planned) = &report.planned_application {
lines.push(format!(
" plannedApplication: status={} decision={}",
planned.status, planned.decision
));
if let Some(id) = planned.created_memory_id.as_deref() {
lines.push(format!(" plannedCreatedMemoryId: {id}"));
}
lines.push(format!(
" plannedDerivedFromLinkCount: {}",
planned.planned_derived_from_links.len()
));
lines.push(format!(
" plannedEvidenceAttachmentCount: {}",
planned.planned_evidence_attachments.len()
));
if let Some(job) = planned.planned_search_index_job_id.as_deref() {
lines.push(format!(" plannedSearchIndexJobId: {job}"));
}
if let Some(audit) = planned.audit_schema_preview.as_deref() {
lines.push(format!(" auditSchemaPreview: {audit}"));
}
if !planned.errors.is_empty() {
lines.push(" plannedApplication errors:".to_owned());
for issue in &planned.errors {
lines.push(format!(" - {}: {}", issue.code, issue.message));
}
}
if !planned.warnings.is_empty() {
lines.push(" plannedApplication warnings:".to_owned());
for issue in &planned.warnings {
lines.push(format!(" - {}: {}", issue.code, issue.message));
}
}
}
if !report.next_commands.is_empty() {
lines.push(" nextCommands:".to_owned());
for command in &report.next_commands {
lines.push(format!(" - {command}"));
}
}
lines.push(format!(" nextAction: {}", report.next_action));
lines.join("\n") + "\n"
}
/// Render a curation show/preview report as TOON.
#[must_use]
pub fn render_curate_show_toon(report: &CurateShowReport) -> String {
render_toon_from_json(&render_curate_show_json(report))
}
/// Render a curation review lifecycle report as JSON (`ee.response.v2` envelope).
#[must_use]
pub fn render_curate_review_json(report: &CurateReviewReport) -> String {
ResponseEnvelope::success()
.data_raw(&report.data_json())
.finish()
}
/// Render a curation review lifecycle report as human-readable text.
#[must_use]
pub fn render_curate_review_human(report: &CurateReviewReport) -> String {
report.human_summary()
}
/// Render a curation review lifecycle report as TOON.
#[must_use]
pub fn render_curate_review_toon(report: &CurateReviewReport) -> String {
render_toon_from_json(&render_curate_review_json(report))
}
/// Render a curation TTL disposition report as JSON (`ee.response.v2` envelope).
#[must_use]
pub fn render_curate_disposition_json(report: &CurateDispositionReport) -> String {
ResponseEnvelope::success()
.data_raw(&report.data_json())
.finish()
}
/// Render a curation TTL disposition report as human-readable text.
#[must_use]
pub fn render_curate_disposition_human(report: &CurateDispositionReport) -> String {
report.human_summary()
}
/// Render a curation TTL disposition report as TOON.
#[must_use]
pub fn render_curate_disposition_toon(report: &CurateDispositionReport) -> String {
render_toon_from_json(&render_curate_disposition_json(report))
}
/// Render binary version and build provenance as JSON (`ee.response.v2` envelope).
#[must_use]
pub fn render_version_json(report: &VersionReport) -> String {
let degraded = aggregate_build_provenance_degradations(&report.degradations);
let mut b = JsonBuilder::with_capacity(2048);
b.field_str("schema", RESPONSE_SCHEMA_V2);
b.field_bool("success", true);
b.field_object("data", |d| {
d.field_str("command", "version");
d.field_str("schema", VERSION_PROVENANCE_SCHEMA_V1);
d.field_str("package", report.build.package);
d.field_str("version", report.build.version);
d.field_str("releaseChannel", report.build.release_channel);
d.field_object("source", |source| {
field_optional_str(source, "gitCommit", report.build.git_commit);
field_optional_str(source, "gitTag", report.build.git_tag);
field_optional_bool(source, "gitDirty", report.build.git_dirty);
source.field_str("state", source_state(report));
});
d.field_object("build", |build| {
build.field_str("profile", report.build.build_profile);
build.field_str("targetTriple", report.build.target_triple);
build.field_str("targetArch", report.build.target_arch);
build.field_str("targetOs", report.build.target_os);
build.field_str("timestampPolicy", report.build.build_timestamp_policy);
build.field_raw("timestamp", "null");
});
d.field_array_of_objects("features", &report.features, |obj, feature| {
obj.field_str("name", feature.name);
obj.field_bool("enabled", feature.enabled);
});
d.field_array_of_objects("schemas", &report.schemas, |obj, schema| {
obj.field_str("name", schema.name);
obj.field_str("schema", schema.schema);
});
d.field_object("database", |db| {
db.field_object("supportedMigrationRange", |range| {
range.field_u32("min", report.build.min_db_migration);
range.field_u32("max", report.build.max_db_migration);
});
db.field_str("compatibility", "unknown_without_workspace");
});
d.field_object("provenance", |provenance| {
provenance.field_bool("available", report.provenance_available());
provenance.field_array_of_objects("degraded", °raded, build_aggregated_degradation);
});
});
b.field_array_of_objects("degraded", °raded, build_aggregated_degradation);
b.finish()
}
/// Render binary version and build provenance as TOON.
#[must_use]
pub fn render_version_toon(report: &VersionReport) -> String {
render_toon_from_json(&render_version_json(report))
}
/// Render `ee install check` as JSON (`ee.response.v2` envelope).
#[must_use]
pub fn render_install_check_json(report: &InstallCheckReport) -> String {
render_serialized_report_response(report, "InstallCheckReport")
}
#[must_use]
pub fn render_install_check_human(report: &InstallCheckReport) -> String {
let mut output = format!(
"ee install check ({})\n\nStatus: {}\nTarget: {}\nInstall path: {}\n",
report.version,
report.status().as_str(),
report.target.target_triple,
report.target.install_path
);
output.push_str(&format!("PATH: {}\n", report.path.status.as_str()));
for finding in &report.findings {
output.push_str(&format!(
"- {}: {} Next: {}\n",
finding.code, finding.message, finding.next_action
));
}
output
}
#[must_use]
pub fn render_install_check_toon(report: &InstallCheckReport) -> String {
render_toon_from_json(&render_install_check_json(report))
}
/// Render install/update dry-run plans as JSON (`ee.response.v2` envelope).
#[must_use]
pub fn render_install_plan_json(report: &InstallPlanReport) -> String {
render_serialized_report_response(report, "InstallPlanReport")
}
pub fn render_toolchain_provenance_json(
report: &crate::core::support_bundle::ToolchainProvenanceReport,
) -> String {
render_serialized_report_response(report, "ToolchainProvenanceReport")
}
#[must_use]
pub fn render_store_integrity_json(report: &StoreIntegrityReport) -> String {
render_serialized_report_response(report, "StoreIntegrityReport")
}
#[must_use]
pub fn render_store_integrity_toon(report: &StoreIntegrityReport) -> String {
render_toon_from_json(&render_store_integrity_json(report))
}
#[must_use]
pub fn render_store_integrity_human(report: &StoreIntegrityReport) -> String {
let mut output = String::new();
output.push_str(&format!(
"Store integrity: {}\n",
store_integrity_status_label(report.status)
));
output.push_str(&format!(
"Read fence: mode={} verdict={} severity={} workspace_generation={} strict_failed={}\n",
report.read_fence.mode,
report.read_fence.verdict,
report.read_fence.severity,
report.read_fence.workspace_generation,
report.read_fence.strict_failed
));
for asset in &report.read_fence.stale_assets {
output.push_str(&format!(
"- stale asset {}: generation={} lag={}\n",
asset.name, asset.generation, asset.lag
));
}
output.push_str(&format!(
"Write immune: sources={} quarantined={} observations={} advisory_only={} global_write_stall={}\n",
report.write_immune.source_count,
report.write_immune.quarantined_source_count,
report.write_immune.observation_count,
report.write_immune.advisory_only,
report.write_immune.global_write_stall
));
for decision in &report.write_immune.decisions {
output.push_str(&format!(
"- source {}: action={} writes={} reasons={}\n",
decision.source_id,
decision.action,
decision.write_count,
decision
.reasons
.iter()
.map(|reason| reason.code)
.collect::<Vec<_>>()
.join(",")
));
}
output
}
fn store_integrity_status_label(status: StoreIntegrityStatus) -> &'static str {
match status {
StoreIntegrityStatus::Ok => "ok",
StoreIntegrityStatus::Degraded => "degraded",
StoreIntegrityStatus::Blocked => "blocked",
}
}
fn render_serialized_report_json<T>(report: &T, report_name: &str) -> String
where
T: Serialize,
{
match serde_json::to_string(report) {
Ok(raw) => raw,
Err(error) => serialization_failure_error_json(report_name, &error),
}
}
fn render_serialized_report_response<T>(report: &T, report_name: &str) -> String
where
T: Serialize,
{
match serde_json::to_string(report) {
Ok(raw) => ResponseEnvelope::success().data_raw(&raw).finish(),
Err(error) => serialization_failure_error_json(report_name, &error),
}
}
fn serialization_failure_error_json(report_name: &str, error: &serde_json::Error) -> String {
let mut envelope = JsonBuilder::with_capacity(384);
envelope.field_str("schema", ERROR_SCHEMA_V2);
envelope.field_object("error", |obj| {
obj.field_str("code", "serialization_failed");
obj.field_str(
"message",
&format!("Failed to serialize {report_name} as JSON."),
);
obj.field_str("severity", "high");
obj.field_str(
"repair",
"Fix the report serializer; refusing to emit an empty object.",
);
obj.field_object("details", |details| {
details.field_str("report", report_name);
details.field_str("serializerError", &error.to_string());
});
});
envelope.finish()
}
#[must_use]
pub fn render_install_plan_human(report: &InstallPlanReport) -> String {
let mut output = format!(
"ee {} plan ({})\n\nStatus: {}\nTarget: {}\nInstall path: {}\n",
report.operation.as_str(),
report.version,
report.status.as_str(),
report.target.target_triple,
report.target.install_path
);
if let Some(version) = &report.target_version {
output.push_str(&format!("Target version: {version}\n"));
}
if let Some(artifact) = &report.artifact {
output.push_str(&format!("Artifact: {}\n", artifact.file_name));
}
for finding in &report.findings {
output.push_str(&format!(
"- {}: {} Next: {}\n",
finding.code, finding.message, finding.next_action
));
}
output
}
#[must_use]
pub fn render_install_plan_toon(report: &InstallPlanReport) -> String {
render_toon_from_json(&render_install_plan_json(report))
}
fn field_optional_str(builder: &mut JsonBuilder, key: &str, value: Option<&str>) {
match value {
Some(value) => builder.field_str(key, value),
None => builder.field_raw(key, "null"),
};
}
fn field_optional_path(builder: &mut JsonBuilder, key: &str, value: Option<&std::path::Path>) {
match value {
Some(value) => builder.field_str(key, value.to_string_lossy().as_ref()),
None => builder.field_raw(key, "null"),
};
}
fn field_optional_bool(builder: &mut JsonBuilder, key: &str, value: Option<bool>) {
match value {
Some(value) => builder.field_bool(key, value),
None => builder.field_raw(key, "null"),
};
}
fn field_optional_u64(builder: &mut JsonBuilder, key: &str, value: Option<u64>) {
match value {
Some(value) => builder.field_raw(key, &value.to_string()),
None => builder.field_raw(key, "null"),
};
}
fn source_state(report: &VersionReport) -> &'static str {
match report.build.git_dirty {
Some(true) => "dirty",
Some(false) => "clean",
None if report.build.git_commit.is_some() || report.build.git_tag.is_some() => "unknown",
None => "unavailable",
}
}
/// Render a capabilities report as JSON (ee.response.v2 envelope).
#[must_use]
pub fn render_capabilities_json(report: &CapabilitiesReport) -> String {
let mut b = JsonBuilder::with_capacity(1024);
b.field_str("schema", RESPONSE_SCHEMA_V2);
b.field_bool("success", true);
b.field_object("data", |d| {
d.field_str("command", "capabilities");
d.field_str("version", report.version);
d.field_array_of_objects("subsystems", &report.subsystems, |obj, sub| {
obj.field_str("name", sub.name);
obj.field_str("status", sub.status.as_str());
obj.field_str("description", sub.description);
});
d.field_array_of_objects("features", &report.features, |obj, feat| {
obj.field_str("name", feat.name);
obj.field_bool("enabled", feat.enabled);
obj.field_str("description", feat.description);
});
d.field_array_of_objects("unimplemented", &report.unimplemented, |obj, gap| {
obj.field_str("code", gap.code);
obj.field_str("featureFlag", gap.feature_flag);
obj.field_str("shipTarget", gap.ship_target);
obj.field_str("trackingBead", gap.tracking_bead);
obj.field_str("userMessage", gap.user_message);
});
d.field_array_of_objects("commands", &report.commands, |obj, cmd| {
obj.field_str("name", &cmd.name);
obj.field_bool("available", cmd.available);
obj.field_str("description", &cmd.description);
});
// Bead bd-17c65.6.4/F5 — discovered binaries and registry-backed
// EE_* environment overrides. Agents reading capabilities can
// determine which discovery source produced each binary, so
// error.recovery hints from F1 are reproducible / verifiable.
write_capabilities_binaries_block(d);
write_capabilities_env_overrides_block(d);
write_capabilities_index_block(d, report);
write_capabilities_output_metadata(d, report, true);
d.field_object("summary", |s| {
s.field_raw(
"readySubsystems",
&report.ready_subsystem_count().to_string(),
);
s.field_raw("totalSubsystems", &report.subsystems.len().to_string());
s.field_raw(
"enabledFeatures",
&report.enabled_feature_count().to_string(),
);
s.field_raw("totalFeatures", &report.features.len().to_string());
s.field_raw(
"unimplementedCapabilities",
&report.unimplemented_count().to_string(),
);
s.field_raw(
"availableCommands",
&report.available_command_count().to_string(),
);
s.field_raw("totalCommands", &report.commands.len().to_string());
});
});
b.field_raw("degraded", "[]");
b.finish()
}
fn write_capabilities_index_block(builder: &mut JsonBuilder, report: &CapabilitiesReport) {
builder.field_object("index", |index| {
match report.index.last_full_rebuild_at.as_deref() {
Some(timestamp) => index.field_str("last_full_rebuild_at", timestamp),
None => index.field_raw("last_full_rebuild_at", "null"),
};
match report.index.embedding.as_ref() {
Some(embedding) => index.field_raw("embedding", &embedding.data_json().to_string()),
None => index.field_raw("embedding", "null"),
};
});
}
/// Emit `binaries` capability block (F4).
///
/// Reports each external binary ee may discover. For each entry:
/// - `name`: stable identifier (e.g. "cass")
/// - `discoveredAt`: the absolute path resolved, or null
/// - `source`: which mechanism resolved it ("env_EE_CASS_BINARY",
/// "config", "PATH_allowlist", or "missing")
/// - `trusted`: whether the discovered path passed the safety
/// ownership / permission checks
///
/// Future recovery work can add `recovery[]` (matching F1) when
/// `discoveredAt` is null.
fn write_capabilities_binaries_block(builder: &mut JsonBuilder) {
builder.field_object("binaries", |bins| {
bins.field_object("cass", |cass| {
let discovery = crate::cass::discover_import_binary(None);
match discovery {
Ok(found) => {
cass.field_str("discoveredAt", &found.path.display().to_string());
cass.field_str("source", source_label(found.source));
cass.field_bool("trusted", true);
}
Err(error) => {
// Honest null + source = "missing" so an agent reading
// the response knows what's happening without parsing
// the error message.
cass.field_str("source", "missing");
cass.field_str("error", &error.to_string());
cass.field_bool("trusted", false);
}
}
});
});
}
/// Map a `DiscoverySource` to a stable wire-form string.
fn source_label(source: crate::cass::DiscoverySource) -> &'static str {
use crate::cass::DiscoverySource;
match source {
DiscoverySource::EnvVar => "env_EE_CASS_BINARY",
DiscoverySource::Config => "config_cass_binary",
DiscoverySource::Path => "trusted_allowlist",
}
}
/// Emit `envOverrides` capability block (F4).
///
/// Each entry lists an `EE_*` environment variable ee honors, what it
/// controls, and whether it's currently set.
fn write_capabilities_env_overrides_block(builder: &mut JsonBuilder) {
builder.field_array_of_objects("envOverrides", EnvVar::all(), |obj, var| {
let value = read_os(*var);
let is_set = value.is_some();
let default = var.default_value();
let source = if is_set {
"process_env"
} else if default.is_some() {
"registry_default"
} else {
"unset"
};
let current_value = if var.exposes_value() {
value.and_then(|value| value.into_string().ok())
} else {
None
};
obj.field_str("name", var.name());
obj.field_str("category", var.category());
obj.field_str("controls", var.description());
match default {
Some(default) => {
obj.field_str("defaultValue", default);
}
None => {
obj.field_raw("defaultValue", "null");
}
}
obj.field_bool("isSet", is_set);
obj.field_str("source", source);
if let Some(value) = current_value.as_deref() {
obj.field_str("currentValue", value);
}
});
}
fn write_capabilities_output_metadata(
builder: &mut JsonBuilder,
report: &CapabilitiesReport,
include_size_diagnostics: bool,
) {
builder.field_object("output", |output| {
output.field_array_of_objects("formats", &report.output_formats, |obj, format| {
obj.field_str("name", format.name);
obj.field_bool("available", format.available);
obj.field_bool("machineReadable", format.machine_readable);
obj.field_str("description", format.description);
});
output.field_object("toon", |toon| {
toon.field_bool("available", report.toon.available);
toon.field_str("canonicalSourceFormat", report.toon.canonical_source_format);
toon.field_object("dependency", |dependency| {
dependency.field_str("crate", report.toon.dependency.crate_name);
dependency.field_str("package", report.toon.dependency.package);
dependency.field_str("version", report.toon.dependency.version);
dependency.field_str("sourceKind", report.toon.dependency.source_kind);
dependency.field_str("path", report.toon.dependency.path);
dependency.field_bool("defaultFeatures", report.toon.dependency.default_features);
});
toon.field_array_of_strs(
"supportedOutputProfiles",
&report.toon.supported_output_profiles,
);
toon.field_str("defaultFormatEnv", report.toon.default_format_env);
toon.field_array_of_strs("errorCodes", &report.toon.error_codes);
});
// Output-token governor feature detection (ADR 0063 §4, bd-7lvbg.3):
// availability, the budget controls, and the per-schema truncation
// points so harnesses can predict which surfaces page and how to
// resume them.
output.field_object("governor", |governor_meta| {
governor_meta.field_bool("available", true);
governor_meta.field_str("ceilingFlag", "--max-output-tokens");
governor_meta.field_str("ceilingEnv", "EE_MAX_OUTPUT_TOKENS");
governor_meta.field_str("resumeFlag", "--cursor");
governor_meta.field_str("cursorSchema", governor::CURSOR_SCHEMA_V1);
governor_meta.field_array_of_strs(
"degradedCodes",
&[
governor::OUTPUT_TRUNCATED_BUDGET_CODE,
governor::OUTPUT_BUDGET_UNSATISFIABLE_CODE,
governor::CURSOR_STALE_CODE,
governor::CURSOR_INVALID_CODE,
],
);
governor_meta.field_array_of_objects(
"truncationPoints",
OUTPUT_TRUNCATION_REGISTRY,
|obj, point| {
obj.field_str("schemaId", point.schema_id);
obj.field_str("command", point.command);
obj.field_str("arrayPath", &format!("data.{}", point.array_path.join(".")));
obj.field_bool("perSectionItems", point.per_section_items);
obj.field_str("positionKeyField", point.position_key_field);
},
);
});
if include_size_diagnostics {
let diagnostics = compute_representative_size_diagnostics();
output.field_array_of_objects("sizeDiagnostics", &diagnostics, |obj, item| {
let (command, diagnostic) = item;
obj.field_str("command", command);
obj.field_raw("diagnostic", &diagnostic.to_json());
});
}
});
}
/// Render a capabilities report as human-readable text.
#[must_use]
pub fn render_capabilities_human(report: &CapabilitiesReport) -> String {
let mut output = format!("ee capabilities (v{})\n\n", report.version);
output.push_str("Subsystems:\n");
for sub in &report.subsystems {
let icon = match sub.status {
crate::models::CapabilityStatus::Ready => "✓",
crate::models::CapabilityStatus::Pending => "◐",
crate::models::CapabilityStatus::Degraded => "⚠",
crate::models::CapabilityStatus::Unimplemented => "○",
};
output.push_str(&format!(" {} {} — {}\n", icon, sub.name, sub.description));
}
output.push_str("\nFeatures:\n");
for feat in &report.features {
let icon = if feat.enabled { "✓" } else { "○" };
output.push_str(&format!(
" {} {} — {}\n",
icon, feat.name, feat.description
));
}
if !report.unimplemented.is_empty() {
output.push_str("\nUnimplemented capabilities:\n");
for gap in &report.unimplemented {
output.push_str(&format!(
" ○ {} ({}) — {}\n",
gap.code, gap.feature_flag, gap.user_message
));
}
}
output.push_str("\nIndex:\n");
match report.index.last_full_rebuild_at.as_deref() {
Some(timestamp) => {
output.push_str(&format!(" Last full rebuild: {timestamp}\n"));
}
None => output.push_str(" Last full rebuild: <not recorded>\n"),
}
match report.index.embedding.as_ref() {
Some(embedding) => output.push_str(&format!(
" Embedding mode: {} (semantic: {}, source: {})\n",
embedding.mode, embedding.semantic, embedding.source
)),
None => output.push_str(" Embedding mode: unavailable\n"),
}
output.push_str("\nCommands:\n");
for cmd in &report.commands {
let icon = if cmd.available { "✓" } else { "○" };
output.push_str(&format!(" {} {} — {}\n", icon, cmd.name, cmd.description));
}
output.push_str(&format!(
"\nSummary: {}/{} subsystems ready, {}/{} features enabled, {}/{} commands available\n",
report.ready_subsystem_count(),
report.subsystems.len(),
report.enabled_feature_count(),
report.features.len(),
report.available_command_count(),
report.commands.len()
));
output.push_str("\nNext:\n ee capabilities --json\n");
output
}
/// Render a capabilities report as TOON.
#[must_use]
pub fn render_capabilities_toon(report: &CapabilitiesReport) -> String {
render_toon_from_json(&render_capabilities_json(report))
}
/// Render evaluation run result as JSON (ee.response.v2 envelope).
#[must_use]
pub fn render_eval_run_json(report: &EvaluationReport, scenario_id: Option<&str>) -> String {
render_eval_report_json(report, scenario_id)
}
fn render_eval_science_metrics_json(
obj: &mut JsonBuilder,
metrics: &crate::eval::EvaluationScienceMetricsReport,
) {
obj.field_str("schema", metrics.schema);
obj.field_str("status", metrics.status.as_str());
obj.field_bool("available", metrics.available);
field_optional_str(obj, "degradationCode", metrics.degradation_code);
obj.field_raw(
"scenariosEvaluated",
&metrics.scenarios_evaluated.to_string(),
);
obj.field_str("positiveLabel", metrics.positive_label);
match metrics.precision {
Some(value) => obj.field_raw("precision", &format!("{value:.6}")),
None => obj.field_raw("precision", "null"),
};
match metrics.recall {
Some(value) => obj.field_raw("recall", &format!("{value:.6}")),
None => obj.field_raw("recall", "null"),
};
match metrics.f1_score {
Some(value) => obj.field_raw("f1Score", &format!("{value:.6}")),
None => obj.field_raw("f1Score", "null"),
};
}
/// Render evaluation report as JSON (ee.response.v2 envelope).
#[must_use]
pub fn render_eval_report_json(report: &EvaluationReport, scenario_id: Option<&str>) -> String {
let mut b = JsonBuilder::with_capacity(1024);
b.field_str("schema", RESPONSE_SCHEMA_V2);
b.field_bool("success", report.status.is_success());
b.field_object("data", |d| {
d.field_str("command", "eval run");
if let Some(id) = scenario_id {
d.field_str("scenarioId", id);
}
d.field_str("status", report.status.as_str());
d.field_raw("scenariosRun", &report.scenarios_run.to_string());
d.field_raw("scenariosPassed", &report.scenarios_passed.to_string());
d.field_raw("scenariosFailed", &report.scenarios_failed.to_string());
d.field_raw("elapsedMs", &format!("{:.2}", report.elapsed_ms));
if let Some(ref dir) = report.fixture_dir {
d.field_str("fixtureDir", dir);
}
if report.status == EvaluationStatus::NoScenarios {
d.field_str(
"message",
"No evaluation scenarios configured. Add fixtures to tests/fixtures/eval/.",
);
}
if let Some(ref metrics) = report.science_metrics {
d.field_object("scienceMetrics", |science| {
render_eval_science_metrics_json(science, metrics);
});
}
d.field_array_of_objects("results", &report.results, render_scenario_result_json);
});
b.field_raw("degraded", "[]");
b.finish()
}
fn render_scenario_result_json(obj: &mut JsonBuilder, result: &ScenarioValidationResult) {
obj.field_str("scenarioId", &result.scenario_id);
obj.field_bool("passed", result.passed);
obj.field_raw("stepsPassed", &result.steps_passed.to_string());
obj.field_raw("stepsTotal", &result.steps_total.to_string());
obj.field_array_of_objects("failures", &result.failures, |f, failure| {
f.field_raw("step", &failure.step.to_string());
f.field_str("kind", failure.kind.as_str());
f.field_str("message", &failure.message);
});
}
/// Render evaluation run result as human-readable text.
#[must_use]
pub fn render_eval_run_human(report: &EvaluationReport, scenario_id: Option<&str>) -> String {
render_eval_report_human(report, scenario_id)
}
/// Render evaluation report as human-readable text.
#[must_use]
pub fn render_eval_report_human(report: &EvaluationReport, scenario_id: Option<&str>) -> String {
let mut output = String::from("ee eval run\n\n");
if let Some(id) = scenario_id {
output.push_str(&format!("Scenario: {id}\n\n"));
}
let status_display = match report.status {
EvaluationStatus::NoScenarios => "no scenarios available",
EvaluationStatus::AllPassed => "all passed",
EvaluationStatus::SomeFailed => "some failed",
EvaluationStatus::AllFailed => "all failed",
};
output.push_str(&format!("Status: {status_display}\n"));
output.push_str(&format!(
"Results: {} run, {} passed, {} failed\n",
report.scenarios_run, report.scenarios_passed, report.scenarios_failed
));
output.push_str(&format!("Elapsed: {:.1}ms\n", report.elapsed_ms));
if let Some(ref dir) = report.fixture_dir {
output.push_str(&format!("Fixtures: {dir}\n"));
}
if report.status == EvaluationStatus::NoScenarios {
output.push_str("\nNo evaluation scenarios configured.\n");
output.push_str("Add fixtures to tests/fixtures/eval/ to define scenarios.\n");
} else {
output.push('\n');
for result in &report.results {
let icon = if result.passed { "[PASS]" } else { "[FAIL]" };
output.push_str(&format!(
"{icon} {}: {}/{} steps\n",
result.scenario_id, result.steps_passed, result.steps_total
));
for failure in &result.failures {
output.push_str(&format!(
" - Step {}: {} - {}\n",
failure.step,
failure.kind.as_str(),
failure.message
));
}
}
}
if let Some(metrics) = report.science_metrics.as_ref() {
output.push_str("\nScience metrics:\n");
output.push_str(&format!(" Status: {}\n", metrics.status.as_str()));
output.push_str(&format!(" Available: {}\n", metrics.available));
output.push_str(&format!(
" Scenarios evaluated: {}\n",
metrics.scenarios_evaluated
));
if let Some(code) = metrics.degradation_code {
output.push_str(&format!(" Degradation: {code}\n"));
}
output.push_str(&format!(" Positive label: {}\n", metrics.positive_label));
match metrics.precision {
Some(value) => output.push_str(&format!(" Precision: {value:.3}\n")),
None => output.push_str(" Precision: n/a\n"),
}
match metrics.recall {
Some(value) => output.push_str(&format!(" Recall: {value:.3}\n")),
None => output.push_str(" Recall: n/a\n"),
}
match metrics.f1_score {
Some(value) => output.push_str(&format!(" F1: {value:.3}\n")),
None => output.push_str(" F1: n/a\n"),
}
}
output
}
/// Render evaluation run result as TOON.
#[must_use]
pub fn render_eval_run_toon(report: &EvaluationReport, scenario_id: Option<&str>) -> String {
render_eval_report_toon(report, scenario_id)
}
/// Render evaluation report as TOON.
#[must_use]
pub fn render_eval_report_toon(report: &EvaluationReport, scenario_id: Option<&str>) -> String {
render_toon_from_json(&render_eval_report_json(report, scenario_id))
}
/// Render evaluation fixture list as JSON (ee.response.v2 envelope).
#[must_use]
pub fn render_eval_list_json(entries: &[FixtureListEntry], fixture_dir: Option<&str>) -> String {
let mut b = JsonBuilder::with_capacity(512);
b.field_str("schema", RESPONSE_SCHEMA_V2);
b.field_bool("success", true);
b.field_object("data", |d| {
d.field_str("command", "eval list");
d.field_array_of_objects("fixtures", entries, render_eval_fixture_list_entry_json);
d.field_raw("fixtureCount", &entries.len().to_string());
if let Some(dir) = fixture_dir {
d.field_str("fixtureDir", dir);
}
if entries.is_empty() {
d.field_str(
"message",
"No evaluation scenarios configured. Add fixtures to tests/fixtures/eval/.",
);
}
});
b.field_raw("degraded", "[]");
b.finish()
}
fn render_eval_fixture_list_entry_json(obj: &mut JsonBuilder, entry: &FixtureListEntry) {
obj.field_str("fixtureId", &entry.fixture_id);
obj.field_str("fixtureFamily", &entry.fixture_family);
obj.field_str("journey", &entry.journey);
obj.field_raw("memoryCount", &entry.memory_count.to_string());
obj.field_raw("queryCount", &entry.query_count.to_string());
obj.field_str("path", &entry.path);
}
/// Render evaluation fixture list as human-readable text.
#[must_use]
pub fn render_eval_list_human(entries: &[FixtureListEntry], fixture_dir: Option<&str>) -> String {
let mut output = String::from("ee eval list\n\n");
if let Some(dir) = fixture_dir {
let _ = writeln!(output, "Fixtures: {dir}");
output.push('\n');
}
if entries.is_empty() {
output.push_str("No evaluation scenarios configured.\n");
output.push_str("Add fixtures to tests/fixtures/eval/ to define scenarios.\n");
} else {
let _ = writeln!(output, "Available evaluation fixtures ({}):", entries.len());
for entry in entries {
output.push('\n');
let _ = writeln!(output, " {} ({})", entry.fixture_id, entry.fixture_family);
let _ = writeln!(output, " Journey: {}", entry.journey);
let _ = writeln!(
output,
" Memories: {}, Queries: {}",
entry.memory_count, entry.query_count
);
let _ = writeln!(output, " Path: {}", entry.path);
}
}
output
}
/// Render evaluation fixture list as TOON.
#[must_use]
pub fn render_eval_list_toon(entries: &[FixtureListEntry], fixture_dir: Option<&str>) -> String {
render_toon_from_json(&render_eval_list_json(entries, fixture_dir))
}
/// Public schema entry for the schema registry.
#[derive(Clone, Debug)]
pub struct SchemaEntry {
pub id: &'static str,
pub version: &'static str,
pub description: &'static str,
pub category: &'static str,
definition: fn() -> String,
}
/// All public schemas exposed by ee.
pub const fn public_schemas() -> &'static [SchemaEntry] {
&[
SchemaEntry {
id: "ee.response.v2",
version: "1",
description: "Success response envelope for all ee commands",
category: "envelope",
definition: response_schema_definition,
},
SchemaEntry {
id: ERROR_SCHEMA_V2,
version: "2",
description: "Error response envelope with structured recovery details",
category: "envelope",
definition: error_schema_definition,
},
SchemaEntry {
id: "ee.pack.v2",
version: "2",
description: "Context pack response envelope and canonical pack payload",
category: "context",
definition: pack_response_schema_definition,
},
SchemaEntry {
id: "ee.pack.replay.v2",
version: "2",
description: "Redaction-safe replay of an integrity-verified persisted pack ledger",
category: "context",
definition: pack_replay_schema_definition,
},
SchemaEntry {
id: "ee.pack.diff.v2",
version: "2",
description: "Authority-preserving comparison of two persisted pack ledgers",
category: "context",
definition: pack_diff_schema_definition,
},
SchemaEntry {
id: "ee.context.delta.v2",
version: "2",
description: "Context delta envelope with centrally verified persisted-pack authority",
category: "context",
definition: context_delta_schema_definition,
},
SchemaEntry {
id: "ee.support_bundle.pack_replay_summary.v2",
version: "2",
description: "Bounded redaction-safe pack replay summary for support bundles",
category: "support",
definition: support_bundle_pack_replay_summary_schema_definition,
},
SchemaEntry {
id: crate::models::REGRESSION_CAUSALITY_SCHEMA_V1,
version: "1",
description: "Redaction-safe regression causality capsule for failed gates",
category: "ops",
definition: regression_causality_schema_definition,
},
SchemaEntry {
id: PROOF_BROKER_SCHEMA_V1,
version: "1",
description: "Redaction-safe proof-broker fingerprint, ledger row, and admission \
decision contract",
category: "coordination",
definition: proof_broker_schema_definition,
},
SchemaEntry {
id: crate::models::QUERY_SCHEMA_V1,
version: "1",
description: "Structured query-file request document accepted by ee context and ee search",
category: "context",
definition: query_request_schema_definition,
},
SchemaEntry {
id: "ee.search.v1",
version: "1",
description: "Search response envelope and result payload",
category: "search",
definition: search_response_schema_definition,
},
SchemaEntry {
id: crate::models::schema::SEARCH_FAMILY_SCHEMA_V1,
version: "1",
description: "Queryless workspace-scoped retrieval of every admitted attempt-family member",
category: "search",
definition: search_family_schema_definition,
},
SchemaEntry {
id: crate::core::search::QUERY_ASSIST_SCHEMA_V1,
version: "1",
description: "Deterministic query-assist guidance for weak or empty search and ask results",
category: "search",
definition: query_assist_schema_definition,
},
SchemaEntry {
id: crate::core::learn::LEARN_GAPS_SCHEMA_V1,
version: "1",
description: "Query-miss demand clusters and remember templates for learning gaps",
category: "learn",
definition: learn_gaps_schema_definition,
},
SchemaEntry {
id: crate::core::memory_debt::MEMORY_DEBT_DOCTOR_SCHEMA_V1,
version: "1",
description: "Read-only memory-debt doctor report with ranked curation repairs",
category: "curation",
definition: memory_debt_doctor_schema_definition,
},
SchemaEntry {
id: crate::core::memory_debt::MEMORY_DEBT_TREND_SCHEMA_V1,
version: "1",
description: "Steward snapshot trend rows for memory-debt posture over time",
category: "curation",
definition: memory_debt_trend_schema_definition,
},
SchemaEntry {
id: "ee.memory.show.v1",
version: "1",
description: "Memory detail response envelope",
category: "memory",
definition: memory_show_schema_definition,
},
SchemaEntry {
id: "ee.memory.list.v1",
version: "1",
description: "Paged memory list response envelope",
category: "memory",
definition: memory_list_schema_definition,
},
SchemaEntry {
id: crate::models::memory::TYPED_MEMORY_FIELDS_SCHEMA_V2,
version: "2",
description: "Registry-backed typed sidecar fields for structured memories",
category: "memory",
definition: typed_memory_fields_schema_definition,
},
SchemaEntry {
id: "ee.status.v1",
version: "1",
description: "Status response envelope and health posture payload",
category: "ops",
definition: status_response_schema_definition,
},
SchemaEntry {
id: crate::models::SINGLEFLIGHT_POSTURE_SCHEMA_V1,
version: "1",
description: "Redaction-safe single-flight posture embedded in status reports",
category: "ops",
definition: singleflight_posture_schema_definition,
},
SchemaEntry {
id: crate::models::MESH_PEER_POLICY_SCHEMA_V1,
version: "1",
description: "Workspace-scoped mesh peer authorization and redaction policy",
category: "mesh",
definition: mesh_peer_policy_schema_definition,
},
SchemaEntry {
id: crate::models::MESH_POLICY_DECISION_SCHEMA_V1,
version: "1",
description: "Redaction-safe inbound and outbound mesh policy decision",
category: "mesh",
definition: mesh_policy_decision_schema_definition,
},
SchemaEntry {
id: crate::models::MESH_POLICY_FAILURE_SURFACE_SCHEMA_V1,
version: "1",
description: "Redaction-safe mesh policy denial, quarantine, and rejection surface",
category: "mesh",
definition: mesh_policy_failure_surface_schema_definition,
},
SchemaEntry {
id: crate::models::MESH_STORAGE_STATUS_SCHEMA_V1,
version: "1",
description: "Redaction-safe mesh storage posture embedded in status reports",
category: "mesh",
definition: mesh_storage_status_schema_definition,
},
SchemaEntry {
id: "ee.doctor.v1",
version: "1",
description: "Doctor diagnostics response envelope",
category: "ops",
definition: doctor_response_schema_definition,
},
SchemaEntry {
id: "ee.capabilities.v1",
version: "1",
description: "Capabilities response envelope and machine-readable feature catalog",
category: "ops",
definition: capabilities_response_schema_definition,
},
SchemaEntry {
id: crate::core::profile::HOST_PROFILE_PROBE_SCHEMA_V1,
version: "1",
description: "Read-only host resource, path, and RCH topology profile",
category: "ops",
definition: host_profile_schema_definition,
},
SchemaEntry {
id: "ee.rch.selector_admission_probe.v1",
version: "1",
description: "Read-only RCH selector/admission diagnostic block embedded in verification proofs",
category: "ops",
definition: rch_selector_admission_probe_schema_definition,
},
SchemaEntry {
id: "ee.resource_admission.v1",
version: "1",
description: "Side-effect-free advisory resource-profile admission decision for agent workloads",
category: "ops",
definition: resource_admission_schema_definition,
},
SchemaEntry {
id: crate::core::swarm_next_action::SWARM_NEXT_ACTION_SCHEMA_V1,
version: "1",
description: "Read-only swarm next-action input snapshot for agent work selection",
category: "coordination",
definition: swarm_next_action_schema_definition,
},
SchemaEntry {
id: crate::core::swarm_next_action::SWARM_REPAIR_PLAN_SCHEMA_V1,
version: "1",
description: "Read-only degraded-stack repair plan for swarm coordination blockers",
category: "coordination",
definition: swarm_repair_plan_schema_definition,
},
SchemaEntry {
id: crate::core::memory_drift::MEMORY_DRIFT_REPORT_SCHEMA_V1,
version: "1",
description: "Read-only memory provenance drift report and compact selection hints",
category: "memory",
definition: memory_drift_report_schema_definition,
},
SchemaEntry {
id: crate::models::IMPORT_CASS_SCHEMA_V1,
version: "1",
description: "CASS import response envelope",
category: "import",
definition: import_cass_response_schema_definition,
},
SchemaEntry {
id: "ee.export.v1",
version: "1",
description: "Export response envelope for JSONL backup/export reports",
category: "backup",
definition: export_response_schema_definition,
},
SchemaEntry {
id: crate::core::curate::CURATE_CANDIDATES_SCHEMA_V1,
version: "1",
description: "Curation candidate list response envelope",
category: "curate",
definition: curate_candidates_response_schema_definition,
},
SchemaEntry {
id: crate::core::curate::CAPTURE_SUGGESTIONS_SCHEMA_V1,
version: "1",
description: "Legacy ambient capture suggestions contract (superseded by v2 canonical provenance)",
category: "curate",
definition: capture_suggestions_v1_schema_definition,
},
SchemaEntry {
id: crate::core::curate::CAPTURE_SUGGESTIONS_SCHEMA_V2,
version: "2",
description: "Read-only ambient capture suggestions with canonical opaque provenance",
category: "curate",
definition: capture_suggestions_v2_schema_definition,
},
SchemaEntry {
id: crate::core::curate::CURATE_AUTO_PROMOTE_SCHEMA_V1,
version: "1",
description: "Threshold-driven memory level-transition proposals emitted by `ee curate auto-promote` (bd-2r8vp).",
category: "curate",
definition: curate_auto_promote_schema_definition,
},
SchemaEntry {
id: crate::core::curate::CURATE_SHOW_SCHEMA_V1,
version: "1",
description: "Read-only inspect/preview surface for a single curation candidate emitted by `ee curate show` (bd-3080b).",
category: "curate",
definition: curate_show_schema_definition,
},
SchemaEntry {
id: crate::core::docs_bootstrap::DOCS_BOOTSTRAP_RUN_SCHEMA_V1,
version: "1",
description: "Docs bootstrap dry-run payload with allowlisted sources, candidate proposals, parser version, and degraded source/quarantine signals.",
category: "curate",
definition: docs_bootstrap_run_schema_definition,
},
SchemaEntry {
id: crate::core::docs_bootstrap::DOCS_BOOTSTRAP_APPLY_SCHEMA_V1,
version: "1",
description: "Docs bootstrap curation apply payload with materialized, approved, skipped, blocked, and durable-mutation counts.",
category: "curate",
definition: docs_bootstrap_apply_schema_definition,
},
SchemaEntry {
id: "ee.diag.incident.replay.v1",
version: "1",
description: "Deterministic swarm-incident replay envelope emitted by `ee diag incident --fixture ... --json` (bd-3tend).",
category: "ops",
definition: diag_incident_replay_schema_definition,
},
SchemaEntry {
id: crate::curate::REFLECTION_SOURCE_PACKAGE_SCHEMA,
version: "1",
description: "Redacted and bounded source package for reflection request artifacts",
category: "reflect",
definition: reflection_source_package_schema_definition,
},
SchemaEntry {
id: crate::curate::REFLECTION_REQUEST_SCHEMA,
version: "1",
description: "Canonical no-LLM reflection request artifact",
category: "reflect",
definition: reflection_request_schema_definition,
},
SchemaEntry {
id: crate::curate::REFLECTION_CHALLENGE_BINDING_SCHEMA,
version: "1",
description: "Non-secret HMAC challenge binding payload for reflection requests",
category: "reflect",
definition: reflection_challenge_binding_schema_definition,
},
SchemaEntry {
id: crate::curate::REFLECTION_RESULT_SCHEMA,
version: "1",
description: "External no-LLM reflection result artifact",
category: "reflect",
definition: reflection_result_schema_definition,
},
SchemaEntry {
id: crate::core::curate::REFLECTION_PROPOSE_SCHEMA_V1,
version: "1",
description: "Reflect propose data report with request artifact and ledger outcome",
category: "reflect",
definition: reflection_propose_schema_definition,
},
SchemaEntry {
id: crate::core::curate::REFLECTION_INGEST_SCHEMA_V1,
version: "1",
description: "Reflect ingest data report with candidate creation outcome",
category: "reflect",
definition: reflection_ingest_schema_definition,
},
SchemaEntry {
id: crate::core::curate::REFLECTION_REQUEST_LEDGER_DIAGNOSTICS_SCHEMA_V1,
version: "1",
description: "Read-only reflection request ledger diagnostics report",
category: "reflect",
definition: reflection_request_ledger_diagnostics_schema_definition,
},
SchemaEntry {
id: crate::graph::GRAPH_EXPORT_SCHEMA_V1,
version: "1",
description: "Graph export response envelope",
category: "graph",
definition: graph_export_response_schema_definition,
},
SchemaEntry {
id: "ee.graph.diff.v1",
version: "1",
description: "Temporal structural diff between two persisted graph snapshots: content-hash-keyed add/remove sets, fingerprint-matched community deltas, persisted-centrality movers (ADR 0066).",
category: "graph",
definition: graph_diff_schema_definition,
},
SchemaEntry {
id: "ee.graph.snapshot_prune.v1",
version: "1",
description: "Graph snapshot archived-row prune report",
category: "graph",
definition: graph_snapshot_prune_schema_definition,
},
SchemaEntry {
id: "ee.graph.suggest_links.v1",
version: "1",
description: "Typed link-prediction report for ee graph suggest-links: bounded candidates, blended fnx-backed signals with raw per-signal values, and curation-candidate emission via --propose.",
category: "graph",
definition: graph_suggest_links_schema_definition,
},
SchemaEntry {
id: crate::core::witness_retention::WITNESS_PRUNE_REPORT_SCHEMA_V1,
version: "1",
description: "Graph algorithm witness prune report",
category: "graph",
definition: graph_witness_prune_schema_definition,
},
SchemaEntry {
id: "ee.db.inspect.v1",
version: "1",
description: "Read-only database inspection response envelope",
category: "ops",
definition: db_inspect_schema_definition,
},
SchemaEntry {
id: crate::core::workspace::WORKSPACE_HYGIENE_SCHEMA_V1,
version: "1",
description: "Read-only workspace hygiene and commit-readiness response envelope",
category: "ops",
definition: workspace_hygiene_schema_definition,
},
SchemaEntry {
id: crate::core::completion_audit::COMPLETION_AUDIT_CHECKLIST_SCHEMA_V1,
version: "1",
description: "Objective-to-artifact completion audit checklist",
category: "handoff",
definition: completion_audit_checklist_schema_definition,
},
SchemaEntry {
id: crate::core::completion_audit::COMPLETION_AUDIT_REPORT_SCHEMA_V2,
version: "2",
description: "Completion audit report response envelope",
category: "handoff",
definition: completion_audit_report_schema_definition,
},
SchemaEntry {
id: crate::core::preflight::AGENT_OPERATING_CONTRACT_SCHEMA_V1,
version: "1",
description: "Read-only agent operating contract extracted from repository docs",
category: "preflight",
definition: agent_operating_contract_schema_definition,
},
SchemaEntry {
id: ENVIRONMENT_ATTESTATION_SCHEMA_V1,
version: "1",
description: "Read-only environment attestation and source-authority inventory",
category: "preflight",
definition: environment_attestation_schema_definition,
},
SchemaEntry {
id: CI_PROOF_LANE_SNAPSHOT_SCHEMA_V1,
version: "1",
description: "Read-only CI proof-lane queue, artifact freshness, and source-authority snapshot",
category: "ops",
definition: ci_proof_lane_snapshot_schema_definition,
},
SchemaEntry {
id: REMOTE_BUILD_ARTIFACT_MANIFEST_SCHEMA_V1,
version: "1",
description: "Source-bound build inputs, packaged bytes, and behavior probes for a remote ee artifact",
category: "verification",
definition: remote_build_artifact_manifest_schema_definition,
},
SchemaEntry {
id: REMOTE_BUILD_ARTIFACT_VERIFICATION_SCHEMA_V1,
version: "1",
description: "Consumer verification of a remote artifact manifest and downloaded packaged bytes",
category: "verification",
definition: remote_build_artifact_verification_schema_definition,
},
SchemaEntry {
id: MCP_MANIFEST_SCHEMA_V1,
version: "1",
description: "MCP adapter manifest generated from ee's public command and schema registries",
category: "adapter",
definition: mcp_manifest_schema_definition,
},
SchemaEntry {
id: "ee.certificate.v1",
version: "1",
description: "Certificate schemas for pack, curation, tail-risk, privacy-budget, and lifecycle",
category: "domain",
definition: certificate_schema_definition,
},
SchemaEntry {
id: "ee.executable_id_schemas.v1",
version: "1",
description: "Executable claim/evidence/policy/trace/demo ID schemas",
category: "id",
definition: crate::models::executable_id_schema_catalog_json,
},
SchemaEntry {
id: "ee.procedure.schemas.v1",
version: "1",
description: "Procedure, verification, export, and render-only skill capsule schemas",
category: "domain",
definition: crate::models::procedure_schema_catalog_json,
},
SchemaEntry {
id: "ee.economy.schemas.v1",
version: "1",
description: "Utility, attention-cost, reserve, debt, recommendation, report, and simulation schemas",
category: "domain",
definition: crate::models::economy_schema_catalog_json,
},
SchemaEntry {
id: "ee.learning.schemas.v1",
version: "1",
description: "Learning question, uncertainty, experiment, observation, and outcome schemas",
category: "domain",
definition: crate::models::learning_schema_catalog_json,
},
SchemaEntry {
id: RULE_ADD_SCHEMA_V1,
version: "1",
description: "Procedural rule creation response data",
category: "domain",
definition: rule_add_schema_definition,
},
SchemaEntry {
id: RULE_LIST_SCHEMA_V1,
version: "1",
description: "Procedural rule list response data",
category: "domain",
definition: rule_list_schema_definition,
},
SchemaEntry {
id: RULE_SHOW_SCHEMA_V1,
version: "1",
description: "Procedural rule detail response data",
category: "domain",
definition: rule_show_schema_definition,
},
SchemaEntry {
id: RULE_MARK_SCHEMA_V1,
version: "1",
description: "Procedural rule lifecycle mark response data",
category: "domain",
definition: rule_mark_schema_definition,
},
SchemaEntry {
id: RULE_UPDATE_SCHEMA_V1,
version: "1",
description: "Procedural rule update response data",
category: "domain",
definition: rule_update_schema_definition,
},
SchemaEntry {
id: "ee.causal.schemas.v1",
version: "1",
description: "Causal exposure, decision trace, uplift, confounder, and promotion-plan schemas",
category: "domain",
definition: crate::models::causal_schema_catalog_json,
},
SchemaEntry {
id: crate::models::PERF_SCHEMA_CATALOG_V1,
version: "1",
description: "Performance artifact summaries and metric schemas for regression forensics",
category: "domain",
definition: crate::models::perf_schema_catalog_json,
},
SchemaEntry {
id: MAINTENANCE_RUN_SCHEMA_V1,
version: "1",
description: "Maintenance job run response data",
category: "ops",
definition: maintenance_run_schema_definition,
},
SchemaEntry {
id: MAINTENANCE_STATUS_SCHEMA_V1,
version: "1",
description: "Maintenance job availability and history status data",
category: "ops",
definition: maintenance_status_schema_definition,
},
SchemaEntry {
id: MAINTENANCE_JOB_LIST_SCHEMA_V1,
version: "1",
description: "Maintenance job history list response data",
category: "ops",
definition: maintenance_job_list_schema_definition,
},
SchemaEntry {
id: MAINTENANCE_JOB_SHOW_SCHEMA_V1,
version: "1",
description: "Maintenance job history detail response data",
category: "ops",
definition: maintenance_job_show_schema_definition,
},
SchemaEntry {
id: MAINTENANCE_JOB_ROW_SCHEMA_V1,
version: "1",
description: "Persisted maintenance job history row data",
category: "ops",
definition: maintenance_job_row_schema_definition,
},
SchemaEntry {
id: RECORDER_EVENTS_LIST_SCHEMA_V1,
version: "1",
description: "Recorder events list response data",
category: "recorder",
definition: recorder_events_list_schema_definition,
},
// ─── R-009 (Pass 2): public registry entries for schemas that existed
// in docs/schemas/ but were missing from `ee schema list --json`.
// Each entry uses `include_str!` to embed the schema JSON at
// compile time, the same pattern the original registry uses.
// Categories follow the existing taxonomy (envelope/context/
// memory/search/curate/graph/ops/mesh/coordination).
SchemaEntry {
id: "ee.agent_workload_replay.v1",
version: "1",
description: "Deterministic, side-effect-free replay summary derived from redacted ee.agent_workload_trace.v1 JSONL rows.",
category: "ops",
definition: agent_workload_replay_schema_definition,
},
SchemaEntry {
id: "ee.agent_workload_trace.v1",
version: "1",
description: "Redacted, local-only flight-recorder trace row for one agent-facing ee command invocation.",
category: "ops",
definition: agent_workload_trace_schema_definition,
},
SchemaEntry {
id: crate::core::lab::SWARM_WORKLOAD_SCHEMA_V1,
version: "1",
description: "Redaction-safe generated swarm workload consumed by the lab replay runner.",
category: "lab",
definition: swarm_workload_schema_definition,
},
SchemaEntry {
id: crate::core::lab::SWARM_REPLAY_RESULT_SCHEMA_V1,
version: "1",
description: "Admission and execution ledger emitted by the swarm replay runner.",
category: "lab",
definition: swarm_replay_result_schema_definition,
},
SchemaEntry {
id: "ee.swarm_slo.scorecard.v1",
version: "1",
description: "Replayable, redaction-safe SLO scorecard for multi-agent ee workflows.",
category: "ops",
definition: swarm_slo_scorecard_schema_definition,
},
SchemaEntry {
id: "ee.swarm_slo.resource_usage_event.v1",
version: "1",
description: "Redaction-safe per-stage resource-usage event consumed by swarm SLO attribution.",
category: "ops",
definition: swarm_slo_resource_usage_event_schema_definition,
},
SchemaEntry {
id: "ee.swarm_slo.coordination_event.v1",
version: "1",
description: "Redaction-safe coordination-source event consumed by swarm SLO attribution.",
category: "ops",
definition: swarm_slo_coordination_event_schema_definition,
},
SchemaEntry {
id: "ee.audit_lane.v1",
version: "1",
description: "Structured audit-lane telemetry event emitted by the Swarm-X audit queue.",
category: "ops",
definition: audit_lane_schema_definition,
},
SchemaEntry {
id: "ee.cache.hotset.v1",
version: "1",
description: "Redaction-safe hotset manifest capturing frequent search and pack cache shapes for prewarm.",
category: "ops",
definition: cache_hotset_schema_definition,
},
SchemaEntry {
id: crate::models::CACHE_HOTSET_COLLECT_SCHEMA_V1,
version: "1",
description: "Bounded read-only hotset collector manifest with per-source freshness, provenance hashes, and explicit degraded posture.",
category: "ops",
definition: cache_hotset_collect_schema_definition,
},
SchemaEntry {
id: crate::models::HOTSET_MANIFEST_SCHEMA_V1,
version: "1",
description: "Read-only swarm hotset manifest contract for redaction-safe prewarm candidate planning.",
category: "ops",
definition: hotset_manifest_schema_definition,
},
SchemaEntry {
id: crate::models::SCALE_ENVELOPE_SCHEMA_V1,
version: "1",
description: "Redaction-safe scale-envelope posture covering corpus, store, WAL, index, SLO, degraded-code, and recovery-action evidence.",
category: "ops",
definition: scale_envelope_schema_definition,
},
SchemaEntry {
id: crate::models::WRITE_GROUP_COMMIT_SCHEMA_V1,
version: "1",
description: "Redaction-safe group-commit write-intake telemetry: batch, coalescing, fsync-saved, commit-latency, and fallback-reason counts.",
category: "performance",
definition: write_group_commit_schema_definition,
},
SchemaEntry {
id: crate::models::INDEX_INTAKE_SCHEMA_V1,
version: "1",
description: "Redaction-safe incremental index-intake telemetry: intake mode, document counts, rebuild-avoided savings, and fallback-to-full reason.",
category: "performance",
definition: index_intake_schema_definition,
},
SchemaEntry {
id: crate::models::EMBEDDING_POSTURE_SCHEMA_V1,
version: "1",
description: "Redaction-safe active embedding posture block: semantic mode, model ids, registry counts, and vector coverage.",
category: "search",
definition: embedding_posture_schema_definition,
},
SchemaEntry {
id: "ee.closeout_audit.v1",
version: "1",
description: "Closeout audit envelope emitted by scripts/closeout_audit.sh before marking a bead closed.",
category: "ops",
definition: closeout_audit_schema_definition,
},
SchemaEntry {
id: crate::models::FAILURE_MODE_FIXTURE_SCHEMA_V1,
version: "1",
description: "Failure-mode fixture catalog entry documenting one degraded response code.",
category: "ops",
definition: failure_mode_fixture_schema_definition,
},
SchemaEntry {
id: "ee.completion_audit.report.v1",
version: "1",
description: "Completion audit response envelope for read-only objective-to-evidence checks.",
category: "ops",
definition: completion_audit_report_schema_v1_definition,
},
SchemaEntry {
id: "ee.conflict.resolve.v1",
version: "1",
description: "Audited conflict-resolution plan/apply report for ee conflict resolve (ADR 0066): verb mapped onto existing audited atoms against the live conflict surface, dry-run default.",
category: "graph",
definition: conflict_resolve_schema_definition,
},
SchemaEntry {
id: "ee.context.agent_profile.v1",
version: "1",
description: "Agent-specific retrieval bias summary emitted by ee context --explain --json.",
category: "context",
definition: context_agent_profile_schema_definition,
},
SchemaEntry {
id: "ee.context.bead_affinity.v1",
version: "1",
description: "Bead-aware retrieval-bias summary emitted by ee context --explain --json (and ee why --json).",
category: "context",
definition: context_bead_affinity_schema_definition,
},
SchemaEntry {
id: "ee.context.budget.v1",
version: "1",
description: "Adaptive context-pack token budget decision and contribution breakdown for ee context explain output.",
category: "context",
definition: context_budget_schema_definition,
},
SchemaEntry {
id: "ee.context.pack_dna.v1",
version: "1",
description: "Graph-derived Pack DNA explanation block for context packs.",
category: "context",
definition: context_pack_dna_schema_definition,
},
SchemaEntry {
id: "ee.context.v1",
version: "1",
description: "Augmentation contract for ee context output with graph-derived ranking fields.",
category: "context",
definition: context_schema_definition,
},
SchemaEntry {
id: "ee.curate.disposition.v1",
version: "1",
description: "ee curate disposition response envelope (structuralAdjustments documents graph-derived retention changes).",
category: "curate",
definition: curate_disposition_schema_definition,
},
SchemaEntry {
id: "ee.curate.peer_evidence.v1",
version: "1",
description: "Curation candidate envelope informed by cached peer-origin evidence.",
category: "curate",
definition: curate_peer_evidence_schema_definition,
},
SchemaEntry {
id: "ee.diag.plan_cache.v1",
version: "1",
description: "Diagnostic response envelope for `ee diag plan-cache --json` (EQL query plan cache).",
category: "ops",
definition: diag_plan_cache_schema_definition,
},
SchemaEntry {
id: "ee.diag.contention.v1",
version: "1",
description: "Read-only contention diagnostic: aggregated write-lock, read-pool, single-flight, and cache posture with ranked top contention.",
category: "ops",
definition: diag_contention_schema_definition,
},
SchemaEntry {
id: "ee.disk_pressure.agent_harness_log_classifier.v1",
version: "1",
description: "Read-only per-file classification for oversized agent-harness logs found by ee diag disk-pressure.",
category: "ops",
definition: disk_pressure_agent_harness_log_classifier_schema_definition,
},
SchemaEntry {
id: "ee.graph.rule_provenance_ego.v1",
version: "1",
description: "Bipartite ego subgraph for a single procedural rule.",
category: "graph",
definition: graph_rule_provenance_ego_schema_definition,
},
SchemaEntry {
id: "ee.health.structural.v1",
version: "1",
description: "Structural health report using graph-derived coherence signals.",
category: "ops",
definition: health_structural_schema_definition,
},
SchemaEntry {
id: crate::core::health::HEALTH_SCORECARD_SCHEMA_V1,
version: "1",
description: "Trend-aware memory-health scorecard combining coverage, freshness, trust, redundancy, and graph signals.",
category: "ops",
definition: health_scorecard_schema_definition,
},
SchemaEntry {
id: "ee.hooks.git_readiness.v1",
version: "1",
description: "Read-only diagnostic report for local Git hook-chain readiness before agent commits and pushes.",
category: "ops",
definition: hooks_git_readiness_schema_definition,
},
SchemaEntry {
id: "ee.hook.harness_install.v1",
version: "1",
description: "Agent-harness hook generation/install plan for memory recall, orientation, journaling, and capture.",
category: "ops",
definition: hook_harness_install_schema_definition,
},
SchemaEntry {
id: crate::models::AMBIENT_CONTEXT_SCHEMA_V1,
version: "1",
description: "On-by-default proactive ambient hook profile for session orientation and pre-edit memory recall.",
category: "ops",
definition: ambient_context_schema_definition,
},
SchemaEntry {
id: crate::hooks::HARNESS_CONFORMANCE_SCHEMA_V1,
version: "1",
description: "Redaction-safe harness conformance fixture contract for hook-event and transcript simulation. ADR 0075.",
category: "ops",
definition: harness_conformance_schema_definition,
},
SchemaEntry {
id: "ee.host_calibration.host_class.v1",
version: "1",
description: "Pure host-class classification derived from a caller-provided host profile probe.",
category: "ops",
definition: host_calibration_host_class_schema_definition,
},
SchemaEntry {
id: "ee.host_calibration.recommendation.v1",
version: "1",
description: "Deterministic, redaction-safe host calibration recommendation for operating profile and budget deltas.",
category: "ops",
definition: host_calibration_recommendation_schema_definition,
},
SchemaEntry {
id: "ee.host_calibration.posture.v1",
version: "1",
description: "Redaction-safe host calibration posture embedded in status, doctor, and support bundles.",
category: "ops",
definition: host_calibration_posture_schema_definition,
},
SchemaEntry {
id: "ee.insights.v1",
version: "1",
description: "Insights bundle response data for graph-accretion findings.",
category: "graph",
definition: insights_schema_definition,
},
SchemaEntry {
id: "ee.memory_drift.queue.v1",
version: "1",
description: "Deterministic, read-only queue of memories whose source provenance snapshots need explicit revalidation.",
category: "memory",
definition: memory_drift_queue_schema_definition,
},
SchemaEntry {
id: "ee.memory_drift.snapshot.v1",
version: "1",
description: "Compact provenance snapshot for read-only memory drift checks.",
category: "memory",
definition: memory_drift_snapshot_schema_definition,
},
SchemaEntry {
id: "ee.memory.delta.v1",
version: "1",
description: "Eidetic Engine memory delta — append-only change record for one memory.",
category: "memory",
definition: memory_delta_schema_definition,
},
SchemaEntry {
id: "ee.memory.impact_analysis.v1",
version: "1",
description: "Impact analysis for memory revision and dominance-frontier planning.",
category: "memory",
definition: memory_impact_analysis_schema_definition,
},
SchemaEntry {
id: "ee.mesh.anti_entropy.v1",
version: "1",
description: "Redaction-safe sync summary for mesh anti-entropy rounds.",
category: "mesh",
definition: mesh_anti_entropy_schema_definition,
},
SchemaEntry {
id: "ee.mesh.approval_token.v1",
version: "1",
description: "Sensitive short-lived bearer projection for an explicitly issued mesh lane-approval token.",
category: "mesh",
definition: mesh_approval_token_schema_definition,
},
SchemaEntry {
id: "ee.mesh.auto_enrollment_result.v1",
version: "1",
description: "Auto-enrollment apply / dry-run result envelope.",
category: "mesh",
definition: mesh_auto_enrollment_result_schema_definition,
},
SchemaEntry {
id: "ee.mesh.auto_enrollment_summary.v1",
version: "1",
description: "Forensic audit-row payload emitted by SRR6.46.5 before any durable auto-enrollment write.",
category: "mesh",
definition: mesh_auto_enrollment_summary_schema_definition,
},
SchemaEntry {
id: "ee.mesh.auto_status.v2",
version: "2",
description: "Read-only auto-enrollment posture with explicit liveness observation state, emitted by `ee mesh status --json`.",
category: "mesh",
definition: mesh_auto_status_schema_definition,
},
SchemaEntry {
id: "ee.mesh.disable_result.v1",
version: "1",
description: "Result envelope for `ee mesh disable [--reason \"...\"] [--dry-run] [--json]`.",
category: "ops",
definition: mesh_disable_result_schema_definition,
},
SchemaEntry {
id: "ee.mesh.discovery_policy.v1",
version: "1",
description: "Per-peer discovery policy posture emitted by `ee mesh discovery-policy --json`.",
category: "mesh",
definition: mesh_discovery_policy_schema_definition,
},
SchemaEntry {
id: "ee.mesh.event.v1",
version: "1",
description: "Append-only optional mesh memory event envelope for deterministic export and replay.",
category: "mesh",
definition: mesh_event_schema_definition,
},
SchemaEntry {
id: "ee.mesh.grant.v1",
version: "1",
description: "Audited generation-advancing result for `ee mesh grant <peer-id> --lane <lane>`.",
category: "mesh",
definition: mesh_grant_schema_definition,
},
SchemaEntry {
id: "ee.mesh.hello_responder.status.v1",
version: "1",
description: "Hello-handshake responder status report.",
category: "mesh",
definition: mesh_hello_responder_status_schema_definition,
},
SchemaEntry {
id: "ee.mesh.hello.error.v1",
version: "1",
description: "Hello-handshake decline response (no responder-side metadata leakage).",
category: "mesh",
definition: mesh_hello_error_schema_definition,
},
SchemaEntry {
id: "ee.mesh.hello.response.v1",
version: "1",
description: "Hello-handshake success response emitted by the SRR6.46.12 responder.",
category: "mesh",
definition: mesh_hello_response_schema_definition,
},
SchemaEntry {
id: "ee.mesh.hello.v1",
version: "1",
description: "Tiny bounded handshake request that SRR6.46.2 autodiscovery sends to candidate peers.",
category: "mesh",
definition: mesh_hello_schema_definition,
},
SchemaEntry {
id: "ee.mesh.import_ledger.v1",
version: "1",
description: "Redaction-safe receiver-local mesh import chain and policy-decision ledger.",
category: "mesh",
definition: mesh_import_ledger_schema_definition,
},
SchemaEntry {
id: "ee.mesh.lane_grant_preview.v2",
version: "2",
description: "Canonical authenticated lane-grant snapshot emitted by `ee mesh preview-grant <peer-id> --lane <lane>`.",
category: "mesh",
definition: mesh_lane_grant_preview_schema_definition,
},
SchemaEntry {
id: "ee.mesh.peer_group_binding.v1",
version: "1",
description: "Workspace-scoped peer-group binding for optional mesh memory authorization.",
category: "mesh",
definition: mesh_peer_group_binding_schema_definition,
},
SchemaEntry {
id: "ee.mesh.revoke_lane.v1",
version: "1",
description: "Audited generation-advancing result for `ee mesh revoke-lane <peer-id> --lane <lane>`.",
category: "mesh",
definition: mesh_revoke_lane_schema_definition,
},
SchemaEntry {
id: "ee.mesh.revoke_result.v1",
version: "1",
description: "Result envelope for `ee mesh revoke <node-key>`.",
category: "ops",
definition: mesh_revoke_result_schema_definition,
},
SchemaEntry {
id: crate::models::schema::MESH_SESSION_CAPABILITY_NEGOTIATION_SCHEMA_V1,
version: "1",
description: "Authenticated mesh session capability offer and selection payload.",
category: "mesh",
definition: mesh_session_capability_negotiation_schema_definition,
},
SchemaEntry {
id: crate::models::schema::MESH_SESSION_CONFIRM_SCHEMA_V1,
version: "1",
description: "Responder confirmation for a fresh authenticated mesh session.",
category: "mesh",
definition: mesh_session_confirm_schema_definition,
},
SchemaEntry {
id: crate::models::schema::MESH_SESSION_FINISH_SCHEMA_V1,
version: "1",
description: "Initiator finish message for a mutually authenticated mesh session.",
category: "mesh",
definition: mesh_session_finish_schema_definition,
},
SchemaEntry {
id: crate::models::schema::MESH_SESSION_OPEN_SCHEMA_V1,
version: "1",
description: "Fresh-nonce mesh session open bound to team, tailnet, endpoints, and workspaces.",
category: "mesh",
definition: mesh_session_open_schema_definition,
},
SchemaEntry {
id: "ee.mesh.surrogate.v1",
version: "1",
description: "Compatibility, privacy, and rebuild metadata for a single search surrogate (embedding, summary, minhash, lexical).",
category: "ops",
definition: mesh_surrogate_schema_definition,
},
SchemaEntry {
id: crate::models::schema::MESH_TAILSCALE_TRANSPORT_FRAME_SCHEMA_V2,
version: "2",
description: "Replay-safe directional mesh transport frame authenticated under fresh session keys.",
category: "mesh",
definition: mesh_tailscale_transport_frame_schema_definition,
},
SchemaEntry {
id: "ee.migration.shard_fanout.v1",
version: "1",
description: "Structured audit event for per-workspace shard fan-out migration planning, apply, rollback, and verification.",
category: "ops",
definition: migration_shard_fanout_schema_definition,
},
SchemaEntry {
id: "ee.pack.revision_token.v1",
version: "1",
description: "Explicit revisable-pack token metadata emitted only when mesh revisable mode is requested.",
category: "context",
definition: pack_revision_token_schema_definition,
},
SchemaEntry {
id: "ee.pack.stream.v1",
version: "1",
description: "NDJSON frame contract for ee context --stream. Each line is exactly one frame object.",
category: "context",
definition: pack_stream_schema_definition,
},
SchemaEntry {
id: "ee.peer_conflict.v1",
version: "1",
description: "Structured event row emitted by the SRR6.37 peer duplicate / contradiction surfacer.",
category: "coordination",
definition: peer_conflict_schema_definition,
},
SchemaEntry {
id: "ee.perf.live.v1",
version: "1",
description: "Read-only live performance snapshot for swarm observability.",
category: "ops",
definition: perf_live_schema_definition,
},
SchemaEntry {
id: crate::daemon::protocol::DAEMON_SEARCH_REQUEST_SCHEMA_V2,
version: "2",
description: "Strict method-specific daemon search request with optional canonical performance diagnostics.",
category: "ops",
definition: daemon_search_request_schema_definition,
},
SchemaEntry {
id: crate::daemon::protocol::DAEMON_ORIENT_HOOK_REQUEST_SCHEMA_V1,
version: "1",
description: "Bounded workspace daemon SessionStart context request.",
category: "ops",
definition: || {
include_str!("../../docs/schemas/ee.daemon.orient_hook.request.v1.json").to_owned()
},
},
SchemaEntry {
id: crate::daemon::protocol::DAEMON_RECALL_REQUEST_SCHEMA_V1,
version: "1",
description: "Workspace daemon anchored recall request.",
category: "ops",
definition: || {
include_str!("../../docs/schemas/ee.daemon.recall.request.v1.json").to_owned()
},
},
SchemaEntry {
id: crate::daemon::protocol::DAEMON_MEMORY_READ_RESPONSE_SCHEMA_V1,
version: "1",
description: "Canonical orientation or recall response served by the workspace daemon.",
category: "ops",
definition: || {
include_str!("../../docs/schemas/ee.daemon.memory_read.response.v1.json").to_owned()
},
},
SchemaEntry {
id: crate::daemon::protocol::DAEMON_SEARCH_RESPONSE_SCHEMA_V3,
version: "3",
description: "Strict daemon search result with optional ee.explain.performance.v1 payload.",
category: "ops",
definition: daemon_search_response_schema_definition,
},
SchemaEntry {
id: "ee.prompt_budget_report.v1",
version: "1",
description: "Read-only prompt-budget bookkeeping report.",
category: "ops",
definition: prompt_budget_report_schema_definition,
},
SchemaEntry {
id: "ee.proof_check.v1",
version: "1",
description: "Machine-readable proof verification report (missing Lean4/TLC tooling reported as degraded).",
category: "ops",
definition: proof_check_schema_definition,
},
SchemaEntry {
id: "ee.proximity.v1",
version: "1",
description: "Pairwise memory proximity report derived from graph min-cut structures.",
category: "graph",
definition: proximity_schema_definition,
},
SchemaEntry {
id: "ee.repair_action_graph.v1",
version: "1",
description: "Structured graph of repair actions emitted by `ee mesh status` and `ee doctor`.",
category: "ops",
definition: repair_action_graph_schema_definition,
},
SchemaEntry {
id: crate::models::ORIENT_SCHEMA_V1,
version: "1",
description: "Read-only agent-orientation bundle with workspace, retrieval, health, decision, revival, and nearby-store posture.",
category: "context",
definition: orient_schema_definition,
},
SchemaEntry {
id: "ee.resume.v1",
version: "1",
description: "Session-resume bundle for ee resume: recent episodic sessions, revisit-conditioned decisions, queued-tag items, staleness flags, nearby stores.",
category: "memory",
definition: resume_schema_definition,
},
SchemaEntry {
id: "ee.search.revision_token.v1",
version: "1",
description: "Explicit revisable-search token metadata emitted only when mesh revisable mode is requested.",
category: "search",
definition: search_revision_token_schema_definition,
},
SchemaEntry {
id: "ee.search.score_interval.v1",
version: "1",
description: "Closed split-conformal relevance score interval emitted on each ee search result.",
category: "search",
definition: search_score_interval_schema_definition,
},
SchemaEntry {
id: "ee.search.score_calibration.v1",
version: "1",
description: "Workspace-level scaled split-conformal calibration metadata emitted under metadata.scoreCalibration on ee search responses.",
category: "search",
definition: search_score_calibration_schema_definition,
},
SchemaEntry {
id: "ee.singleflight.key.v1",
version: "1",
description: "Redaction-safe canonical key for coalescing duplicate in-process read-heavy ee commands.",
category: "ops",
definition: singleflight_key_schema_definition,
},
SchemaEntry {
id: "ee.spec_pack.v1",
version: "1",
description: "Telemetry event row for the swarmx.spec-pack speculative context pre-assembly driver.",
category: "context",
definition: spec_pack_schema_definition,
},
SchemaEntry {
id: "ee.status.graph.numa_pin.v1",
version: "1",
description: "NUMA-aware graph snapshot pinning posture surfaced under `ee status --json` at `data.graph.numaPin`.",
category: "ops",
definition: status_graph_numa_pin_schema_definition,
},
SchemaEntry {
id: "ee.status.search.lexical_ram_tier.v1",
version: "1",
description: "Lexical posting-list RAM-tier pinning posture surfaced under `ee status --json`.",
category: "ops",
definition: status_search_lexical_ram_tier_schema_definition,
},
SchemaEntry {
id: "ee.status.skyline.v1",
version: "1",
description: "Knowledge skyline block for ee status graph-accretion output.",
category: "ops",
definition: status_skyline_schema_definition,
},
SchemaEntry {
id: "ee.symbol_evidence_links.v1",
version: "1",
description: "Read-only derived links from memories, CASS evidence, failures, rules, and decisions to stable code symbols.",
category: "context",
definition: symbol_evidence_links_schema_definition,
},
SchemaEntry {
id: "ee.symbol_snapshot.v1",
version: "1",
description: "Read-only derived symbol snapshot for Rust source files.",
category: "context",
definition: symbol_snapshot_schema_definition,
},
SchemaEntry {
id: "ee.tailscale.autodiscovery.v1",
version: "1",
description: "Tailscale autodiscovery candidate peer list surface.",
category: "mesh",
definition: tailscale_autodiscovery_schema_definition,
},
SchemaEntry {
id: "ee.tailscale.local.v1",
version: "1",
description: "Local Tailscale identity and status surface.",
category: "mesh",
definition: tailscale_local_schema_definition,
},
SchemaEntry {
id: "ee.verification_evidence.v1",
version: "1",
description: "Normalized verification-evidence envelope ingesting heterogeneous proof artifacts.",
category: "ops",
definition: verification_evidence_schema_definition,
},
SchemaEntry {
id: "ee.why_not_selected.v1",
version: "1",
description: "Explanation block emitted by `ee why --json` for memories the retrieval considered but did not select.",
category: "context",
definition: why_not_selected_schema_definition,
},
SchemaEntry {
id: "ee.why.causal.v1",
version: "1",
description: "Causal explanation block for ee why graph-accretion output.",
category: "context",
definition: why_causal_schema_definition,
},
SchemaEntry {
id: crate::core::conformal::WHY_CONFORMAL_CONFIDENCE_INTERVALS_SCHEMA_V1,
version: "1",
description: "Split-conformal confidence interval and prediction-set block emitted by ee why.",
category: "context",
definition: why_conformal_prediction_set_schema_definition,
},
SchemaEntry {
id: crate::core::influence::WHY_COUNTERFACTUAL_INFLUENCE_SCHEMA_V1,
version: "1",
description: "Leave-one-out influence attribution block emitted by ee why.",
category: "context",
definition: why_influence_schema_definition,
},
SchemaEntry {
id: "ee.why.v1",
version: "1",
description: "Augmentation contract for ee why output with graph-derived explanation blocks.",
category: "context",
definition: why_schema_definition,
},
SchemaEntry {
id: crate::core::preflight_guard::PREFLIGHT_GUARD_SCHEMA_V1,
version: "1",
description: "Advisory command-risk memory returned by `ee preflight check --cmd \"<shell-command>\" --json`; it never blocks execution.",
category: "ops",
definition: preflight_guard_schema_definition,
},
SchemaEntry {
id: crate::core::journal::JOURNAL_ENTRY_SCHEMA_V1,
version: "1",
description: "Append-only, redaction-screened agent journal entry emitted by ee journal append/list/show.",
category: "memory",
definition: journal_entry_schema_definition,
},
SchemaEntry {
id: crate::core::journal::JOURNAL_DISTILL_SCHEMA_V1,
version: "1",
description: "Deterministic extractive distillation report emitted by ee journal distill (proposals, abstentions, applied ids).",
category: "memory",
definition: journal_distill_schema_definition,
},
SchemaEntry {
id: governor::CURSOR_SCHEMA_V1,
version: "1",
description: "Opaque continuation-cursor contract for output-token-governed list surfaces (wire form base64url(payload).base64url(blake3_mac)).",
category: "envelope",
definition: cursor_schema_definition,
},
SchemaEntry {
id: crate::core::ask::ASK_SCHEMA_V1,
version: "1",
description: "Deterministic extractive question answering emitted by ee ask (ADR 0067): retrieve, segment, score spans, cluster, compose with citations, and abstain honestly when confidence is low.",
category: "search",
definition: ask_schema_definition,
},
SchemaEntry {
id: crate::core::support_bundle::TOOLCHAIN_PROVENANCE_SCHEMA_V1,
version: "1",
description: "Redaction-safe observed toolchain capsule for ee, rch, br, bv, Agent Mail, cass, git, cargo, and selected scripts.",
category: "diagnostics",
definition: toolchain_provenance_schema_definition,
},
SchemaEntry {
id: crate::core::session_budget::SESSION_BUDGET_PLAN_SCHEMA_V1,
version: "1",
description: "Advisory, deterministic next-command plan emitted by ee session-budget plan (bd-1clqr.3): reads opt-in ledger and degraded-source posture to recommend cheapest useful next command with rationale and fallbacks.",
category: "coordination",
definition: session_budget_plan_schema_definition,
},
SchemaEntry {
id: crate::core::decide::DECIDE_RECORD_SCHEMA_V1,
version: "1",
description: "Data payload emitted by ee decide record under the standard ee.response.v2 envelope.",
category: "coordination",
definition: decide_record_schema_definition,
},
SchemaEntry {
id: crate::core::decide::DECIDE_LIST_SCHEMA_V1,
version: "1",
description: "Data payload emitted by ee decide list under the standard ee.response.v2 envelope.",
category: "coordination",
definition: decide_list_schema_definition,
},
SchemaEntry {
id: crate::core::decide::DECIDE_REVISIT_SCHEMA_V1,
version: "1",
description: "Data payload emitted by ee decide revisit under the standard ee.response.v2 envelope.",
category: "coordination",
definition: decide_revisit_schema_definition,
},
SchemaEntry {
id: crate::core::recall::RECALL_SCHEMA_V1,
version: "1",
description: "Code-anchored recall result emitted by ee recall (ADR 0064): reverse lookup from paths, symbols, or a git diff to anchored memories with deterministic freshness x confidence x level-tilt ranking.",
category: "search",
definition: recall_schema_definition,
},
SchemaEntry {
id: crate::models::schema::TIMELINE_SCHEMA_V1,
version: "1",
description: "Read-only time-travel memory audit report emitted by ee timeline for as-of postmortem and handoff reconstruction.",
category: "memory",
definition: timeline_schema_definition,
},
SchemaEntry {
id: crate::models::schema::MEMORY_SENTINEL_REVIVALS_SCHEMA_V1,
version: "1",
description: "Bounded, redaction-safe read-only list of current Revive-polarity sentinel predicates that pass under the selected observation mode.",
category: "memory",
definition: memory_sentinel_revivals_schema_definition,
},
SchemaEntry {
id: crate::core::agentsmd::AGENTSMD_EXPORT_SCHEMA_V1,
version: "1",
description: "AGENTS.md bridge export report emitted by ee export agentsmd (managed block render, backup, hand-edit refusal).",
category: "memory",
definition: agentsmd_export_schema_definition,
},
SchemaEntry {
id: crate::core::agentsmd::AGENTSMD_IMPORT_SCHEMA_V1,
version: "1",
description: "AGENTS.md bridge import report emitted by ee import agentsmd (rule-statement proposals into curation candidates).",
category: "memory",
definition: agentsmd_import_schema_definition,
},
SchemaEntry {
id: crate::core::agentsmd::AGENTSMD_DRIFT_SCHEMA_V1,
version: "1",
description: "AGENTS.md bridge drift diagnostic emitted by ee diag agentsmd-drift (stale export, contradictions, missing rules).",
category: "memory",
definition: agentsmd_drift_schema_definition,
},
SchemaEntry {
id: crate::models::CLAIMS_FILE_SCHEMA_V1,
version: "1",
description: "Canonical claims.yaml collection consumed by ee claim list, show, and verify.",
category: "claims",
definition: claims_file_schema_definition,
},
SchemaEntry {
id: crate::models::CLAIM_ENTRY_SCHEMA_V1,
version: "1",
description: "Canonical executable-claim entry, including lifecycle, frequency, and evidence fields.",
category: "claims",
definition: claim_entry_schema_definition,
},
SchemaEntry {
id: crate::models::CLAIM_MANIFEST_SCHEMA_V1,
version: "1",
description: "Per-claim artifact manifest consumed by ee claim show and verify.",
category: "claims",
definition: claim_manifest_schema_definition,
},
SchemaEntry {
id: crate::models::MANIFEST_ARTIFACT_SCHEMA_V1,
version: "1",
description: "Portable BLAKE3-bound artifact record embedded in an executable-claim manifest.",
category: "claims",
definition: manifest_artifact_schema_definition,
},
SchemaEntry {
id: "ee.global_promotion.plan.v1",
version: "1",
description: "Workspace-to-global promotion decision (allow insert/merge or typed refusal) from ee memory promote-global and its dry-run plan.",
category: "memory",
definition: global_promotion_plan_schema_definition,
},
SchemaEntry {
id: "ee.global_promotion.report.v1",
version: "1",
description: "Execution report for ee memory promote-global: plan plus executed/globalMemoryId/alreadyPromoted state.",
category: "memory",
definition: global_promotion_report_schema_definition,
},
SchemaEntry {
id: "ee.global_demotion.report.v1",
version: "1",
description: "Execution report for ee memory demote-global: tombstone of a promoted global row with origin parsed from promotion provenance.",
category: "memory",
definition: global_demotion_report_schema_definition,
},
SchemaEntry {
id: "ee.global_promotion.backflow.v1",
version: "1",
description: "Feedback-backflow report for ee memory outcome-global: feedback on a global row with a clamped origin confidence adjustment when promotion provenance exists.",
category: "memory",
definition: global_promotion_backflow_schema_definition,
},
SchemaEntry {
id: "ee.shadow.retrieval_tuning_report.v1",
version: "1",
description: "ADR 0070 offline retrieval-weight tuning report: labeled-evidence counts with honest denominators, deterministic candidate sweep, winner margin, evidence-gate abstention, and reportHash.",
category: "shadow",
definition: shadow_retrieval_tuning_report_schema_definition,
},
]
}
fn global_promotion_plan_schema_definition() -> String {
include_str!("../../docs/schemas/ee.global_promotion.plan.v1.json").to_string()
}
fn global_promotion_report_schema_definition() -> String {
include_str!("../../docs/schemas/ee.global_promotion.report.v1.json").to_string()
}
fn global_demotion_report_schema_definition() -> String {
include_str!("../../docs/schemas/ee.global_demotion.report.v1.json").to_string()
}
fn global_promotion_backflow_schema_definition() -> String {
include_str!("../../docs/schemas/ee.global_promotion.backflow.v1.json").to_string()
}
fn shadow_retrieval_tuning_report_schema_definition() -> String {
include_str!("../../docs/schemas/ee.shadow.retrieval_tuning_report.v1.json").to_string()
}
fn agentsmd_export_schema_definition() -> String {
include_str!("../../docs/schemas/ee.agentsmd.export.v1.json").to_string()
}
fn agentsmd_import_schema_definition() -> String {
include_str!("../../docs/schemas/ee.agentsmd.import.v1.json").to_string()
}
fn agentsmd_drift_schema_definition() -> String {
include_str!("../../docs/schemas/ee.agentsmd.drift.v1.json").to_string()
}
fn claims_file_schema_definition() -> String {
include_str!("../../docs/schemas/ee.claims_file.v1.json").to_string()
}
fn claim_entry_schema_definition() -> String {
include_str!("../../docs/schemas/ee.claim_entry.v1.json").to_string()
}
fn claim_manifest_schema_definition() -> String {
include_str!("../../docs/schemas/ee.claim_manifest.v1.json").to_string()
}
fn manifest_artifact_schema_definition() -> String {
include_str!("../../docs/schemas/ee.manifest_artifact.v1.json").to_string()
}
fn journal_entry_schema_definition() -> String {
include_str!("../../docs/schemas/ee.journal.entry.v1.json").to_string()
}
fn journal_distill_schema_definition() -> String {
include_str!("../../docs/schemas/ee.journal.distill.v1.json").to_string()
}
fn cursor_schema_definition() -> String {
include_str!("../../docs/schemas/ee.cursor.v1.json").to_string()
}
fn ask_schema_definition() -> String {
include_str!("../../docs/schemas/ee.ask.v1.json").to_string()
}
fn session_budget_plan_schema_definition() -> String {
include_str!("../../docs/schemas/ee.session_budget.plan.v1.json").to_string()
}
fn decide_record_schema_definition() -> String {
include_str!("../../docs/schemas/ee.decide.record.v1.json").to_string()
}
fn decide_list_schema_definition() -> String {
include_str!("../../docs/schemas/ee.decide.list.v1.json").to_string()
}
fn decide_revisit_schema_definition() -> String {
include_str!("../../docs/schemas/ee.decide.revisit.v1.json").to_string()
}
fn toolchain_provenance_schema_definition() -> String {
include_str!("../../docs/schemas/ee.toolchain_provenance.v1.json").to_string()
}
fn recall_schema_definition() -> String {
include_str!("../../docs/schemas/ee.recall.v1.json").to_string()
}
fn timeline_schema_definition() -> String {
include_str!("../../docs/schemas/ee.timeline.v1.json").to_string()
}
fn memory_sentinel_revivals_schema_definition() -> String {
include_str!("../../docs/schemas/ee.memory_sentinel.revivals.v1.json").to_string()
}
/// Per-schema output-token truncation-point registry (ADR 0063 §2,
/// bd-7lvbg.2). Lives adjacent to the schema-id catalog above so schema
/// registration and truncation declaration stay in one review surface.
///
/// Each list-like response schema declares exactly one truncation point —
/// the array whose trailing whole elements the governor may drop. Pack
/// `data.pack.items[]` is NEVER governor-truncated (hard rule: pack content
/// is governed solely by its own `--max-tokens` contract); the pack entry
/// below declares `data.pack.skipped[]` only. Per-surface enforcement
/// wiring and golden coverage land with bd-7lvbg.3; the schema-drift gate
/// extension that asserts inventory coverage is bd-7lvbg.4.
///
/// Path notes vs the ADR 0063 table (reconciled to the shipped payload
/// shapes): memory list's droppable array is `data.memories[]` — the ADR
/// table's `data.items[]` rename was REJECTED by the bd-7lvbg.3 wiring
/// (renaming a shipped agent-facing field for cosmetic uniformity breaks
/// consumers); pack's skipped omissions live at `data.pack.skipped[]`.
/// `ee schema list` (`data.schemas[]`) is registered as the middleware
/// demonstration surface.
pub const OUTPUT_TRUNCATION_REGISTRY: &[governor::TruncationPoint] = &[
governor::TruncationPoint {
schema_id: "ee.search.v1",
command: "search",
array_path: &["results"],
per_section_items: false,
// Search result elements key by docId (bd-7lvbg.3; the ADR table's
// `id` predates the shipped payload shape).
position_key_field: "docId",
},
governor::TruncationPoint {
schema_id: "",
command: "memory list",
array_path: &["memories"],
per_section_items: false,
position_key_field: "id",
},
// Unbounded audit surfaces honor the output ceiling with real
// truncation points (bd-1oep7); timeline/show stay on the query-level
// exemption lane instead.
governor::TruncationPoint {
schema_id: "ee.audit.diff.v1",
command: "audit diff",
array_path: &["entries"],
per_section_items: false,
position_key_field: "id",
},
governor::TruncationPoint {
schema_id: "ee.audit.verify.v1",
command: "audit verify",
array_path: &["issues"],
per_section_items: false,
position_key_field: "audit_id",
},
governor::TruncationPoint {
schema_id: "ee.insights.v1",
command: "insights",
array_path: &["sections"],
per_section_items: true,
position_key_field: "id",
},
governor::TruncationPoint {
schema_id: "ee.curate.candidates.v1",
command: "curate candidates",
array_path: &["candidates"],
per_section_items: false,
position_key_field: "id",
},
governor::TruncationPoint {
schema_id: PACK_SCHEMA_V2,
command: "pack",
array_path: &["pack", "skipped"],
per_section_items: false,
position_key_field: "id",
},
governor::TruncationPoint {
schema_id: "ee.recall.v1",
command: "recall",
array_path: &["recall", "items"],
per_section_items: false,
position_key_field: "memoryId",
},
governor::TruncationPoint {
schema_id: "",
command: "journal list",
array_path: &["entries"],
per_section_items: false,
position_key_field: "entryId",
},
governor::TruncationPoint {
schema_id: "ee.mesh.import_ledger.v1",
command: "mesh ledger",
array_path: &["events"],
per_section_items: false,
position_key_field: "eventId",
},
governor::TruncationPoint {
schema_id: "",
command: "schema list",
array_path: &["schemas"],
per_section_items: false,
position_key_field: "id",
},
];
/// Render the schema list as JSON (ee.response.v2 envelope).
#[must_use]
pub fn render_schema_list_json() -> String {
let schemas = public_schemas();
let mut b = JsonBuilder::with_capacity(512);
b.field_str("schema", RESPONSE_SCHEMA_V2);
b.field_bool("success", true);
b.field_object("data", |d| {
d.field_str("command", "schema list");
d.field_array_of_objects("schemas", schemas, |obj, entry| {
obj.field_str("id", entry.id);
obj.field_str("version", entry.version);
obj.field_str("description", entry.description);
obj.field_str("category", entry.category);
});
});
b.field_raw("degraded", "[]");
b.finish()
}
/// Render the schema list as human-readable text.
#[must_use]
pub fn render_schema_list_human() -> String {
let schemas = public_schemas();
let mut output = String::from("ee schema list\n\nAvailable schemas:\n\n");
for entry in schemas {
output.push_str(&format!(" {} (v{})\n", entry.id, entry.version));
output.push_str(&format!(" {}\n\n", entry.description));
}
output.push_str(
"Use `ee schema export <SCHEMA_ID>` to export a schema's JSON Schema definition.\n",
);
output
}
/// Render the schema list as TOON.
#[must_use]
pub fn render_schema_list_toon() -> String {
render_toon_from_json(&render_schema_list_json())
}
/// Render a schema export as JSON (full JSON Schema definition).
#[must_use]
pub fn render_schema_export_json(schema_id: Option<&str>) -> String {
match schema_id {
Some(id) => render_single_schema_export(id),
None => render_all_schemas_export(),
}
}
fn render_single_schema_export(schema_id: &str) -> String {
if let Some(entry) = public_schemas().iter().find(|entry| entry.id == schema_id) {
return (entry.definition)();
}
let mut b = JsonBuilder::with_capacity(256);
b.field_str("schema", ERROR_SCHEMA_V2);
b.field_object("error", |e| {
e.field_str("code", "schema_not_found");
e.field_str("message", &format!("Schema '{}' not found", schema_id));
e.field_str("severity", "low");
e.field_str("repair", "ee schema list");
e.field_object("details", |details| {
details.field_str("schemaId", schema_id);
});
});
b.finish()
}
fn render_all_schemas_export() -> String {
let mut b = JsonBuilder::with_capacity(3072);
b.field_str("schema", RESPONSE_SCHEMA_V2);
b.field_bool("success", true);
b.field_object("data", |d| {
d.field_str("command", "schema export");
d.field_raw("schemas", &schema_definition_array_json());
});
b.field_raw("degraded", "[]");
b.finish()
}
fn schema_definition_array_json() -> String {
let mut output = String::from("[");
for (index, schema) in public_schemas().iter().enumerate() {
if index > 0 {
output.push(',');
}
output.push_str(&(schema.definition)());
}
output.push(']');
output
}
fn response_schema_definition() -> String {
include_str!("../../docs/schemas/ee.response.v2.json").to_string()
}
fn error_schema_definition() -> String {
include_str!("../../docs/schemas/ee.error.v2.json").to_string()
}
fn pack_response_schema_definition() -> String {
include_str!("../../docs/schemas/ee.pack.v2.json").to_string()
}
fn pack_replay_schema_definition() -> String {
include_str!("../../docs/schemas/ee.pack.replay.v2.json").to_string()
}
fn pack_diff_schema_definition() -> String {
include_str!("../../docs/schemas/ee.pack.diff.v2.json").to_string()
}
fn context_delta_schema_definition() -> String {
include_str!("../../docs/schemas/ee.context.delta.v2.json").to_string()
}
fn support_bundle_pack_replay_summary_schema_definition() -> String {
include_str!("../../docs/schemas/ee.support_bundle.pack_replay_summary.v2.json").to_string()
}
fn regression_causality_schema_definition() -> String {
include_str!("../../docs/schemas/ee.regression_causality.v1.json").to_string()
}
fn query_request_schema_definition() -> String {
include_str!("../../docs/schemas/ee.query.v1.json").to_string()
}
fn search_response_schema_definition() -> String {
include_str!("../../docs/schemas/ee.search.v1.json").to_string()
}
fn search_family_schema_definition() -> String {
include_str!("../../docs/schemas/ee.search.family.v1.json").to_string()
}
fn query_assist_schema_definition() -> String {
include_str!("../../docs/schemas/ee.query_assist.v1.json").to_string()
}
fn learn_gaps_schema_definition() -> String {
include_str!("../../docs/schemas/ee.learn.gaps.v1.json").to_string()
}
fn memory_debt_doctor_schema_definition() -> String {
include_str!("../../docs/schemas/ee.curate.doctor.v1.json").to_string()
}
fn memory_debt_trend_schema_definition() -> String {
include_str!("../../docs/schemas/ee.curate.debt_trend.v1.json").to_string()
}
fn memory_show_schema_definition() -> String {
include_str!("../../docs/schemas/ee.memory.show.v1.json").to_string()
}
fn memory_list_schema_definition() -> String {
include_str!("../../docs/schemas/ee.memory.list.v1.json").to_string()
}
fn typed_memory_fields_schema_definition() -> String {
include_str!("../../docs/schemas/ee.memory.typed_fields.v2.json").to_string()
}
fn status_response_schema_definition() -> String {
include_str!("../../docs/schemas/ee.status.v1.json").to_string()
}
fn singleflight_posture_schema_definition() -> String {
include_str!("../../docs/schemas/ee.singleflight.posture.v1.json").to_string()
}
fn mesh_peer_policy_schema_definition() -> String {
include_str!("../../docs/schemas/ee.mesh.peer_policy.v1.json").to_string()
}
fn mesh_policy_decision_schema_definition() -> String {
include_str!("../../docs/schemas/ee.mesh.policy_decision.v1.json").to_string()
}
fn mesh_policy_failure_surface_schema_definition() -> String {
include_str!("../../docs/schemas/ee.mesh.policy_failure_surface.v1.json").to_string()
}
fn mesh_storage_status_schema_definition() -> String {
include_str!("../../docs/schemas/ee.mesh.storage_status.v1.json").to_string()
}
fn doctor_response_schema_definition() -> String {
include_str!("../../docs/schemas/ee.doctor.v1.json").to_string()
}
fn capabilities_response_schema_definition() -> String {
include_str!("../../docs/schemas/ee.capabilities.v1.json").to_string()
}
fn host_profile_schema_definition() -> String {
include_str!("../../docs/schemas/ee.host_profile.v1.json").to_string()
}
fn rch_selector_admission_probe_schema_definition() -> String {
include_str!("../../docs/schemas/ee.rch.selector_admission_probe.v1.json").to_string()
}
fn resource_admission_schema_definition() -> String {
include_str!("../../docs/schemas/ee.resource_admission.v1.json").to_string()
}
fn swarm_next_action_schema_definition() -> String {
include_str!("../../docs/schemas/ee.swarm_next_action.v1.json").to_string()
}
fn swarm_repair_plan_schema_definition() -> String {
include_str!("../../docs/schemas/swarm/ee.swarm.repair_plan.v1.json").to_string()
}
fn memory_drift_report_schema_definition() -> String {
include_str!("../../docs/schemas/ee.memory_drift.report.v1.json").to_string()
}
fn import_cass_response_schema_definition() -> String {
include_str!("../../docs/schemas/ee.import.cass.v1.json").to_string()
}
fn export_response_schema_definition() -> String {
include_str!("../../docs/schemas/ee.export.v1.json").to_string()
}
fn curate_candidates_response_schema_definition() -> String {
include_str!("../../docs/schemas/ee.curate.candidates.v1.json").to_string()
}
fn capture_suggestions_v1_schema_definition() -> String {
include_str!("../../docs/schemas/ee.capture_suggestions.v1.json").to_string()
}
fn capture_suggestions_v2_schema_definition() -> String {
include_str!("../../docs/schemas/ee.capture_suggestions.v2.json").to_string()
}
fn curate_auto_promote_schema_definition() -> String {
include_str!("../../docs/schemas/ee.curate.auto_promote.v1.json").to_string()
}
fn curate_show_schema_definition() -> String {
include_str!("../../docs/schemas/ee.curate.show.v1.json").to_string()
}
fn diag_incident_replay_schema_definition() -> String {
include_str!("../../docs/schemas/ee.diag.incident.replay.v1.json").to_string()
}
fn reflection_source_package_schema_definition() -> String {
include_str!("../../docs/schemas/ee.reflect.source_package.v1.json").to_string()
}
fn reflection_request_schema_definition() -> String {
include_str!("../../docs/schemas/ee.reflect.request.v1.json").to_string()
}
fn reflection_challenge_binding_schema_definition() -> String {
include_str!("../../docs/schemas/ee.reflect.challenge_binding.v1.json").to_string()
}
fn reflection_result_schema_definition() -> String {
include_str!("../../docs/schemas/ee.reflect.result.v1.json").to_string()
}
fn reflection_propose_schema_definition() -> String {
include_str!("../../docs/schemas/ee.reflect.propose.v1.json").to_string()
}
fn reflection_ingest_schema_definition() -> String {
include_str!("../../docs/schemas/ee.reflect.ingest.v1.json").to_string()
}
fn reflection_request_ledger_diagnostics_schema_definition() -> String {
include_str!("../../docs/schemas/ee.reflect.request_ledger.diagnostics.v1.json").to_string()
}
fn graph_export_response_schema_definition() -> String {
include_str!("../../docs/schemas/ee.graph.export.v1.json").to_string()
}
fn graph_suggest_links_schema_definition() -> String {
include_str!("../../docs/schemas/ee.graph.suggest_links.v1.json").to_string()
}
fn conflict_resolve_schema_definition() -> String {
include_str!("../../docs/schemas/ee.conflict.resolve.v1.json").to_string()
}
fn graph_diff_schema_definition() -> String {
include_str!("../../docs/schemas/ee.graph.diff.v1.json").to_string()
}
fn orient_schema_definition() -> String {
include_str!("../../docs/schemas/ee.orient.v1.json").to_string()
}
fn resume_schema_definition() -> String {
include_str!("../../docs/schemas/ee.resume.v1.json").to_string()
}
fn graph_snapshot_prune_schema_definition() -> String {
include_str!("../../docs/schemas/ee.graph.snapshot_prune.v1.json").to_string()
}
fn graph_witness_prune_schema_definition() -> String {
include_str!("../../docs/schemas/ee.graph.witness_prune_report.v1.json").to_string()
}
fn db_inspect_schema_definition() -> String {
include_str!("../../docs/schemas/ee.db.inspect.v1.json").to_string()
}
fn workspace_hygiene_schema_definition() -> String {
include_str!("../../docs/schemas/ee.workspace_hygiene.v1.json").to_string()
}
fn completion_audit_checklist_schema_definition() -> String {
include_str!("../../docs/schemas/ee.completion_audit.checklist.v1.json").to_string()
}
fn completion_audit_report_schema_definition() -> String {
include_str!("../../docs/schemas/ee.completion_audit.report.v2.json").to_string()
}
fn agent_operating_contract_schema_definition() -> String {
include_str!("../../docs/schemas/ee.agent_operating_contract.v1.json").to_string()
}
fn environment_attestation_schema_definition() -> String {
include_str!("../../docs/schemas/ee.environment_attestation.v1.json").to_string()
}
fn ci_proof_lane_snapshot_schema_definition() -> String {
include_str!("../../docs/schemas/ee.ci_proof_lane_snapshot.v1.json").to_string()
}
fn remote_build_artifact_manifest_schema_definition() -> String {
include_str!("../../docs/schemas/ee.remote_build_artifact_manifest.v1.json").to_string()
}
fn remote_build_artifact_verification_schema_definition() -> String {
include_str!("../../docs/schemas/ee.remote_build_artifact_manifest.verification.v1.json")
.to_string()
}
fn proof_broker_schema_definition() -> String {
include_str!("../../docs/schemas/swarm/ee.proof_broker.v1.json").to_string()
}
fn mcp_manifest_schema_definition() -> String {
include_str!("../../docs/schemas/ee.mcp.manifest.v1.json").to_string()
}
fn certificate_schema_definition() -> String {
r#"{"$schema":"https://json-schema.org/draft/2020-12/schema","$id":"ee.certificate.v1","type":"object","required":["kind","status"],"properties":{"kind":{"type":"string","enum":["pack","curation","tail_risk","privacy_budget","lifecycle"]},"status":{"type":"string","enum":["pending","active","revoked","expired"]}}}"#.to_string()
}
fn rule_add_schema_definition() -> String {
serde_json::json!({
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": RULE_ADD_SCHEMA_V1,
"type": "object",
"required": [
"schema",
"command",
"version",
"status",
"ruleId",
"content",
"maturity",
"lifecycle",
"evidence",
"dryRun",
"persisted",
"degraded"
],
"properties": {
"schema": { "const": RULE_ADD_SCHEMA_V1 },
"command": { "const": "rule add" },
"version": { "type": "string" },
"status": { "type": "string" },
"ruleId": { "type": "string" },
"content": { "type": "string" },
"maturity": { "type": "string" },
"lifecycle": { "type": "object" },
"evidence": { "type": "object" },
"dryRun": { "type": "boolean" },
"persisted": { "type": "boolean" },
"degraded": { "type": "array", "items": { "type": "object" } }
}
})
.to_string()
}
fn rule_list_schema_definition() -> String {
serde_json::json!({
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": RULE_LIST_SCHEMA_V1,
"type": "object",
"required": [
"schema",
"command",
"version",
"workspaceId",
"totalCount",
"returnedCount",
"limit",
"offset",
"truncated",
"filter",
"rules",
"degraded"
],
"properties": {
"schema": { "const": RULE_LIST_SCHEMA_V1 },
"command": { "const": "rule list" },
"version": { "type": "string" },
"workspaceId": { "type": "string" },
"totalCount": { "type": "integer", "minimum": 0 },
"returnedCount": { "type": "integer", "minimum": 0 },
"limit": { "type": "integer", "minimum": 0 },
"offset": { "type": "integer", "minimum": 0 },
"truncated": { "type": "boolean" },
"filter": { "type": "object" },
"rules": { "type": "array", "items": { "type": "object" } },
"degraded": { "type": "array", "items": { "type": "object" } }
}
})
.to_string()
}
fn rule_show_schema_definition() -> String {
serde_json::json!({
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": RULE_SHOW_SCHEMA_V1,
"type": "object",
"required": [
"schema",
"command",
"version",
"workspaceId",
"found",
"rule",
"degraded"
],
"properties": {
"schema": { "const": RULE_SHOW_SCHEMA_V1 },
"command": { "const": "rule show" },
"version": { "type": "string" },
"workspaceId": { "type": "string" },
"found": { "type": "boolean" },
"rule": { "type": "object" },
"degraded": { "type": "array", "items": { "type": "object" } }
}
})
.to_string()
}
fn rule_mark_schema_definition() -> String {
serde_json::json!({
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": RULE_MARK_SCHEMA_V1,
"type": "object",
"required": [
"schema",
"command",
"version",
"status",
"ruleId",
"dryRun",
"persisted",
"changed",
"transition",
"evidence",
"previousRule",
"rule",
"degraded"
],
"properties": {
"schema": { "const": RULE_MARK_SCHEMA_V1 },
"command": { "const": "rule mark" },
"version": { "type": "string" },
"status": { "type": "string" },
"ruleId": { "type": "string" },
"dryRun": { "type": "boolean" },
"persisted": { "type": "boolean" },
"changed": { "type": "boolean" },
"transition": { "type": "object" },
"evidence": { "type": "object" },
"previousRule": { "type": "object" },
"rule": { "type": "object" },
"degraded": { "type": "array", "items": { "type": "object" } }
}
})
.to_string()
}
fn rule_update_schema_definition() -> String {
serde_json::json!({
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": RULE_UPDATE_SCHEMA_V1,
"type": "object",
"required": [
"schema",
"command",
"version",
"status",
"ruleId",
"dryRun",
"persisted",
"changed",
"changedFields",
"previousRule",
"rule",
"degraded"
],
"properties": {
"schema": { "const": RULE_UPDATE_SCHEMA_V1 },
"command": { "const": "rule update" },
"version": { "type": "string" },
"status": { "type": "string" },
"ruleId": { "type": "string" },
"dryRun": { "type": "boolean" },
"persisted": { "type": "boolean" },
"changed": { "type": "boolean" },
"changedFields": { "type": "array", "items": { "type": "string" } },
"previousRule": { "type": "object" },
"rule": { "type": "object" },
"degraded": { "type": "array", "items": { "type": "object" } }
}
})
.to_string()
}
fn maintenance_run_schema_definition() -> String {
serde_json::json!({
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": MAINTENANCE_RUN_SCHEMA_V1,
"type": "object",
"required": [
"schema",
"command",
"requestedJob",
"workspace",
"dryRun",
"durableMutation",
"summary",
"job",
"history",
"results",
"degraded"
],
"properties": {
"schema": { "const": MAINTENANCE_RUN_SCHEMA_V1 },
"command": { "type": "string" },
"requestedJob": { "type": "string" },
"workspace": { "type": "string" },
"dryRun": { "type": "boolean" },
"durableMutation": { "type": "boolean" },
"summary": { "type": "object" },
"job": { "type": ["object", "null"] },
"history": { "type": "object" },
"results": { "type": "array", "items": { "type": "object" } },
"degraded": { "type": "array", "items": { "type": "object" } }
}
})
.to_string()
}
fn maintenance_status_schema_definition() -> String {
serde_json::json!({
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": MAINTENANCE_STATUS_SCHEMA_V1,
"type": "object",
"required": [
"schema",
"command",
"jobs",
"historyPath",
"next"
],
"properties": {
"schema": { "const": MAINTENANCE_STATUS_SCHEMA_V1 },
"command": { "const": "maintenance status" },
"jobs": {
"type": "array",
"items": {
"type": "object",
"required": [
"name",
"available",
"stewardJobType",
"description",
"run"
],
"properties": {
"name": { "type": "string" },
"available": { "type": "boolean" },
"stewardJobType": { "type": "string" },
"description": { "type": "string" },
"run": { "type": "string" }
}
}
},
"historyPath": { "type": "string" },
"next": { "type": "string" }
}
})
.to_string()
}
fn maintenance_job_list_schema_definition() -> String {
serde_json::json!({
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": MAINTENANCE_JOB_LIST_SCHEMA_V1,
"type": "object",
"required": [
"schema",
"command",
"jobs"
],
"properties": {
"schema": { "const": MAINTENANCE_JOB_LIST_SCHEMA_V1 },
"command": { "const": "job list" },
"workspace": { "type": "string" },
"historyPath": { "type": "string" },
"filters": { "type": "object" },
"jobCount": { "type": "integer", "minimum": 0 },
"jobs": { "type": "array", "items": { "type": "object" } },
"code": { "type": "string" },
"message": { "type": "string" },
"repair": { "type": "string" }
}
})
.to_string()
}
fn maintenance_job_show_schema_definition() -> String {
serde_json::json!({
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": MAINTENANCE_JOB_SHOW_SCHEMA_V1,
"type": "object",
"required": [
"schema",
"command"
],
"properties": {
"schema": { "const": MAINTENANCE_JOB_SHOW_SCHEMA_V1 },
"command": { "const": "job show" },
"workspace": { "type": "string" },
"historyPath": { "type": "string" },
"job": { "type": ["object", "null"] },
"linkedAuditEntries": { "type": "array", "items": { "type": "object" } },
"code": { "type": "string" },
"message": { "type": "string" },
"repair": { "type": "string" }
}
})
.to_string()
}
fn maintenance_job_row_schema_definition() -> String {
serde_json::json!({
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": MAINTENANCE_JOB_ROW_SCHEMA_V1,
"type": "object",
"required": [
"schema",
"id",
"jobType",
"requestedJob",
"command",
"workspace",
"recordedAt",
"completedAt",
"outcome",
"dryRun",
"durableMutation",
"linkedAuditEntries"
],
"properties": {
"schema": { "const": MAINTENANCE_JOB_ROW_SCHEMA_V1 },
"id": { "type": "string" },
"runnerJobId": { "type": "string" },
"jobId": { "type": "string" },
"jobType": { "type": "string" },
"requestedJob": { "type": "string" },
"command": { "type": "string" },
"workspace": { "type": "string" },
"recordedAt": { "type": "string" },
"completedAt": { "type": "string" },
"outcome": { "type": "string" },
"rowsAffected": { "type": "integer", "minimum": 0 },
"itemsProcessed": { "type": "integer", "minimum": 0 },
"durationMs": { "type": "integer", "minimum": 0 },
"dryRun": { "type": "boolean" },
"durableMutation": { "type": "boolean" },
"error": { "type": ["string", "null"] },
"details": { "type": "object" },
"budgetUsed": { "type": "object" },
"linkedAuditEntries": { "type": "array", "items": { "type": "object" } }
}
})
.to_string()
}
// ─── R-009 (Pass 2): definition functions for the newly-registered schemas.
// Each one uses `include_str!` to embed the on-disk schema JSON at compile
// time, matching the established pattern used by all other public schemas.
fn agent_workload_replay_schema_definition() -> String {
include_str!("../../docs/schemas/ee.agent_workload_replay.v1.json").to_string()
}
fn agent_workload_trace_schema_definition() -> String {
include_str!("../../docs/schemas/ee.agent_workload_trace.v1.json").to_string()
}
fn swarm_workload_schema_definition() -> String {
include_str!("../../docs/schemas/ee.swarm_workload.v1.json").to_string()
}
fn swarm_replay_result_schema_definition() -> String {
include_str!("../../docs/schemas/ee.swarm_replay_result.v1.json").to_string()
}
fn swarm_slo_scorecard_schema_definition() -> String {
include_str!("../../docs/schemas/ee.swarm_slo.scorecard.v1.json").to_string()
}
fn swarm_slo_resource_usage_event_schema_definition() -> String {
include_str!("../../docs/schemas/ee.swarm_slo.resource_usage_event.v1.json").to_string()
}
fn swarm_slo_coordination_event_schema_definition() -> String {
include_str!("../../docs/schemas/ee.swarm_slo.coordination_event.v1.json").to_string()
}
fn audit_lane_schema_definition() -> String {
include_str!("../../docs/schemas/ee.audit_lane.v1.json").to_string()
}
fn cache_hotset_schema_definition() -> String {
include_str!("../../docs/schemas/ee.cache.hotset.v1.json").to_string()
}
fn cache_hotset_collect_schema_definition() -> String {
include_str!("../../docs/schemas/ee.cache.hotset_collect.v1.json").to_string()
}
fn hotset_manifest_schema_definition() -> String {
include_str!("../../docs/schemas/ee.hotset_manifest.v1.json").to_string()
}
fn scale_envelope_schema_definition() -> String {
include_str!("../../docs/schemas/ee.scale_envelope.v1.json").to_string()
}
fn write_group_commit_schema_definition() -> String {
include_str!("../../docs/schemas/ee.write_group_commit.v1.json").to_string()
}
fn index_intake_schema_definition() -> String {
include_str!("../../docs/schemas/ee.index_intake.v1.json").to_string()
}
fn embedding_posture_schema_definition() -> String {
include_str!("../../docs/schemas/ee.embedding_posture.v1.json").to_string()
}
fn closeout_audit_schema_definition() -> String {
include_str!("../../docs/schemas/ee.closeout_audit.v1.json").to_string()
}
fn failure_mode_fixture_schema_definition() -> String {
include_str!("../../docs/schemas/ee.failure_mode_fixture.v1.json").to_string()
}
// Round-3 self-review fix: the v1 schema generator was duplicated under the
// same name as the canonical v2 one above (line 8892). Both call sites at
// 8084 / 8272 reference the v2 form; rename the v1 leftover to disambiguate
// without deleting the underlying schema file in case another agent still
// wants to wire it in. Suffix kept so the function stays grep-able.
#[allow(dead_code)]
fn completion_audit_report_schema_v1_definition() -> String {
include_str!("../../docs/schemas/ee.completion_audit.report.v1.json").to_string()
}
fn context_agent_profile_schema_definition() -> String {
include_str!("../../docs/schemas/ee.context.agent_profile.v1.json").to_string()
}
fn context_bead_affinity_schema_definition() -> String {
include_str!("../../docs/schemas/ee.context.bead_affinity.v1.json").to_string()
}
fn context_budget_schema_definition() -> String {
include_str!("../../docs/schemas/ee.context.budget.v1.json").to_string()
}
fn context_pack_dna_schema_definition() -> String {
include_str!("../../docs/schemas/ee.context.pack_dna.v1.json").to_string()
}
fn context_schema_definition() -> String {
include_str!("../../docs/schemas/ee.context.v1.json").to_string()
}
fn curate_disposition_schema_definition() -> String {
include_str!("../../docs/schemas/ee.curate.disposition.v1.json").to_string()
}
fn curate_peer_evidence_schema_definition() -> String {
include_str!("../../docs/schemas/ee.curate.peer_evidence.v1.json").to_string()
}
fn docs_bootstrap_apply_schema_definition() -> String {
include_str!("../../docs/schemas/ee.bootstrap.docs.apply.v1.json").to_string()
}
fn docs_bootstrap_run_schema_definition() -> String {
include_str!("../../docs/schemas/ee.bootstrap.docs.run.v1.json").to_string()
}
fn diag_plan_cache_schema_definition() -> String {
include_str!("../../docs/schemas/ee.diag.plan_cache.v1.json").to_string()
}
fn diag_contention_schema_definition() -> String {
include_str!("../../docs/schemas/ee.diag.contention.v1.json").to_string()
}
fn disk_pressure_agent_harness_log_classifier_schema_definition() -> String {
include_str!("../../docs/schemas/ee.disk_pressure.agent_harness_log_classifier.v1.json")
.to_string()
}
fn graph_rule_provenance_ego_schema_definition() -> String {
include_str!("../../docs/schemas/ee.graph.rule_provenance_ego.v1.json").to_string()
}
fn health_structural_schema_definition() -> String {
include_str!("../../docs/schemas/ee.health.structural.v1.json").to_string()
}
fn health_scorecard_schema_definition() -> String {
include_str!("../../docs/schemas/ee.health_scorecard.v1.json").to_string()
}
fn hooks_git_readiness_schema_definition() -> String {
include_str!("../../docs/schemas/ee.hooks.git_readiness.v1.json").to_string()
}
fn hook_harness_install_schema_definition() -> String {
include_str!("../../docs/schemas/ee.hook.harness_install.v1.json").to_string()
}
fn ambient_context_schema_definition() -> String {
include_str!("../../docs/schemas/ee.ambient_context.v1.json").to_string()
}
fn harness_conformance_schema_definition() -> String {
include_str!("../../docs/schemas/ee.harness_conformance.v1.json").to_string()
}
fn host_calibration_host_class_schema_definition() -> String {
include_str!("../../docs/schemas/ee.host_calibration.host_class.v1.json").to_string()
}
fn host_calibration_recommendation_schema_definition() -> String {
include_str!("../../docs/schemas/ee.host_calibration.recommendation.v1.json").to_string()
}
fn host_calibration_posture_schema_definition() -> String {
include_str!("../../docs/schemas/ee.host_calibration.posture.v1.json").to_string()
}
fn insights_schema_definition() -> String {
include_str!("../../docs/schemas/ee.insights.v1.json").to_string()
}
fn memory_drift_queue_schema_definition() -> String {
include_str!("../../docs/schemas/ee.memory_drift.queue.v1.json").to_string()
}
fn memory_drift_snapshot_schema_definition() -> String {
include_str!("../../docs/schemas/ee.memory_drift.snapshot.v1.json").to_string()
}
fn memory_delta_schema_definition() -> String {
include_str!("../../docs/schemas/ee.memory.delta.v1.json").to_string()
}
fn memory_impact_analysis_schema_definition() -> String {
include_str!("../../docs/schemas/ee.memory.impact_analysis.v1.json").to_string()
}
fn mesh_anti_entropy_schema_definition() -> String {
include_str!("../../docs/schemas/ee.mesh.anti_entropy.v1.json").to_string()
}
fn mesh_approval_token_schema_definition() -> String {
include_str!("../../docs/schemas/ee.mesh.approval_token.v1.json").to_string()
}
fn mesh_auto_enrollment_result_schema_definition() -> String {
include_str!("../../docs/schemas/ee.mesh.auto_enrollment_result.v1.json").to_string()
}
fn mesh_auto_enrollment_summary_schema_definition() -> String {
include_str!("../../docs/schemas/ee.mesh.auto_enrollment_summary.v1.json").to_string()
}
fn mesh_auto_status_schema_definition() -> String {
include_str!("../../docs/schemas/ee.mesh.auto_status.v2.json").to_string()
}
fn mesh_disable_result_schema_definition() -> String {
include_str!("../../docs/schemas/ee.mesh.disable_result.v1.json").to_string()
}
fn mesh_discovery_policy_schema_definition() -> String {
include_str!("../../docs/schemas/ee.mesh.discovery_policy.v1.json").to_string()
}
fn mesh_event_schema_definition() -> String {
include_str!("../../docs/schemas/ee.mesh.event.v1.json").to_string()
}
fn mesh_grant_schema_definition() -> String {
include_str!("../../docs/schemas/ee.mesh.grant.v1.json").to_string()
}
fn mesh_import_ledger_schema_definition() -> String {
include_str!("../../docs/schemas/ee.mesh.import_ledger.v1.json").to_string()
}
fn mesh_hello_responder_status_schema_definition() -> String {
include_str!("../../docs/schemas/ee.mesh.hello_responder.status.v1.json").to_string()
}
fn mesh_hello_error_schema_definition() -> String {
include_str!("../../docs/schemas/ee.mesh.hello.error.v1.json").to_string()
}
fn mesh_hello_response_schema_definition() -> String {
include_str!("../../docs/schemas/ee.mesh.hello.response.v1.json").to_string()
}
fn mesh_hello_schema_definition() -> String {
include_str!("../../docs/schemas/ee.mesh.hello.v1.json").to_string()
}
fn mesh_lane_grant_preview_schema_definition() -> String {
include_str!("../../docs/schemas/ee.mesh.lane_grant_preview.v2.json").to_string()
}
fn mesh_peer_group_binding_schema_definition() -> String {
include_str!("../../docs/schemas/ee.mesh.peer_group_binding.v1.json").to_string()
}
fn mesh_revoke_lane_schema_definition() -> String {
include_str!("../../docs/schemas/ee.mesh.revoke_lane.v1.json").to_string()
}
fn mesh_revoke_result_schema_definition() -> String {
include_str!("../../docs/schemas/ee.mesh.revoke_result.v1.json").to_string()
}
fn mesh_session_capability_negotiation_schema_definition() -> String {
include_str!("../../docs/schemas/ee.mesh.session_capability_negotiation.v1.json").to_string()
}
fn mesh_session_confirm_schema_definition() -> String {
include_str!("../../docs/schemas/ee.mesh.session_confirm.v1.json").to_string()
}
fn mesh_session_finish_schema_definition() -> String {
include_str!("../../docs/schemas/ee.mesh.session_finish.v1.json").to_string()
}
fn mesh_session_open_schema_definition() -> String {
include_str!("../../docs/schemas/ee.mesh.session_open.v1.json").to_string()
}
fn mesh_surrogate_schema_definition() -> String {
include_str!("../../docs/schemas/ee.mesh.surrogate.v1.json").to_string()
}
fn mesh_tailscale_transport_frame_schema_definition() -> String {
include_str!("../../docs/schemas/ee.mesh.tailscale_transport_frame.v2.json").to_string()
}
fn migration_shard_fanout_schema_definition() -> String {
include_str!("../../docs/schemas/ee.migration.shard_fanout.v1.json").to_string()
}
fn pack_revision_token_schema_definition() -> String {
include_str!("../../docs/schemas/ee.pack.revision_token.v1.json").to_string()
}
fn pack_stream_schema_definition() -> String {
include_str!("../../docs/schemas/ee.pack.stream.v1.json").to_string()
}
fn peer_conflict_schema_definition() -> String {
include_str!("../../docs/schemas/ee.peer_conflict.v1.json").to_string()
}
fn perf_live_schema_definition() -> String {
include_str!("../../docs/schemas/ee.perf.live.v1.json").to_string()
}
fn daemon_search_request_schema_definition() -> String {
include_str!("../../docs/schemas/ee.daemon.search.request.v2.json").to_string()
}
fn daemon_search_response_schema_definition() -> String {
include_str!("../../docs/schemas/ee.daemon.search.response.v3.json").to_string()
}
fn prompt_budget_report_schema_definition() -> String {
include_str!("../../docs/schemas/ee.prompt_budget_report.v1.json").to_string()
}
fn proof_check_schema_definition() -> String {
include_str!("../../docs/schemas/ee.proof_check.v1.json").to_string()
}
fn proximity_schema_definition() -> String {
include_str!("../../docs/schemas/ee.proximity.v1.json").to_string()
}
fn repair_action_graph_schema_definition() -> String {
include_str!("../../docs/schemas/ee.repair_action_graph.v1.json").to_string()
}
fn search_revision_token_schema_definition() -> String {
include_str!("../../docs/schemas/ee.search.revision_token.v1.json").to_string()
}
fn search_score_interval_schema_definition() -> String {
include_str!("../../docs/schemas/ee.search.score_interval.v1.json").to_string()
}
fn search_score_calibration_schema_definition() -> String {
include_str!("../../docs/schemas/ee.search.score_calibration.v1.json").to_string()
}
fn singleflight_key_schema_definition() -> String {
include_str!("../../docs/schemas/ee.singleflight.key.v1.json").to_string()
}
fn spec_pack_schema_definition() -> String {
include_str!("../../docs/schemas/ee.spec_pack.v1.json").to_string()
}
fn status_graph_numa_pin_schema_definition() -> String {
include_str!("../../docs/schemas/ee.status.graph.numa_pin.v1.json").to_string()
}
fn status_search_lexical_ram_tier_schema_definition() -> String {
include_str!("../../docs/schemas/ee.status.search.lexical_ram_tier.v1.json").to_string()
}
fn status_skyline_schema_definition() -> String {
include_str!("../../docs/schemas/ee.status.skyline.v1.json").to_string()
}
fn symbol_evidence_links_schema_definition() -> String {
include_str!("../../docs/schemas/ee.symbol_evidence_links.v1.json").to_string()
}
fn symbol_snapshot_schema_definition() -> String {
include_str!("../../docs/schemas/ee.symbol_snapshot.v1.json").to_string()
}
fn tailscale_autodiscovery_schema_definition() -> String {
include_str!("../../docs/schemas/ee.tailscale.autodiscovery.v1.json").to_string()
}
fn tailscale_local_schema_definition() -> String {
include_str!("../../docs/schemas/ee.tailscale.local.v1.json").to_string()
}
fn verification_evidence_schema_definition() -> String {
include_str!("../../docs/schemas/ee.verification_evidence.v1.json").to_string()
}
fn why_not_selected_schema_definition() -> String {
include_str!("../../docs/schemas/ee.why_not_selected.v1.json").to_string()
}
fn why_causal_schema_definition() -> String {
include_str!("../../docs/schemas/ee.why.causal.v1.json").to_string()
}
fn why_conformal_prediction_set_schema_definition() -> String {
include_str!("../../docs/schemas/ee.why.conformal_prediction_set.v1.json").to_string()
}
fn why_influence_schema_definition() -> String {
include_str!("../../docs/schemas/ee.why.influence.v1.json").to_string()
}
fn why_schema_definition() -> String {
include_str!("../../docs/schemas/ee.why.v1.json").to_string()
}
fn preflight_guard_schema_definition() -> String {
include_str!("../../docs/schemas/ee.preflight.guard.v1.json").to_string()
}
fn recorder_events_list_schema_definition() -> String {
serde_json::json!({
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": RECORDER_EVENTS_LIST_SCHEMA_V1,
"type": "object",
"required": [
"schema",
"command",
"count",
"totalCount",
"events",
"filters"
],
"properties": {
"schema": { "const": RECORDER_EVENTS_LIST_SCHEMA_V1 },
"command": { "const": "recorder events list" },
"count": { "type": "integer", "minimum": 0 },
"totalCount": { "type": "integer", "minimum": 0 },
"events": { "type": "array", "items": { "type": "object" } },
"filters": { "type": "object" }
}
})
.to_string()
}
/// Render a schema export as human-readable text.
#[must_use]
pub fn render_schema_export_human(schema_id: Option<&str>) -> String {
let json = render_schema_export_json(schema_id);
if json.contains("\"code\":\"schema_not_found\"") {
String::from("error: Schema not found\n\nRun `ee schema list` to see available schemas.\n")
} else {
format!("ee schema export\n\n{}\n", json)
}
}
/// Render a schema export as TOON.
#[must_use]
pub fn render_schema_export_toon(schema_id: Option<&str>) -> String {
render_toon_from_json(&render_schema_export_json(schema_id))
}
/// Render the MCP adapter manifest as JSON.
#[must_use]
pub fn render_mcp_manifest_json() -> String {
let mut b = JsonBuilder::with_capacity(8192);
b.field_str("schema", RESPONSE_SCHEMA_V2);
b.field_bool("success", true);
b.field_object("data", |d| {
d.field_str("command", "mcp manifest");
d.field_str("schema", MCP_MANIFEST_SCHEMA_V1);
d.field_str("version", env!("CARGO_PKG_VERSION"));
d.field_str("protocolVersion", MCP_PROTOCOL_VERSION);
d.field_object("adapter", |adapter| {
adapter.field_str("name", "ee");
adapter.field_str("transport", "stdio");
adapter.field_str("feature", "mcp");
adapter.field_bool("featureEnabled", cfg!(feature = "mcp"));
adapter.field_str("runtime", "asupersync");
adapter.field_str("businessLogic", "cli_core_services");
});
d.field_object("capabilities", |capabilities| {
capabilities.field_bool("tools", true);
capabilities.field_bool("resources", cfg!(feature = "mcp"));
capabilities.field_bool("prompts", cfg!(feature = "mcp"));
capabilities.field_bool("experimental", false);
});
if !cfg!(feature = "mcp") {
d.field_object("capabilityGap", |gap| {
gap.field_str("code", "mcp_feature_disabled");
gap.field_str("severity", "low");
gap.field_str(
"message",
"MCP stdio adapter feature is not enabled in this build.",
);
gap.field_str(
"repair",
"Build ee with the mcp feature enabled, or use the CLI surfaces directly.",
);
gap.field_str("feature", "mcp");
gap.field_str("capabilitiesCommand", "ee capabilities --json");
});
}
d.field_object("registry", |registry| {
registry.field_str("commandSource", "COMMAND_MANIFEST");
registry.field_str("schemaSource", "public_schemas");
registry.field_raw("commandCount", &COMMAND_MANIFEST.len().to_string());
registry.field_raw("schemaCount", &public_schemas().len().to_string());
});
d.field_array_of_objects("tools", COMMAND_MANIFEST, render_mcp_tool_manifest_entry);
// R-010 (Pass 2): bring `ee mcp manifest` into compliance with the
// AGENTS.md promise that the manifest exposes specific nested tools
// like `ee_curate_candidates`, `ee_memory_show`, `ee_memory_list`.
// Each subcommand becomes its own flat tool entry under
// `subcommandTools`, separate from but parallel to `tools`. This
// matches the MCP convention of flat tool surfaces while preserving
// the existing parent-command tool shape that downstream consumers
// already serialize against.
let subcommand_tools: Vec<SubcommandToolEntry> = COMMAND_MANIFEST
.iter()
.flat_map(|cmd| {
cmd.subcommands
.iter()
.map(move |sub| SubcommandToolEntry { parent: cmd, sub })
})
.collect();
d.field_array_of_objects(
"subcommandTools",
&subcommand_tools,
render_mcp_subcommand_tool_entry,
);
d.field_array_of_objects("schemas", public_schemas(), render_public_schema_entry);
d.field_raw("degraded", "[]");
});
b.field_raw("degraded", "[]");
b.finish()
}
fn render_mcp_tool_manifest_entry(obj: &mut JsonBuilder, cmd: &CommandEntry) {
let tool_name = format!("ee_{}", cmd.name.replace('-', "_"));
obj.field_str("name", &tool_name);
obj.field_str("command", cmd.name);
obj.field_str("description", cmd.description);
obj.field_bool("available", cmd.available);
obj.field_str("source", "public_command_manifest");
obj.field_str("responseEnvelope", RESPONSE_SCHEMA_V2);
obj.field_str("errorEnvelope", ERROR_SCHEMA_V2);
obj.field_array_of_objects("subcommands", cmd.subcommands, |sub, sc| {
sub.field_str("name", sc.name);
sub.field_str("description", sc.description);
});
obj.field_array_of_objects("args", cmd.args, |arg, a| {
arg.field_str("name", a.name);
arg.field_str("description", a.description);
arg.field_bool("required", a.required);
if let Some(default) = a.default {
arg.field_str("default", default);
}
});
obj.field_object("inputSchema", |schema| {
schema.field_str("type", "object");
schema.field_object("properties", |properties| {
properties.field_object("workspace", |workspace| {
workspace.field_str("type", "string");
workspace.field_str(
"description",
"Workspace path, equivalent to the CLI --workspace option.",
);
});
properties.field_object("args", |args| {
args.field_str("type", "array");
args.field_str("description", "Command-specific CLI arguments in order.");
args.field_object("items", |items| {
items.field_str("type", "string");
});
});
properties.field_object("json", |json| {
json.field_str("type", "boolean");
json.field_str("description", "Request the stable JSON response envelope.");
});
});
schema.field_raw("required", "[]");
});
}
fn render_public_schema_entry(obj: &mut JsonBuilder, schema: &SchemaEntry) {
obj.field_str("id", schema.id);
obj.field_str("version", schema.version);
obj.field_str("description", schema.description);
obj.field_str("category", schema.category);
}
/// R-010 (Pass 2): flat (parent, subcommand) pair for the manifest's
/// `subcommandTools` array. The lifetime is tied to `COMMAND_MANIFEST`'s
/// static storage, so no allocation per entry beyond the surrounding Vec.
struct SubcommandToolEntry {
parent: &'static CommandEntry,
sub: &'static SubcommandEntry,
}
fn render_mcp_subcommand_tool_entry(obj: &mut JsonBuilder, entry: &SubcommandToolEntry) {
let parent_normalized = entry.parent.name.replace('-', "_");
let sub_normalized = entry.sub.name.replace('-', "_");
let tool_name = format!("ee_{parent_normalized}_{sub_normalized}");
let command = format!("{} {}", entry.parent.name, entry.sub.name);
let parent_tool = format!("ee_{parent_normalized}");
obj.field_str("name", &tool_name);
obj.field_str("command", &command);
obj.field_str("description", entry.sub.description);
obj.field_bool("available", entry.parent.available);
obj.field_str("source", "public_command_manifest");
obj.field_str("responseEnvelope", RESPONSE_SCHEMA_V2);
obj.field_str("errorEnvelope", ERROR_SCHEMA_V2);
obj.field_str("parentTool", &parent_tool);
obj.field_str("parentCommand", entry.parent.name);
obj.field_object("inputSchema", |schema| {
schema.field_str("type", "object");
schema.field_object("properties", |properties| {
properties.field_object("workspace", |workspace| {
workspace.field_str("type", "string");
workspace.field_str(
"description",
"Workspace path, equivalent to the CLI --workspace option.",
);
});
properties.field_object("args", |args| {
args.field_str("type", "array");
args.field_str("description", "Subcommand-specific CLI arguments in order.");
args.field_object("items", |items| {
items.field_str("type", "string");
});
});
properties.field_object("json", |json| {
json.field_str("type", "boolean");
json.field_str("description", "Request the stable JSON response envelope.");
});
});
schema.field_raw("required", "[]");
});
}
/// Render the MCP adapter manifest as human-readable text.
#[must_use]
pub fn render_mcp_manifest_human() -> String {
let feature_status = if cfg!(feature = "mcp") {
"enabled"
} else {
"disabled"
};
let mut output = String::from("ee mcp manifest\n\n");
output.push_str(&format!("Protocol: {MCP_PROTOCOL_VERSION}\n"));
output.push_str(&format!("Feature: mcp ({feature_status})\n"));
output.push_str(&format!("Tools: {}\n", COMMAND_MANIFEST.len()));
output.push_str(&format!("Schemas: {}\n", public_schemas().len()));
if !cfg!(feature = "mcp") {
output.push_str("\nCapability gap: mcp_feature_disabled\n");
output.push_str("MCP stdio adapter feature is not enabled in this build.\n");
output.push_str("Inspect build-time gaps with `ee capabilities --json`.\n");
}
output.push_str("\nUse `ee mcp manifest --json` for the machine-readable manifest.\n");
output
}
/// Render the MCP adapter manifest as TOON.
#[must_use]
pub fn render_mcp_manifest_toon() -> String {
render_toon_from_json(&render_mcp_manifest_json())
}
pub fn render_toon_from_json(json: &str) -> String {
toon::json_to_toon(json).unwrap_or_else(|error| {
let message = escape_toon_quoted_string(&format!("TOON encoding failed: {error}"));
format!(
"schema: {ERROR_SCHEMA_V2}\nerror:\n code: toon_encoding_failed\n message: \"{message}\"\n severity: medium\n details:\n"
)
})
}
fn escape_toon_quoted_string(value: &str) -> String {
let mut escaped = String::with_capacity(value.len());
for c in value.chars() {
match c {
'"' => escaped.push_str("\\\""),
'\\' => escaped.push_str("\\\\"),
'\n' => escaped.push_str("\\n"),
'\r' => escaped.push_str("\\r"),
'\t' => escaped.push_str("\\t"),
c => escaped.push(c),
}
}
escaped
}
/// Legacy placeholder for backwards compatibility during transition.
#[must_use]
pub fn status_response_json() -> String {
render_status_json(&StatusReport::gather())
}
/// Legacy placeholder for backwards compatibility during transition.
#[must_use]
pub fn human_status() -> String {
render_status_human(&StatusReport::gather())
}
#[must_use]
pub fn help_text() -> &'static str {
"ee - durable memory substrate for coding agents\n\nUsage:\n ee status [--json]\n ee --version\n ee --help\n"
}
#[must_use]
pub fn schema_json() -> String {
let mut b = JsonBuilder::with_capacity(2048);
b.field_str("schema", RESPONSE_SCHEMA_V2);
b.field_bool("success", true);
b.field_object("data", |d| {
d.field_str("command", "schema");
d.field_str("schemaId", RESPONSE_SCHEMA_V2);
d.field_raw("definition", &response_schema_definition());
});
b.field_raw("degraded", "[]");
b.finish()
}
#[must_use]
pub fn help_json() -> String {
let mut b = JsonBuilder::with_capacity(4096);
b.field_str("schema", RESPONSE_SCHEMA_V2);
b.field_bool("success", true);
b.field_object("data", |d| {
d.field_str("command", "help");
d.field_str("binary", "ee");
d.field_str("version", env!("CARGO_PKG_VERSION"));
d.field_str("usage", "ee [OPTIONS] [COMMAND]");
d.field_str(
"description",
"Durable, local-first, explainable memory for coding agents.",
);
d.field_array_of_objects("globalOptions", GLOBAL_OPTIONS, |obj, opt| {
obj.field_str("name", opt.name);
obj.field_str("short", opt.short);
obj.field_str("description", opt.description);
obj.field_str("type", opt.opt_type);
});
d.field_array_of_objects("commands", COMMAND_MANIFEST, |obj, cmd| {
obj.field_str("name", cmd.name);
obj.field_str("description", cmd.description);
obj.field_bool("available", cmd.available);
if !cmd.subcommands.is_empty() {
obj.field_array_of_objects("subcommands", cmd.subcommands, |sub, sc| {
sub.field_str("name", sc.name);
sub.field_str("description", sc.description);
});
}
if !cmd.args.is_empty() {
obj.field_array_of_objects("args", cmd.args, |arg, a| {
arg.field_str("name", a.name);
arg.field_str("description", a.description);
arg.field_bool("required", a.required);
if let Some(def) = a.default {
arg.field_str("default", def);
}
});
}
});
});
b.field_raw("degraded", "[]");
b.finish()
}
struct GlobalOption {
name: &'static str,
short: &'static str,
description: &'static str,
opt_type: &'static str,
}
const GLOBAL_OPTIONS: &[GlobalOption] = &[
GlobalOption {
name: "--json",
short: "-j",
description: "Emit JSON output",
opt_type: "flag",
},
GlobalOption {
name: "--workspace",
short: "",
description: "Workspace root to operate on",
opt_type: "path",
},
GlobalOption {
name: "--no-color",
short: "",
description: "Disable colored diagnostics",
opt_type: "flag",
},
GlobalOption {
name: "--robot",
short: "",
description: "Use agent-oriented output defaults",
opt_type: "flag",
},
GlobalOption {
name: "--format",
short: "",
description: "Select output renderer (human|json|toon|jsonl|compact|hook|markdown|mermaid)",
opt_type: "enum",
},
GlobalOption {
name: "--fields",
short: "",
description: "Control output verbosity (minimal|summary|standard|full)",
opt_type: "enum",
},
GlobalOption {
name: "--max-output-tokens",
short: "",
description: "Cap estimated response tokens for machine output (ADR 0063 governor; env mirror EE_MAX_OUTPUT_TOKENS)",
opt_type: "integer",
},
GlobalOption {
name: "--schema",
short: "",
description: "Print JSON schema for response envelope",
opt_type: "flag",
},
GlobalOption {
name: "--help-json",
short: "",
description: "Print JSON-formatted help",
opt_type: "flag",
},
GlobalOption {
name: "--agent-docs",
short: "",
description: "Print agent-oriented documentation",
opt_type: "flag",
},
GlobalOption {
name: "--meta",
short: "",
description: "Include additional metadata in response",
opt_type: "flag",
},
GlobalOption {
name: "--shadow",
short: "",
description: "Shadow mode for decision plane tracking (off|compare|record)",
opt_type: "enum",
},
GlobalOption {
name: "--policy",
short: "",
description: "Policy ID to use for decision plane operations",
opt_type: "string",
},
GlobalOption {
name: "--cards",
short: "",
description: "Control cards output verbosity (none|summary|math|full)",
opt_type: "enum",
},
GlobalOption {
name: "--schema-version",
short: "",
description: "Select the response envelope schema version (v0|v1)",
opt_type: "enum",
},
GlobalOption {
name: "--legacy-schema",
short: "",
description: "Shortcut for `--schema-version v0` during the v0 compatibility window",
opt_type: "flag",
},
];
struct CommandArg {
name: &'static str,
description: &'static str,
required: bool,
default: Option<&'static str>,
}
struct SubcommandEntry {
name: &'static str,
description: &'static str,
}
struct CommandEntry {
name: &'static str,
description: &'static str,
available: bool,
subcommands: &'static [SubcommandEntry],
args: &'static [CommandArg],
}
const COMMAND_MANIFEST: &[CommandEntry] = &[
CommandEntry {
name: "agent-docs",
description: "Agent-oriented documentation for ee commands, contracts, and usage",
available: true,
subcommands: &[],
args: &[CommandArg {
name: "TOPIC",
description: "Documentation topic (guide, commands, contracts, schemas, paths, env, exit-codes, fields, errors, formats, examples, recipes)",
required: false,
default: None,
}],
},
CommandEntry {
name: "ask",
description: "Answer a direct question with citations or honest abstention",
available: true,
subcommands: &[],
args: &[CommandArg {
name: "QUESTION",
description: "Question to answer extractively from stored memories",
required: false,
default: None,
}],
},
CommandEntry {
name: "analyze",
description: "Analyze subsystem readiness and diagnostic posture",
available: true,
subcommands: &[SubcommandEntry {
name: "science-status",
description: "Report science analytics availability and degraded posture",
}],
args: &[],
},
CommandEntry {
name: "capabilities",
description: "Report feature availability, commands, and subsystem status",
available: true,
subcommands: &[],
args: &[],
},
CommandEntry {
name: "check",
description: "Quick posture summary: ready, degraded, or needs attention",
available: true,
subcommands: &[],
args: &[],
},
CommandEntry {
name: "diag",
description: "Run diagnostic commands for trust, quarantine, and streams",
available: true,
subcommands: &[SubcommandEntry {
name: "quarantine",
description: "Report quarantine status for import sources",
}],
args: &[],
},
CommandEntry {
name: "doctor",
description: "Run health checks on workspace and subsystems",
available: true,
subcommands: &[],
args: &[CommandArg {
name: "--fix-plan",
description: "Output structured repair plan",
required: false,
default: None,
}],
},
CommandEntry {
name: "eval",
description: "Run evaluation scenarios against fixtures",
available: true,
subcommands: &[
SubcommandEntry {
name: "run",
description: "Run one or more evaluation scenarios",
},
SubcommandEntry {
name: "list",
description: "List available evaluation scenarios",
},
],
args: &[],
},
CommandEntry {
name: "health",
description: "Quick health check with overall verdict",
available: true,
subcommands: &[],
args: &[],
},
CommandEntry {
name: "help",
description: "Print command help",
available: true,
subcommands: &[],
args: &[],
},
CommandEntry {
name: "import",
description: "Import memories and evidence from external sources",
available: true,
subcommands: &[SubcommandEntry {
name: "cass",
description: "Import from coding_agent_session_search",
}],
args: &[],
},
CommandEntry {
name: "index",
description: "Manage search indexes",
available: true,
subcommands: &[
SubcommandEntry {
name: "rebuild",
description: "Rebuild the search index",
},
SubcommandEntry {
name: "status",
description: "Inspect index health and generation",
},
],
args: &[],
},
CommandEntry {
name: "journal",
description: "Append-only agent observation journal",
available: true,
subcommands: &[
SubcommandEntry {
name: "append",
description: "Append one observation or a JSONL batch via --stdin",
},
SubcommandEntry {
name: "distill",
description: "Distill entries into curation candidates (dry-run default)",
},
SubcommandEntry {
name: "list",
description: "List journal entries newest-first with optional filters",
},
SubcommandEntry {
name: "show",
description: "Show one journal entry with structured sidecar",
},
],
args: &[],
},
CommandEntry {
name: "mcp",
description: "Inspect the optional MCP adapter manifest",
available: true,
subcommands: &[SubcommandEntry {
name: "manifest",
description: "Print the MCP tool and schema manifest",
}],
args: &[],
},
CommandEntry {
name: "remember",
description: "Store a new memory",
available: true,
subcommands: &[],
args: &[
CommandArg {
name: "CONTENT",
description: "Memory content to store",
required: true,
default: None,
},
CommandArg {
name: "--level",
description: "Memory level",
required: false,
default: Some("episodic"),
},
CommandArg {
name: "--kind",
description: "Memory kind",
required: false,
default: Some("fact"),
},
CommandArg {
name: "--field",
description: "Set a typed sidecar field declared by ee.memory.typed_fields.v2 (`NAME=VALUE`). Repeat `--field NAME=VALUE` for list-valued fields.",
required: false,
default: None,
},
CommandArg {
name: "--tags",
description: "Tags (comma-separated)",
required: false,
default: None,
},
CommandArg {
name: "--confidence",
description: "Confidence score (0.0-1.0)",
required: false,
default: Some("0.8"),
},
CommandArg {
name: "--source",
description: "Source provenance URI",
required: false,
default: None,
},
CommandArg {
name: "--sentinel",
description: "Attach a deterministic sentinel predicate (`KIND:TARGET`). Supported kinds: path_exists, file_hash_or_marker, json_schema_contains_field, config_key_exists, env_var_registered, degraded_code_fixture_exists, dependency_capability_present, command_help_contains_flag. Unknown kinds are rejected; run `ee sentinel explain` for target syntax.",
required: false,
default: None,
},
CommandArg {
name: "--revive-when",
description: "Attach a revive-when predicate (`KIND:TARGET`); the inverse of --sentinel. The memory records a dead or retired route, and a passing check signals its blocker has cleared and the memory should resurface. Revive predicates never gate serving. Same kinds and target syntax as --sentinel.",
required: false,
default: None,
},
CommandArg {
name: "--seal",
description: "Seal the memory: store only a blake3 content commitment plus metadata and withhold the content until `ee memory reveal <id>` supplies matching bytes. Proves a protocol or prediction was registered before its outcome was seen. Rejected with --reinforce, --sentinel/--revive-when, --idempotency-key, --global, git capture modes, and --batch.",
required: false,
default: None,
},
CommandArg {
name: "--dry-run",
description: "Perform dry run without storing",
required: false,
default: None,
},
],
},
CommandEntry {
name: "resume",
description: "Resume recent session end-state, open loops, and stale next steps",
available: true,
subcommands: &[],
args: &[
CommandArg {
name: "--sessions",
description: "Maximum recent session groups to return",
required: false,
default: Some("3"),
},
CommandArg {
name: "--database",
description: "Exact database path to resume from",
required: false,
default: None,
},
],
},
CommandEntry {
name: "playbook",
description: "Extract playbook rule candidates from repeated memory evidence",
available: true,
subcommands: &[SubcommandEntry {
name: "extract",
description: "Create curation candidates for repeated procedural rules",
}],
args: &[],
},
CommandEntry {
name: "rule",
description: "Direct procedural rule management",
available: true,
subcommands: &[
SubcommandEntry {
name: "add",
description: "Add a procedural rule with lifecycle and evidence metadata",
},
SubcommandEntry {
name: "list",
description: "List procedural rules with stable filters",
},
SubcommandEntry {
name: "show",
description: "Show one procedural rule with evidence and lifecycle metadata",
},
SubcommandEntry {
name: "mark",
description: "Record lifecycle evidence for a procedural rule",
},
SubcommandEntry {
name: "protect",
description: "Protect or unprotect a procedural rule",
},
SubcommandEntry {
name: "update",
description: "Update procedural rule metadata",
},
],
args: &[],
},
CommandEntry {
name: "schema",
description: "List or export public response schemas",
available: true,
subcommands: &[
SubcommandEntry {
name: "list",
description: "List all available public schemas",
},
SubcommandEntry {
name: "export",
description: "Export schema JSON definition",
},
],
args: &[],
},
CommandEntry {
name: "search",
description: "Search indexed memories and sessions",
available: true,
subcommands: &[],
args: &[
CommandArg {
name: "QUERY",
description: "Query string to search for",
required: true,
default: None,
},
CommandArg {
name: "--field",
description: "Filter a typed memory sidecar field with `NAME=VALUE` (exact), `NAME~VALUE` (contains), or `NAME^VALUE` (prefix); repeat `--field` to combine filters. Produce fields with repeatable `ee remember --field NAME=VALUE`; inspect ee.memory.typed_fields.v2 with `ee schema export ee.memory.typed_fields.v2 --json`.",
required: false,
default: None,
},
CommandArg {
name: "--limit",
description: "Maximum results",
required: false,
default: Some("10"),
},
CommandArg {
name: "--database",
description: "Database path",
required: false,
default: None,
},
CommandArg {
name: "--index-dir",
description: "Index directory path",
required: false,
default: None,
},
],
},
CommandEntry {
name: "status",
description: "Report workspace and subsystem readiness",
available: true,
subcommands: &[],
args: &[],
},
CommandEntry {
name: "version",
description: "Print the ee version",
available: true,
subcommands: &[],
args: &[],
},
// ─── Top-level commands surfaced in `ee --help` "Most-used" prelude
// and "Quick categories" that were previously missing from the
// machine-readable manifest. Each entry advertises the command to
// agents discovering capabilities through `--help-json`, the MCP
// tool manifest, and `ee introspect`.
CommandEntry {
name: "init",
description: "Initialize an ee workspace",
available: true,
subcommands: &[],
args: &[],
},
CommandEntry {
name: "note",
description: "Capture a memory with agent-friendly level/kind inference",
available: true,
subcommands: &[],
args: &[CommandArg {
name: "CONTENT",
description: "Memory content to store",
required: true,
default: None,
}],
},
CommandEntry {
name: "context",
description: "Soft-deprecated alias for `ee pack`",
available: true,
subcommands: &[],
args: &[CommandArg {
name: "TASK",
description: "Task description to assemble a context pack for",
required: true,
default: None,
}],
},
CommandEntry {
name: "orient",
description: "Run a read-only agent orientation bundle for a task",
available: true,
subcommands: &[],
args: &[CommandArg {
name: "TASK",
description: "Task description to orient around",
required: true,
default: None,
}],
},
CommandEntry {
name: "pack",
description: "Build, replay, or diff context packs",
available: true,
subcommands: &[
SubcommandEntry {
name: "build",
description: "Build a pack from an explicit query document",
},
SubcommandEntry {
name: "replay",
description: "Inspect the persisted selection ledger for a historical pack",
},
SubcommandEntry {
name: "diff",
description: "Compare two persisted pack ledgers",
},
],
args: &[],
},
CommandEntry {
name: "lens",
description: "Inspect reusable task lens policies for pack/search",
available: true,
subcommands: &[
SubcommandEntry {
name: "list",
description: "List built-in and workspace task lenses",
},
SubcommandEntry {
name: "explain",
description: "Explain one task lens and its effective overlay",
},
],
args: &[],
},
CommandEntry {
name: "why",
description: "Explain why a memory was stored, retrieved, or selected",
available: true,
subcommands: &[],
args: &[CommandArg {
name: "MEMORY_ID",
description: "Identifier of the memory to explain",
required: true,
default: None,
}],
},
CommandEntry {
name: "outcome",
description: "Record observed feedback about a memory or related target",
available: true,
subcommands: &[],
args: &[CommandArg {
name: "ID",
description: "Memory or target identifier",
required: true,
default: None,
}],
},
CommandEntry {
name: "memory",
description: "Manage stored memories (show, list, history, level, expire, drift, link, tags, revise, reveal)",
available: true,
subcommands: &[
SubcommandEntry {
name: "show",
description: "Show a memory with provenance, links, and audit trail",
},
SubcommandEntry {
name: "list",
description: "List filtered memories",
},
SubcommandEntry {
name: "history",
description: "Audit trail for a memory",
},
SubcommandEntry {
name: "level",
description: "Audited adjacent memory level transition",
},
SubcommandEntry {
name: "expire",
description: "Audited soft expiration without deleting rows",
},
SubcommandEntry {
name: "drift",
description: "Read-only provenance drift report for memories",
},
SubcommandEntry {
name: "link",
description: "List or create deterministic memory links",
},
SubcommandEntry {
name: "tags",
description: "Audited tag listing and mutation",
},
SubcommandEntry {
name: "revise",
description: "Preview or apply an immutable audited memory revision",
},
SubcommandEntry {
name: "reveal",
description: "Verify supplied bytes against a sealed memory's commitment and publish through the revise path; mismatches mutate nothing and are audited",
},
],
args: &[],
},
CommandEntry {
name: "workspace",
description: "Resolve and manage workspace identities and aliases",
available: true,
subcommands: &[
SubcommandEntry {
name: "resolve",
description: "Resolve the current workspace identity",
},
SubcommandEntry {
name: "list",
description: "List registered workspaces",
},
SubcommandEntry {
name: "alias",
description: "Manage workspace aliases for monorepo subscopes",
},
],
args: &[],
},
CommandEntry {
name: "insights",
description: "Bundle read-only operational insight sections for agents",
available: true,
subcommands: &[],
args: &[],
},
CommandEntry {
name: "swarm",
description: "Read-only coordination snapshot and preflight recommendations for agent swarms",
available: true,
subcommands: &[SubcommandEntry {
name: "brief",
description: "Compact coordination preflight bundle for crowded repos",
}],
args: &[],
},
CommandEntry {
name: "graph",
description: "Graph analytics, snapshots, and export artifacts",
available: true,
subcommands: &[
SubcommandEntry {
name: "export",
description: "Export a deterministic graph snapshot artifact",
},
SubcommandEntry {
name: "neighborhood",
description: "Expand around a memory/session/rule",
},
SubcommandEntry {
name: "centrality-refresh",
description: "Refresh PageRank / betweenness metrics",
},
],
args: &[],
},
CommandEntry {
name: "curate",
description: "Review curation proposals without silently mutating memory",
available: true,
subcommands: &[
SubcommandEntry {
name: "candidates",
description: "List pending curation candidates",
},
SubcommandEntry {
name: "validate",
description: "Run validation on a candidate",
},
SubcommandEntry {
name: "apply",
description: "Apply an accepted candidate",
},
],
args: &[],
},
CommandEntry {
name: "backup",
description: "Create, verify, and inspect local backups",
available: true,
subcommands: &[
SubcommandEntry {
name: "create",
description: "Create a verified backup with manifest",
},
SubcommandEntry {
name: "list",
description: "List existing backups",
},
SubcommandEntry {
name: "verify",
description: "Re-verify a backup against its manifest hashes",
},
SubcommandEntry {
name: "inspect",
description: "Inspect backup contents without restoring",
},
SubcommandEntry {
name: "restore",
description: "Restore a backup into an isolated side path",
},
],
args: &[],
},
CommandEntry {
name: "bootstrap",
description: "Compile docs into reviewable bootstrap candidates",
available: true,
subcommands: &[
SubcommandEntry {
name: "docs",
description: "Dry-run allowlisted docs into candidate proposals",
},
SubcommandEntry {
name: "apply",
description: "Materialize approved docs bootstrap candidates through curation",
},
],
args: &[],
},
CommandEntry {
name: "export",
description: "Export redacted local memory records as a portable JSONL artifact",
available: true,
subcommands: &[],
args: &[],
},
CommandEntry {
name: "handoff",
description: "Session handoff and resume capsules for agent continuity",
available: true,
subcommands: &[],
args: &[],
},
CommandEntry {
name: "audit",
description: "Operation audit timeline and inspection commands",
available: true,
subcommands: &[],
args: &[],
},
CommandEntry {
name: "migrate",
description: "Apply or inspect workspace schema migrations",
available: true,
subcommands: &[],
args: &[],
},
CommandEntry {
name: "proximity",
description: "Report pairwise min-cut proximity between two memories",
available: true,
subcommands: &[],
args: &[],
},
CommandEntry {
name: "share",
description: "Preview and consent-check outbound mesh sharing",
available: true,
subcommands: &[],
args: &[],
},
CommandEntry {
name: "mesh",
description: "Foreground local mesh operations for peers, status, export/import, and sync-once",
available: true,
subcommands: &[],
args: &[],
},
CommandEntry {
name: "focus",
description: "Show and manage passive active-memory focus state",
available: true,
subcommands: &[],
args: &[],
},
CommandEntry {
name: "introspect",
description: "Introspect ee's command, schema, and error maps",
available: true,
subcommands: &[],
args: &[],
},
CommandEntry {
name: "maintenance",
description: "Run explicit maintenance jobs without a daemon",
available: true,
subcommands: &[],
args: &[],
},
CommandEntry {
name: "preflight",
description: "Run, show, or close preflight risk assessments",
available: true,
subcommands: &[],
args: &[],
},
CommandEntry {
name: "support",
description: "Create or inspect redacted diagnostic support bundles",
available: true,
subcommands: &[],
args: &[],
},
CommandEntry {
name: "completion",
description: "Generate shell completion scripts for ee",
available: true,
subcommands: &[],
args: &[],
},
CommandEntry {
name: "update",
description: "Plan an update without mutating the installation",
available: true,
subcommands: &[],
args: &[],
},
CommandEntry {
name: "perf",
description: "Compare normalized performance artifacts without mutating state",
available: true,
subcommands: &[],
args: &[],
},
CommandEntry {
name: "config",
description: "Inspect and update workspace configuration",
available: true,
subcommands: &[],
args: &[],
},
CommandEntry {
name: "verify",
description: "Record and evaluate verification evidence for closure decisions",
available: true,
subcommands: &[],
args: &[],
},
CommandEntry {
name: "db",
description: "Inspect database state without mutation",
available: true,
subcommands: &[],
args: &[],
},
// ─── Remaining commands from `ee --help` Quick categories. These are
// agent-facing surfaces that an automated harness should be able to
// discover through `ee --help-json` / `ee introspect --json` /
// `ee mcp manifest --json` / `ee agent-docs commands`. Each
// description is the canonical short blurb from the human help.
CommandEntry {
name: "plan",
description: "Agent goal planner and command recipe resolver",
available: true,
subcommands: &[
SubcommandEntry {
name: "goal",
description: "Map a goal to a recipe and return a command plan",
},
SubcommandEntry {
name: "recipe",
description: "List or show recipe definitions",
},
SubcommandEntry {
name: "explain",
description: "Explain why a recipe was selected",
},
SubcommandEntry {
name: "recommend",
description: "Recommend recipes for a task based on memory and procedural rules",
},
],
args: &[],
},
CommandEntry {
name: "hook",
description: "Generate agent-harness recall, orientation, journal, and capture helpers",
available: true,
subcommands: &[
SubcommandEntry {
name: "claude-code",
description: "Generate or install Claude Code recall and journal hooks",
},
SubcommandEntry {
name: "codex",
description: "Generate or install Codex recall and journal hooks",
},
SubcommandEntry {
name: "gemini",
description: "Report Gemini hook support posture",
},
SubcommandEntry {
name: "git-readiness",
description: "Inspect local Git hooks for Agent Mail identity and retired command gates",
},
],
args: &[],
},
CommandEntry {
name: "agent",
description: "Detect and manage coding agent installations",
available: true,
subcommands: &[],
args: &[],
},
CommandEntry {
name: "economy",
description: "Memory economics: utility scores, attention budgets, maintenance debt",
available: true,
subcommands: &[],
args: &[],
},
CommandEntry {
name: "learn",
description: "Active learning agenda, uncertainty sampling, and knowledge gaps",
available: true,
subcommands: &[],
args: &[],
},
CommandEntry {
name: "lab",
description: "Counterfactual memory lab: capture, replay, and counterfactual task episodes",
available: true,
subcommands: &[],
args: &[],
},
CommandEntry {
name: "recorder",
description: "Record agent activity for outcomes and replay",
available: true,
subcommands: &[],
args: &[],
},
CommandEntry {
name: "rationale",
description: "Attach safe rationale traces to memories, packs, or recorder events",
available: true,
subcommands: &[],
args: &[],
},
CommandEntry {
name: "reflect",
description: "Create and inspect external reflection request handshakes",
available: true,
subcommands: &[
SubcommandEntry {
name: "propose",
description: "Create a request artifact and replay ledger row",
},
SubcommandEntry {
name: "request-ledger diagnostics",
description: "Inspect request ledger integrity and replay posture",
},
],
args: &[],
},
CommandEntry {
name: "procedure",
description: "Manage distilled procedures and skill capsules",
available: true,
subcommands: &[],
args: &[],
},
CommandEntry {
name: "rehearse",
description: "Rehearse EE command sequences in an isolated sandbox",
available: true,
subcommands: &[],
args: &[],
},
CommandEntry {
name: "workflow",
description: "Manage memory workflow lifecycle groups",
available: true,
subcommands: &[],
args: &[],
},
CommandEntry {
name: "model",
description: "Inspect the workspace model registry",
available: true,
subcommands: &[],
args: &[],
},
CommandEntry {
name: "job",
description: "Run and inspect explicit steward maintenance jobs",
available: true,
subcommands: &[],
args: &[],
},
CommandEntry {
name: "daemon",
description: "Run the optional maintenance daemon in foreground mode",
available: true,
subcommands: &[],
args: &[],
},
CommandEntry {
name: "serve",
description: "Report localhost HTTP/SSE adapter availability",
available: true,
subcommands: &[],
args: &[],
},
CommandEntry {
name: "causal",
description: "Trace causal chains over recorder runs, packs, preflights, tripwires, and procedures",
available: true,
subcommands: &[],
args: &[],
},
CommandEntry {
name: "claim",
description: "Manage and verify executable claims",
available: true,
subcommands: &[],
args: &[],
},
CommandEntry {
name: "certificate",
description: "List, show, and verify certificate records",
available: true,
subcommands: &[],
args: &[],
},
CommandEntry {
name: "artifact",
description: "Register and inspect narrow coding artifacts",
available: true,
subcommands: &[],
args: &[],
},
CommandEntry {
name: "coordination",
description: "Persist redaction-safe coordination fallback evidence",
available: true,
subcommands: &[],
args: &[],
},
CommandEntry {
name: "situation",
description: "Classify, compare, link (dry-run), show, or explain task situations",
available: true,
subcommands: &[],
args: &[],
},
CommandEntry {
name: "task-frame",
description: "Durable passive task frames and goal stacks",
available: true,
subcommands: &[],
args: &[],
},
CommandEntry {
name: "tripwire",
description: "List and check tripwires from preflight assessments",
available: true,
subcommands: &[],
args: &[],
},
CommandEntry {
name: "verification",
description: "Durable verification evidence ingestion and closure guidance",
available: true,
subcommands: &[],
args: &[],
},
CommandEntry {
name: "demo",
description: "List, run, and verify executable demos",
available: true,
subcommands: &[],
args: &[],
},
CommandEntry {
name: "install",
description: "Agent-safe installation checks and dry-run plans",
available: true,
subcommands: &[],
args: &[],
},
CommandEntry {
name: "outcome-quarantine",
description: "Review harmful-feedback quarantine rows",
available: true,
subcommands: &[],
args: &[],
},
CommandEntry {
name: "context-show",
description: "Retrieve a previously persisted context pack by ID",
available: true,
subcommands: &[],
args: &[],
},
CommandEntry {
name: "profile",
description: "Plan and apply host-adaptive operating profile configuration",
available: true,
subcommands: &[],
args: &[],
},
];
#[must_use]
pub fn render_introspect_json() -> String {
let mut b = JsonBuilder::with_capacity(8192);
b.field_str("schema", RESPONSE_SCHEMA_V2);
b.field_bool("success", true);
b.field_object("data", |d| {
d.field_str("command", "introspect");
d.field_str("version", env!("CARGO_PKG_VERSION"));
d.field_object("commands", |c| {
for cmd in COMMAND_MANIFEST {
c.field_object(cmd.name, |obj| {
obj.field_str("description", cmd.description);
obj.field_bool("available", cmd.available);
if !cmd.subcommands.is_empty() {
obj.field_array_of_objects("subcommands", cmd.subcommands, |sub, sc| {
sub.field_str("name", sc.name);
sub.field_str("description", sc.description);
});
}
if !cmd.args.is_empty() {
obj.field_raw("argCount", &cmd.args.len().to_string());
}
});
}
});
d.field_object("schemas", |s| {
for schema in public_schemas() {
s.field_object(schema.id, |obj| {
obj.field_str("version", schema.version);
obj.field_str("description", schema.description);
obj.field_str("category", schema.category);
});
}
});
d.field_object("errorCodes", |e| {
for code in ERROR_CODES {
e.field_object(code.code, |obj| {
obj.field_str("message", code.message);
obj.field_str("repair", code.repair);
obj.field_str("category", code.category);
});
}
});
d.field_object("globalOptions", |g| {
for opt in GLOBAL_OPTIONS {
g.field_object(opt.name, |obj| {
if !opt.short.is_empty() {
obj.field_str("short", opt.short);
}
obj.field_str("description", opt.description);
obj.field_str("type", opt.opt_type);
});
}
});
});
b.field_raw("degraded", "[]");
b.finish()
}
#[must_use]
pub fn render_introspect_human() -> String {
let mut output = format!("ee introspect (v{})\n\n", env!("CARGO_PKG_VERSION"));
output.push_str("Commands:\n");
for cmd in COMMAND_MANIFEST {
let status = if cmd.available { "✓" } else { "○" };
output.push_str(&format!(
" {} {} — {}\n",
status, cmd.name, cmd.description
));
}
output.push_str("\nSchemas:\n");
for schema in public_schemas() {
output.push_str(&format!(
" {} (v{}) — {}\n",
schema.id, schema.version, schema.description
));
}
output.push_str("\nError Codes:\n");
for code in ERROR_CODES {
output.push_str(&format!(" {} — {}\n", code.code, code.message));
}
output.push_str("\nNext:\n ee introspect --json\n");
output
}
#[must_use]
pub fn render_introspect_toon() -> String {
render_toon_from_json(&render_introspect_json())
}
struct ErrorCodeEntry {
code: &'static str,
message: &'static str,
repair: &'static str,
category: &'static str,
}
const ERROR_CODES: &[ErrorCodeEntry] = &[
ErrorCodeEntry {
code: "usage",
message: "Invalid command usage",
repair: "ee --help",
category: "cli",
},
ErrorCodeEntry {
code: "config",
message: "Configuration error",
repair: "ee doctor",
category: "config",
},
ErrorCodeEntry {
code: "storage",
message: "Storage operation failed",
repair: "ee doctor --fix-plan",
category: "storage",
},
ErrorCodeEntry {
code: "search_index",
message: "Search index error",
repair: "ee index rebuild",
category: "search",
},
ErrorCodeEntry {
code: "import",
message: "Import operation failed",
repair: "ee import cass --dry-run",
category: "import",
},
ErrorCodeEntry {
code: "degraded",
message: "Required capability is degraded",
repair: "ee status --json",
category: "degraded",
},
ErrorCodeEntry {
code: "policy",
message: "Operation denied by policy",
repair: "ee capabilities --json",
category: "policy",
},
ErrorCodeEntry {
code: "migration",
message: "Migration required",
repair: "ee doctor --fix-plan",
category: "storage",
},
// Output-governor degraded codes (ADR 0063): these arrive in
// `degraded[]`, not `error.code`, but agents triage them through the
// same code -> repair lookup.
ErrorCodeEntry {
code: "output_truncated_budget",
message: "Trailing elements dropped to satisfy --max-output-tokens",
repair: "Resume with --cursor <details.continuationCursor> or raise the ceiling",
category: "output",
},
ErrorCodeEntry {
code: "output_budget_unsatisfiable",
message: "Envelope minimum exceeds the output-token ceiling; response failed closed",
repair: "Raise --max-output-tokens or narrow the --fields preset",
category: "output",
},
ErrorCodeEntry {
code: "cursor_stale",
message: "DB generation advanced after the continuation cursor was issued",
repair: "Re-run without --cursor to start a fresh page sequence",
category: "output",
},
ErrorCodeEntry {
code: "cursor_invalid",
message: "Continuation cursor failed MAC, schema, or parameter validation",
repair: "Re-run without --cursor to start a fresh page sequence",
category: "output",
},
];
#[must_use]
pub fn agent_docs() -> String {
let report = crate::core::agent_docs::AgentDocsReport::gather(None);
render_agent_docs_json(&report)
}
fn strings_to_json_array(strings: &[String]) -> String {
let mut arr = String::from("[");
for (i, s) in strings.iter().enumerate() {
if i > 0 {
arr.push(',');
}
arr.push('"');
arr.push_str(&s.replace('\\', "\\\\").replace('"', "\\\""));
arr.push('"');
}
arr.push(']');
arr
}
#[must_use]
pub fn render_agent_detect_json(report: &InstalledAgentDetectionReport) -> String {
let mut b = JsonBuilder::with_capacity(2048);
b.field_str("schema", RESPONSE_SCHEMA_V2);
b.field_bool("success", true);
b.field_object("data", |d| {
d.field_str("command", "agent detect");
d.field_u32("formatVersion", report.format_version);
d.field_str("generatedAt", &report.generated_at);
d.field_object("summary", |s| {
s.field_u32("detectedCount", report.summary.detected_count as u32);
s.field_u32("totalCount", report.summary.total_count as u32);
});
d.field_array_of_objects("installedAgents", &report.installed_agents, |obj, agent| {
obj.field_str("slug", &agent.slug);
obj.field_bool("detected", agent.detected);
obj.field_raw("evidence", &strings_to_json_array(&agent.evidence));
obj.field_raw("rootPaths", &strings_to_json_array(&agent.root_paths));
});
});
b.field_raw("degraded", "[]");
b.finish()
}
#[must_use]
pub fn render_agent_detect_human(report: &InstalledAgentDetectionReport) -> String {
let mut out = String::with_capacity(1024);
out.push_str("Agent Detection Report\n");
out.push_str("======================\n\n");
out.push_str(&format!(
"Detected {} of {} known agent(s)\n\n",
report.summary.detected_count, report.summary.total_count
));
for agent in &report.installed_agents {
let status = if agent.detected {
"[detected]"
} else {
"[missing]"
};
out.push_str(&format!("{} {}\n", agent.slug, status));
for path in &agent.root_paths {
out.push_str(&format!(" - {}\n", path));
}
}
out
}
#[must_use]
pub fn render_agent_detect_toon(report: &InstalledAgentDetectionReport) -> String {
render_toon_from_json(&render_agent_detect_json(report))
}
#[must_use]
pub fn render_agent_status_json(report: &AgentInventoryReport) -> String {
let degraded = aggregate_agent_inventory_degradations(&report.degraded);
let mut b = JsonBuilder::with_capacity(2048);
b.field_str("schema", RESPONSE_SCHEMA_V2);
b.field_bool(
"success",
report.status != crate::core::agent_detect::AgentInventoryStatus::Unavailable,
);
b.field_object("data", |d| {
d.field_str("command", "agent status");
d.field_str("version", env!("CARGO_PKG_VERSION"));
render_agent_inventory_json(d, "inventory", report, true);
});
b.field_array_of_objects("degraded", °raded, build_aggregated_degradation);
b.finish()
}
#[must_use]
pub fn render_agent_status_human(report: &AgentInventoryReport) -> String {
let mut out = String::with_capacity(1024);
out.push_str("Agent Inventory\n");
out.push_str("===============\n\n");
out.push_str(&format!(
"Status: {}\nDetected: {} of {} known connector(s)\n\n",
report.status.as_str(),
report.summary.detected_count,
report.summary.total_count
));
for agent in &report.installed_agents {
let state = if agent.detected {
"detected"
} else {
"missing"
};
out.push_str(&format!("{} [{}]\n", agent.slug, state));
for path in &agent.root_paths {
out.push_str(&format!(" - {}\n", path));
}
}
let degraded = aggregate_agent_inventory_degradations(&report.degraded);
if !degraded.is_empty() {
out.push_str("\nDegraded:\n");
for degraded in °raded {
out.push_str(&format!(" - {}: {}\n", degraded.code, degraded.message));
}
}
out
}
#[must_use]
pub fn render_agent_status_toon(report: &AgentInventoryReport) -> String {
render_toon_from_json(&render_agent_status_json(report))
}
use crate::core::agent_docs::{
AGENT_CORE_COMMANDS, AGENT_DOC_RECIPES, AgentDocsReport, AgentDocsTopic, CONTRACTS,
DEFAULT_PATHS, EXAMPLES, EXIT_CODES, FIELD_LEVELS, GUIDE_SECTIONS, OUTPUT_FORMATS,
env_var_entries,
};
#[must_use]
pub fn render_agent_docs_json(report: &AgentDocsReport) -> String {
let mut b = JsonBuilder::with_capacity(8192);
b.field_str("schema", RESPONSE_SCHEMA_V2);
b.field_bool("success", true);
b.field_object("data", |d| {
d.field_str("command", "agent-docs");
d.field_str("version", report.version);
if let Some(topic) = report.topic {
d.field_str("topic", topic.as_str());
render_agent_docs_topic_json(d, topic);
} else {
d.field_str("topic", "overview");
d.field_str(
"description",
"Durable, local-first, explainable memory for coding agents.",
);
d.field_str(
"primaryWorkflow",
"ee pack \"<task>\" --workspace . --max-tokens 4000 --json",
);
let core_commands = AGENT_CORE_COMMANDS
.iter()
.map(|command| command.name)
.collect::<Vec<_>>();
d.field_array_of_strs("coreCommands", &core_commands);
d.field_str("recipeCatalogCommand", "ee agent-docs recipes --json");
d.field_raw("recipeCount", &AGENT_DOC_RECIPES.len().to_string());
d.field_array_of_strs(
"jqExamples",
&[
".data.topics[] | {name, description}",
".data.recipes[] | {id, command, jq}",
".data.results[] | {memoryId, score}",
".data.pack.items[] | {memoryId, section, why}",
],
);
// bd-13h5k: one authoritative place for agents to learn WHERE each
// command's results live. The result arrays use command-specific keys
// (not a universal `hits`), so spell them out explicitly.
d.field_object("responseFieldMap", |m| {
m.field_str("search", "data.results (count: data.resultCount)");
m.field_str(
"ask",
"data.answerText/data.citations or data.sides/data.nearestEvidence",
);
m.field_str("pack", "data.pack.items (omitted: data.pack.omitted)");
m.field_str(
"orient",
"data.pack.pack.items plus data.doctor/data.workspaceHygiene",
);
m.field_str("insights", "data.sections");
m.field_str("swarm brief", "data.recommendations");
m.field_str("memory list", "data.memories");
});
d.field_array_of_objects("topics", AgentDocsTopic::all(), |obj, topic| {
obj.field_str("name", topic.as_str());
obj.field_str("description", topic.description());
});
}
});
b.field_raw("degraded", "[]");
b.finish()
}
fn render_agent_docs_topic_json(d: &mut JsonBuilder, topic: AgentDocsTopic) {
match topic {
AgentDocsTopic::Guide => {
d.field_array_of_objects("sections", GUIDE_SECTIONS, |obj, section| {
obj.field_str("title", section.title);
obj.field_str("content", section.content);
});
}
AgentDocsTopic::Commands => {
d.field_array_of_objects("commands", COMMAND_MANIFEST, |obj, cmd| {
obj.field_str("name", cmd.name);
obj.field_str("description", cmd.description);
obj.field_bool("available", cmd.available);
if !cmd.subcommands.is_empty() {
obj.field_array_of_objects("subcommands", cmd.subcommands, |sub, sc| {
sub.field_str("name", sc.name);
sub.field_str("description", sc.description);
});
}
if !cmd.args.is_empty() {
obj.field_array_of_objects("args", cmd.args, |arg, a| {
arg.field_str("name", a.name);
arg.field_str("description", a.description);
arg.field_bool("required", a.required);
if let Some(def) = a.default {
arg.field_str("default", def);
}
});
}
});
}
AgentDocsTopic::Contracts => {
d.field_array_of_objects("contracts", CONTRACTS, |obj, contract| {
obj.field_str("name", contract.name);
obj.field_str("schema", contract.schema);
obj.field_str("description", contract.description);
obj.field_str("stability", contract.stability);
});
}
AgentDocsTopic::Schemas => {
let schemas = public_schemas();
d.field_array_of_objects("schemas", schemas, |obj, schema| {
obj.field_str("id", schema.id);
obj.field_str("version", schema.version);
obj.field_str("description", schema.description);
obj.field_str("category", schema.category);
});
}
AgentDocsTopic::Paths => {
d.field_array_of_objects("paths", DEFAULT_PATHS, |obj, path| {
obj.field_str("name", path.name);
obj.field_str("default", path.default);
obj.field_str("description", path.description);
if let Some(env) = path.env_override {
obj.field_str("envOverride", env);
}
});
}
AgentDocsTopic::Env => {
let env_vars = env_var_entries();
d.field_array_of_objects("envVars", &env_vars, |obj, var| {
obj.field_str("name", var.name);
obj.field_str("description", var.description);
obj.field_str("category", var.category);
if let Some(def) = var.default {
obj.field_str("default", def);
}
});
}
AgentDocsTopic::ExitCodes => {
d.field_array_of_objects("exitCodes", EXIT_CODES, |obj, code| {
obj.field_raw("code", &code.code.to_string());
obj.field_str("name", code.name);
obj.field_str("description", code.description);
});
}
AgentDocsTopic::Fields => {
d.field_array_of_objects("fieldLevels", FIELD_LEVELS, |obj, level| {
obj.field_str("name", level.name);
obj.field_str("flag", level.flag);
obj.field_str("includes", level.includes);
obj.field_str("useCase", level.use_case);
});
// The fields projection picks the SHAPE; the output governor
// (ADR 0063) sizes what remains. Surfaced here so agents reading
// the fields topic discover the full output economy.
d.field_object("outputBudget", |budget| {
budget.field_str("ceilingFlag", "--max-output-tokens");
budget.field_str("ceilingEnv", "EE_MAX_OUTPUT_TOKENS");
budget.field_str("resumeFlag", "--cursor");
budget.field_str(
"note",
"Fields presets choose shape; the ceiling enforces size; cursors resume \
truncated pages. See docs/agent-ux/output-budgets.md and ee capabilities \
--json at data.output.governor.",
);
});
}
AgentDocsTopic::Errors => {
d.field_array_of_objects("errorCodes", ERROR_CODES, |obj, code| {
obj.field_str("code", code.code);
obj.field_str("message", code.message);
obj.field_str("repair", code.repair);
obj.field_str("category", code.category);
});
}
AgentDocsTopic::Formats => {
d.field_array_of_objects("formats", OUTPUT_FORMATS, |obj, fmt| {
obj.field_str("name", fmt.name);
obj.field_str("flag", fmt.flag);
obj.field_str("description", fmt.description);
obj.field_bool("machineReadable", fmt.machine_readable);
});
}
AgentDocsTopic::Examples => {
d.field_array_of_objects("examples", EXAMPLES, |obj, example| {
obj.field_str("title", example.title);
obj.field_str("description", example.description);
obj.field_str("command", example.command);
obj.field_str("category", example.category);
});
}
AgentDocsTopic::Recipes => {
d.field_array_of_objects("recipes", AGENT_DOC_RECIPES, |obj, recipe| {
obj.field_str("id", recipe.id);
obj.field_str("title", recipe.title);
obj.field_str("description", recipe.description);
obj.field_str("category", recipe.category);
obj.field_str("command", recipe.command);
obj.field_str("jq", recipe.jq);
obj.field_str("successCheck", recipe.success_check);
obj.field_array_of_objects(
"failureBranches",
recipe.failure_branches,
|b, branch| {
b.field_str("condition", branch.condition);
b.field_str("jq", branch.jq);
b.field_str("nextAction", branch.next_action);
},
);
});
}
}
}
#[must_use]
pub fn render_agent_docs_human(report: &AgentDocsReport) -> String {
let mut output = String::with_capacity(2048);
output.push_str("ee agent-docs");
if let Some(topic) = report.topic {
output.push(' ');
output.push_str(topic.as_str());
}
output.push('\n');
output.push_str(&"-".repeat(40));
output.push('\n');
if let Some(topic) = report.topic {
render_agent_docs_topic_human(&mut output, topic);
} else {
output.push_str("\nDurable, local-first, explainable memory for coding agents.\n\n");
output.push_str(
"Primary workflow:\n ee pack \"<task>\" --workspace . --max-tokens 4000 --json\n\n",
);
output.push_str("Recipe catalog:\n ee agent-docs recipes --json\n\n");
output.push_str("Available topics:\n");
for t in AgentDocsTopic::all() {
output.push_str(&format!(" {:12} {}\n", t.as_str(), t.description()));
}
output.push_str("\nRun `ee agent-docs <topic>` for details.\n");
}
output
}
fn render_agent_docs_topic_human(output: &mut String, topic: AgentDocsTopic) {
match topic {
AgentDocsTopic::Guide => {
for section in GUIDE_SECTIONS {
output.push_str(&format!("\n{}:\n {}\n", section.title, section.content));
}
}
AgentDocsTopic::Commands => {
output.push_str("\nAvailable commands:\n");
for cmd in COMMAND_MANIFEST {
let status = if cmd.available {
""
} else {
" (unimplemented)"
};
output.push_str(&format!(
" {:16} {}{}\n",
cmd.name, cmd.description, status
));
for sub in cmd.subcommands {
output.push_str(&format!(" {:14} {}\n", sub.name, sub.description));
}
}
}
AgentDocsTopic::Contracts => {
output.push_str("\nStable output contracts:\n");
for contract in CONTRACTS {
output.push_str(&format!(
" {:12} {} ({})\n {}\n",
contract.name, contract.schema, contract.stability, contract.description
));
}
}
AgentDocsTopic::Schemas => {
output.push_str("\nPublic schemas:\n");
for schema in public_schemas() {
output.push_str(&format!(
" {:30} v{} [{}]\n {}\n",
schema.id, schema.version, schema.category, schema.description
));
}
}
AgentDocsTopic::Paths => {
output.push_str("\nDefault paths:\n");
for path in DEFAULT_PATHS {
output.push_str(&format!(" {:14} {}\n", path.name, path.default));
output.push_str(&format!(" {}\n", path.description));
if let Some(env) = path.env_override {
output.push_str(&format!(" Override: {}\n", env));
}
}
}
AgentDocsTopic::Env => {
output.push_str("\nEnvironment variables:\n");
let env_vars = env_var_entries();
for var in &env_vars {
let def = var
.default
.map_or(String::new(), |d| format!(" (default: {})", d));
output.push_str(&format!(
" {:20}{}\n {}\n",
var.name, def, var.description
));
}
}
AgentDocsTopic::ExitCodes => {
output.push_str("\nExit codes:\n");
for code in EXIT_CODES {
output.push_str(&format!(
" {:3} {:16} {}\n",
code.code, code.name, code.description
));
}
}
AgentDocsTopic::Fields => {
output.push_str("\nField profile levels:\n");
for level in FIELD_LEVELS {
output.push_str(&format!(" {:10} {}\n", level.name, level.flag));
output.push_str(&format!(" Includes: {}\n", level.includes));
output.push_str(&format!(" Use case: {}\n", level.use_case));
}
output.push_str(
"\nOutput budget: fields presets choose shape; --max-output-tokens (env \
EE_MAX_OUTPUT_TOKENS) enforces size; --cursor resumes truncated pages.\n\
See docs/agent-ux/output-budgets.md.\n",
);
}
AgentDocsTopic::Errors => {
output.push_str("\nError codes:\n");
for code in ERROR_CODES {
output.push_str(&format!(" {:16} [{}]\n", code.code, code.category));
output.push_str(&format!(" {}\n", code.message));
output.push_str(&format!(" Repair: {}\n", code.repair));
}
}
AgentDocsTopic::Formats => {
output.push_str("\nOutput formats:\n");
for fmt in OUTPUT_FORMATS {
let machine = if fmt.machine_readable {
" [machine]"
} else {
""
};
output.push_str(&format!(" {:10}{}\n", fmt.name, machine));
output.push_str(&format!(" Flag: {}\n", fmt.flag));
output.push_str(&format!(" {}\n", fmt.description));
}
}
AgentDocsTopic::Examples => {
output.push_str("\nCommon examples:\n");
for example in EXAMPLES {
output.push_str(&format!("\n {} [{}]\n", example.title, example.category));
output.push_str(&format!(" {}\n", example.description));
output.push_str(&format!(" $ {}\n", example.command));
}
}
AgentDocsTopic::Recipes => {
output.push_str("\nMachine-readable recipes:\n");
for recipe in AGENT_DOC_RECIPES {
output.push_str(&format!("\n {} [{}]\n", recipe.id, recipe.category));
output.push_str(&format!(" {}\n", recipe.description));
output.push_str(&format!(" $ {}\n", recipe.command));
output.push_str(&format!(" jq: {}\n", recipe.jq));
output.push_str(" Failure branches:\n");
for branch in recipe.failure_branches {
output.push_str(&format!(" - {}\n", branch.condition));
output.push_str(&format!(" jq: {}\n", branch.jq));
output.push_str(&format!(" next: {}\n", branch.next_action));
}
}
}
}
}
#[must_use]
pub fn render_agent_docs_toon(report: &AgentDocsReport) -> String {
render_toon_from_json(&render_agent_docs_json(report))
}
const MESH_APPROVAL_TOKEN_REDACTION_REASON: &str = "mesh_approval_token";
/// Remove mesh approval bearers at a public output boundary without changing
/// any other secret-like text. Match discovery stays centralized in policy;
/// this targeted projection consumes only the approval-token spans.
#[must_use]
pub(crate) fn redact_mesh_approval_bearers(text: &str) -> String {
let scan = redact_secret_like_content(text);
let mesh_was_redacted = scan
.redacted_reasons
.contains(&MESH_APPROVAL_TOKEN_REDACTION_REASON);
let mut spans = scan
.matches
.iter()
.filter(|matched| matched.pattern_id == MESH_APPROVAL_TOKEN_REDACTION_REASON)
.map(|matched| (matched.start, matched.end))
.collect::<Vec<_>>();
spans.sort_unstable();
spans.dedup();
if spans.is_empty() {
// The canonical scanner normally reports reasons and spans together.
// If those views ever drift, do not return text the scanner says held
// an approval bearer without a safe range to replace.
return if mesh_was_redacted {
redaction_placeholder(MESH_APPROVAL_TOKEN_REDACTION_REASON)
} else {
text.to_owned()
};
}
redact_mesh_approval_bearer_spans(text, &spans)
}
fn redact_mesh_approval_bearer_spans(text: &str, spans: &[(usize, usize)]) -> String {
let spans_are_safe = spans.iter().all(|&(start, end)| {
start < end
&& end <= text.len()
&& text.is_char_boundary(start)
&& text.is_char_boundary(end)
}) && spans.windows(2).all(|window| window[0].1 <= window[1].0);
if !spans_are_safe {
return redaction_placeholder(MESH_APPROVAL_TOKEN_REDACTION_REASON);
}
let placeholder = redaction_placeholder(MESH_APPROVAL_TOKEN_REDACTION_REASON);
let mut redacted = text.to_owned();
for &(start, end) in spans.iter().rev() {
redacted.replace_range(start..end, &placeholder);
}
redacted
}
#[must_use]
pub fn error_response_json(error: &DomainError) -> String {
let message = error.message();
let recovery_actions = error.recovery_actions();
let non_recoverable = error_non_recoverable(&recovery_actions);
let degraded = domain_error_degraded(error, &message);
tracing::warn!(
target: "ee::output::error",
schema = ERROR_SCHEMA_V2,
code = error.code(),
severity = domain_error_severity(error),
has_recovery = !recovery_actions.is_empty(),
has_nonrecoverable = non_recoverable,
"emitting error envelope"
);
let mut envelope = JsonBuilder::new();
envelope.field_str("schema", ERROR_SCHEMA_V2);
envelope.field_object("error", |obj| {
obj.field_str("code", error.code());
obj.field_str("message", &message);
obj.field_str("severity", domain_error_severity(error));
if let Some(repair) = error.repair() {
build_repair_fields(obj, repair);
}
obj.field_object("details", |details| {
domain_error_details(details, error, &recovery_actions);
});
if non_recoverable {
obj.field_bool("nonRecoverable", true);
}
});
if !degraded.is_empty() {
envelope.field_array_of_objects("degraded", °raded, render_error_degradation);
}
// Scrub only after the full envelope exists so caller-provided nested
// details and generated recovery fields cross the same egress boundary.
redact_mesh_approval_bearers(&envelope.finish())
}
struct ErrorDegradation {
code: &'static str,
severity: &'static str,
message: String,
repair: Option<String>,
}
fn domain_error_degraded(error: &DomainError, message: &str) -> Vec<ErrorDegradation> {
let lower_message = message.to_lowercase();
let code = error.code();
if code.starts_with("level_transition_") {
return vec![ErrorDegradation {
code,
severity: "medium",
message: format!("memory level transition degraded: {message}"),
repair: error.repair().map(str::to_owned),
}];
}
if matches!(
error,
DomainError::Import { .. } | DomainError::ImportWithDetails { .. }
) && (lower_message.contains("cass binary")
// bd-3twa9: the honest "found but untrusted" message does not contain
// "cass binary" (cass is not missing), but it is still cass-unavailable
// to ee until the operator opts in via EE_CASS_BINARY.
|| lower_message.contains("trusted execution allowlist"))
{
return vec![ErrorDegradation {
code: "cass_unavailable",
severity: "medium",
message: format!("cass unavailable: {message}"),
repair: error.repair().map(str::to_owned),
}];
}
if matches!(error, DomainError::Storage { .. })
&& lower_message.contains("advisory lock")
&& lower_message.contains("timeout")
{
return vec![ErrorDegradation {
code: crate::models::degradation::ADVISORY_LOCK_TIMEOUT_CODE,
severity: "medium",
message: format!("advisory lock timeout: {message}"),
repair: error.repair().map(str::to_owned),
}];
}
Vec::new()
}
fn render_error_degradation(obj: &mut JsonBuilder, degradation: &ErrorDegradation) {
obj.field_str("code", degradation.code);
obj.field_str("severity", degradation.severity);
obj.field_str("message", °radation.message);
if let Some(repair) = °radation.repair {
build_repair_fields(obj, repair);
}
}
#[must_use]
pub fn error_response_toon(error: &DomainError) -> String {
render_toon_from_json(&error_response_json(error))
}
fn domain_error_severity(error: &DomainError) -> &'static str {
if error.code().starts_with("level_transition_") {
return "medium";
}
if let DomainError::UsageCodeWithDetails { code, .. } = error {
match *code {
// Keep forged/malformed/wrong-context approval failures above the
// ordinary usage tier without disclosing which authentication
// check failed. Authentic expiry or snapshot drift is separately
// actionable, but remains a warning requiring a fresh preview.
"mesh_approval_token_invalid" => return "high",
"mesh_approval_token_stale" => return "warning",
"mesh_store_authentication_unavailable" => return "high",
_ => {}
}
}
if matches!(
error.code(),
"handoff_hmac_missing"
| "handoff_capsule_tampered"
| "handoff_capsule_machine_mismatch"
| "strict_mode_no_salt_file"
) {
return "critical";
}
if error.code().starts_with("handoff_") || error.code().starts_with("strict_mode_") {
return "high";
}
match error {
DomainError::Usage { .. }
| DomainError::UsageWithDetails { .. }
| DomainError::UsageCodeWithDetails { .. }
| DomainError::NotFound { .. } => "low",
DomainError::Storage { .. }
| DomainError::WorkspaceStoreMissing { .. }
| DomainError::MigrationDrift { .. } => "high",
DomainError::Configuration { .. }
| DomainError::SearchIndex { .. }
| DomainError::Graph { .. }
| DomainError::Import { .. }
| DomainError::ImportWithDetails { .. }
| DomainError::UnsatisfiedDegradedMode { .. }
| DomainError::UnsatisfiedDegradedModeCode { .. }
| DomainError::PolicyDenied { .. }
| DomainError::PolicyDeniedWithDetails { .. }
| DomainError::MigrationRequired { .. } => "medium",
}
}
fn domain_error_details(
details: &mut JsonBuilder,
error: &DomainError,
recovery_actions: &[RecoveryAction],
) {
match error {
DomainError::UsageWithDetails { details_json, .. }
| DomainError::UsageCodeWithDetails { details_json, .. }
| DomainError::ImportWithDetails { details_json, .. }
| DomainError::PolicyDeniedWithDetails { details_json, .. }
| DomainError::WorkspaceStoreMissing { details_json, .. } => {
append_domain_error_details(details, details_json);
}
_ => {}
}
if let DomainError::NotFound { resource, id, .. } = error {
details.field_str("resource", resource);
details.field_str("id", id);
}
if matches!(
error,
DomainError::Import { .. } | DomainError::ImportWithDetails { .. }
) && error
.message()
.to_lowercase()
.contains("cass binary not found")
{
details.field_array_of_strs(
"attemptedPaths",
&[
"/usr/local/bin/cass",
"/usr/bin/cass",
"/opt/homebrew/bin/cass",
],
);
}
if !recovery_actions.is_empty() {
details.field_array_of_objects("recovery", recovery_actions, build_recovery_action_fields);
}
}
fn error_non_recoverable(recovery_actions: &[RecoveryAction]) -> bool {
recovery_actions
.iter()
.any(|action| matches!(action.kind, RecoveryKind::None))
}
fn append_domain_error_details(details: &mut JsonBuilder, details_json: &str) {
let Ok(serde_json::Value::Object(map)) =
serde_json::from_str::<serde_json::Value>(details_json)
else {
return;
};
for (key, value) in map {
details.field_raw(&key, &value.to_string());
}
}
fn escape_mermaid_label(value: &str) -> String {
value
.replace('\\', "\\\\")
.replace('"', "\\\"")
.replace(['\n', '\r'], " ")
}
pub fn escape_json_string(s: &str) -> String {
let mut result = String::with_capacity(s.len());
for c in s.chars() {
match c {
'"' => result.push_str("\\\""),
'\\' => result.push_str("\\\\"),
'\n' => result.push_str("\\n"),
'\r' => result.push_str("\\r"),
'\t' => result.push_str("\\t"),
c if c.is_control() => {
result.push_str(&format!("\\u{:04x}", c as u32));
}
c => result.push(c),
}
}
result
}
// ============================================================================
// Field Profile Filtered Renderers (EE-037)
//
// These functions respect the `FieldProfile` setting to control output
// verbosity. Each level progressively includes more fields:
// - minimal: command, version, status only
// - summary: + top-level metrics and summary counts
// - standard: + arrays with items
// - full: + verbose details like provenance, why, debug info
// ============================================================================
/// Render a status report as JSON with field filtering.
#[must_use]
pub fn render_status_json_filtered(report: &StatusReport, profile: FieldProfile) -> String {
let mut b = JsonBuilder::with_capacity(512);
let degraded = aggregate_status_degradations("status", &report.degradations);
b.field_str("schema", RESPONSE_SCHEMA_V2);
b.field_bool("success", true);
b.field_str("fields", profile.as_str());
b.field_object("data", |d| {
d.field_str("command", "status");
d.field_str("version", report.version);
if let Some(workspace) = report.workspace.as_ref() {
render_workspace_status_json(d, workspace);
}
if profile.include_summary_metrics() {
render_status_posture_json(d, &report.posture);
render_singleflight_posture_json(d, &report.singleflight_posture);
render_write_group_commit_status_json(d, &report.write_group_commit);
render_flight_recorder_status_json(d, &report.flight_recorder);
render_qos_status_json(d, &report.qos_posture, profile.include_verbose_details());
render_rch_worker_pressure_json(d, &report.rch_worker_pressure);
render_verification_posture_json(d, &report.verification_posture);
render_rch_verify_ledger_status_json(d, &report.verification_ledger);
render_host_calibration_posture_json(d, report.host_calibration.as_ref());
if matches!(profile, FieldProfile::Summary) {
render_search_status_json(d, &report.lexical_ram_tier);
}
d.field_object("capabilities", |c| {
c.field_str("runtime", report.capabilities.runtime.as_str());
c.field_str("storage", report.capabilities.storage.as_str());
c.field_str("search", report.capabilities.search.as_str());
c.field_str("mesh", report.capabilities.mesh.as_str());
c.field_object("output", |output| {
output.field_str("toon", report.capabilities.output_toon.as_str());
});
c.field_str(
"agentDetection",
report.capabilities.agent_detection.as_str(),
);
});
}
if profile.include_arrays() {
d.field_object("runtime", |r| {
r.field_str("engine", report.runtime.engine);
r.field_str("profile", report.runtime.profile);
r.field_raw("workerThreads", &report.runtime.worker_threads.to_string());
r.field_str("asyncBoundary", report.runtime.async_boundary);
});
render_read_pool_status_json(d, &report.read_pool);
render_wal_status_json(d, &report.wal);
render_shard_fanout_status_json(d, &report.shard_fanout);
render_pack_budget_buckets_json(d, &report.pack_budget_buckets);
render_memory_health_json(d, &report.memory_health);
render_curation_health_json(d, &report.curation_health);
render_feedback_health_json(d, &report.feedback_health);
render_graph_compute_json(d, &report.graph_compute);
render_graph_snapshot_artifact_json(d, &report.graph_snapshot_artifact);
render_search_status_json(d, &report.lexical_ram_tier);
render_derived_assets_json(
d,
&report.derived_assets,
profile.include_verbose_details(),
);
render_mesh_status_json(
d,
report.mesh_storage.as_ref(),
report.tailscale_local.as_ref(),
);
render_agent_inventory_json(
d,
"agentInventory",
&report.agent_inventory,
profile.include_verbose_details(),
);
d.field_array_of_objects("degraded", °raded, build_aggregated_degradation);
}
});
b.field_array_of_objects("degraded", °raded, build_aggregated_degradation);
b.finish()
}
/// Render a capabilities report as JSON with field filtering.
#[must_use]
pub fn render_capabilities_json_filtered(
report: &CapabilitiesReport,
profile: FieldProfile,
) -> String {
let mut b = JsonBuilder::with_capacity(1024);
b.field_str("schema", RESPONSE_SCHEMA_V2);
b.field_bool("success", true);
b.field_str("fields", profile.as_str());
b.field_object("data", |d| {
d.field_str("command", "capabilities");
d.field_str("version", report.version);
if profile.include_arrays() {
d.field_array_of_objects("subsystems", &report.subsystems, |obj, sub| {
obj.field_str("name", sub.name);
obj.field_str("status", sub.status.as_str());
if profile.include_verbose_details() {
obj.field_str("description", sub.description);
}
});
d.field_array_of_objects("features", &report.features, |obj, feat| {
obj.field_str("name", feat.name);
obj.field_bool("enabled", feat.enabled);
if profile.include_verbose_details() {
obj.field_str("description", feat.description);
}
});
d.field_array_of_objects("unimplemented", &report.unimplemented, |obj, gap| {
obj.field_str("code", gap.code);
obj.field_str("featureFlag", gap.feature_flag);
obj.field_str("shipTarget", gap.ship_target);
obj.field_str("trackingBead", gap.tracking_bead);
if profile.include_verbose_details() {
obj.field_str("userMessage", gap.user_message);
}
});
d.field_array_of_objects("commands", &report.commands, |obj, cmd| {
obj.field_str("name", &cmd.name);
obj.field_bool("available", cmd.available);
if profile.include_verbose_details() {
obj.field_str("description", &cmd.description);
}
});
// Bead bd-17c65.6.4 (F4) — binaries + envOverrides in
// capabilities. Always emit regardless of profile (lite vs
// full) since these are critical for agent discoverability.
write_capabilities_binaries_block(d);
write_capabilities_env_overrides_block(d);
write_capabilities_index_block(d, report);
write_capabilities_output_metadata(d, report, true);
}
if profile.include_summary_metrics() {
d.field_object("summary", |s| {
s.field_raw(
"readySubsystems",
&report.ready_subsystem_count().to_string(),
);
s.field_raw("totalSubsystems", &report.subsystems.len().to_string());
s.field_raw(
"enabledFeatures",
&report.enabled_feature_count().to_string(),
);
s.field_raw("totalFeatures", &report.features.len().to_string());
s.field_raw(
"unimplementedCapabilities",
&report.unimplemented_count().to_string(),
);
s.field_raw(
"availableCommands",
&report.available_command_count().to_string(),
);
s.field_raw("totalCommands", &report.commands.len().to_string());
});
}
});
b.field_raw("degraded", "[]");
b.finish()
}
/// Render a doctor report as JSON with field filtering.
#[must_use]
pub fn render_doctor_json_filtered(report: &DoctorReport, profile: FieldProfile) -> String {
let mut b = JsonBuilder::with_capacity(512);
let mesh_auto_enrollment = if profile.include_summary_metrics() {
Some(render_doctor_mesh_auto_enrollment_json())
} else {
None
};
b.field_str("schema", RESPONSE_SCHEMA_V2);
// bd-2xdom Gap 4: envelope `success` means "command ran", not "system is healthy".
// System state is in `data.posture` (canonical) and `data.healthy` (deprecated alias).
b.field_bool("success", true);
b.field_raw("degraded", "[]");
b.field_str("fields", profile.as_str());
b.field_object("data", |d| {
d.field_str("command", "doctor");
d.field_str("version", report.version);
// Bead bd-17c65.5.1 (E1) — three-state posture.
d.field_str("posture", report.posture.as_str());
d.field_bool("healthy", report.overall_healthy);
if profile.include_summary_metrics() {
render_singleflight_posture_json(d, &report.singleflight_posture);
render_flight_recorder_status_json(d, &report.flight_recorder);
render_qos_status_json(d, &report.qos_posture, profile.include_verbose_details());
render_rch_worker_pressure_json(d, &report.rch_worker_pressure);
render_verification_posture_json(d, &report.verification_posture);
render_rch_verify_ledger_status_json(d, &report.verification_ledger);
render_host_calibration_posture_json(d, report.host_calibration.as_ref());
if let Some(mesh_auto_enrollment) = mesh_auto_enrollment.as_deref() {
d.field_raw("meshAutoEnrollment", mesh_auto_enrollment);
}
}
if profile.include_arrays() {
render_doctor_advisories_json(
d,
&report.checks,
profile.include_summary_metrics(),
profile.include_verbose_details(),
);
d.field_array_of_objects("checks", &report.checks, |obj, check| {
render_doctor_check_json(
obj,
check,
profile.include_summary_metrics(),
profile.include_verbose_details(),
);
});
}
});
b.finish()
}
/// Render a health report as JSON with field filtering.
#[must_use]
pub fn render_health_json_filtered(report: &HealthReport, profile: FieldProfile) -> String {
let mut b = JsonBuilder::with_capacity(512);
b.field_str("schema", RESPONSE_SCHEMA_V2);
b.field_bool("success", report.verdict.is_healthy());
b.field_str("fields", profile.as_str());
b.field_object("data", |d| {
d.field_str("command", "health");
d.field_str("version", report.version);
d.field_str("verdict", report.verdict.as_str());
if profile.include_summary_metrics() {
d.field_object("subsystems", |s| {
s.field_bool("runtime", report.runtime_ok);
s.field_bool("storage", report.storage_ok);
s.field_bool("search", report.search_ok);
});
d.field_object("summary", |s| {
s.field_raw("issueCount", &report.issue_count().to_string());
s.field_raw("highSeverity", &report.high_severity_count().to_string());
s.field_raw(
"mediumSeverity",
&report.medium_severity_count().to_string(),
);
});
}
if profile.include_arrays() {
d.field_array_of_objects("issues", &report.issues, |obj, issue| {
obj.field_str("subsystem", issue.subsystem);
obj.field_str("code", issue.code);
obj.field_str("severity", issue.severity);
obj.field_str("message", issue.message);
});
}
});
b.field_raw("degraded", "[]");
b.finish()
}
/// Render a check report as JSON with field filtering.
#[must_use]
pub fn render_check_json_filtered(report: &CheckReport, profile: FieldProfile) -> String {
let mut b = JsonBuilder::with_capacity(512);
b.field_str("schema", RESPONSE_SCHEMA_V2);
b.field_bool("success", report.posture.is_usable());
b.field_str("fields", profile.as_str());
b.field_object("data", |d| {
d.field_str("command", "check");
d.field_str("version", report.version);
d.field_str("posture", report.posture.as_str());
if profile.include_summary_metrics() {
d.field_bool("workspaceInitialized", report.workspace_initialized);
d.field_bool("databaseReady", report.database_ready);
d.field_bool("searchReady", report.search_ready);
d.field_bool("runtimeReady", report.runtime_ready);
}
if profile.include_arrays() {
d.field_array_of_objects(
"suggestedActions",
&report.suggested_actions,
|obj, action| {
obj.field_raw("priority", &action.priority.to_string());
obj.field_str("command", action.command);
if profile.include_verbose_details() {
obj.field_str("reason", action.reason);
}
},
);
}
});
b.field_raw("degraded", "[]");
b.finish()
}
/// Render a quarantine report as JSON with field filtering.
#[must_use]
pub fn render_quarantine_json_filtered(report: &QuarantineReport, profile: FieldProfile) -> String {
let degraded = aggregate_quarantine_degradations(&report.degraded);
let mut b = JsonBuilder::with_capacity(1024);
b.field_str("schema", RESPONSE_SCHEMA_V2);
b.field_bool("success", true);
b.field_str("fields", profile.as_str());
b.field_object("data", |d| {
d.field_str("command", "diag quarantine");
d.field_str("version", report.version);
d.field_str("storageStatus", report.storage_status.as_str());
if profile.include_summary_metrics() {
d.field_object("summary", |s| {
s.field_raw(
"quarantinedCount",
&report.summary.quarantined_count.to_string(),
);
s.field_raw("atRiskCount", &report.summary.at_risk_count.to_string());
s.field_raw("blockedCount", &report.summary.blocked_count.to_string());
s.field_raw("totalSources", &report.summary.total_sources.to_string());
s.field_raw("healthyCount", &report.summary.healthy_count.to_string());
});
}
if profile.include_arrays() {
let build_entry = |obj: &mut JsonBuilder, entry: &QuarantineEntry| {
let source_id = redact_quarantine_source_uri(&entry.source_id);
obj.field_str("sourceId", &source_id);
obj.field_str("advisory", entry.advisory.as_str());
obj.field_raw("effectiveTrust", &format!("{:.4}", entry.effective_trust));
if profile.include_verbose_details() {
obj.field_raw("decayFactor", &format!("{:.4}", entry.decay_factor));
obj.field_raw("negativeRate", &format!("{:.4}", entry.negative_rate));
obj.field_raw("negativeCount", &entry.negative_count.to_string());
obj.field_raw("totalImports", &entry.total_imports.to_string());
obj.field_str("message", &entry.message);
obj.field_bool("permitsImport", entry.permits_import);
obj.field_bool("requiresValidation", entry.requires_validation);
}
};
d.field_array_of_objects(
"quarantinedSources",
&report.quarantined_sources,
build_entry,
);
d.field_array_of_objects("atRiskSources", &report.at_risk_sources, build_entry);
d.field_array_of_objects("blockedSources", &report.blocked_sources, build_entry);
d.field_array_of_objects("degraded", °raded, build_aggregated_degradation);
}
});
b.field_array_of_objects("degraded", °raded, build_aggregated_degradation);
b.finish()
}
// ============================================================================
// EE-342: Certificate output renderers
// ============================================================================
use crate::core::certificate::{
CERTIFICATE_LIST_SCHEMA_V1, CERTIFICATE_SHOW_SCHEMA_V1, CERTIFICATE_STORE_UNAVAILABLE_CODE,
CERTIFICATE_VERIFY_SCHEMA_V1, CertificateListReport, CertificateShowReport,
CertificateStoreStatus, CertificateVerifyReport,
};
/// bd-79c16: render a JSON `degraded[]` entry for an unavailable certificate
/// store. Called from the certificate list/show/verify JSON renderers when
/// the report's `store_status` is `Unavailable`.
fn certificate_store_unavailable_degraded(reason: &str) -> String {
let mut b = JsonBuilder::with_capacity(256);
b.field_str("code", CERTIFICATE_STORE_UNAVAILABLE_CODE);
b.field_str("severity", "medium");
b.field_str(
"message",
"Certificate store could not be inspected; result reflects an absent backing store, not an empty store.",
);
b.field_str("repair", "Provide an explicit --manifest path, or run `ee init` and configure the workspace database before listing/showing/verifying certificates.");
b.field_object("details", |d| {
d.field_str("reason", reason);
});
let entry = b.finish();
format!("[{entry}]")
}
fn append_certificate_store_status_degraded(b: &mut JsonBuilder, status: &CertificateStoreStatus) {
if let Some(reason) = status.unavailable_reason() {
b.field_raw("degraded", &certificate_store_unavailable_degraded(reason));
}
}
#[must_use]
pub fn render_certificate_list_json(report: &CertificateListReport) -> String {
let mut b = JsonBuilder::with_capacity(1024);
b.field_str("schema", CERTIFICATE_LIST_SCHEMA_V1);
b.field_bool("success", true);
b.field_object("data", |d| {
d.field_str("command", "certificate list");
d.field_u32("totalCount", report.total_count);
d.field_u32("usableCount", report.usable_count);
d.field_u32("expiredCount", report.expired_count);
d.field_array_of_strings(
"kindsPresent",
&report
.kinds_present
.iter()
.map(|k| k.as_str().to_owned())
.collect::<Vec<_>>(),
);
d.field_array_of_objects("certificates", &report.certificates, |d, cert| {
d.field_str("id", &cert.id);
d.field_str("kind", cert.kind.as_str());
d.field_str("status", cert.status.as_str());
d.field_str("issuedAt", &cert.issued_at);
d.field_str("workspaceId", &cert.workspace_id);
d.field_bool("isUsable", cert.is_usable);
});
});
append_certificate_store_status_degraded(&mut b, &report.store_status);
b.finish()
}
#[must_use]
pub fn render_certificate_list_human(report: &CertificateListReport) -> String {
let mut out = String::new();
out.push_str(&format!(
"Certificates: {} total, {} usable, {} expired\n\n",
report.total_count, report.usable_count, report.expired_count
));
if report.certificates.is_empty() {
out.push_str("No certificates found.\n");
} else {
for cert in &report.certificates {
let status_marker = if cert.is_usable { "✓" } else { "✗" };
out.push_str(&format!(
" {} {} [{}] {}\n",
status_marker,
cert.id,
cert.kind.as_str(),
cert.status.as_str()
));
}
}
out
}
#[must_use]
pub fn render_certificate_list_toon(report: &CertificateListReport) -> String {
render_toon_from_json(&render_certificate_list_json(report))
}
#[must_use]
pub fn render_certificate_show_json(report: &CertificateShowReport) -> String {
let mut b = JsonBuilder::with_capacity(1024);
b.field_str("schema", CERTIFICATE_SHOW_SCHEMA_V1);
b.field_bool("success", true);
b.field_object("data", |d| {
d.field_str("command", "certificate show");
d.field_str("verificationStatus", report.verification_status.as_str());
d.field_str("payloadSummary", &report.payload_summary);
d.field_object("certificate", |d| {
d.field_str("id", &report.certificate.id);
d.field_str("kind", report.certificate.kind.as_str());
d.field_str("status", report.certificate.status.as_str());
d.field_str("workspaceId", &report.certificate.workspace_id);
d.field_str("issuedAt", &report.certificate.issued_at);
if let Some(ref expires) = report.certificate.expires_at {
d.field_str("expiresAt", expires);
}
d.field_str("payloadHash", &report.certificate.payload_hash);
d.field_bool("isUsable", report.certificate.is_usable());
});
});
append_certificate_store_status_degraded(&mut b, &report.store_status);
b.finish()
}
#[must_use]
pub fn render_certificate_show_human(report: &CertificateShowReport) -> String {
let mut out = String::new();
out.push_str(&format!("Certificate: {}\n", report.certificate.id));
out.push_str(&format!(" Kind: {}\n", report.certificate.kind.as_str()));
out.push_str(&format!(
" Status: {}\n",
report.certificate.status.as_str()
));
out.push_str(&format!(
" Workspace: {}\n",
report.certificate.workspace_id
));
out.push_str(&format!(" Issued: {}\n", report.certificate.issued_at));
if let Some(ref expires) = report.certificate.expires_at {
out.push_str(&format!(" Expires: {}\n", expires));
}
out.push_str(&format!(
" Payload Hash: {}\n",
report.certificate.payload_hash
));
out.push_str(&format!(
" Verification: {}\n",
report.verification_status.as_str()
));
out.push_str(&format!(" Summary: {}\n", report.payload_summary));
out
}
#[must_use]
pub fn render_certificate_show_toon(report: &CertificateShowReport) -> String {
render_toon_from_json(&render_certificate_show_json(report))
}
#[must_use]
pub fn render_certificate_verify_json(report: &CertificateVerifyReport) -> String {
let mut b = JsonBuilder::with_capacity(512);
b.field_str("schema", CERTIFICATE_VERIFY_SCHEMA_V1);
b.field_bool("success", report.is_valid());
b.field_object("data", |d| {
d.field_str("command", "certificate verify");
d.field_str("certificateId", &report.certificate_id);
d.field_str("result", report.result.as_str());
d.field_bool("valid", report.is_valid());
d.field_str("checkedAt", &report.checked_at);
d.field_bool("hashVerified", report.hash_verified);
d.field_bool("payloadHashFresh", report.payload_hash_fresh);
d.field_bool("schemaVersionValid", report.schema_version_valid);
d.field_bool("assumptionsValid", report.assumptions_valid);
d.field_bool("statusValid", report.status_valid);
d.field_bool("expiryValid", report.expiry_valid);
d.field_bool("attestationOk", report.attestation_ok);
if let Some(signer) = &report.signer {
d.field_str("signer", signer);
}
d.field_raw(
"mismatches",
&string_array_json(report.mismatches.iter().map(String::as_str)),
);
d.field_raw(
"failureCodes",
&string_array_json(report.failure_codes.iter().map(String::as_str)),
);
d.field_str("message", &report.message);
});
append_certificate_store_status_degraded(&mut b, &report.store_status);
b.finish()
}
#[must_use]
pub fn render_certificate_verify_human(report: &CertificateVerifyReport) -> String {
let mut out = String::new();
let status = if report.is_valid() {
"PASSED"
} else {
"FAILED"
};
out.push_str(&format!("Certificate Verification: {}\n\n", status));
out.push_str(&format!(" Certificate: {}\n", report.certificate_id));
out.push_str(&format!(" Result: {}\n", report.result.as_str()));
out.push_str(&format!(" Checked: {}\n", report.checked_at));
out.push_str(&format!(
" Hash Verified: {}\n",
if report.hash_verified { "yes" } else { "no" }
));
out.push_str(&format!(
" Payload Hash Fresh: {}\n",
if report.payload_hash_fresh {
"yes"
} else {
"no"
}
));
out.push_str(&format!(
" Schema Version Valid: {}\n",
if report.schema_version_valid {
"yes"
} else {
"no"
}
));
out.push_str(&format!(
" Assumptions Valid: {}\n",
if report.assumptions_valid {
"yes"
} else {
"no"
}
));
out.push_str(&format!(
" Status Valid: {}\n",
if report.status_valid { "yes" } else { "no" }
));
out.push_str(&format!(
" Expiry Valid: {}\n",
if report.expiry_valid { "yes" } else { "no" }
));
out.push_str(&format!(
" Attestation OK (content-hash, not a cryptographic signature): {}\n",
if report.attestation_ok { "yes" } else { "no" }
));
if let Some(signer) = &report.signer {
out.push_str(&format!(" Signer: {signer}\n"));
}
out.push_str(&format!(" Message: {}\n", report.message));
out
}
#[must_use]
pub fn render_certificate_verify_toon(report: &CertificateVerifyReport) -> String {
render_toon_from_json(&render_certificate_verify_json(report))
}
// ============================================================================
// EE-jfd9: Plan recommend and explain output renderers
// ============================================================================
use crate::core::plan::{PlanExplainReport, PlanRecommendReport, RecipeRecommendation};
fn write_recipe_recommendation(d: &mut JsonBuilder, rec: &RecipeRecommendation) {
d.field_str("recipeId", &rec.recipe_id);
d.field_str("recipeName", &rec.recipe_name);
d.field_str("category", rec.category.as_str());
d.field_raw("score", &rec.score.to_string());
d.field_raw("rank", &rec.rank.to_string());
d.field_raw("components", &serde_json::json!(rec.components).to_string());
d.field_str("sourceKind", rec.source_kind);
d.field_str("sourceId", &rec.source_id);
if let Some(maturity) = &rec.maturity {
d.field_str("maturity", maturity);
}
d.field_array_of_strings("evidenceUris", &rec.evidence_uris);
d.field_u32(
"stepsCount",
u32::try_from(rec.steps_count).unwrap_or(u32::MAX),
);
d.field_str("effectPosture", rec.effect_posture.as_str());
d.field_array_of_strings("matchReasons", &rec.match_reasons);
}
#[must_use]
pub fn render_plan_recommend_json(report: &PlanRecommendReport) -> String {
let mut b = JsonBuilder::with_capacity(1024);
b.field_str("schema", &report.schema);
b.field_bool("success", true);
b.field_object("data", |d| {
d.field_str("command", "plan recommend");
d.field_str("task", &report.task);
d.field_raw(
"recencyAnchor",
&serde_json::json!(report.recency_anchor).to_string(),
);
d.field_u32(
"totalRecipesConsidered",
u32::try_from(report.total_recipes_considered).unwrap_or(u32::MAX),
);
d.field_u32(
"matchesFound",
u32::try_from(report.matches_found).unwrap_or(u32::MAX),
);
d.field_array_of_objects(
"recommendations",
&report.recommendations,
write_recipe_recommendation,
);
});
b.field_raw("degraded", &serde_json::json!(report.degraded).to_string());
b.finish()
}
#[must_use]
pub fn render_plan_recommend_human(report: &PlanRecommendReport) -> String {
let mut out = String::with_capacity(1024);
out.push_str(&format!("Plan Recommendations for: {}\n", report.task));
out.push_str("==========================\n\n");
out.push_str(&format!(
"Considered {} recipes, found {} matches\n\n",
report.total_recipes_considered, report.matches_found
));
for (i, rec) in report.recommendations.iter().enumerate() {
out.push_str(&format!(
"{}. {} ({})\n",
i + 1,
rec.recipe_name,
rec.recipe_id
));
out.push_str(&format!(" Category: {}\n", rec.category.as_str()));
out.push_str(&format!(" Score: {:.6}\n", rec.score));
out.push_str(&format!(" Source: {}\n", rec.source_id));
if let Some(maturity) = &rec.maturity {
out.push_str(&format!(" Maturity: {maturity}\n"));
}
out.push_str(&format!(" Steps: {}\n", rec.steps_count));
out.push_str(&format!(" Effect: {}\n", rec.effect_posture.as_str()));
if !rec.match_reasons.is_empty() {
out.push_str(" Reasons:\n");
for reason in &rec.match_reasons {
out.push_str(&format!(" - {}\n", reason));
}
}
out.push('\n');
}
for degraded in &report.degraded {
if let Some(message) = degraded["message"].as_str() {
out.push_str(&format!("Degraded: {message}\n"));
}
}
out
}
#[must_use]
pub fn render_plan_recommend_toon(report: &PlanRecommendReport) -> String {
render_toon_from_json(&render_plan_recommend_json(report))
}
#[must_use]
pub fn render_plan_explain_json(report: &PlanExplainReport) -> String {
let mut b = JsonBuilder::with_capacity(512);
b.field_str("schema", &report.schema);
b.field_bool("success", report.found);
b.field_object("data", |d| {
d.field_str("command", "plan explain");
d.field_str("recipeId", &report.recipe_id);
d.field_bool("found", report.found);
if let Some(ref name) = report.recipe_name {
d.field_str("recipeName", name);
}
if let Some(ref category) = report.category {
d.field_str("category", category);
}
if let Some(ref description) = report.description {
d.field_str("description", description);
}
if let Some(ref when_to_use) = report.when_to_use {
d.field_str("whenToUse", when_to_use);
}
d.field_array_of_strings("steps", &report.steps);
if let Some(ref posture) = report.effect_posture {
d.field_str("effectPosture", posture);
}
if let Some(ref maturity) = report.maturity {
d.field_str("maturity", maturity);
}
d.field_array_of_strings("evidenceUris", &report.evidence_uris);
if let Some(source) = &report.source_id {
d.field_str("sourceId", source);
}
if let Some(kind) = &report.source_kind {
d.field_str("sourceKind", kind);
}
if let Some(evaluation) = &report.task_evaluation {
d.field_object("taskEvaluation", |d| {
d.field_str("task", &evaluation.task);
d.field_raw(
"recencyAnchor",
&serde_json::json!(evaluation.recency_anchor).to_string(),
);
d.field_raw(
"totalRecipesConsidered",
&evaluation.total_recipes_considered.to_string(),
);
d.field_raw("matchesFound", &evaluation.matches_found.to_string());
let matched = evaluation
.recommendations
.iter()
.find(|r| r.recipe_id == report.recipe_id);
d.field_bool("matched", matched.is_some());
if let Some(matched) = matched {
d.field_object("recommendation", |d| {
write_recipe_recommendation(d, matched)
});
} else {
d.field_str(
"reason",
"No text hit or semantic similarity of at least 0.5 for this task.",
);
}
let alternatives = evaluation
.recommendations
.iter()
.filter(|r| r.recipe_id != report.recipe_id)
.take(5)
.cloned()
.collect::<Vec<_>>();
d.field_bool(
"alternativesTruncated",
evaluation
.matches_found
.saturating_sub(usize::from(matched.is_some()))
> alternatives.len(),
);
d.field_array_of_objects(
"alternativesConsidered",
&alternatives,
write_recipe_recommendation,
);
});
}
});
if let Some(evaluation) = &report.task_evaluation {
b.field_raw(
"degraded",
&serde_json::json!(evaluation.degraded).to_string(),
);
}
b.finish()
}
#[must_use]
pub fn render_plan_explain_human(report: &PlanExplainReport) -> String {
let mut out = String::with_capacity(512);
if !report.found {
out.push_str(&format!("Recipe not found: {}\n", report.recipe_id));
return out;
}
out.push_str(&format!(
"Recipe: {} ({})\n",
report.recipe_name.as_deref().unwrap_or("unknown"),
report.recipe_id
));
out.push_str("========================\n\n");
if let Some(ref category) = report.category {
out.push_str(&format!("Category: {}\n", category));
}
if let Some(ref description) = report.description {
out.push_str(&format!("Description: {}\n", description));
}
if let Some(ref when_to_use) = report.when_to_use {
out.push_str(&format!("When to use: {}\n", when_to_use));
}
if let Some(ref posture) = report.effect_posture {
out.push_str(&format!("Effect posture: {}\n", posture));
}
if let Some(source) = &report.source_id {
out.push_str(&format!("Source: {source}\n"));
}
if let Some(maturity) = &report.maturity {
out.push_str(&format!("Maturity: {maturity}\n"));
}
for uri in &report.evidence_uris {
out.push_str(&format!("Evidence: {uri}\n"));
}
if !report.steps.is_empty() {
out.push_str("\nSteps:\n");
for (i, step) in report.steps.iter().enumerate() {
out.push_str(&format!(" {}. {}\n", i + 1, step));
}
}
if let Some(evaluation) = &report.task_evaluation {
out.push_str(&format!("\nTask: {}\n", evaluation.task));
if let Some(matched) = evaluation
.recommendations
.iter()
.find(|r| r.recipe_id == report.recipe_id)
{
out.push_str(&format!(
"Rank: {}; score: {:.6}\n",
matched.rank, matched.score
));
for reason in &matched.match_reasons {
out.push_str(&format!(" {reason}\n"));
}
} else {
out.push_str("No retrieval match for this task.\n");
}
for alternative in evaluation
.recommendations
.iter()
.filter(|r| r.recipe_id != report.recipe_id)
.take(5)
{
out.push_str(&format!(
"Alternative: {} ({:.6})\n",
alternative.recipe_id, alternative.score
));
}
for degraded in &evaluation.degraded {
if let Some(message) = degraded.get("message").and_then(serde_json::Value::as_str) {
out.push_str(&format!("Degraded: {message}\n"));
}
}
}
out
}
#[must_use]
pub fn render_plan_explain_toon(report: &PlanExplainReport) -> String {
render_toon_from_json(&render_plan_explain_json(report))
}
// ============================================================================
// EE-362: Claim verification output renderers
// ============================================================================
use crate::core::claims::{ClaimListReport, ClaimShowReport, ClaimVerifyReport};
#[must_use]
pub fn render_claim_list_json(report: &ClaimListReport) -> String {
let mut b = JsonBuilder::with_capacity(1024);
b.field_str("schema", report.schema);
b.field_bool("success", true);
b.field_object("data", |d| {
d.field_str("command", "claim list");
d.field_str("claimsFile", &report.claims_file);
d.field_bool("claimsFileExists", report.claims_file_exists);
d.field_u32("totalCount", report.total_count as u32);
d.field_u32("filteredCount", report.filtered_count as u32);
if let Some(ref s) = report.filter_status {
d.field_str("filterStatus", s);
}
if let Some(ref f) = report.filter_frequency {
d.field_str("filterFrequency", f);
}
if let Some(ref t) = report.filter_tag {
d.field_str("filterTag", t);
}
d.field_array_of_objects("claims", &report.claims, |d, claim| {
d.field_str("id", &claim.id);
d.field_str("title", &claim.title);
d.field_str("status", claim.status.as_str());
d.field_str("frequency", claim.frequency.as_str());
if let Some(ref owner) = claim.owner {
d.field_str("owner", owner);
}
if let Some(ref ttl) = claim.ttl {
d.field_str("ttl", ttl);
}
d.field_u32("evidenceCount", claim.evidence_count as u32);
d.field_u32("demoCount", claim.demo_count as u32);
});
});
b.finish()
}
#[must_use]
pub fn render_claim_list_human(report: &ClaimListReport) -> String {
let mut out = String::new();
if !report.claims_file_exists {
out.push_str("No claims.yaml found at ");
out.push_str(&report.claims_file);
out.push_str("\n\nTo create a claims file, add claims.yaml to your workspace root.\n");
return out;
}
out.push_str(&format!(
"Claims: {} total, {} after filters\n\n",
report.total_count, report.filtered_count
));
if report.claims.is_empty() {
out.push_str("No claims match the specified filters.\n");
} else {
for claim in &report.claims {
out.push_str(&format!(
" {} [{}] {}\n",
claim.id,
claim.status.as_str(),
claim.title
));
}
}
out
}
#[must_use]
pub fn render_claim_list_toon(report: &ClaimListReport) -> String {
render_toon_from_json(&render_claim_list_json(report))
}
#[must_use]
pub fn render_claim_show_json(report: &ClaimShowReport) -> String {
let mut b = JsonBuilder::with_capacity(1024);
b.field_str("schema", report.schema);
b.field_bool("success", report.found);
b.field_object("data", |d| {
d.field_str("command", "claim show");
d.field_str("claimId", &report.claim_id);
d.field_bool("found", report.found);
if let Some(ref claim) = report.claim {
d.field_object("claim", |d| {
d.field_str("id", &claim.id);
d.field_str("title", &claim.title);
d.field_str("description", &claim.description);
d.field_str("status", claim.status.as_str());
d.field_str("frequency", claim.frequency.as_str());
if let Some(ref owner) = claim.owner {
d.field_str("owner", owner);
}
if let Some(ref ttl) = claim.ttl {
d.field_str("ttl", ttl);
}
if let Some(ref pid) = claim.policy_id {
d.field_str("policyId", pid);
}
let evidence_ids = claim
.evidence_ids
.iter()
.map(String::as_str)
.collect::<Vec<_>>();
d.field_array_of_strs("evidenceIds", &evidence_ids);
d.field_array_of_objects("evidence", &claim.evidence, |d, evidence| {
d.field_str("kind", &evidence.kind);
d.field_str("target", &evidence.target);
if let Some(ref expected_hash) = evidence.expected_hash {
d.field_str("expectedHash", expected_hash);
}
if let Some(expected_exit) = evidence.expected_exit {
d.field_i32("expectedExit", expected_exit);
}
if let Some(ref expected_status) = evidence.expected_status {
d.field_str("expectedStatus", expected_status);
}
});
});
}
if report.include_manifest {
if let Some(ref manifest) = report.manifest {
d.field_object("manifest", |d| {
d.field_str("claimId", &manifest.claim_id);
d.field_u32("artifactCount", manifest.artifact_count as u32);
d.field_str("verificationStatus", manifest.verification_status.as_str());
if let Some(ref t) = manifest.last_verified_at {
d.field_str("lastVerifiedAt", t);
}
if let Some(ref t) = manifest.last_trace_id {
d.field_str("lastTraceId", t);
}
});
}
}
});
b.finish()
}
#[must_use]
pub fn render_claim_show_human(report: &ClaimShowReport) -> String {
let mut out = String::new();
if !report.found {
out.push_str(&format!("Claim not found: {}\n", report.claim_id));
return out;
}
if let Some(ref claim) = report.claim {
out.push_str(&format!("Claim: {}\n", claim.id));
out.push_str(&format!(" Title: {}\n", claim.title));
out.push_str(&format!(" Status: {}\n", claim.status.as_str()));
out.push_str(&format!(" Frequency: {}\n", claim.frequency.as_str()));
out.push_str(&format!(" Description: {}\n", claim.description));
}
out
}
#[must_use]
pub fn render_claim_show_toon(report: &ClaimShowReport) -> String {
render_toon_from_json(&render_claim_show_json(report))
}
#[must_use]
pub fn render_claim_verify_json(report: &ClaimVerifyReport) -> String {
let mut b = JsonBuilder::with_capacity(2048);
b.field_str("schema", report.schema);
b.field_bool("success", report.failed_count == 0);
b.field_object("data", |d| {
d.field_str("command", "claim verify");
d.field_str("claimId", &report.claim_id);
d.field_bool("verifyAll", report.verify_all);
d.field_str("claimsFile", &report.claims_file);
d.field_str("artifactsDir", &report.artifacts_dir);
d.field_u32("totalClaims", report.total_claims as u32);
d.field_u32("verifiedCount", report.verified_count as u32);
d.field_u32("failedCount", report.failed_count as u32);
d.field_u32("skippedCount", report.skipped_count as u32);
d.field_bool("failFast", report.fail_fast);
d.field_array_of_objects("results", &report.results, |d, result| {
d.field_str("claimId", &result.claim_id);
d.field_str("status", result.status.as_str());
d.field_u32("artifactsChecked", result.artifacts_checked as u32);
d.field_u32("artifactsPassed", result.artifacts_passed as u32);
d.field_u32("artifactsFailed", result.artifacts_failed as u32);
d.field_u32("evidenceChecked", result.evidence_checked as u32);
d.field_u32("evidencePassed", result.evidence_passed as u32);
d.field_u32("evidenceFailed", result.evidence_failed as u32);
if !result.errors.is_empty() {
let errors = result.errors.iter().map(String::as_str).collect::<Vec<_>>();
d.field_array_of_strs("errors", &errors);
}
});
});
b.finish()
}
#[must_use]
pub fn render_claim_verify_human(report: &ClaimVerifyReport) -> String {
let mut out = String::new();
out.push_str(&format!(
"Verification: {} verified, {} failed, {} skipped\n\n",
report.verified_count, report.failed_count, report.skipped_count
));
if report.results.is_empty() {
out.push_str("No claims to verify.\n");
} else {
for result in &report.results {
let icon = match result.status {
crate::models::ManifestVerificationStatus::Passing => "[PASS]",
crate::models::ManifestVerificationStatus::Failing => "[FAIL]",
_ => "[----]",
};
out.push_str(&format!(
" {} {} ({}/{} artifacts)\n",
icon, result.claim_id, result.artifacts_passed, result.artifacts_checked
));
}
}
out
}
#[must_use]
pub fn render_claim_verify_toon(report: &ClaimVerifyReport) -> String {
render_toon_from_json(&render_claim_verify_json(report))
}
// ============================================================================
// EE-DIAG-001: Support Bundle Rendering
// ============================================================================
use crate::core::support_bundle::{BundleReport, InspectReport};
#[must_use]
pub fn render_support_bundle_json(report: &BundleReport) -> String {
render_serialized_report_response(report, "BundleReport")
}
#[must_use]
pub fn render_support_bundle_human(report: &BundleReport) -> String {
let mut out = String::new();
let mode_str = if report.dry_run { "DRY RUN" } else { "CREATED" };
out.push_str(&format!("Support Bundle [{mode_str}]\n"));
if let Some(ref path) = report.output_path {
out.push_str(&format!("Output: {}\n", path.display()));
}
out.push_str(&format!(
"Redaction: {}\n",
if report.redaction_applied {
"enabled"
} else {
"disabled"
}
));
out.push_str(&format!("Size: {} bytes\n\n", report.total_size_bytes));
out.push_str("Files:\n");
for file in &report.files_collected {
out.push_str(&format!(" - {file}\n"));
}
out
}
#[must_use]
pub fn render_support_bundle_toon(report: &BundleReport) -> String {
render_toon_from_json(&render_support_bundle_json(report))
}
#[must_use]
pub fn render_support_inspect_json(report: &InspectReport) -> String {
render_serialized_report_response(report, "InspectReport")
}
#[must_use]
pub fn render_support_inspect_human(report: &InspectReport) -> String {
let mut out = String::new();
out.push_str("Support Bundle Inspection\n");
out.push_str(&format!("Path: {}\n", report.bundle_path.display()));
out.push_str(&format!("Files: {}\n", report.files_found.len()));
out.push_str(&format!("Total Size: {} bytes\n", report.total_size_bytes));
let hash_status = if report.hash_verified {
if report.hash_mismatches.is_empty() {
"passed"
} else {
"FAILED"
}
} else {
"not requested"
};
out.push_str(&format!("Hash Verification: {hash_status}\n"));
out.push_str(&format!(
"Valid: {}\n",
if report.valid { "yes" } else { "no" }
));
if let Some(ref manifest) = report.manifest {
out.push_str(&format!("Version: {}\n", manifest.ee_version));
}
out
}
#[must_use]
pub fn render_support_inspect_toon(report: &InspectReport) -> String {
render_toon_from_json(&render_support_inspect_json(report))
}
// ============================================================================
// EE-431: Memory Economics Rendering
// ============================================================================
use crate::core::economy::{
EconomyPrunePlan, EconomyReport, EconomyScoreReport, EconomySimulationReport,
};
#[must_use]
pub fn render_economy_report_json(report: &EconomyReport) -> String {
render_serialized_report_response(report, "EconomyReport")
}
#[must_use]
pub fn render_economy_report_human(report: &EconomyReport) -> String {
let mut out = String::new();
out.push_str("Economy Report\n");
out.push_str(&format!("Total Artifacts: {}\n", report.total_artifacts));
out.push_str(&format!(
"Overall Utility: {:.2}\n",
report.overall_utility_score
));
out.push_str(&format!(
"Attention Budget: {:.0}/{:.0} ({:.1}%)\n\n",
report.attention_budget_used,
report.attention_budget_total,
(report.attention_budget_used / report.attention_budget_total) * 100.0
));
out.push_str("Artifact Breakdown:\n");
for stats in &report.artifact_breakdown {
out.push_str(&format!(
" {}: {} items, avg utility {:.2}, cost {:.0}, false alarm {:.1}%\n",
stats.artifact_type,
stats.count,
stats.avg_utility,
stats.total_cost,
stats.false_alarm_rate * 100.0
));
}
if let Some(ref debt) = report.maintenance_debt {
out.push_str(&format!(
"\nMaintenance Debt: {} stale, {} consolidation candidates, {} pending tombstone\n",
debt.stale_artifacts, debt.consolidation_candidates, debt.tombstone_pending
));
}
if let Some(ref reserves) = report.tail_risk_reserves {
out.push_str(&format!(
"\nTail-Risk Reserves: {} critical memories, {} fallback procedures, {:.1}% degradation coverage\n",
reserves.critical_memories, reserves.fallback_procedures, reserves.degradation_coverage * 100.0
));
}
out
}
#[must_use]
pub fn render_economy_report_toon(report: &EconomyReport) -> String {
render_toon_from_json(&render_economy_report_json(report))
}
#[must_use]
pub fn render_economy_score_json(report: &EconomyScoreReport) -> String {
render_serialized_report_response(report, "EconomyScoreReport")
}
#[must_use]
pub fn render_economy_score_human(report: &EconomyScoreReport) -> String {
let mut out = String::new();
out.push_str(&format!(
"Economy Score: {} ({})\n",
report.artifact_id, report.artifact_type
));
out.push_str(&format!("Overall: {:.2}\n", report.overall_score));
out.push_str(&format!(" Utility: {:.2}\n", report.utility_score));
out.push_str(&format!(" Cost: {:.2}\n", report.cost_score));
out.push_str(&format!(" Freshness: {:.2}\n", report.freshness_score));
out.push_str(&format!(" Confidence: {:.2}\n", report.confidence_score));
if let Some(ref breakdown) = report.breakdown {
out.push_str("\nBreakdown:\n");
out.push_str(&format!(
" Retrieval frequency: {}\n",
breakdown.retrieval_frequency
));
out.push_str(&format!(
" Last accessed: {} days ago\n",
breakdown.last_accessed_days_ago
));
out.push_str(&format!(" Citation count: {}\n", breakdown.citation_count));
out.push_str(&format!(
" Confidence delta: {:.3}\n",
breakdown.confidence_delta
));
out.push_str(&format!(" Decay factor: {:.3}\n", breakdown.decay_factor));
}
out
}
#[must_use]
pub fn render_economy_score_toon(report: &EconomyScoreReport) -> String {
render_toon_from_json(&render_economy_score_json(report))
}
#[must_use]
pub fn render_economy_simulation_json(report: &EconomySimulationReport) -> String {
render_serialized_report_response(report, "EconomySimulationReport")
}
#[must_use]
pub fn render_economy_simulation_human(report: &EconomySimulationReport) -> String {
let mut out = String::new();
out.push_str("Economy Simulation\n");
out.push_str(&format!("Mutation: {}\n", report.mutation_status));
out.push_str(&format!(
"Ranking State Unchanged: {}\n",
report.ranking_state_unchanged
));
out.push_str(&format!(
"Baseline Budget: {} tokens\n",
report.baseline_budget_tokens
));
out.push_str(&format!(
"Recommended Budget: {} tokens\n",
report.summary.recommended_budget_tokens
));
out.push_str(&format!(
"Best Score: {:.3} ({:+.3} vs baseline)\n\n",
report.summary.best_score, report.summary.score_delta_vs_baseline
));
for scenario in &report.scenarios {
out.push_str(&format!(
"- {} tokens: score {:.3}, surfaced {}, reserve {} tokens\n",
scenario.budget_tokens,
scenario.score,
scenario.surfaced_count,
scenario.budget.risk_reserve_tokens
));
}
out
}
#[must_use]
pub fn render_economy_simulation_toon(report: &EconomySimulationReport) -> String {
render_toon_from_json(&render_economy_simulation_json(report))
}
#[must_use]
pub fn render_economy_prune_plan_json(report: &EconomyPrunePlan) -> String {
render_serialized_report_response(report, "EconomyPrunePlan")
}
#[must_use]
pub fn render_economy_prune_plan_human(report: &EconomyPrunePlan) -> String {
let mut out = String::new();
out.push_str("Economy Prune Plan\n");
out.push_str(&format!("Status: {}\n", report.status));
out.push_str(&format!("Dry Run: {}\n", report.dry_run));
out.push_str(&format!("Mutation: {}\n", report.mutation_status));
out.push_str(&format!(
"Recommendations: {}\n",
report.summary.recommendation_count
));
out.push_str(&format!(
"Estimated Token Savings: {}\n\n",
report.summary.estimated_token_savings
));
for recommendation in &report.recommendations {
out.push_str(&format!(
"- {} {} {} item(s): {} [priority {}, risk {}]\n",
recommendation.action,
recommendation.candidate_count,
recommendation.artifact_type,
recommendation.rationale,
recommendation.priority,
recommendation.risk
));
}
out
}
#[must_use]
pub fn render_economy_prune_plan_toon(report: &EconomyPrunePlan) -> String {
render_toon_from_json(&render_economy_prune_plan_json(report))
}
/// Schema identifier for shadow-run reports.
pub const SHADOW_RUN_SCHEMA_V1: &str = "ee.shadow_run.v1";
/// A single shadow-vs-incumbent comparison for decision plane tracking.
#[derive(Clone, Debug)]
pub struct ShadowRunComparison {
/// Which decision plane this comparison belongs to.
pub plane: DecisionPlane,
/// Tracking metadata (policy, decision, trace IDs).
pub metadata: DecisionPlaneMetadata,
/// When the decision was made.
pub decided_at: String,
/// The shadow policy's outcome.
pub shadow_outcome: String,
/// The incumbent policy's outcome.
pub incumbent_outcome: String,
/// Whether the outcomes differ.
pub diverged: bool,
/// Confidence score from the shadow decision.
pub confidence: Option<f64>,
/// Explanation for the shadow decision.
pub reason: Option<String>,
}
impl ShadowRunComparison {
#[must_use]
pub fn from_record(record: &DecisionRecord) -> Option<Self> {
if !record.shadow {
return None;
}
Some(Self {
plane: record.plane,
metadata: record.metadata.clone(),
decided_at: record.decided_at.clone(),
shadow_outcome: record.outcome.clone(),
incumbent_outcome: record.incumbent_outcome.clone().unwrap_or_default(),
diverged: record.incumbent_outcome.as_deref() != Some(&record.outcome),
confidence: record.confidence,
reason: record.reason.clone(),
})
}
}
/// Summary metrics for a shadow-run report.
#[derive(Clone, Debug, Default)]
pub struct ShadowRunSummary {
/// Total number of shadow decisions.
pub total: u32,
/// Number that diverged from incumbent.
pub diverged: u32,
/// Number that matched incumbent.
pub matched: u32,
/// Average confidence of shadow decisions (if available).
pub avg_confidence: Option<f64>,
}
/// Report for shadow-run comparisons.
#[derive(Clone, Debug)]
pub struct ShadowRunReport {
/// Schema identifier.
pub schema: String,
/// Command that generated this report.
pub command: String,
/// Policy ID being shadow-tested.
pub shadow_policy: String,
/// Incumbent policy for comparison.
pub incumbent_policy: String,
/// Individual comparisons.
pub comparisons: Vec<ShadowRunComparison>,
/// Summary metrics.
pub summary: ShadowRunSummary,
}
impl ShadowRunReport {
#[must_use]
pub fn new(shadow_policy: impl Into<String>, incumbent_policy: impl Into<String>) -> Self {
Self {
schema: SHADOW_RUN_SCHEMA_V1.to_owned(),
command: "shadow-run".to_owned(),
shadow_policy: shadow_policy.into(),
incumbent_policy: incumbent_policy.into(),
comparisons: Vec::new(),
summary: ShadowRunSummary::default(),
}
}
#[must_use]
pub fn with_command(mut self, command: impl Into<String>) -> Self {
self.command = command.into();
self
}
pub fn add_comparison(&mut self, comparison: ShadowRunComparison) {
if comparison.diverged {
self.summary.diverged += 1;
} else {
self.summary.matched += 1;
}
self.summary.total += 1;
self.comparisons.push(comparison);
}
pub fn add_from_record(&mut self, record: &DecisionRecord) {
if let Some(comparison) = ShadowRunComparison::from_record(record) {
self.add_comparison(comparison);
}
}
pub fn compute_avg_confidence(&mut self) {
let confidences: Vec<f64> = self
.comparisons
.iter()
.filter_map(|c| c.confidence)
.collect();
if !confidences.is_empty() {
let sum: f64 = confidences.iter().sum();
self.summary.avg_confidence = Some(sum / confidences.len() as f64);
}
}
#[must_use]
pub fn divergence_rate(&self) -> f64 {
if self.summary.total == 0 {
0.0
} else {
f64::from(self.summary.diverged) / f64::from(self.summary.total)
}
}
}
/// Render a shadow-run report as JSON.
#[must_use]
pub fn render_shadow_run_json(report: &ShadowRunReport) -> String {
let mut b = JsonBuilder::with_capacity(2048);
b.field_str("schema", &report.schema);
b.field_str("command", &report.command);
b.field_object("policies", |p| {
p.field_str("shadow", &report.shadow_policy);
p.field_str("incumbent", &report.incumbent_policy);
});
b.field_object("summary", |s| {
s.field_u32("total", report.summary.total);
s.field_u32("diverged", report.summary.diverged);
s.field_u32("matched", report.summary.matched);
let rate = format!("{:.4}", report.divergence_rate());
s.field_raw("divergenceRate", &rate);
if let Some(avg) = report.summary.avg_confidence {
let avg_str = format!("{:.4}", avg);
s.field_raw("avgConfidence", &avg_str);
}
});
b.field_array_of_objects("comparisons", &report.comparisons, |obj, c| {
obj.field_str("plane", c.plane.as_str());
obj.field_str("decidedAt", &c.decided_at);
obj.field_str("shadowOutcome", &c.shadow_outcome);
obj.field_str("incumbentOutcome", &c.incumbent_outcome);
obj.field_bool("diverged", c.diverged);
if let Some(conf) = c.confidence {
let conf_str = format!("{:.4}", conf);
obj.field_raw("confidence", &conf_str);
}
if let Some(reason) = &c.reason {
obj.field_str("reason", reason);
}
if let Some(policy_id) = &c.metadata.policy_id {
obj.field_str("policyId", policy_id);
}
if let Some(decision_id) = &c.metadata.decision_id {
obj.field_str("decisionId", decision_id);
}
if let Some(trace_id) = &c.metadata.trace_id {
obj.field_str("traceId", trace_id);
}
});
b.finish()
}
/// Render a shadow-run report as human-readable text.
#[must_use]
pub fn render_shadow_run_human(report: &ShadowRunReport) -> String {
let mut out = String::with_capacity(1024);
out.push_str("Shadow-Run Comparison Report\n");
out.push_str("============================\n\n");
out.push_str(&format!("Shadow policy: {}\n", report.shadow_policy));
out.push_str(&format!(
"Incumbent policy: {}\n\n",
report.incumbent_policy
));
out.push_str("Summary:\n");
out.push_str(&format!(" Total decisions: {}\n", report.summary.total));
out.push_str(&format!(
" Diverged: {}\n",
report.summary.diverged
));
out.push_str(&format!(" Matched: {}\n", report.summary.matched));
out.push_str(&format!(
" Divergence rate: {:.1}%\n",
report.divergence_rate() * 100.0
));
if let Some(avg) = report.summary.avg_confidence {
out.push_str(&format!(" Avg confidence: {:.2}\n", avg));
}
if !report.comparisons.is_empty() {
out.push_str("\nComparisons:\n");
for (i, c) in report.comparisons.iter().enumerate() {
let status = if c.diverged { "DIVERGED" } else { "MATCHED" };
out.push_str(&format!(
"\n {}. [{}] {} ({})\n",
i + 1,
status,
c.plane,
c.decided_at
));
out.push_str(&format!(" Shadow: {}\n", c.shadow_outcome));
out.push_str(&format!(" Incumbent: {}\n", c.incumbent_outcome));
if let Some(reason) = &c.reason {
out.push_str(&format!(" Reason: {}\n", reason));
}
if let Some(conf) = c.confidence {
out.push_str(&format!(" Confidence: {:.2}\n", conf));
}
}
}
out.push_str("\nNext:\n");
out.push_str(" ee shadow-run --policy <id> --json\n");
out
}
/// Render a shadow-run report as TOON.
#[must_use]
pub fn render_shadow_run_toon(report: &ShadowRunReport) -> String {
render_toon_from_json(&render_shadow_run_json(report))
}
// ============================================================================
// EE-382: Lab (Counterfactual Memory) Rendering
// ============================================================================
use crate::core::lab::{CaptureReport, CounterfactualReport, ReplayReport};
/// Render a lab capture report as JSON.
#[must_use]
pub fn render_lab_capture_json(report: &CaptureReport) -> String {
let json = serde_json::json!({
"schema": crate::models::RESPONSE_SCHEMA_V2,
"success": true,
"data": {
"episode_id": report.episode_id,
"workspace": report.workspace,
"task_input": report.task_input,
"packHash": report.pack_hash,
"policyIds": report.policy_ids,
"outcomeRef": report.outcome_ref,
"repositoryFingerprint": report.repository_fingerprint,
"evidenceIds": report.evidence_ids,
"redactionStatus": report.redaction_status,
"redactionClasses": report.redaction_classes,
"episodeHash": report.episode_hash,
"stored": report.stored,
"memories_captured": report.memories_captured,
"actions_captured": report.actions_captured,
"wal_retention_kind": report.wal_retention_kind,
"dry_run": report.dry_run,
"captured_at": report.captured_at,
},
"degraded": [],
});
json.to_string()
}
/// Render a lab capture report as human-readable text.
#[must_use]
pub fn render_lab_capture_human(report: &CaptureReport) -> String {
let mut lines = Vec::new();
if report.dry_run {
lines.push("Lab capture (dry run):".to_string());
} else {
lines.push("Lab capture:".to_string());
}
lines.push(format!(" Episode ID: {}", report.episode_id));
if !report.task_input.is_empty() {
lines.push(format!(" Task input: {}", report.task_input));
}
lines.push(format!(" Memories: {}", report.memories_captured));
lines.push(format!(" Actions: {}", report.actions_captured));
lines.push(format!(" WAL retention: {}", report.wal_retention_kind));
lines.push(format!(" Captured at: {}", report.captured_at));
lines.join("\n")
}
/// Render a lab capture report as TOON.
#[must_use]
pub fn render_lab_capture_toon(report: &CaptureReport) -> String {
format!(
"LAB_CAPTURE|{}|{}|{}|{}|{}",
report.episode_id,
report.memories_captured,
report.actions_captured,
report.wal_retention_kind,
if report.dry_run {
"dry_run"
} else {
"captured"
}
)
}
/// Render a lab replay report as JSON.
#[must_use]
pub fn render_lab_replay_json(report: &ReplayReport) -> String {
let degraded = lab_replay_degraded(report);
let json = serde_json::json!({
"schema": crate::models::RESPONSE_SCHEMA_V2,
"success": true,
"degraded": °raded,
"data": {
"episode_id": report.episode_id,
"replay_id": report.replay_id,
"status": report.status.as_str(),
"query": report.query,
"capturedPackHash": report.captured_pack_hash,
"replayedPackHash": report.replayed_pack_hash,
"matchesCaptureTimeHash": report.matches_capture_time_hash,
"queryMatchesCapture": report.query_matches_capture,
"replayedPack": report.replayed_pack,
"verifyDeterminism": report.verify_determinism,
"determinismDiff": report.determinism_diff,
"frozenInputs": report.frozen_inputs,
"replayEvidenceAvailable": report.replay_evidence_available,
"missingFrozenInputs": report.missing_frozen_inputs,
"mutableCurrentStateAccess": report.mutable_current_state_access,
"episodeHashVerified": report.episode_hash_verified,
"dry_run": report.dry_run,
"warnings": report.warnings,
"degraded": °raded,
"replayed_at": report.replayed_at,
}
});
json.to_string()
}
fn lab_replay_degraded(report: &ReplayReport) -> Vec<AggregatedDegradation> {
let mut codes = Vec::new();
for code in [
"lab_replay_unavailable",
"lab_replay_determinism_violation",
"lab_replay_nondeterministic",
] {
if report.warnings.iter().any(|warning| warning.contains(code)) {
codes.push(code);
}
}
aggregate_degraded_entries(
codes
.into_iter()
.map(|code| lab_degradation_input("lab_replay", code)),
)
}
fn lab_degradation_input(source: &'static str, code: &str) -> DegradationAggregationInput {
let (severity, message, repair) = match code {
"lab_replay_unavailable" => (
"medium",
"Lab replay evidence is unavailable because stored episode inputs are missing.",
"Capture or provide stored episodes before running lab replay or counterfactual analysis.",
),
"lab_replay_determinism_violation" => (
"high",
"Lab replay produced a pack hash that differs from the captured pack hash.",
"Inspect determinismDiff, restore the captured snapshot, or re-capture against current state.",
),
"lab_replay_nondeterministic" => (
"high",
"Lab replay produced non-identical packs across repeated deterministic replay runs.",
"Inspect verifyDeterminism and docs/volatile_field_registry.md before trusting replay output.",
),
"dry_run_no_durable_mutation" => (
"info",
"Lab counterfactual ran as a dry run and did not persist durable mutations.",
"Run without --dry-run after validating the counterfactual hypothesis.",
),
"lab_counterfactual_multi_swap_unsupported" => (
"medium",
"Lab counterfactual rejected multiple single-input swaps in one invocation.",
"Run separate counterfactual invocations and compose diffs externally; multi-swap is rejected by design (see ADR 0028).",
),
_ => (
"medium",
"Lab analysis completed with degraded evidence.",
"Inspect the lab output and provide the missing replay evidence.",
),
};
DegradationAggregationInput::new(source, code, severity, message, repair)
}
/// Render a lab replay report as human-readable text.
#[must_use]
pub fn render_lab_replay_human(report: &ReplayReport) -> String {
let mut lines = Vec::new();
if report.dry_run {
lines.push("Lab replay (dry run):".to_string());
} else {
lines.push("Lab replay:".to_string());
}
lines.push(format!(" Episode ID: {}", report.episode_id));
lines.push(format!(" Replay ID: {}", report.replay_id));
lines.push(format!(" Status: {}", report.status.as_str()));
lines.push(format!(
" Replay evidence available: {}",
report.replay_evidence_available
));
if let Some(pack_hash) = &report.replayed_pack_hash {
lines.push(format!(" Replayed pack hash: {pack_hash}"));
}
if let Some(matches) = report.matches_capture_time_hash {
lines.push(format!(" Matches capture-time pack: {matches}"));
}
if !report.missing_frozen_inputs.is_empty() {
lines.push(format!(
" Missing frozen inputs: {}",
report.missing_frozen_inputs.join(", ")
));
}
lines.push(format!(" Replayed at: {}", report.replayed_at));
lines.join("\n")
}
/// Render a lab replay report as TOON.
#[must_use]
pub fn render_lab_replay_toon(report: &ReplayReport) -> String {
format!(
"LAB_REPLAY|{}|{}|{}",
report.episode_id,
report.status.as_str(),
if report.dry_run {
"dry_run"
} else {
"replayed"
}
)
}
/// Render a lab counterfactual report as JSON.
#[must_use]
pub fn render_lab_counterfactual_json(report: &CounterfactualReport) -> String {
let degraded = lab_counterfactual_degraded(report);
let mut data = serde_json::json!({
"run_id": report.run_id,
"episode_id": report.episode_id,
"status": report.status.as_str(),
"observedPackHash": report.observed_pack_hash,
"counterfactualPackHash": report.counterfactual_pack_hash,
"changedItems": report.changed_items,
"confidenceState": report.confidence_state,
"assumptions": report.assumptions,
"degradationCodes": report.degradation_codes,
"degraded": degraded,
"nextAction": report.next_action,
"durableMutation": report.durable_mutation,
"curationCandidates": report.curation_candidates,
"claimStatus": report.claim_status,
"replayEvidenceAvailable": report.replay_evidence_available,
"behaviorClaims": report.behavior_claims,
"interventions_applied": report.interventions_applied,
"hypothesisRecords": report.hypothesis_records.len(),
"hypothesisKinds": report.hypothesis_records.iter().map(|record| &record.hypothesis_kind).collect::<Vec<_>>(),
"dry_run": report.dry_run,
"analyzed_at": report.analyzed_at,
});
if let Some(swap_summary) = &report.swap_summary {
data["swapSummary"] = serde_json::json!(swap_summary);
}
if let Some(pack_diff) = &report.pack_diff {
data["packDiff"] = serde_json::json!(pack_diff);
}
let json = serde_json::json!({
"schema": crate::models::RESPONSE_SCHEMA_V2,
"success": true,
"degraded": degraded,
"data": data
});
json.to_string()
}
fn lab_counterfactual_degraded(report: &CounterfactualReport) -> Vec<AggregatedDegradation> {
aggregate_degraded_entries(
report
.degradation_codes
.iter()
.map(|code| lab_degradation_input("lab_counterfactual", code)),
)
}
/// Render a lab counterfactual report as human-readable text.
#[must_use]
pub fn render_lab_counterfactual_human(report: &CounterfactualReport) -> String {
let mut lines = Vec::new();
if report.dry_run {
lines.push("Lab counterfactual (dry run):".to_string());
} else {
lines.push("Lab counterfactual:".to_string());
}
lines.push(format!(" Run ID: {}", report.run_id));
lines.push(format!(" Episode ID: {}", report.episode_id));
lines.push(format!(" Status: {}", report.status.as_str()));
lines.push(format!(" Interventions: {}", report.interventions_applied));
lines.push(format!(
" Behavior claims: {}",
report.behavior_claims.len()
));
if !report.hypothesis_records.is_empty() {
lines.push(format!(
" Hypothesis records: {}",
report.hypothesis_records.len()
));
for record in &report.hypothesis_records {
lines.push(format!(" - {}: {}", record.id, record.explanation));
}
}
lines.push(format!(" Analyzed at: {}", report.analyzed_at));
lines.join("\n")
}
/// Render a lab counterfactual report as TOON.
#[must_use]
pub fn render_lab_counterfactual_toon(report: &CounterfactualReport) -> String {
format!(
"LAB_COUNTERFACTUAL|{}|{}|{}|{}|{}",
report.run_id,
report.episode_id,
report.status.as_str(),
report.interventions_applied,
if report.dry_run {
"dry_run"
} else {
"executed"
}
)
}
// ============================================================================
// EE-391: Preflight Rendering
// ============================================================================
use crate::core::preflight::{CloseReport, RunReport, ShowReport};
/// Render a preflight run report as JSON.
#[must_use]
pub fn render_preflight_run_json(report: &RunReport) -> String {
let degraded = aggregate_preflight_degradations("preflight_run", &report.degraded);
let json = serde_json::json!({
"schema": crate::models::RESPONSE_SCHEMA_V2,
"success": true,
"data": {
"run_id": report.run_id,
"task_input": report.task_input,
"status": report.status,
"risk_level": report.risk_level,
"cleared": report.cleared,
"block_reason": report.block_reason,
"risk_brief_id": report.risk_brief_id,
"top_risks": report.top_risks,
"ask_now_prompts": report.ask_now_prompts,
"must_verify_checks": report.must_verify_checks,
"evidence_ids": report.evidence_ids,
"next_action": report.next_action,
"risks_identified": report.risks_identified,
"tripwires_set": report.tripwires_set,
"tripwires": report.tripwires,
"degraded": degraded,
"dry_run": report.dry_run,
"started_at": report.started_at,
"completed_at": report.completed_at,
}
});
json.to_string()
}
/// Render a preflight run report as human-readable text.
#[must_use]
pub fn render_preflight_run_human(report: &RunReport) -> String {
let mut lines = Vec::new();
if report.dry_run {
lines.push("Preflight run (dry run):".to_string());
} else {
lines.push("Preflight run:".to_string());
}
lines.push(format!(" Run ID: {}", report.run_id));
lines.push(format!(" Task: {}", report.task_input));
lines.push(format!(" Status: {}", report.status));
lines.push(format!(" Risk level: {}", report.risk_level));
lines.push(format!(" Cleared: {}", report.cleared));
if let Some(ref reason) = report.block_reason {
lines.push(format!(" Block reason: {}", reason));
}
lines.push(format!(" Started at: {}", report.started_at));
lines.join("\n")
}
/// Render a preflight run report as TOON.
#[must_use]
pub fn render_preflight_run_toon(report: &RunReport) -> String {
format!(
"PREFLIGHT_RUN|{}|{}|{}|{}",
report.run_id,
report.risk_level,
if report.cleared { "cleared" } else { "blocked" },
if report.dry_run {
"dry_run"
} else {
"executed"
}
)
}
/// Render a preflight show report as JSON.
#[must_use]
pub fn render_preflight_show_json(report: &ShowReport) -> String {
let degraded = aggregate_preflight_degradations("preflight_show", &report.degraded);
let json = serde_json::json!({
"schema": crate::models::RESPONSE_SCHEMA_V2,
"success": true,
"data": {
"run": report.run,
"brief": report.brief,
"tripwires": report.tripwires,
"degraded": degraded,
}
});
json.to_string()
}
fn aggregate_preflight_degradations(
source: &'static str,
degraded: &[crate::core::preflight::PreflightDegradation],
) -> Vec<AggregatedDegradation> {
aggregate_degraded_entries(degraded.iter().map(|entry| {
DegradationAggregationInput::new(
source,
entry.code.clone(),
entry.severity.clone(),
entry.message.clone(),
entry.repair.clone().unwrap_or_default(),
)
}))
}
/// Render a preflight show report as human-readable text.
#[must_use]
pub fn render_preflight_show_human(report: &ShowReport) -> String {
let mut lines = Vec::new();
lines.push("Preflight run details:".to_string());
lines.push(format!(" ID: {}", report.run.id));
lines.push(format!(" Task: {}", report.run.task_input));
lines.push(format!(" Status: {}", report.run.status));
lines.push(format!(" Risk level: {}", report.run.risk_level));
lines.push(format!(" Cleared: {}", report.run.cleared));
if let Some(ref reason) = report.run.block_reason {
lines.push(format!(" Block reason: {}", reason));
}
if let Some(ref brief) = report.brief {
lines.push(" Risk brief:".to_string());
lines.push(format!(" ID: {}", brief.id));
lines.push(format!(" Level: {}", brief.risk_level));
if let Some(ref summary) = brief.summary {
lines.push(format!(" Summary: {}", summary));
}
}
if !report.tripwires.is_empty() {
lines.push(format!(" Tripwires: {}", report.tripwires.len()));
}
lines.join("\n")
}
/// Render a preflight show report as TOON.
#[must_use]
pub fn render_preflight_show_toon(report: &ShowReport) -> String {
format!(
"PREFLIGHT_SHOW|{}|{}|{}",
report.run.id, report.run.risk_level, report.run.status
)
}
/// Render a preflight close report as JSON.
#[must_use]
pub fn render_preflight_close_json(report: &CloseReport) -> String {
let json = serde_json::json!({
"schema": crate::models::RESPONSE_SCHEMA_V2,
"success": true,
"data": {
"run_id": report.run_id,
"previous_status": report.previous_status,
"new_status": report.new_status,
"cleared": report.cleared,
"reason": report.reason,
"task_outcome": report.task_outcome,
"feedback": report.feedback,
"dry_run": report.dry_run,
"closed_at": report.closed_at,
},
"degraded": [],
});
json.to_string()
}
/// Render a preflight close report as human-readable text.
#[must_use]
pub fn render_preflight_close_human(report: &CloseReport) -> String {
let mut lines = Vec::new();
if report.dry_run {
lines.push("Preflight close (dry run):".to_string());
} else {
lines.push("Preflight closed:".to_string());
}
lines.push(format!(" Run ID: {}", report.run_id));
lines.push(format!(" Previous status: {}", report.previous_status));
lines.push(format!(" New status: {}", report.new_status));
lines.push(format!(" Cleared: {}", report.cleared));
if let Some(ref outcome) = report.task_outcome {
lines.push(format!(" Task outcome: {}", outcome));
}
if let Some(ref reason) = report.reason {
lines.push(format!(" Reason: {}", reason));
}
if let Some(ref feedback) = report.feedback {
lines.push(format!(" Feedback: {}", feedback.signal));
lines.push(format!(
" Score effect: utility {:+.2}, confidence {:+.2}, false alarms +{}",
feedback.score_effect.utility_delta,
feedback.score_effect.confidence_delta,
feedback.score_effect.false_alarm_delta
));
}
lines.push(format!(" Closed at: {}", report.closed_at));
lines.join("\n")
}
/// Render a preflight close report as TOON.
#[must_use]
pub fn render_preflight_close_toon(report: &CloseReport) -> String {
format!(
"PREFLIGHT_CLOSE|{}|{}|{}",
report.run_id,
report.new_status,
if report.dry_run { "dry_run" } else { "closed" }
)
}
// ============================================================================
// EE-411: Procedure Output Rendering
// ============================================================================
use crate::core::procedure::{
ProcedureDriftReport, ProcedureExportReport, ProcedureListReport, ProcedurePromoteReport,
ProcedureProposeReport, ProcedureRetireReport, ProcedureShowReport, ProcedureVerifyReport,
};
/// Render a procedure propose report as JSON.
#[must_use]
pub fn render_procedure_propose_json(report: &ProcedureProposeReport) -> String {
serde_json::json!({
"schema": report.schema,
"success": true,
"procedureId": report.procedure_id,
"title": report.title,
"summary": report.summary,
"status": report.status,
"sourceRunCount": report.source_run_count,
"evidenceCount": report.evidence_count,
"dryRun": report.dry_run,
"createdAt": report.created_at,
})
.to_string()
}
/// Render a procedure propose report as human-readable text.
#[must_use]
pub fn render_procedure_propose_human(report: &ProcedureProposeReport) -> String {
let mut out = String::with_capacity(512);
out.push_str(&format!("Procedure Proposed: {}\n\n", report.procedure_id));
out.push_str(&format!("Title: {}\n", report.title));
out.push_str(&format!("Summary: {}\n", report.summary));
out.push_str(&format!("Status: {}\n", report.status));
out.push_str(&format!("Source runs: {}\n", report.source_run_count));
out.push_str(&format!("Evidence items: {}\n", report.evidence_count));
if report.dry_run {
out.push_str("\n[dry-run: no changes made]\n");
}
out.push_str("\nNext:\n ee procedure show ");
out.push_str(&report.procedure_id);
out.push_str(" --json\n");
out
}
/// Render a procedure propose report as TOON.
#[must_use]
pub fn render_procedure_propose_toon(report: &ProcedureProposeReport) -> String {
format!(
"PROCEDURE_PROPOSE|{}|{}|{}",
report.procedure_id,
report.status,
if report.dry_run { "dry_run" } else { "created" }
)
}
/// Render a procedure show report as JSON.
#[must_use]
pub fn render_procedure_show_json(report: &ProcedureShowReport) -> String {
render_serialized_report_json(report, "ProcedureShowReport")
}
/// Render a procedure show report as human-readable text.
#[must_use]
pub fn render_procedure_show_human(report: &ProcedureShowReport) -> String {
let mut out = String::with_capacity(1024);
out.push_str(&format!("Procedure: {}\n", report.procedure.procedure_id));
out.push_str(&format!("Title: {}\n", report.procedure.title));
out.push_str(&format!("Status: {}\n", report.procedure.status));
out.push_str(&format!("Steps: {}\n\n", report.procedure.step_count));
out.push_str(&format!("Summary: {}\n\n", report.procedure.summary));
if !report.steps.is_empty() {
out.push_str("Steps:\n");
for step in &report.steps {
out.push_str(&format!(
" {}. {} {}\n",
step.sequence,
step.title,
if step.required { "" } else { "(optional)" }
));
out.push_str(&format!(" {}\n", step.instruction));
if let Some(ref hint) = step.command_hint {
out.push_str(&format!(" Command: {}\n", hint));
}
}
}
if let Some(ref v) = report.verification {
out.push_str(&format!("\nVerification: {}\n", v.status));
}
out.push_str("\nNext:\n ee procedure export ");
out.push_str(&report.procedure.procedure_id);
out.push_str(" --export-format markdown\n");
out
}
/// Render a procedure show report as TOON.
#[must_use]
pub fn render_procedure_show_toon(report: &ProcedureShowReport) -> String {
format!(
"PROCEDURE_SHOW|{}|{}|steps={}",
report.procedure.procedure_id, report.procedure.status, report.procedure.step_count
)
}
/// Render a procedure list report as JSON.
#[must_use]
pub fn render_procedure_list_json(report: &ProcedureListReport) -> String {
render_serialized_report_json(report, "ProcedureListReport")
}
/// Render a procedure list report as human-readable text.
#[must_use]
pub fn render_procedure_list_human(report: &ProcedureListReport) -> String {
let mut out = String::with_capacity(512);
out.push_str(&format!(
"Procedures: {} of {} shown\n\n",
report.filtered_count, report.total_count
));
if report.procedures.is_empty() {
out.push_str("No procedures found.\n");
} else {
for p in &report.procedures {
out.push_str(&format!(
" {} [{}] {} ({} steps)\n",
p.procedure_id, p.status, p.title, p.step_count
));
}
}
out.push_str("\nNext:\n ee procedure show <id> --json\n");
out
}
/// Render a procedure list report as TOON.
#[must_use]
pub fn render_procedure_list_toon(report: &ProcedureListReport) -> String {
format!(
"PROCEDURE_LIST|total={}|shown={}",
report.total_count, report.filtered_count
)
}
/// Render a procedure export report as JSON.
#[must_use]
pub fn render_procedure_export_json(report: &ProcedureExportReport) -> String {
serde_json::json!({
"schema": RESPONSE_SCHEMA_V2,
"success": true,
"data": {
"schema": report.schema,
"command": "procedure export",
"exportId": report.export_id,
"procedureId": report.procedure_id,
"format": report.format,
"artifactKind": report.artifact_kind,
"outputPath": report.output_path,
"content": report.content,
"contentLength": report.content_length,
"contentHash": report.content_hash,
"includesEvidence": report.includes_evidence,
"redactionStatus": report.redaction_status,
"installMode": report.install_mode,
"warnings": report.warnings,
"exportedAt": report.exported_at,
},
"degraded": [],
})
.to_string()
}
/// Render a procedure export report as human-readable text.
#[must_use]
pub fn render_procedure_export_human(report: &ProcedureExportReport) -> String {
if report.output_path.is_none() {
return report.content.clone();
}
let mut out = String::with_capacity(256);
out.push_str(&format!("Exported: {}\n", report.procedure_id));
out.push_str(&format!("Format: {}\n", report.format));
out.push_str(&format!("Artifact: {}\n", report.artifact_kind));
out.push_str(&format!("Size: {} bytes\n", report.content_length));
out.push_str(&format!("Hash: {}\n", report.content_hash));
if let Some(ref path) = report.output_path {
out.push_str(&format!("Output: {}\n", path));
}
out
}
/// Render a procedure export report as TOON.
#[must_use]
pub fn render_procedure_export_toon(report: &ProcedureExportReport) -> String {
format!(
"PROCEDURE_EXPORT|id={}|format={}|kind={}|bytes={}|hash={}",
report.procedure_id,
report.format,
report.artifact_kind,
report.content_length,
report.content_hash
)
}
/// Render a procedure promotion dry-run report as JSON.
#[must_use]
pub fn render_procedure_promote_json(report: &ProcedurePromoteReport) -> String {
serde_json::json!({
"schema": RESPONSE_SCHEMA_V2,
"success": true,
"data": {
"schema": report.schema,
"command": "procedure promote",
"promotionId": report.promotion_id,
"procedureId": report.procedure_id,
"dryRun": report.dry_run,
"status": report.status,
"fromStatus": report.from_status,
"toStatus": report.to_status,
"curation": report.curation,
"audit": report.audit,
"verification": report.verification,
"plannedEffects": report.planned_effects,
"warnings": report.warnings,
"nextActions": report.next_actions,
"generatedAt": report.generated_at,
},
"degraded": [],
})
.to_string()
}
/// Render a procedure promotion dry-run report as human-readable text.
#[must_use]
pub fn render_procedure_promote_human(report: &ProcedurePromoteReport) -> String {
let mut out = String::with_capacity(768);
out.push_str("Procedure Promotion [DRY RUN]\n\n");
out.push_str(&format!("Procedure: {}\n", report.procedure_id));
out.push_str(&format!(
"Status: {} -> {} ({})\n",
report.from_status, report.to_status, report.status
));
out.push_str(&format!(
"Curation candidate: {}\n",
report.curation.candidate_id
));
out.push_str(&format!("Audit operation: {}\n", report.audit.operation_id));
out.push_str(&format!(
"Verification: {} passed, {} failed, confidence {:.1}%\n",
report.verification.pass_count,
report.verification.fail_count,
report.verification.confidence * 100.0
));
if !report.planned_effects.is_empty() {
out.push_str("\nPlanned effects:\n");
for effect in &report.planned_effects {
out.push_str(&format!(
" - {} {} {} (would write: {}, applied: {})\n",
effect.surface,
effect.operation,
effect.target_id,
effect.would_write,
effect.applied
));
}
}
if !report.warnings.is_empty() {
out.push_str("\nWarnings:\n");
for warning in &report.warnings {
out.push_str(&format!(" - {warning}\n"));
}
}
if !report.next_actions.is_empty() {
out.push_str("\nNext:\n");
for action in &report.next_actions {
out.push_str(&format!(" {action}\n"));
}
}
out
}
/// Render a procedure-promotion curation plan as a deterministic Mermaid diagram.
#[must_use]
pub fn render_procedure_promote_mermaid(report: &ProcedurePromoteReport) -> String {
let mut output = String::from("flowchart TD\n");
output.push_str(&format!(
" procedure[\"procedure: {}\"]\n",
escape_mermaid_label(&report.procedure_id)
));
let curation_label = format!(
"curation: {} {}",
report.curation.candidate_id, report.curation.candidate_type
);
output.push_str(&format!(
" curation[\"{}\"]\n",
escape_mermaid_label(&curation_label)
));
output.push_str(" procedure --> curation\n");
let verification_label = format!(
"verification: {} pass {} fail {}",
report.verification.status, report.verification.pass_count, report.verification.fail_count
);
output.push_str(&format!(
" verification[\"{}\"]\n",
escape_mermaid_label(&verification_label)
));
output.push_str(" curation --> verification\n");
let audit_label = format!("audit: {}", report.audit.operation_id);
output.push_str(&format!(
" audit[\"{}\"]\n",
escape_mermaid_label(&audit_label)
));
output.push_str(" curation --> audit\n");
for (index, effect) in report.planned_effects.iter().enumerate() {
let node_id = format!("effect{}", index + 1);
let label = format!(
"{}: {} {}",
effect.surface, effect.operation, effect.target_id
);
output.push_str(&format!(
" {}[\"{}\"]\n",
node_id,
escape_mermaid_label(&label)
));
output.push_str(&format!(" curation --> {}\n", node_id));
}
output
}
/// Render a procedure promotion dry-run report as TOON.
#[must_use]
pub fn render_procedure_promote_toon(report: &ProcedurePromoteReport) -> String {
format!(
"PROCEDURE_PROMOTE|id={}|status={}|dry_run={}|effects={}|warnings={}",
report.procedure_id,
report.status,
report.dry_run,
report.planned_effects.len(),
report.warnings.len()
)
}
/// Render a procedure retire report as JSON.
#[must_use]
pub fn render_procedure_retire_json(report: &ProcedureRetireReport) -> String {
serde_json::json!({
"schema": RESPONSE_SCHEMA_V2,
"success": true,
"data": {
"schema": report.schema,
"command": "procedure retire",
"procedureId": report.procedure_id,
"status": report.status,
"fromMaturity": report.from_maturity,
"toMaturity": report.to_maturity,
"eventId": report.event_id,
"auditId": report.audit_id,
"reason": report.reason,
"retiredAt": report.retired_at,
},
"degraded": [],
})
.to_string()
}
/// Render a procedure retire report as human-readable text.
#[must_use]
pub fn render_procedure_retire_human(report: &ProcedureRetireReport) -> String {
let mut out = String::with_capacity(384);
out.push_str(&format!("Procedure Retired: {}\n\n", report.procedure_id));
out.push_str(&format!(
"Maturity: {} -> {}\n",
report.from_maturity, report.to_maturity
));
out.push_str(&format!("Reason: {}\n", report.reason));
out.push_str(&format!("Event: {}\n", report.event_id));
out.push_str(&format!("Audit: {}\n", report.audit_id));
out.push_str(&format!("Retired at: {}\n", report.retired_at));
out.push_str("\nNext:\n ee procedure show ");
out.push_str(&report.procedure_id);
out.push_str(" --json\n");
out
}
/// Render a procedure retire report as TOON.
#[must_use]
pub fn render_procedure_retire_toon(report: &ProcedureRetireReport) -> String {
format!(
"PROCEDURE_RETIRE|id={}|from={}|to={}|audit={}",
report.procedure_id, report.from_maturity, report.to_maturity, report.audit_id
)
}
/// Render a procedure verify report as JSON.
#[must_use]
pub fn render_procedure_verify_json(report: &ProcedureVerifyReport) -> String {
serde_json::json!({
"schema": RESPONSE_SCHEMA_V2,
"success": true,
"data": {
"schema": report.schema,
"command": "procedure verify",
"procedureId": report.procedure_id,
"verificationId": report.verification_id,
"status": report.status,
"sourceKind": report.source_kind,
"sourcesChecked": report.sources_checked,
"passCount": report.pass_count,
"failCount": report.fail_count,
"skipCount": report.skip_count,
"overallResult": report.overall_result,
"verifiedAt": report.verified_at,
"dryRun": report.dry_run,
"confidence": report.confidence,
"nextActions": report.next_actions,
},
"degraded": [],
})
.to_string()
}
/// Render a procedure verify report as human-readable text.
#[must_use]
pub fn render_procedure_verify_human(report: &ProcedureVerifyReport) -> String {
report.human_summary()
}
/// Render a procedure verify report as TOON.
#[must_use]
pub fn render_procedure_verify_toon(report: &ProcedureVerifyReport) -> String {
format!(
"PROCEDURE_VERIFY|id={}|status={}|result={}|passed={}|failed={}|skipped={}",
report.procedure_id,
report.status,
report.overall_result,
report.pass_count,
report.fail_count,
report.skip_count
)
}
/// Render a procedure drift report as JSON.
#[must_use]
pub fn render_procedure_drift_json(report: &ProcedureDriftReport) -> String {
serde_json::json!({
"schema": RESPONSE_SCHEMA_V2,
"success": true,
"data": {
"schema": report.schema,
"command": "procedure drift",
"procedureId": report.procedure_id,
"status": report.status,
"driftDetected": report.drift_detected,
"checkedAt": report.checked_at,
"stalenessThresholdDays": report.staleness_threshold_days,
"dryRun": report.dry_run,
"mutation": report.mutation,
"counts": report.counts,
"signals": report.signals,
"nextActions": report.next_actions,
},
"degraded": [],
})
.to_string()
}
/// Render a procedure drift report as human-readable text.
#[must_use]
pub fn render_procedure_drift_human(report: &ProcedureDriftReport) -> String {
let mut out = String::with_capacity(1024);
out.push_str("Procedure Drift [DRY RUN]\n\n");
out.push_str(&format!("Procedure: {}\n", report.procedure_id));
out.push_str(&format!("Status: {}\n", report.status));
out.push_str(&format!("Signals: {}\n", report.counts.total));
out.push_str(&format!("Checked: {}\n", report.checked_at));
if !report.signals.is_empty() {
out.push_str("\nSignals:\n");
for signal in &report.signals {
out.push_str(&format!(
" - {} [{}] {}: {}\n",
signal.kind, signal.severity, signal.source_id, signal.summary
));
out.push_str(&format!(" Next: {}\n", signal.recommended_action));
}
}
if !report.next_actions.is_empty() {
out.push_str("\nNext:\n");
for action in &report.next_actions {
out.push_str(&format!(" {action}\n"));
}
}
out
}
/// Render a procedure drift report as TOON.
#[must_use]
pub fn render_procedure_drift_toon(report: &ProcedureDriftReport) -> String {
format!(
"PROCEDURE_DRIFT|id={}|status={}|signals={}|high={}|medium={}|applied={}",
report.procedure_id,
report.status,
report.counts.total,
report.counts.high,
report.counts.medium,
report.mutation.applied
)
}
// ============================================================================
// EE-441: Learn Output Rendering
// ============================================================================
use crate::core::learn::{
LearnAgendaReport, LearnCloseReport, LearnClusterReport, LearnExperimentProposalReport,
LearnExperimentRunReport, LearnGapsReport, LearnObserveReport, LearnSummaryReport,
LearnUncertaintyReport,
};
/// Render a learn agenda report as JSON.
#[must_use]
pub fn render_learn_agenda_json(report: &LearnAgendaReport) -> String {
serde_json::json!({
"schema": report.schema,
"success": true,
"totalGaps": report.total_gaps,
"highPriorityCount": report.high_priority_count,
"resolvedCount": report.resolved_count,
"items": report.items,
"generatedAt": report.generated_at,
})
.to_string()
}
/// Render a learn agenda report as human-readable text.
#[must_use]
pub fn render_learn_agenda_human(report: &LearnAgendaReport) -> String {
let mut out = String::with_capacity(1024);
out.push_str("Learning Agenda\n\n");
out.push_str(&format!(
"Total gaps: {} ({} high priority, {} resolved)\n\n",
report.total_gaps, report.high_priority_count, report.resolved_count
));
for item in &report.items {
out.push_str(&format!(
"[{}] {} (priority: {}, uncertainty: {:.2})\n",
item.id, item.topic, item.priority, item.uncertainty
));
out.push_str(&format!(" {}\n", item.gap_description));
out.push_str(&format!(
" Status: {} | Source: {}\n\n",
item.status, item.source
));
}
out.push_str("Next:\n ee learn uncertainty --json\n");
out
}
/// Render a learn agenda report as TOON.
#[must_use]
pub fn render_learn_agenda_toon(report: &LearnAgendaReport) -> String {
format!(
"LEARN_AGENDA|total={}|high={}|resolved={}",
report.total_gaps, report.high_priority_count, report.resolved_count
)
}
/// Render a learn uncertainty report as JSON.
#[must_use]
pub fn render_learn_uncertainty_json(report: &LearnUncertaintyReport) -> String {
serde_json::json!({
"schema": report.schema,
"success": true,
"meanUncertainty": report.mean_uncertainty,
"highUncertaintyCount": report.high_uncertainty_count,
"samplingCandidates": report.sampling_candidates,
"items": report.items,
"generatedAt": report.generated_at,
})
.to_string()
}
/// Render a learn uncertainty report as human-readable text.
#[must_use]
pub fn render_learn_uncertainty_human(report: &LearnUncertaintyReport) -> String {
let mut out = String::with_capacity(1024);
out.push_str("Uncertainty Estimates\n\n");
out.push_str(&format!(
"Mean uncertainty: {:.2} ({} high, {} candidates)\n\n",
report.mean_uncertainty, report.high_uncertainty_count, report.sampling_candidates
));
for item in &report.items {
out.push_str(&format!(
"[{}] {} (uncertainty: {:.2}, confidence: {:.2})\n",
item.memory_id, item.kind, item.uncertainty, item.confidence
));
out.push_str(&format!(" {}\n", item.content));
out.push_str(&format!(
" Retrieval count: {}\n\n",
item.retrieval_count
));
}
out.push_str("Next:\n ee learn summary --json\n");
out
}
/// Render a learn uncertainty report as TOON.
#[must_use]
pub fn render_learn_uncertainty_toon(report: &LearnUncertaintyReport) -> String {
format!(
"LEARN_UNCERTAINTY|mean={:.2}|high={}|candidates={}",
report.mean_uncertainty, report.high_uncertainty_count, report.sampling_candidates
)
}
/// Render a learn cluster report as JSON.
#[must_use]
pub fn render_learn_cluster_json(report: &LearnClusterReport) -> String {
let degraded = learn_cluster_degraded_json(report);
serde_json::json!({
"schema": report.schema,
"success": true,
"workspaceId": report.workspace_id,
"threshold": report.threshold,
"minClusterSize": report.min_cluster_size,
"memoryCount": report.memory_count,
"clusteredMemoryCount": report.clustered_memory_count,
"clusterCount": report.cluster_count,
"clusters": report.clusters,
"degradations": report.degradations,
"degraded": degraded,
"generatedAt": report.generated_at,
})
.to_string()
}
fn learn_cluster_degraded_json(report: &LearnClusterReport) -> Vec<AggregatedDegradation> {
aggregate_degraded_entries(
report
.degradations
.iter()
.map(|degradation| learn_cluster_degradation_input(degradation)),
)
}
fn learn_cluster_degradation_input(degradation: &str) -> DegradationAggregationInput {
let code = degradation.strip_prefix("degraded.").unwrap_or(degradation);
let (severity, message, repair) = match code {
"clustering_insufficient_data" => (
"warning",
"No embedding points were supplied for clustering.",
"Collect at least three related memories before proposing a curation candidate.",
),
"clustering_threshold_too_strict" => (
"warning",
"No cluster reached the configured minimum member count.",
"Lower learn.cluster_coherence_threshold or collect stronger related evidence.",
),
"clustering_silhouette_undefined_for_singleton" => (
"warning",
"Only one embedding point was supplied; silhouette is undefined.",
"Collect at least three related memories before promoting the cluster.",
),
"clustering_silhouette_requires_two_clusters" => (
"warning",
"At least two clusters are required to compute silhouette scores.",
"Collect more diverse related memories before promoting the cluster.",
),
_ => (
"warning",
"Learning cluster analysis completed with degraded confidence.",
"Inspect the learn cluster output and adjust the workspace evidence.",
),
};
DegradationAggregationInput::new("learn_cluster", code, severity, message, repair)
}
/// Render a learn cluster report as human-readable text.
#[must_use]
pub fn render_learn_cluster_human(report: &LearnClusterReport) -> String {
let mut out = String::with_capacity(1024);
out.push_str("Learning Clusters\n\n");
out.push_str(&format!(
"Clusters: {} from {} memories (threshold {:.3}, min size {})\n\n",
report.cluster_count, report.memory_count, report.threshold, report.min_cluster_size
));
for cluster in &report.clusters {
out.push_str(&format!(
"{}: {} member(s), silhouette {}\n",
cluster.cluster_id,
cluster.member_memory_ids.len(),
cluster
.silhouette_score
.map_or_else(|| "n/a".to_owned(), |score| format!("{score:.3}"))
));
out.push_str(&format!(" {}\n", cluster.member_memory_ids.join(", ")));
}
if !report.degradations.is_empty() {
out.push_str("\nDegraded:\n");
for degradation in learn_cluster_degraded_json(report) {
let code = degradation.code;
let message = degradation.message;
let repair = degradation.repair;
out.push_str(&format!(" {code}: {message} (repair: {repair})\n"));
}
}
out
}
/// Render a learn cluster report as TOON.
#[must_use]
pub fn render_learn_cluster_toon(report: &LearnClusterReport) -> String {
format!(
"LEARN_CLUSTER|clusters={}|memories={}|clustered={}|threshold={:.3}",
report.cluster_count, report.memory_count, report.clustered_memory_count, report.threshold
)
}
/// Render a learn summary report as JSON.
#[must_use]
pub fn render_learn_summary_json(report: &LearnSummaryReport) -> String {
serde_json::json!({
"schema": report.schema,
"success": true,
"summary": report.summary,
"events": report.events,
"generatedAt": report.generated_at,
})
.to_string()
}
/// Render a learn summary report as human-readable text.
#[must_use]
pub fn render_learn_summary_human(report: &LearnSummaryReport) -> String {
let mut out = String::with_capacity(1024);
out.push_str(&format!("Learning Summary ({})\n\n", report.summary.period));
out.push_str(&format!(
"Memories created: {}\n",
report.summary.memories_created
));
out.push_str(&format!(
"Memories promoted: {}\n",
report.summary.memories_promoted
));
out.push_str(&format!(
"Memories demoted: {}\n",
report.summary.memories_demoted
));
out.push_str(&format!(
"Rules learned: {}\n",
report.summary.rules_learned
));
out.push_str(&format!(
"Rules validated: {}\n",
report.summary.rules_validated
));
out.push_str(&format!(
"Gaps identified: {}\n",
report.summary.gaps_identified
));
out.push_str(&format!(
"Gaps resolved: {}\n",
report.summary.gaps_resolved
));
out.push_str(&format!(
"Net knowledge delta: {:+}\n\n",
report.summary.net_knowledge_delta
));
if !report.events.is_empty() {
out.push_str("Recent Events:\n");
for event in &report.events {
out.push_str(&format!(
" [{}] {} ({})\n",
event.event_type, event.description, event.impact
));
}
}
out.push_str("\nNext:\n ee learn agenda --json\n");
out
}
/// Render a learn summary report as TOON.
#[must_use]
pub fn render_learn_summary_toon(report: &LearnSummaryReport) -> String {
format!(
"LEARN_SUMMARY|{}|delta={:+}|events={}",
report.summary.period,
report.summary.net_knowledge_delta,
report.events.len()
)
}
/// Render a query-miss learning gap report as JSON.
#[must_use]
pub fn render_learn_gaps_json(report: &LearnGapsReport) -> String {
serde_json::json!({
"schema": report.schema,
"success": true,
"workspaceId": report.workspace_id,
"retentionDays": report.retention_days,
"requestedSince": report.requested_since,
"effectiveSince": report.effective_since,
"scannedMissCount": report.scanned_miss_count,
"clusterCount": report.cluster_count,
"gaps": report.gaps,
"degraded": report.degraded,
"generatedAt": report.generated_at,
})
.to_string()
}
/// Render a query-miss learning gap report as human-readable text.
#[must_use]
pub fn render_learn_gaps_human(report: &LearnGapsReport) -> String {
let mut out = String::with_capacity(1536);
out.push_str("Learning Gaps\n\n");
out.push_str(&format!(
"Clusters: {} from {} miss row(s) (retention: {} days, since: {})\n\n",
report.cluster_count,
report.scanned_miss_count,
report.retention_days,
report.effective_since
));
for gap in &report.gaps {
out.push_str(&format!(
"[{}] {} miss(es), demand {:.3}, hash {}\n",
gap.cluster_id, gap.miss_count, gap.demand_score, gap.query_hash
));
let origins = gap
.origins
.iter()
.map(|origin| format!("{}={}", origin.origin, origin.miss_count))
.collect::<Vec<_>>()
.join(", ");
if !origins.is_empty() {
out.push_str(&format!(" Origins: {origins}\n"));
}
if !gap.reasons.is_empty() {
out.push_str(&format!(" Reasons: {}\n", gap.reasons.join(", ")));
}
if let Some(query) = gap.representative_redacted_queries.first() {
out.push_str(&format!(" Query: {query}\n"));
}
if let Some(agenda) = &gap.matching_agenda_item {
out.push_str(&format!(" Agenda: {agenda}\n"));
}
out.push_str(&format!(
" Template: {} / {} - {}\n",
gap.remember_template.suggested_level,
gap.remember_template.suggested_kind,
gap.remember_template.content_skeleton
));
out.push_str(&format!(" Next: {}\n\n", gap.suggested_command));
}
if !report.degraded.is_empty() {
out.push_str("Degraded:\n");
for degradation in &report.degraded {
out.push_str(&format!(
" {}: {} (repair: {})\n",
degradation.code, degradation.message, degradation.repair
));
}
}
out
}
/// Render a query-miss learning gap report as TOON.
#[must_use]
pub fn render_learn_gaps_toon(report: &LearnGapsReport) -> String {
format!(
"LEARN_GAPS|clusters={}|misses={}|retention_days={}|degraded={}",
report.cluster_count,
report.scanned_miss_count,
report.retention_days,
report.degraded.len()
)
}
/// Render a learn experiment proposal report as JSON.
#[must_use]
pub fn render_learn_experiment_proposal_json(report: &LearnExperimentProposalReport) -> String {
serde_json::json!({
"schema": report.schema,
"success": true,
"totalCandidates": report.total_candidates,
"returned": report.returned,
"minExpectedValue": report.min_expected_value,
"maxAttentionTokens": report.max_attention_tokens,
"maxRuntimeSeconds": report.max_runtime_seconds,
"proposals": report.proposals,
"generatedAt": report.generated_at,
})
.to_string()
}
/// Render a learn experiment proposal report as human-readable text.
#[must_use]
pub fn render_learn_experiment_proposal_human(report: &LearnExperimentProposalReport) -> String {
let mut out = String::with_capacity(1536);
out.push_str("Learning Experiment Proposals\n\n");
out.push_str(&format!(
"Returned {} of {} candidates (min expected value: {:.2})\n\n",
report.returned, report.total_candidates, report.min_expected_value
));
for proposal in &report.proposals {
out.push_str(&format!(
"[{}] {} (expected value: {:.2})\n",
proposal.experiment_id, proposal.title, proposal.expected_value
));
out.push_str(&format!(" Topic: {}\n", proposal.topic));
out.push_str(&format!(" Hypothesis: {}\n", proposal.hypothesis));
out.push_str(&format!(
" Budget: {} tokens, {}s runtime ({})\n",
proposal.budget.attention_tokens,
proposal.budget.max_runtime_seconds,
proposal.budget.budget_class
));
out.push_str(&format!(
" Safety: {} | dry-run-first: {} | review-required: {}\n",
proposal.safety.boundary,
proposal.safety.dry_run_first,
proposal.safety.review_required
));
out.push_str(&format!(
" Decision impact: {} -> {}\n",
proposal.decision_impact.current_decision, proposal.decision_impact.possible_change
));
out.push_str(&format!(" Next: {}\n\n", proposal.next_command));
}
out.push_str("Next:\n ee learn experiment run --dry-run --json\n");
out
}
/// Render a learn experiment proposal report as TOON.
#[must_use]
pub fn render_learn_experiment_proposal_toon(report: &LearnExperimentProposalReport) -> String {
format!(
"LEARN_EXPERIMENT_PROPOSAL|returned={}|candidates={}|min_ev={:.2}",
report.returned, report.total_candidates, report.min_expected_value
)
}
/// Render a learn experiment run rehearsal as JSON.
#[must_use]
pub fn render_learn_experiment_run_json(report: &LearnExperimentRunReport) -> String {
report.data_json().to_string()
}
/// Render a learn experiment run rehearsal as human-readable text.
#[must_use]
pub fn render_learn_experiment_run_human(report: &LearnExperimentRunReport) -> String {
report.human_summary()
}
/// Render a learn experiment run rehearsal as TOON.
#[must_use]
pub fn render_learn_experiment_run_toon(report: &LearnExperimentRunReport) -> String {
report.toon_summary()
}
/// Render a learn observation report as JSON.
#[must_use]
pub fn render_learn_observe_json(report: &LearnObserveReport) -> String {
report.data_json().to_string()
}
/// Render a learn observation report as human-readable text.
#[must_use]
pub fn render_learn_observe_human(report: &LearnObserveReport) -> String {
report.human_summary()
}
/// Render a learn observation report as TOON.
#[must_use]
pub fn render_learn_observe_toon(report: &LearnObserveReport) -> String {
report.toon_summary()
}
/// Render a learn closure report as JSON.
#[must_use]
pub fn render_learn_close_json(report: &LearnCloseReport) -> String {
report.data_json().to_string()
}
/// Render a learn closure report as human-readable text.
#[must_use]
pub fn render_learn_close_human(report: &LearnCloseReport) -> String {
report.human_summary()
}
/// Render a learn closure report as TOON.
#[must_use]
pub fn render_learn_close_toon(report: &LearnCloseReport) -> String {
report.toon_summary()
}
// ============================================================================
// EE-AUDIT-001: Audit Output Rendering
// ============================================================================
use crate::core::audit::{
AuditDiffReport, AuditShowReport, AuditTimelineReport, AuditVerifyReport,
};
use crate::core::handoff::{
CreateReport as HandoffCreateReport, InspectReport as HandoffInspectReport,
PreviewReport as HandoffPreviewReport, ResumeReport as HandoffResumeReport,
RotateKeyReport as HandoffRotateKeyReport,
};
/// Render an audit timeline report as JSON.
#[must_use]
pub fn render_audit_timeline_json(report: &AuditTimelineReport) -> Result<String, DomainError> {
audit_response_v2_json(&report.to_json())
}
/// Wrap a bare `ee.audit.*.v1` report payload in the canonical
/// `ee.response.v2` success envelope, lifting any `degraded[]` array to the
/// envelope level per the machine-facing response contract. A payload that
/// fails to parse — including the `serialization_failed` marker emitted by
/// `serialize_or_error` — is a typed `DomainError` so the CLI handler emits
/// the canonical `ee.error.v2` envelope (with `error.details.recovery[]`)
/// and exits nonzero, never a hollow success on exit 0.
fn audit_response_v2_json(report_json: &str) -> Result<String, DomainError> {
let mut data: serde_json::Value =
serde_json::from_str(report_json).map_err(|error| DomainError::Storage {
message: format!("Audit report serialization produced invalid JSON: {error}"),
repair: Some("ee doctor --json".to_owned()),
})?;
if data
.get("error")
.and_then(serde_json::Value::as_str)
.is_some_and(|code| code == "serialization_failed")
{
let message = data
.get("message")
.and_then(serde_json::Value::as_str)
.unwrap_or("Audit report serialization failed.")
.to_owned();
return Err(DomainError::Storage {
message: format!("Audit report serialization failed: {message}"),
repair: Some("ee doctor --json".to_owned()),
});
}
let degraded = data
.as_object_mut()
.and_then(|map| map.remove("degraded"))
.unwrap_or_else(|| serde_json::json!([]));
Ok(serde_json::json!({
"schema": RESPONSE_SCHEMA_V2,
"success": true,
"data": data,
"degraded": degraded,
})
.to_string())
}
/// Render an audit timeline report as human-readable text.
#[must_use]
pub fn render_audit_timeline_human(report: &AuditTimelineReport) -> String {
let mut out = String::with_capacity(2048);
out.push_str("Audit Timeline\n\n");
out.push_str(&format!(
"Showing {} of {} operations\n\n",
report.pagination.returned_count, report.pagination.total_count
));
for entry in &report.entries {
out.push_str(&format!(
"[{}] {} {}\n",
entry.id, entry.surface, entry.mutation_kind
));
out.push_str(&format!(
" Actor: {} | Target: {} {}\n",
entry.actor.as_deref().unwrap_or("<none>"),
entry.target_type.as_deref().unwrap_or("<none>"),
entry.target_id.as_deref().unwrap_or("<none>")
));
if let Some(hash) = &entry.this_row_hash {
out.push_str(&format!(
" Hash: {} | Prev: {}\n",
hash,
entry.prev_row_hash.as_deref().unwrap_or("<none>")
));
}
out.push('\n');
}
// Cursor-rejection (and any other) degraded entries must be explained in
// human output too: an empty page with a silent reason is not honest.
for degraded in &report.degraded {
let code = degraded
.get("code")
.and_then(serde_json::Value::as_str)
.unwrap_or("unknown");
let severity = degraded
.get("severity")
.and_then(serde_json::Value::as_str)
.unwrap_or("info");
let message = degraded
.get("message")
.and_then(serde_json::Value::as_str)
.unwrap_or("");
out.push_str(&format!("Degraded [{severity}] {code}: {message}\n"));
if let Some(repair) = degraded.get("repair").and_then(serde_json::Value::as_str) {
out.push_str(&format!(" Repair: {repair}\n"));
}
out.push('\n');
}
if let Some(next_cursor) = &report.pagination.next_cursor {
out.push_str(&format!(
"More rows available. Next page:\n ee audit timeline --cursor {next_cursor} --json\n\n"
));
}
out.push_str("Next:\n ee audit show <audit-id> --json\n");
out
}
/// Render an audit timeline report as TOON: the lossless canonical encoding
/// of the enveloped JSON, so no entry, cursor, or degraded signal is dropped.
pub fn render_audit_timeline_toon(report: &AuditTimelineReport) -> Result<String, DomainError> {
Ok(render_toon_from_json(&render_audit_timeline_json(report)?))
}
/// Render an audit show report as JSON.
#[must_use]
pub fn render_audit_show_json(report: &AuditShowReport) -> Result<String, DomainError> {
audit_response_v2_json(&report.to_json())
}
/// Render an audit show report as human-readable text.
#[must_use]
pub fn render_audit_show_human(report: &AuditShowReport) -> String {
let row = &report.row;
let mut out = String::with_capacity(1024);
out.push_str(&format!("Audit row: {}\n\n", row.id));
out.push_str(&format!("Timestamp: {}\n", row.timestamp));
out.push_str(&format!(
"Actor: {}\n",
row.actor.as_deref().unwrap_or("<none>")
));
out.push_str(&format!("Surface: {}\n", row.surface));
out.push_str(&format!("Mutation: {}\n", row.mutation_kind));
out.push_str(&format!(
"Target: {} {}\n",
row.target_type.as_deref().unwrap_or("<none>"),
row.target_id.as_deref().unwrap_or("<none>")
));
out.push_str(&format!("Hash chain valid: {}\n", report.hash_chain_valid));
out.push_str(&format!(
"Row hash: {}\n",
row.this_row_hash.as_deref().unwrap_or("<missing>")
));
out.push_str(&format!(
"Linked snapshot: {}\n",
if report.linked_snapshot.found {
"found"
} else {
"not found"
}
));
out.push_str("\nNext:\n ee audit verify --json\n");
out
}
/// Render an audit show report as TOON: the lossless canonical encoding of
/// the enveloped JSON.
pub fn render_audit_show_toon(report: &AuditShowReport) -> Result<String, DomainError> {
Ok(render_toon_from_json(&render_audit_show_json(report)?))
}
/// Render an audit diff report as JSON.
#[must_use]
pub fn render_audit_diff_json(report: &AuditDiffReport) -> Result<String, DomainError> {
audit_response_v2_json(&report.to_json())
}
/// Render an audit diff report as human-readable text.
#[must_use]
pub fn render_audit_diff_human(report: &AuditDiffReport) -> String {
let mut out = String::with_capacity(1024);
out.push_str(&format!(
"Audit Diff\n\nWindow: {} to {}\nRows: {}\n\n",
report.from, report.to, report.row_count
));
for entry in &report.entries {
out.push_str(&format!(
"[{}] {} {}\n",
entry.id, entry.surface, entry.mutation_kind
));
out.push_str(&format!(" Timestamp: {}\n", entry.timestamp));
out.push('\n');
}
out.push_str("Next:\n ee audit verify --json\n");
out
}
/// Render an audit diff report as TOON: the lossless canonical encoding of
/// the enveloped JSON, preserving every diff entry.
pub fn render_audit_diff_toon(report: &AuditDiffReport) -> Result<String, DomainError> {
Ok(render_toon_from_json(&render_audit_diff_json(report)?))
}
/// Render an audit verify report as JSON.
#[must_use]
pub fn render_audit_verify_json(report: &AuditVerifyReport) -> Result<String, DomainError> {
audit_response_v2_json(&report.to_json())
}
/// Render an audit verify report as human-readable text.
#[must_use]
pub fn render_audit_verify_human(report: &AuditVerifyReport) -> String {
let mut out = String::with_capacity(1024);
out.push_str("Audit Verification\n\n");
out.push_str(&format!(
"Overall: {}\n\n",
if report.integrity_ok {
"VALID"
} else {
"ISSUES FOUND"
}
));
out.push_str(&format!("Rows checked: {}\n", report.rows));
out.push_str(&format!(
"Last hash: {}\n",
report.last_hash.as_deref().unwrap_or("<none>")
));
out.push_str(&format!(
"First break: {}\n",
report.first_break.as_deref().unwrap_or("<none>")
));
if report.shard_count > 0 {
out.push_str(&format!("Shards checked: {}\n", report.shard_count));
out.push_str(&format!("Broken shards: {}\n", report.broken_shard_count));
}
if !report.issues.is_empty() {
out.push_str("\nIssues:\n");
for issue in &report.issues {
let shard = issue
.shard_id
.as_deref()
.map(|value| format!(" shard={value}"))
.unwrap_or_default();
out.push_str(&format!(
" [{}{}] {}: {}\n",
issue.audit_id.as_deref().unwrap_or("<unknown>"),
shard,
issue.code,
issue.message
));
}
}
out.push_str("\nNext:\n ee audit timeline --json\n");
out
}
/// Render an audit verify report as TOON: the lossless canonical encoding of
/// the enveloped JSON, preserving every issue detail.
pub fn render_audit_verify_toon(report: &AuditVerifyReport) -> Result<String, DomainError> {
Ok(render_toon_from_json(&render_audit_verify_json(report)?))
}
// ============================================================================
// Handoff Rendering
// ============================================================================
/// Render a completion audit report as a JSON response envelope.
#[must_use]
pub fn render_completion_audit_json(
report: &crate::core::completion_audit::CompletionAuditReport,
) -> String {
serde_json::json!({
"schema": crate::models::RESPONSE_SCHEMA_V2,
"success": true,
"data": report,
"degraded": []
})
.to_string()
}
/// Render a completion audit report as human-readable text.
#[must_use]
pub fn render_completion_audit_human(
report: &crate::core::completion_audit::CompletionAuditReport,
) -> String {
let mut lines = Vec::new();
lines.push(format!("Completion Audit: {:?}", report.completion_verdict));
lines.push(format!(
"Requirements: {}",
report.checklist.summary.requirement_count
));
lines.push(format!(
"Local build policy: {}",
report.local_build_policy.state.as_str()
));
lines.push(format!("Gaps: {}", report.gaps.len()));
lines.push(format!("Residual risks: {}", report.residual_risks.len()));
if !report.recommended_next_actions.is_empty() {
lines.push(String::new());
lines.push("Recommended Next Actions:".to_owned());
for action in &report.recommended_next_actions {
lines.push(format!(" - {action}"));
}
}
lines.push(String::new());
lines.join("\n")
}
/// Render a handoff preview report as JSON.
#[must_use]
pub fn render_handoff_preview_json(report: &HandoffPreviewReport) -> String {
serde_json::json!({
"schema": report.schema,
"workspace": report.workspace,
"profile": report.profile,
"planned_sections": report.planned_sections,
"omitted_sections": report.omitted_sections,
"evidence_ids": report.evidence_ids,
"active_focus": report.active_focus,
"task_frame": report.task_frame,
"swarm_brief_summary": report.swarm_brief_summary,
"swarm_incident_summary": report.swarm_incident_summary,
"swarm_replay_summary": report.swarm_replay_summary,
"pack_replay_summary": report.pack_replay_summary,
"environment_attestation_summary": report.environment_attestation_summary,
"regression_causality_summary": report.regression_causality_summary,
"token_estimate": report.token_estimate,
"byte_estimate": report.byte_estimate,
"redaction_posture": report.redaction_posture,
"degradations": report.degradations,
"sufficient_for_resume": report.sufficient_for_resume,
"generated_at": report.generated_at
})
.to_string()
}
/// Render a handoff preview report as human-readable text.
#[must_use]
pub fn render_handoff_preview_human(report: &HandoffPreviewReport) -> String {
let mut lines = Vec::new();
lines.push(format!("Handoff Preview ({})", report.profile));
lines.push(format!("Workspace: {}", report.workspace.display()));
lines.push(String::new());
lines.push("Planned Sections:".to_owned());
for section in &report.planned_sections {
lines.push(format!(
" - {} ({}, ~{} tokens)",
section.title, section.confidence, section.token_estimate
));
}
if !report.omitted_sections.is_empty() {
lines.push(String::new());
lines.push("Omitted Sections:".to_owned());
for omission in &report.omitted_sections {
lines.push(format!(" - {}: {}", omission.id, omission.reason));
}
}
lines.push(String::new());
lines.push(format!(
"Estimates: ~{} tokens, ~{} bytes",
report.token_estimate, report.byte_estimate
));
if report.active_focus.is_some() {
lines.push("Active focus: included".to_owned());
}
lines.push(format!(
"Sufficient for resume: {}",
if report.sufficient_for_resume {
"yes"
} else {
"no"
}
));
if !report.degradations.is_empty() {
lines.push(String::new());
lines.push("Degradations:".to_owned());
for deg in &report.degradations {
lines.push(format!(" - [{}] {}", deg.code, deg.message));
}
}
lines.join("\n") + "\n"
}
/// Render a handoff preview report as TOON.
#[must_use]
pub fn render_handoff_preview_toon(report: &HandoffPreviewReport) -> String {
render_toon_from_json(&render_handoff_preview_json(report))
}
/// Render a handoff create report as JSON.
#[must_use]
pub fn render_handoff_create_json(report: &HandoffCreateReport) -> String {
serde_json::json!({
"schema": report.schema,
"capsule_id": report.capsule_id,
"workspace": report.workspace,
"output_path": report.output_path,
"profile": report.profile,
"sections_included": report.sections_included,
"evidence_count": report.evidence_count,
"active_focus": report.active_focus,
"task_frame": report.task_frame,
"swarm_brief_summary": report.swarm_brief_summary,
"swarm_incident_summary": report.swarm_incident_summary,
"swarm_replay_summary": report.swarm_replay_summary,
"pack_replay_summary": report.pack_replay_summary,
"environment_attestation_summary": report.environment_attestation_summary,
"regression_causality_summary": report.regression_causality_summary,
"token_count": report.token_count,
"byte_count": report.byte_count,
"content_hash": report.content_hash,
"canonical_content_hash": report.canonical_content_hash,
"redaction_summary": report.redaction_summary,
"dry_run": report.dry_run,
"created_at": report.created_at
})
.to_string()
}
/// Render a handoff create report as human-readable text.
#[must_use]
pub fn render_handoff_create_human(report: &HandoffCreateReport) -> String {
let mut lines = Vec::new();
if report.dry_run {
lines.push("Handoff Capsule (dry run)".to_owned());
} else {
lines.push("Handoff Capsule Created".to_owned());
}
lines.push(format!("ID: {}", report.capsule_id));
lines.push(format!("Output: {}", report.output_path.display()));
lines.push(format!("Profile: {}", report.profile));
lines.push(String::new());
lines.push(format!("Sections: {}", report.sections_included));
lines.push(format!("Evidence items: {}", report.evidence_count));
if report.active_focus.is_some() {
lines.push("Active focus: included".to_owned());
}
lines.push(format!("Tokens: {}", report.token_count));
lines.push(format!("Bytes: {}", report.byte_count));
lines.push(format!("Content hash: {}", report.content_hash));
lines.join("\n") + "\n"
}
/// Render a handoff create report as TOON.
#[must_use]
pub fn render_handoff_create_toon(report: &HandoffCreateReport) -> String {
render_toon_from_json(&render_handoff_create_json(report))
}
/// Render a handoff rotate-key report as JSON.
#[must_use]
pub fn render_handoff_rotate_key_json(report: &HandoffRotateKeyReport) -> String {
serde_json::json!({
"schema": report.schema,
"capsule_id": report.capsule_id,
"capsule_path": report.capsule_path,
"key_mode": report.key_mode,
"body_sha256": report.body_sha256,
"old_hmac_prefix": report.old_hmac_prefix,
"new_hmac_prefix": report.new_hmac_prefix,
"canonical_content_hash_before": report.canonical_content_hash_before,
"canonical_content_hash_after": report.canonical_content_hash_after,
"body_preserved": report.body_preserved,
"audit_id": report.audit_id,
"rotated_at": report.rotated_at
})
.to_string()
}
/// Render a handoff rotate-key report as human-readable text.
#[must_use]
pub fn render_handoff_rotate_key_human(report: &HandoffRotateKeyReport) -> String {
let mut lines = Vec::new();
lines.push("Handoff Capsule HMAC Rotated".to_owned());
lines.push(format!("ID: {}", report.capsule_id));
lines.push(format!("Capsule: {}", report.capsule_path.display()));
lines.push(format!("Key mode: {}", report.key_mode));
lines.push(format!(
"HMAC prefix: {} -> {}",
report.old_hmac_prefix.as_deref().unwrap_or(""),
report.new_hmac_prefix
));
lines.push(format!("Body preserved: {}", report.body_preserved));
lines.join("\n") + "\n"
}
/// Render a handoff rotate-key report as TOON.
#[must_use]
pub fn render_handoff_rotate_key_toon(report: &HandoffRotateKeyReport) -> String {
render_toon_from_json(&render_handoff_rotate_key_json(report))
}
/// Render a handoff inspect report as JSON.
#[must_use]
pub fn render_handoff_inspect_json(report: &HandoffInspectReport) -> String {
serde_json::json!({
"schema": report.schema,
"path": report.path,
"capsule_id": report.capsule_id,
"capsule_schema": report.capsule_schema,
"validation_status": report.validation_status,
"workspace_id": report.workspace_id,
"repository_fingerprint": report.repository_fingerprint,
"profile": report.profile,
"section_count": report.section_count,
"evidence_count": report.evidence_count,
"hash_valid": report.hash_valid,
"hash_expected": report.hash_expected,
"hash_actual": report.hash_actual,
"stale_evidence": report.stale_evidence,
"missing_evidence": report.missing_evidence,
"redaction_status": report.redaction_status,
"compatible_versions": report.compatible_versions,
"warnings": report.warnings,
"inspected_at": report.inspected_at
})
.to_string()
}
/// Render a handoff inspect report as human-readable text.
#[must_use]
pub fn render_handoff_inspect_human(report: &HandoffInspectReport) -> String {
let mut lines = Vec::new();
lines.push(format!("Capsule Inspection: {}", report.path.display()));
lines.push(format!("Status: {}", report.validation_status));
lines.push(String::new());
lines.push(format!("Capsule ID: {}", report.capsule_id));
lines.push(format!("Schema: {}", report.capsule_schema));
lines.push(format!("Profile: {}", report.profile));
if let Some(ref ws) = report.workspace_id {
lines.push(format!("Workspace: {ws}"));
}
lines.push(String::new());
lines.push(format!("Sections: {}", report.section_count));
lines.push(format!("Evidence items: {}", report.evidence_count));
lines.push(format!(
"Hash valid: {}",
if report.hash_valid { "yes" } else { "no" }
));
if !report.warnings.is_empty() {
lines.push(String::new());
lines.push("Warnings:".to_owned());
for warning in &report.warnings {
lines.push(format!(" - {warning}"));
}
}
lines.join("\n") + "\n"
}
/// Render a handoff inspect report as TOON.
#[must_use]
pub fn render_handoff_inspect_toon(report: &HandoffInspectReport) -> String {
render_toon_from_json(&render_handoff_inspect_json(report))
}
/// Render a handoff resume report as JSON.
#[must_use]
pub fn render_handoff_resume_json(report: &HandoffResumeReport) -> String {
let value = serde_json::json!({
"schema": report.schema,
"capsule_id": report.capsule_id,
"capsule_path": report.capsule_path,
"workspace": report.workspace,
"current_objective": report.current_objective,
"status_summary": report.status_summary,
"next_actions": report.next_actions,
"blockers": report.blockers,
"do_not_repeat": report.do_not_repeat,
"recent_decisions": report.recent_decisions,
"recent_outcomes": report.recent_outcomes,
"selected_memories": report.selected_memories,
"active_focus": report.active_focus,
"task_frame": report.task_frame,
"swarm_brief_summary": report.swarm_brief_summary,
"swarm_incident_summary": report.swarm_incident_summary,
"swarm_replay_summary": report.swarm_replay_summary,
"pack_replay_summary": report.pack_replay_summary,
"environment_attestation_summary": report.environment_attestation_summary,
"regression_causality_summary": report.regression_causality_summary,
"artifact_pointers": report.artifact_pointers,
"degradations": report.degradations,
"resumed_at": report.resumed_at,
"prompt_fragment": report.prompt_fragment,
"workspace_mismatch": report.workspace_mismatch,
"workspace_match": report.workspace_match,
"stale_snapshot": report.stale_snapshot
});
log_handoff_resume_size_check(report, &value);
value.to_string()
}
fn log_handoff_resume_size_check(report: &HandoffResumeReport, value: &serde_json::Value) {
let current_bytes = serde_json::to_vec(value).map_or(0, |bytes| bytes.len());
let mut baseline = value.clone();
if let Some(object) = baseline.as_object_mut() {
object.remove("stale_snapshot");
}
let baseline_bytes = serde_json::to_vec(&baseline).map_or(0, |bytes| bytes.len());
let overhead_bytes = current_bytes.saturating_sub(baseline_bytes);
let budget_bytes = baseline_bytes.div_ceil(12);
let overhead_pct = if baseline_bytes == 0 {
0.0
} else {
overhead_bytes as f64 * 100.0 / baseline_bytes as f64
};
tracing::info!(
event = "handoff_resume_size_check",
capsule_id = %report.capsule_id,
baseline_bytes,
current_bytes,
overhead_bytes,
budget_bytes,
within_budget = overhead_bytes <= budget_bytes,
overhead_pct,
"handoff resume stale snapshot size budget computed"
);
}
/// Render a handoff resume report as human-readable text.
#[must_use]
pub fn render_handoff_resume_human(report: &HandoffResumeReport) -> String {
let mut lines = Vec::new();
lines.push("Session Resume".to_owned());
lines.push(format!("From capsule: {}", report.capsule_id));
lines.push(String::new());
if let Some(ref obj) = report.current_objective {
lines.push("Current Objective:".to_owned());
lines.push(format!(" {obj}"));
lines.push(String::new());
}
if !report.next_actions.is_empty() {
lines.push("Next Actions:".to_owned());
for action in &report.next_actions {
lines.push(format!(" {}. {}", action.priority, action.description));
if let Some(ref cmd) = action.suggested_command {
lines.push(format!(" Command: {cmd}"));
}
}
lines.push(String::new());
}
if !report.blockers.is_empty() {
lines.push("Blockers:".to_owned());
for blocker in &report.blockers {
let hard = if blocker.hard { " [HARD]" } else { "" };
lines.push(format!(" - {}{hard}", blocker.description));
}
lines.push(String::new());
}
if !report.do_not_repeat.is_empty() {
lines.push("Do Not Repeat:".to_owned());
for dnr in &report.do_not_repeat {
lines.push(format!(" - {}: {}", dnr.pattern, dnr.reason));
}
lines.push(String::new());
}
if !report.degradations.is_empty() {
lines.push("Degradations:".to_owned());
for deg in &report.degradations {
lines.push(format!(" - [{}] {}", deg.code, deg.message));
}
}
lines.join("\n") + "\n"
}
/// Render a handoff resume report as TOON.
#[must_use]
pub fn render_handoff_resume_toon(report: &HandoffResumeReport) -> String {
render_toon_from_json(&render_handoff_resume_json(report))
}
// ============================================================================
// EE-363: Claim Diagnostics Output
// ============================================================================
/// Render a claims diagnostic report as JSON (ee.response.v2 envelope).
#[must_use]
pub fn render_diag_claims_json(report: &crate::core::claims::DiagClaimsReport) -> String {
let mut b = JsonBuilder::with_capacity(1024);
b.field_str("schema", RESPONSE_SCHEMA_V2);
b.field_bool("success", report.health_status == "healthy");
b.field_object("data", |d| {
d.field_str("command", "diag claims");
d.field_str("reportSchema", report.schema);
d.field_str("claimsFile", &report.claims_file);
d.field_bool("claimsFileExists", report.claims_file_exists);
d.field_raw(
"stalenessThresholdDays",
&report.staleness_threshold_days.to_string(),
);
d.field_str("healthStatus", report.health_status);
d.field_object("counts", |c| {
c.field_raw("total", &report.counts.total.to_string());
c.field_raw("verified", &report.counts.verified.to_string());
c.field_raw("unverified", &report.counts.unverified.to_string());
c.field_raw("stale", &report.counts.stale.to_string());
c.field_raw("regressed", &report.counts.regressed.to_string());
c.field_raw("unknown", &report.counts.unknown.to_string());
});
d.field_array_of_objects("entries", &report.entries, |obj, entry| {
obj.field_str("id", &entry.id);
obj.field_str("title", &entry.title);
obj.field_str("posture", entry.posture.as_str());
obj.field_str("severity", entry.posture.severity());
if let Some(ref verified_at) = entry.last_verified_at {
obj.field_str("lastVerifiedAt", verified_at);
}
if let Some(days) = entry.staleness_days {
obj.field_raw("stalenessDays", &days.to_string());
}
obj.field_raw("evidenceCount", &entry.evidence_count.to_string());
obj.field_raw("demoCount", &entry.demo_count.to_string());
obj.field_str("frequency", entry.frequency.as_str());
});
d.field_array_of_strings("repairActions", &report.repair_actions);
});
b.field_raw("degraded", "[]");
b.finish()
}
/// Render a claims diagnostic report as human-readable text.
#[must_use]
pub fn render_diag_claims_human(report: &crate::core::claims::DiagClaimsReport) -> String {
let mut output = String::with_capacity(1024);
output.push_str("ee diag claims\n\n");
if !report.claims_file_exists {
output.push_str(&format!(
"Claims file not found: {}\n\n",
report.claims_file
));
output.push_str("Next:\n");
for action in &report.repair_actions {
output.push_str(&format!(" {}\n", action));
}
return output;
}
output.push_str(&format!("Claims file: {}\n", report.claims_file));
output.push_str(&format!("Health: {}\n", report.health_status));
output.push_str(&format!(
"Staleness threshold: {} days\n\n",
report.staleness_threshold_days
));
output.push_str("Summary:\n");
output.push_str(&format!(" Total: {}\n", report.counts.total));
output.push_str(&format!(" Verified: {}\n", report.counts.verified));
output.push_str(&format!(" Unverified: {}\n", report.counts.unverified));
output.push_str(&format!(" Stale: {}\n", report.counts.stale));
output.push_str(&format!(" Regressed: {}\n", report.counts.regressed));
if !report.entries.is_empty() {
output.push_str("\nClaims requiring attention:\n");
for entry in &report.entries {
let severity_marker = match entry.posture.severity() {
"error" => "✗",
"warning" => "⚠",
_ => "·",
};
output.push_str(&format!(
" {} [{}] {} — {}\n",
severity_marker,
entry.posture.as_str(),
entry.id,
entry.title
));
}
}
if !report.repair_actions.is_empty() {
output.push_str("\nNext:\n");
for action in &report.repair_actions {
output.push_str(&format!(" {}\n", action));
}
}
output
}
/// Render a claims diagnostic report as TOON.
#[must_use]
pub fn render_diag_claims_toon(report: &crate::core::claims::DiagClaimsReport) -> String {
render_toon_from_json(&render_diag_claims_json(report))
}
#[cfg(test)]
mod tests {
use std::path::PathBuf;
use std::str::FromStr;
use uuid::Uuid;
use super::{
ContextJsonRenderOptions, Degradation, DegradationSeverity, FieldProfile, JsonBuilder,
OutputContext, OutputEnvironment, Renderer, ResponseEnvelope, SHADOW_RUN_SCHEMA_V1,
ShadowRunComparison, ShadowRunReport, build_aggregated_degradation, error_response_json,
escape_json_string, help_json, help_text, human_status, redact_mesh_approval_bearer_spans,
redact_mesh_approval_bearers, render_agent_docs_json, render_agent_docs_toon,
render_capabilities_json, render_capabilities_json_filtered, render_check_json,
render_check_json_filtered, render_context_response_human, render_context_response_json,
render_context_response_json_with_options, render_context_response_markdown,
render_context_response_toon, render_dependency_diagnostics_json,
render_doctor_concise_human, render_doctor_concise_json, render_doctor_concise_toon,
render_doctor_json, render_doctor_json_filtered, render_doctor_toon, render_eval_list_json,
render_eval_report_json, render_fix_plan_json, render_graph_diag_json,
render_handoff_create_json, render_handoff_create_toon, render_handoff_inspect_json,
render_handoff_inspect_toon, render_handoff_preview_json, render_handoff_preview_toon,
render_handoff_resume_json, render_handoff_resume_toon, render_health_json,
render_health_toon, render_integrity_diagnostics_json, render_introspect_json,
render_learn_cluster_json, render_learn_experiment_proposal_human,
render_learn_experiment_proposal_json, render_learn_experiment_proposal_toon,
render_mcp_manifest_json, render_memory_history_json, render_memory_history_toon,
render_memory_impact_analysis_json, render_memory_impact_analysis_markdown,
render_memory_impact_analysis_toon, render_memory_list_json, render_memory_list_toon,
render_memory_show_human, render_memory_show_json, render_memory_show_toon,
render_pack_dna_json, render_pack_dna_markdown, render_pack_dna_toon,
render_preflight_run_json, render_preflight_show_json, render_proximity_json,
render_proximity_markdown, render_proximity_toon, render_quarantine_entry_human,
render_quarantine_entry_json, render_quarantine_entry_toon, render_quarantine_human,
render_quarantine_json, render_quarantine_json_filtered, render_quarantine_toon,
render_schema_export_json, render_schema_list_json, render_shadow_run_human,
render_shadow_run_json, render_shadow_run_toon, render_status_json,
render_status_json_filtered, render_status_json_with_meta, render_status_skyline_json,
render_status_skyline_markdown, render_status_skyline_toon, render_status_toon,
render_streams_json, render_structural_health_json, render_structural_health_markdown,
render_structural_health_toon, render_version_json, render_why_causal_json,
render_why_causal_markdown, render_why_causal_toon, schema_json, status_response_json,
};
use crate::core::agent_docs::AgentDocsReport;
use crate::core::capabilities::{CapabilitiesReport, CommandEntry};
use crate::core::degraded_aggregation::AggregatedDegradation;
use crate::core::doctor::{
CassImportGuidance, CassImportGuidanceStatus, CheckResult, CheckSeverity, CheckTier,
DependencyContractEntry, DependencyDiagnosticsReport, DependencyDiagnosticsSummary,
DependencyDriftPolicy, DependencyFeatureProfile, DependencySource, DoctorReport, FixPlan,
IntegrityCanaryReport, IntegrityDiagnosticCheck, IntegrityDiagnosticDegradation,
IntegrityDiagnosticsReport, IntegrityDiagnosticsStatus, Posture,
};
use crate::core::handoff::{
CapsuleProfile, CreateReport as HandoffCreateReport, InspectReport as HandoffInspectReport,
PreviewReport as HandoffPreviewReport, ResumeReport as HandoffResumeReport,
};
use crate::core::health::{
HealthReport, StructuralContradictionCluster, StructuralHealthDegradation,
StructuralHealthReport, StructuralHealthSummary, StructuralKTrussMember,
StructuralKTrussSummary,
};
use crate::core::learn::{
ExperimentBudget, ExperimentDecisionImpact, ExperimentProposal, ExperimentSafetyPlan,
LEARN_EXPERIMENT_PROPOSAL_SCHEMA_V1, LearnClusterReport, LearnExperimentProposalReport,
};
use crate::core::memory::{
MemoryDetails, MemoryHistoryEntry, MemoryHistoryReport, MemoryListFilter, MemoryListReport,
MemoryShowReport, MemorySummary,
};
use crate::core::preflight::{
PreflightDegradation, PreflightRunView, RunReport as PreflightRunReport,
ShowReport as PreflightShowReport,
};
use crate::core::quarantine::{
AdvisoryLevel, QuarantineEntry, QuarantineReport, QuarantineStorageStatus,
QuarantineSummary,
};
use crate::core::status::{
DegradationReport, FeedbackHealthReport, FeedbackHealthStatus, FeedbackSourceHealth,
MeshStorageStatusReport, STATUS_SKYLINE_SCHEMA_V1, StatusReport,
StatusSkylineCommunityReport, StatusSkylineReport, StatusSkylineSummaryReport,
};
use crate::core::swarm_brief::{
RCH_WORKER_PRESSURE_SCHEMA_V1, RchWorkerPressureObservation, RchWorkerPressureReport,
};
use crate::core::tailscale_probe::{
DEFAULT_TAILSCALE_PROBE_TIMEOUT_MS, TailscaleLocalReport, TailscalePlatform,
TailscaleProbeMethod,
};
use crate::core::{
BUILD_TIMESTAMP_POLICY, BuildFeature, BuildInfo, BuildProvenanceDegradation,
SupportedSchema, VERSION_PROVENANCE_SCHEMA_V1, VersionReport,
};
use crate::db::{StoredMemory, StoredTrustQuarantine};
use crate::graph::gomory_hu::{PROXIMITY_SCHEMA_V1, ProximityDegradation, ProximityReport};
use crate::graph::health::HEALTH_STRUCTURAL_SCHEMA_V1;
use crate::models::decision::{DecisionPlane, DecisionPlaneMetadata, DecisionRecord};
use crate::models::{
DomainError, ERROR_SCHEMA_V2, MemoryId, ProvenanceUri, RESPONSE_SCHEMA_V2, TrustClass,
UnitScore,
};
use crate::pack::{
ContextRequest, ContextResponse, ContextResponsePagination, PACK_BUDGET_TOO_SMALL_CODE,
PackAssemblySlo, PackAssemblySloActuals, PackCandidate, PackCandidateInput,
PackFreshnessAnchorFacet, PackFreshnessFacet, PackProvenance, PackResourceProfile,
PackScoreBreakdown, PackSection, PackTrustSignal, TokenBudget, assemble_draft,
budget_classifier::{AdaptiveBudgetInput, classify_adaptive_budget},
};
type TestResult = Result<(), String>;
fn capabilities_report_fixture() -> CapabilitiesReport {
CapabilitiesReport::gather(vec![CommandEntry::new(
"capabilities",
true,
"Report capabilities",
)])
}
fn mesh_approval_bearer_canary() -> String {
// Keep the recognizable credential prefix out of the source fixture
// while retaining the exact fixed-width public bearer shape.
format!(
"{}{}",
["e", "e", "a", "p", "1", "_"].concat(),
"A".repeat(151)
)
}
fn rch_worker_pressure_fixture() -> RchWorkerPressureReport {
RchWorkerPressureReport {
schema: RCH_WORKER_PRESSURE_SCHEMA_V1,
status: "healthy_but_pressure_blocked".to_string(),
worker_count: 1,
usable_worker_count: 0,
blocked_worker_count: 1,
stale_worker_count: 0,
unknown_worker_count: 0,
workers: vec![RchWorkerPressureObservation {
worker_id: "worker-redacted".to_string(),
pressure_state: "critical".to_string(),
confidence: "high".to_string(),
reason_code: "disk_pressure_critical".to_string(),
free_gb: Some(0),
free_ratio_bps: Some(300),
telemetry_freshness: "fresh".to_string(),
admission_impact: "blocked".to_string(),
}],
}
}
fn verification_posture_fixture() -> crate::core::verify::VerificationPostureReport {
let mut report = crate::core::verify::VerificationPostureReport::not_inspected();
report.status = "degraded_recoverable".to_owned();
report.evidence_health.ledger_available = true;
report.evidence_health.status = "degraded".to_owned();
report.evidence_health.reason = Some("remote_required_gate_used_local_fallback".to_owned());
report.record_count = 4;
report.recent_run_count = 3;
report.stale_run_count = 1;
report.recent_reusable_run_count = 1;
report.in_flight_equivalent_command_count = 1;
report.advisory_counts.remote_success = 1;
report.advisory_counts.remote_in_flight = 1;
report.advisory_counts.local_disallowed = 1;
report.evidence_health.local_disallowed_count = 1;
report.evidence_health.issue_count = 1;
report
}
struct FailingSerialize;
impl serde::Serialize for FailingSerialize {
fn serialize<S>(&self, _serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
Err(serde::ser::Error::custom(
"intentional serialization failure",
))
}
}
#[test]
fn serialized_report_response_reports_serializer_failures() -> TestResult {
let json = super::render_serialized_report_response(&FailingSerialize, "FailingReport");
let parsed: serde_json::Value =
serde_json::from_str(&json).map_err(|error| error.to_string())?;
assert_eq!(parsed["schema"].as_str(), Some(ERROR_SCHEMA_V2));
assert_eq!(
parsed["error"]["code"].as_str(),
Some("serialization_failed")
);
assert_eq!(
parsed["error"]["details"]["report"].as_str(),
Some("FailingReport")
);
assert!(
!json.contains("\"data\":{}"),
"serialization failure must not be hidden as empty data"
);
Ok(())
}
#[test]
fn serialized_report_json_reports_serializer_failures() -> TestResult {
let json = super::render_serialized_report_json(&FailingSerialize, "DirectFailingReport");
let parsed: serde_json::Value =
serde_json::from_str(&json).map_err(|error| error.to_string())?;
assert_eq!(parsed["schema"].as_str(), Some(ERROR_SCHEMA_V2));
assert_eq!(
parsed["error"]["code"].as_str(),
Some("serialization_failed")
);
assert_eq!(
parsed["error"]["details"]["report"].as_str(),
Some("DirectFailingReport")
);
assert!(
!json.is_empty(),
"serialization failure must not be hidden as an empty string"
);
Ok(())
}
#[test]
fn dependency_diagnostics_degraded_entries_are_aggregated() -> TestResult {
static TEST_ENTRIES: &[DependencyContractEntry] = &[
DependencyContractEntry {
name: "graph-alpha",
kind: "franken",
owning_surface: "ee-graph",
status: "optional_feature_gated",
enabled_by_default: false,
source: DependencySource {
kind: "path",
version: "0.1.0",
path: "/dp/graph-alpha",
},
default_feature_profile: DependencyFeatureProfile {
default_features: false,
features: &[],
},
optional_feature_profiles: &[],
blocked_features: &[],
forbidden_transitive_dependencies: &[],
minimum_smoke_test: "cargo test graph_alpha",
degradation_code: "graph_unavailable",
status_fields: &[],
diagnostic_command: "ee diag graph --json",
release_pin_decision: "test",
},
DependencyContractEntry {
name: "graph-beta",
kind: "franken",
owning_surface: "ee-graph",
status: "optional_feature_gated",
enabled_by_default: false,
source: DependencySource {
kind: "path",
version: "0.1.0",
path: "/dp/graph-beta",
},
default_feature_profile: DependencyFeatureProfile {
default_features: false,
features: &[],
},
optional_feature_profiles: &[],
blocked_features: &[],
forbidden_transitive_dependencies: &[],
minimum_smoke_test: "cargo test graph_beta",
degradation_code: "graph_unavailable",
status_fields: &[],
diagnostic_command: "ee diag graph --json",
release_pin_decision: "test",
},
];
let report = DependencyDiagnosticsReport {
version: "test",
schema: "ee.diag.dependencies.v1",
matrix_revision: 1,
source_bead: "bd-test",
source_plan_item: "test",
default_feature_profile: "test",
forbidden_crates: &[],
entries: TEST_ENTRIES,
drift_policy: DependencyDriftPolicy {
cargo_update_dry_run: "cargo update --dry-run",
fail_conditions: &[],
runtime_diagnostic_owner: "test",
},
summary: DependencyDiagnosticsSummary::from_entries(TEST_ENTRIES),
};
let json = render_dependency_diagnostics_json(&report);
let parsed: serde_json::Value =
serde_json::from_str(&json).map_err(|error| error.to_string())?;
let degraded = parsed["data"]["degraded"]
.as_array()
.ok_or_else(|| "degraded must be an array".to_string())?;
ensure_top_level_degraded_mirrors_data_degraded(&parsed, "dependency diagnostics JSON")?;
assert_eq!(degraded.len(), 1);
assert_eq!(degraded[0]["code"], "graph_unavailable");
assert_eq!(
degraded[0]["sources"],
serde_json::json!(["dependency_contract"])
);
assert_eq!(
degraded[0]["details"]["dependencies"],
serde_json::json!(["graph-alpha", "graph-beta"])
);
assert_eq!(
degraded[0]["details"]["diagnosticCommands"],
serde_json::json!(["ee diag graph --json"])
);
Ok(())
}
#[test]
fn preflight_json_degraded_entries_are_aggregated() -> TestResult {
let duplicate_degraded = vec![
PreflightDegradation::evidence_unavailable("No matching evidence."),
PreflightDegradation::evidence_unavailable("No matching evidence."),
];
let mut run_report =
PreflightRunReport::new("pf_test".to_owned(), "ship risky change".to_owned());
run_report.degraded = duplicate_degraded.clone();
let run_json = render_preflight_run_json(&run_report);
let run: serde_json::Value =
serde_json::from_str(&run_json).map_err(|error| error.to_string())?;
let run_degraded = run["data"]["degraded"]
.as_array()
.ok_or_else(|| "preflight run degraded must be an array".to_string())?;
assert_eq!(run_degraded.len(), 1);
assert_eq!(run_degraded[0]["code"], "preflight_evidence_unavailable");
assert_eq!(
run_degraded[0]["sources"],
serde_json::json!(["preflight_run"])
);
let mut show_report = PreflightShowReport::new(PreflightRunView {
id: "pf_test".to_owned(),
task_input: "ship risky change".to_owned(),
status: "blocked".to_owned(),
risk_level: "high".to_owned(),
cleared: false,
block_reason: None,
started_at: "2026-05-16T00:00:00Z".to_owned(),
completed_at: None,
duration_ms: None,
});
show_report.degraded = duplicate_degraded;
let show_json = render_preflight_show_json(&show_report);
let show: serde_json::Value =
serde_json::from_str(&show_json).map_err(|error| error.to_string())?;
let show_degraded = show["data"]["degraded"]
.as_array()
.ok_or_else(|| "preflight show degraded must be an array".to_string())?;
assert_eq!(show_degraded.len(), 1);
assert_eq!(
show_degraded[0]["sources"],
serde_json::json!(["preflight_show"])
);
Ok(())
}
#[test]
fn learn_cluster_degraded_entries_are_aggregated() -> TestResult {
let report = LearnClusterReport {
schema: "ee.learn.cluster.v1".to_owned(),
workspace_id: "workspace_test".to_owned(),
threshold: 0.82,
min_cluster_size: 3,
memory_count: 4,
clustered_memory_count: 0,
cluster_count: 0,
clusters: Vec::new(),
degradations: vec![
"degraded.clustering_threshold_too_strict".to_owned(),
"degraded.clustering_threshold_too_strict".to_owned(),
],
generated_at: "1970-01-01T00:00:00Z".to_owned(),
};
let json = render_learn_cluster_json(&report);
let parsed: serde_json::Value =
serde_json::from_str(&json).map_err(|error| error.to_string())?;
let degraded = parsed["degraded"]
.as_array()
.ok_or_else(|| "learn cluster degraded must be an array".to_string())?;
assert_eq!(degraded.len(), 1);
assert_eq!(degraded[0]["code"], "clustering_threshold_too_strict");
assert_eq!(degraded[0]["sources"], serde_json::json!(["learn_cluster"]));
Ok(())
}
#[test]
fn pack_budget_too_small_degradation_renders_recovery_details() -> TestResult {
let degraded = AggregatedDegradation {
code: PACK_BUDGET_TOO_SMALL_CODE.to_string(),
severity: "warning".to_string(),
message: "Pack budget could not fit any candidate.".to_string(),
repair: String::new(),
sources: vec!["context".to_string()],
};
let mut builder = JsonBuilder::with_capacity(512);
build_aggregated_degradation(&mut builder, °raded);
let parsed: serde_json::Value =
serde_json::from_str(&builder.finish()).map_err(|error| error.to_string())?;
let recovery = parsed
.pointer("/details/recovery")
.and_then(serde_json::Value::as_array)
.ok_or_else(|| "details.recovery must be an array".to_string())?;
ensure_equal(&recovery.len(), &3, "recovery action count")?;
ensure_equal(
&recovery[0]["flagName"].as_str(),
&Some("--max-tokens"),
"first recovery flag",
)?;
ensure_equal(
&recovery[0]["valueHint"].as_str(),
&Some("8000"),
"first recovery value hint",
)?;
ensure_equal(
&recovery[1]["flagName"].as_str(),
&Some("--profile"),
"second recovery flag",
)?;
ensure_equal(
&recovery[1]["valueHint"].as_str(),
&Some("compact"),
"second recovery value hint",
)?;
ensure_equal(
&recovery[2]["kind"].as_str(),
&Some("broaden"),
"third recovery kind",
)
}
#[test]
fn aggregated_degradation_repair_kind_marks_templates() -> TestResult {
let degraded = AggregatedDegradation {
code: "repair_kind_fixture".to_string(),
severity: "warning".to_string(),
message: "fixture degradation".to_string(),
repair: "ee index rebuild --workspace <path>".to_string(),
sources: vec!["fixture".to_string()],
};
let mut builder = JsonBuilder::with_capacity(256);
build_aggregated_degradation(&mut builder, °raded);
let parsed: serde_json::Value =
serde_json::from_str(&builder.finish()).map_err(|error| error.to_string())?;
ensure_equal(
&parsed["repair"].as_str(),
&Some("ee index rebuild --workspace <path>"),
"repair string",
)?;
ensure_equal(
&parsed["repairKind"].as_str(),
&Some("template"),
"template repair kind",
)
}
#[test]
fn embed_model_unavailable_degradation_renders_recovery_details() -> TestResult {
let degraded = AggregatedDegradation {
code: "embed_model_unavailable".to_string(),
severity: "warning".to_string(),
message: "Embedding model unavailable.".to_string(),
repair: "ee index reembed --workspace .".to_string(),
sources: vec!["search".to_string()],
};
let mut builder = JsonBuilder::with_capacity(512);
build_aggregated_degradation(&mut builder, °raded);
let parsed: serde_json::Value =
serde_json::from_str(&builder.finish()).map_err(|error| error.to_string())?;
let recovery = parsed
.pointer("/details/recovery")
.and_then(serde_json::Value::as_array)
.ok_or_else(|| "details.recovery must be an array".to_string())?;
ensure_equal(&recovery.len(), &2, "recovery action count")?;
ensure_equal(
&recovery[0]["kind"].as_str(),
&Some("rebuild"),
"first recovery kind",
)?;
ensure_equal(
&recovery[0]["command"].as_str(),
&Some("ee index reembed --workspace ."),
"first recovery command",
)?;
ensure_equal(
&recovery[0]["resultsIn"].as_str(),
&Some(
"Rebuilds the embedding index against the current embed-fast feature and model configuration.",
),
"first recovery resultsIn",
)?;
ensure_equal(
&recovery[1]["kind"].as_str(),
&Some("rebuild"),
"second recovery kind",
)?;
ensure_equal(
&recovery[1]["command"].as_str(),
&Some("cargo build --features embed-fast"),
"second recovery command",
)
}
fn ensure(condition: bool, message: impl Into<String>) -> TestResult {
if condition {
Ok(())
} else {
Err(message.into())
}
}
fn ensure_empty_top_level_degraded(value: &serde_json::Value, context: &str) -> TestResult {
let degraded = value
.get("degraded")
.and_then(serde_json::Value::as_array)
.ok_or_else(|| format!("{context}: missing top-level degraded array"))?;
ensure(
degraded.is_empty(),
format!("{context}: expected empty degraded array, got {degraded:?}"),
)
}
fn parse_rendered_json(json: &str, context: &str) -> Result<serde_json::Value, String> {
serde_json::from_str(json)
.map_err(|error| format!("{context}: JSON should parse: {error}; {json}"))
}
fn ensure_top_level_degraded_mirrors_data_degraded(
value: &serde_json::Value,
context: &str,
) -> TestResult {
let top_degraded = value
.get("degraded")
.and_then(serde_json::Value::as_array)
.ok_or_else(|| format!("{context}: missing top-level degraded array"))?;
let data_degraded = value
.pointer("/data/degraded")
.and_then(serde_json::Value::as_array)
.ok_or_else(|| format!("{context}: missing data degraded array"))?;
ensure_equal(
top_degraded,
data_degraded,
&format!("{context}: top-level degraded mirrors data degraded"),
)
}
fn ensure_contains(haystack: &str, needle: &str, context: &str) -> TestResult {
ensure(
haystack.contains(needle),
format!("{context}: expected output to contain {needle:?}, got {haystack:?}"),
)
}
fn output_test_memory(provenance_uri: Option<String>) -> StoredMemory {
StoredMemory {
id: "mem_output_redaction".to_owned(),
workspace_id: "wsp_output_redaction".to_owned(),
level: "procedural".to_owned(),
kind: "rule".to_owned(),
content: "Keep memory provenance output redacted.".to_owned(),
workflow_id: None,
confidence: 0.9,
utility: 0.8,
importance: 0.7,
provenance_uri,
trust_class: "human_explicit".to_owned(),
trust_subclass: None,
provenance_chain_hash: None,
provenance_chain_hash_version: "1".to_owned(),
provenance_verification_status: "unverified".to_owned(),
provenance_verified_at: None,
provenance_verification_note: None,
created_at: "2026-05-17T00:00:00Z".to_owned(),
updated_at: "2026-05-17T00:00:00Z".to_owned(),
tombstoned_at: None,
valid_from: None,
valid_to: None,
}
}
fn output_test_quarantine(source_uri: String) -> StoredTrustQuarantine {
StoredTrustQuarantine {
workspace_id: "wsp_output_redaction".to_owned(),
source_uri,
first_event_at: "2026-05-17T00:00:00Z".to_owned(),
last_event_at: "2026-05-17T00:01:00Z".to_owned(),
harmful_event_count: 3,
quarantined_until: Some("2026-05-18T00:00:00Z".to_owned()),
reason: "redaction regression fixture".to_owned(),
status: "active".to_owned(),
created_at: "2026-05-17T00:00:00Z".to_owned(),
updated_at: "2026-05-17T00:01:00Z".to_owned(),
}
}
fn output_test_quarantine_report(source_id: String) -> QuarantineReport {
let entry = QuarantineEntry {
source_id,
advisory: AdvisoryLevel::Block,
effective_trust: 0.1,
decay_factor: 0.2,
negative_rate: 1.0,
negative_count: 3,
total_imports: 3,
message: "source is blocked".to_owned(),
permits_import: false,
requires_validation: true,
};
QuarantineReport {
version: "test",
quarantined_sources: Vec::new(),
at_risk_sources: Vec::new(),
blocked_sources: vec![entry],
summary: QuarantineSummary {
quarantined_count: 0,
at_risk_count: 0,
blocked_count: 1,
total_sources: 1,
healthy_count: 0,
},
storage_status: QuarantineStorageStatus::Ready,
workspace_path: None,
database_path: None,
degraded: Vec::new(),
}
}
#[test]
fn quarantine_entry_output_redacts_sensitive_source_uri() -> TestResult {
let mut entry = output_test_quarantine(
"file:///Users/alice/private/quarantine.json?api_key=redaction-fixture".to_owned(),
);
entry.reason =
"harmful burst from /Users/alice/private/quarantine.log?token=redaction-fixture"
.to_owned();
let json = render_quarantine_entry_json(&entry);
ensure_contains(
&json,
"[REDACTED_PATH]",
"quarantine entry JSON path redaction",
)?;
ensure_contains(
&json,
"[REDACTED:secret]",
"quarantine entry JSON secret redaction",
)?;
ensure(
!json.contains("/Users/alice") && !json.contains("redaction-fixture"),
format!("quarantine entry JSON leaked sensitive source URI: {json}"),
)?;
ensure(
!json.contains("quarantine.log"),
format!("quarantine entry JSON leaked sensitive reason path: {json}"),
)?;
let human = render_quarantine_entry_human(&entry);
ensure_contains(
&human,
"[REDACTED_PATH]",
"quarantine entry human path redaction",
)?;
ensure(
!human.contains("/Users/alice") && !human.contains("redaction-fixture"),
format!("quarantine entry human leaked sensitive source URI: {human}"),
)?;
ensure(
!human.contains("quarantine.log"),
format!("quarantine entry human leaked sensitive reason path: {human}"),
)?;
let toon = render_quarantine_entry_toon(&entry);
ensure(
!toon.contains("/Users/alice") && !toon.contains("redaction-fixture"),
format!("quarantine entry TOON leaked sensitive source URI: {toon}"),
)?;
ensure(
!toon.contains("quarantine.log"),
format!("quarantine entry TOON leaked sensitive reason path: {toon}"),
)
}
#[test]
fn quarantine_report_output_redacts_sensitive_source_id() -> TestResult {
let mut report = output_test_quarantine_report(
"file:///Volumes/USBNVME16TB/private/quarantine.json#token=redaction-fixture"
.to_owned(),
);
report
.degraded
.push(crate::core::quarantine::QuarantineDegradation {
code: "quarantine_state_unavailable",
severity: "medium",
message: "Quarantine state was only partially inspected.".to_owned(),
repair: "Run ee diag quarantine --json",
});
for (surface, rendered) in [
("json", render_quarantine_json(&report)),
("human", render_quarantine_human(&report)),
("toon", render_quarantine_toon(&report)),
(
"filtered",
render_quarantine_json_filtered(&report, FieldProfile::Full),
),
] {
ensure_contains(
&rendered,
"[REDACTED_PATH]",
format!("quarantine report {surface} path redaction").as_str(),
)?;
ensure(
!rendered.contains("/Volumes/USBNVME16TB")
&& !rendered.contains("redaction-fixture"),
format!("quarantine report {surface} leaked sensitive source id: {rendered}"),
)?;
}
for (context, rendered) in [
("quarantine JSON", render_quarantine_json(&report)),
(
"filtered quarantine JSON",
render_quarantine_json_filtered(&report, FieldProfile::Full),
),
] {
let value = parse_rendered_json(&rendered, context)?;
ensure_top_level_degraded_mirrors_data_degraded(&value, context)?;
}
Ok(())
}
#[test]
fn status_feedback_health_redacts_sensitive_source_ids() -> TestResult {
let mut report = StatusReport::gather();
report.feedback_health = FeedbackHealthReport {
status: FeedbackHealthStatus::ReviewQueued,
harmful_per_source_per_hour: 5,
harmful_burst_window_seconds: 60,
per_source_harmful_counts: vec![
FeedbackSourceHealth {
source_id:
"file:///Users/alice/private/feedback.jsonl?api_key=redaction-fixture"
.to_owned(),
harmful_count: 7,
},
FeedbackSourceHealth {
source_id: "cass://safe-source".to_owned(),
harmful_count: 1,
},
],
quarantine_queue_depth: 1,
protected_rule_count: 0,
last_inversion_event: None,
next_deterministic_action: "review quarantined feedback".to_owned(),
};
for (surface, rendered) in [
("json", render_status_json(&report)),
("toon", render_status_toon(&report)),
(
"filtered",
render_status_json_filtered(&report, FieldProfile::Full),
),
] {
ensure_contains(
&rendered,
"[REDACTED_PATH]",
format!("status feedback-health {surface} path redaction").as_str(),
)?;
ensure_contains(
&rendered,
"cass://safe-source",
format!("status feedback-health {surface} safe source preserved").as_str(),
)?;
ensure(
!rendered.contains("/Users/alice") && !rendered.contains("redaction-fixture"),
format!("status feedback-health {surface} leaked source id: {rendered}"),
)?;
}
Ok(())
}
#[test]
fn memory_show_output_preserves_local_path_and_redacts_secret_value() -> TestResult {
let source = "file:///Users/alice/private/logs/build.log?api_key=redaction-fixture";
let expected = "file:///Users/alice/private/logs/build.log?api_key=[REDACTED:secret]";
let report = MemoryShowReport::found(MemoryDetails {
memory: output_test_memory(Some(source.to_owned())),
tags: Vec::new(),
typed_fields: None,
});
let json = render_memory_show_json(&report);
let value: serde_json::Value =
serde_json::from_str(&json).map_err(|error| error.to_string())?;
ensure_equal(
&value
.pointer("/data/memoryId")
.and_then(serde_json::Value::as_str),
&Some("mem_output_redaction"),
"memory show root memoryId alias",
)?;
ensure_equal(
&value
.pointer("/data/memory/memoryId")
.and_then(serde_json::Value::as_str),
&Some("mem_output_redaction"),
"memory show nested memoryId alias",
)?;
ensure_equal(
&value
.pointer("/data/memory/id")
.and_then(serde_json::Value::as_str),
&Some("mem_output_redaction"),
"memory show compatibility id",
)?;
ensure_equal(
&value
.pointer("/data/memory/provenance_uri")
.and_then(serde_json::Value::as_str),
&Some(expected),
"memory show local provenance",
)?;
ensure(
!json.contains("[REDACTED_PATH]"),
format!("memory show JSON must preserve the local path: {json}"),
)?;
ensure_contains(&json, "[REDACTED:secret]", "memory show secret redaction")?;
ensure(
!json.contains("redaction-fixture"),
format!("memory show JSON leaked secret-like value: {json}"),
)?;
let human = render_memory_show_human(&report);
ensure_contains(&human, expected, "memory show human local provenance")?;
ensure(
!human.contains("redaction-fixture"),
format!("memory show human leaked secret-like value: {human}"),
)?;
let toon = render_memory_show_toon(&report);
ensure_toon_matches_json(&json, &toon, "memory show TOON local provenance")
}
#[test]
fn memory_list_output_preserves_local_path_and_redacts_secret_value() -> TestResult {
let source = "file:///Volumes/USBNVME16TB/private/index.json#token=redaction-fixture";
let expected = "file:///Volumes/USBNVME16TB/private/index.json#token=[REDACTED:secret]";
let report = MemoryListReport::success(
vec![MemorySummary {
id: "mem_output_redaction".to_owned(),
level: "procedural".to_owned(),
kind: "rule".to_owned(),
content: "Keep memory provenance output redacted.".to_owned(),
content_truncated: false,
confidence: 0.9,
provenance_uri: Some(source.to_owned()),
is_tombstoned: false,
valid_from: None,
valid_to: None,
validity_status: "current".to_owned(),
validity_window_kind: "unbounded".to_owned(),
created_at: "2026-05-17T00:00:00Z".to_owned(),
}],
1,
false,
MemoryListFilter::default(),
);
let json = render_memory_list_json(&report);
let value: serde_json::Value =
serde_json::from_str(&json).map_err(|error| error.to_string())?;
ensure_equal(
&value
.pointer("/data/memories/0/provenance_uri")
.and_then(serde_json::Value::as_str),
&Some(expected),
"memory list local provenance",
)?;
ensure(
!json.contains("[REDACTED_PATH]"),
format!("memory list JSON must preserve the local path: {json}"),
)?;
ensure_contains(&json, "[REDACTED:secret]", "memory list secret redaction")?;
ensure(
!json.contains("redaction-fixture"),
format!("memory list JSON leaked secret-like value: {json}"),
)?;
let toon = render_memory_list_toon(&report);
ensure_toon_matches_json(&json, &toon, "memory list TOON local provenance")
}
fn ensure_starts_with(haystack: &str, prefix: &str, context: &str) -> TestResult {
ensure(
haystack.starts_with(prefix),
format!("{context}: expected output to start with {prefix:?}, got {haystack:?}"),
)
}
#[test]
fn procedure_retire_renderers_are_response_enveloped() -> TestResult {
let report = crate::core::procedure::ProcedureRetireReport {
schema: crate::core::procedure::PROCEDURE_RETIRE_REPORT_SCHEMA_V1.to_owned(),
procedure_id: "proc_01234567890123456789012345678901".to_owned(),
status: "retired".to_owned(),
from_maturity: "validated".to_owned(),
to_maturity: "retired".to_owned(),
event_id: "pevt_01234567890123456789012345678901".to_owned(),
audit_id: "audit_01234567890123456789012345678901".to_owned(),
reason: "harmful evidence contradicted the procedure".to_owned(),
retired_at: "2026-05-07T00:00:00Z".to_owned(),
};
let json = super::render_procedure_retire_json(&report);
let parsed: serde_json::Value =
serde_json::from_str(&json).map_err(|error| error.to_string())?;
assert_eq!(parsed["schema"], RESPONSE_SCHEMA_V2);
assert_eq!(parsed["success"], true);
assert_eq!(parsed["data"]["command"], "procedure retire");
assert_eq!(parsed["degraded"], serde_json::json!([]));
assert_eq!(
parsed["data"]["schema"],
crate::core::procedure::PROCEDURE_RETIRE_REPORT_SCHEMA_V1
);
let human = super::render_procedure_retire_human(&report);
ensure_contains(&human, "Procedure Retired", "human heading")?;
ensure_contains(&human, "validated -> retired", "human maturity")?;
let toon = super::render_procedure_retire_toon(&report);
ensure_contains(&toon, "PROCEDURE_RETIRE", "toon command")?;
ensure_contains(
&toon,
"audit_01234567890123456789012345678901",
"toon audit",
)
}
fn memory_id(seed: u128) -> MemoryId {
MemoryId::from_uuid(Uuid::from_u128(seed))
}
fn score(value: f32) -> Result<UnitScore, String> {
UnitScore::parse(value).map_err(|error| format!("test score rejected: {error:?}"))
}
fn pack_provenance(uri: &str) -> Result<PackProvenance, String> {
let uri = ProvenanceUri::from_str(uri)
.map_err(|error| format!("test provenance URI rejected: {error:?}"))?;
PackProvenance::new(uri, "source evidence")
.map_err(|error| format!("test provenance rejected: {error:?}"))
}
fn output_context_from_env(environment: OutputEnvironment) -> OutputContext {
OutputContext::detect_with_environment(false, false, None, false, &environment)
}
fn context_response_fixture() -> Result<ContextResponse, String> {
context_response_fixture_with_query("prepare release")
}
fn context_response_fixture_with_query(query: &str) -> Result<ContextResponse, String> {
let request = ContextRequest::from_query(query)
.map_err(|error| format!("request rejected: {error:?}"))?;
let budget =
TokenBudget::new(100).map_err(|error| format!("budget rejected: {error:?}"))?;
let candidate = PackCandidate::new(PackCandidateInput {
memory_id: memory_id(42),
section: PackSection::ProceduralRules,
content: "Run cargo fmt --check before release.".to_string(),
estimated_tokens: 10,
relevance: score(0.8)?,
utility: score(0.6)?,
provenance: vec![pack_provenance("file://AGENTS.md#L42")?],
why: "selected because release checks match the task".to_string(),
})
.map(|candidate| {
candidate.with_trust_signal(PackTrustSignal::new(
TrustClass::HumanExplicit,
Some("project-rule".to_string()),
))
})
.map_err(|error| format!("candidate rejected: {error:?}"))?;
let draft = assemble_draft(&request.query, budget, vec![candidate])
.map_err(|error| format!("draft rejected: {error:?}"))?;
ContextResponse::new(request, draft, Vec::new())
.map_err(|error| format!("response rejected: {error:?}"))
}
fn learn_experiment_proposal_fixture() -> LearnExperimentProposalReport {
LearnExperimentProposalReport {
schema: LEARN_EXPERIMENT_PROPOSAL_SCHEMA_V1.to_string(),
total_candidates: 3,
returned: 1,
min_expected_value: 0.3,
max_attention_tokens: 800,
max_runtime_seconds: 180,
generated_at: "2026-01-02T03:04:05Z".to_string(),
proposals: vec![ExperimentProposal {
experiment_id: "exp_renderer_fixture".to_string(),
question_id: "gap_renderer_fixture".to_string(),
title: "Render experiment proposal contract".to_string(),
hypothesis: "A fixed renderer fixture preserves proposal JSON, human, and TOON output without invoking unavailable learn records.".to_string(),
status: "proposed".to_string(),
topic: "renderer_contract".to_string(),
expected_value: 0.539,
uncertainty_reduction: 0.32,
confidence: 0.48,
budget: ExperimentBudget {
attention_tokens: 800,
max_runtime_seconds: 180,
dry_run_required: true,
budget_class: "medium".to_string(),
},
safety: ExperimentSafetyPlan {
boundary: "human_review".to_string(),
dry_run_first: true,
mutation_allowed: false,
review_required: true,
stop_conditions: vec![
"Stop after renderer output is validated.".to_string(),
"Stop before any durable memory mutation.".to_string(),
],
denied_reasons: Vec::new(),
},
decision_impact: ExperimentDecisionImpact {
decision_id: "decision_renderer_fixture".to_string(),
target_artifact_ids: vec!["mem_renderer_fixture".to_string()],
current_decision: "Keep proposal renderer output stable.".to_string(),
possible_change: "Update only renderer contracts when the public shape changes."
.to_string(),
impact_score: 0.85,
},
evidence_ids: vec!["gap_renderer_fixture".to_string()],
next_command: "ee learn experiment run --dry-run --id exp_renderer_fixture --json"
.to_string(),
}],
}
}
#[test]
fn learn_experiment_proposal_json_exposes_ev_budget_safety_and_decision() -> TestResult {
let report = learn_experiment_proposal_fixture();
let json = render_learn_experiment_proposal_json(&report);
let value: serde_json::Value =
serde_json::from_str(&json).map_err(|error| error.to_string())?;
ensure_contains(&json, "\"expectedValue\"", "expected value field")?;
ensure_contains(&json, "\"budget\"", "budget field")?;
ensure_contains(&json, "\"safety\"", "safety field")?;
ensure_contains(&json, "\"decisionImpact\"", "decision impact field")?;
ensure(
value.get("success").and_then(serde_json::Value::as_bool) == Some(true),
"proposal JSON must be successful",
)?;
ensure(
value
.get("proposals")
.and_then(serde_json::Value::as_array)
.is_some_and(|items| !items.is_empty()),
"proposal JSON must include proposals",
)
}
#[test]
fn learn_experiment_proposal_human_and_toon_are_stable() -> TestResult {
let report = learn_experiment_proposal_fixture();
let human = render_learn_experiment_proposal_human(&report);
ensure_contains(&human, "Learning Experiment Proposals", "human title")?;
ensure_contains(&human, "Decision impact:", "human decision impact")?;
ensure_contains(&human, "ee learn experiment run --dry-run", "human next")?;
let toon = render_learn_experiment_proposal_toon(&report);
ensure_starts_with(
&toon,
"LEARN_EXPERIMENT_PROPOSAL|returned=1|candidates=3",
"toon prefix",
)
}
fn version_report_fixture(
git_commit: Option<&'static str>,
git_tag: Option<&'static str>,
git_dirty: Option<bool>,
target_triple: &'static str,
build_profile: &'static str,
release_channel: &'static str,
degradations: Vec<BuildProvenanceDegradation>,
) -> VersionReport {
VersionReport {
build: BuildInfo {
package: "ee",
version: "9.9.9",
git_commit,
git_tag,
git_dirty,
target_triple,
target_arch: "x86_64",
target_os: "linux",
build_profile,
release_channel,
build_timestamp_policy: BUILD_TIMESTAMP_POLICY,
min_db_migration: 1,
max_db_migration: 14,
},
features: vec![
BuildFeature::new("fts5", true),
BuildFeature::new("json", true),
BuildFeature::new("mcp", false),
BuildFeature::new("serve", false),
],
schemas: vec![
SupportedSchema::new("response", RESPONSE_SCHEMA_V2),
SupportedSchema::new("error", ERROR_SCHEMA_V2),
SupportedSchema::new("version_provenance", VERSION_PROVENANCE_SCHEMA_V1),
],
degradations,
}
}
#[test]
fn version_json_release_clean_fixture_has_full_provenance() -> TestResult {
let report = version_report_fixture(
Some("abcdef123456"),
Some("v9.9.9"),
Some(false),
"x86_64-unknown-linux-gnu",
"release",
"stable",
Vec::new(),
);
let json = render_version_json(&report);
ensure_starts_with(&json, "{\"schema\":\"ee.response.v2\"", "response schema")?;
ensure_contains(&json, "\"command\":\"version\"", "command")?;
ensure_contains(
&json,
"\"schema\":\"ee.version.provenance.v1\"",
"version schema",
)?;
ensure_contains(&json, "\"releaseChannel\":\"stable\"", "release channel")?;
ensure_contains(&json, "\"gitCommit\":\"abcdef123456\"", "git commit")?;
ensure_contains(&json, "\"gitTag\":\"v9.9.9\"", "git tag")?;
ensure_contains(&json, "\"gitDirty\":false", "clean source")?;
ensure_contains(&json, "\"state\":\"clean\"", "clean state")?;
ensure_contains(&json, "\"profile\":\"release\"", "release profile")?;
ensure_contains(
&json,
"\"targetTriple\":\"x86_64-unknown-linux-gnu\"",
"target triple",
)?;
ensure_contains(
&json,
"\"timestampPolicy\":\"omitted_for_reproducibility\",\"timestamp\":null",
"timestamp policy",
)?;
ensure_contains(&json, "\"available\":true", "available provenance")
}
#[test]
fn version_json_dirty_fixture_reports_dirty_source() -> TestResult {
let report = version_report_fixture(
Some("abcdef123456"),
Some("v9.9.9-dirty"),
Some(true),
"x86_64-unknown-linux-gnu",
"debug",
"dev",
Vec::new(),
);
let json = render_version_json(&report);
ensure_contains(&json, "\"gitDirty\":true", "dirty flag")?;
ensure_contains(&json, "\"state\":\"dirty\"", "dirty state")?;
ensure_contains(&json, "\"releaseChannel\":\"dev\"", "dev channel")
}
#[test]
fn version_json_missing_metadata_fixture_reports_degradations() -> TestResult {
let report = version_report_fixture(
None,
None,
None,
"unknown",
"debug",
"dev",
vec![
BuildProvenanceDegradation::new(
"git_metadata_unavailable",
"low",
"Git source metadata was not provided by the build.",
"Build with VERGEN_GIT_SHA, VERGEN_GIT_DESCRIBE, and VERGEN_GIT_DIRTY set.",
),
BuildProvenanceDegradation::new(
"target_triple_unavailable",
"low",
"Target triple was not provided by the build.",
"Build with EE_BUILD_TARGET set to the target triple.",
),
],
);
let json = render_version_json(&report);
ensure_contains(&json, "\"gitCommit\":null", "missing commit")?;
ensure_contains(&json, "\"gitTag\":null", "missing tag")?;
ensure_contains(&json, "\"gitDirty\":null", "missing dirty flag")?;
ensure_contains(&json, "\"state\":\"unavailable\"", "unavailable state")?;
ensure_contains(&json, "\"available\":false", "degraded provenance")?;
ensure_contains(
&json,
"\"code\":\"git_metadata_unavailable\"",
"git degradation",
)?;
ensure_contains(
&json,
"\"code\":\"target_triple_unavailable\"",
"target degradation",
)
}
#[test]
fn version_json_feature_and_db_contracts_are_stable() -> TestResult {
let report = version_report_fixture(
Some("abcdef123456"),
Some("v9.9.9"),
Some(false),
"x86_64-unknown-linux-gnu",
"release",
"stable",
Vec::new(),
);
let json = render_version_json(&report);
ensure_contains(
&json,
"\"features\":[{\"name\":\"fts5\",\"enabled\":true},{\"name\":\"json\",\"enabled\":true},{\"name\":\"mcp\",\"enabled\":false},{\"name\":\"serve\",\"enabled\":false}]",
"feature order and adapter flags",
)?;
ensure_contains(
&json,
"\"supportedMigrationRange\":{\"min\":1,\"max\":14}",
"database range",
)?;
ensure_contains(
&json,
"\"compatibility\":\"unknown_without_workspace\"",
"workspace compatibility state",
)?;
let assignment_needle = concat!("TOKEN", "=");
ensure(
!json.contains("/tmp/")
&& !json.contains(assignment_needle)
&& !json.contains("ubuntu"),
"version JSON must not leak build paths, usernames, or assignment-like secrets",
)
}
#[test]
fn status_json_has_stable_schema_and_degradation_codes() -> TestResult {
let json = status_response_json();
ensure_starts_with(&json, "{\"schema\":\"ee.response.v2\"", "status schema")?;
ensure_contains(&json, "\"success\":true", "status success flag")?;
ensure_contains(&json, "\"runtime\":\"ready\"", "status runtime capability")?;
ensure_contains(&json, "\"engine\":\"asupersync\"", "status runtime engine")?;
ensure_contains(
&json,
"\"profile\":\"current_thread\"",
"status runtime profile",
)?;
// After fix: gather() inspects current workspace, so we get actual
// degradation codes (degraded/missing) instead of not_inspected.
ensure_contains(&json, "\"degraded\":[", "status degraded array")?;
ensure_contains(&json, "\"derivedAssets\":[", "derived assets")?;
ensure_contains(&json, "\"shardFanout\":{", "shard fanout status")?;
ensure_contains(
&json,
"\"schema\":\"ee.shard_fanout.status.v1\"",
"shard fanout schema",
)?;
ensure_contains(&json, "\"name\":\"search_index\"", "search index asset")
}
#[test]
fn manual_response_v2_json_renderers_emit_top_level_degraded() -> TestResult {
let status = StatusReport::gather();
for (context, json) in [
("status JSON", render_status_json(&status)),
(
"status JSON with meta",
render_status_json_with_meta(&status, None),
),
(
"status skyline JSON",
render_status_skyline_json(&sample_status_skyline_report()),
),
] {
let value = parse_rendered_json(&json, context)?;
ensure_top_level_degraded_mirrors_data_degraded(&value, context)?;
}
let capabilities = capabilities_report_fixture();
let check = crate::core::check::CheckReport::gather();
let streams = crate::core::streams::StreamsReport {
stdout_isolated: true,
stderr_received_probe: true,
stderr_probe_message: "test probe".to_owned(),
version: env!("CARGO_PKG_VERSION"),
};
let eval = crate::eval::EvaluationReport::new();
for (context, json) in [
("capabilities JSON", render_capabilities_json(&capabilities)),
(
"filtered capabilities JSON",
render_capabilities_json_filtered(&capabilities, FieldProfile::Standard),
),
("check JSON", render_check_json(&check)),
(
"filtered check JSON",
render_check_json_filtered(&check, FieldProfile::Standard),
),
(
"graph diagnostics JSON",
render_graph_diag_json(&crate::graph::module_readiness()),
),
("streams diagnostics JSON", render_streams_json(&streams)),
("evaluation JSON", render_eval_report_json(&eval, None)),
("evaluation list JSON", render_eval_list_json(&[], None)),
("MCP manifest JSON", render_mcp_manifest_json()),
("help JSON", help_json()),
("introspect JSON", render_introspect_json()),
("schema list JSON", render_schema_list_json()),
] {
let value = parse_rendered_json(&json, context)?;
ensure_empty_top_level_degraded(&value, context)?;
}
let memory = output_test_memory(None);
let memory_show = MemoryShowReport::found(MemoryDetails {
memory: memory.clone(),
tags: Vec::new(),
typed_fields: None,
});
let memory_list = MemoryListReport::success(
vec![MemorySummary {
id: memory.id.clone(),
level: memory.level.clone(),
kind: memory.kind.clone(),
content: memory.content.clone(),
content_truncated: false,
confidence: memory.confidence,
provenance_uri: memory.provenance_uri.clone(),
is_tombstoned: memory.tombstoned_at.is_some(),
valid_from: memory.valid_from.clone(),
valid_to: memory.valid_to.clone(),
validity_status: "current".to_owned(),
validity_window_kind: "unbounded".to_owned(),
created_at: memory.created_at.clone(),
}],
1,
false,
MemoryListFilter::default(),
);
let memory_history =
MemoryHistoryReport::found(memory.id.clone(), false, Vec::new(), 0, false);
let fix_plan = FixPlan {
version: env!("CARGO_PKG_VERSION"),
total_issues: 0,
fixable_issues: 0,
steps: Vec::new(),
cass_import_guidance: CassImportGuidance {
status: CassImportGuidanceStatus::NotInspected,
detected_agent_count: 0,
detected_root_count: 0,
roots: Vec::new(),
suggested_commands: Vec::new(),
message: "Agent source roots were not inspected for this fix plan.".to_owned(),
},
};
for (context, json) in [
("fix plan JSON", render_fix_plan_json(&fix_plan)),
("memory show JSON", render_memory_show_json(&memory_show)),
("memory list JSON", render_memory_list_json(&memory_list)),
(
"memory history JSON",
render_memory_history_json(&memory_history),
),
] {
let value = parse_rendered_json(&json, context)?;
ensure_empty_top_level_degraded(&value, context)?;
}
Ok(())
}
#[test]
fn status_json_aggregates_duplicate_degradation_codes() -> TestResult {
let mut report = StatusReport::gather();
report.degradations = vec![
DegradationReport {
code: "storage_unavailable",
severity: "low",
message: "Storage was not initialized.",
repair: "Run ee init --workspace .",
},
DegradationReport {
code: "storage_unavailable",
severity: "high",
message: "Storage was unavailable for this response.",
repair: "Inspect the database path.",
},
DegradationReport {
code: "index_stale",
severity: "medium",
message: "Search index is stale.",
repair: "Run ee index rebuild --workspace .",
},
];
let value: serde_json::Value = serde_json::from_str(&render_status_json(&report))
.map_err(|error| error.to_string())?;
let degraded = value
.pointer("/data/degraded")
.and_then(serde_json::Value::as_array)
.ok_or_else(|| "status JSON has degraded array".to_string())?;
ensure_equal(
&serde_json::Value::from(degraded.len()),
&serde_json::json!(2),
"duplicate degraded codes are collapsed",
)?;
ensure_equal(
°raded[0]["code"],
&serde_json::json!("storage_unavailable"),
"highest-severity aggregate sorts first",
)?;
ensure_equal(
°raded[0]["severity"],
&serde_json::json!("high"),
"duplicate code escalates severity",
)?;
ensure_equal(
°raded[0]["sources"],
&serde_json::json!(["status"]),
"status source label is preserved",
)
}
#[test]
fn status_json_aggregates_tailscale_degradation_codes() -> TestResult {
let mut report = StatusReport::gather();
let mut tailscale = TailscaleLocalReport::timed_out(
TailscaleProbeMethod::Cli,
1_501,
DEFAULT_TAILSCALE_PROBE_TIMEOUT_MS,
TailscalePlatform::Other,
);
tailscale.degradations.push(
TailscaleLocalReport::timed_out(
TailscaleProbeMethod::Cli,
1_501,
DEFAULT_TAILSCALE_PROBE_TIMEOUT_MS,
TailscalePlatform::Other,
)
.degradations[0]
.clone(),
);
report.tailscale_local = Some(tailscale);
let value: serde_json::Value = serde_json::from_str(&render_status_json(&report))
.map_err(|error| error.to_string())?;
let degraded = value
.pointer("/data/mesh/tailscale/degraded")
.and_then(serde_json::Value::as_array)
.ok_or_else(|| "tailscale status JSON has degraded array".to_string())?;
ensure_equal(
&serde_json::Value::from(degraded.len()),
&serde_json::json!(1),
"duplicate tailscale degraded codes are collapsed",
)?;
ensure_equal(
°raded[0]["code"],
&serde_json::json!("tailscale_probe_timeout"),
"tailscale degradation code is preserved",
)?;
ensure_equal(
°raded[0]["sources"],
&serde_json::json!(["tailscale_status"]),
"tailscale source label is preserved",
)
}
#[test]
fn status_json_renders_mesh_storage_counts_without_peer_identifiers() -> TestResult {
let mut report = StatusReport::gather();
report.mesh_storage = Some(MeshStorageStatusReport {
peer_count: 2,
cursor_count: 3,
imported_event_count: 5,
policy_decision_event_count: 13,
policy_failure_event_count: 1,
mapped_memory_count: 7,
cached_body_count: 11,
});
let value: serde_json::Value = serde_json::from_str(&render_status_json(&report))
.map_err(|error| error.to_string())?;
let storage = value
.pointer("/data/mesh/storage")
.ok_or_else(|| "status JSON has mesh storage posture".to_string())?;
ensure_equal(
&storage["schema"],
&serde_json::json!("ee.mesh.storage_status.v1"),
"mesh storage schema",
)?;
ensure_equal(
&storage["importedEventCount"],
&serde_json::json!(5),
"imported event count",
)?;
ensure_equal(
&storage["policyDecisionEventCount"],
&serde_json::json!(13),
"policy decision count",
)?;
ensure_equal(
&storage["policyFailureEventCount"],
&serde_json::json!(1),
"policy failure count",
)?;
ensure_equal(&storage["hasRows"], &serde_json::json!(true), "has rows")?;
ensure(
storage.get("producerPeerId").is_none(),
"mesh storage status must not expose peer identifiers",
)
}
#[test]
fn status_json_embeds_workspace_storage_posture_object() -> TestResult {
let temp = tempfile::tempdir().map_err(|error| error.to_string())?;
crate::core::write_owner::mark_write_replay_required(temp.path())
.map_err(|error| error.to_string())?;
let report = StatusReport::gather_for_workspace(temp.path());
let json = render_status_json(&report);
let parsed: serde_json::Value =
serde_json::from_str(&json).map_err(|error| error.to_string())?;
ensure(
parsed["data"]["posture"]["workspace"]["storage"]["status"] == "degraded_recoverable",
"storage posture status is nested under posture.workspace.storage",
)?;
ensure(
parsed["data"]["posture"]["workspace"]["storage"]["reason"]
== "uncommitted_write_replay_required",
"storage posture reason is nested under posture.workspace.storage",
)
}
#[test]
fn status_json_exposes_rch_worker_pressure() -> TestResult {
let mut report = StatusReport::gather();
report.rch_worker_pressure = rch_worker_pressure_fixture();
let value = serde_json::from_str::<serde_json::Value>(&render_status_json(&report))
.map_err(|error| format!("status JSON should parse: {error}"))?;
let pressure = value
.pointer("/data/rchWorkerPressure")
.ok_or_else(|| "status JSON has data.rchWorkerPressure object".to_string())?;
ensure_equal(
&pressure["schema"],
&serde_json::json!("ee.rch.worker_pressure.v1"),
"rch worker pressure schema",
)?;
ensure_equal(
&pressure["blockedWorkerCount"],
&serde_json::json!(1),
"blocked worker count",
)?;
ensure_equal(
&pressure["workers"][0]["admissionImpact"],
&serde_json::json!("blocked"),
"admission impact",
)
}
#[test]
fn status_json_exposes_verification_posture() -> TestResult {
let mut report = StatusReport::gather();
report.verification_posture = verification_posture_fixture();
let value = serde_json::from_str::<serde_json::Value>(&render_status_json(&report))
.map_err(|error| format!("status JSON should parse: {error}"))?;
let posture = value
.pointer("/data/verificationPosture")
.ok_or_else(|| "status JSON has data.verificationPosture object".to_string())?;
ensure_equal(
&posture["schema"],
&serde_json::json!("ee.verification.posture.v1"),
"verification posture schema",
)?;
ensure_equal(
&posture["recentReusableRunCount"],
&serde_json::json!(1),
"recent reusable run count",
)?;
ensure_equal(
&posture["advisoryCounts"]["localDisallowed"],
&serde_json::json!(1),
"local disallowed count",
)
}
#[test]
fn human_status_is_not_json() -> TestResult {
let status = human_status();
ensure_starts_with(&status, "ee status", "human status heading")?;
ensure(!status.starts_with('{'), "human status must not be JSON")
}
#[test]
fn help_mentions_supported_skeleton_commands() -> TestResult {
let help = help_text();
ensure_contains(help, "ee status [--json]", "help status command")?;
ensure_contains(help, "ee --version", "help version command")
}
#[test]
fn schema_json_returns_response_json_schema_not_stub_catalog() -> TestResult {
let output = schema_json();
let parsed = serde_json::from_str::<serde_json::Value>(&output)
.map_err(|error| format!("schema_json must emit valid JSON: {error}"))?;
ensure_equal(
&parsed["schema"],
&serde_json::json!(RESPONSE_SCHEMA_V2),
"schema envelope id",
)?;
ensure_equal(
&parsed["data"]["command"],
&serde_json::json!("schema"),
"schema command",
)?;
ensure_equal(
&parsed["data"]["schemaId"],
&serde_json::json!(RESPONSE_SCHEMA_V2),
"exported schema id",
)?;
let definition = &parsed["data"]["definition"];
ensure_equal(
&definition["$schema"],
&serde_json::json!("https://json-schema.org/draft/2020-12/schema"),
"json schema dialect",
)?;
ensure_equal(
&definition["$id"],
&serde_json::json!("https://eidetic-engine/schemas/ee.response.v2.json"),
"response schema id",
)?;
ensure_equal(
&definition["title"],
&serde_json::json!(RESPONSE_SCHEMA_V2),
"response schema title",
)?;
ensure(
parsed["data"].get("schemas").is_none(),
"global --schema must not return the old schema-id catalog",
)
}
#[test]
fn error_json_has_stable_schema_and_code() -> TestResult {
let error = DomainError::Usage {
message: "unrecognized subcommand 'foo'".to_string(),
repair: Some("ee --help".to_string()),
};
let json = error_response_json(&error);
ensure_starts_with(&json, "{\"schema\":\"ee.error.v2\"", "error schema")?;
ensure_contains(&json, "\"code\":\"usage\"", "error code")?;
ensure_contains(
&json,
"\"message\":\"unrecognized subcommand 'foo'\"",
"error message",
)?;
ensure_contains(&json, "\"severity\":\"low\"", "error severity")?;
ensure_contains(&json, "\"repair\":\"ee --help\"", "error repair")
}
#[test]
fn workspace_store_missing_merges_discovery_details_and_exact_recovery() -> TestResult {
let error = DomainError::WorkspaceStoreMissing {
message: "Database not found at /tmp/missing/.ee/ee.db".to_owned(),
repair: Some("Re-check --workspace addressing".to_owned()),
details_json: serde_json::json!({
"addressedStorePath": "/tmp/missing/.ee/ee.db",
"storeDiscovery": {
"scanned": true,
"truncated": false,
"nearbyStores": [{
"workspaceRoot": "/tmp/populated",
"storeDir": "/tmp/populated/.ee",
"documents": 4,
"lastWrite": null,
}],
},
})
.to_string(),
recovery_actions: vec![crate::models::RecoveryAction::flag(
1,
"--workspace",
"/tmp/populated",
"Retarget to the populated workspace.",
)],
};
let parsed: serde_json::Value = serde_json::from_str(&error_response_json(&error))
.map_err(|error| format!("workspace-store error JSON must parse: {error}"))?;
ensure_equal(
&parsed["error"]["details"]["addressedStorePath"],
&serde_json::json!("/tmp/missing/.ee/ee.db"),
"addressed store detail",
)?;
ensure_equal(
&parsed["error"]["details"]["storeDiscovery"]["nearbyStores"][0]["documents"],
&serde_json::json!(4),
"live nearby-store count",
)?;
ensure_equal(
&parsed["error"]["details"]["recovery"][0]["valueHint"],
&serde_json::json!("/tmp/populated"),
"exact recovery value",
)
}
#[test]
fn error_json_scrubs_mesh_approval_bearers_after_complete_envelope_assembly() -> TestResult {
let bearer = mesh_approval_bearer_canary();
ensure_equal(
&bearer.len(),
&crate::mesh::lane_grant::APPROVAL_TOKEN_BEARER_LEN,
"approval bearer canary length",
)?;
let unrelated_secret = format!("{}{}", ["g", "h", "p", "_"].concat(), "B".repeat(36));
let error = DomainError::UsageCodeWithDetails {
code: "usage",
message: format!("request failed with bearer {bearer}; marker {unrelated_secret}"),
repair: Some(format!("retry with --approval-token {bearer}")),
details_json: serde_json::json!({
"nested": {
"example": format!("nested example {bearer}"),
},
"recovery": [{
"command": format!("ee mesh grant --approval-token {bearer}"),
"rationale": format!("replace leaked bearer {bearer}"),
"example": format!("printf '%s' '{bearer}' | ee mesh grant"),
}],
})
.to_string(),
};
let json = error_response_json(&error);
ensure(
!json.contains(&bearer),
"complete JSON error envelope must not expose the approval bearer",
)?;
ensure_contains(
&json,
"[REDACTED:mesh_approval_token]",
"approval bearer placeholder",
)?;
ensure_contains(
&json,
&unrelated_secret,
"targeted approval-token pass must preserve unrelated spans",
)?;
let parsed: serde_json::Value = serde_json::from_str(&json)
.map_err(|error| format!("redacted error envelope must remain JSON: {error}"))?;
for pointer in [
"/error/message",
"/error/repair",
"/error/details/nested/example",
"/error/details/recovery/0/command",
"/error/details/recovery/0/rationale",
"/error/details/recovery/0/example",
] {
let value = parsed
.pointer(pointer)
.and_then(serde_json::Value::as_str)
.ok_or_else(|| format!("missing redaction canary field {pointer}"))?;
ensure(
value.contains("[REDACTED:mesh_approval_token]") && !value.contains(&bearer),
format!("error field {pointer} must be approval-token safe: {value:?}"),
)?;
}
Ok(())
}
#[test]
fn mesh_approval_bearer_span_replacement_fails_closed_on_invalid_ranges() -> TestResult {
let redacted = redact_mesh_approval_bearer_spans("safe text", &[(2, usize::MAX)]);
ensure_equal(
&redacted,
&"[REDACTED:mesh_approval_token]".to_owned(),
"invalid approval-token span must redact the whole projection",
)?;
let unrelated_secret = format!("{}{}", ["g", "h", "p", "_"].concat(), "B".repeat(36));
ensure_equal(
&redact_mesh_approval_bearers(&unrelated_secret),
&unrelated_secret,
"approval-token egress pass must not replace other secret classes",
)
}
#[test]
fn mesh_approval_token_invalid_is_high_without_authentication_oracle_details() -> TestResult {
let error = DomainError::UsageCodeWithDetails {
code: "mesh_approval_token_invalid",
message: "mesh approval token is invalid".to_string(),
repair: Some(
"ee mesh preview-grant peer_example --lane body --issue-approval-token --json"
.to_string(),
),
details_json: serde_json::json!({
"recovery": [{
"priority": 0,
"kind": "command",
"command": "ee mesh preview-grant peer_example --lane body --issue-approval-token --json",
"rationale": "Issue a fresh approval in the current store and workspace.",
"riskClass": "read_only_probe",
"requiresHumanApproval": false,
"mutatesExternalState": false,
"mutatesTrackerState": false,
"privacyClass": "sensitive_bearer_issuance",
}],
})
.to_string(),
};
let json = error_response_json(&error);
ensure_contains(
&json,
"\"code\":\"mesh_approval_token_invalid\"",
"invalid token code",
)?;
ensure_contains(&json, "\"severity\":\"high\"", "invalid token severity")?;
for forbidden in [
"approvalToken",
"eeap1_",
"snapshotTag",
"envelopeMac",
"keyId",
] {
ensure(
!json.contains(forbidden),
format!("invalid-token error must not expose {forbidden}"),
)?;
}
Ok(())
}
#[test]
fn mesh_approval_token_stale_is_warning_and_contains_no_replacement_bearer() -> TestResult {
let error = DomainError::UsageCodeWithDetails {
code: "mesh_approval_token_stale",
message: "mesh approval token is stale; preview again".to_string(),
repair: Some(
"ee mesh preview-grant peer_example --lane body --issue-approval-token --json"
.to_string(),
),
details_json: serde_json::json!({
"recovery": [{
"priority": 0,
"kind": "command",
"command": "ee mesh preview-grant peer_example --lane body --issue-approval-token --json",
"rationale": "Rebuild the approval snapshot against current state.",
"riskClass": "read_only_probe",
"requiresHumanApproval": false,
"mutatesExternalState": false,
"mutatesTrackerState": false,
"privacyClass": "sensitive_bearer_issuance",
}],
})
.to_string(),
};
let json = error_response_json(&error);
ensure_contains(
&json,
"\"code\":\"mesh_approval_token_stale\"",
"stale token code",
)?;
ensure_contains(&json, "\"severity\":\"warning\"", "stale token severity")?;
ensure(
!json.contains("approvalToken") && !json.contains("eeap1_"),
"stale-token error must require a separate preview without returning a bearer",
)
}
#[test]
fn error_json_without_repair_omits_repair_but_keeps_details() -> TestResult {
let error = DomainError::Storage {
message: "Database locked".to_string(),
repair: None,
};
let json = error_response_json(&error);
ensure_starts_with(&json, "{\"schema\":\"ee.error.v2\"", "error schema")?;
ensure_contains(&json, "\"code\":\"storage\"", "error code")?;
ensure_contains(&json, "\"severity\":\"high\"", "error severity")?;
ensure_contains(&json, "\"details\":{}", "empty details object")?;
ensure(!json.contains("repair"), "repair field should be absent")
}
#[test]
fn cass_import_error_json_includes_degraded_code() -> TestResult {
let error = DomainError::Import {
message: "cass binary '/missing/cass' is not allowed: EE_CASS_BINARY path does not exist or is not a file".to_string(),
repair: Some(
"set EE_CASS_BINARY or [cass.binary] to an absolute trusted cass executable"
.to_string(),
),
};
let json = error_response_json(&error);
ensure_contains(&json, "\"code\":\"cass_unavailable\"", "degraded code")?;
ensure_contains(&json, "\"severity\":\"medium\"", "degraded severity")?;
ensure_contains(&json, "cass unavailable", "degraded message")?;
ensure_contains(&json, "EE_CASS_BINARY", "degraded repair")
}
#[test]
fn cass_import_error_json_merges_subprocess_diagnostics_details() -> TestResult {
let error = DomainError::ImportWithDetails {
message: "cass command `cass view` failed with exit None:".to_string(),
repair: Some("run cass health --json".to_string()),
details_json: serde_json::json!({
"subprocessDiagnostics": {
"schema": "ee.cass.subprocess_diagnostics.v1",
"outcome": "timeout",
"command": "cass view",
"timeout": true,
"killAttempted": true,
"reapSucceeded": true,
},
})
.to_string(),
};
let json = error_response_json(&error);
ensure_contains(&json, "\"code\":\"import\"", "error code")?;
ensure_contains(
&json,
"\"subprocessDiagnostics\":{",
"subprocess diagnostics details",
)?;
ensure_contains(
&json,
"\"schema\":\"ee.cass.subprocess_diagnostics.v1\"",
"diagnostics schema",
)?;
ensure_contains(&json, "\"outcome\":\"timeout\"", "diagnostics outcome")?;
ensure_contains(&json, "\"killAttempted\":true", "kill attempted")
}
#[test]
fn escape_json_handles_special_chars() -> TestResult {
let escaped = escape_json_string("line1\nline2\ttab\"quote\\backslash");
ensure_contains(&escaped, "\\n", "newline escape")?;
ensure_contains(&escaped, "\\t", "tab escape")?;
ensure_contains(&escaped, "\\\"", "quote escape")?;
ensure_contains(&escaped, "\\\\", "backslash escape")
}
#[test]
fn json_builder_constructs_simple_object() -> TestResult {
let mut b = JsonBuilder::new();
b.field_str("name", "test");
b.field_bool("active", true);
b.field_u32("count", 42);
let json = b.finish();
ensure_contains(&json, "\"name\":\"test\"", "string field")?;
ensure_contains(&json, "\"active\":true", "bool field")?;
ensure_contains(&json, "\"count\":42", "u32 field")?;
ensure(
json.starts_with('{') && json.ends_with('}'),
"valid JSON object",
)
}
#[test]
fn json_builder_escapes_string_values() -> TestResult {
let mut b = JsonBuilder::new();
b.field_str("message", "line1\nline2");
let json = b.finish();
ensure_contains(&json, "\"message\":\"line1\\nline2\"", "escaped newline")
}
#[test]
fn json_builder_supports_nested_objects() -> TestResult {
let mut b = JsonBuilder::new();
b.field_str("schema", "test.v1");
b.field_object("data", |obj| {
obj.field_str("inner", "value");
});
let json = b.finish();
ensure_contains(&json, "\"schema\":\"test.v1\"", "outer field")?;
ensure_contains(&json, "\"data\":{\"inner\":\"value\"}", "nested object")
}
#[test]
fn json_builder_supports_array_of_objects() -> TestResult {
let items = vec![("a", 1u32), ("b", 2u32)];
let mut b = JsonBuilder::new();
b.field_array_of_objects("items", &items, |obj, (name, val)| {
obj.field_str("name", name);
obj.field_u32("value", *val);
});
let json = b.finish();
ensure_contains(&json, "\"items\":[", "array start")?;
ensure_contains(&json, "{\"name\":\"a\",\"value\":1}", "first item")?;
ensure_contains(&json, "{\"name\":\"b\",\"value\":2}", "second item")
}
#[test]
fn json_builder_raw_field_allows_prebuilt_json() -> TestResult {
let mut b = JsonBuilder::new();
b.field_raw("config", "[1,2,3]");
let json = b.finish();
ensure_contains(&json, "\"config\":[1,2,3]", "raw json array")
}
#[test]
fn integrity_diagnostics_json_marks_uncollected_provenance_sample() -> TestResult {
let report = IntegrityDiagnosticsReport {
version: "0.1.0",
schema: crate::core::doctor::INTEGRITY_DIAGNOSTICS_SCHEMA_V1,
status: IntegrityDiagnosticsStatus::Degraded,
workspace_id: "default".to_owned(),
database_path: PathBuf::from("missing.db"),
sample_size: 16,
checks: vec![IntegrityDiagnosticCheck::warning(
"database_exists",
"Database not found.",
Some("ee init --workspace ."),
)],
provenance_sample: None,
canary: IntegrityCanaryReport::not_requested(),
degraded: vec![IntegrityDiagnosticDegradation {
code: "integrity_database_missing",
severity: "medium",
message: "Integrity checks require an initialized ee database.".to_owned(),
repair: Some("ee init --workspace ."),
}],
};
let json = render_integrity_diagnostics_json(&report);
let value: serde_json::Value =
serde_json::from_str(&json).map_err(|error| error.to_string())?;
ensure_top_level_degraded_mirrors_data_degraded(&value, "integrity diagnostics JSON")?;
let sample = &value["data"]["provenanceSample"];
ensure_equal(
&sample["status"],
&serde_json::json!("not_collected"),
"uncollected provenance sample status",
)?;
ensure_equal(
&sample["requestedSampleSize"],
&serde_json::json!(16),
"uncollected provenance requested sample size",
)?;
ensure(
sample.get("checkedCount").is_none(),
"uncollected provenance must not fabricate checkedCount",
)?;
ensure(
sample.get("verifiedCount").is_none(),
"uncollected provenance must not fabricate verifiedCount",
)?;
ensure(
sample.get("records").is_none(),
"uncollected provenance must not fabricate an empty records array",
)
}
#[test]
fn renderer_wire_names_are_stable() -> TestResult {
ensure_equal(&Renderer::Human.as_str(), &"human", "human")?;
ensure_equal(&Renderer::Json.as_str(), &"json", "json")?;
ensure_equal(&Renderer::Toon.as_str(), &"toon", "toon")?;
ensure_equal(&Renderer::Jsonl.as_str(), &"jsonl", "jsonl")?;
ensure_equal(&Renderer::Compact.as_str(), &"compact", "compact")?;
ensure_equal(&Renderer::Hook.as_str(), &"hook", "hook")
}
fn ensure_equal<T: std::fmt::Debug + PartialEq>(
actual: &T,
expected: &T,
ctx: &str,
) -> TestResult {
if actual == expected {
Ok(())
} else {
Err(format!("{ctx}: expected {expected:?}, got {actual:?}"))
}
}
fn ensure_toon_matches_json(json: &str, toon: &str, context: &str) -> TestResult {
let expected_json = serde_json::from_str::<serde_json::Value>(json)
.map_err(|error| format!("{context}: JSON should parse: {error}"))?;
let expected = serde_json::Value::from(toon::JsonValue::from(expected_json));
let decoded = toon::try_decode(toon, None)
.map_err(|error| format!("{context}: TOON should decode: {error}"))?;
let actual = serde_json::Value::from(decoded);
ensure_equal(&actual, &expected, context)
}
#[test]
fn renderer_machine_readable_classification() -> TestResult {
ensure(
!Renderer::Human.is_machine_readable(),
"human is not machine",
)?;
ensure(!Renderer::Toon.is_machine_readable(), "toon is not machine")?;
ensure(Renderer::Json.is_machine_readable(), "json is machine")?;
ensure(Renderer::Jsonl.is_machine_readable(), "jsonl is machine")?;
ensure(
Renderer::Compact.is_machine_readable(),
"compact is machine",
)?;
ensure(Renderer::Hook.is_machine_readable(), "hook is machine")
}
#[test]
fn output_context_json_flag_forces_json() -> TestResult {
let ctx = OutputContext::detect_with_hints(true, false, None);
ensure_equal(&ctx.renderer, &Renderer::Json, "json flag")
}
#[test]
fn output_context_robot_flag_forces_json() -> TestResult {
let ctx = OutputContext::detect_with_hints(false, true, None);
ensure_equal(&ctx.renderer, &Renderer::Json, "robot flag")
}
#[test]
fn output_context_format_override_takes_precedence() -> TestResult {
let ctx = OutputContext::detect_with_hints(true, true, Some(Renderer::Toon));
ensure_equal(&ctx.renderer, &Renderer::Toon, "format override")
}
#[test]
fn output_context_ee_json_forces_json_over_toon_default() -> TestResult {
let ctx = output_context_from_env(OutputEnvironment {
ee_json: Some("1".to_string()),
toon_default_format: Some("toon".to_string()),
..OutputEnvironment::default()
});
ensure_equal(&ctx.renderer, &Renderer::Json, "EE_JSON precedence")
}
#[test]
fn output_context_agent_mode_forces_json_over_output_format() -> TestResult {
let ctx = output_context_from_env(OutputEnvironment {
ee_agent_mode: Some("true".to_string()),
ee_output_format: Some("toon".to_string()),
..OutputEnvironment::default()
});
ensure_equal(&ctx.renderer, &Renderer::Json, "EE_AGENT_MODE precedence")
}
#[test]
fn output_context_hook_mode_precedes_toon_default() -> TestResult {
let ctx = output_context_from_env(OutputEnvironment {
ee_hook_mode: Some("yes".to_string()),
toon_default_format: Some("toon".to_string()),
..OutputEnvironment::default()
});
ensure_equal(&ctx.renderer, &Renderer::Hook, "EE_HOOK_MODE precedence")
}
#[test]
fn output_context_ee_output_format_precedes_toon_default() -> TestResult {
let ctx = output_context_from_env(OutputEnvironment {
ee_output_format: Some("jsonl".to_string()),
toon_default_format: Some("toon".to_string()),
..OutputEnvironment::default()
});
ensure_equal(
&ctx.renderer,
&Renderer::Jsonl,
"EE_OUTPUT_FORMAT precedence",
)
}
#[test]
fn output_context_legacy_ee_format_precedes_toon_default() -> TestResult {
let ctx = output_context_from_env(OutputEnvironment {
ee_format: Some("compact".to_string()),
toon_default_format: Some("toon".to_string()),
..OutputEnvironment::default()
});
ensure_equal(&ctx.renderer, &Renderer::Compact, "EE_FORMAT precedence")
}
#[test]
fn output_context_toon_default_format_applies_as_fallback() -> TestResult {
let ctx = output_context_from_env(OutputEnvironment {
toon_default_format: Some("toon".to_string()),
..OutputEnvironment::default()
});
ensure_equal(
&ctx.renderer,
&Renderer::Toon,
"TOON_DEFAULT_FORMAT fallback",
)
}
#[test]
fn output_context_disable_toon_falls_back_to_json() -> TestResult {
let ctx = output_context_from_env(OutputEnvironment {
ee_disable_toon: Some("1".to_string()),
toon_default_format: Some("toon".to_string()),
..OutputEnvironment::default()
});
ensure_equal(
&ctx.renderer,
&Renderer::Json,
"EE_DISABLE_TOON fallback renderer",
)
}
#[test]
fn renderer_requested_by_environment_is_none_without_output_vars() -> TestResult {
ensure_equal(
&super::renderer_requested_by_environment(&OutputEnvironment::default()),
&None,
"no output env vars set",
)
}
#[test]
fn renderer_requested_by_environment_prefers_output_format_over_format() -> TestResult {
ensure_equal(
&super::renderer_requested_by_environment(&OutputEnvironment {
ee_output_format: Some("jsonl".to_string()),
ee_format: Some("compact".to_string()),
..OutputEnvironment::default()
}),
&Some(Renderer::Jsonl),
"EE_OUTPUT_FORMAT outranks EE_FORMAT",
)
}
#[test]
fn renderer_requested_by_environment_skips_invalid_values() -> TestResult {
ensure_equal(
&super::renderer_requested_by_environment(&OutputEnvironment {
ee_output_format: Some("bogus".to_string()),
ee_format: Some("markdown".to_string()),
..OutputEnvironment::default()
}),
&Some(Renderer::Markdown),
"invalid EE_OUTPUT_FORMAT falls through to EE_FORMAT",
)
}
#[test]
fn renderer_requested_by_environment_degrades_toon_when_disabled() -> TestResult {
ensure_equal(
&super::renderer_requested_by_environment(&OutputEnvironment {
ee_format: Some("toon".to_string()),
ee_disable_toon: Some("1".to_string()),
..OutputEnvironment::default()
}),
&Some(Renderer::Json),
"EE_DISABLE_TOON degrades an env TOON selection to JSON",
)
}
// EE-336: TOON_DEFAULT_FORMAT precedence tests proving explicit machine
// output flags always override the fallback environment variable.
#[test]
fn toon_default_format_json_flag_forces_json() -> TestResult {
let ctx = OutputContext::detect_with_environment(
true,
false,
None,
false,
&OutputEnvironment {
toon_default_format: Some("toon".to_string()),
..OutputEnvironment::default()
},
);
ensure_equal(
&ctx.renderer,
&Renderer::Json,
"--json flag must override TOON_DEFAULT_FORMAT",
)
}
#[test]
fn toon_default_format_robot_flag_forces_json() -> TestResult {
let ctx = OutputContext::detect_with_environment(
false,
true,
None,
false,
&OutputEnvironment {
toon_default_format: Some("toon".to_string()),
..OutputEnvironment::default()
},
);
ensure_equal(
&ctx.renderer,
&Renderer::Json,
"--robot flag must override TOON_DEFAULT_FORMAT",
)
}
#[test]
fn toon_default_format_format_json_override_forces_json() -> TestResult {
let ctx = OutputContext::detect_with_environment(
false,
false,
Some(Renderer::Json),
false,
&OutputEnvironment {
toon_default_format: Some("toon".to_string()),
..OutputEnvironment::default()
},
);
ensure_equal(
&ctx.renderer,
&Renderer::Json,
"--format json must override TOON_DEFAULT_FORMAT",
)
}
#[test]
fn toon_default_format_hook_mode_stays_hook() -> TestResult {
let ctx = OutputContext::detect_with_environment(
false,
false,
None,
false,
&OutputEnvironment {
ee_hook_mode: Some("1".to_string()),
toon_default_format: Some("toon".to_string()),
..OutputEnvironment::default()
},
);
ensure_equal(
&ctx.renderer,
&Renderer::Hook,
"EE_HOOK_MODE must override TOON_DEFAULT_FORMAT",
)
}
#[test]
fn toon_default_format_mcp_agent_mode_stays_json() -> TestResult {
let ctx = OutputContext::detect_with_environment(
false,
false,
None,
false,
&OutputEnvironment {
ee_agent_mode: Some("1".to_string()),
toon_default_format: Some("toon".to_string()),
..OutputEnvironment::default()
},
);
ensure_equal(
&ctx.renderer,
&Renderer::Json,
"EE_AGENT_MODE (MCP) must override TOON_DEFAULT_FORMAT",
)
}
#[test]
fn output_context_falsey_env_flags_do_not_force_machine_output() -> TestResult {
let ctx = output_context_from_env(OutputEnvironment {
ee_json: Some("0".to_string()),
ee_agent_mode: Some("false".to_string()),
ee_hook_mode: Some("off".to_string()),
..OutputEnvironment::default()
});
ensure_equal(&ctx.renderer, &Renderer::Human, "falsey env flags")
}
#[test]
fn output_context_no_color_wins_over_force_color() -> TestResult {
let ctx = OutputContext::detect_with_environment(
false,
false,
None,
false,
&OutputEnvironment {
no_color: Some("".to_string()),
force_color: Some("1".to_string()),
..OutputEnvironment::default()
},
);
ensure(!ctx.color_enabled, "NO_COLOR must disable color")
}
#[test]
fn output_context_force_color_enables_human_color_without_tty() -> TestResult {
let ctx = OutputContext::detect_with_environment(
false,
false,
None,
false,
&OutputEnvironment {
force_color: Some("1".to_string()),
..OutputEnvironment::default()
},
);
ensure(ctx.color_enabled, "FORCE_COLOR enables human color")
}
#[test]
fn output_context_force_color_does_not_color_machine_output() -> TestResult {
let ctx = OutputContext::detect_with_environment(
false,
false,
None,
false,
&OutputEnvironment {
ee_output_format: Some("json".to_string()),
force_color: Some("1".to_string()),
..OutputEnvironment::default()
},
);
ensure_equal(&ctx.renderer, &Renderer::Json, "machine renderer")?;
ensure(!ctx.color_enabled, "machine output stays uncolored")
}
#[test]
fn response_envelope_success_has_stable_schema() -> TestResult {
let json = ResponseEnvelope::success()
.data(|d| {
d.field_str("command", "test");
})
.finish();
ensure_starts_with(&json, "{\"schema\":\"ee.response.v2\"", "schema")?;
ensure_contains(&json, "\"success\":true", "success flag")?;
ensure_contains(&json, "\"data\":{\"command\":\"test\"}", "data object")
}
#[test]
fn response_envelope_failure_has_success_false() -> TestResult {
let json = ResponseEnvelope::failure()
.data_raw("{\"error\":\"something\"}")
.finish();
ensure_contains(&json, "\"success\":false", "failure flag")?;
ensure_contains(&json, "\"data\":{\"error\":\"something\"}", "data raw")
}
#[test]
fn response_envelope_degraded_array() -> TestResult {
let degradations = vec![("code1", "message1")];
let json = ResponseEnvelope::success()
.data(|d| {
d.field_str("status", "ok");
})
.degraded_array(°radations, |obj, (code, msg)| {
obj.field_str("code", code);
obj.field_str("severity", "warning");
obj.field_str("message", msg);
})
.finish();
ensure_contains(&json, "\"degraded\":[{", "degraded array start")?;
ensure_contains(&json, "\"code\":\"code1\"", "degradation code")?;
ensure_contains(&json, "\"severity\":\"warning\"", "degradation severity")
}
#[test]
fn memory_drift_report_json_uses_v2_envelope_and_mirrors_degraded() -> TestResult {
let report = crate::core::memory_drift::MemoryDriftReport::new(
crate::core::memory_drift::MemoryDriftReportMode::OneMemory,
Some("2026-05-19T11:10:00Z"),
vec![crate::core::memory_drift::MemoryDriftSelectionHint::new(
"mem_changed",
crate::core::memory_drift::MemoryDriftStatus::Changed,
"provenance_chain_mismatch",
1,
)],
)
.with_degraded(vec![
crate::core::memory_drift::MemoryDriftDegradation::new(
"memory_drift_source_changed",
"medium",
"The selected memory provenance changed.",
),
]);
let json = super::render_memory_drift_report_json(&report);
let parsed = serde_json::from_str::<serde_json::Value>(&json)
.map_err(|error| format!("memory drift report JSON should parse: {error}; {json}"))?;
ensure_equal(
&parsed.get("schema").and_then(serde_json::Value::as_str),
&Some("ee.response.v2"),
"memory drift envelope schema",
)?;
ensure_equal(
&parsed.get("success").and_then(serde_json::Value::as_bool),
&Some(true),
"memory drift envelope success",
)?;
ensure_equal(
&parsed
.get("data")
.and_then(|data| data.get("schema"))
.and_then(serde_json::Value::as_str),
&Some(crate::core::memory_drift::MEMORY_DRIFT_REPORT_SCHEMA_V1),
"memory drift data schema",
)?;
let top_degraded = parsed
.get("degraded")
.and_then(serde_json::Value::as_array)
.ok_or_else(|| format!("top-level degraded array missing: {parsed:?}"))?;
let data_degraded = parsed
.get("data")
.and_then(|data| data.get("degraded"))
.and_then(serde_json::Value::as_array)
.ok_or_else(|| format!("data degraded array missing: {parsed:?}"))?;
ensure_equal(&top_degraded.len(), &1usize, "top-level degraded count")?;
ensure_equal(top_degraded, data_degraded, "mirrored degraded entries")
}
#[test]
fn memory_history_json_escapes_malicious_audit_details() -> TestResult {
let payloads = [
"}{}",
"\"},\"success\":false,\"forged\":{\"x\":\"y",
"line\nquote\"tab\tcontrol\u{0001}",
];
let entries = payloads
.iter()
.enumerate()
.map(|(index, payload)| MemoryHistoryEntry {
audit_id: format!("audit_{index:03}"),
timestamp: "2026-05-04T19:51:23Z".to_string(),
actor: Some("tester".to_string()),
action: "memory.update".to_string(),
details: Some((*payload).to_string()),
})
.collect::<Vec<_>>();
let report = MemoryHistoryReport::found(
"mem_test".to_string(),
false,
entries,
u32::try_from(payloads.len()).map_err(|error| format!("{error}"))?,
false,
);
let json = render_memory_history_json(&report);
let parsed = serde_json::from_str::<serde_json::Value>(&json)
.map_err(|error| format!("memory history JSON should parse: {error}; {json}"))?;
let rendered_entries = parsed
.get("data")
.and_then(|data| data.get("entries"))
.and_then(serde_json::Value::as_array)
.ok_or_else(|| format!("entries should be an array: {parsed:?}"))?;
for (index, payload) in payloads.iter().enumerate() {
let details = rendered_entries
.get(index)
.and_then(|entry| entry.get("details"))
.and_then(serde_json::Value::as_str);
ensure_equal(
&details,
&Some(*payload),
"malicious audit details are rendered as JSON strings",
)?;
}
let success = parsed.get("success").and_then(serde_json::Value::as_bool);
ensure_equal(
&success,
&Some(true),
"quote injection must not alter envelope success",
)
}
#[test]
fn memory_history_toon_decodes_after_malicious_audit_details() -> TestResult {
let entries = vec![MemoryHistoryEntry {
audit_id: "audit_001".to_string(),
timestamp: "2026-05-04T19:51:23Z".to_string(),
actor: Some("tester".to_string()),
action: "memory.update".to_string(),
details: Some("}{}\n\"},\"success\":false,\u{0001}".to_string()),
}];
let report = MemoryHistoryReport::found("mem_test".to_string(), false, entries, 1, false);
let json = render_memory_history_json(&report);
let toon = render_memory_history_toon(&report);
ensure(
!toon.contains("toon_encoding_failed"),
format!("malicious details should not poison TOON encoding: {toon:?}"),
)?;
ensure_toon_matches_json(&json, &toon, "memory history TOON matches escaped JSON")
}
#[test]
fn memory_history_json_preserves_valid_audit_detail_objects() -> TestResult {
let entries = vec![MemoryHistoryEntry {
audit_id: "audit_001".to_string(),
timestamp: "2026-05-04T19:51:23Z".to_string(),
actor: Some("tester".to_string()),
action: "memory.update".to_string(),
details: Some(r#"{"field":"content","changed":true}"#.to_string()),
}];
let report = MemoryHistoryReport::found("mem_test".to_string(), false, entries, 1, false);
let parsed =
serde_json::from_str::<serde_json::Value>(&render_memory_history_json(&report))
.map_err(|error| format!("memory history JSON should parse: {error}"))?;
let details = parsed
.get("data")
.and_then(|data| data.get("entries"))
.and_then(serde_json::Value::as_array)
.and_then(|entries| entries.first())
.and_then(|entry| entry.get("details"))
.ok_or_else(|| format!("details should be present: {parsed:?}"))?;
let field = details.get("field").and_then(serde_json::Value::as_str);
let changed = details.get("changed").and_then(serde_json::Value::as_bool);
ensure_equal(
&field,
&Some("content"),
"valid audit detail JSON object remains structured",
)?;
ensure_equal(
&changed,
&Some(true),
"valid audit detail boolean remains structured",
)
}
#[test]
fn pack_response_json_renders_provenance() -> TestResult {
let response = context_response_fixture()?;
let json = render_context_response_json(&response);
ensure_starts_with(&json, "{\"schema\":\"ee.response.v2\"", "schema")?;
ensure_contains(&json, "\"command\":\"pack\"", "command")?;
ensure_contains(
&json,
&format!(
"\"embed_backend\":\"{}\"",
response.data.embed_backend.as_str()
),
"pack embedding backend",
)?;
ensure_contains(
&render_context_response_human(&response),
&format!("embed_backend: {}", response.data.embed_backend.as_str()),
"human pack embedding backend",
)?;
ensure_contains(
&render_context_response_markdown(&response),
&format!(
"**embed_backend:** `{}`",
response.data.embed_backend.as_str()
),
"markdown pack embedding backend",
)?;
ensure_contains(
&json,
"\"provenance\":[{\"uri\":\"file://AGENTS.md#L42\",\"scheme\":\"file\",\"label\":\"AGENTS.md:L42\",\"locator\":\"L42\",\"note\":\"source evidence\"}]",
"item provenance",
)?;
// Bead bd-2pe1z (A1 phase 2): provenanceFooter no longer emits the
// entries[] array — sourceIndex moved inline onto items[]. Footer
// keeps the aggregate summary fields only.
ensure_contains(
&json,
"\"provenanceFooter\":{\"memoryCount\":1,\"sourceCount\":1,\"schemes\":[\"file\"]}",
"provenance footer summary",
)?;
ensure_contains(
&json,
"\"advisoryBanner\":{\"status\":\"clear\"",
"advisory banner",
)?;
ensure_contains(
&json,
"\"trust\":{\"class\":\"human_explicit\",\"subclass\":\"project-rule\",\"posture\":\"authoritative\"}",
"item trust posture",
)?;
ensure_contains(&json, "\"relevance\":0.800000", "stable relevance")
}
#[test]
fn context_response_json_renders_query_file_pagination_metadata() -> TestResult {
let mut response = context_response_fixture()?;
response.data.pagination = Some(ContextResponsePagination {
offset: 2,
limit: 2,
total: 5,
page_size: 2,
has_more: true,
next_cursor: Some("cursor_next_page".to_owned()),
});
let json = render_context_response_json(&response);
ensure_contains(
&json,
"\"pagination\":{\"offset\":2,\"limit\":2,\"total\":5,\"hasMore\":true,\"nextCursor\":\"cursor_next_page\"}",
"query-file pagination metadata",
)
}
#[test]
fn context_response_json_renders_pack_item_freshness_facets() -> TestResult {
let mut response = context_response_fixture()?;
response.data.pack.items[0]
.freshness_facets
.push(PackFreshnessFacet {
kind: "stale_anchor".to_owned(),
freshness: "drifted".to_owned(),
stale_anchor: true,
drift_status: "changed".to_owned(),
severity: "medium".to_owned(),
top_reason: "code_anchor_provenance_changed".to_owned(),
degraded_code: Some("memory_drift_source_changed".to_owned()),
revalidation_command: "ee memory drift mem_fixture --json".to_owned(),
captured_at_commit: Some("abcdef0".to_owned()),
current_commit: Some("abcdef1".to_owned()),
commit_distance: Some(1),
changed_regions: vec!["path:lib.rs:abcdef12".to_owned()],
anchors: vec![PackFreshnessAnchorFacet {
anchor_kind: "path".to_owned(),
anchor_value_hash:
"blake3:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
.to_owned(),
redacted_anchor_value: "path:lib.rs:abcdef12".to_owned(),
captured_span_hash:
"blake3:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"
.to_owned(),
freshness_state: "current".to_owned(),
freshness: "drifted".to_owned(),
generation: 7,
stale_anchor: true,
}],
});
let json = render_context_response_json(&response);
ensure_contains(&json, "\"freshnessFacets\":[{", "freshness facets array")?;
ensure_contains(&json, "\"kind\":\"stale_anchor\"", "freshness kind")?;
ensure_contains(&json, "\"staleAnchor\":true", "stale anchor flag")?;
ensure_contains(&json, "\"capturedAtCommit\":\"abcdef0\"", "captured commit")?;
ensure_contains(&json, "\"currentCommit\":\"abcdef1\"", "current commit")?;
ensure_contains(&json, "\"commitDistance\":1", "commit distance")?;
ensure_contains(
&json,
"\"changedRegions\":[\"path:lib.rs:abcdef12\"]",
"changed regions",
)?;
ensure_contains(&json, "\"anchors\":[{", "anchor facets")
}
#[test]
fn context_markdown_includes_attached_pack_dna_before_footer() -> TestResult {
let mut response = context_response_fixture()?;
response.data.pack_dna = Some(sample_pack_dna_value());
let markdown = render_context_response_markdown(&response);
ensure_contains(&markdown, "# Pack DNA", "Pack DNA block title")?;
ensure_contains(
&markdown,
"- Schema: `ee.context.pack_dna.v1`",
"Pack DNA schema",
)?;
ensure_contains(
&markdown,
"- Voronoi dominator: `mem_release_policy`",
"Pack DNA dominator",
)?;
let pack_dna_start = markdown
.find("# Pack DNA")
.ok_or_else(|| "Pack DNA markdown block missing".to_string())?;
let footer_start = markdown
.find("*Generated by `ee pack")
.ok_or_else(|| "generated footer missing".to_string())?;
ensure(
pack_dna_start < footer_start,
"Pack DNA block should render before generated footer",
)
}
#[test]
fn context_markdown_pack_dna_footer_anchor_handles_backtick_queries() -> TestResult {
let mut response = context_response_fixture_with_query("prepare `release`")?;
response.data.pack_dna = Some(sample_pack_dna_value());
let markdown = render_context_response_markdown(&response);
ensure_contains(
&markdown,
"*Generated by ``ee pack 'prepare `release`' --format markdown``*",
"double-backtick generated footer",
)?;
let pack_dna_start = markdown
.find("# Pack DNA")
.ok_or_else(|| "Pack DNA markdown block missing".to_string())?;
let footer_start = markdown
.find("*Generated by ")
.ok_or_else(|| "generated footer missing".to_string())?;
ensure(
pack_dna_start < footer_start,
"Pack DNA block should render before generated footer with expanded inline-code delimiter",
)
}
#[test]
fn context_response_json_renders_pack_item_score_breakdown() -> TestResult {
let request = ContextRequest::from_query("prepare release")
.map_err(|error| format!("request rejected: {error:?}"))?;
let budget =
TokenBudget::new(100).map_err(|error| format!("budget rejected: {error:?}"))?;
let candidate = PackCandidate::new(PackCandidateInput {
memory_id: memory_id(420),
section: PackSection::ProceduralRules,
content: "Run cargo fmt --check before release.".to_string(),
estimated_tokens: 10,
relevance: score(0.44)?,
utility: score(0.6)?,
provenance: vec![pack_provenance("file://AGENTS.md#L42")?],
why: "selected because release checks match the task".to_string(),
})
.map_err(|error| format!("candidate rejected: {error:?}"))?
.with_score_breakdown(PackScoreBreakdown::ppr(0.20, 0.80, 0.44));
let draft = assemble_draft(&request.query, budget, vec![candidate])
.map_err(|error| format!("draft rejected: {error:?}"))?;
let response = ContextResponse::new(request, draft, Vec::new())
.map_err(|error| format!("response rejected: {error:?}"))?;
let json = render_context_response_json(&response);
ensure_contains(
&json,
"\"selection\":{\"scoreBreakdown\":{\"textScore\":0.200000,\"pprScore\":0.800000,\"combinedScore\":0.440000}}",
"PPR score breakdown",
)
}
#[test]
fn context_response_json_renders_adaptive_budget_decision() -> TestResult {
let mut response = context_response_fixture()?;
response.data.adaptive_budget = Some(classify_adaptive_budget(
AdaptiveBudgetInput::new("audit release context", &[0.7, 0.3], 1.0)
.with_max_tokens(100),
));
let json = render_context_response_json(&response);
ensure_contains(
&json,
"\"budget\":{\"maxTokens\":100,\"usedTokens\":10,\"utilization\":0.100000,\"schema\":\"ee.context.budget.v1\",\"adaptive\":true",
"adaptive budget decision",
)?;
ensure_contains(
&json,
"\"classifierContributions\"",
"adaptive budget contributions",
)
}
#[test]
fn context_response_json_renders_pack_item_proximity_to_seed() -> TestResult {
let request = ContextRequest::from_query("prepare release")
.map_err(|error| format!("request rejected: {error:?}"))?;
let budget =
TokenBudget::new(100).map_err(|error| format!("budget rejected: {error:?}"))?;
let candidate = PackCandidate::new(PackCandidateInput {
memory_id: memory_id(421),
section: PackSection::ProceduralRules,
content: "Review tightly coupled release notes together.".to_string(),
estimated_tokens: 10,
relevance: score(0.44)?,
utility: score(0.6)?,
provenance: vec![pack_provenance("file://AGENTS.md#L43")?],
why: "selected because release notes share graph proximity".to_string(),
})
.map_err(|error| format!("candidate rejected: {error:?}"))?
.with_proximity_to_seed(0.91);
let draft = assemble_draft(&request.query, budget, vec![candidate])
.map_err(|error| format!("draft rejected: {error:?}"))?;
let response = ContextResponse::new(request, draft, Vec::new())
.map_err(|error| format!("response rejected: {error:?}"))?;
let json = render_context_response_json(&response);
ensure_contains(
&json,
"\"proximityToSeed\":0.910000",
"proximity-to-seed score",
)
}
#[test]
fn context_response_json_renders_pack_item_redactions() -> TestResult {
let request = ContextRequest::from_query("protect context pack secrets")
.map_err(|error| format!("request rejected: {error:?}"))?;
let budget =
TokenBudget::new(100).map_err(|error| format!("budget rejected: {error:?}"))?;
let key_name = concat!("api", "_", "key");
let raw_value = concat!("sk", "_", "pack", "_", "secret", "_", "123");
let candidate = PackCandidate::new(PackCandidateInput {
memory_id: memory_id(314),
section: PackSection::ProceduralRules,
content: format!("Keep the operational note; mask {key_name}={raw_value} for review."),
estimated_tokens: 12,
relevance: score(0.9)?,
utility: score(0.7)?,
provenance: vec![pack_provenance("file://AGENTS.md#L7")?],
why: "selected because it matches a secret-handling task".to_string(),
})
.map_err(|error| format!("candidate rejected: {error:?}"))?;
let draft = assemble_draft(&request.query, budget, vec![candidate])
.map_err(|error| format!("draft rejected: {error:?}"))?;
let response = ContextResponse::new(request, draft, Vec::new())
.map_err(|error| format!("response rejected: {error:?}"))?;
let json = render_context_response_json(&response);
ensure(
!json.contains(raw_value),
"context JSON should not contain raw secret-like value",
)?;
ensure_contains(
&json,
"\"content\":\"Keep the operational note; mask api_key=[REDACTED:api_key] for review.\"",
"context JSON emits redacted pack content",
)?;
ensure_contains(
&json,
"\"contentRedacted\":true",
"context JSON flags redacted pack content",
)?;
ensure_contains(
&json,
"\"redactions\":[{\"reason\":\"api_key\",\"placeholder\":\"[REDACTED:api_key]\"}]",
"context JSON emits per-item redaction metadata",
)
}
#[test]
fn context_response_json_renders_pack_quality() -> TestResult {
let response = context_response_fixture()?;
let json = render_context_response_json(&response);
ensure_contains(
&json,
"\"quality\":{\"itemCount\":1,\"omittedCount\":0,\"usedTokens\":10,\"maxTokens\":100,\"budgetUtilization\":0.100000",
"quality metric header",
)?;
ensure_contains(
&json,
"\"averageRelevance\":0.800000,\"averageUtility\":0.600000",
"quality score averages",
)?;
ensure_contains(
&json,
"\"provenanceSourceCount\":1,\"provenanceSourcesPerItem\":1.000000,\"provenanceComplete\":true",
"quality provenance density",
)?;
ensure_contains(
&json,
"\"sections\":[{\"section\":\"procedural_rules\",\"itemCount\":1,\"usedTokens\":10},{\"section\":\"decisions\",\"itemCount\":0,\"usedTokens\":0}",
"quality section metrics",
)?;
ensure_contains(
&json,
"\"omissions\":{\"tokenBudgetExceeded\":0,\"redundantCandidates\":0,\"belowRelevanceFloor\":0}",
"quality omission metrics",
)
}
#[test]
fn context_response_json_renders_pack_slo() -> TestResult {
let mut response = context_response_fixture()?;
response.data.slo = Some(PackAssemblySlo::evaluate(
PackResourceProfile::Lean,
PackAssemblySloActuals {
candidate_count: 80,
scanned_count: 80,
index_generation: Some(3),
graph_generation: Some(3),
graph_edges_traversed: 128,
elapsed_ms: 25,
memory_bytes_peak: 4096,
},
));
let json = render_context_response_json(&response);
ensure_contains(
&json,
"\"slo\":{\"schema\":\"ee.pack.slo.v1\",\"profile\":\"lean\"",
"pack SLO object",
)?;
ensure_contains(&json, "\"status\":\"warning\"", "pack SLO status")?;
ensure_contains(
&json,
"\"code\":\"pack_assembly_slow\"",
"pack SLO degradation code",
)
}
#[test]
fn context_response_json_exposes_degraded_repair_kind() -> TestResult {
let mut response = context_response_fixture()?;
response.data.degraded.push(
crate::pack::ContextResponseDegradation::new(
"template_repair_fixture",
crate::pack::ContextResponseSeverity::Medium,
"fixture degradation",
Some("ee preflight check --cmd <command> --json".to_string()),
)
.map_err(|error| format!("degradation rejected: {error:?}"))?,
);
let json = render_context_response_json(&response);
let parsed: serde_json::Value =
serde_json::from_str(&json).map_err(|error| error.to_string())?;
let degraded = parsed["data"]["degraded"]
.as_array()
.ok_or_else(|| "degraded must be an array".to_string())?;
let entry = degraded
.iter()
.find(|entry| entry["code"] == "template_repair_fixture")
.ok_or_else(|| "template repair fixture degradation missing".to_string())?;
ensure_equal(
&entry["repairKind"].as_str(),
&Some("template"),
"context degraded repair kind",
)
}
#[test]
fn context_response_json_mirrors_degraded_to_top_level_envelope() -> TestResult {
let mut response = context_response_fixture()?;
response.data.degraded.push(
crate::pack::ContextResponseDegradation::new(
"template_repair_fixture",
crate::pack::ContextResponseSeverity::Medium,
"fixture degradation",
Some("ee preflight check --cmd <command> --json".to_string()),
)
.map_err(|error| format!("degradation rejected: {error:?}"))?,
);
let json = render_context_response_json(&response);
let parsed: serde_json::Value =
serde_json::from_str(&json).map_err(|error| error.to_string())?;
ensure_top_level_degraded_mirrors_data_degraded(&parsed, "context response")?;
ensure_equal(
&parsed["degraded"][0]["code"].as_str(),
&Some("template_repair_fixture"),
"context response top-level degraded code",
)
}
#[test]
fn cached_context_response_json_backfills_top_level_degraded() -> TestResult {
let cached_json = serde_json::json!({
"schema": RESPONSE_SCHEMA_V2,
"success": true,
"data": {
"command": "pack",
"embed_backend": "hash_fallback",
"pack": {
"schema": crate::models::PACK_SCHEMA_V2,
"query": "prepare release"
},
"degraded": [{
"code": "template_repair_fixture",
"severity": "medium",
"message": "fixture degradation",
"repair": "ee preflight check --cmd <command> --json",
"sources": ["context"]
}]
}
})
.to_string();
let request = ContextRequest::from_query("prepare release")
.map_err(|error| format!("request rejected: {error:?}"))?;
let response = ContextResponse::from_cached_json(request, cached_json);
let rendered = render_context_response_json(&response);
let parsed: serde_json::Value =
serde_json::from_str(&rendered).map_err(|error| error.to_string())?;
ensure_top_level_degraded_mirrors_data_degraded(&parsed, "cached context response")?;
ensure_equal(
&parsed["degraded"][0]["code"].as_str(),
&Some("template_repair_fixture"),
"cached context response top-level degraded code",
)
}
#[test]
fn context_degraded_aggregation_preserves_warning_severity() -> TestResult {
let mut response = context_response_fixture()?;
response.data.degraded.push(
crate::pack::ContextResponseDegradation::new(
"embed_model_unavailable",
crate::pack::ContextResponseSeverity::Warning,
"Embedding model unavailable; semantic similarity is disabled.",
Some("ee index reembed --workspace .".to_string()),
)
.map_err(|error| format!("degradation rejected: {error:?}"))?,
);
let aggregated =
super::aggregate_context_degraded_as_response(response.data.degraded.iter());
let severity = aggregated
.iter()
.find(|entry| entry.code == "embed_model_unavailable")
.map(|entry| entry.severity);
ensure_equal(
&severity,
&Some(crate::pack::ContextResponseSeverity::Warning),
"aggregated context degradation severity",
)
}
#[test]
fn context_degraded_aggregation_preserves_critical_severity() -> TestResult {
let mut response = context_response_fixture()?;
response.data.degraded.push(
crate::pack::ContextResponseDegradation::new(
"mesh_cursor_repair_required",
crate::pack::ContextResponseSeverity::Critical,
"Mesh cursor repair is required before continuing.",
Some("ee mesh repair-cursor --json".to_string()),
)
.map_err(|error| format!("degradation rejected: {error:?}"))?,
);
let aggregated =
super::aggregate_context_degraded_as_response(response.data.degraded.iter());
let severity = aggregated
.iter()
.find(|entry| entry.code == "mesh_cursor_repair_required")
.map(|entry| entry.severity);
ensure_equal(
&severity,
&Some(crate::pack::ContextResponseSeverity::Critical),
"aggregated critical context degradation severity",
)
}
#[test]
fn pack_text_drops_non_affecting_degradation_by_default_bd_2v6r0() -> TestResult {
// search_index_stale is WorkspaceStateNotPerResponse (non-affecting): it
// is dropped from data.degraded[] by default, so the rendered pack text
// must not advertise it either. Verbose mode surfaces both. The markdown
// ## Degradations section renders the message (not the raw code), so the
// pack.text assertions key on the message and the section header.
let mut response = context_response_fixture()?;
response.data.degraded.clear();
response.data.degraded.push(
crate::pack::ContextResponseDegradation::new(
"search_index_stale",
crate::pack::ContextResponseSeverity::Medium,
"Search index is behind the database generation.",
Some("ee index rebuild --workspace .".to_string()),
)
.map_err(|error| format!("degradation rejected: {error:?}"))?,
);
// Default render: the non-affecting signal is filtered from BOTH
// data.degraded[] and the rendered pack text.
let json = render_context_response_json(&response);
let parsed: serde_json::Value =
serde_json::from_str(&json).map_err(|error| error.to_string())?;
let degraded = parsed["data"]["degraded"]
.as_array()
.ok_or_else(|| "degraded must be an array".to_string())?;
if degraded
.iter()
.any(|entry| entry["code"] == "search_index_stale")
{
return Err(
"default degraded[] must drop the non-affecting search_index_stale".to_string(),
);
}
let pack_text = parsed["data"]["pack"]["text"]
.as_str()
.ok_or_else(|| "data.pack.text must be a string".to_string())?;
if pack_text.contains("## Degradations") {
return Err(
"default pack.text must not render a Degradations section for a non-affecting signal"
.to_string(),
);
}
if pack_text.contains("behind the database generation") {
return Err("default pack.text must not mention the dropped degradation".to_string());
}
ensure_equal(
&parsed["data"]["pack"]["advisoryBanner"]["degradationCount"],
&serde_json::json!(0),
"default advisory banner drops the non-affecting degradation",
)?;
// Verbose render (--include-non-affecting-degradations): both surfaces
// include the signal again.
let verbose = render_context_response_json_with_options(
&response,
ContextJsonRenderOptions {
include_non_affecting_degradations: true,
..ContextJsonRenderOptions::default()
},
);
let verbose_parsed: serde_json::Value =
serde_json::from_str(&verbose).map_err(|error| error.to_string())?;
let verbose_text = verbose_parsed["data"]["pack"]["text"]
.as_str()
.ok_or_else(|| "verbose data.pack.text must be a string".to_string())?;
if !verbose_text.contains("## Degradations") {
return Err("verbose pack.text must render the Degradations section".to_string());
}
ensure_contains(
verbose_text,
"behind the database generation",
"verbose pack.text surfaces the non-affecting degradation",
)?;
ensure_equal(
&verbose_parsed["data"]["pack"]["advisoryBanner"]["degradationCount"],
&serde_json::json!(1),
"verbose advisory banner includes the non-affecting degradation",
)
}
#[test]
fn context_markdown_preserves_section_order_by_rank() -> TestResult {
// Create items in a specific non-alphabetical order: Failures (rank 1),
// ProceduralRules (rank 2), Decisions (rank 3). Alphabetically this would
// be Decisions, Failures, ProceduralRules. The markdown must preserve
// the pack rank order, not sort alphabetically.
let request = ContextRequest::from_query("test rank order")
.map_err(|error| format!("request rejected: {error:?}"))?;
let budget =
TokenBudget::new(500).map_err(|error| format!("budget rejected: {error:?}"))?;
let failure_candidate = PackCandidate::new(PackCandidateInput {
memory_id: memory_id(1),
section: PackSection::Failures,
content: "Failure memory content".to_string(),
estimated_tokens: 10,
relevance: score(0.9)?,
utility: score(0.9)?,
provenance: vec![pack_provenance("file://failures.md#L1")?],
why: "highest ranked".to_string(),
})
.map_err(|error| format!("failure candidate rejected: {error:?}"))?;
let rule_candidate = PackCandidate::new(PackCandidateInput {
memory_id: memory_id(2),
section: PackSection::ProceduralRules,
content: "Rule memory content".to_string(),
estimated_tokens: 10,
relevance: score(0.8)?,
utility: score(0.8)?,
provenance: vec![pack_provenance("file://rules.md#L1")?],
why: "second ranked".to_string(),
})
.map_err(|error| format!("rule candidate rejected: {error:?}"))?;
let decision_candidate = PackCandidate::new(PackCandidateInput {
memory_id: memory_id(3),
section: PackSection::Decisions,
content: "Decision memory content".to_string(),
estimated_tokens: 10,
relevance: score(0.7)?,
utility: score(0.7)?,
provenance: vec![pack_provenance("file://decisions.md#L1")?],
why: "third ranked".to_string(),
})
.map_err(|error| format!("decision candidate rejected: {error:?}"))?;
let draft = assemble_draft(
&request.query,
budget,
vec![failure_candidate, rule_candidate, decision_candidate],
)
.map_err(|error| format!("draft rejected: {error:?}"))?;
let response = ContextResponse::new(request, draft, Vec::new())
.map_err(|error| format!("response rejected: {error:?}"))?;
let markdown = render_context_response_markdown(&response);
// Find positions of section headers in the output. Failure memories
// selected through the reserved anti-pattern-first phase
// (bd-2vq2z.11) render under the "What NOT to do" heading rather
// than a raw `## failures` header; the rank-order contract this test
// guards is unchanged — the reserved failure item still leads.
let failures_pos = markdown
.find("## What NOT to do")
.ok_or("anti-pattern failures section not found in markdown")?;
if markdown.contains("## failures") {
return Err("failure item must not double-render under a raw failures header".into());
}
let rules_pos = markdown
.find("## procedural_rules")
.ok_or("procedural_rules section not found in markdown")?;
let decisions_pos = markdown
.find("## decisions")
.ok_or("decisions section not found in markdown")?;
// Verify order: failures < procedural_rules < decisions (by pack rank, not
// alphabetically). Alphabetical would be: decisions < failures < procedural_rules
if failures_pos > rules_pos {
return Err(format!(
"failures (rank 1) should appear before procedural_rules (rank 2): {} > {}",
failures_pos, rules_pos
));
}
if rules_pos > decisions_pos {
return Err(format!(
"procedural_rules (rank 2) should appear before decisions (rank 3): {} > {}",
rules_pos, decisions_pos
));
}
Ok(())
}
#[test]
fn context_markdown_escapes_adversarial_memory_content() -> TestResult {
let request =
ContextRequest::from_query("release [query-link](javascript:alert(1)) <img src=x>")
.map_err(|error| format!("request rejected: {error:?}"))?;
let budget =
TokenBudget::new(500).map_err(|error| format!("budget rejected: {error:?}"))?;
let content = "before\n```\n# injected heading\n```\nafter".to_string();
let candidate = PackCandidate::new(PackCandidateInput {
memory_id: memory_id(77),
section: PackSection::ProceduralRules,
content,
estimated_tokens: 10,
relevance: score(0.9)?,
utility: score(0.8)?,
provenance: vec![pack_provenance("file://rules.md#L7")?],
why: "because [why-link](javascript:alert(2)) <em>why-html</em>".to_string(),
})
.map_err(|error| format!("candidate rejected: {error:?}"))?;
let draft = assemble_draft(&request.query, budget, vec![candidate])
.map_err(|error| format!("draft rejected: {error:?}"))?;
let response = ContextResponse::new(request, draft, Vec::new())
.map_err(|error| format!("response rejected: {error:?}"))?;
let markdown = render_context_response_markdown(&response);
// Bead bd-17c65.8.1 (H1) — spec-minimal escapes. The security
// boundary is still met (brackets escape, so the link can't
// fire; HTML chars become entities), but mid-text `-`, `(`, `)`
// no longer escape unnecessarily. Verify the bracket-escaped
// shape + HTML entitization explicitly.
ensure_contains(
&markdown,
"\\[query-link\\](javascript:alert(1)) <img src=x>",
"escaped brackets + HTML entitization neutralize injection",
)?;
ensure_contains(
&markdown,
"````\nbefore\n```\n# injected heading\n```\nafter\n````",
"variable-length code fence contains embedded fence",
)?;
ensure_contains(
&markdown,
"\\[why-link\\](javascript:alert(2)) <em>why-html</em>",
"escaped why link brackets and HTML",
)?;
let prompt_body = markdown
.split("\n---\n\n*Generated by ")
.next()
.unwrap_or(markdown.as_str());
ensure(
!prompt_body.contains("[query-link](javascript")
&& !prompt_body.contains("[why-link](javascript")
&& !markdown.contains("<em>why-html</em>"),
"markdown should not contain active injected links or raw why HTML",
)
}
#[test]
fn context_markdown_renders_contiguous_display_index_per_a7() -> TestResult {
// Bead bd-17c65.1.7 (A7) — even when MMR has filtered some
// intermediate ranks (so item.rank skips numbers), the markdown
// render must show contiguous 1..N. The 2026-05-10 walkthrough
// showed "### 1." then "### 4." then "### 7." after filtering;
// post-A7 we expect "### 1.", "### 2.", "### 3.".
let request = ContextRequest::from_query("prepare release")
.map_err(|error| format!("request rejected: {error:?}"))?;
let budget =
TokenBudget::new(500).map_err(|error| format!("budget rejected: {error:?}"))?;
// Three candidates — assemble_draft assigns ranks contiguously.
// The A7 invariant is that the rendered markdown headers count
// 1..N contiguously regardless of what `rank` lands on (in
// practice MMR can produce non-contiguous ranks). For this
// unit-level test we trust assemble_draft and verify the
// renderer emits ### 1, ### 2, ### 3.
let mut candidates = Vec::new();
for (i, suffix) in [(1u128, "first"), (2u128, "second"), (3u128, "third")] {
let candidate = PackCandidate::new(PackCandidateInput {
memory_id: memory_id(i),
section: PackSection::ProceduralRules,
content: format!("Content for {suffix} item."),
estimated_tokens: 5,
relevance: score(0.5)?,
utility: score(0.5)?,
provenance: vec![pack_provenance("file://x")?],
why: format!(
"matched 'prepare release' via lexical (relevance 0.5{i}, utility 0.5000)"
),
})
.map_err(|error| format!("candidate rejected: {error:?}"))?;
candidates.push(candidate);
}
let draft = assemble_draft(&request.query, budget, candidates)
.map_err(|error| format!("draft rejected: {error:?}"))?;
let response = ContextResponse::new(request, draft, Vec::new())
.map_err(|error| format!("response rejected: {error:?}"))?;
let markdown = render_context_response_markdown(&response);
// Verify contiguous 1..N section headers (the items count is 3).
ensure_contains(&markdown, "### 1.", "first display index")?;
ensure_contains(&markdown, "### 2.", "second display index")?;
ensure_contains(&markdown, "### 3.", "third display index")?;
// No higher indices should appear (this is the contiguous guarantee).
ensure(
!markdown.contains("### 4."),
"rendered markdown shouldn't contain index beyond N=3",
)
}
#[test]
fn degradation_severity_strings_are_stable() -> TestResult {
ensure_equal(
&DegradationSeverity::ALL.map(DegradationSeverity::as_str),
&["info", "low", "warning", "medium", "high", "critical"],
"canonical severity vocabulary",
)
}
#[test]
fn degradation_to_json_has_stable_structure() -> TestResult {
let d = Degradation::new(
"storage_stale",
DegradationSeverity::Medium,
"Storage index is stale.",
"ee index rebuild",
);
let json = d.to_json();
ensure_contains(&json, "\"code\":\"storage_stale\"", "code field")?;
ensure_contains(&json, "\"severity\":\"medium\"", "severity field")?;
ensure_contains(
&json,
"\"message\":\"Storage index is stale.\"",
"message field",
)?;
ensure_contains(&json, "\"repair\":\"ee index rebuild\"", "repair field")
}
// ========================================================================
// Error JSON Schema Tests (EE-015)
//
// These tests verify the ee.error.v2 JSON schema contract for all
// DomainError variants. Each error type must produce valid JSON with:
// - schema: "ee.error.v2"
// - error.code: stable string matching the error variant
// - error.message: human-readable description
// - error.severity: stable low/medium/high classification
// - error.details: always-present structured object
// - error.repair: optional remediation command (present when provided)
// ========================================================================
#[test]
fn error_schema_usage_has_stable_structure() -> TestResult {
let error = DomainError::Usage {
message: "Unknown command 'xyz'.".to_string(),
repair: Some("ee --help".to_string()),
};
let json = error_response_json(&error);
ensure_starts_with(&json, "{\"schema\":\"ee.error.v2\"", "schema")?;
ensure_contains(&json, "\"code\":\"usage\"", "code")?;
ensure_contains(&json, "\"message\":\"Unknown command 'xyz'.\"", "message")?;
ensure_contains(&json, "\"severity\":\"low\"", "severity")?;
ensure_contains(&json, "\"details\":{}", "details")?;
ensure_contains(&json, "\"repair\":\"ee --help\"", "repair")
}
#[test]
fn error_schema_repair_kind_marks_template_repairs() -> TestResult {
let error = DomainError::UnsatisfiedDegradedMode {
message: "Preflight command requires caller-supplied shell text.".to_string(),
repair: Some("ee preflight check --cmd <command> --json".to_string()),
};
let parsed: serde_json::Value = serde_json::from_str(&error_response_json(&error))
.map_err(|error| error.to_string())?;
ensure_equal(
&parsed["error"]["repair"].as_str(),
&Some("ee preflight check --cmd <command> --json"),
"repair string",
)?;
ensure_equal(
&parsed["error"]["repairKind"].as_str(),
&Some("template"),
"error repair kind",
)
}
#[test]
fn error_schema_configuration_has_stable_structure() -> TestResult {
let error = DomainError::Configuration {
message: "Invalid config file format.".to_string(),
repair: Some("ee doctor --fix-plan --json".to_string()),
};
let json = error_response_json(&error);
ensure_starts_with(&json, "{\"schema\":\"ee.error.v2\"", "schema")?;
ensure_contains(&json, "\"code\":\"configuration\"", "code")?;
ensure_contains(
&json,
"\"message\":\"Invalid config file format.\"",
"message",
)?;
ensure_contains(&json, "\"severity\":\"medium\"", "severity")?;
ensure_contains(&json, "\"details\":{}", "details")?;
ensure_contains(
&json,
"\"repair\":\"ee doctor --fix-plan --json\"",
"repair",
)
}
#[test]
fn error_schema_storage_has_stable_structure() -> TestResult {
let error = DomainError::Storage {
message: "Database file corrupted.".to_string(),
repair: Some("ee doctor --fix-plan --json".to_string()),
};
let json = error_response_json(&error);
ensure_starts_with(&json, "{\"schema\":\"ee.error.v2\"", "schema")?;
ensure_contains(&json, "\"code\":\"storage\"", "code")?;
ensure_contains(&json, "\"message\":\"Database file corrupted.\"", "message")?;
ensure_contains(&json, "\"severity\":\"high\"", "severity")?;
ensure_contains(&json, "\"details\":{}", "details")?;
ensure_contains(
&json,
"\"repair\":\"ee doctor --fix-plan --json\"",
"repair",
)
}
#[test]
fn error_schema_storage_advisory_lock_timeout_adds_degraded_code() -> TestResult {
let error = DomainError::Storage {
message: "advisory lock timeout while waiting for workspace write lock held by agent"
.to_string(),
repair: Some(
"ee diag advisory-lock --workspace . --resource-type workspace --release --json"
.to_string(),
),
};
let json = error_response_json(&error);
ensure_contains(&json, "\"code\":\"storage\"", "storage code")?;
ensure_contains(
&json,
"\"code\":\"advisory_lock_timeout\"",
"advisory lock degraded code",
)?;
ensure_contains(
&json,
"\"severity\":\"medium\"",
"advisory lock degraded severity",
)?;
ensure_contains(
&json,
"ee diag advisory-lock --workspace . --resource-type workspace --release --json",
"repair command",
)?;
let parsed: serde_json::Value =
serde_json::from_str(&json).map_err(|error| error.to_string())?;
ensure_equal(
&parsed["degraded"][0]["repairKind"].as_str(),
&Some("actionable"),
"error degraded repair kind",
)
}
#[test]
fn error_schema_search_index_has_stable_structure() -> TestResult {
let error = DomainError::SearchIndex {
message: "Index is stale (generation 9, database generation 12).".to_string(),
repair: Some("ee index rebuild".to_string()),
};
let json = error_response_json(&error);
ensure_starts_with(&json, "{\"schema\":\"ee.error.v2\"", "schema")?;
ensure_contains(&json, "\"code\":\"search_index\"", "code")?;
ensure_contains(&json, "generation 9", "message contains details")?;
ensure_contains(&json, "\"severity\":\"medium\"", "severity")?;
// Bead bd-17c65.6.1 (F1): search-index errors carry recovery[] in
// details. Verify the structure is well-formed; specific contents
// are covered by the unit tests in models::tests.
ensure_contains(&json, "\"details\":{", "details opens")?;
ensure_contains(&json, "\"recovery\":[", "recovery array present")?;
ensure_contains(&json, "\"kind\":\"migration\"", "recovery kind")?;
ensure_contains(&json, "ee index rebuild", "recovery command")?;
ensure_contains(&json, "\"repair\":\"ee index rebuild\"", "repair")
}
#[test]
fn error_schema_import_has_stable_structure() -> TestResult {
let error = DomainError::Import {
message: "CASS session file not found.".to_string(),
repair: Some("ee import cass --dry-run".to_string()),
};
let json = error_response_json(&error);
ensure_starts_with(&json, "{\"schema\":\"ee.error.v2\"", "schema")?;
ensure_contains(&json, "\"code\":\"import\"", "code")?;
ensure_contains(
&json,
"\"message\":\"CASS session file not found.\"",
"message",
)?;
ensure_contains(&json, "\"severity\":\"medium\"", "severity")?;
ensure_contains(&json, "\"details\":{}", "details")?;
ensure_contains(&json, "\"repair\":\"ee import cass --dry-run\"", "repair")
}
#[test]
fn error_schema_unsatisfied_degraded_mode_has_stable_structure() -> TestResult {
let error = DomainError::UnsatisfiedDegradedMode {
message: "Semantic search unimplemented and --require-semantic was set.".to_string(),
repair: Some("ee index reembed --dry-run".to_string()),
};
let json = error_response_json(&error);
ensure_starts_with(&json, "{\"schema\":\"ee.error.v2\"", "schema")?;
ensure_contains(&json, "\"code\":\"unsatisfied_degraded_mode\"", "code")?;
ensure_contains(&json, "--require-semantic", "message contains flag")?;
ensure_contains(&json, "\"severity\":\"medium\"", "severity")?;
ensure_contains(&json, "\"details\":{}", "details")?;
ensure_contains(&json, "\"repair\":\"ee index reembed --dry-run\"", "repair")
}
#[test]
fn error_schema_policy_denied_has_stable_structure() -> TestResult {
let error = DomainError::PolicyDenied {
message: "Redaction policy prevents this operation.".to_string(),
repair: Some("ee doctor --fix-plan --json".to_string()),
};
let json = error_response_json(&error);
ensure_starts_with(&json, "{\"schema\":\"ee.error.v2\"", "schema")?;
ensure_contains(&json, "\"code\":\"policy_denied\"", "code")?;
ensure_contains(
&json,
"\"message\":\"Redaction policy prevents this operation.\"",
"message",
)?;
ensure_contains(&json, "\"severity\":\"medium\"", "severity")?;
ensure_contains(&json, "\"details\":{}", "details")?;
ensure_contains(
&json,
"\"repair\":\"ee doctor --fix-plan --json\"",
"repair",
)
}
#[test]
fn error_schema_detailed_variants_merge_details_object() -> TestResult {
let error = DomainError::PolicyDeniedWithDetails {
message: "Refusing to persist memory content that contains secrets: api_key."
.to_string(),
repair: Some("Redact the secret.".to_string()),
details_json: serde_json::json!({
"detectedPattern": "api_key",
"matchedAt": [{"start": 12, "end": 40, "pattern_id": "api_key"}],
"bypassFlag": "--allow-secret-mention",
})
.to_string(),
};
let json = error_response_json(&error);
ensure_contains(&json, "\"code\":\"policy_denied\"", "code")?;
ensure_contains(&json, "\"details\":{", "details object")?;
ensure_contains(&json, "\"detectedPattern\":\"api_key\"", "detected pattern")?;
ensure_contains(&json, "\"matchedAt\":[", "matchedAt array")?;
ensure_contains(
&json,
"\"bypassFlag\":\"--allow-secret-mention\"",
"bypass flag",
)?;
ensure_contains(&json, "\"recovery\":[", "recovery still present")
}
#[test]
fn error_schema_derivation_failure_has_structured_recovery() -> TestResult {
let error = DomainError::UsageCodeWithDetails {
code: crate::models::DERIVED_SOURCE_HASH_DRIFTED_CODE,
message: "Memory source mem_1 hash drifted from blake3:old to blake3:new.".to_owned(),
repair: Some("Re-propose the candidate against the current source content.".to_owned()),
details_json: serde_json::json!({
"failureModeCode": crate::models::DERIVED_SOURCE_HASH_DRIFTED_CODE,
})
.to_string(),
};
let parsed: serde_json::Value = serde_json::from_str(&error_response_json(&error))
.map_err(|error| error.to_string())?;
let recovery = parsed["error"]["details"]["recovery"]
.as_array()
.ok_or_else(|| "derivation error should include details.recovery[]".to_owned())?;
ensure_equal(
&recovery[0]["priority"].as_u64(),
&Some(1),
"derivation recovery priority",
)?;
ensure_equal(
&recovery[0]["kind"].as_str(),
&Some("command"),
"derivation recovery kind",
)?;
ensure_equal(
&recovery[0]["command"].as_str(),
&Some("ee curate propose-derived --workspace . --json"),
"derivation recovery command",
)?;
ensure_contains(
recovery[0]["rationale"].as_str().unwrap_or_default(),
"current source hashes",
"derivation recovery rationale",
)
}
#[test]
fn error_schema_derived_apply_conflict_storage_failure_has_recovery() -> TestResult {
let error = DomainError::Storage {
message:
"Create-derived curation candidate cand_1 source refs failed apply-time revalidation: \
derived_source_memory_tombstoned: Memory source mem_1 was tombstoned before apply."
.to_owned(),
repair: Some(
"Re-run `ee curate validate <candidate-id>` and refresh drifted sources."
.to_owned(),
),
};
let parsed: serde_json::Value = serde_json::from_str(&error_response_json(&error))
.map_err(|error| error.to_string())?;
let recovery = parsed["error"]["details"]["recovery"]
.as_array()
.ok_or_else(|| "derived apply conflict should include details.recovery[]".to_owned())?;
ensure_equal(
&recovery[0]["command"].as_str(),
&Some("ee curate propose-derived --workspace . --json"),
"derived apply conflict recovery command",
)?;
ensure_equal(
&recovery[1]["command"].as_str(),
&Some("ee why <source-id> --workspace . --json"),
"derived apply source inspection command",
)?;
ensure_contains(
recovery[0]["rationale"].as_str().unwrap_or_default(),
"active source memories",
"derived apply conflict recovery rationale",
)
}
#[test]
fn error_schema_create_derived_replay_inconsistency_has_recovery() -> TestResult {
let error = DomainError::Storage {
message:
"create_derived_replay_missing_audit: applied candidate cand_1 is missing its \
curation apply audit row."
.to_owned(),
repair: Some("Run `ee doctor --workspace . --json` before retrying replay.".to_owned()),
};
let parsed: serde_json::Value = serde_json::from_str(&error_response_json(&error))
.map_err(|error| error.to_string())?;
let recovery = parsed["error"]["details"]["recovery"]
.as_array()
.ok_or_else(|| "replay inconsistency should include details.recovery[]".to_owned())?;
ensure_equal(
&recovery[0]["command"].as_str(),
&Some("ee curate show <candidate-id> --workspace . --json"),
"first replay recovery command",
)?;
ensure_equal(
&recovery[1]["command"].as_str(),
&Some("ee audit timeline --surface curation --json"),
"second replay recovery command",
)?;
ensure_equal(
&recovery[2]["command"].as_str(),
&Some("ee doctor --workspace . --json"),
"third replay recovery command",
)
}
#[test]
fn error_schema_reflection_failure_has_structured_recovery() -> TestResult {
let error = DomainError::Configuration {
message: "reflect_hmac_key_missing: reflection HMAC key unavailable".to_owned(),
repair: Some("Configure reflection HMAC key material.".to_owned()),
};
let parsed: serde_json::Value = serde_json::from_str(&error_response_json(&error))
.map_err(|error| error.to_string())?;
let recovery = parsed["error"]["details"]["recovery"]
.as_array()
.ok_or_else(|| "reflection error should include details.recovery[]".to_owned())?;
ensure_equal(
&recovery[0]["command"].as_str(),
&Some("ee status --workspace . --json"),
"reflection recovery command",
)?;
ensure(
recovery
.iter()
.any(|action| action["envName"].as_str() == Some("EE_REFLECTION_HMAC_KEY")),
"reflection key recovery should include env action",
)?;
ensure_equal(
&recovery[0]["requiresHumanApproval"].as_bool(),
&Some(false),
"reflection read-only recovery does not require approval",
)
}
#[test]
fn error_schema_migration_required_has_stable_structure() -> TestResult {
let error = DomainError::MigrationRequired {
message: "Database schema version 3 requires migration to version 5.".to_string(),
repair: Some("ee init --workspace .".to_string()),
};
let json = error_response_json(&error);
ensure_starts_with(&json, "{\"schema\":\"ee.error.v2\"", "schema")?;
ensure_contains(&json, "\"code\":\"migration_required\"", "code")?;
ensure_contains(&json, "version 3", "message contains version")?;
ensure_contains(&json, "\"severity\":\"medium\"", "severity")?;
// Bead bd-17c65.6.1 (F1): migration_required carries a recovery[]
// pointing at `ee migrate run`. Verify structure.
ensure_contains(&json, "\"details\":{", "details opens")?;
ensure_contains(&json, "\"recovery\":[", "recovery array present")?;
ensure_contains(&json, "\"kind\":\"migration\"", "recovery kind")?;
ensure_contains(&json, "ee migrate run", "recovery command")?;
ensure_contains(&json, "\"repair\":\"ee init --workspace .\"", "repair")
}
#[test]
fn error_schema_not_found_details_are_structured() -> TestResult {
let error = DomainError::NotFound {
resource: "memory".to_string(),
id: "mem_abc123".to_string(),
repair: Some("ee memory list --json".to_string()),
};
let json = error_response_json(&error);
ensure_contains(&json, "\"code\":\"not_found\"", "code")?;
ensure_contains(&json, "\"severity\":\"low\"", "severity")?;
ensure_contains(&json, "\"details\":{", "details object")?;
ensure_contains(&json, "\"resource\":\"memory\"", "details resource")?;
ensure_contains(&json, "\"id\":\"mem_abc123\"", "details id")
}
#[test]
fn error_schema_all_codes_are_covered() -> TestResult {
let codes = [
"usage",
"configuration",
"storage",
"search_index",
"graph",
"import",
"not_found",
"unsatisfied_degraded_mode",
"policy_denied",
"migration_required",
];
let severities = [
"low", "medium", "high", "medium", "medium", "medium", "low", "medium", "medium",
"medium",
];
let errors = [
DomainError::Usage {
message: "test".to_string(),
repair: None,
},
DomainError::Configuration {
message: "test".to_string(),
repair: None,
},
DomainError::Storage {
message: "test".to_string(),
repair: None,
},
DomainError::SearchIndex {
message: "test".to_string(),
repair: None,
},
DomainError::Graph {
message: "test".to_string(),
repair: None,
},
DomainError::Import {
message: "test".to_string(),
repair: None,
},
DomainError::NotFound {
resource: "thing".to_string(),
id: "item_1".to_string(),
repair: None,
},
DomainError::UnsatisfiedDegradedMode {
message: "test".to_string(),
repair: None,
},
DomainError::PolicyDenied {
message: "test".to_string(),
repair: None,
},
DomainError::MigrationRequired {
message: "test".to_string(),
repair: None,
},
];
for ((error, expected_code), expected_severity) in
errors.iter().zip(codes.iter()).zip(severities.iter())
{
let json = error_response_json(error);
ensure_starts_with(&json, "{\"schema\":\"ee.error.v2\"", expected_code)?;
ensure_contains(
&json,
&format!("\"code\":\"{expected_code}\""),
expected_code,
)?;
ensure_contains(
&json,
&format!("\"severity\":\"{expected_severity}\""),
expected_code,
)?;
ensure_contains(&json, "\"details\":{", expected_code)?;
}
Ok(())
}
#[test]
fn error_schema_without_repair_omits_field() -> TestResult {
// Verify that when repair is None, the field is absent (not null)
for error in [
DomainError::Usage {
message: "test".to_string(),
repair: None,
},
DomainError::Storage {
message: "test".to_string(),
repair: None,
},
] {
let json = error_response_json(&error);
ensure(
!json.contains("repair"),
format!("{}: repair field should be absent when None", error.code()),
)?;
}
Ok(())
}
// ========================================================================
// TOON Output Tests (EE-036)
//
// TOON is rendered from the canonical JSON envelope through /dp/toon_rust.
// These tests prove the public renderer is valid TOON and semantically
// equivalent to the JSON status output.
// ========================================================================
fn sample_status_skyline_report() -> StatusSkylineReport {
StatusSkylineReport {
schema: STATUS_SKYLINE_SCHEMA_V1,
snapshot_version: 7,
summary: StatusSkylineSummaryReport {
community_count: 2,
highest_risk_community_id: Some("community-risk".to_owned()),
load_bearing_memory_count: 3,
stale_community_count: 1,
},
skyline: vec![StatusSkylineCommunityReport {
community_id: "community-risk".to_owned(),
memory_count: 4,
mean_trust: 0.75,
mean_age_days: 12.5,
onion_layer: 2,
structural_health: "stale".to_owned(),
}],
degraded: vec![DegradationReport {
code: "graph.skyline_fixture",
severity: "info",
message: "fixture degradation",
repair: "no repair needed",
}],
}
}
fn sample_proximity_report() -> ProximityReport {
ProximityReport {
schema: PROXIMITY_SCHEMA_V1,
memory_a: "mem_alpha".to_owned(),
memory_b: "mem_beta".to_owned(),
snapshot_version: 11,
min_cut: Some(2.5),
interpretation: "moderate".to_owned(),
tree_path: Some(vec![
"mem_alpha".to_owned(),
"mem_bridge".to_owned(),
"mem_beta".to_owned(),
]),
degraded: vec![ProximityDegradation {
code: "graph.proximity_fixture".to_owned(),
severity: "warning".to_owned(),
message: "fixture proximity degradation".to_owned(),
repair: Some("ee graph centrality-refresh --workspace .".to_owned()),
}],
}
}
fn sample_structural_health_report() -> StructuralHealthReport {
StructuralHealthReport {
schema: HEALTH_STRUCTURAL_SCHEMA_V1,
snapshot_version: 5,
k_truss: StructuralKTrussSummary {
max_k: 4,
support_subgraph_memory_count: 9,
top_members: vec![StructuralKTrussMember {
memory_id: "mem_support".to_owned(),
k: 4,
triangle_support: 6,
}],
},
contradiction_clusters: vec![StructuralContradictionCluster {
cluster_id: "cluster_contradiction".to_owned(),
memory_count: 3,
contradiction_density: 0.625,
example_memory_ids: vec!["mem_a".to_owned(), "mem_b".to_owned()],
severity: "medium".to_owned(),
suggested_action: "ee curate candidates --workspace . --json".to_owned(),
}],
summary: StructuralHealthSummary {
status: "degraded".to_owned(),
k_truss_max_k: 4,
support_subgraph_memory_count: 9,
contradiction_cluster_count: 1,
recommended_command: "ee health --robot-insights --json".to_owned(),
},
degraded: vec![StructuralHealthDegradation {
code: "graph.health_fixture".to_owned(),
severity: "warning".to_owned(),
message: "fixture structural health degradation".to_owned(),
repair: Some("ee graph centrality-refresh --workspace .".to_owned()),
}],
}
}
fn sample_pack_dna_value() -> serde_json::Value {
serde_json::json!({
"schema": "ee.context.pack_dna.v1",
"snapshotVersion": 42,
"voronoiDominator": {
"memoryId": "mem_release_policy",
"distance": 0.0,
"reason": "selected item dominates the local evidence neighborhood"
},
"communityOfMass": {
"communityId": "release-readiness",
"mass": 0.72,
"topMemoryIds": ["mem_release_policy", "mem_rch_remote_required"]
},
"egoSubgraph": {
"nodes": [
{"id": "mem_release_policy", "kind": "memory"},
{"id": "mem_rch_remote_required", "kind": "memory"}
],
"edges": [
{
"source": "mem_release_policy",
"target": "mem_rch_remote_required",
"relation": "supports",
"weight": 0.91
}
]
},
"pprNeighbors": [
{"memoryId": "mem_rch_remote_required", "score": 0.41, "rank": 1}
],
"degraded": [
{
"code": "graph.pack_dna_fixture",
"severity": "warning",
"message": "fixture pack DNA degradation",
"repair": "ee graph centrality-refresh --workspace . --json"
}
]
})
}
fn sample_why_causal_value() -> serde_json::Value {
serde_json::json!({
"schema": "ee.why.causal.v1",
"memoryId": "mem_release_failure",
"snapshotVersion": 42,
"paths": [
{
"rank": 1,
"sourceMemoryId": "mem_rch_topology_note",
"targetMemoryId": "mem_release_failure",
"edgeCount": 2,
"totalContribution": 0.87,
"steps": [
{
"source": "mem_rch_topology_note",
"target": "mem_remote_check_blocked",
"relation": "supports",
"contributionScore": 0.48
},
{
"source": "mem_remote_check_blocked",
"target": "mem_release_failure",
"relation": "caused",
"contributionScore": 0.39
}
]
}
],
"minCut": {
"sourceMemoryId": "mem_rch_topology_note",
"targetMemoryId": "mem_release_failure",
"cutWeight": 0.31,
"cutMemoryIds": ["mem_remote_check_blocked"]
},
"degraded": [
{
"code": "graph.causal_fixture",
"severity": "low",
"message": "fixture causal degradation",
"repair": "ee causal trace --workspace . --json"
}
]
})
}
fn sample_memory_impact_analysis_value() -> serde_json::Value {
serde_json::json!({
"schema": "ee.memory.impact_analysis.v1",
"memoryId": "mem_release_policy",
"snapshotVersion": 7,
"revisionLineage": [
{
"memoryId": "mem_release_policy",
"logicalId": "release-policy",
"depth": 0,
"relation": "self",
"validFrom": "2026-05-19T00:00:00Z"
}
],
"impactAnalysis": {
"immediateDominator": "mem_root_policy",
"dominanceFrontier": ["mem_ci_gate", "mem_release_notes"],
"affectedMemoryCount": 3,
"validationStatus": "valid"
},
"frontiers": [
{
"memoryId": "mem_ci_gate",
"dominanceFrontierSize": 2,
"affectedMemoryIds": ["mem_release_notes", "mem_install_docs"],
"evidence": {
"algorithm": "dominance_frontiers",
"snapshotVersion": 7
}
}
],
"degraded": [
{
"code": "graph.impact_fixture",
"severity": "info",
"message": "fixture impact degradation",
"repair": "ee why mem_release_policy --workspace . --json"
}
]
})
}
#[test]
fn pack_dna_markdown_renderer_preserves_graph_summary() -> TestResult {
let markdown = render_pack_dna_markdown(&sample_pack_dna_value());
ensure_contains(&markdown, "# Pack DNA", "pack DNA markdown title")?;
ensure_contains(
&markdown,
"- Schema: `ee.context.pack_dna.v1`",
"pack DNA markdown schema",
)?;
ensure_contains(
&markdown,
"- Snapshot version: 42",
"pack DNA markdown snapshot",
)?;
ensure_contains(
&markdown,
"- Voronoi dominator: `mem_release_policy` distance=0.0 reason=selected item dominates the local evidence neighborhood",
"pack DNA markdown dominator",
)?;
ensure_contains(
&markdown,
"- Community of mass: `release-readiness` mass=0.72 topMemoryIds=mem_release_policy, mem_rch_remote_required",
"pack DNA markdown community",
)?;
ensure_contains(
&markdown,
"- Ego subgraph: nodes=2 edges=1",
"pack DNA markdown ego",
)?;
ensure_contains(
&markdown,
"- rank=1 `mem_rch_remote_required` score=0.41",
"pack DNA markdown ppr",
)?;
ensure_contains(
&markdown,
"- **warning** `graph.pack_dna_fixture`: fixture pack DNA degradation",
"pack DNA markdown degradation",
)
}
#[test]
fn pack_dna_toon_decodes_to_canonical_json() -> TestResult {
let value = sample_pack_dna_value();
let json = render_pack_dna_json(&value);
let toon = render_pack_dna_toon(&value);
ensure_toon_matches_json(&json, &toon, "decoded pack DNA TOON")
}
#[test]
fn why_causal_markdown_renderer_preserves_paths_and_degraded() -> TestResult {
let markdown = render_why_causal_markdown(&sample_why_causal_value());
ensure_contains(&markdown, "# Why Causal", "why causal markdown title")?;
ensure_contains(
&markdown,
"- Schema: `ee.why.causal.v1`",
"why causal markdown schema",
)?;
ensure_contains(
&markdown,
"- Memory: `mem_release_failure`",
"why causal markdown memory",
)?;
ensure_contains(
&markdown,
"- rank=1 `mem_rch_topology_note` -> `mem_release_failure` edges=2 totalContribution=0.87",
"why causal markdown path",
)?;
ensure_contains(
&markdown,
" - `mem_rch_topology_note` -> `mem_remote_check_blocked` relation=`supports` contribution=0.48",
"why causal markdown step",
)?;
ensure_contains(
&markdown,
"- **low** `graph.causal_fixture`: fixture causal degradation",
"why causal markdown degradation",
)
}
#[test]
fn why_causal_toon_decodes_to_canonical_json() -> TestResult {
let value = sample_why_causal_value();
let json = render_why_causal_json(&value);
let toon = render_why_causal_toon(&value);
ensure_toon_matches_json(&json, &toon, "decoded why causal TOON")
}
#[test]
fn memory_impact_analysis_markdown_renderer_preserves_frontiers() -> TestResult {
let markdown =
render_memory_impact_analysis_markdown(&sample_memory_impact_analysis_value());
ensure_contains(
&markdown,
"# Memory Impact Analysis",
"impact markdown title",
)?;
ensure_contains(
&markdown,
"- Schema: `ee.memory.impact_analysis.v1`",
"impact markdown schema",
)?;
ensure_contains(
&markdown,
"- Memory: `mem_release_policy`",
"impact markdown memory",
)?;
ensure_contains(
&markdown,
"- Affected memories: 3",
"impact markdown affected count",
)?;
ensure_contains(
&markdown,
"- Immediate dominator: `mem_root_policy`",
"impact markdown dominator",
)?;
ensure_contains(
&markdown,
"- Dominance frontier: mem_ci_gate, mem_release_notes",
"impact markdown frontier",
)?;
ensure_contains(
&markdown,
"- `mem_release_policy` logical=`release-policy` depth=0 relation=`self`",
"impact markdown lineage",
)?;
ensure_contains(
&markdown,
"- `mem_ci_gate` size=2 affected=mem_release_notes, mem_install_docs",
"impact markdown frontier item",
)?;
ensure_contains(
&markdown,
"- **info** `graph.impact_fixture`: fixture impact degradation",
"impact markdown degradation",
)
}
#[test]
fn memory_impact_analysis_toon_decodes_to_canonical_json() -> TestResult {
let value = sample_memory_impact_analysis_value();
let json = render_memory_impact_analysis_json(&value);
let toon = render_memory_impact_analysis_toon(&value);
ensure_toon_matches_json(&json, &toon, "decoded impact analysis TOON")
}
#[test]
fn status_skyline_markdown_renderer_preserves_summary_and_rows() -> TestResult {
let markdown = render_status_skyline_markdown(&sample_status_skyline_report());
ensure_contains(&markdown, "# Status Skyline", "markdown title")?;
ensure_contains(
&markdown,
"- Schema: `ee.status.skyline.v1`",
"markdown schema",
)?;
ensure_contains(&markdown, "- Communities: 2", "markdown communities")?;
ensure_contains(
&markdown,
"- Load-bearing memories: 3",
"markdown load-bearing count",
)?;
ensure_contains(
&markdown,
"- Highest-risk community: `community-risk`",
"markdown highest-risk community",
)?;
ensure_contains(
&markdown,
"- `community-risk` [####................] memories=4 trust=0.75 age=12.5d onion=2 health=`stale`",
"markdown skyline row",
)?;
ensure_contains(
&markdown,
"- **info** `graph.skyline_fixture`: fixture degradation",
"markdown degradation",
)
}
#[test]
fn status_skyline_toon_decodes_to_canonical_json() -> TestResult {
let report = sample_status_skyline_report();
let json = render_status_skyline_json(&report);
let toon = render_status_skyline_toon(&report);
let expected_json = serde_json::from_str::<serde_json::Value>(&json)
.map_err(|error| format!("status skyline JSON should parse: {error}"))?;
let expected = serde_json::Value::from(toon::JsonValue::from(expected_json));
let decoded = toon::try_decode(&toon, None)
.map_err(|error| format!("status skyline TOON should decode: {error}"))?;
let actual = serde_json::Value::from(decoded);
ensure_equal(&actual, &expected, "decoded status skyline TOON")
}
fn audit_timeline_entry_fixture(id: &str) -> crate::core::audit::AuditTimelineEntry {
crate::core::audit::AuditTimelineEntry {
id: id.to_owned(),
timestamp: "2026-08-01T00:00:00Z".to_owned(),
actor: Some("ee".to_owned()),
surface: "memory".to_owned(),
mutation_kind: "curation_candidate.apply".to_owned(),
before_hash: None,
after_hash: None,
prev_row_hash: Some("blake3:prevfixture".to_owned()),
this_row_hash: Some("blake3:thisfixture".to_owned()),
workspace_id: Some("wsp_00000000000000000000000001".to_owned()),
shard_id: None,
target_type: Some("memory".to_owned()),
target_id: Some("mem_00000000000000000000000001".to_owned()),
producer: crate::models::ProducerMetadata::audit_actor(
Some("ee"),
Some("2026-08-01T00:00:00Z"),
),
details: Some(serde_json::json!({
"candidateId": "curate_00000000000000000000000001",
})),
}
}
fn audit_timeline_report_fixture() -> crate::core::audit::AuditTimelineReport {
crate::core::audit::AuditTimelineReport {
schema: "ee.audit.timeline.v1".to_owned(),
entries: vec![audit_timeline_entry_fixture(
"audit_0193c5a37d2f7b7fa3b0c2d4",
)],
pagination: crate::core::audit::TimelinePagination {
total_count: 7,
returned_count: 1,
has_more: true,
next_cursor: Some("eec1.fixture-cursor-token".to_owned()),
},
degraded: vec![super::governor::cursor_invalid_degraded_entry()],
}
}
/// bd-1oep7: paginated / cursor-rejected human output must explain both
/// the continuation cursor and every degraded entry — an empty or partial
/// page with a silent reason is not honest.
#[test]
fn audit_timeline_human_renders_cursor_and_degraded() -> TestResult {
let report = audit_timeline_report_fixture();
let human = super::render_audit_timeline_human(&report);
ensure_contains(&human, "Showing 1 of 7 operations", "timeline human count")?;
ensure_contains(
&human,
"Degraded [low] cursor_invalid:",
"timeline human degraded code and severity",
)?;
ensure_contains(
&human,
"Continuation cursor failed validation",
"timeline human degraded message",
)?;
ensure_contains(
&human,
"Repair: Re-run the command without --cursor",
"timeline human degraded repair",
)?;
ensure_contains(
&human,
"ee audit timeline --cursor eec1.fixture-cursor-token --json",
"timeline human next-page cursor continuation",
)
}
/// bd-1oep7: every audit TOON rendering must be the lossless canonical
/// encoding of the enveloped JSON — decoding the TOON yields exactly the
/// JSON value, for all four surfaces.
#[test]
fn audit_toon_output_is_lossless_canonical_encoding() -> TestResult {
let timeline = audit_timeline_report_fixture();
ensure_toon_matches_json(
&super::render_audit_timeline_json(&timeline).map_err(|error| error.message())?,
&super::render_audit_timeline_toon(&timeline).map_err(|error| error.message())?,
"audit timeline TOON",
)?;
let show = crate::core::audit::AuditShowReport {
schema: "ee.audit.show.v1".to_owned(),
row: audit_timeline_entry_fixture("audit_0193c5a37d2f7b7fa3b0c2d4"),
linked_snapshot: crate::core::audit::LinkedSnapshot {
target_type: Some("memory".to_owned()),
target_id: Some("mem_00000000000000000000000001".to_owned()),
found: true,
snapshot_hash: Some("blake3:snapshotfixture".to_owned()),
snapshot: Some(serde_json::json!({"content": "fixture"})),
},
hash_chain_valid: true,
};
ensure_toon_matches_json(
&super::render_audit_show_json(&show).map_err(|error| error.message())?,
&super::render_audit_show_toon(&show).map_err(|error| error.message())?,
"audit show TOON",
)?;
let diff = crate::core::audit::AuditDiffReport {
schema: "ee.audit.diff.v1".to_owned(),
from: "2026-08-01T00:00:00Z".to_owned(),
to: "2026-08-02T00:00:00Z".to_owned(),
entries: vec![audit_timeline_entry_fixture(
"audit_0193c5a37d2f7b7fa3b0c2d4",
)],
row_count: 1,
};
ensure_toon_matches_json(
&super::render_audit_diff_json(&diff).map_err(|error| error.message())?,
&super::render_audit_diff_toon(&diff).map_err(|error| error.message())?,
"audit diff TOON",
)?;
let verify = crate::core::audit::AuditVerifyReport {
schema: "ee.audit.verify.v1".to_owned(),
integrity_ok: false,
rows: 3,
last_hash: Some("blake3:lastfixture".to_owned()),
first_break: Some("audit_0193c5a37d2f7b7fa3b0c2d5".to_owned()),
issues: vec![crate::core::audit::VerificationIssue {
code: "hash_chain_break".to_owned(),
audit_id: Some("audit_0193c5a37d2f7b7fa3b0c2d5".to_owned()),
shard_id: None,
message: "prev hash mismatch at fixture row".to_owned(),
}],
shard_count: 0,
broken_shard_count: 0,
shards: Vec::new(),
};
ensure_toon_matches_json(
&super::render_audit_verify_json(&verify).map_err(|error| error.message())?,
&super::render_audit_verify_toon(&verify).map_err(|error| error.message())?,
"audit verify TOON",
)
}
/// bd-1oep7: a payload that is not valid JSON must surface as a typed
/// DomainError whose canonical ee.error.v2 rendering carries mandatory
/// error.details.recovery[] — never a hollow success, never exit 0.
#[test]
fn audit_response_envelope_propagates_parse_failure_as_error_v2() -> TestResult {
let error = super::audit_response_v2_json("this is not json")
.expect_err("invalid JSON payload must be a typed error");
ensure(
error.code() == "storage",
format!(
"parse failure must map to the stable storage code: {}",
error.code()
),
)?;
ensure(
error.message().contains("invalid JSON"),
format!("parse failure must explain itself: {}", error.message()),
)?;
let envelope = super::error_response_json(&error);
let value: serde_json::Value = serde_json::from_str(&envelope)
.map_err(|render_error| format!("error envelope must be JSON: {render_error}"))?;
ensure(
value["schema"] == "ee.error.v2",
format!("parse failure must render ee.error.v2: {value}"),
)?;
ensure(
value["error"]["details"]["recovery"]
.as_array()
.is_some_and(|recovery| !recovery.is_empty()),
format!("error envelope must carry mandatory details.recovery[]: {value}"),
)?;
ensure(
value.get("success").is_none() && value.get("data").is_none(),
format!("error envelope must not claim success or carry hollow data: {value}"),
)
}
/// bd-1oep7: the serialize_or_error marker must propagate as a typed
/// error carrying the original failure message, never be wrapped as
/// success data.
#[test]
fn audit_response_envelope_propagates_serialization_failed_marker() -> TestResult {
let marker = serde_json::json!({
"error": "serialization_failed",
"message": "audit row was not serializable",
})
.to_string();
let error = super::audit_response_v2_json(&marker)
.expect_err("serialization_failed marker must be a typed error");
ensure(
error.message().contains("audit row was not serializable"),
format!(
"marker must propagate the original failure message: {}",
error.message()
),
)?;
let envelope = super::error_response_json(&error);
let value: serde_json::Value = serde_json::from_str(&envelope)
.map_err(|render_error| format!("error envelope must be JSON: {render_error}"))?;
ensure(
value["schema"] == "ee.error.v2",
format!("marker must render ee.error.v2: {value}"),
)?;
ensure(
value["error"]["details"]["recovery"]
.as_array()
.is_some_and(|recovery| !recovery.is_empty()),
format!("marker envelope must carry mandatory details.recovery[]: {value}"),
)
}
/// bd-1oep7: the success envelope lifts degraded[] to the envelope level
/// and leaves no duplicate degraded key inside data.
#[test]
fn audit_response_envelope_lifts_degraded_on_success() -> TestResult {
let report = audit_timeline_report_fixture();
let out = super::render_audit_timeline_json(&report).map_err(|error| error.message())?;
let value: serde_json::Value = serde_json::from_str(&out)
.map_err(|error| format!("success envelope must be JSON: {error}"))?;
ensure(
value["schema"] == "ee.response.v2" && value["success"] == true,
format!("audit timeline must emit a canonical success envelope: {value}"),
)?;
ensure(
value["data"]["schema"] == "ee.audit.timeline.v1",
format!("report must nest under data: {value}"),
)?;
ensure(
value["degraded"][0]["code"] == "cursor_invalid",
format!("degraded must be lifted to the envelope level: {value}"),
)?;
ensure(
value["data"].get("degraded").is_none(),
format!("data must not retain a duplicate degraded key: {value}"),
)
}
#[test]
fn proximity_markdown_renderer_preserves_values_and_degradations() -> TestResult {
let markdown = render_proximity_markdown(&sample_proximity_report());
ensure_contains(&markdown, "# Proximity", "proximity markdown title")?;
ensure_contains(
&markdown,
"- Schema: `ee.proximity.v1`",
"proximity markdown schema",
)?;
ensure_contains(
&markdown,
"- Memory A: `mem_alpha`",
"proximity markdown memory A",
)?;
ensure_contains(
&markdown,
"- Memory B: `mem_beta`",
"proximity markdown memory B",
)?;
ensure_contains(
&markdown,
"- Interpretation: `moderate`",
"proximity markdown interpretation",
)?;
ensure_contains(
&markdown,
"- Min cut: 2.500000",
"proximity markdown min cut",
)?;
ensure_contains(
&markdown,
"- Tree path: mem_alpha -> mem_bridge -> mem_beta",
"proximity markdown tree path",
)?;
ensure_contains(
&markdown,
"- **warning** `graph.proximity_fixture`: fixture proximity degradation",
"proximity markdown degradation",
)?;
ensure_contains(
&markdown,
" - Repair: `ee graph centrality-refresh --workspace .`",
"proximity markdown repair",
)
}
#[test]
fn proximity_toon_decodes_to_canonical_json() -> TestResult {
let report = sample_proximity_report();
let json = render_proximity_json(&report);
let toon = render_proximity_toon(&report);
let expected_json = serde_json::from_str::<serde_json::Value>(&json)
.map_err(|error| format!("proximity JSON should parse: {error}"))?;
let expected = serde_json::Value::from(toon::JsonValue::from(expected_json));
let decoded = toon::try_decode(&toon, None)
.map_err(|error| format!("proximity TOON should decode: {error}"))?;
let actual = serde_json::Value::from(decoded);
ensure_equal(&actual, &expected, "decoded proximity TOON")
}
#[test]
fn structural_health_markdown_renderer_preserves_sections() -> TestResult {
let markdown = render_structural_health_markdown(&sample_structural_health_report());
ensure_contains(
&markdown,
"# Structural Health",
"structural markdown title",
)?;
ensure_contains(
&markdown,
"- Schema: `ee.health.structural.v1`",
"structural markdown schema",
)?;
ensure_contains(
&markdown,
"- Status: `degraded`",
"structural markdown status",
)?;
ensure_contains(
&markdown,
"- K-truss max k: 4",
"structural markdown k-truss max",
)?;
ensure_contains(
&markdown,
"- `mem_support` k=4 triangleSupport=6",
"structural markdown k-truss member",
)?;
ensure_contains(
&markdown,
"- `cluster_contradiction` memories=3 density=0.625000 severity=`medium` examples=mem_a, mem_b action=`ee curate candidates --workspace . --json`",
"structural markdown contradiction cluster",
)?;
ensure_contains(
&markdown,
"- **warning** `graph.health_fixture`: fixture structural health degradation",
"structural markdown degradation",
)?;
ensure_contains(
&markdown,
" - Repair: `ee graph centrality-refresh --workspace .`",
"structural markdown repair",
)
}
#[test]
fn structural_health_toon_decodes_to_canonical_json() -> TestResult {
let report = sample_structural_health_report();
let json = render_structural_health_json(&report);
let toon = render_structural_health_toon(&report);
ensure_toon_matches_json(&json, &toon, "decoded structural health TOON")
}
#[test]
fn structural_health_json_wraps_in_ee_response_v2_envelope() -> TestResult {
// bd-34ivx: `ee health --robot-insights --json` must ride the
// canonical ee.response.v2 envelope; the bare report previously
// emitted at the top level now lives at `.data` with its own
// inner schema id preserved.
let report = sample_structural_health_report();
let json = render_structural_health_json(&report);
let value: serde_json::Value =
serde_json::from_str(&json).map_err(|error| error.to_string())?;
ensure_equal(
&value.pointer("/schema").and_then(serde_json::Value::as_str),
&Some(RESPONSE_SCHEMA_V2),
"top-level envelope schema must be ee.response.v2",
)?;
ensure_equal(
&value
.pointer("/success")
.and_then(serde_json::Value::as_bool),
&Some(true),
"envelope success must be true",
)?;
ensure(
value
.pointer("/data")
.is_some_and(serde_json::Value::is_object),
"envelope data must be an object",
)?;
ensure_equal(
&value
.pointer("/data/summary/status")
.and_then(serde_json::Value::as_str),
&Some("degraded"),
"inner summary.status must be preserved verbatim from the sample report",
)?;
ensure_top_level_degraded_mirrors_data_degraded(&value, "structural health JSON envelope")
}
#[test]
fn toon_status_has_required_fields() -> TestResult {
let report = StatusReport::gather();
let toon = render_status_toon(&report);
ensure_contains(&toon, "schema: ee.response.v2", "toon schema")?;
ensure_contains(&toon, "success: true", "toon success")?;
ensure_contains(&toon, "command: status", "toon command")?;
ensure_contains(&toon, "capabilities:", "toon capabilities section")?;
ensure_contains(&toon, "runtime:", "toon runtime section")?;
ensure_contains(&toon, "derivedAssets", "toon derived assets section")?;
ensure_contains(&toon, "engine: asupersync", "toon engine")
}
#[test]
fn toon_status_has_degradation_details() -> TestResult {
let report = StatusReport::gather();
let toon = render_status_toon(&report);
// After fix: gather() inspects current workspace, so degradation count
// varies based on actual workspace state. Just verify the section exists.
ensure_contains(&toon, "degraded[", "degradation section")?;
ensure_contains(&toon, "code:", "degradation code field")?;
ensure_contains(&toon, "sources[1]: status", "degradation source label")
}
#[test]
fn json_toon_parity_status_decodes_to_same_json() -> TestResult {
let report = StatusReport::gather();
let json = render_status_json_filtered(&report, FieldProfile::Standard);
let toon = render_status_toon(&report);
let expected_json = serde_json::from_str::<serde_json::Value>(&json)
.map_err(|error| format!("status JSON should parse: {error}"))?;
let expected = serde_json::Value::from(toon::JsonValue::from(expected_json));
let decoded = toon::try_decode(&toon, None)
.map_err(|error| format!("status TOON should decode: {error}"))?;
let actual = serde_json::Value::from(decoded);
ensure_equal(&actual, &expected, "decoded TOON matches status JSON")
}
#[test]
fn json_toon_parity_health_decodes_to_same_json() -> TestResult {
let report = HealthReport::gather();
let json = render_health_json(&report);
let toon = render_health_toon(&report);
let expected_json = serde_json::from_str::<serde_json::Value>(&json)
.map_err(|error| format!("health JSON should parse: {error}"))?;
let expected = serde_json::Value::from(toon::JsonValue::from(expected_json));
let decoded = toon::try_decode(&toon, None)
.map_err(|error| format!("health TOON should decode: {error}"))?;
let actual = serde_json::Value::from(decoded);
ensure_equal(&actual, &expected, "decoded TOON matches health JSON")
}
#[test]
fn json_toon_parity_doctor_decodes_to_same_json() -> TestResult {
let report = DoctorReport::gather();
let json = render_doctor_json(&report);
let toon = render_doctor_toon(&report);
let expected_json = serde_json::from_str::<serde_json::Value>(&json)
.map_err(|error| format!("doctor JSON should parse: {error}"))?;
ensure_empty_top_level_degraded(&expected_json, "doctor JSON envelope")?;
let expected = serde_json::Value::from(toon::JsonValue::from(expected_json));
let decoded = toon::try_decode(&toon, None)
.map_err(|error| format!("doctor TOON should decode: {error}"))?;
let actual = serde_json::Value::from(decoded);
ensure_equal(&actual, &expected, "decoded TOON matches doctor JSON")
}
#[test]
fn json_toon_parity_doctor_concise_decodes_to_same_json() -> TestResult {
let report = DoctorReport::gather();
let json = render_doctor_concise_json(&report);
let toon = render_doctor_concise_toon(&report);
let expected_json = serde_json::from_str::<serde_json::Value>(&json)
.map_err(|error| format!("doctor concise JSON should parse: {error}"))?;
ensure_empty_top_level_degraded(&expected_json, "doctor concise JSON envelope")?;
let expected = serde_json::Value::from(toon::JsonValue::from(expected_json));
let decoded = toon::try_decode(&toon, None)
.map_err(|error| format!("doctor concise TOON should decode: {error}"))?;
let actual = serde_json::Value::from(decoded);
ensure_equal(
&actual,
&expected,
"decoded TOON matches concise doctor JSON",
)
}
#[test]
fn render_doctor_concise_json_omits_diagnostic_firehose() -> TestResult {
let mut report = DoctorReport::gather();
report.overall_healthy = false;
report.posture = Posture::DegradedRecoverable;
report.checks = vec![
CheckResult::ok("runtime", "runtime ok"),
CheckResult {
name: "database",
severity: CheckSeverity::Warning,
message: "database sidecar requires repair".to_owned(),
error_code: None,
repair: Some("ee init --workspace . --json"),
tier: CheckTier::Core,
},
CheckResult {
name: "cass",
severity: CheckSeverity::Warning,
message: "CASS binary found but capabilities are limited.".to_owned(),
error_code: None,
repair: Some("ee import cass --dry-run --json"),
tier: CheckTier::Advisory,
},
CheckResult {
name: "reranker_posture",
severity: CheckSeverity::Warning,
message: "Permanent capability gap: fusion-only ranking.".to_owned(),
error_code: None,
repair: None,
tier: CheckTier::Advisory,
},
CheckResult::ok("rch_worker_pressure", "worker pressure ok").advisory(),
];
let concise = render_doctor_concise_json(&report);
let concise_human = render_doctor_concise_human(&report);
let full = render_doctor_json_filtered(&report, FieldProfile::Full);
let value = serde_json::from_str::<serde_json::Value>(&concise)
.map_err(|error| format!("doctor concise JSON should parse: {error}"))?;
let full_value = serde_json::from_str::<serde_json::Value>(&full)
.map_err(|error| format!("doctor full JSON should parse: {error}"))?;
let data = value["data"]
.as_object()
.ok_or_else(|| "doctor concise data must be an object".to_string())?;
ensure_equal(
&value["fields"],
&serde_json::json!("doctor_concise"),
"fields",
)?;
ensure_equal(&data["mode"], &serde_json::json!("concise"), "mode")?;
ensure_equal(
&data["posture"],
&serde_json::json!("degraded_recoverable"),
"posture",
)?;
ensure(
!data.contains_key("checks"),
"default concise omits full checks",
)?;
ensure(
!data.contains_key("meshAutoEnrollment"),
"default concise omits mesh firehose",
)?;
ensure(
!data.contains_key("rchWorkerPressure"),
"default concise omits RCH worker firehose",
)?;
ensure(
!data.contains_key("verificationPosture"),
"default concise omits verification posture firehose",
)?;
ensure(
!data.contains_key("verificationLedger"),
"default concise omits verification ledger firehose",
)?;
ensure(
!data.contains_key("hostCalibration"),
"default concise omits host calibration firehose",
)?;
let core_checks = data["coreChecks"]
.as_array()
.ok_or_else(|| "coreChecks must be an array".to_string())?;
ensure_equal(&core_checks.len(), &2usize, "core check count")?;
ensure_equal(
&core_checks[1]["name"],
&serde_json::json!("database"),
"core check name",
)?;
let actionable = data["actionable"]
.as_array()
.ok_or_else(|| "actionable must be an array".to_string())?;
ensure_equal(&actionable.len(), &1usize, "actionable core count")?;
ensure_equal(
&actionable[0]["repair"],
&serde_json::json!("ee init --workspace . --json"),
"actionable repair",
)?;
ensure_equal(
&data["advisorySummary"]["nonOk"],
&serde_json::json!(2),
"advisory non-ok count",
)?;
ensure_contains(
data["advisorySummary"]["summary"]
.as_str()
.unwrap_or_default(),
"2 non-ok of 3",
"advisory summary counts non-ok advisories",
)?;
ensure_equal(
&data["permanentCapabilityGaps"][0]["name"],
&serde_json::json!("reranker_posture"),
"concise permanent capability gap",
)?;
ensure_equal(
&data["permanentCapabilityGaps"][0]["permanent"],
&serde_json::json!(true),
"concise permanent marker",
)?;
ensure(
data["permanentCapabilityGaps"][0].get("repair").is_none(),
"concise permanent capability gap omits unavailable automatic repair",
)?;
ensure(
!concise_human.contains("--from-file /path/to/"),
"concise human doctor omits placeholder repair",
)?;
ensure_equal(
&full_value["data"]["advisories"][0].get("permanent"),
&None,
"transient advisory has no permanent marker",
)?;
ensure_equal(
&full_value["data"]["advisories"][1]["permanent"],
&serde_json::json!(true),
"permanent advisory marker",
)?;
ensure_contains(
data["advisorySummary"]["summary"]
.as_str()
.unwrap_or_default(),
"ee doctor --full --json",
"advisory summary points to full report",
)?;
ensure(concise.len() < 4096, "concise doctor JSON stays compact")?;
ensure(
concise.len() < full.len(),
"concise doctor JSON is smaller than full report",
)
}
#[test]
fn render_doctor_concise_json_handles_empty_check_set() -> TestResult {
let mut report = DoctorReport::gather();
report.overall_healthy = true;
report.posture = Posture::Ok;
report.checks.clear();
let json = render_doctor_concise_json(&report);
let value = serde_json::from_str::<serde_json::Value>(&json)
.map_err(|error| format!("doctor concise JSON should parse: {error}"))?;
ensure_equal(
&value["data"]["coreChecks"].as_array().map(Vec::len),
&Some(0),
"empty coreChecks",
)?;
ensure_equal(
&value["data"]["actionable"].as_array().map(Vec::len),
&Some(0),
"empty actionable",
)?;
ensure_equal(
&value["data"]["advisorySummary"]["total"],
&serde_json::json!(0),
"empty advisory total",
)?;
ensure_contains(
value["data"]["advisorySummary"]["summary"]
.as_str()
.unwrap_or_default(),
"advisories: none",
"empty advisory summary",
)
}
#[test]
fn render_doctor_json_exposes_singleflight_posture() -> TestResult {
let report = DoctorReport::gather();
let json = render_doctor_json_filtered(&report, FieldProfile::Standard);
let value = serde_json::from_str::<serde_json::Value>(&json)
.map_err(|error| format!("doctor JSON should parse: {error}"))?;
let singleflight = value
.pointer("/data/singleFlight")
.and_then(serde_json::Value::as_object)
.ok_or_else(|| "doctor JSON has data.singleFlight object".to_string())?;
ensure_equal(
&singleflight
.get("schema")
.and_then(serde_json::Value::as_str),
&Some("ee.singleflight.posture.v1"),
"singleFlight schema",
)?;
ensure(
singleflight.contains_key("surfaces"),
"singleFlight includes surface summaries",
)?;
let rendered = serde_json::to_string(singleflight)
.map_err(|error| format!("render doctor singleFlight JSON: {error}"))?;
for forbidden in [
"rawQuery",
"queryText",
"workspacePath",
"workspaceIdentity",
"memoryContent",
"memoryBody",
"mailBody",
"sourcePath",
"optionPairs",
"optionHashInput",
"release token secret",
"BEGIN PRIVATE KEY",
"sk-",
"ghp_",
"/private/",
] {
ensure(
!rendered.contains(forbidden),
format!("doctor singleFlight leaked forbidden text {forbidden:?}"),
)?;
}
Ok(())
}
#[test]
fn render_doctor_json_exposes_check_tier_and_advisory_summary() -> TestResult {
let mut report = DoctorReport::gather();
report.overall_healthy = true;
report.posture = Posture::Ok;
report.checks = vec![
CheckResult::ok("runtime", "runtime ok"),
CheckResult {
name: "cass",
severity: CheckSeverity::Warning,
message: "CASS binary found but capabilities are limited.".to_string(),
error_code: None,
repair: Some("Inspect `ee import cass --dry-run --json`."),
tier: CheckTier::Advisory,
},
];
let json = render_doctor_json_filtered(&report, FieldProfile::Standard);
let value = serde_json::from_str::<serde_json::Value>(&json)
.map_err(|error| format!("doctor JSON should parse: {error}"))?;
ensure_empty_top_level_degraded(&value, "doctor filtered JSON envelope")?;
ensure_equal(
&value["data"]["healthy"],
&serde_json::json!(true),
"healthy",
)?;
ensure_equal(
&value["data"]["posture"],
&serde_json::json!("ok"),
"posture",
)?;
ensure_equal(
&value["data"]["checks"][0]["tier"],
&serde_json::json!("core"),
"core check tier",
)?;
ensure_equal(
&value["data"]["checks"][1]["tier"],
&serde_json::json!("advisory"),
"advisory check tier",
)?;
ensure_equal(
&value["data"]["advisories"][0]["name"],
&serde_json::json!("cass"),
"advisory summary keeps cass warning visible",
)?;
ensure_equal(
&value["data"]["advisories"][0]["tier"],
&serde_json::json!("advisory"),
"advisory summary classifies tier",
)
}
#[test]
fn render_doctor_json_exposes_flight_recorder_posture() -> TestResult {
let report = DoctorReport::gather();
let json = render_doctor_json_filtered(&report, FieldProfile::Standard);
let value = serde_json::from_str::<serde_json::Value>(&json)
.map_err(|error| format!("doctor JSON should parse: {error}"))?;
let recorder = value
.pointer("/data/flightRecorder")
.and_then(serde_json::Value::as_object)
.ok_or_else(|| "doctor JSON has data.flightRecorder object".to_string())?;
ensure_equal(
&recorder.get("schema").and_then(serde_json::Value::as_str),
&Some("ee.flight_recorder.status.v1"),
"flightRecorder schema",
)?;
ensure(
recorder.contains_key("retentionDays") && recorder.contains_key("redactionLevel"),
"flightRecorder includes retention and redaction posture",
)
}
#[test]
fn render_doctor_json_exposes_rch_worker_pressure() -> TestResult {
let mut report = DoctorReport::gather();
report.rch_worker_pressure = rch_worker_pressure_fixture();
let json = render_doctor_json_filtered(&report, FieldProfile::Standard);
let value = serde_json::from_str::<serde_json::Value>(&json)
.map_err(|error| format!("doctor JSON should parse: {error}"))?;
let pressure = value
.pointer("/data/rchWorkerPressure")
.ok_or_else(|| "doctor JSON has data.rchWorkerPressure object".to_string())?;
ensure_equal(
&pressure["schema"],
&serde_json::json!("ee.rch.worker_pressure.v1"),
"rch worker pressure schema",
)?;
ensure_equal(
&pressure["status"],
&serde_json::json!("healthy_but_pressure_blocked"),
"rch worker pressure status",
)?;
ensure_equal(
&pressure["workers"][0]["reasonCode"],
&serde_json::json!("disk_pressure_critical"),
"rch worker pressure reason code",
)
}
#[test]
fn render_doctor_json_exposes_verification_posture() -> TestResult {
let mut report = DoctorReport::gather();
report.verification_posture = verification_posture_fixture();
let json = render_doctor_json_filtered(&report, FieldProfile::Standard);
let value = serde_json::from_str::<serde_json::Value>(&json)
.map_err(|error| format!("doctor JSON should parse: {error}"))?;
let posture = value
.pointer("/data/verificationPosture")
.ok_or_else(|| "doctor JSON has data.verificationPosture object".to_string())?;
ensure_equal(
&posture["schema"],
&serde_json::json!("ee.verification.posture.v1"),
"verification posture schema",
)?;
ensure_equal(
&posture["inFlightEquivalentCommandCount"],
&serde_json::json!(1),
"in-flight equivalent count",
)?;
ensure_equal(
&posture["evidenceHealth"]["reason"],
&serde_json::json!("remote_required_gate_used_local_fallback"),
"evidence health reason",
)
}
#[test]
fn render_doctor_json_exposes_host_calibration() -> TestResult {
let report = DoctorReport::gather();
let json = render_doctor_json_filtered(&report, FieldProfile::Standard);
let value = serde_json::from_str::<serde_json::Value>(&json)
.map_err(|error| format!("doctor JSON should parse: {error}"))?;
let calibration = value
.pointer("/data/hostCalibration")
.and_then(serde_json::Value::as_object)
.ok_or_else(|| "doctor JSON has data.hostCalibration object".to_string())?;
ensure_equal(
&calibration
.get("schema")
.and_then(serde_json::Value::as_str),
&Some("ee.host_calibration.posture.v1"),
"hostCalibration schema",
)?;
ensure(
calibration.contains_key("targetDirPosture"),
"hostCalibration includes target-dir posture",
)
}
#[test]
fn render_doctor_json_exposes_mesh_auto_enrollment_checks() -> TestResult {
let report = DoctorReport::gather();
let json = render_doctor_json_filtered(&report, FieldProfile::Standard);
let value = serde_json::from_str::<serde_json::Value>(&json)
.map_err(|error| format!("doctor JSON should parse: {error}"))?;
let mesh = value
.pointer("/data/meshAutoEnrollment")
.ok_or_else(|| "doctor JSON has data.meshAutoEnrollment object".to_string())?;
ensure_equal(
&mesh["schema"],
&serde_json::json!("ee.doctor.mesh_auto_enrollment.v1"),
"mesh auto-enrollment schema",
)?;
ensure_equal(
&mesh["actionGraph"]["schema"],
&serde_json::json!("ee.repair_action_graph.v1"),
"mesh auto-enrollment action graph schema",
)?;
ensure_equal(
&mesh["checks"].as_array().map(Vec::len),
&Some(15),
"mesh auto-enrollment check count",
)
}
#[test]
fn json_toon_parity_agent_docs_decodes_to_same_json() -> TestResult {
let report = AgentDocsReport::gather(None);
let json = render_agent_docs_json(&report);
let toon = render_agent_docs_toon(&report);
let expected_json = serde_json::from_str::<serde_json::Value>(&json)
.map_err(|error| format!("agent-docs JSON should parse: {error}"))?;
let expected = serde_json::Value::from(toon::JsonValue::from(expected_json));
let decoded = toon::try_decode(&toon, None)
.map_err(|error| format!("agent-docs TOON should decode: {error}"))?;
let actual = serde_json::Value::from(decoded);
ensure_equal(&actual, &expected, "decoded TOON matches agent-docs JSON")
}
#[test]
fn json_toon_parity_context_decodes_to_same_json() -> TestResult {
let response = context_response_fixture()?;
let json = render_context_response_json(&response);
let toon = render_context_response_toon(&response);
ensure_toon_matches_json(&json, &toon, "decoded TOON matches context JSON")
}
#[test]
fn handoff_toon_renderers_decode_to_json_contracts() -> TestResult {
let mut preview = HandoffPreviewReport::new(
PathBuf::from("/tmp/ee-handoff-workspace"),
CapsuleProfile::Resume,
);
preview.generated_at = "2026-05-04T12:00:00Z".to_string();
preview.token_estimate = 42;
preview.byte_estimate = 420;
preview.sufficient_for_resume = true;
preview.task_frame = Some(serde_json::json!({
"schema": "ee.task_frame.v1",
"redactionStatus": "redacted",
}));
preview.swarm_brief_summary = Some(serde_json::json!({
"schema": "ee.support_bundle.swarm_brief_summary.v1",
}));
preview.swarm_incident_summary = Some(serde_json::json!({
"schema": "ee.support_bundle.swarm_incident_summary.v1",
}));
preview.swarm_replay_summary = Some(serde_json::json!({
"schema": "ee.support_bundle.swarm_replay_summary.v1",
}));
preview.pack_replay_summary = Some(serde_json::json!({
"schema": "ee.support_bundle.pack_replay_summary.v2",
}));
preview.environment_attestation_summary = Some(serde_json::json!({
"schema": "ee.support_bundle.environment_attestation_summary.v1",
}));
preview.regression_causality_summary = Some(serde_json::json!({
"schema": "ee.support_bundle.regression_causality_summary.v1",
}));
let mut create = HandoffCreateReport::new(
"hcap_toon_fixture".to_string(),
PathBuf::from("/tmp/ee-handoff-workspace"),
PathBuf::from("/tmp/ee-handoff-workspace/handoff.json"),
);
create.created_at = "2026-05-04T12:01:00Z".to_string();
create.sections_included = 2;
create.evidence_count = 1;
create.token_count = 99;
create.byte_count = 999;
create.content_hash = "blake3:fixture".to_string();
create.canonical_content_hash = "abc123def4567890".to_string();
create.task_frame = Some(serde_json::json!({
"schema": "ee.task_frame.v1",
"redactionStatus": "redacted",
}));
create.swarm_brief_summary = Some(serde_json::json!({
"schema": "ee.support_bundle.swarm_brief_summary.v1",
}));
create.swarm_incident_summary = Some(serde_json::json!({
"schema": "ee.support_bundle.swarm_incident_summary.v1",
}));
create.swarm_replay_summary = Some(serde_json::json!({
"schema": "ee.support_bundle.swarm_replay_summary.v1",
}));
create.pack_replay_summary = Some(serde_json::json!({
"schema": "ee.support_bundle.pack_replay_summary.v2",
}));
create.environment_attestation_summary = Some(serde_json::json!({
"schema": "ee.support_bundle.environment_attestation_summary.v1",
}));
create.regression_causality_summary = Some(serde_json::json!({
"schema": "ee.support_bundle.regression_causality_summary.v1",
}));
create.dry_run = true;
let preview_json =
serde_json::from_str::<serde_json::Value>(&render_handoff_preview_json(&preview))
.map_err(|error| format!("handoff preview JSON should parse: {error}"))?;
ensure_equal(
&preview_json
.pointer("/task_frame/schema")
.and_then(serde_json::Value::as_str),
&Some("ee.task_frame.v1"),
"handoff preview JSON includes task frame",
)?;
ensure_equal(
&preview_json
.pointer("/swarm_incident_summary/schema")
.and_then(serde_json::Value::as_str),
&Some("ee.support_bundle.swarm_incident_summary.v1"),
"handoff preview JSON includes swarm incident summary",
)?;
ensure_equal(
&preview_json
.pointer("/swarm_replay_summary/schema")
.and_then(serde_json::Value::as_str),
&Some("ee.support_bundle.swarm_replay_summary.v1"),
"handoff preview JSON includes swarm replay summary",
)?;
ensure_equal(
&preview_json
.pointer("/pack_replay_summary/schema")
.and_then(serde_json::Value::as_str),
&Some("ee.support_bundle.pack_replay_summary.v2"),
"handoff preview JSON includes pack replay summary",
)?;
ensure_equal(
&preview_json
.pointer("/environment_attestation_summary/schema")
.and_then(serde_json::Value::as_str),
&Some("ee.support_bundle.environment_attestation_summary.v1"),
"handoff preview JSON includes environment attestation summary",
)?;
ensure_equal(
&preview_json
.pointer("/regression_causality_summary/schema")
.and_then(serde_json::Value::as_str),
&Some("ee.support_bundle.regression_causality_summary.v1"),
"handoff preview JSON includes regression causality summary",
)?;
let create_json =
serde_json::from_str::<serde_json::Value>(&render_handoff_create_json(&create))
.map_err(|error| format!("handoff create JSON should parse: {error}"))?;
ensure_equal(
&create_json
.pointer("/task_frame/schema")
.and_then(serde_json::Value::as_str),
&Some("ee.task_frame.v1"),
"handoff create JSON includes task frame",
)?;
ensure_equal(
&create_json
.pointer("/swarm_incident_summary/schema")
.and_then(serde_json::Value::as_str),
&Some("ee.support_bundle.swarm_incident_summary.v1"),
"handoff create JSON includes swarm incident summary",
)?;
ensure_equal(
&create_json
.pointer("/swarm_replay_summary/schema")
.and_then(serde_json::Value::as_str),
&Some("ee.support_bundle.swarm_replay_summary.v1"),
"handoff create JSON includes swarm replay summary",
)?;
ensure_equal(
&create_json
.pointer("/pack_replay_summary/schema")
.and_then(serde_json::Value::as_str),
&Some("ee.support_bundle.pack_replay_summary.v2"),
"handoff create JSON includes pack replay summary",
)?;
ensure_equal(
&create_json
.pointer("/environment_attestation_summary/schema")
.and_then(serde_json::Value::as_str),
&Some("ee.support_bundle.environment_attestation_summary.v1"),
"handoff create JSON includes environment attestation summary",
)?;
ensure_equal(
&create_json
.pointer("/regression_causality_summary/schema")
.and_then(serde_json::Value::as_str),
&Some("ee.support_bundle.regression_causality_summary.v1"),
"handoff create JSON includes regression causality summary",
)?;
ensure_equal(
&create_json
.pointer("/canonical_content_hash")
.and_then(serde_json::Value::as_str),
&Some("abc123def4567890"),
"handoff create JSON includes canonical content hash",
)?;
let mut inspect =
HandoffInspectReport::new(PathBuf::from("/tmp/ee-handoff-workspace/handoff.json"));
inspect.inspected_at = "2026-05-04T12:02:00Z".to_string();
inspect.capsule_id = "hcap_toon_fixture".to_string();
inspect.section_count = 2;
inspect.evidence_count = 1;
let mut resume = HandoffResumeReport::new(
"hcap_toon_fixture".to_string(),
PathBuf::from("/tmp/ee-handoff-workspace/handoff.json"),
);
resume.resumed_at = "2026-05-04T12:03:00Z".to_string();
resume.workspace = Some("workspace_toon_fixture".to_string());
resume.swarm_incident_summary = Some(serde_json::json!({
"schema": "ee.support_bundle.swarm_incident_summary.v1",
}));
resume.swarm_replay_summary = Some(serde_json::json!({
"schema": "ee.support_bundle.swarm_replay_summary.v1",
}));
resume.pack_replay_summary = Some(serde_json::json!({
"schema": "ee.support_bundle.pack_replay_summary.v2",
}));
resume.environment_attestation_summary = Some(serde_json::json!({
"schema": "ee.support_bundle.environment_attestation_summary.v1",
}));
resume.regression_causality_summary = Some(serde_json::json!({
"schema": "ee.support_bundle.regression_causality_summary.v1",
}));
let resume_json =
serde_json::from_str::<serde_json::Value>(&render_handoff_resume_json(&resume))
.map_err(|error| format!("handoff resume JSON should parse: {error}"))?;
ensure_equal(
&resume_json
.pointer("/swarm_incident_summary/schema")
.and_then(serde_json::Value::as_str),
&Some("ee.support_bundle.swarm_incident_summary.v1"),
"handoff resume JSON includes swarm incident summary",
)?;
ensure_equal(
&resume_json
.pointer("/swarm_replay_summary/schema")
.and_then(serde_json::Value::as_str),
&Some("ee.support_bundle.swarm_replay_summary.v1"),
"handoff resume JSON includes swarm replay summary",
)?;
ensure_equal(
&resume_json
.pointer("/pack_replay_summary/schema")
.and_then(serde_json::Value::as_str),
&Some("ee.support_bundle.pack_replay_summary.v2"),
"handoff resume JSON includes pack replay summary",
)?;
ensure_equal(
&resume_json
.pointer("/environment_attestation_summary/schema")
.and_then(serde_json::Value::as_str),
&Some("ee.support_bundle.environment_attestation_summary.v1"),
"handoff resume JSON includes environment attestation summary",
)?;
ensure_equal(
&resume_json
.pointer("/regression_causality_summary/schema")
.and_then(serde_json::Value::as_str),
&Some("ee.support_bundle.regression_causality_summary.v1"),
"handoff resume JSON includes regression causality summary",
)?;
let pairs = [
(
render_handoff_preview_json(&preview),
render_handoff_preview_toon(&preview),
"handoff preview",
),
(
render_handoff_create_json(&create),
render_handoff_create_toon(&create),
"handoff create",
),
(
render_handoff_inspect_json(&inspect),
render_handoff_inspect_toon(&inspect),
"handoff inspect",
),
(
render_handoff_resume_json(&resume),
render_handoff_resume_toon(&resume),
"handoff resume",
),
];
for (json, toon, context) in pairs {
ensure_toon_matches_json(&json, &toon, context)?;
ensure(
!toon.starts_with("HANDOFF_") && !toon.contains('|'),
format!("{context}: TOON must not use legacy pipe summary: {toon:?}"),
)?;
}
Ok(())
}
#[test]
fn invalid_json_to_toon_returns_stable_error() -> TestResult {
let toon = super::render_toon_from_json("{not valid json");
ensure_contains(&toon, "schema: ee.error.v2", "error schema")?;
ensure_contains(&toon, "code: toon_encoding_failed", "error code")?;
ensure_contains(&toon, "severity: medium", "error severity")?;
ensure_contains(&toon, "details:", "error details")
}
#[test]
fn unknown_schema_export_error_has_required_fields() -> TestResult {
let json = render_schema_export_json(Some("ee.missing.v1"));
ensure_starts_with(&json, "{\"schema\":\"ee.error.v2\"", "schema")?;
ensure_contains(&json, "\"code\":\"schema_not_found\"", "code")?;
ensure_contains(&json, "\"severity\":\"low\"", "severity")?;
ensure_contains(&json, "\"details\":{", "details")?;
ensure_contains(&json, "\"schemaId\":\"ee.missing.v1\"", "schema id")
}
#[test]
fn public_schema_registry_exports_every_listed_schema_once() -> TestResult {
fn exported_schema_id(schema: &serde_json::Value) -> Option<String> {
if let Some(title) = schema.get("title").and_then(serde_json::Value::as_str) {
return Some(title.to_string());
}
if let Some(schema_id) = schema.get("schema").and_then(serde_json::Value::as_str) {
return Some(schema_id.to_string());
}
let uri = schema.get("$id").and_then(serde_json::Value::as_str)?;
let file_name = uri.rsplit('/').next().unwrap_or(uri);
Some(
file_name
.strip_suffix(".json")
.unwrap_or(file_name)
.to_string(),
)
}
let list_json = super::render_schema_list_json();
let list: serde_json::Value =
serde_json::from_str(&list_json).map_err(|error| error.to_string())?;
let listed_ids = list["data"]["schemas"]
.as_array()
.ok_or("schema list data.schemas must be an array")?
.iter()
.map(|schema| {
schema["id"]
.as_str()
.map(str::to_owned)
.ok_or_else(|| "schema list entry missing string id".to_owned())
})
.collect::<Result<Vec<_>, _>>()?;
let mut unique_ids = listed_ids.clone();
unique_ids.sort();
unique_ids.dedup();
ensure_equal(
&unique_ids.len(),
&listed_ids.len(),
"schema list ids must be unique",
)?;
ensure_equal(
&listed_ids.len(),
&super::public_schemas().len(),
"schema list count must match public_schemas",
)?;
for schema_id in &listed_ids {
let export_json = render_schema_export_json(Some(schema_id));
let exported: serde_json::Value =
serde_json::from_str(&export_json).map_err(|error| error.to_string())?;
ensure(
exported.get("error").is_none(),
format!("listed schema {schema_id} must not export an error"),
)?;
ensure_equal(
&exported_schema_id(&exported),
&Some(schema_id.clone()),
"single schema export id",
)?;
}
let bulk_json = render_schema_export_json(None);
let bulk: serde_json::Value =
serde_json::from_str(&bulk_json).map_err(|error| error.to_string())?;
let bulk_ids = bulk["data"]["schemas"]
.as_array()
.ok_or("bulk schema export data.schemas must be an array")?
.iter()
.map(|schema| {
exported_schema_id(schema)
.ok_or_else(|| "bulk schema export entry missing $id/schema".to_owned())
})
.collect::<Result<Vec<_>, _>>()?;
ensure_equal(
&bulk_ids,
&listed_ids,
"bulk schema export must match schema list order exactly once",
)
}
#[test]
fn public_schema_registry_covers_sampled_emitted_payload_schemas() -> TestResult {
let emitted_schema_ids = [
crate::steward::MAINTENANCE_RUN_SCHEMA_V1,
crate::steward::MAINTENANCE_STATUS_SCHEMA_V1,
crate::steward::MAINTENANCE_JOB_LIST_SCHEMA_V1,
crate::steward::MAINTENANCE_JOB_SHOW_SCHEMA_V1,
crate::steward::MAINTENANCE_JOB_ROW_SCHEMA_V1,
crate::core::recorder::RECORDER_EVENTS_LIST_SCHEMA_V1,
];
for schema_id in emitted_schema_ids {
ensure(
super::public_schemas()
.iter()
.any(|entry| entry.id == schema_id),
format!("public schema registry missing emitted schema {schema_id}"),
)?;
let export_json = render_schema_export_json(Some(schema_id));
let exported: serde_json::Value =
serde_json::from_str(&export_json).map_err(|error| error.to_string())?;
ensure(
exported.get("error").is_none(),
format!("emitted schema {schema_id} must export without schema_not_found"),
)?;
ensure_equal(
&exported.get("$id").and_then(serde_json::Value::as_str),
&Some(schema_id),
"exported emitted schema id",
)?;
}
Ok(())
}
#[test]
fn docs_bootstrap_is_registered_for_agents() -> TestResult {
let command = super::COMMAND_MANIFEST
.iter()
.find(|entry| entry.name == "bootstrap")
.ok_or_else(|| "bootstrap command missing from command manifest".to_string())?;
let subcommands = command
.subcommands
.iter()
.map(|entry| entry.name)
.collect::<Vec<_>>();
ensure_equal(
&subcommands,
&vec!["docs", "apply"],
"bootstrap subcommands",
)?;
let schema_ids = super::public_schemas()
.iter()
.map(|entry| entry.id)
.collect::<Vec<_>>();
for expected in [
crate::core::docs_bootstrap::DOCS_BOOTSTRAP_RUN_SCHEMA_V1,
crate::core::docs_bootstrap::DOCS_BOOTSTRAP_APPLY_SCHEMA_V1,
] {
ensure(
schema_ids.contains(&expected),
format!("docs bootstrap schema {expected} missing from public registry"),
)?;
}
Ok(())
}
#[test]
fn resume_is_registered_for_agents() -> TestResult {
let command = super::COMMAND_MANIFEST
.iter()
.find(|entry| entry.name == "resume")
.ok_or_else(|| "resume command missing from command manifest".to_string())?;
ensure(command.available, "resume command must be available")?;
ensure_equal(
&command
.args
.iter()
.map(|entry| entry.name)
.collect::<Vec<_>>(),
&vec!["--sessions", "--database"],
"resume command arguments",
)
}
#[test]
fn exported_payload_schemas_match_known_emitted_fields() -> TestResult {
fn exported_schema(schema_id: &str) -> Result<serde_json::Value, String> {
let export_json = render_schema_export_json(Some(schema_id));
serde_json::from_str(&export_json).map_err(|error| error.to_string())
}
fn ensure_required_fields_exist_in_payload(
schema_id: &str,
payload: &serde_json::Value,
) -> TestResult {
let schema = exported_schema(schema_id)?;
let required = schema["required"]
.as_array()
.ok_or_else(|| format!("{schema_id} export missing required array"))?;
let payload_object = payload
.as_object()
.ok_or_else(|| format!("{schema_id} sample payload must be an object"))?;
for field in required {
let field = field
.as_str()
.ok_or_else(|| format!("{schema_id} required entry must be a string"))?;
ensure(
payload_object.contains_key(field),
format!("{schema_id} requires {field}, but emitted sample lacks it"),
)?;
}
Ok(())
}
let recorder_report = crate::core::recorder::RecorderEventsListReport {
schema: crate::core::recorder::RECORDER_EVENTS_LIST_SCHEMA_V1,
events: Vec::new(),
filters: crate::core::recorder::RecorderEventsListOptions {
since: None,
source: None,
run_id: None,
limit: 100,
},
}
.data_json();
let recorder_schema =
exported_schema(crate::core::recorder::RECORDER_EVENTS_LIST_SCHEMA_V1)?;
let recorder_properties = recorder_schema["properties"]
.as_object()
.ok_or("recorder events list export missing properties object")?;
for key in recorder_report
.as_object()
.ok_or("recorder events list report must be an object")?
.keys()
{
ensure(
recorder_properties.contains_key(key),
format!("recorder events list export missing emitted field {key}"),
)?;
}
ensure(
!recorder_properties.contains_key("eventCount"),
"recorder events list export must not advertise obsolete eventCount field",
)?;
ensure_required_fields_exist_in_payload(
crate::core::recorder::RECORDER_EVENTS_LIST_SCHEMA_V1,
&recorder_report,
)?;
let job_list_error = serde_json::json!({
"schema": crate::steward::MAINTENANCE_JOB_LIST_SCHEMA_V1,
"command": "job list",
"code": "maintenance_job_since_invalid",
"message": "Invalid --since timestamp",
"repair": "Pass --since as an RFC 3339 timestamp.",
"jobs": [],
});
ensure_required_fields_exist_in_payload(
crate::steward::MAINTENANCE_JOB_LIST_SCHEMA_V1,
&job_list_error,
)?;
let job_show_error = serde_json::json!({
"schema": crate::steward::MAINTENANCE_JOB_SHOW_SCHEMA_V1,
"command": "job show",
"code": "maintenance_job_history_read_failed",
"message": "Could not read history",
"repair": "Check workspace .ee directory permissions.",
});
ensure_required_fields_exist_in_payload(
crate::steward::MAINTENANCE_JOB_SHOW_SCHEMA_V1,
&job_show_error,
)
}
#[test]
fn toon_status_has_required_structure() -> TestResult {
let report = StatusReport::gather();
let actual = render_status_toon(&report);
// Verify required TOON structure is present (not exact content, since
// gather() now inspects actual workspace state which varies).
ensure_contains(&actual, "schema: ee.response.v2", "schema")?;
ensure_contains(&actual, "success: true", "success flag")?;
ensure_contains(&actual, "data:", "data section")?;
ensure_contains(&actual, "command: status", "command field")?;
ensure_contains(&actual, "capabilities:", "capabilities section")?;
ensure_contains(&actual, "runtime:", "runtime section")?;
ensure_contains(&actual, "derivedAssets[", "derived assets array")
}
#[test]
fn golden_error_fixtures_are_valid_json() -> TestResult {
let fixtures = [
include_str!("../../tests/fixtures/golden/error/usage.golden"),
include_str!("../../tests/fixtures/golden/error/configuration.golden"),
include_str!("../../tests/fixtures/golden/error/storage.golden"),
include_str!("../../tests/fixtures/golden/error/search_index.golden"),
include_str!("../../tests/fixtures/golden/error/import.golden"),
include_str!("../../tests/fixtures/golden/error/policy_denied.golden"),
include_str!("../../tests/fixtures/golden/error/migration_required.golden"),
include_str!("../../tests/fixtures/golden/error/unsatisfied_degraded_mode.golden"),
include_str!("../../tests/fixtures/golden/error/no_repair.golden"),
];
for (i, fixture) in fixtures.iter().enumerate() {
let value: serde_json::Value = serde_json::from_str(fixture)
.map_err(|e| format!("error fixture {} is not valid JSON: {e}", i))?;
if value.get("schema") != Some(&serde_json::Value::String("ee.error.v2".to_string())) {
return Err(format!("error fixture {} missing schema", i));
}
}
Ok(())
}
#[test]
fn golden_status_fixtures_are_valid_json() -> TestResult {
let fixtures = [
include_str!("../../tests/fixtures/golden/status/status_healthy.golden"),
include_str!("../../tests/fixtures/golden/status/status_degraded.golden"),
];
for (i, fixture) in fixtures.iter().enumerate() {
let value: serde_json::Value = serde_json::from_str(fixture)
.map_err(|e| format!("status fixture {} is not valid JSON: {e}", i))?;
if value.get("schema") != Some(&serde_json::Value::String("ee.response.v2".to_string()))
{
return Err(format!("status fixture {} missing schema", i));
}
}
Ok(())
}
#[test]
fn golden_version_fixture_is_valid_json() -> TestResult {
let fixture = include_str!("../../tests/fixtures/golden/version/version.golden");
let value: serde_json::Value = serde_json::from_str(fixture)
.map_err(|e| format!("version fixture is not valid JSON: {e}"))?;
if value.get("schema") != Some(&serde_json::Value::String("ee.response.v2".to_string())) {
return Err("version fixture missing schema".to_string());
}
Ok(())
}
#[test]
fn golden_human_fixtures_have_expected_structure() -> TestResult {
let error_fixture =
include_str!("../../tests/fixtures/golden/human/error_with_repair.golden");
ensure_starts_with(error_fixture, "error:", "human error starts with 'error:'")?;
ensure_contains(error_fixture, "Next:", "human error has Next section")?;
let success_fixture =
include_str!("../../tests/fixtures/golden/human/success_with_summary.golden");
ensure_contains(success_fixture, "Next:", "human success has Next section")?;
ensure(
!success_fixture.starts_with('{'),
"human output is not JSON",
)
}
// ========================================================================
// Field Profile Tests (EE-037)
//
// These tests verify the --fields filtering behavior for JSON output.
// Each profile level progressively includes more fields.
// ========================================================================
#[test]
fn field_profile_as_str_is_stable() -> TestResult {
use super::FieldProfile;
ensure_equal(&FieldProfile::Minimal.as_str(), &"minimal", "minimal")?;
ensure_equal(&FieldProfile::Summary.as_str(), &"summary", "summary")?;
ensure_equal(&FieldProfile::Standard.as_str(), &"standard", "standard")?;
ensure_equal(&FieldProfile::Full.as_str(), &"full", "full")
}
#[test]
fn field_profile_inclusion_rules() -> TestResult {
use super::FieldProfile;
// Minimal: no arrays, no summary metrics, no verbose
ensure(!FieldProfile::Minimal.include_arrays(), "minimal no arrays")?;
ensure(
!FieldProfile::Minimal.include_summary_metrics(),
"minimal no summary",
)?;
ensure(
!FieldProfile::Minimal.include_verbose_details(),
"minimal no verbose",
)?;
// Summary: no arrays, has summary metrics, no verbose
ensure(!FieldProfile::Summary.include_arrays(), "summary no arrays")?;
ensure(
FieldProfile::Summary.include_summary_metrics(),
"summary has summary",
)?;
ensure(
!FieldProfile::Summary.include_verbose_details(),
"summary no verbose",
)?;
// Standard: has arrays, has summary metrics, no verbose
ensure(
FieldProfile::Standard.include_arrays(),
"standard has arrays",
)?;
ensure(
FieldProfile::Standard.include_summary_metrics(),
"standard has summary",
)?;
ensure(
!FieldProfile::Standard.include_verbose_details(),
"standard no verbose",
)?;
// Full: has everything
ensure(FieldProfile::Full.include_arrays(), "full has arrays")?;
ensure(
FieldProfile::Full.include_summary_metrics(),
"full has summary",
)?;
ensure(
FieldProfile::Full.include_verbose_details(),
"full has verbose",
)
}
#[test]
fn search_standard_field_preset_retains_structured_index_freshness() -> TestResult {
let fields = super::preset_fields_for_command("search", FieldProfile::Standard);
ensure(
fields.contains(&"indexFreshness"),
"search standard preset must retain per-response index freshness truth",
)
}
#[test]
fn render_status_json_filtered_minimal_has_only_essentials() -> TestResult {
use super::{FieldProfile, render_status_json_filtered};
let report = StatusReport::gather();
let json = render_status_json_filtered(&report, FieldProfile::Minimal);
ensure_contains(&json, "\"schema\":\"ee.response.v2\"", "schema")?;
ensure_contains(&json, "\"success\":true", "success")?;
ensure_contains(&json, "\"fields\":\"minimal\"", "fields indicator")?;
ensure_contains(&json, "\"command\":\"status\"", "command")?;
ensure_contains(&json, "\"version\":", "version")?;
// Minimal omits optional data fields but keeps the response envelope.
ensure(!json.contains("\"capabilities\":"), "no capabilities")?;
ensure(!json.contains("\"runtime\":"), "no runtime")?;
let value = parse_rendered_json(&json, "minimal status")?;
ensure(
value
.get("degraded")
.and_then(serde_json::Value::as_array)
.is_some(),
"minimal status keeps top-level degraded array",
)?;
ensure(
value.pointer("/data/degraded").is_none(),
"minimal status omits data degraded array",
)
}
#[test]
fn render_status_json_filtered_summary_adds_capabilities() -> TestResult {
use super::{FieldProfile, render_status_json_filtered};
let report = StatusReport::gather();
let json = render_status_json_filtered(&report, FieldProfile::Summary);
ensure_contains(&json, "\"fields\":\"summary\"", "fields indicator")?;
ensure_contains(&json, "\"capabilities\":", "has capabilities")?;
ensure_contains(&json, "\"mesh\":\"pending\"", "mesh capability default")?;
// Summary should NOT have runtime or degraded arrays
let value = serde_json::from_str::<serde_json::Value>(&json)
.map_err(|error| format!("status summary JSON parses: {error}"))?;
let data = value
.get("data")
.and_then(serde_json::Value::as_object)
.ok_or_else(|| "status summary has data object".to_string())?;
ensure(
data.contains_key("singleFlight"),
"has singleFlight posture",
)?;
ensure(
data.contains_key("rchWorkerPressure"),
"has RCH worker pressure posture",
)?;
ensure(
data.contains_key("hostCalibration"),
"has host calibration posture",
)?;
ensure(!data.contains_key("runtime"), "no runtime object")?;
ensure(!data.contains_key("degraded"), "no data degraded array")?;
ensure(
value
.get("degraded")
.and_then(serde_json::Value::as_array)
.is_some(),
"summary status keeps top-level degraded array",
)
}
#[test]
fn render_status_json_filtered_standard_adds_arrays() -> TestResult {
use super::{FieldProfile, render_status_json_filtered};
let report = StatusReport::gather();
let json = render_status_json_filtered(&report, FieldProfile::Standard);
ensure_contains(&json, "\"fields\":\"standard\"", "fields indicator")?;
ensure_contains(&json, "\"capabilities\":", "has capabilities")?;
ensure_contains(&json, "\"mesh\":\"pending\"", "mesh capability default")?;
ensure_contains(&json, "\"runtime\":", "has runtime")?;
ensure_contains(&json, "\"packBudgetBuckets\":", "has pack budget buckets")?;
ensure_contains(&json, "\"singleFlight\":", "has singleFlight")?;
ensure_contains(&json, "\"rchWorkerPressure\":", "has RCH worker pressure")?;
ensure_contains(&json, "\"hostCalibration\":", "has host calibration")?;
ensure_contains(
&json,
"\"schema\":\"ee.singleflight.posture.v1\"",
"has singleFlight schema",
)?;
ensure_contains(&json, "\"degraded\":", "has degraded")?;
// Standard degraded entries keep repair guidance because agents rely on
// the default JSON profile for recovery planning.
ensure_contains(&json, "\"repair\":", "has repair in degraded")?;
let value = parse_rendered_json(&json, "standard status")?;
ensure_top_level_degraded_mirrors_data_degraded(&value, "standard status")
}
#[test]
fn render_health_json_filtered_standard_keeps_issue_messages() -> TestResult {
use super::{FieldProfile, render_health_json_filtered};
let report = HealthReport::gather();
let json = render_health_json_filtered(&report, FieldProfile::Standard);
ensure_contains(&json, "\"fields\":\"standard\"", "fields indicator")?;
ensure_contains(&json, "\"issues\":", "has issues")?;
ensure_contains(&json, "\"message\":", "has issue message")
}
#[test]
fn render_status_json_filtered_full_includes_verbose() -> TestResult {
use super::{FieldProfile, render_status_json_filtered};
let report = StatusReport::gather();
let json = render_status_json_filtered(&report, FieldProfile::Full);
ensure_contains(&json, "\"fields\":\"full\"", "fields indicator")?;
ensure_contains(&json, "\"capabilities\":", "has capabilities")?;
ensure_contains(&json, "\"mesh\":\"pending\"", "mesh capability default")?;
ensure_contains(&json, "\"runtime\":", "has runtime")?;
ensure_contains(&json, "\"degraded\":", "has degraded")?;
ensure_contains(&json, "\"repair\":", "has repair in degraded")?;
let value = parse_rendered_json(&json, "full status")?;
ensure_top_level_degraded_mirrors_data_degraded(&value, "full status")
}
#[test]
fn render_capabilities_json_filtered_minimal_only_essentials() -> TestResult {
use super::{FieldProfile, render_capabilities_json_filtered};
let report = capabilities_report_fixture();
let json = render_capabilities_json_filtered(&report, FieldProfile::Minimal);
ensure_contains(&json, "\"command\":\"capabilities\"", "command")?;
ensure_contains(&json, "\"version\":", "version")?;
ensure_contains(&json, "\"fields\":\"minimal\"", "fields")?;
// Minimal: no arrays, no summary
ensure(!json.contains("\"subsystems\":"), "no subsystems")?;
ensure(!json.contains("\"features\":"), "no features")?;
ensure(!json.contains("\"commands\":"), "no commands")?;
ensure(!json.contains("\"summary\":"), "no summary")
}
#[test]
fn render_capabilities_json_filtered_full_has_descriptions() -> TestResult {
use super::{FieldProfile, render_capabilities_json_filtered};
let report = capabilities_report_fixture();
let json = render_capabilities_json_filtered(&report, FieldProfile::Full);
ensure_contains(&json, "\"subsystems\":", "has subsystems")?;
ensure_contains(&json, "\"unimplemented\":", "has build-time gaps")?;
ensure_contains(&json, "\"index\":", "has index metadata")?;
ensure_contains(
&json,
"\"last_full_rebuild_at\":",
"has last full rebuild timestamp",
)?;
ensure_contains(&json, "\"description\":", "has descriptions")?;
ensure_contains(&json, "\"summary\":", "has summary")
}
// ========================================================================
// Evaluation Report Renderer Tests (EE-255)
// ========================================================================
#[test]
fn render_eval_report_json_empty_report() -> TestResult {
use super::render_eval_report_json;
use crate::eval::EvaluationReport;
let report = EvaluationReport::new();
let json = render_eval_report_json(&report, None);
ensure_contains(&json, "\"schema\":\"ee.response.v2\"", "schema")?;
ensure_contains(&json, "\"success\":true", "success")?;
ensure_contains(&json, "\"command\":\"eval run\"", "command")?;
ensure_contains(&json, "\"status\":\"no_scenarios\"", "status")?;
ensure_contains(&json, "\"scenariosRun\":0", "scenariosRun")?;
ensure_contains(&json, "\"results\":[]", "empty results")
}
#[test]
fn render_eval_report_json_with_scenario_id() -> TestResult {
use super::render_eval_report_json;
use crate::eval::EvaluationReport;
let report = EvaluationReport::new();
let json = render_eval_report_json(&report, Some("test_scenario"));
ensure_contains(&json, "\"scenarioId\":\"test_scenario\"", "scenarioId")
}
#[test]
fn render_eval_run_json_uses_supplied_report() -> TestResult {
use super::render_eval_run_json;
use crate::eval::{EvaluationReport, ScenarioValidationResult};
let mut report = EvaluationReport::new().with_fixture_dir("tests/fixtures/eval");
report.add_result(ScenarioValidationResult {
scenario_id: "fx.release_failure.v1".to_owned(),
passed: true,
steps_passed: 4,
steps_total: 4,
failures: Vec::new(),
});
report.finalize();
let json = render_eval_run_json(&report, Some("fx.release_failure.v1"));
ensure_contains(&json, "\"status\":\"all_passed\"", "status")?;
ensure_contains(&json, "\"scenariosRun\":1", "scenario count")?;
ensure_contains(
&json,
"\"scenarioId\":\"fx.release_failure.v1\"",
"scenario id",
)?;
ensure(
!json.contains("\"status\":\"no_scenarios\""),
"wrapper must not fabricate an empty report",
)
}
#[test]
fn render_eval_run_human_uses_supplied_report() -> TestResult {
use super::render_eval_run_human;
use crate::eval::{EvaluationReport, ScenarioValidationResult};
let mut report = EvaluationReport::new();
report.add_result(ScenarioValidationResult {
scenario_id: "fx.async_migration.v1".to_owned(),
passed: true,
steps_passed: 2,
steps_total: 2,
failures: Vec::new(),
});
report.finalize();
let human = render_eval_run_human(&report, None);
ensure_contains(&human, "Status: all passed", "status")?;
ensure_contains(&human, "Results: 1 run, 1 passed, 0 failed", "results")?;
ensure_contains(
&human,
"[PASS] fx.async_migration.v1: 2/2 steps",
"scenario result",
)?;
ensure(
!human.contains("No evaluation scenarios configured"),
"wrapper must not render an empty-report message",
)
}
#[test]
fn render_eval_run_json_with_science_includes_metrics() -> TestResult {
use super::render_eval_report_json;
use crate::eval::{EVAL_SCIENCE_METRICS_SCHEMA_V1, EvaluationReport};
use crate::science::status;
let mut report = EvaluationReport::new();
report.attach_science_metrics();
let json = render_eval_report_json(&report, None);
ensure_contains(&json, "\"scienceMetrics\":", "science metrics block")?;
ensure_contains(
&json,
&format!("\"schema\":\"{EVAL_SCIENCE_METRICS_SCHEMA_V1}\""),
"science schema",
)?;
ensure_contains(
&json,
&format!("\"status\":\"{}\"", status().as_str()),
"science status",
)
}
#[test]
fn render_eval_run_human_with_science_includes_metrics_section() -> TestResult {
use super::render_eval_report_human;
use crate::eval::EvaluationReport;
let mut report = EvaluationReport::new();
report.attach_science_metrics();
let human = render_eval_report_human(&report, None);
ensure_contains(&human, "Science metrics:", "science header")?;
ensure_contains(&human, "Scenarios evaluated:", "scenario count")
}
#[test]
fn render_eval_report_json_all_passed() -> TestResult {
use super::render_eval_report_json;
use crate::eval::{EvaluationReport, EvaluationStatus, ScenarioValidationResult};
let mut report = EvaluationReport::new();
report.add_result(ScenarioValidationResult {
scenario_id: "scenario_1".to_string(),
passed: true,
steps_passed: 3,
steps_total: 3,
failures: vec![],
});
report.add_result(ScenarioValidationResult {
scenario_id: "scenario_2".to_string(),
passed: true,
steps_passed: 2,
steps_total: 2,
failures: vec![],
});
report.finalize();
ensure_equal(&report.status, &EvaluationStatus::AllPassed, "status")?;
let json = render_eval_report_json(&report, None);
ensure_contains(&json, "\"success\":true", "success")?;
ensure_contains(&json, "\"status\":\"all_passed\"", "status")?;
ensure_contains(&json, "\"scenariosRun\":2", "scenariosRun")?;
ensure_contains(&json, "\"scenariosPassed\":2", "scenariosPassed")?;
ensure_contains(&json, "\"scenariosFailed\":0", "scenariosFailed")?;
ensure_contains(&json, "\"scenarioId\":\"scenario_1\"", "result 1")?;
ensure_contains(&json, "\"scenarioId\":\"scenario_2\"", "result 2")
}
#[test]
fn render_eval_report_json_some_failed() -> TestResult {
use super::render_eval_report_json;
use crate::eval::{
EvaluationReport, EvaluationStatus, ScenarioValidationResult, ValidationFailure,
ValidationFailureKind,
};
let mut report = EvaluationReport::new();
report.add_result(ScenarioValidationResult {
scenario_id: "passing".to_string(),
passed: true,
steps_passed: 2,
steps_total: 2,
failures: vec![],
});
report.add_result(ScenarioValidationResult {
scenario_id: "failing".to_string(),
passed: false,
steps_passed: 1,
steps_total: 2,
failures: vec![ValidationFailure {
step: 2,
kind: ValidationFailureKind::GoldenMismatch,
message: "Output differs from golden".to_string(),
}],
});
report.finalize();
ensure_equal(&report.status, &EvaluationStatus::SomeFailed, "status")?;
let json = render_eval_report_json(&report, None);
ensure_contains(&json, "\"success\":false", "not success")?;
ensure_contains(&json, "\"status\":\"some_failed\"", "status")?;
ensure_contains(&json, "\"scenariosPassed\":1", "scenariosPassed")?;
ensure_contains(&json, "\"scenariosFailed\":1", "scenariosFailed")?;
ensure_contains(&json, "\"kind\":\"golden_mismatch\"", "failure kind")?;
ensure_contains(
&json,
"\"message\":\"Output differs from golden\"",
"failure msg",
)
}
#[test]
fn render_eval_report_human_empty_report() -> TestResult {
use super::render_eval_report_human;
use crate::eval::EvaluationReport;
let report = EvaluationReport::new();
let human = render_eval_report_human(&report, None);
ensure_contains(&human, "ee eval run", "header")?;
ensure_contains(&human, "Status: no scenarios available", "status")?;
ensure_contains(&human, "Results: 0 run, 0 passed, 0 failed", "results")?;
ensure_contains(&human, "No evaluation scenarios configured", "message")
}
#[test]
fn render_eval_report_human_with_results() -> TestResult {
use super::render_eval_report_human;
use crate::eval::{
EvaluationReport, ScenarioValidationResult, ValidationFailure, ValidationFailureKind,
};
let mut report = EvaluationReport::new();
report.add_result(ScenarioValidationResult {
scenario_id: "test_scenario".to_string(),
passed: false,
steps_passed: 2,
steps_total: 3,
failures: vec![ValidationFailure {
step: 3,
kind: ValidationFailureKind::ExitCodeMismatch,
message: "Expected 0, got 1".to_string(),
}],
});
report.finalize();
let human = render_eval_report_human(&report, None);
ensure_contains(&human, "[FAIL] test_scenario: 2/3 steps", "scenario result")?;
ensure_contains(&human, "Step 3: exit_code_mismatch", "failure step")?;
ensure_contains(&human, "Expected 0, got 1", "failure message")
}
#[test]
fn render_eval_report_toon_produces_valid_toon() -> TestResult {
use super::render_eval_report_toon;
use crate::eval::{EvaluationReport, ScenarioValidationResult};
let mut report = EvaluationReport::new();
report.add_result(ScenarioValidationResult {
scenario_id: "test".to_string(),
passed: true,
steps_passed: 1,
steps_total: 1,
failures: vec![],
});
report.finalize();
let toon = render_eval_report_toon(&report, None);
ensure_contains(&toon, "ee.response.v2", "schema")?;
ensure_contains(&toon, "all_passed", "status")?;
ensure_contains(&toon, "test", "scenario id")
}
#[test]
fn evaluation_status_strings_are_stable() -> TestResult {
use crate::eval::EvaluationStatus;
ensure_equal(
&EvaluationStatus::NoScenarios.as_str(),
&"no_scenarios",
"no_scenarios",
)?;
ensure_equal(
&EvaluationStatus::AllPassed.as_str(),
&"all_passed",
"all_passed",
)?;
ensure_equal(
&EvaluationStatus::SomeFailed.as_str(),
&"some_failed",
"some_failed",
)?;
ensure_equal(
&EvaluationStatus::AllFailed.as_str(),
&"all_failed",
"all_failed",
)
}
#[test]
fn evaluation_status_is_success() -> TestResult {
use crate::eval::EvaluationStatus;
ensure_equal(
&EvaluationStatus::NoScenarios.is_success(),
&true,
"no_scenarios is success",
)?;
ensure_equal(
&EvaluationStatus::AllPassed.is_success(),
&true,
"all_passed is success",
)?;
ensure_equal(
&EvaluationStatus::SomeFailed.is_success(),
&false,
"some_failed not success",
)?;
ensure_equal(
&EvaluationStatus::AllFailed.is_success(),
&false,
"all_failed not success",
)
}
#[test]
fn render_eval_report_with_elapsed_and_fixture_dir() -> TestResult {
use super::render_eval_report_json;
use crate::eval::EvaluationReport;
let report = EvaluationReport::new()
.with_elapsed_ms(42.5)
.with_fixture_dir("tests/fixtures/eval/");
let json = render_eval_report_json(&report, None);
ensure_contains(&json, "\"elapsedMs\":42.50", "elapsedMs")?;
ensure_contains(
&json,
"\"fixtureDir\":\"tests/fixtures/eval/\"",
"fixtureDir",
)
}
#[test]
fn render_eval_list_json_includes_fixture_entries() -> TestResult {
use super::render_eval_list_json;
use crate::eval::FixtureListEntry;
let entries = vec![FixtureListEntry {
fixture_id: "fx.release_failure.v1".to_owned(),
fixture_family: "release".to_owned(),
journey: "Release failure triage".to_owned(),
memory_count: 3,
query_count: 5,
path: "tests/fixtures/eval/release_failure".to_owned(),
}];
let json = render_eval_list_json(&entries, Some("tests/fixtures/eval"));
let parsed: serde_json::Value =
serde_json::from_str(&json).map_err(|error| error.to_string())?;
ensure_equal(
&parsed["data"]["fixtureCount"],
&serde_json::json!(1),
"fixture count",
)?;
ensure_equal(
&parsed["data"]["fixtures"][0]["fixtureId"],
&serde_json::json!("fx.release_failure.v1"),
"fixture id",
)?;
ensure_equal(
&parsed["data"]["fixtures"][0]["memoryCount"],
&serde_json::json!(3),
"memory count",
)?;
ensure_equal(
&parsed["data"]["fixtureDir"],
&serde_json::json!("tests/fixtures/eval"),
"fixture dir",
)?;
ensure(
parsed["data"]["message"].is_null(),
"non-empty list must not claim no scenarios are configured",
)
}
#[test]
fn render_eval_list_human_lists_fixture_entries() -> TestResult {
use super::render_eval_list_human;
use crate::eval::FixtureListEntry;
let entries = vec![FixtureListEntry {
fixture_id: "fx.async_migration.v1".to_owned(),
fixture_family: "migration".to_owned(),
journey: "Async migration investigation".to_owned(),
memory_count: 2,
query_count: 4,
path: "tests/fixtures/eval/async_migration".to_owned(),
}];
let human = render_eval_list_human(&entries, Some("tests/fixtures/eval"));
ensure_contains(
&human,
"Available evaluation fixtures (1):",
"fixture count",
)?;
ensure_contains(
&human,
"fx.async_migration.v1 (migration)",
"fixture identity",
)?;
ensure_contains(&human, "Memories: 2, Queries: 4", "fixture counts")?;
ensure(
!human.contains("No evaluation scenarios configured"),
"non-empty human list must not claim no scenarios are configured",
)
}
#[test]
fn shadow_run_report_new_has_correct_schema() -> TestResult {
let report = ShadowRunReport::new("exp-policy", "default");
ensure_equal(&report.schema, &SHADOW_RUN_SCHEMA_V1.to_owned(), "schema")
}
#[test]
fn shadow_run_report_add_comparison_updates_summary() -> TestResult {
let mut report = ShadowRunReport::new("exp-policy", "default");
report.add_comparison(ShadowRunComparison {
plane: DecisionPlane::Ranking,
metadata: DecisionPlaneMetadata::empty(),
decided_at: "2026-04-30T12:00:00Z".to_owned(),
shadow_outcome: "rank-3".to_owned(),
incumbent_outcome: "rank-1".to_owned(),
diverged: true,
confidence: Some(0.85),
reason: None,
});
report.add_comparison(ShadowRunComparison {
plane: DecisionPlane::Packing,
metadata: DecisionPlaneMetadata::empty(),
decided_at: "2026-04-30T12:01:00Z".to_owned(),
shadow_outcome: "include".to_owned(),
incumbent_outcome: "include".to_owned(),
diverged: false,
confidence: Some(0.95),
reason: None,
});
ensure_equal(&report.summary.total, &2, "total")?;
ensure_equal(&report.summary.diverged, &1, "diverged")?;
ensure_equal(&report.summary.matched, &1, "matched")
}
#[test]
fn shadow_run_divergence_rate_empty_is_zero() -> TestResult {
let report = ShadowRunReport::new("exp", "default");
let rate = report.divergence_rate();
ensure(
(rate - 0.0).abs() < 0.0001,
format!("expected 0.0, got {rate}"),
)
}
#[test]
fn shadow_run_divergence_rate_computed_correctly() -> TestResult {
let mut report = ShadowRunReport::new("exp", "default");
report.add_comparison(ShadowRunComparison {
plane: DecisionPlane::Curation,
metadata: DecisionPlaneMetadata::empty(),
decided_at: "2026-04-30T12:00:00Z".to_owned(),
shadow_outcome: "archive".to_owned(),
incumbent_outcome: "keep".to_owned(),
diverged: true,
confidence: None,
reason: None,
});
report.add_comparison(ShadowRunComparison {
plane: DecisionPlane::Curation,
metadata: DecisionPlaneMetadata::empty(),
decided_at: "2026-04-30T12:01:00Z".to_owned(),
shadow_outcome: "keep".to_owned(),
incumbent_outcome: "keep".to_owned(),
diverged: false,
confidence: None,
reason: None,
});
let rate = report.divergence_rate();
ensure(
(rate - 0.5).abs() < 0.0001,
format!("expected 0.5, got {rate}"),
)
}
#[test]
fn shadow_run_from_record_only_shadow_records() -> TestResult {
let non_shadow = DecisionRecord::builder()
.plane(DecisionPlane::Ranking)
.shadow(false)
.build();
ensure(
ShadowRunComparison::from_record(&non_shadow).is_none(),
"non-shadow record should return None",
)?;
let shadow = DecisionRecord::builder()
.plane(DecisionPlane::Ranking)
.shadow(true)
.outcome("rank-2")
.incumbent_outcome("rank-1")
.build();
let comparison = ShadowRunComparison::from_record(&shadow);
ensure(comparison.is_some(), "shadow record should return Some")
}
#[test]
fn render_shadow_run_json_contains_schema_and_policies() -> TestResult {
let report = ShadowRunReport::new("exp-ranker", "default-ranker");
let json = render_shadow_run_json(&report);
ensure_contains(&json, "\"schema\":\"ee.shadow_run.v1\"", "schema")?;
ensure_contains(&json, "\"shadow\":\"exp-ranker\"", "shadow policy")?;
ensure_contains(
&json,
"\"incumbent\":\"default-ranker\"",
"incumbent policy",
)
}
#[test]
fn render_shadow_run_json_contains_summary() -> TestResult {
let mut report = ShadowRunReport::new("exp", "default");
report.add_comparison(ShadowRunComparison {
plane: DecisionPlane::CacheAdmission,
metadata: DecisionPlaneMetadata::empty(),
decided_at: "2026-04-30T12:00:00Z".to_owned(),
shadow_outcome: "admit".to_owned(),
incumbent_outcome: "evict".to_owned(),
diverged: true,
confidence: Some(0.9),
reason: Some("high reuse".to_owned()),
});
let json = render_shadow_run_json(&report);
ensure_contains(&json, "\"total\":1", "total")?;
ensure_contains(&json, "\"diverged\":1", "diverged")?;
ensure_contains(&json, "\"matched\":0", "matched")?;
ensure_contains(&json, "\"divergenceRate\":1.0", "divergenceRate")
}
#[test]
fn render_shadow_run_json_contains_comparison_fields() -> TestResult {
let mut report = ShadowRunReport::new("exp", "default");
report.add_comparison(ShadowRunComparison {
plane: DecisionPlane::RepairOrder,
metadata: DecisionPlaneMetadata::full("exp", "dec-001", "trace-abc"),
decided_at: "2026-04-30T12:00:00Z".to_owned(),
shadow_outcome: "priority-high".to_owned(),
incumbent_outcome: "priority-low".to_owned(),
diverged: true,
confidence: Some(0.75),
reason: Some("critical path".to_owned()),
});
let json = render_shadow_run_json(&report);
ensure_contains(&json, "\"plane\":\"repair_order\"", "plane")?;
ensure_contains(
&json,
"\"shadowOutcome\":\"priority-high\"",
"shadowOutcome",
)?;
ensure_contains(
&json,
"\"incumbentOutcome\":\"priority-low\"",
"incumbentOutcome",
)?;
ensure_contains(&json, "\"diverged\":true", "diverged")?;
ensure_contains(&json, "\"reason\":\"critical path\"", "reason")?;
ensure_contains(&json, "\"decisionId\":\"dec-001\"", "decisionId")?;
ensure_contains(&json, "\"traceId\":\"trace-abc\"", "traceId")
}
#[test]
fn render_shadow_run_human_contains_header_and_summary() -> TestResult {
let mut report = ShadowRunReport::new("exp-policy", "incumbent-policy");
report.add_comparison(ShadowRunComparison {
plane: DecisionPlane::Packing,
metadata: DecisionPlaneMetadata::empty(),
decided_at: "2026-04-30T12:00:00Z".to_owned(),
shadow_outcome: "include".to_owned(),
incumbent_outcome: "exclude".to_owned(),
diverged: true,
confidence: None,
reason: None,
});
let human = render_shadow_run_human(&report);
ensure_contains(&human, "Shadow-Run Comparison Report", "header")?;
ensure_contains(&human, "Shadow policy: exp-policy", "shadow policy")?;
ensure_contains(
&human,
"Incumbent policy: incumbent-policy",
"incumbent policy",
)?;
ensure_contains(&human, "Total decisions: 1", "total")?;
ensure_contains(&human, "Diverged: 1", "diverged")?;
ensure_contains(&human, "Divergence rate: 100.0%", "rate")
}
#[test]
fn render_shadow_run_human_contains_comparison_details() -> TestResult {
let mut report = ShadowRunReport::new("exp", "default");
report.add_comparison(ShadowRunComparison {
plane: DecisionPlane::Ranking,
metadata: DecisionPlaneMetadata::empty(),
decided_at: "2026-04-30T12:00:00Z".to_owned(),
shadow_outcome: "rank-5".to_owned(),
incumbent_outcome: "rank-2".to_owned(),
diverged: true,
confidence: Some(0.88),
reason: Some("recency boost".to_owned()),
});
let human = render_shadow_run_human(&report);
ensure_contains(&human, "[DIVERGED]", "status")?;
ensure_contains(&human, "ranking", "plane")?;
ensure_contains(&human, "Shadow: rank-5", "shadow outcome")?;
ensure_contains(&human, "Incumbent: rank-2", "incumbent outcome")?;
ensure_contains(&human, "Reason: recency boost", "reason")?;
ensure_contains(&human, "Confidence: 0.88", "confidence")
}
#[test]
fn render_shadow_run_toon_is_valid_toon() -> TestResult {
let report = ShadowRunReport::new("exp", "default");
let toon = render_shadow_run_toon(&report);
ensure_starts_with(&toon, "schema: ee.shadow_run.v1", "toon schema")
}
#[test]
fn shadow_run_compute_avg_confidence() -> TestResult {
let mut report = ShadowRunReport::new("exp", "default");
report.add_comparison(ShadowRunComparison {
plane: DecisionPlane::Packing,
metadata: DecisionPlaneMetadata::empty(),
decided_at: "2026-04-30T12:00:00Z".to_owned(),
shadow_outcome: "include".to_owned(),
incumbent_outcome: "include".to_owned(),
diverged: false,
confidence: Some(0.8),
reason: None,
});
report.add_comparison(ShadowRunComparison {
plane: DecisionPlane::Packing,
metadata: DecisionPlaneMetadata::empty(),
decided_at: "2026-04-30T12:01:00Z".to_owned(),
shadow_outcome: "exclude".to_owned(),
incumbent_outcome: "include".to_owned(),
diverged: true,
confidence: Some(0.6),
reason: None,
});
report.compute_avg_confidence();
let avg = report
.summary
.avg_confidence
.ok_or_else(|| "expected avg confidence".to_owned())?;
ensure(
(avg - 0.7).abs() < 0.0001,
format!("expected 0.7, got {avg}"),
)
}
// ========================================================================
// Output Size Diagnostic Tests (EE-335)
// ========================================================================
#[test]
fn size_diagnostic_from_json_computes_all_fields() -> TestResult {
use super::OutputSizeDiagnostic;
let json = r#"{"schema":"ee.response.v2","success":true,"data":{"command":"status"}}"#;
let diagnostic = OutputSizeDiagnostic::from_json(json);
ensure(diagnostic.json_bytes > 0, "json_bytes should be positive")?;
ensure(diagnostic.toon_bytes > 0, "toon_bytes should be positive")?;
ensure(
diagnostic.json_estimated_tokens > 0,
"json tokens should be positive",
)?;
ensure(
diagnostic.toon_estimated_tokens > 0,
"toon tokens should be positive",
)?;
ensure(
diagnostic.compression_ratio > 0.0 && diagnostic.compression_ratio <= 2.0,
format!(
"compression ratio should be reasonable, got {}",
diagnostic.compression_ratio
),
)
}
#[test]
fn size_diagnostic_json_output_has_required_schema() -> TestResult {
use super::{OUTPUT_SIZE_DIAGNOSTIC_SCHEMA_V1, OutputSizeDiagnostic};
let json = r#"{"schema":"ee.response.v2","success":true,"data":{"command":"test"}}"#;
let diagnostic = OutputSizeDiagnostic::from_json(json);
let output = diagnostic.to_json();
ensure_contains(&output, OUTPUT_SIZE_DIAGNOSTIC_SCHEMA_V1, "schema field")?;
ensure_contains(&output, "\"json\":", "json section")?;
ensure_contains(&output, "\"toon\":", "toon section")?;
ensure_contains(&output, "\"savings\":", "savings section")?;
ensure_contains(&output, "\"bytes\":", "bytes field")?;
ensure_contains(&output, "\"estimatedTokens\":", "estimatedTokens field")?;
ensure_contains(&output, "\"compressionRatio\":", "compressionRatio field")
}
#[test]
fn size_diagnostic_human_output_has_structure() -> TestResult {
use super::OutputSizeDiagnostic;
let json = r#"{"schema":"ee.response.v2","success":true,"data":{"command":"test"}}"#;
let diagnostic = OutputSizeDiagnostic::from_json(json);
let output = diagnostic.to_human();
ensure_contains(&output, "Output Size Diagnostic", "title")?;
ensure_contains(&output, "JSON:", "JSON label")?;
ensure_contains(&output, "TOON:", "TOON label")?;
ensure_contains(&output, "Savings:", "savings label")?;
ensure_contains(&output, "bytes", "bytes unit")?;
ensure_contains(&output, "tokens", "tokens unit")
}
#[test]
fn size_diagnostic_status_report_shows_toon_savings() -> TestResult {
use super::OutputSizeDiagnostic;
let report = StatusReport::gather();
let json = render_status_json(&report);
let diagnostic = OutputSizeDiagnostic::from_json(&json);
// TOON should typically be smaller than JSON for structured data
// But we only assert both are computed, not the relationship
ensure(diagnostic.json_bytes > 0, "json_bytes computed")?;
ensure(diagnostic.toon_bytes > 0, "toon_bytes computed")
}
#[test]
fn size_diagnostic_health_report_shows_toon_savings() -> TestResult {
use super::OutputSizeDiagnostic;
let report = HealthReport::gather();
let json = render_health_json(&report);
let diagnostic = OutputSizeDiagnostic::from_json(&json);
ensure(diagnostic.json_bytes > 0, "json_bytes computed")?;
ensure(diagnostic.toon_bytes > 0, "toon_bytes computed")
}
#[test]
fn size_diagnostic_empty_json_handles_gracefully() -> TestResult {
use super::OutputSizeDiagnostic;
let diagnostic = OutputSizeDiagnostic::from_json("{}");
ensure(diagnostic.json_bytes == 2, "empty json is 2 bytes")?;
ensure(
diagnostic.compression_ratio >= 0.0,
"compression ratio should be non-negative",
)
}
#[test]
fn representative_diagnostics_returns_multiple_reports() -> TestResult {
use super::compute_representative_size_diagnostics;
let diagnostics = compute_representative_size_diagnostics();
ensure(
diagnostics.len() >= 2,
format!("expected at least 2 diagnostics, got {}", diagnostics.len()),
)?;
for (name, diag) in &diagnostics {
ensure(
diag.json_bytes > 0,
format!("{name}: json_bytes should be positive"),
)?;
ensure(
diag.toon_bytes > 0,
format!("{name}: toon_bytes should be positive"),
)?;
}
Ok(())
}
// ========================================================================
// Cards Output Tests (EE-341)
// ========================================================================
use super::{
Card, CardKind, CardMath, CardsProfile, GraveyardPriority, GraveyardRecommendationType,
diversity_penalty_card, graveyard_deprecated_dependency_card,
graveyard_failed_verification_card, graveyard_missing_demo_card,
graveyard_output_drift_card, graveyard_stale_claim_card, graveyard_uplift_candidate_card,
pack_budget_card, relevance_score_card, render_cards_json, selection_score_card,
trust_score_card, utility_decay_card,
};
#[test]
fn cards_profile_none_excludes_all_cards() -> TestResult {
let profile = CardsProfile::None;
ensure(!profile.include_cards(), "none excludes cards")?;
ensure(!profile.include_math(), "none excludes math")?;
ensure(!profile.include_provenance(), "none excludes provenance")
}
#[test]
fn cards_profile_summary_includes_cards_only() -> TestResult {
let profile = CardsProfile::Summary;
ensure(profile.include_cards(), "summary includes cards")?;
ensure(!profile.include_math(), "summary excludes math")?;
ensure(!profile.include_provenance(), "summary excludes provenance")
}
#[test]
fn cards_profile_math_includes_math() -> TestResult {
let profile = CardsProfile::Math;
ensure(profile.include_cards(), "math includes cards")?;
ensure(profile.include_math(), "math includes math")?;
ensure(!profile.include_provenance(), "math excludes provenance")
}
#[test]
fn cards_profile_full_includes_everything() -> TestResult {
let profile = CardsProfile::Full;
ensure(profile.include_cards(), "full includes cards")?;
ensure(profile.include_math(), "full includes math")?;
ensure(profile.include_provenance(), "full includes provenance")
}
#[test]
fn card_to_json_respects_profile_none() -> TestResult {
let card = Card::new("card_001", CardKind::Certificate, "Test Card")
.with_summary("A test summary")
.with_math(CardMath::new().with_value(0.95))
.with_provenance("file://test.rs#L42");
let json = card.to_json(CardsProfile::None);
ensure_contains(&json, "\"id\":\"card_001\"", "id always present")?;
ensure_contains(&json, "\"kind\":\"certificate\"", "kind always present")?;
ensure_contains(&json, "\"title\":\"Test Card\"", "title always present")?;
// Summary excluded in None profile
ensure(
!json.contains("summary"),
"summary should be excluded in None profile",
)
}
#[test]
fn card_to_json_respects_profile_summary() -> TestResult {
let card = Card::new("card_002", CardKind::Risk, "Risk Card")
.with_summary("Risk summary")
.with_math(CardMath::new().with_value(0.75).with_confidence(0.9));
let json = card.to_json(CardsProfile::Summary);
ensure_contains(&json, "\"summary\":\"Risk summary\"", "summary included")?;
ensure(
!json.contains("math"),
"math should be excluded in Summary profile",
)
}
#[test]
fn card_to_json_respects_profile_math() -> TestResult {
let card = Card::new("card_003", CardKind::Artifact, "Math Card")
.with_summary("Summary here")
.with_math(
CardMath::new()
.with_value(0.85)
.with_formula("f(x) = x^2")
.with_unit("score"),
)
.with_provenance("file://math.rs");
let json = card.to_json(CardsProfile::Math);
ensure_contains(&json, "\"summary\":", "summary included")?;
ensure_contains(&json, "\"math\":", "math included")?;
ensure_contains(&json, "\"formula\":\"f(x) = x^2\"", "formula in math")?;
ensure(
!json.contains("provenance"),
"provenance should be excluded in Math profile",
)
}
#[test]
fn card_to_json_respects_profile_full() -> TestResult {
let card = Card::new("card_004", CardKind::Lifecycle, "Full Card")
.with_summary("Full summary")
.with_math(CardMath::new().with_confidence(0.99))
.with_provenance("file://full.rs#L100");
let json = card.to_json(CardsProfile::Full);
ensure_contains(&json, "\"summary\":", "summary included")?;
ensure_contains(&json, "\"math\":", "math included")?;
ensure_contains(
&json,
"\"provenance\":\"file://full.rs#L100\"",
"provenance included",
)
}
#[test]
fn render_cards_json_returns_empty_array_for_none_profile() -> TestResult {
let cards = vec![Card::new("c1", CardKind::Certificate, "Card 1")];
let json = render_cards_json(&cards, CardsProfile::None);
ensure(json == "[]", format!("expected [], got {json}"))
}
#[test]
fn render_cards_json_returns_empty_array_for_empty_list() -> TestResult {
let cards: Vec<Card> = vec![];
let json = render_cards_json(&cards, CardsProfile::Full);
ensure(json == "[]", format!("expected [], got {json}"))
}
#[test]
fn render_cards_json_formats_array_correctly() -> TestResult {
let cards = vec![
Card::new("c1", CardKind::Certificate, "Card 1"),
Card::new("c2", CardKind::Risk, "Card 2"),
];
let json = render_cards_json(&cards, CardsProfile::Summary);
ensure_contains(&json, "[{", "starts with array")?;
ensure_contains(&json, "}]", "ends with array")?;
ensure_contains(&json, "},{", "cards separated by comma")
}
#[test]
fn card_kind_as_str_covers_all_variants() -> TestResult {
ensure(
CardKind::Certificate.as_str() == "certificate",
"certificate",
)?;
ensure(CardKind::Artifact.as_str() == "artifact", "artifact")?;
ensure(CardKind::Audit.as_str() == "audit", "audit")?;
ensure(CardKind::Risk.as_str() == "risk", "risk")?;
ensure(CardKind::Lifecycle.as_str() == "lifecycle", "lifecycle")
}
#[test]
fn card_math_to_json_includes_all_fields() -> TestResult {
let math = CardMath::new()
.with_value(0.123456)
.with_confidence(0.9999)
.with_formula("E = mc^2")
.with_unit("joules");
let json = math.to_json();
ensure_contains(&json, "\"formula\":\"E = mc^2\"", "formula")?;
ensure_contains(&json, "\"value\":0.123456", "value")?;
ensure_contains(&json, "\"confidence\":0.9999", "confidence")?;
ensure_contains(&json, "\"unit\":\"joules\"", "unit")
}
#[test]
fn selection_score_card_computes_weighted_combination() -> TestResult {
let card = selection_score_card(0.9, 0.8, 0.7, 0.835);
ensure(card.id == "card_selection_score", "card id matches")?;
ensure_equal(&card.kind, &CardKind::Certificate, "card kind")?;
ensure(card.summary.is_some(), "summary present")?;
ensure(card.math.is_some(), "math present")?;
let Some(math) = card.math else {
return Err("math present".to_string());
};
ensure(math.formula.is_some(), "formula present")?;
let Some(formula) = math.formula.as_ref() else {
return Err("formula present".to_string());
};
ensure_contains(formula, "score =", "formula has expected form")
}
#[test]
fn relevance_score_card_shows_rrf_fusion() -> TestResult {
let card = relevance_score_card(0.95, 0.8, 0.875, 3, 60);
ensure(card.id == "card_relevance_score", "card id matches")?;
ensure(card.summary.is_some(), "summary present")?;
let Some(summary) = card.summary else {
return Err("summary present".to_string());
};
ensure_contains(&summary, "Rank 3", "shows rank")?;
ensure_contains(&summary, "semantic=0.950", "shows semantic score")
}
#[test]
fn utility_decay_card_shows_exponential_decay() -> TestResult {
let card = utility_decay_card(0.9, 30, 0.01, 0.67);
ensure(card.id == "card_utility_decay", "card id matches")?;
ensure(card.math.is_some(), "math present")?;
let Some(math) = card.math else {
return Err("math present".to_string());
};
let Some(formula) = math.formula.as_ref() else {
return Err("formula present".to_string());
};
ensure_contains(formula, "exp(", "formula shows exponential decay")
}
#[test]
fn trust_score_card_shows_weighted_computation() -> TestResult {
let card = trust_score_card("human_explicit", 1.0, 0.95, 0.95);
ensure(card.id == "card_trust_score", "card id matches")?;
ensure(card.summary.is_some(), "summary present")?;
let Some(summary) = card.summary.as_ref() else {
return Err("summary present".to_string());
};
ensure_contains(summary, "human_explicit", "shows trust class")
}
#[test]
fn pack_budget_card_shows_utilization() -> TestResult {
let card = pack_budget_card(3500, 4000, 12, 3);
ensure(card.id == "card_pack_budget", "card id matches")?;
ensure_equal(&card.kind, &CardKind::Audit, "card kind is audit")?;
ensure(card.summary.is_some(), "summary present")?;
let Some(summary) = card.summary else {
return Err("summary present".to_string());
};
ensure_contains(&summary, "3500/4000", "shows token usage")?;
ensure_contains(&summary, "12 items", "shows item count")?;
ensure_contains(&summary, "3 omitted", "shows omitted count")
}
#[test]
fn diversity_penalty_card_shows_mmr_computation() -> TestResult {
let card = diversity_penalty_card(0.95, 0.15, 0.80, 2);
ensure(card.id == "card_diversity_penalty", "card id matches")?;
ensure(card.math.is_some(), "math present")?;
let Some(math) = card.math else {
return Err("math present".to_string());
};
let Some(formula) = math.formula.as_ref() else {
return Err("formula present".to_string());
};
ensure_contains(formula, "max_sim", "formula references similarity")
}
// ====================================================================
// EE-374: Graveyard recommendation card tests
// ====================================================================
#[test]
fn graveyard_priority_ordering() {
assert!(GraveyardPriority::Low < GraveyardPriority::Medium);
assert!(GraveyardPriority::Medium < GraveyardPriority::High);
assert!(GraveyardPriority::High < GraveyardPriority::Critical);
}
#[test]
fn graveyard_priority_strings_stable() {
assert_eq!(GraveyardPriority::Low.as_str(), "low");
assert_eq!(GraveyardPriority::Medium.as_str(), "medium");
assert_eq!(GraveyardPriority::High.as_str(), "high");
assert_eq!(GraveyardPriority::Critical.as_str(), "critical");
}
#[test]
fn graveyard_recommendation_type_strings_stable() {
assert_eq!(
GraveyardRecommendationType::StaleClaim.as_str(),
"stale_claim"
);
assert_eq!(
GraveyardRecommendationType::MissingDemo.as_str(),
"missing_demo"
);
assert_eq!(
GraveyardRecommendationType::FailedVerification.as_str(),
"failed_verification"
);
assert_eq!(
GraveyardRecommendationType::UpliftCandidate.as_str(),
"uplift_candidate"
);
assert_eq!(
GraveyardRecommendationType::OutputDrift.as_str(),
"output_drift"
);
assert_eq!(
GraveyardRecommendationType::DeprecatedDependency.as_str(),
"deprecated_dependency"
);
}
#[test]
fn graveyard_recommendation_default_priorities() {
assert_eq!(
GraveyardRecommendationType::StaleClaim.default_priority(),
GraveyardPriority::Medium
);
assert_eq!(
GraveyardRecommendationType::MissingDemo.default_priority(),
GraveyardPriority::High
);
assert_eq!(
GraveyardRecommendationType::FailedVerification.default_priority(),
GraveyardPriority::Critical
);
assert_eq!(
GraveyardRecommendationType::UpliftCandidate.default_priority(),
GraveyardPriority::Low
);
}
#[test]
fn graveyard_stale_claim_card_fixture() -> TestResult {
let card = graveyard_stale_claim_card("claim_test_001", 45, 30);
ensure(
card.id.contains("graveyard_stale"),
"card id contains graveyard_stale",
)?;
ensure_equal(
&card.kind,
&CardKind::Recommendation,
"card kind is recommendation",
)?;
ensure(card.summary.is_some(), "summary present")?;
let Some(summary) = card.summary else {
return Err("summary present".to_string());
};
ensure_contains(&summary, "45 days", "shows days since verification")?;
ensure_contains(&summary, "claim_test_001", "includes claim id")
}
#[test]
fn graveyard_missing_demo_card_fixture() -> TestResult {
let card = graveyard_missing_demo_card("claim_test_002", "Test Claim Title");
ensure(
card.id.contains("missing_demo"),
"card id contains missing_demo",
)?;
ensure_equal(
&card.kind,
&CardKind::Recommendation,
"card kind is recommendation",
)?;
ensure(card.summary.is_some(), "summary present")?;
let Some(summary) = card.summary else {
return Err("summary present".to_string());
};
ensure_contains(&summary, "Test Claim Title", "includes claim title")?;
ensure_contains(&summary, "demo.yaml", "mentions demo.yaml")
}
#[test]
fn graveyard_failed_verification_card_fixture() -> TestResult {
let card =
graveyard_failed_verification_card("claim_test_003", "Exit code 1", "2026-04-30");
ensure(
card.id.contains("graveyard_failed"),
"card id contains graveyard_failed",
)?;
ensure_equal(
&card.kind,
&CardKind::Recommendation,
"card kind is recommendation",
)?;
ensure(card.summary.is_some(), "summary present")?;
let Some(summary) = card.summary else {
return Err("summary present".to_string());
};
ensure_contains(&summary, "Exit code 1", "includes failure reason")?;
ensure_contains(&summary, "2026-04-30", "includes last attempt date")
}
#[test]
fn graveyard_uplift_candidate_card_fixture() -> TestResult {
let card = graveyard_uplift_candidate_card("claim_test_004", 5, 0.95);
ensure(
card.id.contains("graveyard_uplift"),
"card id contains graveyard_uplift",
)?;
ensure_equal(
&card.kind,
&CardKind::Recommendation,
"card kind is recommendation",
)?;
ensure(card.summary.is_some(), "summary present")?;
let Some(summary) = card.summary else {
return Err("summary present".to_string());
};
ensure_contains(&summary, "5 consecutive", "shows consecutive passes")?;
ensure_contains(&summary, "95.0%", "shows confidence percentage")?;
ensure(card.math.is_some(), "math present for uplift card")
}
#[test]
fn graveyard_output_drift_card_fixture() -> TestResult {
let card =
graveyard_output_drift_card("demo_test_001", "abc123def456", "xyz789uvw012", 0.15);
ensure(
card.id.contains("graveyard_drift"),
"card id contains graveyard_drift",
)?;
ensure_equal(
&card.kind,
&CardKind::Recommendation,
"card kind is recommendation",
)?;
ensure(card.summary.is_some(), "summary present")?;
let Some(summary) = card.summary else {
return Err("summary present".to_string());
};
ensure_contains(&summary, "15.0%", "shows drift percentage")?;
ensure_contains(&summary, "abc123de", "shows truncated expected hash")?;
ensure(card.math.is_some(), "math present for drift card")
}
#[test]
fn graveyard_deprecated_dependency_card_fixture() -> TestResult {
let card = graveyard_deprecated_dependency_card(
"claim_test_005",
"old_feature_v1",
Some("new_feature_v2"),
);
ensure(
card.id.contains("graveyard_deprecated"),
"card id contains graveyard_deprecated",
)?;
ensure_equal(
&card.kind,
&CardKind::Recommendation,
"card kind is recommendation",
)?;
ensure(card.summary.is_some(), "summary present")?;
let Some(summary) = card.summary else {
return Err("summary present".to_string());
};
ensure_contains(&summary, "old_feature_v1", "shows deprecated feature")?;
ensure_contains(&summary, "new_feature_v2", "shows replacement")
}
#[test]
fn graveyard_deprecated_dependency_card_no_replacement() -> TestResult {
let card = graveyard_deprecated_dependency_card("claim_test_006", "legacy_api", None);
ensure(card.summary.is_some(), "summary present")?;
let Some(summary) = card.summary else {
return Err("summary present".to_string());
};
ensure_contains(&summary, "legacy_api", "shows deprecated feature")?;
ensure_contains(&summary, "remove", "suggests removal when no replacement")
}
#[test]
fn card_kind_recommendation_stable() {
assert_eq!(CardKind::Recommendation.as_str(), "recommendation");
}
}