cordance-core 0.1.1

Cordance core types, schemas, and ports. No I/O.
Documentation
//! Cordance core: types, schemas, ports. No I/O.
//!
//! Doctrine alignment:
//! - `modularity-and-ports-adapters.md`: ports here, adapters elsewhere.
//! - `event-contracts.md`: every emitted artifact has a versioned `schema` tag.
//! - `single-source-of-truth.md`: serde structs are the single source of truth
//!   for on-disk shapes; the JSON schemas in `/contracts/` are generated from
//!   these structs and round-trip-tested.
//!
//! # Golden path
//!
//! ```
//! use cordance_core::advise::AdviseReport;
//! use cordance_core::lock::SourceLock;
//! use cordance_core::pack::{CordancePack, PackTargets, ProjectIdentity};
//! use cordance_core::schema;
//!
//! let pack = CordancePack {
//!     schema: schema::CORDANCE_PACK_V1.into(),
//!     project: ProjectIdentity {
//!         name: "my-project".into(),
//!         repo_root: ".".into(),
//!         kind: "rust-workspace".into(),
//!         host_os: "linux".into(),
//!         axiom_pin: None,
//!     },
//!     sources: vec![],
//!     doctrine_pins: vec![],
//!     targets: PackTargets::all(),
//!     outputs: vec![],
//!     source_lock: SourceLock::empty(),
//!     advise: AdviseReport::empty(),
//!     residual_risk: vec!["claim_ceiling=candidate".into()],
//! };
//!
//! let json = serde_json::to_string(&pack).expect("serialise pack");
//! assert!(json.contains("cordance-pack.v1"));
//! ```
//!
//! See [`fs::safe_write`] for the symlink-refusing write helper every emitter
//! routes through, and [`paths::doctrine_cache_dir_for_url`] for the
//! operator-trusted doctrine cache location.

#![forbid(unsafe_code)]
#![deny(clippy::unwrap_used, clippy::expect_used)]
#![cfg_attr(test, allow(clippy::expect_used, clippy::unwrap_used))]

pub mod advise;
pub mod evidence;
pub mod fence;
pub mod fs;
pub mod harness_target;
pub mod lock;
pub mod pack;
pub mod paths;
pub mod receipt;
pub mod source;

pub use advise::{AdviseFinding, AdviseReport, Severity};
pub use evidence::{EvidenceEntry, EvidenceMap, EvidenceSource, OutputEvidence};
pub use fence::{
    find_regions, replace_region, replace_regions, sanitise_fenced_value, FenceError, FenceMarker,
    FencedRegion,
};
// Round-6 codereview-3 / Round-7 codereview-3: re-export the symlink-refusal
// helpers and error type at the crate root so downstream callers can write
// `use cordance_core::SymlinkRefusal` instead of the longer
// `cordance_core::fs::SymlinkRefusal`. The error type is what
// `safe_write`/`safe_write_with_mkdir` wrap inside `std::io::Error::other`,
// and callers typed-downcast against it; the inconsistent re-export shape
// was an ergonomic trap that pushed `cordance-emit`'s integration test into
// string-scraping the error message instead of typed matching.
pub use fs::{
    extract_symlink_refusal, precheck_no_reparse_point_ancestor, safe_write, safe_write_with_mkdir,
    SymlinkRefusal,
};
pub use harness_target::{
    AccessMode, AuthoritySurfaces, AxiomProjectHarnessTargetV1, ClaimCeiling, HarnessBlock,
    HarnessClassification, HarnessInvariantError, HarnessOperations, ProjectBlock,
};
pub use lock::{DriftReport, OutputDriftEntry, SourceDriftEntry, SourceLock, SourceLockEntry};
pub use pack::{CordancePack, PackOutput, PackTargets, ProjectIdentity};
pub use receipt::{
    AuthorityBoundary, CortexReceiptV1Candidate, ReceiptBody, ReceiptInvariantError, SourceAnchor,
    TruthCeiling,
};
pub use source::{SourceClass, SourceRecord, SurfaceCategory};

/// Schema versions emitted by this crate. Never mutate; add a new constant.
pub mod schema {
    pub const CORDANCE_PACK_V1: &str = "cordance-pack.v1";
    pub const CORDANCE_SOURCE_LOCK_V1: &str = "cordance-source-lock.v1";
    pub const CORDANCE_ADVISE_REPORT_V1: &str = "cordance-advise-report.v1";
    pub const CORDANCE_CORTEX_RECEIPT_V1_CANDIDATE: &str = "cordance-cortex-receipt-v1-candidate";
    pub const CORDANCE_EVIDENCE_MAP_V1: &str = "cordance-evidence-map.v1";
    pub const AXIOM_PROJECT_HARNESS_TARGET_V1: &str = "pai-axiom-project-harness-target.v1";
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn schema_constants_present() {
        // Verify the constants have the expected name prefix (not vacuous).
        assert!(schema::CORDANCE_PACK_V1.starts_with("cordance-"));
        assert!(schema::CORDANCE_CORTEX_RECEIPT_V1_CANDIDATE.starts_with("cordance-"));
    }
}