diff --git a/.repo-classification.yaml b/.repo-classification.yaml new file mode 100644 index 0000000..4bd71af --- /dev/null +++ b/.repo-classification.yaml @@ -0,0 +1,28 @@ +repo_classification: + standard: Repo Classification Standard + version: "1.0" + classified_at: "2026-09-09" + classified_by: claude + category: product + domain: infotech + secondary_domains: [] + capability_tags: + - governance + - evidence + - identity + - user-interface + - audit + business_stake: + - technology + - legal + - operations + business_mechanics: + - control + - operation + notes: >- + Presentation and binding surface for decisions — the Decision Memo, and the + browser-facing approver UI that approval-engine deliberately does not + contain. Category is product, not project: this is a durable offering with + emerging product requirements (see workplans/INFD-WP-0001 T03), not a + bounded cross-repo coordination effort, so the prj- flavor does not apply. + Not a decision point; access-engine remains the only PDP. diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..46c6b30 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,296 @@ +# informed-decision — Agent Instructions + +## Repo Identity + +**Purpose:** Presentation and binding surface for decisions — the Decision Memo, and the browser-facing approver UI that approval-engine does not contain. + +**Domain:** infotech +**Repo slug:** informed-decision +**Topic ID:** `a6c6e745-bf54-4465-9340-1534a2be493e` +**Workplan prefix:** `INFD-WP-` +**Category:** product (not `prj-` project flavor — see `.repo-classification.yaml`) + +Read in this order: `INTENT.md` (stable purpose) → `GOAL.md` (current stage) → +`SCOPE.md` (what actually exists) → `workplans/`. + +`history/20260909-initial-exploration/` is the founding provenance record and is +**never edited**. Governed copies of the schema, canonicalizer and vectors live +in `schemas/` and the package once `INFD-WP-0001-T06` promotes them. + +--- + +## State Hub Integration + +The Custodian State Hub tracks work across all domains. Codex uses HTTP REST and +the `statehub` CLI by default. MCP is opt-in because the current Codex MCP bridge +adds severe call latency; the full administrative MCP surface remains available +to clients that need it. + +| Context | URL | +|---------|-----| +| Local workstation | `http://127.0.0.1:8000` | +| Remote via tunnel | `http://127.0.0.1:18000` | +| Optional local edge relay | http://127.0.0.1:18080 | + +When an operator has enabled the edge relay, set API_BASE to the relay URL. +Queueable writes return an explicit queued receipt if the central hub is +unreachable. Treat that as pending local evidence, then ask the operator to run +statehub outbox status/replay after connectivity returns. + +Codex workspace-write sandboxes need network access enabled to reach the host's +loopback listener. Bootstrap this once with `make -C ~/state-hub configure-codex` +and restart Codex. The canonical REST health endpoint is `/state/health`, not +`/health`. If a sandboxed loopback probe fails, retry it with escalated execution +before declaring State Hub unavailable; a managed Codex permission profile may +still enforce isolated networking. Experimental MCP can be enabled explicitly +with `make -C ~/state-hub configure-codex WITH_MCP=1`. + +### Orient at session start + +```bash +# Offline brief — works without hub connection +cat .custodian-brief.md + +# Active workplans for this domain +curl -s "http://127.0.0.1:8000/workplans/?topic_id=cee7bedf-2b48-46ef-8601-006474f2ad7a&status=active" \ + | python3 -m json.tool + +# Check inbox +curl -s "http://127.0.0.1:8000/messages/?to_agent=informed-decision&unread_only=true" \ + | python3 -m json.tool +``` + +Mark a message read: +```bash +curl -s -X PATCH "http://127.0.0.1:8000/messages//read" \ + -H "Content-Type: application/json" -d '{}' +``` + +### Log progress (required at session close) + +```bash +curl -s -X POST http://127.0.0.1:8000/progress/ \ + -H "Content-Type: application/json" \ + -d '{ + "summary": "what was done", + "event_type": "note", + "author": "codex", + "workplan_id": "", + "task_id": "" + }' +``` + +Omit `workplan_id` / `task_id` when not applicable. + +### Update task status + +```bash +curl -s -X PATCH "http://127.0.0.1:8000/tasks/" \ + -H "Content-Type: application/json" \ + -d '{"status": "progress"}' +# values: wait | todo | progress | done | cancel +``` + +### Flag a task for human review + +```bash +curl -s -X PATCH "http://127.0.0.1:8000/tasks/" \ + -H "Content-Type: application/json" \ + -d '{"needs_human": true, "intervention_note": "reason"}' +``` + +--- + +## Session Protocol + +**Start:** +1. `cat .custodian-brief.md` — domain goal and open workplans (offline-safe) +2. Check inbox: `GET /messages/?to_agent=informed-decision&unread_only=true`; mark read +3. Scan workplans: `ls workplans/` — note `status: ready`, `active`, or `blocked` files and open tasks +4. Check human-needed tasks: `GET /tasks/?needs_human=true` + +**During work:** +- Update task statuses in workplan files as tasks progress +- Record significant decisions via `POST /decisions/` + +**Close:** +1. Update workplan file task statuses to reflect progress +2. If finishing a workplan: hand off **residuals** as live work records first + (intake with `origin: residual` + `origin_ref: `, or a next workplan / + decision / engagement). Do not park leftovers only in prose or `SCOPE.md`. + Canon: `the-custodian/canon/standards/work-record-types_v0.1.md` § Residuals. +3. Log: `POST /progress/` with a summary of what changed (name handoff ids) +4. After workplan file changes, run: + ```bash + statehub fix-consistency + ``` + Coding agents should run this directly; ask the operator only if the CLI or + State Hub API is unavailable. This syncs task status from files into the hub DB. + If C-06/C-11 reports that this host is not the identifier registrar, do not + retry, export `STATEHUB_REGISTRAR`, or register records by hand. Commit and + push the file-backed work first, then run the repo-manager fallback once: + ```bash + uv run --project ~/repo-manager rmgr registrar-reconcile \ + --path . --confirm-primary --push + ``` + If unavailable, send one deduplicated registrar request to `repo-manager` + naming the repo and canonical ids; UUID absence does not block local work. + +--- + +## Credential and access routing + +**Audience:** Codex, Claude Code, Grok, and custodian agents that call **llm-connect** +for inference. Run this check **before** requesting secrets, API keys, SSH access, +login tokens, or database passwords — in any repo, not only `ops-warden`. + +The companion (`net-kingdom/SECURITY-COMPANION.md`) says what the rules are; +`ops-warden` stewards the paths through them. **Do not** message `ops-warden` +on State Hub expecting a secret value; the reply is a pointer, not a key. + +### Lookup (do this first) + +```bash +warden route find "" --json +warden route show --json +``` + +Requires the `warden` CLI from `~/ops-warden`. + +| Agent runtime | How to orient | +| --- | --- | +| **Codex / Grok** (shell, HTTP State Hub) | `warden route`; inbox `to_agent=informed-decision` is for coordination, not secret vending | +| **Claude Code** (MCP when available) | domain summary for workplans; **still** use `warden route` for credential ownership | +| **llm-connect** | Never put secret retrieval in prompts | + +### Quick routing table + +| I need… | Owner | ops-warden executes? | +| --- | --- | --- | +| SSH cert (`adm`/`agt`/`atm`) | ops-warden | **Yes** — `warden sign` | +| API key, DB password, provider token | OpenBao | No — route only | +| Login / OIDC / MFA | key-cape | No — route only | +| Authorization decision | access-engine (`flex-auth`) | No — route only | +| Approval current-state | **this engine** (not yet implemented) | No | +| SSH tunnel | ops-bridge | No — route only | + +### Anti-patterns + +- Asking State Hub or `ops-warden` to vend a secret +- Pasting secrets into Git, State Hub, workplans, logs, or chat +- Treating a callable tool as permission (companion §7) + +**Canon:** `~/ops-warden/wiki/CredentialRouting.md` + + + +## This repository's layer + +**Provisional: PEP-shaped**, statute §6.4 / companion §5. Not ratified — the +catalog row does not exist and `layer.yaml` is not written yet. +`INFD-WP-0001-T02` takes the placement to `gate-house`; the ruling wins over +anything asserted in `INTENT.md` or here. + +Hard rules, regardless of how the ruling lands: + +- **Never decide.** No endpoint in this repository answers "may this actor do + X". That is `access-engine`, always and only (statute §6). This surface + renders a question and records a human's answer; a disposition is evidence of + an act, not an authorization verdict. +- **Never own approval state.** `approval-engine` is the sole mutator. Do not + cache validity, do not infer consumption from a decision record, and do not + request scope `approval:consume` — the engine refuses it for human principals + and consumption belongs to the PEP that causes the side effect + (`GH-DEC-2026-003`). +- **Never invent identity.** Every principal is authenticated by `key-cape`. + No local credential, no self-issued assurance level. +- **Never let awareness enter the signature.** `view_hash` covers only what the + person committed to. Proposed roles, other-tenant orientation and last-session + summaries are hashed separately and are unsigned unless explicitly promoted + into `awareness_promoted`. +- **Never let an agent bind.** An agent may assemble a memo; only a human + completes a disposition. +- **Never fork the schema.** A field added for approvals must be expressible for + an L0 login banner, or it does not go in the shared object. +- **Fail closed.** Degrading into showing a memo that cannot be bound is + acceptable. Degrading into binding without evidence is not. +- Remote hub: this host reaches State Hub on `http://127.0.0.1:8000` (primary + on railiance01). Do not use `127.0.0.1:18000` — that reverse tunnel is being + retired (`CUST-WP-0067`). + +--- + +## Workplan Convention (ADR-001) + +Work items originate as files in this repo — not in the hub. The hub is a +read/cache/index layer that rebuilds from files. + +**File location:** `workplans/INFD-WP-NNNN-.md` + +**Archived location:** finished workplans may move to +`workplans/archived/YYMMDD-INFD-WP-NNNN-.md`. The `YYMMDD` prefix is +the completion/archive date; the frontmatter `id` does not change. + +**Ad Hoc Tasks:** small opportunistic fixes discovered during a session use +`workplans/ADHOC-YYYY-MM-DD.md`, workplan id +`INFD-WP-ADHOC-YYYY-MM-DD`, and task ids +`INFD-WP-ADHOC-YYYY-MM-DD-T01`, etc. `APPROVAL-WP` includes its final `-WP` +token. Unqualified historic `ADHOC-*` ids are grandfathered and must not be +copied into new records. Use this only for low-risk work completed directly; +create a normal workplan for anything needing analysis, design, approval, +dependencies, or multiple phases. + +**Frontmatter:** + +```yaml +--- +id: INFD-WP-NNNN +type: workplan +title: "..." +domain: infotech +repo: approval-engine +status: proposed | ready | active | blocked | backlog | finished | archived +owner: codex +topic_slug: ... +created: "YYYY-MM-DD" +updated: "YYYY-MM-DD" +state_hub_workstream_id: "" # fix-consistency — do not edit (legacy field name; workplan UUID) +--- +``` + +Use `proposed` for a new draft, `ready` after review against current repo +state, and `finished` after implementation. `stalled` and `needs_review` are +derived health labels, not frontmatter statuses. + +**Terminology:** workplan is the fleet term; `workstream` appears only in legacy +API/MCP/frontmatter bridges until `STATE-WP-0069` retires them — see +`the-custodian/canon/standards/workplan-terminology-fleet_v0.1.md`. + +**Task block format** (one per `##` section): + +``` +## Task Title + +` ` `task +id: INFD-WP-NNNN-T01 +status: wait | todo | progress | done | cancel +priority: high | medium | low +state_hub_task_id: "" # written by fix-consistency — do not edit +` ` ` + +Task description text. +``` + +Status progression: `todo` → `progress` → `done`; use `wait` for waiting/blocked work and `cancel` for stopped work. + +**Residuals when finishing:** actionable leftovers become live work records +before `status: finished` — usually an intake (`origin: residual`, +`origin_ref: INFD-WP-NNNN`) or a spawned workplan. Residual is a *role*, +not a kind. Fleet list lives on State Hub, not in `SCOPE.md`. + +To create a new workplan: +1. Write the file following the format above +2. Run `statehub fix-consistency` locally. +3. On a non-registrar C-06/C-11 skip, use the repo-manager fallback documented + above exactly once; never set registrar authority directly. diff --git a/GOAL.md b/GOAL.md index 9f4eba3..c03bd22 100644 --- a/GOAL.md +++ b/GOAL.md @@ -1,11 +1,19 @@ --- repo: informed-decision -repo_flavor: project -project_status: active +category: product stage: 1 +stage_status: active started: "2026-09-09" --- +> **Flavor note.** This is a durable **product** repository, not a `prj-` +> project repository. Per `project-repository-flavor_v0.1.md`, durable products +> use `INTENT.md` and an ordinary category; the `prj-` flavor is for bounded +> cross-repo coordination efforts and is not used here. `GOAL.md` is retained +> as the *stage* statement: `INTENT.md` is stable and aspirational, this file +> is what the current stage must achieve and is replaced when the stage turns +> over. + # Goal — informed-decision, Stage 1 ## Outcome diff --git a/SCOPE.md b/SCOPE.md new file mode 100644 index 0000000..21b6775 --- /dev/null +++ b/SCOPE.md @@ -0,0 +1,75 @@ +# SCOPE + +> Implemented-and-first-cut boundary for agents and contributors. Aspirational +> direction belongs in `INTENT.md`; the current stage belongs in `GOAL.md`; +> current work and gates belong in `workplans/`. + +## Status — 2026-09-09 + +**Nothing is implemented.** This repository currently contains founding +documents, the preserved founding exploration under `history/`, and +`workplans/INFD-WP-0001`. There is no package, no service, no deployment, and +no UI. + +This file exists because the Repo Manager requires it and because an honest +empty boundary is more useful than an imagined one. It is rewritten in +`INFD-WP-0001-T06`, once the `gate-house` layer ruling (T02) and the +specifications (T03–T05) have fixed the real boundary. **Do not read the +sections below as describing working code.** + +## One-liner + +informed-decision is the presentation and binding surface for decisions: it +renders a Decision Memo to the human who holds the mandate, records what was +shown, and binds their identity to the act — and owns the browser-facing +approver UI that `approval-engine` deliberately does not contain. + +## Core Idea + +A decision surface is not a workflow engine and not a decision point. This +repository owns the Decision Memo object, the presentation record, the +canonicalization that produces `view_hash` / `awareness_hash`, the disposition +vocabulary, and the evidence bundle export. It does not evaluate whether an act +is permitted, does not hold approval current-state, and does not archive the +trail. + +## In Scope — first cut (Stage 1, not yet built) + +- The Decision Memo object and its versions, promoted from + `history/20260909-initial-exploration/` into governed `schemas/`. +- Canonicalization of the binding and awareness documents, with the four + isolation vectors under test. +- The presentation record: what was rendered, to whom, when, in which locale + and UI release. +- Required-highlight acknowledgment as a precondition of binding. +- The disposition vocabulary — `comment`, `discuss`, `return`, `forward`, + `escalate`, `acknowledge`, `accept`, `decline`, `withdraw`, `configure` — + and its legality tables. +- The browser-facing OIDC client for human principals: authorization-code + + PKCE against `key-cape`, yielding a token with `aud=approval-engine`, + `principal_type: human`, scope `approval:approve`. +- An L3 approver surface calling `approval-engine`'s approval-entry mutation. +- The evidence bundle as an offline-verifiable export. + +## Out of Scope + +- Authorization decisions — `access-engine`, always and only (statute §6). +- The approval object, its state machine, validity and consumption — + `approval-engine`. This surface never caches validity, never infers + consumption, never requests `approval:consume`. +- Approval doctrine: which acts require approval, how many approvers, which + separations of duty — `gate-house`. +- Identity and authentication — `key-cape`. Identity is imported, never + invented here. +- The evidence archive — `audit-core`. This repository emits and exports. +- Credentials materialized after a decision — `secrets-engine`. +- Notification transport, ticketing, and general workflow. +- L4/L5, QES, QTSP integration, qualified archival retention. +- The mandate graph. Stage 1 routes to a named approver and does not maintain a + map of who may bind what — a known, accepted limitation recorded in `GOAL.md`. + +## Layer placement + +**Provisional and unratified.** The working position is PEP-shaped under +statute §6.4 and companion §5. `layer.yaml` does not exist yet and is written +from the `gate-house` ruling in `INFD-WP-0001-T02`, not from this file. diff --git a/WORK-RECORDS.md b/WORK-RECORDS.md new file mode 100644 index 0000000..33ecff6 --- /dev/null +++ b/WORK-RECORDS.md @@ -0,0 +1,19 @@ +# Work Records — informed-decision + +> Generated by `statehub fix-consistency` (CUST-WP-0061-T04, work-record +> stage 3). Do not edit by hand — edit the source file/block listed for +> each record and re-run fix-consistency to refresh this index. Archived +> workplans are omitted; closed decisions/intakes/engagements stay listed +> so recently-resolved work is still visible. [auto] + +| Kind | ID | Status | Lane | Source | +| --- | --- | --- | --- | --- | +| workplan | INFD-WP-0001 | proposed | — | workplans/INFD-WP-0001-founding-specs-and-approver-ui-ownership.md | +| task | INFD-WP-0001-T01 | done | — | workplans/INFD-WP-0001-founding-specs-and-approver-ui-ownership.md | +| task | INFD-WP-0001-T02 | todo | — | workplans/INFD-WP-0001-founding-specs-and-approver-ui-ownership.md | +| task | INFD-WP-0001-T03 | todo | — | workplans/INFD-WP-0001-founding-specs-and-approver-ui-ownership.md | +| task | INFD-WP-0001-T04 | todo | — | workplans/INFD-WP-0001-founding-specs-and-approver-ui-ownership.md | +| task | INFD-WP-0001-T05 | todo | — | workplans/INFD-WP-0001-founding-specs-and-approver-ui-ownership.md | +| task | INFD-WP-0001-T06 | todo | — | workplans/INFD-WP-0001-founding-specs-and-approver-ui-ownership.md | +| task | INFD-WP-0001-T07 | todo | — | workplans/INFD-WP-0001-founding-specs-and-approver-ui-ownership.md | +| task | INFD-WP-0001-T08 | todo | — | workplans/INFD-WP-0001-founding-specs-and-approver-ui-ownership.md | diff --git a/workplans/INFD-WP-0001-founding-specs-and-approver-ui-ownership.md b/workplans/INFD-WP-0001-founding-specs-and-approver-ui-ownership.md index b5a3f6a..7c46f6f 100644 --- a/workplans/INFD-WP-0001-founding-specs-and-approver-ui-ownership.md +++ b/workplans/INFD-WP-0001-founding-specs-and-approver-ui-ownership.md @@ -11,6 +11,7 @@ created: "2026-09-09" updated: "2026-09-09" origin: founding origin_ref: history/20260909-initial-exploration/InitialExploration.md +state_hub_workstream_id: "a985a65a-08f7-5a39-8645-b618ea022657" --- # INFD-WP-0001 — Founding specs and approver-UI ownership @@ -44,6 +45,7 @@ walking skeleton**. Full L3 product build is residual and belongs to id: INFD-WP-0001-T01 status: done priority: high +state_hub_task_id: "abe83f6a-18d2-5fe5-bd01-56b6fd0babbe" ``` Write the repository's stable statements of purpose and current stage, derived @@ -56,10 +58,23 @@ invariants and definition of done; `README.md` orients a new reader in under a minute; `history/20260909-initial-exploration/` is preserved unmodified as the provenance record. -Completed 2026-09-09: `INTENT.md`, `GOAL.md` and `README.md` written. `SCOPE.md` -is deliberately deferred to T06 — a scope file written before the layer ruling -and the specs would describe an imagined boundary, which is the drift `SCOPE.md` -exists to prevent. +Completed 2026-09-09: `INTENT.md`, `GOAL.md`, `README.md`, `SCOPE.md`, +`AGENTS.md` and `.repo-classification.yaml` written; repo registered in the +State Hub and `INFD-WP-0001` indexed by `fix-consistency`. + +Two corrections made during the same task, recorded rather than silently fixed: + +- `GOAL.md` first declared `repo_flavor: project`. That is wrong. + `project-repository-flavor_v0.1.md` reserves the `prj-` flavor for bounded + cross-repo coordination efforts and states that durable products use + `INTENT.md` and an ordinary category. This is a durable product; + `.repo-classification.yaml` sets `category: product`. `GOAL.md` is retained + as the *stage* statement, which the flavor standard does not forbid. +- `SCOPE.md` was initially deferred to T06 on the reasoning that a scope file + written before the layer ruling describes an imagined boundary. The Repo + Manager requires it (C-35), and the reasoning was better served by writing an + honestly empty one: the shipped `SCOPE.md` states plainly that nothing is + implemented and that T06 rewrites it. T06 now rewrites rather than creates. ## Settle layer placement and approver-UI ownership with gate-house @@ -67,6 +82,7 @@ exists to prevent. id: INFD-WP-0001-T02 status: todo priority: high +state_hub_task_id: "4f94134b-2260-5404-84e0-12f2b08ef565" ``` Take the ownership question to `gate-house` as doctrine rather than asserting a @@ -104,6 +120,7 @@ recorded as a decision, not left implicit. Blocking for T05 and T07. id: INFD-WP-0001-T03 status: todo priority: high +state_hub_task_id: "86465a35-1af5-5956-a767-57ad838dffa9" ``` Write `docs/specs/ProductRequirementsDocument.md` for Stage 1: the L3 approval @@ -130,6 +147,7 @@ names what it is deliberately not requiring and why. id: INFD-WP-0001-T04 status: todo priority: medium +state_hub_task_id: "00a83db5-fe0e-522a-b885-6f9ef034bc07" ``` Write `docs/specs/UseCaseCatalog.md` covering the full depth spectrum L0–L5, with @@ -156,6 +174,7 @@ catalog states for each level which estate repository would consume it. id: INFD-WP-0001-T05 status: todo priority: high +state_hub_task_id: "20ea118e-0657-5054-8aa2-b316444f4000" ``` Write `docs/specs/ArchitectureBlueprint.md`. Depends on T02 — the layer ruling @@ -186,6 +205,7 @@ are placeholders. id: INFD-WP-0001-T06 status: todo priority: high +state_hub_task_id: "47cb3f7a-e349-5c81-a304-86275e058a85" ``` Promote the exploration artifacts from `history/` into governed, tested @@ -210,13 +230,16 @@ offline, its relationship to `audit-core`'s archive, and — carried over from that a hash chain proves records were not altered after arrival and cannot prove a record was never sent. -Write `SCOPE.md` as the last step of this task, once the layer ruling and the -specs have fixed the real boundary. +**Rewrite** `SCOPE.md` as the last step of this task. The version shipped in +T01 is honestly empty — it states that nothing is implemented. Replace it with +the real implemented-and-first-cut boundary once the layer ruling and the specs +have fixed it, and drop the T01 status banner. Acceptance: schema, canonicalizer and vectors live outside `history/` and are exercised in CI; the three published expected hashes reproduce byte-for-byte; -`EvidenceModel.md` states the residual it does not close; `SCOPE.md` exists and -describes the implemented-and-first-cut boundary, not the aspiration. +`EvidenceModel.md` states the residual it does not close; `SCOPE.md` describes +the implemented-and-first-cut boundary rather than the aspiration, and no longer +carries the T01 "nothing is implemented" banner. ## Publish the OIDC browser-client contract to key-cape @@ -224,6 +247,7 @@ describes the implemented-and-first-cut boundary, not the aspiration. id: INFD-WP-0001-T07 status: todo priority: high +state_hub_task_id: "38a83a76-f152-55bf-8a9a-6132fd6d9642" ``` Own and publish the two strings `approval-engine` could not supply: the human @@ -253,6 +277,7 @@ repository.** id: INFD-WP-0001-T08 status: todo priority: medium +state_hub_task_id: "b5c1d329-9580-5672-9640-2930cbbb729a" ``` Prove the specs against reality with the thinnest possible L3 path: sign in via