docs: deployment mode and conversion contract (S2 contract 6)
ci/woodpecker/pr/ci Pipeline was canceled

This commit is contained in:
fred
2026-08-26 18:58:12 -05:00
parent 49b7943420
commit be32b693d0
+165
View File
@@ -0,0 +1,165 @@
# Deployment Mode and Conversion Contract (D3)
Status: DRAFT — awaiting ratification (webui-audit S2, contract 6 of 9).
Authority: PRD D3 (Part I §3) — two modes chosen at install time,
Standalone and Enterprise, with the mode table (brains, user-data
isolation, secrets, conversion); Standalone → Enterprise conversion is
**one-way** and Enterprise is a **terminal state**. PRD D14 (Part I §7)
— the per-user brain split is optional in Standalone and keeping it is
the recommended default because it preserves forward-compatibility with
the one-way conversion. PRD D11 (Part I §9) — v1 ships the Standalone
flow only; Enterprise conversion is explicitly deferred. PRD D3
federation clause — federation is intentionally not fully designed,
deferred, and nothing in v1 may foreclose it.
This contract binds the mode as a canonical platform property (§2), the
per-mode obligations and which contract owns each (§3), the conversion
transition (§4), the v1 non-foreclosure obligations (§5), and their
witnesses (§6). Domain semantics stay with their owning contracts:
wizard mode choice and branching (contract 3 §2), identity/SSO
(`identity-lifecycle.md`), custody and per-user brain mechanics
(contract 7), tool mapping (`tool-gateway-mapping.md`).
## 1. Definitions
1. **Mode**: the platform-wide deployment mode, exactly one of
`standalone` or `enterprise`. The vocabulary is closed in v1;
extension (e.g. a federation mode) is by amendment to this contract,
never ad hoc.
2. **Conversion**: the one-way transition `standalone → enterprise`.
No other mode transition exists.
3. **Conversion preconditions**: the verifiable conditions of §4.2 that
must all hold before the mode record may change.
## 2. Mode is a canonical recorded property
1. Mode is recorded canonically in the platform database at bootstrap,
as the explicit operator choice contract 3 §2.3 requires. It is
never derived from feature state (presence of Vault, count of
brains, count of users), and no component may infer a different
mode than the record states.
2. The record is readable through the Gateway (and CLI, D8) by any
authenticated user; components branch on the read value only.
3. The record is immutable except by the §4 conversion transition.
Editing it by direct database access, config file, environment
variable, or wizard re-run is non-conformant (contract 3 §2.3:
changing mode later is conversion, not a wizard re-run).
## 3. Per-mode obligations (owner map)
The PRD mode table binds four rows; this contract assigns each an
owning contract so no obligation is unowned and none is bound twice:
| Obligation | Standalone | Enterprise | Owner |
| ------------------- | -------------------------------------- | -------------------------------------------------- | --------------------------------------------- |
| Brains | one mosaic-brain (system + user files) | system brain for config + one brain per user | contract 7 (custody/brain mechanics) |
| User-data isolation | single user | no user-data leakage between users; sharing opt-in | contract 7 (enforced by architecture, D14) |
| Secrets | OpenBao/Vault or flat files | OpenBao/Vault REQUIRED | this contract (§4.2 gate; steady-state check) |
| Conversion | may convert to Enterprise, one-way | terminal state | this contract (§4) |
In Enterprise steady state, a flat-file secrets backend is
non-conformant; the platform refuses to start Enterprise-mode
components against a flat-file secrets configuration (fail-closed, not
warn-and-run).
## 4. Conversion transition
1. **Direction and terminality.** The only transition is
`standalone → enterprise`. `enterprise → standalone` does not exist:
there is no command, no admin override, and no support path. An
attempt is refused with the precondition/state error class of the
command envelope (`tool-gateway-mapping.md` §4.2).
2. **Preconditions (all verified before the record changes):**
- Secrets: OpenBao/Vault is configured and reachable, and no
required secret is served from a flat-file backend. Secret
migration completes before conversion; this contract does not
define the migration tooling, only the gate.
- Brains: the per-user brain split required by the Enterprise row of
§3 is established for every existing user (or the deployment
already kept the split, the D14 recommended default). Brain
partitioning mechanics are contract 7; this contract binds only
that the split is complete before the mode flips.
- Identity: at least one platform administrator account exists and
the identity contract's registration controls are in a
deliberately chosen state (`identity-lifecycle.md` §2) — recorded
as re-affirmed at conversion, since Enterprise changes their
consequences.
3. **Atomicity of the flip.** The mode record changes in one
transaction, only after every §4.2 precondition verifies. An
interrupted or failed conversion leaves the record `standalone` and
the platform fully operational in Standalone semantics; there is no
intermediate mode and no half-converted state observable through
the record. Preparatory work (secret migration, brain partitioning)
is re-runnable and may complete across multiple attempts, in the
same at-most-once, keyed style contract 3 §4 binds for wizard
seeding.
4. **Authority and audit.** Conversion is a platform-administrator
command carrying an explicit irreversibility acknowledgment in its
request. It is an official Gateway/CLI command (D8): when built, it
is added to the tool↔Gateway mapping by amendment
(`tool-gateway-mapping.md` §3.3). The transition emits an audit
event (actor, prior mode, new mode, precondition evidence
reference) in the same transaction as the record change; the event
survives indefinitely.
## 5. v1 obligations (non-foreclosure)
v1 ships Standalone only (D11); the conversion command is deferred
work. v1 still MUST:
1. Record the mode per §2 (the wizard already binds the choice,
contract 3 §3.2) with `enterprise` a reserved, refused value for
bootstrap — v1 bootstrap accepts `standalone` only.
2. Keep the §2.3 immutability rule: no v1 surface mutates the mode
record.
3. Not foreclose conversion: v1 data layouts follow the custody
contract's pointer/consent structure (contract 7) so the per-user
brain split remains establishable, matching the D14 recommendation.
4. Not foreclose federation: the closed mode vocabulary is extensible
by amendment, and no v1 component may treat the mode enum as
exhaustive in a way that fails closed against a future added value
at parse time (unknown mode values are a refused configuration, not
undefined behavior).
## 6. Verification requirements
Binding on the implementing PRs:
1. **Mode-record witness (v1):** the mode is readable via Gateway and
CLI after bootstrap and equals the wizard-recorded choice;
bootstrap with mode `enterprise` is refused; no other write path to
the record exists (covered by a writer assertion in the style of
contract 1 §6.3, scoped to the mode record).
2. **Immutability witness (v1):** every mutation surface shipped in v1
leaves the mode record unchanged (asserted over the Gateway
command inventory); direct-write attempts through shipped code
paths do not exist.
3. **No-downgrade witness (conversion milestone):** with mode
`enterprise`, a conversion request to `standalone` (and any crafted
mode-write) is refused with the precondition/state error class and
no record change.
4. **Precondition witnesses (conversion milestone):** conversion with
(a) an unreachable Vault, (b) a required secret still flat-file
backed, or (c) an unpartitioned user brain is refused with no
record change and no partial mode effect.
5. **Interruption witness (conversion milestone):** fault injection
aborting conversion after preparatory work leaves the record
`standalone`, the platform operational, and a re-attempt able to
complete without duplicating prepared state.
6. **Audit witness (conversion milestone):** a completed conversion
has exactly one audit event, same-transaction with the record
change; a failed attempt has a refusal event and no mode-change
event.
## Ruling request
Ratify sections 16 as written, with one decision embedded:
- Decision (§5): v1 implements the **mode record and its immutability
only** — bootstrap records `standalone`, the `enterprise` value is
reserved and refused, and the conversion command itself is deferred
to the Enterprise milestone, consistent with D11's deferred list.
Alternative if rejected: build the conversion command inside v1 —
rejected because D11 scopes v1 to the Standalone slice and
conversion depends on contract 7 custody mechanics that are
themselves not in the v1 slice.