ADR-0027: Baseline Configurations — Portable Semantic Contracts¶
- Status: Accepted (2026-04-19)
- Date: 2026-04-17
Context¶
Trails instances are configured through trails.toml — a flat,
project-local file that covers store backend, MCP transport, HTTP
binding, LLM provider, and federation peers. This works for single-
project development but creates friction at scale:
-
Reinvention per project. Every KG team independently configures mapping pipelines, validation rules, schema alignment, and policy templates. A healthcare team starting a new FHIR-based app copies config snippets from prior projects, tweaks them manually, and hopes nothing was forgotten. There is no reusable "healthcare KG" config bundle.
-
No config standard for KG apps. The wider KG ecosystem lacks a widely adopted baseline-config convention. Helm charts standardized Kubernetes deployment;
.eslintrcstandardized JS linting; Trails has no equivalent for "this KG app follows these schema, policy, and pipeline rules." -
Federation incompatibility. When two Trails instances federate (ADR-0023), they must share compatible assumptions about schema strictness, reasoning mode, policy requirements, and trust levels. Today, compatibility is checked manually or not at all. A formal baseline exchange would make federation negotiation automatic.
-
Compliance drift. Regulated environments (HIPAA, GDPR, EU AI Act) need auditable proof that a configuration meets compliance requirements. Without a declared baseline, auditors must inspect raw config files and cross-reference them against regulatory checklists.
-
Emerging patterns. KG-as-code, declarative pipelines, constraint-first modeling, and agent-negotiated schemas all point toward treating configuration as a versionable, composable, sharable artifact — not a project-local detail.
Baselines fill the gap between trails.toml (runtime config) and the
framework's opinionated defaults. They are constraints ON the config,
not the config itself.
Decision¶
Baselines are a first-class framework primitive: versionable, inheritable, negotiable TOML files that declare what a Trails project MUST look like to be compliant with a named profile.
1. Baseline format¶
Baselines live in baselines/ in a project directory or
~/.trails/baselines/ for user-global presets. Each is a TOML file
with a [baseline] header and typed sections:
[baseline]
name = "healthcare-fhir"
version = "1.0"
extends = "trails:default" # can extend other baselines
[baseline.store]
backend = "oxigraph"
reasoning = "rdfs"
max_query_time_ms = 30000
[baseline.schema]
upper_ontology = "schema.org"
core_types = ["Patient", "Encounter", "Observation"]
alignment = "fhir-r4"
shacl_strictness = "closed" # or "open"
[baseline.pipeline]
default_extractors = ["pdf", "html", "docx"]
enrichment_steps = ["ner", "linking", "dedup"]
validation = "strict"
[baseline.policy]
template = "hipaa"
audit_level = "full"
[baseline.agents]
default_model = "haiku"
max_cost_per_run_usd = 1.0
planner = "react"
budget_enforcement = true
[baseline.federation]
require_policy_alignment = true
minimum_peer_trust_level = "verified"
Sections are optional. A baseline that only declares [baseline.policy]
constrains only the policy dimension — everything else is unconstrained.
2. Baseline inheritance¶
The extends field references a parent baseline:
extends = "trails:default"— built-in minimal baseline.extends = "trails:strict"— built-in strict baseline.extends = "file:../base.toml"— relative file path.extends = "registry:org/healthcare-base@1.2"— from the Trails registry (future, post-M4).
Inheritance rules:
- Child values override parent values at the leaf level.
- Multiple inheritance is supported via an array:
extends = ["trails:strict", "file:../compliance.toml"]. Conflicts are resolved left-to-right (last wins), with a warning emitted for each override. trails:defaultis the implicit root. Every baseline without an explicitextendsinherits fromtrails:default.
3. Built-in baselines (shipped with Trails)¶
| Baseline | Description |
|---|---|
trails:default |
Minimal, no constraints, open-world. SHACL open, no policy required, no reasoning. The zero-overhead starting point. |
trails:strict |
SHACL closed-world validation, full PROV-O provenance, Cedar policy required on all capabilities, cost envelopes enforced. |
trails:research |
RDF-star enabled, reasoning active (RDFS), large query timeouts (120s), open SHACL, relaxed cost limits. |
trails:compliance |
Full audit trail, consent receipts required, PROV-O on every write, cost tracking mandatory, budget enforcement on. |
Domain-specific baselines (healthcare, legal, finance) can be published
to the Trails registry and referenced via extends = "registry:...".
4. CLI commands¶
Scaffolds a new project with the baseline applied:trails.toml is
generated to satisfy baseline constraints, baselines/active.toml
records the active baseline.
Checks the current trails.toml against the active baseline. Reports
violations as structured diagnostics (same format as trails doctor).
Exports the current trails.toml as a baseline file — useful for
extracting a reusable baseline from a working project.
Compares two baselines section by section, showing overrides, additions,
and incompatibilities.
Exchanges baselines with a federated peer and computes the compatible
intersection. Outputs the negotiated baseline to stdout or writes it to
a file.
5. Runtime validation (trails doctor integration)¶
trails doctor gains baseline-awareness:
- Schema alignment: declared
core_typesexist as registered@node_typeor@shapedefinitions. - Policy compliance: declared
template(e.g.,hipaa) is loaded as a Cedar policy preset. - Store match: declared
backendandreasoningmatch the running store configuration. - Pipeline coverage: declared
enrichment_stepsare registered in the enrichment pipeline (M15). - Agent budget: declared
max_cost_per_run_usdis enforced by the cost accountant.
Each check maps to a HealthCheck(name="baseline: <section>", ...).
Violations produce status="warn" (soft baseline) or status="fail"
(strict baseline with validation = "strict").
6. Federation negotiation¶
When two Trails instances federate (ADR-0023), baselines enable automatic compatibility checks:
- Exchange. On federation handshake, each instance sends its active baseline (minus sensitive fields like API keys) to the peer.
- Compatibility check. The framework computes whether the two baselines are compatible: same or compatible SHACL strictness, policy templates satisfy each other's requirements, reasoning modes are compatible (RDFS subsumes no-reasoning; OWL-RL subsumes RDFS).
- Negotiation. If baselines differ but overlap, the framework
computes a "negotiated baseline" — the intersection of compatible
constraints. Example: if one peer requires
shacl_strictness = "closed"and the other is"open", the negotiated baseline uses"closed"(the stricter option wins for safety). - PROV-O recording. The negotiation result is recorded as a
prov:Activityin both instances' provenance graphs, linking the federation session to the negotiated baseline. - Rejection. If baselines are incompatible (e.g., one requires
hipaapolicy and the other has no policy engine), federation is refused with a diagnostic explaining the incompatibility.
7. Agent-adaptive baselines (future, Level 4)¶
Agents can propose baseline modifications based on observed usage:
trails baseline suggestanalyzes query logs, SHACL validation failures, cost overruns, and enrichment gaps to suggest baseline changes.- Ties into M14 auto-ontology: inferred schema from
onto infercan update the[baseline.schema]section. - Ties into M15 enrichment: enrichment pipelines discovered during
operation can be added to
[baseline.pipeline]. - All suggestions are proposals — the user confirms before the baseline changes. No unsupervised baseline mutations.
Progressive enhancement levels¶
Per ADR-0021, baselines are additive. Existing projects without baselines are unaffected.
| Level | Capability | Config required |
|---|---|---|
| 0 | No baseline (just trails.toml, today's behavior) |
None |
| 1 | Static baseline file validates config | baselines/active.toml |
| 2 | Inheritance + built-in presets | extends field in baseline |
| 3 | Federation negotiation | [baseline.federation] + ADR-0023 peers |
| 4 | Agent-adaptive baselines | M14 + M15 integration |
Each level is a strict superset of the previous. An instance at Level 0 is unaffected by baseline features existing in the codebase.
Consequences¶
Positive¶
- Reusable configuration. A healthcare team writes a baseline once; every new FHIR project starts from it. No copy-paste drift.
- Auditable compliance. A
healthcare-fhirbaseline is a machine-readable compliance contract. Auditors verify the baseline file +trails baseline validateoutput, not raw config files. - Federation safety. Baseline exchange makes incompatible federation attempts fail fast with clear diagnostics instead of producing silent data-quality issues.
- Progressive. Existing projects pay zero overhead. Baselines are opt-in at every level.
- Composable. Inheritance lets teams layer domain baselines on top of
compliance baselines:
extends = ["trails:compliance", "registry:org/healthcare-base"]. - Standard format. TOML is already the Trails config format. No new syntax, no new parser dependency.
Negative¶
- Complexity budget. Baselines add a second layer of config (config
about config). Users must understand the difference between
trails.toml(what the app IS) andbaselines/(what the app SHOULD BE). Mitigation: clear docs,trails doctorsurfaces mismatches, and Level 0 is "no baseline at all." - Inheritance debugging. Deep inheritance chains (
A extends B extends C extends D) can be hard to trace. Mitigation:trails baseline diffshows the fully resolved baseline;trails doctorreports which parent contributed each constraint. - Federation negotiation is complex. Automatic baseline negotiation across trust boundaries is an unsolved problem in the broader KG ecosystem. Mitigation: Level 3 is explicitly deferred to post-M12; Level 2 (static baselines) covers 90% of use cases.
- Versioning challenges. Baseline versions must be tracked when
published to a registry. Breaking changes in a baseline (removing a
required constraint) need a migration path. Mitigation: SemVer on
baseline
versionfield;trails baseline difffor upgrade review.
Non-consequences¶
- Not replacing
trails.toml. Baselines are constraints on the config, not the config itself.trails.tomlremains the runtime configuration file. A project can have a baseline without changing itstrails.toml— the baseline just validates it. - Not a package manager. Baselines do not install dependencies, download models, or provision infrastructure. They declare what should be present; the user or deployment tool provides it.
- Not a deployment tool. Use Docker, Helm, Nix, or whatever for deployment. Baselines are a development-time and audit-time tool.
- Not a replacement for Cedar policies. Baselines declare WHICH policy template should be loaded; Cedar policies define the actual authorization rules.
Revisit conditions¶
- If baseline inheritance proves too confusing for users, simplify to single-parent inheritance only.
- If federation negotiation requirements diverge significantly from baseline structure, consider a separate "federation contract" format.
- If the Trails registry (M4) does not materialize, drop
extends = "registry:..."and keep file-based + built-in baselines only.
Alternatives considered¶
-
Extend
trails.tomlwith constraint sections. Rejected. Mixing runtime config and constraints in one file makes both harder to read. Baselines are a separate concern — "what should be" vs. "what is." -
Use JSON Schema to validate
trails.toml. Rejected. JSON Schema validates structure but not semantic constraints (e.g., "SHACL strictness must be closed" or "policy template must be loaded"). Baselines are semantic, not structural. -
OPA / Rego policies on config files. Rejected per ADR-0006 — Cedar is the policy engine. Config validation is not authorization but shares the "declarative constraint" pattern.
-
Helm-style charts for Trails apps. Rejected. Helm solves deployment templating; baselines solve development-time and audit-time config validation. Different problems at different lifecycle stages.
-
Convention-over-configuration (no baselines). Rejected for multi-team / federated / regulated scenarios where conventions need to be machine-verifiable. The
trails:defaultbaseline IS the convention; explicit baselines are for when conventions need teeth.
Dependencies¶
| ADR | Relationship |
|---|---|
| ADR-0006 (Cedar policy) | Baselines reference Cedar policy templates (e.g., template = "hipaa"). The policy presets pattern in trails.policy_presets is the mechanism baselines use to load policies. |
| ADR-0012 (Cost envelopes) | [baseline.agents] constraints (e.g., max_cost_per_run_usd) are enforced by the cost accountant from ADR-0012. |
| ADR-0021 (Progressive enhancement) | Baseline levels follow the additive, no-decision-upfront principle. Level 0 is today's behavior. |
| ADR-0023 (Federation) | Baseline exchange and negotiation build on the federation handshake from ADR-0023 Layer 3. |
| ADR-0025 (Auto-ontology) | Agent-adaptive baselines (Level 4) integrate with onto infer and onto refine to suggest schema section updates. |
| ADR-0026 (Schema transformation) | Enrichment pipelines declared in [baseline.pipeline] tie into the @enrichment decorator from ADR-0026. |