pr4xis 0.29.1

Axiomatic Intelligence — an ontology + category-theory reasoning engine: every claim derived from explicit axioms, with a proof path back to them
Documentation
//! The Constitution — pr4xis's five guarantees, and the machinery that binds
//! the test suite to them.
//!
//! The `ontology` submodule defines the five guarantees ([`Guarantee`]) as a first-class
//! ontology. This module adds the *self-binding* layer: every test in the
//! workspace declares the guarantee it witnesses with the
//! [`praxis_value`](crate::praxis_value) attribute, which registers a
//! [`GuaranteeTag`] into the [`CONSTITUTION_TESTS`] distributed slice at link
//! time. A `constitution_coverage` meta-test then folds that slice into a
//! per-guarantee partition of the suite — so a guarantee cannot silently lose
//! coverage and a new test cannot escape classification.
//!
//! The classification is declared, not reverse-engineered from test names: a
//! claim's guarantee is first-class and discoverable, the same discipline the
//! rest of pr4xis applies to domain knowledge.

mod ontology;

pub use ontology::{
    ConstitutionConcept, DeterminismEnablesVerificationAndExplanation,
    EveryAxiomCarriesItsExplanation, ExtensiblePreservesEveryGuarantee, Guarantee,
    HonestGroundsEveryGuarantee, OntologyBaseIsConsistent,
};

/// How strongly a test witnesses its guarantee.
///
/// An [`Example`](TestKind::Example) is a point-claim: it asserts the property
/// at one chosen input. A [`Property`](TestKind::Property) is a ∀-claim: a
/// `proptest!` that asserts the property for *every* input in a strategy's
/// domain, checked over many generated cases (proptest's default sample budget
/// is 256, configurable via `PROPTEST_CASES`). A property is a stronger witness
/// than an example — the case count is a sampling budget, not a test count, so
/// a property is still **one** test here, distinguished only by its kind.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum TestKind {
    /// A point-claim: the property holds at one chosen input.
    Example,
    /// A ∀-claim: the property holds for every input in a generated domain.
    Property,
}

/// The constitutional guarantee(s) a single test witnesses.
///
/// `primary` is the guarantee the test most directly evidences — the partition
/// key, so every tagged test falls in exactly one bucket. `secondary` records
/// any further guarantees an irreducible test also witnesses (e.g. a property
/// asserting that a mutated `.prx` is always rejected witnesses Honesty
/// primarily, but also Verifiability and Determinism) without forcing an
/// artificial split. `kind` distinguishes a point-claim from a ∀-claim, so
/// coverage can report depth (how many witnesses are properties) as well as
/// breadth.
#[derive(Debug, Clone)]
pub struct GuaranteeTag {
    /// The guarantee this test most directly witnesses (the partition key).
    pub primary: Guarantee,
    /// Further guarantees the same test also witnesses, if any.
    pub secondary: &'static [Guarantee],
    /// Whether the test is an example (point-claim) or a property (∀-claim).
    pub kind: TestKind,
    /// The module the test lives in (`module_path!()` at the call site).
    pub module: &'static str,
    /// The test function's name.
    pub name: &'static str,
}

/// Every test tagged with [`praxis_value`](crate::praxis_value) or
/// [`register_praxis_value!`](crate::register_praxis_value), gathered at link
/// time.
///
/// Native targets only — `linkme` is unsupported on wasm32, where the slice is
/// empty (fail-closed: the coverage meta-test does not run there).
#[cfg(not(target_arch = "wasm32"))]
#[linkme::distributed_slice]
pub static CONSTITUTION_TESTS: [GuaranteeTag];

/// Register a test's constitutional guarantee(s) without an attribute.
///
/// Companion to the [`praxis_value`](crate::praxis_value) attribute for tests
/// the attribute cannot wrap — chiefly `proptest! { #[test] fn .. }` blocks,
/// where the test function is generated by another macro and so is not an
/// `ItemFn` the attribute can parse. Place the call at module scope, next to
/// the test:
///
/// ```text
/// proptest! {
///     #[test]
///     fn prop_mutated_prx_always_rejected(..) { .. }
/// }
/// pr4xis::register_praxis_value!(prop_mutated_prx_always_rejected, Honest, Verifiable, Deterministic);
/// ```
///
/// The first guarantee is primary; any others are secondary. The named
/// function is not checked to exist here — the completeness gate (registry
/// length vs the live `--list` count) is what catches an untagged test or a
/// tag whose name has no test.
#[macro_export]
macro_rules! register_praxis_value {
    ($name:ident, $primary:ident $(, $secondary:ident)* $(,)?) => {
        $crate::paste::paste! {
            #[cfg(not(target_arch = "wasm32"))]
            #[allow(non_upper_case_globals)]
            #[$crate::linkme::distributed_slice($crate::constitution::CONSTITUTION_TESTS)]
            #[linkme(crate = $crate::linkme)]
            static [<__PRAXIS_VALUE_ $name>]: $crate::constitution::GuaranteeTag =
                $crate::constitution::GuaranteeTag {
                    primary: $crate::constitution::Guarantee::$primary,
                    secondary: &[ $( $crate::constitution::Guarantee::$secondary ),* ],
                    // The declarative macro exists for proptest!/generated
                    // tests, which are ∀-claims.
                    kind: $crate::constitution::TestKind::Property,
                    module: module_path!(),
                    name: ::core::stringify!($name),
                };
        }
    };
}

/// Write this binary's registered tag set where the completeness gate expects
/// it.
///
/// `pkg` and `krate` must be the CALLER's `env!("CARGO_PKG_NAME")` and
/// `env!("CARGO_CRATE_NAME")` — they cannot be read here, because `env!` in
/// this file would expand to `pr4xis` no matter who called. They identify the
/// writing binary, and package+crate is what makes that unique: `pr4xis-cli`'s
/// bin target is itself named `pr4xis`, so the crate name alone collides with
/// the `pr4xis` library's.
///
/// Three destinations, in the order the gate uses them:
///
/// - a DIRECTORY — workspace mode. Every binary runs in ONE `cargo nextest
///   run` and each writes its own `<pkg>__<crate>.tags`, so the gate extracts
///   the archive once rather than once per binary.
/// - a FILE — single-crate mode, for running the gate against one crate.
/// - unset — print, for ad-hoc use.
///
/// One function rather than three copies: this is called by
/// [`constitution_coverage_gate!`](crate::constitution_coverage_gate), by
/// pr4xis's own gate below, and by `pr4xis-domains`' richer meta-test, which
/// asserts partition coverage before emitting and so cannot use the macro
/// wholesale.
#[cfg(all(feature = "std", not(target_arch = "wasm32")))]
pub fn emit_tags(pkg: &str, krate: &str) {
    extern crate std;
    use alloc::{format, string::String, vec::Vec};

    let mut lines: Vec<String> = CONSTITUTION_TESTS
        .iter()
        .map(|t| format!("{}::{}", t.module, t.name))
        .collect();
    // Link order is not guaranteed, and the gate diffs this against a sorted
    // listing.
    lines.sort();
    let body = lines.join("\n");

    match std::env::var("PRAXIS_CONSTITUTION_TAGS_OUT") {
        Ok(dir) if std::path::Path::new(&dir).is_dir() => {
            let name = format!("{pkg}__{krate}.tags");
            std::fs::write(std::path::Path::new(&dir).join(name), body)
                .expect("write constitution tags");
        }
        Ok(path) => std::fs::write(&path, body).expect("write constitution tags"),
        Err(_) => std::eprintln!("{body}"),
    }
}

/// Emit this test binary's registered tag set, for the completeness gate.
///
/// Place one invocation in every test binary the workspace builds:
///
/// ```text
/// #[cfg(all(test, not(target_arch = "wasm32")))]
/// pr4xis::constitution_coverage_gate!();
/// ```
///
/// PER BINARY IS NOT AN IMPLEMENTATION DETAIL — it is the whole reason this
/// macro exists. Tags register through a `linkme` distributed slice, and a
/// distributed slice is assembled by the LINKER, so it holds exactly the tags
/// linked into the binary being run and nothing else. A test binary with no
/// invocation of this macro therefore emits no tags at all, and contributes 0
/// to both sides of the gate's diff — `untagged=0 phantom=0`, which reads as
/// COMPLETE. That arithmetic is what let 156 tests across 11 binaries sit
/// unclassified while the gate reported success, so the gate now also fails
/// loudly on a suite that lists tests but emits nothing.
///
/// The body was hand-copied verbatim into four crates before this macro
/// existed (pr4xis, pr4xis-runtime, pr4xis-chat, pr4xis-domains); adding the
/// remaining binaries by copy would have made eleven. Writing it once means a
/// new test binary opts in with one line, which is the only way "every test
/// declares a guarantee" stays true as the workspace grows.
///
/// Fully-qualified paths throughout: this expands inside `pr4xis` itself
/// (`no_std` + `alloc`) as well as in ordinary `std` crates, so it can rely on
/// nothing being in scope at the call site.
#[macro_export]
macro_rules! constitution_coverage_gate {
    () => {
        #[cfg(all(test, not(target_arch = "wasm32")))]
        mod constitution_coverage_gate {
            extern crate std;

            #[$crate::praxis_value(Verifiable)]
            #[test]
            fn constitution_coverage() {
                // env! expands in the CALLING crate, which is the whole point —
                // it names the binary that is doing the writing.
                $crate::constitution::emit_tags(
                    ::core::env!("CARGO_PKG_NAME"),
                    ::core::env!("CARGO_CRATE_NAME"),
                );
            }
        }
    };
}

/// Per-crate completeness-gate support: emit pr4xis-core's own tag set so
/// `scripts/constitution-gate.sh pr4xis` can diff it against `--list`. This
/// binds the substrate crate's tests to the constitution exactly as the domains
/// crate is bound — the constitution covers its own foundation, not only the
/// reasoning layer.
#[cfg(all(test, not(target_arch = "wasm32")))]
mod coverage_gate {
    #[crate::praxis_value(Verifiable)]
    #[test]
    fn constitution_coverage() {
        crate::constitution::emit_tags(
            ::core::env!("CARGO_PKG_NAME"),
            ::core::env!("CARGO_CRATE_NAME"),
        );
    }
}