Request a create-only sitting requester for INFD-WP-0002-T03.
Names informed-decision-sitting-requester (approval:create only, no approve/consume, no redirect). Eight binding intents are drafted and not posted; c01 stays undecided vs secrets-engine-requester. No secret, no live registration, no bind. Assistant: grok Assistant-Session: 01a09dc1-b21e-77e1-919e-fcad2f82b267
This commit is contained in:
parent
6289ecbb68
commit
c333063185
7 changed files with 299 additions and 2 deletions
|
|
@ -31,8 +31,12 @@ Evidence: `docs/evidence/2026-09-14-infd-0002-t03-accept-reopened.json`.
|
|||
denied. Request shape: `policy-request.md`. Do not expand the T03 mandate
|
||||
in place.
|
||||
2. **No `approval:create` requester** whose `binding.actor` matches these
|
||||
acts. Do **not** reuse `secrets-engine-requester` for WSL2, clock
|
||||
ownership, mason plan, or warden seal.
|
||||
acts. Requested, **not applied**:
|
||||
`docs/keycape-sitting-requester-registration.md`. Do **not** reuse
|
||||
`secrets-engine-requester` for WSL2, clock ownership, mason plan, or
|
||||
warden seal. Create intents (not posted):
|
||||
`approval-create-intents.json`. `c01` is undecided between this client
|
||||
and `secrets-engine-requester`.
|
||||
3. Drafts still have `approval_id: null` and principal
|
||||
`pending-human-session`. Live review refuses `missing_act_binding` /
|
||||
`wrong_recipient`.
|
||||
|
|
|
|||
|
|
@ -26,3 +26,6 @@ Those memos are not this sitting. Live accept reopened 2026-09-14 22:16 UTC
|
|||
(`/readyz` 200). This sitting stays `draft-unsigned` until native receipts,
|
||||
a live KeyCape subject, a new Flex Auth package, and a human bind.
|
||||
Attach (does not bind): `uv run python tools/attach_compact_bindings.py`.
|
||||
Sitting requester (requested, not applied):
|
||||
`docs/keycape-sitting-requester-registration.md`. Create intents (not posted):
|
||||
`approval-create-intents.json`.
|
||||
|
|
|
|||
134
docs/batches/2026-09-14/approval-create-intents.json
Normal file
134
docs/batches/2026-09-14/approval-create-intents.json
Normal file
|
|
@ -0,0 +1,134 @@
|
|||
{
|
||||
"kind": "informed-decision-approval-create-intents",
|
||||
"sitting_id": "infd-sitting-2026-09-14",
|
||||
"status": "draft-not-posted",
|
||||
"posted": false,
|
||||
"requester_client": "informed-decision-sitting-requester",
|
||||
"human_control": true,
|
||||
"pdp_path": false,
|
||||
"required_count": 1,
|
||||
"note": "Intents only. Do not POST until the sitting requester exists and key-cape/approval-engine have accepted actor/principal. Digests are computed by approval-engine at create; do not invent them here.",
|
||||
"intents": [
|
||||
{
|
||||
"memo_id": "infd-20260914-c01",
|
||||
"create_client": "undecided",
|
||||
"reason": "May be secrets-engine-requester if a later consume is in-scope.",
|
||||
"binding": {
|
||||
"action": "admit",
|
||||
"actor": "informed-decision",
|
||||
"principal": "secrets-engine",
|
||||
"purpose": "Admit real native OpenRouter delivery for intelligence-radar on the existing reviewed lane",
|
||||
"target": {
|
||||
"id": "catalog:openrouter-llm-connect",
|
||||
"type": "secret-catalog-lane",
|
||||
"system": "secrets-engine"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"memo_id": "infd-20260914-c02",
|
||||
"create_client": "informed-decision-sitting-requester",
|
||||
"binding": {
|
||||
"action": "accept",
|
||||
"actor": "informed-decision",
|
||||
"principal": "railiance-platform",
|
||||
"purpose": "Accept provisioning of the secrets-engine service JWT login on the reviewed credential lane",
|
||||
"target": {
|
||||
"id": "rpf-wp-0035-t02",
|
||||
"type": "credential-lane",
|
||||
"system": "railiance-platform"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"memo_id": "infd-20260914-c03",
|
||||
"create_client": "informed-decision-sitting-requester",
|
||||
"binding": {
|
||||
"action": "apply",
|
||||
"actor": "informed-decision",
|
||||
"principal": "netkingdom",
|
||||
"purpose": "Apply the live OpenBao role addition already specified for the operator-tunneled browser callback",
|
||||
"target": {
|
||||
"id": "nk-wp-0032-t03",
|
||||
"type": "openbao-role",
|
||||
"system": "netkingdom"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"memo_id": "infd-20260914-c04",
|
||||
"create_client": "informed-decision-sitting-requester",
|
||||
"binding": {
|
||||
"action": "attend",
|
||||
"actor": "informed-decision",
|
||||
"principal": "ops-warden",
|
||||
"purpose": "Attend the graded lockdown / break-glass seal for ops-warden trust-root work",
|
||||
"target": {
|
||||
"id": "warden-wp-0027-t02",
|
||||
"type": "trust-root",
|
||||
"system": "ops-warden"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"memo_id": "infd-20260914-d01",
|
||||
"create_client": "informed-decision-sitting-requester",
|
||||
"binding": {
|
||||
"action": "retire",
|
||||
"actor": "informed-decision",
|
||||
"principal": "the-custodian",
|
||||
"purpose": "After HA failover and restore drills pass, retire WSL2 as a State Hub fallback",
|
||||
"target": {
|
||||
"id": "cust-wp-0038-t08",
|
||||
"type": "operating-model",
|
||||
"system": "the-custodian"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"memo_id": "infd-20260914-d02",
|
||||
"create_client": "informed-decision-sitting-requester",
|
||||
"binding": {
|
||||
"action": "confirm",
|
||||
"actor": "informed-decision",
|
||||
"principal": "helixforge-factory",
|
||||
"purpose": "Confirm the existing operator-group claim for CCR-2026-0019 as required by the factory identity/audit/approval path",
|
||||
"target": {
|
||||
"id": "ccr-2026-0019",
|
||||
"type": "ccr",
|
||||
"system": "helixforge-factory"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"memo_id": "infd-20260914-d03",
|
||||
"create_client": "informed-decision-sitting-requester",
|
||||
"binding": {
|
||||
"action": "accept",
|
||||
"actor": "informed-decision",
|
||||
"principal": "mason",
|
||||
"purpose": "Accept the fluid-telegram operator credential lane plan so construction may proceed",
|
||||
"target": {
|
||||
"id": "mason-wp-0005",
|
||||
"type": "workplan",
|
||||
"system": "mason"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"memo_id": "infd-20260914-d04",
|
||||
"create_client": "informed-decision-sitting-requester",
|
||||
"binding": {
|
||||
"action": "confirm",
|
||||
"actor": "informed-decision",
|
||||
"principal": "railiance-clock",
|
||||
"purpose": "Confirm ecosystem ownership and the security role for Railiance Clock as specified",
|
||||
"target": {
|
||||
"id": "rclk-wp-0002-t01",
|
||||
"type": "workplan",
|
||||
"system": "railiance-clock"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
21
docs/keycape-sitting-requester-registration.json
Normal file
21
docs/keycape-sitting-requester-registration.json
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
{
|
||||
"clientId": "informed-decision-sitting-requester",
|
||||
"displayName": "Informed Decision compact-sitting approval requester",
|
||||
"audience": "approval-engine",
|
||||
"allowedScopes": [
|
||||
"approval:create"
|
||||
],
|
||||
"grantTypes": [
|
||||
"client_credentials"
|
||||
],
|
||||
"clientType": "confidential",
|
||||
"secretRef": "env:KEYCAPE_INFORMED_DECISION_SITTING_REQUESTER_CLIENT_SECRET",
|
||||
"serviceSubject": "informed-decision",
|
||||
"tenant": "tenant:platform",
|
||||
"roles": [
|
||||
"informed-decision-sitting-requester"
|
||||
],
|
||||
"tokenLifetime": "15m",
|
||||
"status": "requested",
|
||||
"applied": false
|
||||
}
|
||||
79
docs/keycape-sitting-requester-registration.md
Normal file
79
docs/keycape-sitting-requester-registration.md
Normal file
|
|
@ -0,0 +1,79 @@
|
|||
# Sitting requester — create-only client (requested, not applied)
|
||||
|
||||
**Workplan task:** `INFD-WP-0002-T03`
|
||||
**For:** `key-cape` (same registration shape as `secrets-engine-requester`)
|
||||
**Copied to:** `approval-engine` (`docs/keycape-service-registrations.md` —
|
||||
“no requester identity has been settled for `approval:create`”)
|
||||
**Status:** requested 2026-09-14. **Not registered. Not in OpenBao. No secret
|
||||
is in this repository.**
|
||||
|
||||
This is the missing presenter for compact Decision Memo sittings whose
|
||||
protected side effect is a **work-record update** (`INFD-WP-0002-T04`), not a
|
||||
PEP consume.
|
||||
|
||||
## Why a second client
|
||||
|
||||
`informed-decision-approver` is the **human** browser client
|
||||
(`approval:read` + `approval:approve`). Humans cannot `POST /v1/approvals`.
|
||||
`secrets-engine-requester` is create-only with `sub=secrets-engine` and must
|
||||
not draft WSL2 retirement, clock ownership, or mason plan accepts —
|
||||
`binding.actor` has to match the authenticated subject.
|
||||
|
||||
This client names the presenter for *this* sitting.
|
||||
|
||||
## The strings
|
||||
|
||||
| Field | Value |
|
||||
| --- | --- |
|
||||
| `client_id` | `informed-decision-sitting-requester` |
|
||||
| Grant | `client_credentials` |
|
||||
| Client type | confidential |
|
||||
| Audience | `approval-engine` (resource server, never the OAuth client id) |
|
||||
| Scopes | `approval:create` **only** |
|
||||
| `serviceSubject` / token `sub` | `informed-decision` |
|
||||
| `tenant` | `tenant:platform` (exact) |
|
||||
| `principal_type` | `service` |
|
||||
| Role | `informed-decision-sitting-requester` |
|
||||
| Token lifetime | 15m |
|
||||
| Redirect URI | **none** — this is not a browser client |
|
||||
|
||||
Machine-readable copy: `keycape-sitting-requester-registration.json`.
|
||||
`secretRef` is a custody *name*. It is not a credential.
|
||||
|
||||
## Anti-requirements
|
||||
|
||||
- **No** `approval:approve`. That stays on the human PKCE client.
|
||||
- **No** `approval:consume`. Consumption belongs to a PEP. This sitting's
|
||||
T04 path is repo files + `fix-consistency`.
|
||||
- **No** `approval:read` on this client. The human already has read.
|
||||
- Do **not** reuse `approval-engine-operator` (cancelled bundle, too wide).
|
||||
- Do **not** reuse `secrets-engine-requester` for unrelated acts.
|
||||
- Do **not** register this client until `key-cape` owns the row and
|
||||
`railiance-platform` owns attended secret custody. This document is not
|
||||
admission.
|
||||
|
||||
## Binding rules at create time
|
||||
|
||||
`POST /v1/approvals` requires `binding.actor ==` the token `sub`, so actor is
|
||||
always `informed-decision`.
|
||||
|
||||
| Binding field | Value for this sitting |
|
||||
| --- | --- |
|
||||
| `actor` | `informed-decision` |
|
||||
| `principal` | owning system of the work record (not the human, not this client by default) |
|
||||
| `action` / `purpose` / `target` | one memo, one act — see `docs/batches/2026-09-14/approval-create-intents.json` |
|
||||
| `human_control` | `true` |
|
||||
| `pdp_path` | `false` — no consume PEP on T04 |
|
||||
| `required_count` | 1 |
|
||||
|
||||
`infd-20260914-c01` (SECRETS-WP-0010 native delivery) may belong on
|
||||
`secrets-engine-requester` instead if a later consume is in-scope. It is
|
||||
marked undecided in the intents file. Do not POST it on this client until
|
||||
that is stated.
|
||||
|
||||
## What this does not do
|
||||
|
||||
It does not bind. It does not admit Flex Auth. It does not load the review
|
||||
store. After KeyCape registers the row and platform materializes custody,
|
||||
an attended create can mint the eight (or seven) objects; then
|
||||
`tools/attach_compact_bindings.py` with the operator's live KeyCape `sub`.
|
||||
47
tests/test_sitting_requester_registration.py
Normal file
47
tests/test_sitting_requester_registration.py
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
import json
|
||||
from pathlib import Path
|
||||
|
||||
from informed_decision.records import memo_from
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
REG = json.loads((ROOT / "docs" / "keycape-sitting-requester-registration.json").read_text())
|
||||
INTENTS = json.loads((ROOT / "docs" / "batches" / "2026-09-14" / "approval-create-intents.json").read_text())
|
||||
|
||||
|
||||
def test_sitting_requester_is_create_only_and_unapplied():
|
||||
assert REG["clientId"] == "informed-decision-sitting-requester"
|
||||
assert REG["audience"] == "approval-engine"
|
||||
assert REG["allowedScopes"] == ["approval:create"]
|
||||
assert REG["grantTypes"] == ["client_credentials"]
|
||||
assert REG["clientType"] == "confidential"
|
||||
assert REG["serviceSubject"] == "informed-decision"
|
||||
assert REG["tenant"] == "tenant:platform"
|
||||
assert REG["applied"] is False
|
||||
assert "redirect" not in json.dumps(REG).lower()
|
||||
forbidden = {"approval:approve", "approval:consume", "approval:read", "openid"}
|
||||
assert forbidden.isdisjoint(REG["allowedScopes"])
|
||||
assert not REG["secretRef"].startswith("s.") and ":" in REG["secretRef"]
|
||||
|
||||
|
||||
def test_create_intents_cover_the_sitting_and_are_not_posted():
|
||||
assert INTENTS["posted"] is False
|
||||
assert INTENTS["human_control"] is True
|
||||
assert INTENTS["pdp_path"] is False
|
||||
ids = [row["memo_id"] for row in INTENTS["intents"]]
|
||||
sitting_ids = []
|
||||
batch_root = ROOT / "docs" / "batches" / "2026-09-14"
|
||||
for name in ("credentials", "decisions"):
|
||||
index = json.loads((batch_root / name / "index.json").read_text())
|
||||
sitting_ids.extend(row["memo_id"] for row in index["ordinal"])
|
||||
assert ids == sitting_ids
|
||||
undecided = [row for row in INTENTS["intents"] if row["create_client"] == "undecided"]
|
||||
assert [row["memo_id"] for row in undecided] == ["infd-20260914-c01"]
|
||||
for row in INTENTS["intents"]:
|
||||
binding = row["binding"]
|
||||
assert set(binding) == {"action", "actor", "principal", "purpose", "target"}
|
||||
assert binding["actor"] == "informed-decision"
|
||||
assert "digest" not in binding
|
||||
batch = "credentials" if "-c0" in row["memo_id"] else "decisions"
|
||||
memo = memo_from(json.loads((batch_root / batch / f"{row['memo_id']}.memo.json").read_text()))
|
||||
assert binding["target"]["id"] == memo.binding.target.id
|
||||
assert memo.question.startswith(binding["purpose"][:20]) or binding["purpose"] in memo.question or memo.question.rstrip("?") in binding["purpose"]
|
||||
|
|
@ -144,6 +144,15 @@ create approvals or dispositions. Evidence:
|
|||
`docs/evidence/2026-09-14-infd-0002-t03-accept-reopened.json`.
|
||||
Task stays `wait`.
|
||||
|
||||
2026-09-14 22:44 UTC — **sitting requester requested, not registered.**
|
||||
`docs/keycape-sitting-requester-registration.md` asks key-cape for a
|
||||
create-only confidential client (`informed-decision-sitting-requester`,
|
||||
`sub=informed-decision`, scope `approval:create` only, no approve/consume,
|
||||
no redirect). Intents for the eight bindings are in
|
||||
`docs/batches/2026-09-14/approval-create-intents.json` (`posted: false`;
|
||||
`c01` create-client undecided). No secret, no POST, no bind. Task stays
|
||||
`wait`.
|
||||
|
||||
## Feed outcomes back to State Hub without hub-authoring
|
||||
|
||||
```task
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue