diff --git a/WORK-RECORDS.md b/WORK-RECORDS.md index d12daa8..94c583a 100644 --- a/WORK-RECORDS.md +++ b/WORK-RECORDS.md @@ -14,8 +14,8 @@ | task | GLAS-0001-T02 | todo | — | workplans/GLAS-0001-statehub-bootstrap.md | | task | GLAS-0001-T03 | todo | — | workplans/GLAS-0001-statehub-bootstrap.md | | task | GLAS-WP-0001-T01 | done | — | workplans/GLAS-WP-0001-harness-router-foundation.md | -| task | GLAS-WP-0001-T02 | todo | — | workplans/GLAS-WP-0001-harness-router-foundation.md | -| task | GLAS-WP-0001-T03 | todo | — | workplans/GLAS-WP-0001-harness-router-foundation.md | -| task | GLAS-WP-0001-T04 | todo | — | workplans/GLAS-WP-0001-harness-router-foundation.md | +| task | GLAS-WP-0001-T02 | done | — | workplans/GLAS-WP-0001-harness-router-foundation.md | +| task | GLAS-WP-0001-T03 | done | — | workplans/GLAS-WP-0001-harness-router-foundation.md | +| task | GLAS-WP-0001-T04 | progress | — | workplans/GLAS-WP-0001-harness-router-foundation.md | | task | GLAS-WP-0001-T05 | todo | — | workplans/GLAS-WP-0001-harness-router-foundation.md | | task | GLAS-WP-0001-T06 | todo | — | workplans/GLAS-WP-0001-harness-router-foundation.md | diff --git a/docs/adr/ADR-001-rein-harness-family.md b/docs/adr/ADR-001-rein-harness-family.md index dbf8373..0593991 100644 --- a/docs/adr/ADR-001-rein-harness-family.md +++ b/docs/adr/ADR-001-rein-harness-family.md @@ -88,6 +88,7 @@ through an equivalent agentic tool-use loop. (kaizen-agentic, activity-core), or does only `rein-aharness` depend on those while `rein-openweights` is triggered differently (e.g. directly by glas-harness channels)? -- Where does credential brokering for `rein-openweights`'s OpenRouter/ - llm-connect calls live — glas-harness (per the sandbox-consumption - pattern) or the rein itself? +- ~~Where does credential brokering for `rein-openweights`'s OpenRouter/ + llm-connect calls live~~ — resolved in + `docs/adr/ADR-002-credential-brokering-and-composable-reins.md`: the + rein itself (Option B), not glas-harness. diff --git a/docs/adr/ADR-002-credential-brokering-and-composable-reins.md b/docs/adr/ADR-002-credential-brokering-and-composable-reins.md new file mode 100644 index 0000000..4dbeb41 --- /dev/null +++ b/docs/adr/ADR-002-credential-brokering-and-composable-reins.md @@ -0,0 +1,106 @@ +# ADR-002: Credential brokering for rein-openweights; composable reins deferred + +- Status: accepted (part 1), open (part 2) +- Date: 2026-07-26 +- Deciders: Bernd Worsch + +## Context + +`GLAS-WP-0001-T06` asked who acquires the OpenRouter credential +`rein-openweights` needs: glas-harness (mirroring how it brokers sand-boxer +sandbox handles) or the rein itself (mirroring how `rein-aharness` already +holds its own OpenBao AppRole lane for IMAP/mail credentials). + +Discussion surfaced a prior question: should `rein-openweights` talk to +OpenRouter through `llm-connect`, or through a leaner, independent wrapper +that both `llm-connect` and `rein-openweights` depend on — keeping +`llm-connect`'s monitoring/evaluation/optimization features optional +rather than bundled in? + +Checking `llm-connect` directly resolved that half cleanly: + +- Its own `ARCHITECTURE-LAYERS.md` already separates Core (frozen adapter + ABC + models) from Functional (independently shippable per-provider + adapters, diagnostics, replay, budget tracking — all explicitly + optional: *"Keeps base install lightweight... optional dep, not + runtime dep"*) from Configuration (TOML resolution, key lookup). +- `resolve_api_key()` (`llm_connect/config.py`) only reads an + **already-materialized** key — explicit argument → env var → file. It + never talks to OpenBao/ops-warden. `llm-connect/INTENT.md` states this + as an explicit boundary: *"not intended to... manage secrets, + credentials, or organizational access policies."* + +So `llm-connect` was never a credential broker regardless of which +adapter path `rein-openweights` uses — the earlier concern that "using +llm-connect" imports a credential model doesn't hold. `rein-openweights` +can depend on just Core + the `OpenRouterAdapter` Functional module and +skip diagnostics/replay/budget, the same way any other consumer can +today. + +## Decision (part 1 — resolved) + +**Option B: `rein-openweights` acquires its OpenRouter credential +directly** (OpenBao/ops-warden), the same way `rein-aharness` already +does for its own credentials. glas-harness does not broker LLM-provider +credentials. + +Rationale, in order of weight: + +1. Consistency with the existing family precedent. `rein-aharness`'s own + INTENT.md states *"the harness is the only credential holder and only + policy enforcement point."* Having glas-harness broker for one rein + but not the other bakes an inconsistency into the family from its + second member. +2. Scope discipline. glas-harness has zero live end-to-end proof yet + (`GLAS-WP-0001-T04` is a unit-tested wiring, not a live run) — growing + it into a secrets broker ahead of validated need repeats the + premature-generalization mistake ADR-001 was written to avoid on the + sandbox side. +3. Credential lifecycle doesn't map cleanly onto sand-boxer's + create/destroy session lifecycle the way a sandbox handle does — the + analogy that made Option A attractive was weaker than it first looked. + +Accepted cost: `rein-openweights` duplicates OpenBao wiring rather than +inheriting it from glas-harness. Revisit centralizing it if a third rein +repeats the same need — decide from evidence, not in advance. + +## Consequences (part 1) + +- `rein-openweights` (`REIN-OW-WP-0001-T04`) implements its own + credential acquisition; it does not wait on or call into glas-harness + for this. +- `rein-openweights` depends on `llm-connect`'s Core + `OpenRouterAdapter` + only — not the full package surface — confirmed against the actual + layer boundaries above, not assumed. +- `GLAS-WP-0001-T06` is done. `GLAS-WP-0001-T05` (bootstrap + `rein-openweights`) is unblocked. + +## Part 2 — open, deferred: composable reins as middleware + +Separately, the idea surfaced that monitoring/evaluation/optimization +(capabilities `llm-connect` already stages as optional Functional +modules) could eventually become their own **composable reins** — +cross-cutting capabilities that wrap or observe another rein's +`dispatch_tool` calls, rather than each being a complete alternative +harness backend the way `rein-aharness`/`rein-openweights` are. + +This is a real extension to `docs/harness-contract.md`: the current +`Rein` ABC assumes one rein *is* the whole session, with no +wrapping/composition concept (no middleware chain, no way for a +"monitoring rein" to sit between glas-harness and the base rein's calls). + +**Left open deliberately** — it does not block `rein-openweights` +bootstrap and there is only one candidate capability (llm-connect's +existing optional modules) to generalize from, not evidence of a +recurring pattern. Revisit if/when a second capability +(evaluation, or a distinct optimization concern) wants the same +treatment. If pursued, it would need: + +- A `Middleware`/`ReinWrapper` concept distinct from `Rein` in + `contract.py`, with an explicit chain-of-responsibility around + `dispatch_tool`. +- A decision on whether `llm-connect` itself gets decomposed into + reins/middleware, or stays a shared library that both base reins and + middleware reins happen to depend on (the leaner option, and the one + consistent with `llm-connect`'s own INTENT.md boundary against owning + application-level workflow). diff --git a/workplans/GLAS-WP-0001-harness-router-foundation.md b/workplans/GLAS-WP-0001-harness-router-foundation.md index 40c85f5..5c49afe 100644 --- a/workplans/GLAS-WP-0001-harness-router-foundation.md +++ b/workplans/GLAS-WP-0001-harness-router-foundation.md @@ -109,15 +109,20 @@ state_hub_task_id: "84fa62ae-3b34-42fd-a263-f65c35e87586" ## Task: Decide credential-brokering ownership for rein-openweights -Resolve the open question from ADR-001: does glas-harness broker the -OpenRouter/llm-connect credential the same way it will broker sand-boxer -sandbox handles, or does rein-openweights acquire it directly (OpenBao/ -ops-warden) the way rein-aharness does today? Record as an ADR addendum -before T05 lands, not after. +Resolved in `docs/adr/ADR-002-credential-brokering-and-composable-reins.md`: +**Option B** — rein-openweights acquires its OpenRouter credential +directly (OpenBao/ops-warden), consistent with rein-aharness's own +credential-holder principle. glas-harness does not broker LLM-provider +credentials. Confirmed llm-connect itself never brokers credentials +either (`resolve_api_key()` only reads an already-materialized key) — +the earlier "does using llm-connect impose a credential model" concern +does not apply. A separate, deliberately deferred question (composable +reins as middleware for monitoring/eval/optimization) is recorded in the +same ADR as open, not blocking this task or T05. ```task id: GLAS-WP-0001-T06 -status: todo +status: done priority: medium state_hub_task_id: "b4e775d6-ad81-40a4-9fd0-974ba27182fd" ```