diff --git a/ArchitectureBlueprint.md b/ArchitectureBlueprint.md index 968e942..3e2d722 100644 --- a/ArchitectureBlueprint.md +++ b/ArchitectureBlueprint.md @@ -107,30 +107,34 @@ Two boundaries are lexical as well as architectural: ### 2.2 Engine -An engine is the deterministic processor for one domain, as proposed in -[ADR-015](docs/adr/ADR-015-engine-is-a-processor.md). The canon states the -domain. The engine implements it. Tooling holds the records. The engine owns -the record type and is the only admitted client of its store. +An engine is a tool of automation for one capability, as proposed in +[ADR-015](docs/adr/ADR-015-engine-is-a-processor.md). 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, which reduces +failure modes and makes the work more reliable and more efficient. The canon +states the domain. The engine implements the capability. Tooling holds the +records. Several engines may use one store, each for a different capability. -One library has three manifestations. The library performs the domain -operations. The CLI runs that library in a process. A service is the same -process kept running for one scoped environment. At start, that process is -injected with the credential for that environment alone. The credential is how -the process reads its inputs and writes its outputs. Callers do not receive it. +An engine enables that capability. It is not an access-control mechanism. +Restricting who may act remains access-engine's domain. + +One library has three manifestations. The library performs the capability. +The CLI runs that library in a process. A service is the same process kept +running for one scoped environment. At start, that process is injected with +the credential for that environment alone. The credential enables the +capability. Callers do not receive it. An operator is a Staff actor who starts or calls an engine. Authentication establishes who the operator is. Permission to use one named instance, or a -named set of instances, is an access rule rendered by access-engine. The -engine enforces that result and does not decide it. Holding the use-privilege -does not confer the injected credential, and it does not authorize every -operation the domain can perform. The engine still applies its deterministic -rules to each call. +named set of instances, is an access rule rendered by access-engine. Holding +that use-privilege does not confer the injected credential. The engine does +not decide the permission and does not become a gate on the store. An operator who is allowed to delegate may assign a task to another operator who is allowed to use an engine the delegator cannot use. The delegate uses the engine. The delegator does not gain that use-privilege or the injected -credential. Engines stay stringent. Operators stay flexible. An operator's -reliability does not relax an engine check. +credential. Engines stay deterministic. Operators stay flexible and are +expected to be reliable in the work they choose and assign. Until ADR-015 is accepted, this section records the proposed doctrine. The security-layer standard is amended only after acceptance. @@ -366,9 +370,11 @@ not cause another component to invent authority or silently substitute a broader credential. The credential injected into an engine instance is that instance's -encapsulated privilege, defined in §2.2. It authorizes the process toward its -store for one scoped environment. It is not the operator's authority to use -the instance, and it is not issued to the operator. +encapsulated privilege, defined in §2.2. It enables that capability against +its store for one scoped environment. Another engine may hold a different +credential to the same store for a different capability. The injected +credential is not the operator's authority to use the instance, and it is not +issued to the operator. ## 10. MCP and tooling doctrine @@ -742,7 +748,7 @@ return path. | ADR-010 | Still meaningful — Autonomous mandate model. | | ADR-013 | Still meaningful — MCP authorization integration. | | ADR-014 | Still meaningful — policy self-modification protection. | -| ADR-015 | Proposed — an engine is a processor; an operator's use-privilege is separate from the credentials injected into the instance. | +| ADR-015 | Proposed — an engine enables one capability over Tooling; several engines may share a store; an operator's use-privilege is separate from the credentials injected into the instance. | Future ADRs in Gate House decide doctrine and responsibility boundaries. They must not select an Engine's implementation technology or create a Gate House diff --git a/docs/adr/ADR-015-engine-is-a-processor.md b/docs/adr/ADR-015-engine-is-a-processor.md index 254e252..29287cb 100644 --- a/docs/adr/ADR-015-engine-is-a-processor.md +++ b/docs/adr/ADR-015-engine-is-a-processor.md @@ -3,6 +3,7 @@ **Repository:** gate-house **Status:** proposed **Date:** 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 @@ -21,28 +22,44 @@ 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 deterministic processor for one domain. It implements that -domain from its canon. It does not hold the domain's records. Tooling holds -the records. The engine owns the record type: the schema, the invariants, and -the legal transitions. It is the only admitted client of its store. +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 domain operations: validate, explain, plan, and compute - the next state. A caller may use these pure operations without receiving a - store credential. +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 - read its inputs and write its outputs. It is not returned to the caller. + 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 is -the lifecycle processor. Build, test, and production are different scoped -environments and different processes. +`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 @@ -53,16 +70,15 @@ not grant use of an engine. Two privileges stay distinct. - The **encapsulated privilege** is the credential injected into one engine - instance at start. It is how that process reads its inputs and writes its - outputs. The operator does not possess it, see it, or reuse it outside the - process. + 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 enforces the rendered result and does not decide it. - A use-privilege is not a grant of the encapsulated credential, and it is not - permission for every operation the domain can perform. The engine still - applies its own deterministic rules to each call, including any decision - record that domain requires. + 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 @@ -76,22 +92,24 @@ 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. The assignment cannot widen what the -delegate is allowed to do, and it cannot authorize an operation the engine's -own rules refuse. Engines stay deterministic and stringent. Operators stay -flexible. Reliability of an operator is a Staff expectation. It does not relax -an engine check. +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, and the - engine remains the only admitted client and the owner of the record type. + 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 processors over records in Tooling. Approval consumption remains one - transaction that the engine opens against its store. A user or tenant fact - remains readable only through the engine. -- `audit-core` appends and verifies. The tamper-evident store is Tooling. + 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. @@ -105,18 +123,33 @@ an engine check. ### 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 and invites -every other engine intent to do the same. +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 could then bypass the processor and call Tooling -directly. That is the failure the use-privilege exists to prevent. +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 -becomes a second policy decision point. +takes on an access-control role this ADR withholds from engines in general. ### Delegation transfers the delegate's privileges to the delegator @@ -125,7 +158,7 @@ delegate already holds the use-privilege. The delegator remains without it. ### Library only, or service only -Rejected because the domain implementation, 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. +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.