From 69884ac2d0e1ba053e1c6a050486dd621c85e700 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Wed, 2 Sep 2026 12:39:56 +0900 Subject: [PATCH 1/3] docs(adr): record ecosystem admin-web architecture (Keyverse SSO + Keyvault) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cross-repo research pass (owner request: "관리자 웹 개발 (noema, contextual-orchestrator, keyverse) 및 상호 연계 준비") across all three named repos, cloned fresh -- not assumed -- before any design work. Records: Keyverse as the shared SSO provider for every admin web (design only, not yet wired); each repo's admin web as a thin frontend over its own backend (no shared cross-repo frontend package, matching contextual-orchestrator's own ADR 0033 reasoning); the Keyverse-as-Keyvault bounded-context decision and why service ABAC/RBAC and "login credential store" are NOT rebuilt from scratch (PR #103 already covers the former; the latter is Keyvault + per-service Anti-Corruption Layers, not a new module); and why noema got no code change this iteration (no admin-relevant HTTP surface exists yet to build a console on). Points to the two implemented slices from this same pass: ContextualWisdomLab/contextual-orchestrator#1010 (per-model LLM timeout admin surface, closing docs/product-goal-directive.md §8) and ContextualWisdomLab/keyverse#129 (Keyvault: namespaced encrypted-at-rest secrets store, plus ADRs 0014-0016 for the three-capability Keyverse research). Co-Authored-By: Claude Sonnet 5 --- ...21-ecosystem-admin-web-sso-and-keyvault.md | 138 ++++++++++++++++++ 1 file changed, 138 insertions(+) create mode 100644 docs/adr/0021-ecosystem-admin-web-sso-and-keyvault.md diff --git a/docs/adr/0021-ecosystem-admin-web-sso-and-keyvault.md b/docs/adr/0021-ecosystem-admin-web-sso-and-keyvault.md new file mode 100644 index 0000000000..3f2dfe3ece --- /dev/null +++ b/docs/adr/0021-ecosystem-admin-web-sso-and-keyvault.md @@ -0,0 +1,138 @@ +# ADR-0021: Ecosystem admin-web architecture — Keyverse SSO and Keyvault + +- **Status:** Accepted +- **Date:** 2026-09-02 +- **Scope:** cross-repository admin-web architecture for `noema`, `contextual-orchestrator`, and `keyverse` + +## Context + +The owner asked for admin web UIs across three repositories +(`noema`, `contextual-orchestrator`, `keyverse`) and for mutual +integration so `keyverse` — currently a Keycloak-fronting central Identity +Provider — can also be used as a Keyvault (secrets/credential management, +analogous to Azure Key Vault or HashiCorp Vault), later expanded by the +owner to two further Keyverse capabilities: service-to-service ABAC/RBAC, +and a "login credential store" for service-account/machine credentials. + +Direct repository research (cloned fresh, not assumed) found: + +- **`contextual-orchestrator`** already runs a real, serving `/admin` + operator console (`admin.py`, inline stdlib HTML/JS, eight Figma-grounded + screens) with no per-model LLM timeout control — the exact gap + `docs/product-goal-directive.md` §8 already names. An `admin_ui/` + React+Storybook scaffold exists but is confirmed (by direct inspection, + matching that repo's own planning ADR 0036, superseded) to be the + unmodified Vite demo output — no admin-web work in flight there. This + was the readiest of the three repos: it already had a serving console, + an established KV/audit pattern (`credentials.py`, `model_group` + family), and an explicit product requirement to build against. +- **`keyverse`** had no encrypted secrets store (`kv_store.py`'s + `idp_config_entries` is its own internal, unencrypted config — never a + generic secrets product surface) and no frontend of any kind. PR #103 + (open, Draft) already implements most of the requested service + ABAC/RBAC capability (`authorization_plane.py`, `org_authorization.py`, + ADRs 0010–0012) but is not currently mergeable. +- **`noema`** is a Cloudflare Worker OIDC/credential-exchange broker with + only `/health`, `/ready`, `/exchange` and Durable-Object-only internal + state — no admin-readable HTTP surface exists to build a console on top + of today. The least ready of the three. + +Per this repo's own scoping guidance for genuinely multi-week product +work, the correct first iteration is the smallest real, honestly-scoped +slice per repo — not three parallel half-built admin webs. + +## Decision + +1. **Keyverse is the shared SSO provider for every admin web in this + ecosystem.** It is already the org's central IdP; admins authenticate + to each product's admin console via Keyverse OIDC rather than a + per-repo local admin credential. This is itself the "상호 연계" + (mutual integration) the owner asked for, independent of the Keyvault + question. **Design only in this iteration** — `contextual-orchestrator`'s + `/admin` still uses its existing shared-bearer-token session model + (`/admin/session`); wiring Keyverse OIDC in is the next concrete step + for that console, tracked as an explicit open item rather than + silently deferred. +2. **Each repo's admin web stays a thin frontend over that repo's own + backend API**, not a shared cross-repo frontend package — there is no + second consumer of shared UI primitives yet (matching + `contextual-orchestrator`'s own ADR 0033 reasoning for why Storybook/ + component tooling stays deferred there specifically). +3. **Keyverse's Keyvault is a bounded context separate from its IdP + identity/config modules**, sharing only the KV storage *pattern* + (Protocol + in-memory/SQLite backends) already proven in that repo, + not any shared table. `contextual-orchestrator`'s existing + `CredentialBackend` Protocol (pluggable backends, KV-not-env + discipline) is the natural adapter target for a future + `KeyverseCredentialBackend` — the motivating first consumer, not + implemented in this pass. Full reasoning: `keyverse` ADR-0014. +4. **Service ABAC/RBAC is not rebuilt here.** Keycloak's built-in + Authorization Services (UMA 2.0) exist but are unconfigured in this + deployment and do not natively cover the hierarchical org-path + inheritance CWL's Orgmetra-owned org tree requires; PR #103 already + implements that hierarchy. Recommendation: reconcile and land PR #103 + rather than duplicate it. Full reasoning: `keyverse` ADR-0015. +5. **"Login credential store" is Keyvault plus per-service + Anti-Corruption Layers, not a fourth Keyverse module.** Centralizing + secret *storage* in Keyverse while each consuming service keeps its + own credential-taxonomy knowledge (via its own Protocol adapter, e.g. + `contextual-orchestrator`'s `CredentialBackend`) avoids growing + Keyverse into a service that must change whenever any consumer's + credential schema changes. Full reasoning: `keyverse` ADR-0016. +6. **The first implemented slice is `contextual-orchestrator`'s per-model + LLM timeout admin surface** (view/set/clear/restore, units, priority/ + inheritance, validation, audit history, API contract — the exact §8 + requirement), extending the existing `/admin` console in place per its + own ADR 0033/0042. `keyverse`'s Keyvault (write/read/delete/list APIs, + encryption at rest via Fernet, audit logging) is implemented alongside + it as the second slice, since it was independently ready and directly + answers the Keyvault half of the owner's request. `noema` gets no code + change this iteration — it has no admin-relevant state to expose yet; + the honest next step there is deciding what operational state (OIDC + exchange health/rate, App-token issuance evidence) is worth exposing + before building a console around it. + +## Consequences + +- No repo gained a half-built parallel admin frontend; each shipped + either a real, tested slice or an explicit, evidenced "not yet, and + here is why" record. +- Cross-repo SSO and the Keyvault-as-credential-backend consolidation are + both real, next, concretely-scoped follow-ups — not vague future work — + recorded here and in the two repos' own ADRs so the next iteration does + not have to re-derive this research. +- `keyverse` PR #103 (service authorization) is now more clearly the + blocking dependency for capability #2 of the owner's three-capability + Keyverse request; this ADR does not change its status, only records + that a competing implementation was deliberately not built. + +## Rejected alternatives + +- **Build out `admin_ui/` (React+Storybook) for `contextual-orchestrator` + instead of extending `admin.py`.** Rejected: contradicts that repo's own + operative ADR 0033, and no revisit trigger from that ADR is met by this + work. +- **Build a from-scratch policy engine for Keyverse service ABAC/RBAC.** + Rejected: PR #103 already implements the actual (hierarchical, + org-path-aware) requirement; a second implementation would duplicate + ~2,000 lines of already-written, already-tested domain logic. +- **Centralize per-service credential semantics inside Keyverse.** + Rejected: violates this org's minimal-Shared-Kernel/Anti-Corruption-Layer + DDD convention and would couple Keyverse's deploy cadence to every + consuming service's credential taxonomy. +- **Force a code change into all three repos this iteration regardless of + readiness.** Rejected per this org's own genuinely-multi-week scoping + guidance: `noema` had no admin-relevant surface to build against yet, + and forcing one would have meant fabricating state or shipping a + console with nothing real to show. + +## References + +- `contextual-orchestrator` planning ADR 0033 (admin console UI tooling + boundary), 0036 (superseded React/Storybook proposal), 0042 (per-model + timeout admin surface — this iteration's `contextual-orchestrator` + slice). +- `keyverse` ADR-0014 (Keyvault bounded context), ADR-0015 (service + authorization plane), ADR-0016 (login credential store). +- `docs/product-goal-directive.md` §8 (LLM/orchestration; the per-model + timeout admin requirement this ADR's first slice closes). From d8d8cbdd2f2d39c73908ce3f625791c9bb69869d Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Thu, 3 Sep 2026 17:49:56 +0900 Subject: [PATCH 2/3] docs(adr-0021): correct stale claim that contextual-orchestrator#1010 shipped PR #1010 (the ADR's decision item 6, the timeout-admin-surface slice) was opened at 03:40:12Z, this ADR PR at 03:40:12Z, and #1010 was subsequently closed unmerged by the repo owner at 05:10:46Z the same day on a categorical objection to its live-enforcement wiring becoming production authority, plus four distinct unresolved correctness findings -- already repair-policy rechecked and confirmed a valid closure with delta preserved, not orphaned. Adds an Update section rather than rewriting the original decision record, so the ADR doesn't merge into main citing a closed PR as an implemented slice. Decisions 1-5 (SSO/Keyvault/ABAC-RBAC/credential-store shape) are unaffected; only item 6's implementation claim was stale. Co-Authored-By: Claude Sonnet 5 --- ...21-ecosystem-admin-web-sso-and-keyvault.md | 32 +++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) diff --git a/docs/adr/0021-ecosystem-admin-web-sso-and-keyvault.md b/docs/adr/0021-ecosystem-admin-web-sso-and-keyvault.md index 3f2dfe3ece..5c95ace47f 100644 --- a/docs/adr/0021-ecosystem-admin-web-sso-and-keyvault.md +++ b/docs/adr/0021-ecosystem-admin-web-sso-and-keyvault.md @@ -126,13 +126,41 @@ slice per repo — not three parallel half-built admin webs. and forcing one would have meant fabricating state or shipping a console with nothing real to show. +## Update — 2026-09-03: `contextual-orchestrator#1010` closed, not merged + +Decision item 6 above named `contextual-orchestrator#1010` (per-model LLM +timeout admin surface) as this iteration's first implemented slice. That PR +was subsequently **closed unmerged by the repo owner the same day** (2026-09-02, +`closed_at` 05:10:46Z — after this ADR PR was opened at 03:40:12Z), on a +categorical objection independent of this ADR's design: "the current manual +timeout-setting semantics must not become production authority," plus four +distinct unresolved correctness findings in the PR's live-enforcement wiring +(local queue path ignores the override, passthrough/tool requests bypass it, +failed persistence can leave the live timeout mutated, and admin-refresh races +can misreport/stale audit state). A subsequent repair-policy recheck (recorded +on the PR and in `docs/product-technical-gap-baseline.md`) confirmed this +closure is valid under the org's repair-not-close policy's "explicit user +instruction" ground, and that the PR's delta is preserved (not orphaned) on +its own closed branch for selective future reuse once a research-/standard-backed +timeout allocator exists to host it — not revived as-is. + +**This ADR's own architecture decisions (1–5) are unaffected** — they concern +the SSO/Keyvault/ABAC-RBAC/credential-store shape, not the timeout-surface +implementation. Only decision item 6's specific claim that the timeout slice +was "implemented" is now stale. `keyverse#129` (Keyvault, this iteration's +second slice) is unaffected by this and remains open. Left as an update rather +than rewriting the original decision record, so the historical reasoning +trail (what was true when each decision was made) stays intact. + ## References - `contextual-orchestrator` planning ADR 0033 (admin console UI tooling boundary), 0036 (superseded React/Storybook proposal), 0042 (per-model timeout admin surface — this iteration's `contextual-orchestrator` - slice). + slice, subsequently closed unmerged; see Update above). - `keyverse` ADR-0014 (Keyvault bounded context), ADR-0015 (service authorization plane), ADR-0016 (login credential store). +- `docs/product-technical-gap-baseline.md`, 2026-09-02 entry (repair-policy + recheck of `contextual-orchestrator#1010`'s closure). - `docs/product-goal-directive.md` §8 (LLM/orchestration; the per-model - timeout admin requirement this ADR's first slice closes). + timeout admin requirement this ADR's first slice attempted to close). From 297eedf8477b39353887b3eeee838497160dc609 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Thu, 3 Sep 2026 18:37:56 +0900 Subject: [PATCH 3/3] fix(adr): renumber ADR-0021 to ADR-0026 to resolve a numbering collision docs/adr/0021-hourly-review-repair-single-file-consolidation.md landed on main after this PR branched, so this ADR's own "0021 is the next free number" claim went stale. 0026 is the next free number after the current highest (0025, the CodeQL dispatch ADR). Renamed the file and updated its own title heading; no other file in the repo references the old number or filename. Co-Authored-By: Claude Sonnet 5 --- ...keyvault.md => 0026-ecosystem-admin-web-sso-and-keyvault.md} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename docs/adr/{0021-ecosystem-admin-web-sso-and-keyvault.md => 0026-ecosystem-admin-web-sso-and-keyvault.md} (99%) diff --git a/docs/adr/0021-ecosystem-admin-web-sso-and-keyvault.md b/docs/adr/0026-ecosystem-admin-web-sso-and-keyvault.md similarity index 99% rename from docs/adr/0021-ecosystem-admin-web-sso-and-keyvault.md rename to docs/adr/0026-ecosystem-admin-web-sso-and-keyvault.md index 5c95ace47f..e2f1f5f998 100644 --- a/docs/adr/0021-ecosystem-admin-web-sso-and-keyvault.md +++ b/docs/adr/0026-ecosystem-admin-web-sso-and-keyvault.md @@ -1,4 +1,4 @@ -# ADR-0021: Ecosystem admin-web architecture — Keyverse SSO and Keyvault +# ADR-0026: Ecosystem admin-web architecture — Keyverse SSO and Keyvault - **Status:** Accepted - **Date:** 2026-09-02