pub mod author;
pub mod calibrate;
pub mod catalog;
pub mod config;
mod error;
pub mod finding;
pub mod harness_assert_graph;
pub mod harness_citation_integrity;
pub mod harness_concordance;
pub mod harness_corpus;
pub mod harness_falsify;
pub mod harness_graph;
pub mod harness_import;
pub mod harness_index;
pub mod harness_markdown;
pub mod harness_membership;
pub mod harness_ontology_registry;
pub mod harness_project;
pub mod harness_reconcile;
pub mod harness_relationship_targets;
pub mod harness_release;
pub mod harness_render;
pub mod harness_shippable_typing;
pub mod harness_synthesize;
pub mod harness_toggle;
pub mod harness_topic_metadata;
pub mod harness_validate_concordance;
pub mod harness_wrap;
pub mod index;
pub mod lock;
pub mod ontology_pack;
pub mod queue;
pub mod resolve;
pub mod review;
pub mod suggest;
pub mod vendor;
pub use author::{DraftReport, draft_from_clusters, draft_from_topic};
pub use calibrate::{
CONFUSION_REPRESENTATIVES, CalibrateOptions, CalibrationSample, ConfusionPair, ConfusionReport,
collect_topic_samples, confusions, packs_carry_negatives, subsample, sweep,
};
pub use catalog::Catalog;
pub use config::HarnessConfig;
pub use error::MifRhError;
pub use finding::Finding;
pub use harness_assert_graph::{CheckResult, GraphAssertion, assert_graph_mif_file};
pub use harness_citation_integrity::{CitationIntegrityReport, check_citation_integrity};
pub use harness_concordance::build_concordance;
pub use harness_corpus::{CorpusSynthesis, synthesize_corpus};
pub use harness_falsify::{FalsifyResult, falsify};
pub use harness_graph::build_graph;
pub use harness_import::{ImportReport, import_corpus};
pub use harness_index::build_index;
pub use harness_membership::{MembershipReport, resolve_membership};
pub use harness_ontology_registry::{RegistryValidation, validate_ontology_registry};
pub use harness_project::project_report;
pub use harness_reconcile::{ReconcileReport, reconcile_session, sort_object_keys};
pub use harness_relationship_targets::{
Orphan, RelationshipTargetsReport, check_relationship_targets,
};
pub use harness_release::{
BumpOptions, BumpReport, VersionGateFailure, VersionGateReport, bump_version,
check_version_bump, goal_version_id,
};
pub use harness_render::{RenderInputs, render_artifact};
pub use harness_shippable_typing::{ShippableTypingReport, check_shippable_typing};
pub use harness_synthesize::synthesize_artifact;
pub use harness_toggle::{SITE_PLUGINS, pack_toggle, site_toggle_plugin, site_toggle_primary};
pub use harness_topic_metadata::{TopicMetadata, topic_metadata};
pub use harness_validate_concordance::{ConcordanceValidation, validate_concordance};
pub use harness_wrap::{WrapSourceInputs, read_source_content, wrap_source};
pub use index::{FindingIndex, IndexStats, IndexedFinding, Miss, SearchMatch, SimilarFinding};
pub use lock::ReviewLock;
pub use ontology_pack::{EntityType, OntologyPack};
pub use queue::{
ClusterMember, ExpansionCandidate, SuggestionEntry, SuggestionQueue, expansion_candidates,
upsert_suggestions,
};
pub use resolve::{Basis, MapRecord, ResolveContext, build_allowed, resolve_finding};
pub use review::{
FollowupBacklog, FollowupEntry, ReviewOptions, ReviewReport, TopicSummary, review,
write_followup,
};
pub use suggest::{TypeSuggestion, suggest_type};
pub use vendor::{
CatalogSyncReport, DriftEntry, FetchReport, LockCheckReport, LockEntry, LockFile,
NewlyRequiredField, PinSafetyGap, PinSafetyReport, RegistrySyncReport, VendoredOntology,
check_pin_safety, fetch, lock_check, resolve_source, sync_catalog, sync_registry,
};
pub fn build_search_index(
reports_dir: &std::path::Path,
topic_ids: &[String],
index: &mut FindingIndex,
) -> Result<(), MifRhError> {
let embedder = mif_embed::Embedder::load()?;
let mut indexed = Vec::new();
for topic in topic_ids {
let findings_dir = reports_dir.join(topic).join("findings");
if !findings_dir.is_dir() {
continue;
}
for file in review::list_finding_files(&findings_dir)? {
let finding = Finding::load(&file)?;
let text = index_text(&finding);
let vector = embedder.embed(&text)?;
indexed.push(IndexedFinding {
finding_id: finding.id,
topic: topic.clone(),
content: text,
vector,
});
}
}
index.rebuild(&indexed)
}
pub fn write_json_atomic<T: serde::Serialize>(
path: &std::path::Path,
value: &T,
) -> Result<(), MifRhError> {
let json = serde_json::to_string_pretty(value).map_err(|source| MifRhError::JsonSerialize {
path: path.display().to_string(),
source,
})?;
let tmp_path = path.with_extension("json.tmp");
std::fs::write(&tmp_path, json).map_err(|source| MifRhError::Io {
path: tmp_path.display().to_string(),
source,
})?;
std::fs::rename(&tmp_path, path).map_err(|source| MifRhError::Io {
path: path.display().to_string(),
source,
})
}
#[must_use]
pub fn index_text(finding: &Finding) -> String {
let discovery_text = finding.discovery_text();
if !discovery_text.is_empty() {
return discovery_text;
}
finding
.entity
.as_ref()
.and_then(|entity| entity.get("name"))
.and_then(serde_json::Value::as_str)
.unwrap_or_default()
.to_string()
}