Status: LOCKED at v0.80. Every crate admitted to the Diamond workspace must
comply before passing Gate 12. Patterns distilled from Rust (2015→), Tokio
(0.1→1.x), Deno, Cargo, Serde (9+ years stable), Axum/Tower, Bevy.Canonical source:
docs/architecture/forward-compat-invariants.md.The 8 patterns
FCI-001: Kernel traits upfront, implementations deferred
FCI-001: Kernel traits upfront, implementations deferred
Define traits in Locked traits (v0.90):
nika-kernel at v0.90 for subsystems that ship later.
Default methods return Err(Unsupported) until real implementations land.MemoryStore, EmbeddingProvider, ToolExecutor,
WasmPluginHost, MetricsExporter + TracerProvider + AuditSink +
EventSink + BillingSink, Sandbox. Stubs in src/plugin/, src/infra/.Impact: v0.95 lights up the memory subsystem by adding nika-memory-oxigraph that implements
MemoryStore. Zero v0.90 code modification.FCI-002: #[non_exhaustive] on every public struct, enum, error variant
FCI-002: #[non_exhaustive] on every public struct, enum, error variant
Every public type carries Invariant #19: every
#[non_exhaustive] so adding a field or variant
is always additive. new() constructors provide ergonomic construction
without exposing struct literal syntax.#[non_exhaustive] struct ships a new() constructor.FCI-003: One mark per on-disk artifact
FCI-003: One mark per on-disk artifact
A workflow opens with one header line · A grammar change before 1.0 ships with its migration and a refusal that
names the move (the pre-1.0 stability contract) · after engine 1.0.0 the
grammar is additive only. Non-workflow artifacts (package manifests,
events, the project file) carry their own frozen schema marker.
nika: <name> (the
language name as key, the workflow’s own identifier as value · the
nine-key envelope of 0.109 · supersedes the nika: v1 + workflow: { id } form and the older K8s apiVersion: / schema: nika/workflow@X forms). The document type is the tasks: key: present
= a workflow · absent = the project file nika.yaml, whose mark stays
nika: v1, frozen. Parsers refuse the previous envelope with a clear
error and nika check --fix migrates it.illustration · the envelope mark
FCI-004: Extension namespaces (nika.* core + x-* community)
FCI-004: Extension namespaces (nika.* core + x-* community)
Public schemas reserve two namespaces:
nika.* for core additions
(authoritative, versioned) and x-* for community overlays (no
stability guarantee, no collision with core). Scope note · in the
workflow language both are RESERVED, not current: unknown top-level
fields are rejected at v0.1, and the tool namespace set is closed at
nika: / mcp: (engine-specific tools route through mcp:). The
live x-* surface today is the pck registry.illustration · RESERVED future extension fields (rejected today)
FCI-005: Reserved error code ranges
FCI-005: Reserved error code ranges
Two error surfaces, one rule each. The WORKFLOW-VISIBLE surface is the
spec’s
NIKA-<NAMESPACE>-<NNN> taxonomy ( registered
codes across namespaces ·
reference/error-codes). Namespaces own
001-099 ranges, codes are never repurposed. The ENGINE-INTERNAL
registry (nika_error::codes · NIKA-1000+ blocks per L1 effect
crate) is diagnostics machinery: reserved per crate, never
reassigned, and never leaked into workflow-visible errors.FCI-006: Sealed traits for core, open traits for extension
FCI-006: Sealed traits for core, open traits for extension
Core kernel traits (e.g., Enforced by ADR-014.
Provider, EventSink, Sandbox) are
sealed via a private supertrait: only Nika-owned crates can
implement them. Extension traits (e.g., MemoryStore) are open for
community crates to implement.FCI-007: Feature flags with stable defaults
FCI-007: Feature flags with stable defaults
New capability = new
feature flag, OFF by default. After 1-2 minor
cycles of stability, flips to default-ON. Never remove a default feature
(breaking change): deprecate and redirect.FCI-008: Public API discipline via CI
FCI-008: Public API discipline via CI
Three tools on every CI run:
cargo public-api: detects API surface changes per crate.cargo semver-checks: verifies SemVer compatibility.cargo deny: enforces license + advisories + layer bans.
.public-api.json
snapshots are checked into the repo per crate.The 5 locked decisions (v0.80)
The 10 rules
Every crate admission answers “yes” to each.
cargo public-api +
cargo semver-checks catch violations before merge.- All public types carry
#[non_exhaustive]. - All public structs with
#[non_exhaustive]ship anew()constructor. - All
asynctrait methods usetrait_variant::makefor dynamic dispatch. - All core traits seal via private supertrait.
- All error types expose a
NIKA-XXXcode viaNikaError::code(). - All on-disk schemas carry
schema: "nika/<kind>@<major>". - All DTO fields reserve forward-compat extension slots (see FCI-010).
- All feature flags default to a stable subset: new caps ship OFF.
- All public API changes emit a
cargo public-apidiff in the PR. - All breaking changes require ADR Accepted before merge.
See also
Layer registry
Six layers + L0.5, mechanical sort test, security axes.
L0 foundation decisions
Q1-Q13 locked 2026-04-16: proc macros, kernel prelude, transform crate, memory sinks.
12-gate admission
How a crate earns a seat at the workspace: SPEC through ATOMIC commit.
ADR index
Live ADR counts from the status snapshot.