Files
shard-wiki/spec/adr/ADR-0001-engine-activation-via-feature-control.md
tegwick cdcf4b09aa adr: ADR-0001 engine activation via feature-control (OpenFeature, availability-only)
Records the accepted decision: shard-wiki's native engine uses feature-control via
OpenFeature for per-shard extension activation (availability only, never authz),
provider-pluggable with a LocalProvider standalone default (mirrors the identity
ladder), at the engine layer, consuming the mature feature-control.evaluate slice.
Adds spec/adr/ series + README; hub decision abf7830f recorded.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15 23:48:49 +02:00

80 lines
4.7 KiB
Markdown

# ADR-0001 — Engine extension activation via feature-control (OpenFeature)
Status: **Accepted** · Date: 2026-06-15 · Deciders: tegwick · Source: SHARD-WP-0013 follow-up
(feature-control assessment)
> First repo-level ADR. (Note: `FederationRequirements.md` contains document-internal
> "ADR-01…06" design notes — those are scoped to that spec; this `spec/adr/` series is the
> repository's standalone architecture decision log, starting here.)
## Context
`WikiEngineCoreArchitecture.md` (SHARD-WP-0013 T5) defines the engine as a small kernel plus a
**typed-extension framework** where each shard **activates only the extensions it needs**
(invariants E-4 activation, E-8 reuse-not-reinvent). It needs a mechanism to decide, per shard
(and per tenant/context), which extensions/features are active — without baking a bespoke flag
system into the engine, and without breaking the **standalone, zero-external-dependency** L0
posture shard-wiki guarantees.
The helix_forge sibling **`feature-control`** (`capability.feature-control.evaluate`, registered
at **D5 / A4 / C3 / R3**) provides exactly this: an **OpenFeature**-based feature-availability
control plane with a working SDK (`feature_control_sdk`: `FeatureControlClient`, `Resolver`, a
static `LocalProvider`), context-scoped evaluation (`tenant_id`/scope), explainable decisions,
and graceful degradation when OpenFeature is absent. shard-wiki already proposed this as a T3
*consumption* (reuse, don't rebuild).
## Decision
**Adopt `feature-control` (via the OpenFeature standard) as the engine's per-shard extension/
feature activation mechanism** — *availability only* — with these constraints:
1. **OpenFeature-shaped, provider-pluggable.** The engine evaluates activation through an
OpenFeature-style client. A static **`LocalProvider`** is the **standalone/L0 default**
(zero external dependency); a `feature-control`/remote provider is plugged in for governed
deployments. This mirrors shard-wiki's existing **identity-provider ladder** (null/local
default → external when present).
2. **Availability ≠ authorization.** feature-control decides *which extensions are active*,
never *who may read/write*. Authorization stays in core (X-AUTHZ / `authorization.policy-
evaluate`). The two are composed but never conflated. (feature-control's own INTENT requires
this.)
3. **Engine layer, not the orchestrator foundation.** Integration lives in
`engine/activation.py`; the current `src/shard_wiki/` core stays dependency-free. OpenFeature/
feature-control is an optional extra, kept out of the standalone path by the `LocalProvider`.
4. **Thin slice only.** Consume `feature-control.evaluate` (mature, A4). Do **not** take a
dependency on the heavier control-plane governance / `rollout` / `visibility` (A2) until a
concrete need appears.
Activation keys = extension ids; evaluation context = `{tenant_id: root-entity, shard_id, …}`;
the resulting active-extension set then **derives** the shard's §A capability profile (E-5).
## Consequences
**Positive**
- No bespoke flag system; reuses a mature (D5/A4) capability — reuse-surface aligned.
- Standalone stays zero-dep (LocalProvider); governed deployments get real runtime control,
multi-tenant scoping, and **explainable** decisions that feed the engine's agent-introspection
API (E-7: "why is extension X off for this shard?").
- "Activate only what you need" + compute control become first-class and reversible at runtime.
- Clean layering: availability (feature-control) vs authorization (core) vs identity (provider).
**Negative / risks (mitigated by the constraints)**
- An optional OpenFeature dependency at the engine layer (mitigated: out of the standalone path).
- Coupling to an external control plane in governed mode (mitigated: provider-pluggable, degrade
to LocalProvider).
- Temptation to route authz through it (mitigated: constraint 2, hard boundary).
## Alternatives considered
- **Bespoke per-shard flag/config in the engine** — rejected: reinvents feature-control, no
standard, no multi-tenant/explainability, violates reuse-not-reinvent (E-8).
- **No activation (all extensions always on)** — rejected: defeats "small core + activate only
what you need" (E-2/E-4) and the compute-control goal.
- **Build on the heavier feature-control control-plane now** — deferred: over-scoping a single
engine's activation; revisit if rollout/governance needs emerge.
## Related
`WikiEngineCoreArchitecture.md` (E-4/E-8, §4 activation), `UseCaseCatalog.md` capability-structure
layer (X-AUTHZ vs activation), `history/260615-reuse-surface-contributions.md` (T3 consumption),
reuse-surface `capability.feature-control.evaluate`, INTENT amendment decision `84ffdb48`.