docs(arch): set OQ-42 decision direction — repo/adapter storage + Option 2 integration

Two structural decisions for dynamic resource ownership (OQ-42), recorded
in the OQ so ADR drafting starts from a clear position:

1. Storage side reuses the repo/adapter pattern (ADR-033) — a fourth
   instance alongside IdentityProvider/IdentityStore/CredentialStore.
   Trait in alknet-core with an in-memory default adapter; persistence
   adapter separable. Sync read with ArcSwap + honker-NOTIFY cache
   invalidation, same shape as ConfigIdentityProvider (ADR-035). No new
   shape invented; no Phase 0 needed for the storage side.

2. Integration point is Option 2 — AccessControl::check consults the
   ownership provider directly. Rejected Option 1 (augment identity with
   a per-request snapshot) because its purity was theatrical — the
   question 'can X exec into container C' was never purely a function of
   identity, it just looked that way because the resource set was static.
   Option 2 makes check's signature honest about what ACL checking is in
   the presence of dynamic resources. Cost is a check signature change
   (one-way door, every call site updates) — implementation cost, not
   semantic cost, per the project's decision principle.

Refinement that makes Option 2 clean: OperationSpec gains resource_id_path
(JSON pointer into the input, e.g. '$.containerId'). Fits naturally with
the existing JSON-Schema-backed input_schema — the pointer is within an
existing schema on the same spec. OperationSpec becomes fully
self-describing for authorization: resource type, action, and which input
field drives the resource lookup, all declared on the spec.

Four specifics remain open for the ADR: the no-specific-resource (list)
case, teardown coupling, fleet representation (spoke resources on the
hub), and composition interaction with dynamic ownership. These were
surfaced by choosing Option 2 rather than by leaving the integration point
undecided.
This commit is contained in:
2026-07-04 13:04:14 +00:00
parent e29672942c
commit f390550a06
2 changed files with 140 additions and 88 deletions

View File

@@ -156,7 +156,7 @@ See [open-questions.md](open-questions.md) for the full tracker.
- **OQ-41**: Stream operators library — a handler-level utility library (filter, map, batch, dedupe, window, etc. on `BoxStream<T>`), prior art in `@alkdev/pubsub/operators.ts`; feature extension, not an architectural decision (the architecture decision — stream composition is handler-level, not protocol-level — is made in ADR-049)
**Open (blocking, requires ADR before the dependent crate specs):**
- **OQ-42**: Dynamic resource ownership for runtime-spawned resources — surfaced by the alknet-docker POC (containers as `AccessControl` resources), generalized to every "spawn a thing at runtime and expose it over the call protocol" crate (docker, tty, opencode-runner wrapper, `alknet-container` fleet layer). The current `Identity.resources``AccessControl::check` model is static (config-sourced via `PeerEntry`/`CompositionAuthority`); runtime-spawned resources with derived ownership don't fit. One-way door at the model level (core/call), two-way at the mechanism level. High priority — blocks the docker/tty/runner/fleet crate specs. Likely warrants a Phase 0 research/POC pass before the ADR.
- **OQ-42**: Dynamic resource ownership for runtime-spawned resources — surfaced by the alknet-docker POC (containers as `AccessControl` resources), generalized to every "spawn a thing at runtime and expose it over the call protocol" crate (docker, tty, opencode-runner wrapper, `alknet-container` fleet layer). The current `Identity.resources``AccessControl::check` model is static (config-sourced via `PeerEntry`/`CompositionAuthority`); runtime-spawned resources with derived ownership don't fit. **Decision direction set**: storage side reuses the repo/adapter pattern (ADR-033, fourth instance alongside `IdentityProvider`/`IdentityStore`/`CredentialStore`); integration point is Option 2 — `AccessControl::check` consults an ownership provider directly, with `OperationSpec` gaining a `resource_id_path` JSON pointer so the spec stays fully self-describing for authorization. Four specifics remain open for the ADR: the no-specific-resource (`list`) case, teardown coupling, fleet representation (spoke resources on the hub), and composition interaction with dynamic ownership. High priority — blocks the docker/tty/runner/fleet crate specs.
**Deferred (not active):**
- **OQ-09**: WASM target boundaries — design constraint, not deliverable