Certification and Drift
For an introduction to retained assurance, see Getting Started. The Architectural Principles govern that role; Blueprints explains the declarations being assessed, and Schemas explains what structural validation can and cannot prove.
Assurance model
Five ideas must remain distinct:
- Structural validity means an artifact has the permitted machine-readable shape and satisfies mechanically expressible structural rules.
- Semantic accuracy means the artifact truthfully and completely describes the behavior or policy it represents.
- Certification retains mechanical results and semantic review evidence for one exact repository state.
- Currentness means that retained evidence still matches every state and dependency on which it relies.
- Drift is a relevant mismatch that makes the retained assurance suspect; it is not by itself proof that the changed state is wrong.
The lifecycle is:
validate structure -> review meaning -> certify exact state
-> compare current state -> report drift or remain current
Schema validity does not establish semantic truth. Certification combines the mechanical and semantic questions; currentness then determines whether the recorded answer still applies.
Read the remaining contract in four parts:
- Graph and certifiability: nodes, dependencies, structural validity, and semantic completeness.
- Identity of reviewed state: input policy, manifests, Git provenance, node hashes, and facets.
- Retained evidence: certificate payloads, signatures, checks, history, and the certification basis.
- Ongoing assurance: currentness, drift selection, issuance order, and the authority and security boundary.
This document defines the live version-6 certification contract.
Certification is repository-bound. The public certifier requires an explicit reviewed repository and commit and derives the complete certifiable graph from that checkout. Installed-source adapters are read-only drift diagnostics; installing a plugin does not add its modules to the package's certification graph.
Nodes and dependencies
Version 6 has two authored node types:
- A
moduleowns discovery, filesystem authority, contained behavioral sources, and exported interfaces. - A
behavioral_sourceowns one whole-file gateway, content and interface-use envelopes, intrinsic interface contracts, and source dependencies. Each explicit interface claims content and interface-use subsets of those envelopes.
The blueprint graph derives certification dependencies from source use, private-interface use, module-export use, namespace routing, topology proofs, and cross-owner contract references. Containment assigns ownership but adds no certification edge. An edge records the target node and its exact version. A node's local hash does not recursively include dependency bytes; certificates record direct dependency node hashes separately.
Semantic-audit ordering uses a separate neutral projection,
officina.certification-dependency-dag/v1. It contains every module,
behavioral source, and interface facet. In addition to facet-attributed direct
uses, it orders an interface before its owning source, a source before its
owning module, and a child module before its parent. It omits evidence-only
certified-under relations and contains no audit or worker state.
Every authored node has one blueprint. Every behavioral source has one whole-file gateway. A module with discovery also has a whole-file gateway; a dependency-only module may omit discovery. Blueprint declarations are graph authority. Certificates and generated review artifacts report graph state but never add graph edges.
Structural validity and certifiability
A version-6 blueprint may be structurally valid before it is certifiable. Structural validation requires canonical identity, a resolvable whole-file gateway, containment and relationship shape, safe paths, and closed shapes for every semantic value that is present. It does not manufacture semantic facts or assert that an interface is complete.
Structural validation does not invent permissive argv rules, generic success outcomes, or other guessed defaults merely to satisfy a schema. Missing descriptions, contract sections, invocation details, direct-I/O facts, or compatibility claims are certifier findings.
The certifier-owned workflow reviews such a draft against the gateway and node
content. It may repair the candidate blueprint, but each repair invalidates the
previous review snapshot. The workflow reloads the schema and graph and reruns
all checks until either the blueprint is complete and exact or it reports
failure. The signing core accepts no caller-supplied payload and signs only the
final reconstructed state. No certified, conformant, or draft-status field
is authored in a blueprint; availability is determined solely from a current
certificate.
Resolving node inputs
The certifier loads one project policy from
references/certification-policy/node-hash-policy.yaml
and validates it through the central src/officina/configuration/schema.json.
The certification policy directory
contains the policy and its retained historical contract. The historical
references/certification-policy/node-hash-policy.schema.json remains in the
certification basis for existing records but is not the active runtime
validator. The canonical policy has this shape:
policy_version: 1
path_syntax: gitignore
starting_set: git-tracked-directly-owned-regular-files
rules:
- action: exclude
pattern: "**/*.log"
- action: exclude
pattern: "**/_build/**"
- action: include
pattern: "skills/example-skill/generated/required.json"
require_match: true
The repository policy contains only the canonical exclusions; the final include above illustrates the syntax and is not part of that file.
Input resolution follows these rules:
- Normalize paths relative to the repository root and reject absolute paths, traversal, boundary crossings, symlinks, and special files.
- Start from Git-tracked regular files owned directly by the node.
- Apply policy rules in order using Git-ignore pattern syntax. The last matching rule wins.
- An
includemay add an ignored or untracked regular file only when that file is directly owned by the node. Its optionalrequire_matchdefaults to false; when true, loading the project policy fails if the rule matches no eligible file anywhere in the repository. Anexcludecannot declarerequire_match; an unmatched exclusion is a no-op. - Add the mandatory closure: the blueprint, gateway, and the transitive same-owner authored contracts referenced by them. A policy exclusion that removes a mandatory input is an error. A referenced contract owned by another node becomes a dependency instead of a local input.
Content regular expressions continue to express authored ownership. They are not ordered hash rules and do not replace the project policy.
The following inputs are forbidden regardless of project policy:
- current certificates and certificate histories;
- signing material;
- any other reserved certifier output.
The canonical policy explicitly excludes logs, log/ and logs/, Python
bytecode and __pycache__/, .pytest_cache/, .cache/, _build/, build/,
dist/, and .certificates/. A later include may deliberately restore an
eligible runtime or generated regular file, but it cannot override mandatory
closure or reserved-output safety.
Manifest, Git provenance, and node hash
The resolved input_manifest records each selected repository-relative
path, its sha256 digest, and git_provenance: tracked, ignored, or
untracked. It does not record policy-internal details such as a final rule.
At issuance, all tracked manifest entries and tracked blueprint data must match
the certificate's source_commit. Included ignored and untracked files are
signed local-state claims: their exact bytes must remain stable while
certification runs, but they need not be committed. Consequently,
source_commit records the snapshot needed to reproduce the tracked subset
when a certificate includes local inputs. Later currentness requires relevant
tracked inputs to be clean at current HEAD, but does not require current
HEAD to equal the certificate's issuance commit.
For a version-6 behavioral source, each explicit interface has a local hash
covering its canonical declaration and selected input manifest. Unclaimed
source state forms a remainder facet. node_hash(x) aggregates the remainder
and sorted interface local hashes. It excludes certificates, history, generated
status artifacts, and dependency content. Changing an interface input changes
that interface facet and the aggregate source hash; changing unclaimed input
changes the remainder and aggregate. Changing only a dependency makes the
owning facet suspect through its dependency claim without changing its local
hash or the aggregate source hash.
Certificate format
references/blueprint-schema/certificate.schema.json defines a closed envelope:
payload:
certificate_schema_version: 3
subject:
id: example-skill._rtx.source.runtime
node_type: behavioral_source
version: 1
blueprint_path: skills/example-skill/_rtx/blueprints/runtime.yaml
gateway_path: skills/example-skill/_rtx/runtime.py
node_hash: sha256:...
source_commit: ...
input_manifest:
- path: skills/example-skill/_rtx/runtime.py
digest: sha256:...
git_provenance: tracked
dependencies: []
facets:
- id: example-skill._rtx.source.runtime
type: remainder
local_hash: sha256:...
input_manifest: []
dependencies: []
- id: example-skill._rtx.source.runtime.interface.run
type: interface
local_hash: sha256:...
input_manifest:
- path: skills/example-skill/_rtx/runtime.py
digest: sha256:...
git_provenance: tracked
dependencies: []
certification_basis_hash: sha256:...
certifier:
interface: node-certify._rtx.interface.certify
version: 2
node_hash: sha256:...
source_commit: ...
checks: []
key_id: sha256:...
previous_entry_hash: null
certified_at: 2026-07-20T12:00:00Z
signature:
scheme: ed25519
value: base64:...
The signature covers the canonical encoding of payload. The schema does not
freeze the signature algorithm, but the scheme is explicit and the signature
value is valid base64. certified_at is informational and never establishes
currentness.
Each dependency entry contains relation, target, version, and
node_hash. Version-6 dependency relations are uses-source,
uses-private-interface, uses-export, references-cross-owner-contract,
contains-source, routes-child-namespace, and routes-terminal-module. The payload contains
no separate dependency-certificate hash.
Version-6 certificates use payload version 3 and include canonical facet claims. Payload versions 1 and 2 remain readable only as historical formats; they are not current version-6 certification state.
Containment and route topology are certificate dependencies in version 6:
module certificates depend on contained sources, parent namespace routes
depend on the routed child module. A uses-export dependency targets the exact
behavioral source implementing the export. The exporting-module certificate
separately records boundary identity and access without making every consumer
depend on every source in that module. Live dispatcher authorization reads the
relevant blueprints directly and treats certificate currentness as advisory.
The certifier identity contains its exported interface and version, its node
hash, and its source commit. certification_basis_hash is the single digest
for all other certification machinery: the node-input policy, certifier,
schemas, hashing and safety implementation, checks, binding compilers, and
machine evaluators. There is no separate policy, schema, or checker hash in the
certificate. A change to any basis component changes this one digest.
Gateway-language, gateway-machine, runtime-dependency, and platform claims are
audited for blueprint correctness through versioned entries in checks. The
certifier does not test or record the performance, installed versions, or host
availability of those machines and dependencies; ordinary tests own those
questions.
Python route-smoke dependency tracing is another certifier-owned mechanical check. For the stale issuance worklist, each discovered implementation file or invoked interface must map to a directly owned certification input, an explicit certification dependency, or the certification basis. The certifier runs the scoped trace twice before any certificate append and requires the mapped signatures to agree. It records only the passed versioned check. Manifest and node-hash derivation are pure: drift and currentness never execute gateways or rerun route smoke. Nodes already current are neither route-smoked nor appended.
Each node has one append-only certificate log. Every appended complete entry
contains payload and signature, and the signature covers the canonical
encoding of payload only. The first entry has previous_entry_hash: null;
each later entry hashes the canonical complete preceding entry, including its
signature. The last complete valid entry is the current certificate and earlier
entries are history. The chain detects modification, middle-entry removal, and
reordering within retained history. Without an external anchor it cannot prove
that the newest entries were removed.
Currentness and drift
A certificate is current only when all of the following hold:
- its envelope and payload validate and its signature verifies under
key_id; - its subject identifies the current node, and its tracked inputs are clean and
reproducible at HEAD;
source_commitrecords issuance provenance and need not equal the current HEAD; - its input manifest resolves safely and every digest matches current bytes;
- its recorded node hash equals the reconstructed node hash;
- its facet set, local hashes, input manifests, and facet dependency claims exactly match the reconstructed facets;
- its dependency set exactly matches the derived direct dependencies, every target version and hash matches, and every ordinary recursive dependency certificate is current;
- for a certifier-bearing schema-v6 graph, its
certified-underinterface dependencies exactly match the current mechanical certifier and the semantic audit interface for each module, source remainder, or interface facet; generic graphs without structured evidence retain the aggregate certifier identity check; - its
certification_basis_hashequals the current basis hash; - its signed checks exactly match the current versioned check registry and all are recorded as passed without findings;
- its history link agrees with the retained preceding entry.
A missing or malformed field, signature, dependency, or input makes the node suspect. A suspect certificate is retained. It becomes current again without reissuance if all currentness conditions later return to the recorded values. Reissuing an unchanged certificate does not change the node hash or semantic interface projections.
Drift projects these comparisons into an exact stale worklist. For interface
and remainder facets it distinguishes local-hash, input-manifest, and direct-
dependency mismatches. Input-manifest causes name added, removed, and changed
files. Dependency causes cover all direct facet dependencies: interface uses
name the interface id, while other relations name their relation and target.
The evidence-only certified-under relation identifies the exact mechanical,
interface-audit, source-audit, or module-audit interface whose hash changed;
it participates in hash comparison and drift reporting but not recursive
currentness, cycle, postorder, or route-smoke traversal. Old or partial v6
certificates report missing structured dependencies and require recertification;
there is no compatibility fallback to the certifier module hash.
Certificate, basis, graph, or other non-facet concerns remain node-scoped. This
worklist is diagnostic evidence for selective bottom-up semantic review, not
authority to sign.
In dependency-first pseudocode:
is_current(x):
certificate = read_current_certificate(x)
return (
valid_signature(certificate)
and safe_manifest_matches(certificate.payload.input_manifest)
and certificate.payload.node_hash == node_hash(x)
and certificate.payload.facets == current_facet_claims(x)
and certificate.payload.dependencies == current_dependency_claims(x)
and all(is_current(d) for d in recursive_direct_dependencies(x))
and project_certifier_identity(certificate.payload.certifier, x)
== project_certifier_identity(current_certifier_identity(), x)
and certificate.payload.certification_basis_hash
== current_certification_basis_hash()
and certificate.payload.checks == expected_passed_checks()
and valid_history_link(certificate)
)
recursive_direct_dependencies excludes certified-under evidence. For a
certifier-bearing schema-v6 graph, project_certifier_identity excludes the
aggregate certifier node hash because the structured interface records carry
that identity.
When drift exists, certification uses the stale worklist for selective
bottom-up semantic review. Exact interface drift selects that interface, its
source, and module ancestors; remainder drift selects its source and module
ancestors; an unattributed stale source conservatively selects all its
interfaces. A sole mechanical certified-under change selects no semantic
task. An unchanged facet reuses evidence only when its claim is authenticated
by the latest valid signed certificate and still matches canonical state. The
signature covers the facet manifest and dependencies plus the certificate's
whole-node semantic-review pass. Selective reuse interprets that pass as
covering each included unchanged facet; it is not an independent per-facet
semantic attestation.
Code, not the orchestrating LLM, traverses this graph. The
node-certify._rtx.interface.semantic-audit-scheduler keeps one locked run
state and returns only dependency-ready task IDs, kinds, bounded input-file
handles, and counts. Each input identifies the exact repository and assigned
vertex without exposing the full DAG. The orchestrator fills a bounded pool
with one fresh subagent per task, submits each exact
node-certify.semantic-audit-result/v1 report, and refills available slots.
Workers audit only their assigned vertex; they must not recursively audit,
schedule, or delegate dependencies. Missing or inconsistent prerequisite
evidence produces abort, and any malformed, rejected, aborted, lost, or
failed task terminates the run before signing.
Only a scheduler-complete run reaches the mechanical certifier. The mechanical certifier then independently reloads current repository state, skips current nodes, route-smokes the stale issuance worklist, and issues certificates dependency-first. Semantic scheduling therefore reduces LLM context without weakening final freshness checks.
Selectivity applies only while certification_basis_hash matches. Because the
aggregate hash does not identify which basis input changed, a basis mismatch
remains semantically invalidating until the separate node/interface-only basis
migration. Semantic audit instruction-body changes are the current localized
case; basis-listed mechanical, gateway, blueprint, hashing, and view inputs
remain global.
After each repair the certifier discards the prior review snapshot, reloads the
blueprint and graph, and reruns the checks. It then recomputes currentness,
skips nodes already current, route-smokes the remaining stale worklist, and
issues those nodes dependency-first. Only after discrepancies are resolved does
it reconstruct the manifest, node hash, dependencies, basis hash, and checks
internally, sign the canonical payload, append the complete signed record, and
verify the append before reporting success. Runtime performance and host
availability remain outside certification. The certifier never signs a
caller-supplied certificate payload.
Authority and security boundary
node-certify is the sole supported writer for blueprint repair,
certificate signing, and the append-only certificate log. node-drift is
read-only and verifies through the public-key path.
No broker, service identity, second writer, or parallel signing route is
introduced. Atomic no-follow writes, user-only permissions, history, and
post-write verification remain defense in depth.
Secure atomic writes are the default. A caller may explicitly opt into the existing non-atomic fallback when the host cannot provide the secure primitive; the certifier never selects that fallback silently.
Dispatcher authorization is independent of certificate currentness. If a preverified in-memory status view is available, dispatcher consults only the caller ancestry, crossed target namespaces, terminal module, and implementing source and emits bounded diagnostics. Missing, stale, expired, malformed, or unavailable status is warning-only: it cannot grant authority, deny an otherwise valid route, trigger certification work, or cause repository reads.
Certification workflows retain their own fail-closed rules. In particular, self-certification may resume only from empty history or a canonical, signature-valid, unbroken dependency-first prefix of the exact closure. Corrupt history, a non-prefix gap, a wrong-subject entry, or missing verification material blocks certification even though it does not block an otherwise authorized dispatcher route.
This is a cooperative same-user contract, not filesystem isolation between same-UID processes. A malicious process running as the same OS user may access signing material or certificate outputs. Signatures and currentness detect drift, corruption, and changes outside the supported writer contract; they do not defend against that attacker.