Skip to main content

cordance_core/
lib.rs

1//! Cordance core: types, schemas, ports. No I/O.
2//!
3//! Doctrine alignment:
4//! - `modularity-and-ports-adapters.md`: ports here, adapters elsewhere.
5//! - `event-contracts.md`: every emitted artifact has a versioned `schema` tag.
6//! - `single-source-of-truth.md`: serde structs are the single source of truth
7//!   for on-disk shapes; the JSON schemas in `/contracts/` are generated from
8//!   these structs and round-trip-tested.
9//!
10//! # Golden path
11//!
12//! ```
13//! use cordance_core::advise::AdviseReport;
14//! use cordance_core::lock::SourceLock;
15//! use cordance_core::pack::{CordancePack, PackTargets, ProjectIdentity};
16//! use cordance_core::schema;
17//!
18//! let pack = CordancePack {
19//!     schema: schema::CORDANCE_PACK_V1.into(),
20//!     project: ProjectIdentity {
21//!         name: "my-project".into(),
22//!         repo_root: ".".into(),
23//!         kind: "rust-workspace".into(),
24//!         host_os: "linux".into(),
25//!         axiom_pin: None,
26//!     },
27//!     sources: vec![],
28//!     doctrine_pins: vec![],
29//!     targets: PackTargets::all(),
30//!     outputs: vec![],
31//!     source_lock: SourceLock::empty(),
32//!     advise: AdviseReport::empty(),
33//!     residual_risk: vec!["claim_ceiling=candidate".into()],
34//! };
35//!
36//! let json = serde_json::to_string(&pack).expect("serialise pack");
37//! assert!(json.contains("cordance-pack.v1"));
38//! ```
39//!
40//! See [`fs::safe_write`] for the symlink-refusing write helper every emitter
41//! routes through, and [`paths::doctrine_cache_dir_for_url`] for the
42//! operator-trusted doctrine cache location.
43
44#![forbid(unsafe_code)]
45#![deny(clippy::unwrap_used, clippy::expect_used)]
46#![cfg_attr(test, allow(clippy::expect_used, clippy::unwrap_used))]
47
48pub mod advise;
49pub mod evidence;
50pub mod fence;
51pub mod fs;
52pub mod harness_target;
53pub mod lock;
54pub mod pack;
55pub mod paths;
56pub mod receipt;
57pub mod source;
58
59pub use advise::{AdviseFinding, AdviseReport, Severity};
60pub use evidence::{EvidenceEntry, EvidenceMap, EvidenceSource, OutputEvidence};
61pub use fence::{
62    find_regions, replace_region, replace_regions, sanitise_fenced_value, FenceError, FenceMarker,
63    FencedRegion,
64};
65// Round-6 codereview-3 / Round-7 codereview-3: re-export the symlink-refusal
66// helpers and error type at the crate root so downstream callers can write
67// `use cordance_core::SymlinkRefusal` instead of the longer
68// `cordance_core::fs::SymlinkRefusal`. The error type is what
69// `safe_write`/`safe_write_with_mkdir` wrap inside `std::io::Error::other`,
70// and callers typed-downcast against it; the inconsistent re-export shape
71// was an ergonomic trap that pushed `cordance-emit`'s integration test into
72// string-scraping the error message instead of typed matching.
73pub use fs::{
74    extract_symlink_refusal, precheck_no_reparse_point_ancestor, safe_write, safe_write_with_mkdir,
75    SymlinkRefusal,
76};
77pub use harness_target::{
78    AccessMode, AuthoritySurfaces, AxiomProjectHarnessTargetV1, ClaimCeiling, HarnessBlock,
79    HarnessClassification, HarnessInvariantError, HarnessOperations, ProjectBlock,
80};
81pub use lock::{DriftReport, OutputDriftEntry, SourceDriftEntry, SourceLock, SourceLockEntry};
82pub use pack::{CordancePack, PackOutput, PackTargets, ProjectIdentity};
83pub use receipt::{
84    AuthorityBoundary, CortexReceiptV1Candidate, ReceiptBody, ReceiptInvariantError, SourceAnchor,
85    TruthCeiling,
86};
87pub use source::{SourceClass, SourceRecord, SurfaceCategory};
88
89/// Schema versions emitted by this crate. Never mutate; add a new constant.
90pub mod schema {
91    pub const CORDANCE_PACK_V1: &str = "cordance-pack.v1";
92    pub const CORDANCE_SOURCE_LOCK_V1: &str = "cordance-source-lock.v1";
93    pub const CORDANCE_ADVISE_REPORT_V1: &str = "cordance-advise-report.v1";
94    pub const CORDANCE_CORTEX_RECEIPT_V1_CANDIDATE: &str = "cordance-cortex-receipt-v1-candidate";
95    pub const CORDANCE_EVIDENCE_MAP_V1: &str = "cordance-evidence-map.v1";
96    pub const AXIOM_PROJECT_HARNESS_TARGET_V1: &str = "pai-axiom-project-harness-target.v1";
97}
98
99#[cfg(test)]
100mod tests {
101    use super::*;
102
103    #[test]
104    fn schema_constants_present() {
105        // Verify the constants have the expected name prefix (not vacuous).
106        assert!(schema::CORDANCE_PACK_V1.starts_with("cordance-"));
107        assert!(schema::CORDANCE_CORTEX_RECEIPT_V1_CANDIDATE.starts_with("cordance-"));
108    }
109}