Add the OpenSpec proposal, design, tasks, and requirements for an app-ensured tenant resolved by natural key instead of configured UUIDs. Align FedWiki, entitlement, and provider lifecycle specs around active and non-active site states, and record related operator UX follow-ups.
4.2 KiB
provider-lifecycle-contract
Purpose
Defines the lifecycle contract every provisioning provider conforms to: the set of mutating and read operations a provider may declare support for, and the division of ownership whereby the console owns intent and aggregate facts while the provider owns canonical per-instance state.
Requirements
Requirement: A provider declares the lifecycle operations it supports
The lifecycle contract SHALL comprise the operations create, set_status, and delete, and a read class of list and describe. create provisions a new instance and delete permanently (irreversibly) removes one; set_status moves an existing instance between the lifecycle states the provider declares (see "A provider declaring set_status declares its lifecycle state set"). Each provider SHALL declare which operations it supports via provider_operations. An operator or system action for a given operation SHALL be offered only for providers that declare support for it. Every provisioning provider SHALL declare at least one read operation so its instances can be enumerated.
Scenario: Provider declares its supported verbs
- WHEN a provisioning provider is registered
- THEN
provider_operationsSHALL record the operations it supports from{create, set_status, delete, list, describe} - AND the set SHALL include at least one read operation (
listordescribe)
Scenario: Action gated on declaration
- WHEN a provider does not declare
set_status - THEN no status-change action (read-only, archive, restore) SHALL be offered for that provider
Requirement: The console owns intent; the provider owns canonical per-instance state
Canonical per-instance state SHALL live provider-side. The member-console SHALL own intent and aggregate facts — resource counts, limits, and requested operations. The console MAY maintain an observed projection of per-instance state (a cache refreshed from the provider's read class) for display, reconciliation, and provenance, provided the provider remains the canonical source of truth and the projection is never treated as authoritative over the provider.
Scenario: Console stores intent and an observed projection, provider stays canonical
- WHEN a downgrade requests that an instance become read-only
- THEN the console SHALL record the intent and the limit
- AND the console MAY record an observed per-instance status as a projection
- AND the provider SHALL remain the canonical source of truth for that status
Scenario: The observed projection is refreshed via the read class
- WHEN the console reconciles per-instance state
- THEN it SHALL refresh its observed projection from the provider's
list/describe(the read class) - AND it SHALL NOT treat the projection as an independent source of truth that can diverge from the provider unreconciled
Requirement: set_status moves an instance between provider-declared states
The set_status operation SHALL move an instance to a target state drawn from the provider's declared state set. The active state SHALL be the implicit baseline that every provisioning provider supports. Non-active states (e.g. readonly, archived) SHALL be reversible — set_status SHALL be able to return an instance to active. set_status to a state the provider does not declare SHALL be refused. delete is terminal and distinct from the reversible state machine — it is not a set_status target.
Scenario: Transition to a declared state
- WHEN
set_status(readonly)is requested for an instance of a provider that declares thereadonlystate - THEN the provider SHALL move the instance to
readonly
Scenario: Transition is reversible back to active
- WHEN
set_status(active)is requested for an instance currentlyreadonly - THEN the provider SHALL return the instance to
active
Scenario: Transition to an undeclared state is refused
- WHEN
set_status(suspended)is requested for a provider that does not declare asuspendedstate - THEN the request SHALL be refused
Scenario: Delete is not a status target
- WHEN an instance is deleted
- THEN removal SHALL occur via the terminal
deleteoperation, not viaset_status