Construction-plan format + first real plan draft (MASON-WP-0001-T01)
docs/construction-plan-format.md: one file per plan (plans/<id>.md), frontmatter status tracker (draft -> reviewed -> approved -> built -> catalogued, the phase-4 hard gate), six body sections threading all four phases through one document. Proven against real demand: plans/rein-openweights-openrouter-approle.md, phases 1-2 filled in. Found and reasoned through a real existing-structure question along the way -- the openrouter-llm-connect catalog lane could technically be reused, but its auth_method is interactive-caller-shaped and its policy is shared/high-risk; recommends a dedicated, narrowly scoped AppRole instead, same reasoning agent-harness-binky-mail used for its own dedicated lane. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
parent
d3dbad34e1
commit
a762be9e17
3 changed files with 219 additions and 1 deletions
97
docs/construction-plan-format.md
Normal file
97
docs/construction-plan-format.md
Normal file
|
|
@ -0,0 +1,97 @@
|
|||
# Construction plan format
|
||||
|
||||
The artifact phase 1 (`INTENT.md`) produces. One markdown file per plan,
|
||||
stored at `plans/<plan-id>.md` in this repo — plain, versioned, reviewable
|
||||
in a diff, not a database. `<plan-id>` is kebab-case and traceable to the
|
||||
demand that triggered it (usually a workplan task id from the requesting
|
||||
repo, e.g. `rein-openweights-openrouter-approle` for
|
||||
`glas-harness/GLAS-WP-0002-T02`).
|
||||
|
||||
A plan file is the single source of truth across all four phases: phase 1
|
||||
writes it, phase 2 edits it in place (self-review, not a separate
|
||||
document), phase 3's executive summary is generated *from* it (not a
|
||||
parallel artifact that can drift), and phase 4 reads the same file to
|
||||
execute and appends a result section when done.
|
||||
|
||||
## Frontmatter
|
||||
|
||||
```yaml
|
||||
---
|
||||
id: rein-openweights-openrouter-approle
|
||||
demand_source: glas-harness/workplans/GLAS-WP-0002-T02
|
||||
consumer_repo: rein-openweights
|
||||
credential_type: openbao-approle-kv
|
||||
status: draft # draft -> reviewed -> approved -> built -> catalogued
|
||||
approved_by: null # founder identity string, set only at phase 3 -> 4
|
||||
approved_at: null # ISO date, set alongside approved_by
|
||||
created: "2026-07-27"
|
||||
updated: "2026-07-27"
|
||||
---
|
||||
```
|
||||
|
||||
`status` is the phase tracker for the plan itself, distinct from any
|
||||
State Hub task status — it's what the build executor (`MASON-WP-0001-T04`)
|
||||
checks before doing anything: **refuses to execute unless
|
||||
`status: approved` and both `approved_by`/`approved_at` are set.** No
|
||||
other field or file can substitute for this — that's the one hard gate.
|
||||
|
||||
## Body sections
|
||||
|
||||
### 1. Demand
|
||||
|
||||
Plain description: who needs what, why, and what they need it *for* (one
|
||||
paragraph — this feeds the executive summary's plain-language framing
|
||||
directly, so write it for the founder, not for `bao`).
|
||||
|
||||
### 2. Existing-structure survey
|
||||
|
||||
What already exists that might cover this, checked *before* proposing
|
||||
anything new:
|
||||
|
||||
- Relevant `bao policy list` / `bao auth list` / `bao secrets list`
|
||||
entries (paste the actual output, not a paraphrase)
|
||||
- Relevant `ops-warden/registry/routing/catalog.yaml` entries (grep by
|
||||
`owner_repo`/`subsystem`/`need_keywords`)
|
||||
- Explicit answer: **does an existing lane already satisfy this demand?**
|
||||
If yes, the plan's proposed changes should be "bind to existing policy
|
||||
X" or "reuse existing path Y," not "create new." (See
|
||||
`binky-control/integrations/executor-worker-secrets.md`'s own Lane 1 —
|
||||
reused the existing `llm-connect-provider-secrets` secret instead of
|
||||
minting a new one, because the scoping already covered the new
|
||||
consumer.)
|
||||
|
||||
### 3. Proposed changes
|
||||
|
||||
A list, each item tagged `create` / `modify` / `tear-down`, each with a
|
||||
one-line reuse-vs-new rationale referencing section 2. Every item names
|
||||
exactly what OpenBao object it touches (policy name, AppRole name, KV
|
||||
path) — no vague "provision access" line items.
|
||||
|
||||
### 4. Review notes (phase 2)
|
||||
|
||||
Filled in during the self-review pass, before a human ever sees the
|
||||
plan: naming/TTL/scoping convention check against existing lanes (e.g.
|
||||
the `agent-harness-binky-mail` shape — `token_ttl=15m`,
|
||||
`token_max_ttl=30m`, bounded `token_num_uses`), redundancy check, and any
|
||||
compaction opportunity spotted along the way. If this section is empty,
|
||||
the plan is not ready for phase 3.
|
||||
|
||||
### 5. Executive summary (phase 3, generated from sections 1-4)
|
||||
|
||||
See `docs/executive-summary-format.md` (`MASON-WP-0001-T03`) for the
|
||||
exact rendering. Lives in the same plan file so there is one document to
|
||||
read, not two to cross-reference.
|
||||
|
||||
### 6. Build result (phase 4, appended after execution)
|
||||
|
||||
What was actually created/modified/torn down (object names, not values),
|
||||
the ops-warden catalog entry proposed (id + PR/commit reference once
|
||||
filed), and the exact `paste_once_provision` step the founder still needs
|
||||
to run (path, field) if the plan involved a new secret value. This
|
||||
section does not exist until phase 4 has run.
|
||||
|
||||
## Worked example (also the input to `MASON-WP-0001-T05`)
|
||||
|
||||
See `plans/rein-openweights-openrouter-approle.md` once T01 is
|
||||
implemented against this format — the first real plan, not a synthetic
|
||||
one, per `MASON-WP-0001`'s own scoping.
|
||||
108
plans/rein-openweights-openrouter-approle.md
Normal file
108
plans/rein-openweights-openrouter-approle.md
Normal file
|
|
@ -0,0 +1,108 @@
|
|||
---
|
||||
id: rein-openweights-openrouter-approle
|
||||
demand_source: glas-harness/workplans/GLAS-WP-0002-T02
|
||||
consumer_repo: rein-openweights
|
||||
credential_type: openbao-approle-kv
|
||||
status: draft
|
||||
approved_by: null
|
||||
approved_at: null
|
||||
created: "2026-07-27"
|
||||
updated: "2026-07-27"
|
||||
---
|
||||
|
||||
# Construction plan: rein-openweights OpenBao AppRole
|
||||
|
||||
## 1. Demand
|
||||
|
||||
`rein-openweights` (the OpenRouter-driven rein in the glas-harness family)
|
||||
needs to authenticate to OpenBao **non-interactively** — no operator OIDC
|
||||
session, no human in the loop at run time — to fetch its OpenRouter API
|
||||
key when it runs unattended (e.g. via a future scheduled trigger, or a
|
||||
glas-harness gateway invocation with no operator present). This was
|
||||
scoped as `glas-harness/GLAS-WP-0002-T02` ("Option B" — see that
|
||||
workplan's discussion) and is currently blocked: the only credential path
|
||||
exercised so far is the `OPENROUTER_API_KEY` env-var short-circuit in
|
||||
`rein_openweights/credentials.py`; the AppRole/vault branch
|
||||
(`_acquire_token`, `bao kv get`) is real code, live-verifiable, but has
|
||||
never actually talked to OpenBao.
|
||||
|
||||
## 2. Existing-structure survey
|
||||
|
||||
**Checked:** `ops-warden/registry/routing/catalog.yaml` (readable directly
|
||||
— no OpenBao session needed for this). **Not checked:** live `bao policy
|
||||
list` / `bao auth list` / `bao secrets list` — this session has no valid
|
||||
OpenBao token (`bao token lookup` returns `403`). Whoever executes phase 4
|
||||
must re-verify against live state before applying anything below; this
|
||||
survey is current as of what's on disk, not as of live OpenBao ACL state.
|
||||
|
||||
**Relevant existing catalog entry: `openrouter-llm-connect`**
|
||||
(`ops-warden/registry/routing/catalog.yaml:283`) — an OpenRouter key
|
||||
already exists at
|
||||
`platform/workloads/activity-core/llm-connect/llm-connect-provider-secrets`
|
||||
(field `OPENROUTER_API_KEY`), gated by policy
|
||||
`workload-kv-read-llm-connect-provider-secrets`, `auth_method: caller's
|
||||
own OpenBao token (operator OIDC via key-cape, or a token carrying
|
||||
[that policy])`, marked `risk: high` ("provider API key with spend impact").
|
||||
`rein-aharness`'s own mail-triage/brief-daily already reuse this exact
|
||||
lane (see `binky-control/integrations/executor-worker-secrets.md`, Lane 1
|
||||
— "REUSE (verified)").
|
||||
|
||||
**Does this existing lane satisfy the demand? Partially, by design, not
|
||||
fully — reuse considered and declined:**
|
||||
|
||||
- The existing lane's `auth_method` is interactive-caller-shaped (OIDC /
|
||||
"a token carrying the policy") — it was never scoped for a bare AppRole
|
||||
login the way `agent-harness-binky-mail`'s Lane 3 was. Binding a new
|
||||
AppRole to the *existing* policy is mechanically possible (Option A
|
||||
from the original discussion) but would give `rein-openweights`
|
||||
standing, non-interactive access to a policy explicitly flagged
|
||||
`risk: high` for spend impact, shared with `activity-core`'s broader
|
||||
usage — a wider blast radius than a single rein needs.
|
||||
- **Recommendation: do not reuse.** Build a dedicated, narrowly-scoped
|
||||
AppRole + KV path for `rein-openweights` specifically (matches
|
||||
`credentials.py`'s existing default `reins/rein-openweights/openrouter`
|
||||
path already in the code) — same reasoning `agent-harness-binky-mail`
|
||||
used for its own dedicated lane rather than widening an existing one.
|
||||
This keeps a leak scoped to exactly one consumer, one credential.
|
||||
|
||||
## 3. Proposed changes
|
||||
|
||||
| # | Action | Object | Reuse-vs-new rationale |
|
||||
|---|---|---|---|
|
||||
| 1 | create | KV v2 secret path `reins/rein-openweights/openrouter` (field `api_key`) | New, narrowly scoped — matches `credentials.py`'s existing default path; declined reuse of the shared `activity-core` path (see §2) |
|
||||
| 2 | create | Policy `workload-kv-read-rein-openweights-openrouter` — read-only, scoped to exactly path #1 | New — mirrors the shape of `workload-kv-read-llm-connect-provider-secrets` but scoped to one path, not shared |
|
||||
| 3 | create | AppRole `rein-openweights`, bound to policy #2 | New — mirrors `agent-harness-binky-mail`'s AppRole shape: `token_ttl=15m`, `token_max_ttl=30m`, bounded `token_num_uses`, `secret_id_ttl` per current posture (build-phase; see `ops-warden/wiki/WorkloadSecurityPosture.md`) |
|
||||
| 4 | deliver | `role_id`/`secret_id` files, `0600`, to wherever the live verification runs (workstation or a future Railiance deployment) | New — matches `agent-harness-binky-mail`'s delivery pattern (`~/.local/agent-harness/approle-binky-mail`), analogous path for this consumer |
|
||||
| 5 | propose | ops-warden catalog entry `rein-openweights-openrouter-approle` — pointer-only, `warden_executes: false`, `status: draft` | New — no existing entry covers this AppRole; `openrouter-llm-connect` entry stays as-is, untouched |
|
||||
|
||||
No tear-down in this plan — no existing lane is being retired or
|
||||
compacted; the existing `openrouter-llm-connect` lane is explicitly kept
|
||||
as-is for its current interactive-caller consumers.
|
||||
|
||||
## 4. Review notes (phase 2)
|
||||
|
||||
- **Naming convention check:** follows `<consumer>-<credential-purpose>`
|
||||
shape used by `agent-harness-binky-mail` — proposed
|
||||
`rein-openweights-openrouter-approle` for the AppRole/catalog id,
|
||||
`workload-kv-read-rein-openweights-openrouter` for the policy (matches
|
||||
the `workload-kv-read-<path-slug>` convention already visible in the
|
||||
existing catalog).
|
||||
- **TTL/scoping check:** `token_ttl=15m`/`token_max_ttl=30m`/bounded
|
||||
`token_num_uses` matches `agent-harness-binky-mail` exactly — no reason
|
||||
to diverge, this consumer's access pattern (one-shot credential fetch
|
||||
per run) is identical in shape.
|
||||
- **Redundancy check:** confirmed no second existing AppRole or policy
|
||||
already scoped to `reins/rein-openweights/*` — this is genuinely new
|
||||
structure, not a duplicate.
|
||||
- **Compaction opportunity:** none identified — nothing existing becomes
|
||||
redundant once this lands; the shared `activity-core` lane keeps its
|
||||
own consumers.
|
||||
- **Open item carried into phase 3/4:** confirm current build-phase
|
||||
posture (`ops-warden/wiki/WorkloadSecurityPosture.md`) still supports
|
||||
`secret_id_ttl=0` (no expiry, matching `agent-harness-binky-mail`'s
|
||||
choice) rather than a rotation schedule — note this explicitly in the
|
||||
executive summary rather than assuming it silently.
|
||||
|
||||
<!-- Phase 3 (executive summary) and phase 4 (build result) sections are
|
||||
appended once MASON-WP-0001-T03/T04 land — this file stops at phase 2
|
||||
until then. -->
|
||||
|
|
@ -26,9 +26,22 @@ tear-down, each with a stated reuse-vs-new rationale). Document in
|
|||
not a database — so a plan can be reviewed in a diff and stored next to
|
||||
the workplan that requested it.
|
||||
|
||||
**Done (2026-07-27).** `docs/construction-plan-format.md`: one file per
|
||||
plan at `plans/<id>.md`, YAML frontmatter (`status: draft -> reviewed ->
|
||||
approved -> built -> catalogued`, the phase-4 hard gate), six body
|
||||
sections (demand, existing-structure survey, proposed changes, phase-2
|
||||
review notes, phase-3 executive summary, phase-4 build result) — one
|
||||
document threaded through all four phases, not four separate artifacts.
|
||||
Proven against a real demand, not a synthetic one:
|
||||
`plans/rein-openweights-openrouter-approle.md`, phases 1-2 filled in —
|
||||
including a genuine finding in the existing-structure survey (an
|
||||
existing `openrouter-llm-connect` catalog lane that could theoretically
|
||||
be reused, and an explicit, reasoned decision *not* to reuse it, scoped
|
||||
narrowly instead). Phases 3-4 wait on `MASON-WP-0001-T03`/`T04`/`T05`.
|
||||
|
||||
```task
|
||||
id: MASON-WP-0001-T01
|
||||
status: todo
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "6b25e7ca-52a0-41c2-b5a0-b5e46c824264"
|
||||
```
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue