Jesús Pérez 401294de5d
Some checks failed
Nickel Type Check / Nickel Type Checking (push) Has been cancelled
Rust CI / Security Audit (push) Has been cancelled
Rust CI / Check + Test + Lint (nightly) (push) Has been cancelled
Rust CI / Check + Test + Lint (stable) (push) Has been cancelled
feat: config surface, NCL contracts, override-layer mutation, on+re update
Config surface — per-project config introspection, coherence verification, and
  audited mutation without destroying NCL structure (ADR-008):

  - crates/ontoref-daemon/src/config.rs — typed DaemonNclConfig (parse-at-boundary
    pattern); all section structs derive ConfigFields + config_section(id, ncl_file)
    emitting inventory::submit!(ConfigFieldsEntry{...}) at link time
  - crates/ontoref-derive/src/lib.rs — #[derive(ConfigFields)] proc-macro; serde
    rename support; serde_rename_of() helper extracted to fix excessive_nesting
  - crates/ontoref-daemon/src/main.rs — 3-tuple bootstrap block (nickel_import_path,
    loaded_ncl_config: Option<DaemonNclConfig>, stdin_raw); apply_ui_config takes
    &UiConfig; NATS call site typed; resolve_asset_dir cfg(feature = "ui")
  - crates/ontoref-daemon/src/api.rs — config GET/PUT endpoints, quickref, coherence,
    cross-project comparison; index_section_fields() extracted (excessive_nesting)
  - crates/ontoref-daemon/src/config_coherence.rs — multi-consumer coherence;
    merge_meta_into_section() extracted; and() replaces unnecessary and_then

  NCL contracts for ontoref's own config:
  - .ontoref/contracts.ncl — LogConfig (LogLevel, LogRotation, PositiveInt) and
    DaemonConfig (Port, optional overrides); std.contract.from_validator throughout
  - .ontoref/config.ncl — log | C.LogConfig applied
  - .ontology/manifest.ncl — contracts_path, log/daemon contract refs, daemon section
    with DaemonRuntimeConfig consumer and 7 declared fields

  Protocol:
  - adrs/adr-008-ncl-first-config-validation-and-override-layer.ncl — NCL contracts
    as single validation gate; Rust structs are contract-trusted; override-layer
    mutation writes {section}.overrides.ncl + _overrides_meta, never touches source

  on+re update:
  - .ontology/core.ncl — config-surface node (28 practices); adr-lifecycle extended
    to adr-007 + adr-008; 6 new edges (ManifestsIn daemon, DependsOn ontology-crate,
    Complements api-catalog-surface/dag-formalized/self-describing/adopt-ontoref)
  - .ontology/state.ncl — protocol-maturity blocker and self-description-coverage
    catalyst updated for session 2026-03-26
  - README.md / CHANGELOG.md updated
2026-03-26 20:20:22 +00:00

64 lines
2.6 KiB
Rust

/// A statically registered node contribution, submitted at link time.
///
/// Crates that derive `OntologyNode` emit an
/// `inventory::submit!(NodeContribution { ... })` call, which is collected
/// here. All submissions are merged into [`Core`] via
/// [`Core::merge_contributors`] — NCL-loaded nodes always win on id collision.
///
/// [`Core`]: crate::ontology::Core
pub struct NodeContribution {
/// Returns the node to contribute. Called once per contribution during
/// merge.
pub supplier: fn() -> crate::types::Node,
}
inventory::collect!(NodeContribution);
/// A statically registered test coverage entry, submitted at test-binary link
/// time.
///
/// Produced by `#[onto_validates(practice = "...", adr = "...")]` from
/// `ontoref-derive`. Collected by [`Core::uncovered_practices`] to identify
/// practices without test coverage.
///
/// Only present in test binaries — zero production binary impact because
/// `#[cfg(all(test, feature = "derive"))]` gates all `inventory::submit!`
/// calls.
///
/// [`Core::uncovered_practices`]: crate::ontology::Core::uncovered_practices
pub struct TestCoverage {
/// Practice node id validated by this test, if any.
pub practice_id: Option<&'static str>,
/// ADR id validated by this test, if any.
pub adr_id: Option<&'static str>,
}
inventory::collect!(TestCoverage);
/// A statically registered config field inventory entry.
///
/// Consumer projects derive `#[derive(ConfigFields)]` on their serde config
/// structs to emit `inventory::submit!(ConfigFieldsEntry { ... })` at link
/// time. Ontoref daemon and test helpers iterate these entries to compare
/// against NCL section exports — detecting unclaimed NCL fields and fields
/// expected by Rust but absent in the contract.
///
/// Field names respect `#[serde(rename = "...")]` — the registered name is
/// what serde would use to match the JSON key, not the Rust identifier.
pub struct ConfigFieldsEntry {
/// Matches the `id` in the project's `manifest.ncl
/// config_surface.sections`.
pub section_id: &'static str,
/// Path to the NCL file for this section, relative to the project root.
/// Used to locate the file for export during coherence verification.
pub ncl_file: &'static str,
/// Fully-qualified Rust type name (e.g.
/// `"vapora_backend::config::ServerConfig"`). Informational — used in
/// coherence reports for traceability.
pub struct_name: &'static str,
/// All serde field names this struct expects from the NCL JSON export.
pub fields: &'static [&'static str],
}
inventory::collect!(ConfigFieldsEntry);