gate-house/docs/adr/ADR-015-engine-is-a-processor.md
tegwick 8698f50706 Record the engine-section amendment against the proposed layer model.
ADR-015 and the doctrine blueprint now point at the assembled section 3.3 text. Accepted v0.8 still governs.

Assistant: grok
Assistant-Session: 01a1609f-72b8-7222-9dff-fae300115e42
2026-10-22 14:34:29 +02:00

7.9 KiB

ADR-015 — Engine as processor and operator use-privilege

Repository: gate-house Status: accepted Date: 2026-10-22 Accepted: 2026-10-22 Revision: 2026-10-22 — a store may serve several engines; an engine enables a capability and is not an access-control mechanism.

Context

The security-layer standard defines an Engine as a deterministic API for a modeled concept. It types that layer into PDP, PIP, Evidence, and Lifecycle. It does not say whether an engine is a library, a command, or a service, or where the records of the concept live.

Repository intents filled that gap in incompatible ways. Some engines describe themselves as the store of their facts. secrets-engine describes itself as a processor over OpenBao: the vault holds the credential records, and the engine turns an already-rendered access decision into a scoped change and a one-shot delivery. The same estate also needs a rule for who may start that process. The process holds credentials the calling operator must not hold. Without a separate use-privilege, "the operator uses the engine" collapses into "the operator receives the engine's credentials," or into the engine deciding for itself who may call it.

A first draft of this ADR also made each engine the only client of its store. That rule is withdrawn. One store can back several capabilities, and each capability can be an engine. Exclusive clientship would turn every engine into a gate on the records.

Decision

An engine is a tool of automation for one capability. It encapsulates the complexity of that capability in a consistent, often simpler interface than doing the work by hand. The same inputs yield the same result. That determinism is what reduces failure modes and what makes the work more reliable and more efficient.

An engine implements its capability from the domain canon. It does not hold the domain's records. Tooling holds the records. Several engines may use one store. Each engine provides a different capability over those records. Being an engine does not make a process the store's only client, and it does not make the engine an access-control mechanism. An engine enables the capability. Restricting who may act remains the domain of access-engine, not a property of engines in general.

The implementation has three manifestations of one library:

  1. Library. The capability: validate, explain, plan, and compute the next state. A caller may use these operations without receiving a store credential.
  2. CLI. The library in a process. At start, the process is injected with the credential for one scoped environment. That credential lets the process reach the inputs and outputs of its capability. It is not returned to the caller.
  3. Service. The same process, kept running for a scoped environment that needs a standing processor. A service is not a second implementation and does not receive the credentials of any other environment.

secrets-engine is the reference shape. OpenBao is the store. The engine enables credential lifecycle as a reliable operation. Another engine may use OpenBao for a different capability. Build, test, and production are different scoped environments and different processes.

Authentication and the operator

An operator is a Staff actor, human or agent, who starts or calls an engine. Authentication, by key-cape, establishes who the operator is. It does not grant use of an engine.

Two privileges stay distinct.

  • The encapsulated privilege is the credential injected into one engine instance at start. It enables that instance to perform its capability. The operator does not possess it, see it, or reuse it outside the process. Holding it inside the process does not turn the engine into a restriction on the store.
  • The use-privilege is permission to start and call one named engine instance, or a named set of instances. access-engine renders that permission. The engine does not decide it and does not become the access control for its store. A use-privilege is not a grant of the encapsulated credential. It is permission to use the enabling interface.

Starting an instance and calling it both require a use-privilege for that instance. The operator who starts it is the operator under whose use the process is injected. One process is injected for one scoped environment.

Delegation between operators

An operator who is allowed to delegate tasks may assign a task to another operator who holds a use-privilege the delegator does not hold. The delegate uses the engine. The delegator does not gain the use-privilege and does not gain the encapsulated credential.

Delegation assigns work. It does not transfer either privilege. The delegate must already hold the use-privilege. Engines stay deterministic, so the enabled operation stays consistent. Operators stay flexible and are expected to be reliable in the work they choose and assign. That reliability is a Staff expectation. It is not a second restriction inside the engine.

Consequences

  • An engine intent that says the running service is the store of record is aligned later: the database, the vault, or the log is Tooling. The engine is a client of that store for its capability. Other engines may be clients of the same store for other capabilities.
  • user-engine, tenant-engine, approval-engine, and the access decision log are enabling processors over records in Tooling. Another engine may use the same records for a different capability. Approval consumption remains the approval capability's own transaction. It is not an exclusive lock on the store.
  • audit-core enables append and verification. The tamper-evident store is Tooling.
  • A Deployment exists when a scoped environment keeps the process running. A one-task environment manifests the same binary as a CLI. Absence of a Deployment does not make the engine incomplete.
  • This ADR selects no database, framework, or hosting technology, and it creates no Gate House runtime surface.
  • Accepted on 2026-10-22. The engine section is assembled into proposed security-layer-model_v0.9 §3.3 (docs/amendments/adr-015-engine-section.md). Accepted v0.8 still governs.

Alternatives rejected

The engine holds the records

Rejected because the layer cut already gives persistence to Tooling. Putting the store inside the engine makes the process the system of record.

Exactly one engine is the client of a store

Rejected because one store can back several capabilities. Each capability is an engine. Exclusive clientship would block a second engine from offering a different interface over the same records, and it would make the first engine a gate.

The engine is the access control for its store

Rejected because an engine enables a capability. It encapsulates complexity so the operation is consistent, reliable, and efficient. Restricting who may act is access-engine's domain. An injected credential does not create a second restriction mechanism.

The operator receives the encapsulated credential

Rejected because the operator would then perform the complex operation by hand. The engine exists so that work goes through the reliable interface. The use-privilege names who may invoke that interface. It does not hand over the store credential.

The engine decides who may use it

Rejected because that decision is an access rule. An engine that renders it takes on an access-control role this ADR withholds from engines in general.

Delegation transfers the delegate's privileges to the delegator

Rejected because assigning a task would then widen the delegator. The delegate already holds the use-privilege. The delegator remains without it.

Library only, or service only

Rejected because the capability, the process boundary, and the standing manifestation are one implementation. Collapsing them either gives callers the store credential inside a library, or forces a Deployment for a one-task environment.