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
64 lines
2.6 KiB
Rust
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);
|