What it is
The Runtime Pipeline is the ordered sequence of checks and steps aBusinessTransaction
passes through, from arrival to a signed ExecutionTrustRecord. Its center is
RuntimeEngine.execute() (packages/runtime/src/RuntimeEngine.ts), a single method that
loads a policy, runs every configured pre-authorization protection in a fixed order,
evaluates the policy, builds a Decision, signs an ExecutionAuthorizationPayload if
approved, and hands the result to two further pipelines (RuntimePipeline for execution,
BusinessTrustPipeline for the final trust record). Everything downstream of a request
being accepted runs through this one method.
Why it was built
A system that authorizes real-world actions needs one place where every protection is guaranteed to run, in a guaranteed order, with no way for a caller or a misconfigured deployment to skip a step silently.RuntimeEngine is that place. Its own class doc comment
states its responsibilities directly: load the requested policy, evaluate it deterministically,
create the Decision artifact, create the initial Execution artifact, execute the Runtime
Pipeline, and produce the ExecutionTrustRecord. Most of the protections wired into it
(signal-intent binding, capability/policy binding, signal-state verification, policy
governance verification) were added incrementally, each as an optional, trailing
constructor parameter, specifically so every pre-existing call site keeps compiling and
behaving identically when a new protection is introduced. This is a deliberate, repeated
pattern in this codebase, not an accident of growth.
How it works
RuntimeEngine’s constructor takes ten required dependencies (RuntimePipeline,
PolicyRouter, PolicyEngine, SignalIntentBinder, DecisionBuilder, ExecutionGate,
ExecutionBuilder, BusinessTrustPipeline, RuntimeAuthorizationSigner,
authorizationTtlSeconds) and seven optional trailing ones (hooks,
refusalRecordBuilder, refusalRecordRepository, signalStateVerifier,
capabilityPolicyBinder, policyExecutionVerifier, policyGovernanceAnchorResolver).
At construction, it logs which optional protections are actually configured
(runtime_engine_constructed), which is how an operator can confirm, from log output alone,
exactly which protections are active for a given deployment.
execute(transaction) runs these steps, in this exact order (comments quoted verbatim from
RuntimeEngine.ts):
- Policy load.
policyRouter.load(transaction.policy.name, transaction.policy.version).beforePolicyLoad/afterPolicyLoadhooks fire around this. - Policy content hash (G-24).
policyContentHash = policyContentHasher.hash(policy), computed from the actually loaded policy document, never from what the caller declared, using the sameTrustRecordHasher(canonicalize, then SHA-256) every other content hash in this codebase uses. - Policy Governance evidence anchor (G-45). If
policyGovernanceAnchorResolveris configured, it resolves whether this policy has a valid, matching approval record. Purely evidentiary, a resolver error is caught and logged, never allowed to affect the real outcome. - Policy Governance execution-time verification. If
policyExecutionVerifieris configured, it checks the same approval-record question, but this one can reject: “a policy with no approval record, an approval record whose signature does not verify, or live content that no longer matches its approval record is rejected beforePolicyEngineever evaluates a single rule in it.” - Capability/Policy binding (TD-22). If
capabilityPolicyBinderis configured and step 4 found no violation, it checks whether the invoked capability has a canonical policy binding and, if so, whether the declared policy matches it. Runs before signal-intent binding “for the same reason capabilityPolicyBinder runs before signalIntentBinder: checking a narrower guarantee against an already-wrong policy is meaningless.” - Signal-intent binding. If steps 4 and 5 found no violation,
signalIntentBinder.findViolations(policy, signals, {target, parameters})checks that everyboundSignalsentry actually matches the real Intent’s target/parameters. - Policy evaluation. If none of steps 4 through 6 rejected,
policyEngine.evaluate(policy, signals)runs the real rules. Any rejection from steps 4 through 6 becomes a syntheticPolicyDecisionwithoutcome: REJECT,evaluatedRules: 0, no rule is ever evaluated for a request that fails an earlier check. - Signal-state verification (G-24 residual closure, RFC-0022). Only runs if the
provisional decision is
APPROVE, “a request already rejected… needs no independent re-fetch of real state.” IfsignalStateVerifieris configured, it independently re-derives the declared facts from a real external source; a mismatch overrides the decision toREJECT. - Decision.
decisionBuilder.build(transaction, policyDecision). - Refusal Record (RFC-0021). If the decision is not
APPROVED, aRefusalRecordis built and persisted, but this write is explicitly never allowed to affect or block anything downstream; a failure here is only logged (refusal_record_write_failed), the method quote: “The refusal itself must never depend on its own evidence being writable.” - Enforce.
executionGate.enforce(decision), this is the actual gate; aREJECTthrows here and nothing past this point runs for a rejected transaction. - Authorization. Only reached on
APPROVE.signalsHashis computed, thenauthorizationSigner.sign(...)produces theSignedExecutionAuthorization(Chapter 9 covers this envelope’s exact fields). - Execution + Runtime Context.
executionBuilder.build(...)and theRuntimeContextare assembled, the context carries a copy oftransaction.policyaugmented withcontentHashand, if resolved,governanceAnchor; the original caller-submitted transaction (already persisted before this method ever ran) is never mutated. - Runtime Pipeline, then Business Trust Pipeline.
pipeline.execute(context)runs the actual execution stages (Chapter 10 coversExecutionGateway, one implementation of theExecutionSysteminterface this pipeline calls into);trustPipeline.execute(...)produces the final, signedExecutionTrustRecord.
RuntimeFactory.create() (packages/runtime/src/RuntimeFactory.ts) is the composition root
that assembles a fully wired RuntimeEngine (via RuntimeBuilder) plus the surrounding
ExecutionTrustApplication (transaction/execution/verification/receipt services). It takes
the same optional protections as trailing parameters and only wires them into RuntimeBuilder
when supplied (if (signalStateVerifier) { builder.withSignalStateVerifier(...) }), the same
“absent means unconfigured, not broken” discipline as the constructor itself.
How it enables things, with examples
examples/tutorials/03-runtime-execution, the baseline: a transaction throughRuntimeEngine.execute()to a trust record, no optional protections.examples/tutorials/16-runtime-pipeline, the pipeline stages themselves.examples/tutorials/18-runtime-hooks, theRuntimeHookinterface (beforePolicyLoad,afterDecision, etc.) that lets an integrator observe or extend the pipeline without modifyingRuntimeEngineitself.examples/tutorials/19-runtime-composition, composing multiple pipeline stages.examples/tutorials/15-custom-runtime-component, writing a custom pipeline stage.
How to validate this yourself
packages/runtime/src/RuntimeEngine.ts, the method itself; every ordering claim above is a direct comment in this file.packages/runtime/src/RuntimeFactory.ts,RuntimeBuilder.ts, how aRuntimeEngineactually gets constructed for a real deployment.packages/runtime/tests/e2e/runtime.e2e.test.ts, end-to-end proof, including the G-24 content-hash-at-decision-time assertion against real on-disk policy content.packages/runtime/tests/unit/optional-protections-logging.test.ts, proves the construction-time log line accurately reflects what’s wired.packages/runtime/tests/integration/runtime.integration.test.ts, the fuller integration surface.
Integration requirements
None beyond what Chapter 2 (Configuration and Bootstrapping) already covers,RuntimeEngine
itself takes no environment variables directly; every dependency it needs is constructed and
passed in by RuntimeFactory/application.ts. The optional protections
(signalStateVerifier, capabilityPolicyBinder, policyExecutionVerifier,
policyGovernanceAnchorResolver) each have their own configuration surface, covered in the
chapters specific to them.