docs: preserve reviewed NetKingdom session artifacts
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 1s
Reject generated-only commits / generated-commit-guard (push) Successful in 12s

This commit is contained in:
codex 2026-11-01 23:32:07 +01:00
parent 592d8d1082
commit 1fc8eed19c
50 changed files with 11442 additions and 0 deletions

View file

@ -0,0 +1,216 @@
---
id: NK-WP-0013
type: workplan
title: "Playbook Capability Contract"
domain: infotech
repo: net-kingdom
status: finished
owner: worsch
topic_slug: netkingdom
planning_priority: high
planning_order: 13
created: "2026-05-21"
updated: "2026-05-22"
depends_on:
- NK-WP-0006
state_hub_workstream_id: 32a54d8e-8633-42a6-8ec1-104842c581c1
---
> **Terminology note:** Historical text in this archived workplan may use the legacy term "workstream". The fleet term is **workplan** (`canon/standards/workplan-terminology-fleet_v0.1.md`).
# NK-WP-0013 — Playbook Capability Contract
> The **orchestration-layer analog of the IAM Profile**. ADR-0007's
> meta-orchestration refinement named this as a prerequisite: for NetKingdom
> to select and parametrize playbooks reliably, each Railiance playbook must
> publish a **declared interface** — the capability it provisions, its
> parameters (with defaults and constraints), and the responsibility it
> claims. Without it, meta-orchestration composes against implicit behavior
> and breaks silently when a playbook changes. This workplan defines that
> contract.
## Goal
Define the **Playbook Capability Contract** — the schema and vocabulary by
which a playbook declares:
1. **what capability it provisions** (controlled vocabulary, aligned to the
capability ladder and the responsibility-map resource kinds),
2. **its parameters** — name, type, default, constraints, required/optional,
and which are security-sensitive, and
3. **the responsibility it claims** — which element owns which resources, and
which trust state(s) / readiness checks it satisfies or requires.
…plus the **catalog/consumption model** NetKingdom meta-orchestration uses
to select, parametrize, and build a responsibility map for a scenario, and a
**conformance validator** for declarations.
## Ownership (the boundary this realizes)
By symmetry with the IAM Profile, the **consumer that needs a stable
interface defines the contract; the provider conforms**:
| | Contract owner | Publishes conformant declarations | Consumer |
|---|---|---|---|
| Identity | NetKingdom (IAM Profile) | key-cape / Keycloak | apps, flex-auth |
| Orchestration | **NetKingdom (this contract)** | Railiance playbooks | NetKingdom meta-orchestration |
NetKingdom owns the contract schema; Railiance owns the playbooks and
publishes one declaration per playbook; **execution stays in Railiance**
(ADR-0007 unchanged). The contract makes a playbook change a versioned event
rather than a silent break.
## Scope
In scope:
- ownership & boundary decision (ADR) and contract versioning governance
- the capability vocabulary a declaration draws from
- the parameter declaration format (defaults, constraints, sensitivity)
- the responsibility-claim and trust-state/readiness format
- the catalog and the meta-orchestration consumption model
- a conformance validator for declarations
- coordinated adoption proof with one reference Railiance playbook
Out of scope:
- authoring the playbooks themselves (Railiance owns execution)
- writing declarations for every existing playbook (Railiance work; this
workplan proves the contract with one reference declaration)
- a dedicated execution-orchestration repo (deferred per ADR-0007)
## Tasks
```task
id: NK-WP-0013-T1
state_hub_task_id: d40f8b29-e983-4d52-bc1f-5f1c51709e7d
status: done
priority: high
```
**Ownership & boundary decision (ADR-0012).** Record that NetKingdom owns
the Playbook Capability Contract schema (consumer-defines-contract, IAM
Profile precedent), Railiance authors playbooks and publishes conformant
declarations, and execution stays in Railiance (ADR-0007). Decide whether
the contract is NetKingdom-owned outright or NetKingdom-owned with Railiance
co-design. Define contract **versioning and breaking-change governance**.
```task
id: NK-WP-0013-T2
state_hub_task_id: ece4b5b1-e1c2-449d-b0f4-83b7010bc838
status: done
priority: high
```
**Capability vocabulary.** Define the controlled vocabulary of capabilities
a playbook can declare it provisions, aligned to the **capability ladder
(C0–C6)** and the **responsibility-map resource kinds** (identities,
roles/scopes/policies, secrets/credentials, infrastructure resources). This
is what "capability" means in a declaration, so two playbooks providing the
same capability are comparable.
```task
id: NK-WP-0013-T3
state_hub_task_id: c956f4a8-b9fa-44ab-8174-31999b98e3b1
status: done
priority: high
```
**Parameter declaration format.** Define how a playbook declares its
parameters: name, type, **default**, **constraints** (allowed values /
ranges), required vs optional, and a **security-sensitivity** marker so
NetKingdom knows which parameters it may tune versus which are
security-critical and constrained. This is what makes "parametrize where
adequate" safe rather than guesswork.
```task
id: NK-WP-0013-T4
state_hub_task_id: e7de05a6-528a-4213-b6db-2c2e90353996
status: done
priority: high
```
**Responsibility-claim & trust-state format.** Define how a declaration
states which element **owns which resources** (feeding the responsibility
map) and which **trust state(s) / readiness checks** (ADR-0007 model) it
satisfies or requires. This lets NetKingdom assemble a coherent
responsibility map and sequence for a scenario from the declarations.
```task
id: NK-WP-0013-T5
state_hub_task_id: 05a2ff7d-86c4-4de9-9ea8-39a9ad5352a8
status: done
priority: high
```
**Catalog, consumption model, and conformance validator.** Define how
declarations are published and discovered (the catalog), how
meta-orchestration consumes them to **select**, **parametrize**, and build a
**responsibility map** for a scenario, and a **conformance validator** that
checks a declaration against the contract (the orchestration-layer analog of
the IAM Profile conformance check, NK-WP-0012-T5).
```task
id: NK-WP-0013-T6
state_hub_task_id: 769ed490-c091-41c1-b2e2-e8e378470b6b
status: done
priority: medium
```
**Reference adoption with Railiance.** Coordinate with Railiance to have
**one reference playbook publish a conformant declaration end-to-end**, and
demonstrate NetKingdom selecting + parametrizing it from the declaration
alone. Proves the contract is sufficient and is the template for adopting
the rest. Cross-repo coordination item for the Railiance domain.
## Acceptance Criteria
- An ADR records contract ownership, the Railiance-publishes/NetKingdom-
consumes split, and ADR-0007 is confirmed unchanged.
- The contract specifies capability vocabulary, parameter format (defaults,
constraints, sensitivity), and responsibility/trust-state claims.
- A catalog/consumption model and a declaration conformance validator exist.
- At least one Railiance playbook publishes a conformant declaration, and
NetKingdom composes and parametrizes it from that declaration alone.
- Contract versioning and breaking-change governance is documented.
## Completion Notes
- ADR: `docs/adr/ADR-0012-playbook-capability-contract-ownership.md`
- Canonical contract:
`canon/standards/playbook-capability-contract_v0.1.md`
- Machine-readable schema:
`canon/schemas/playbook-capability-declaration_v0.1.schema.json`
- Validator and composition demo:
`tools/playbook-capability-contract/playbook_contract_validator.py`
- Reference Railiance declaration:
`../railiance-infra/capabilities/playbooks/railiance-infra.bootstrap-host.yaml`
- Sample scenario:
`examples/playbook-capability-contract/scenario-s1-host-bootstrap.yaml`
- Fixture tests cover valid declarations, controlled vocabulary failures,
forbidden tenant overrides, missing required parameters, and successful
selection/parameter composition.
## Dependencies & Sequencing
- **Realizes** the playbook-contract dependency from ADR-0007's
meta-orchestration refinement; does not change ADR-0007.
- **Depends on NK-WP-0006** for the trust-state model and the
responsibility-map resource kinds the declarations reference.
- **Coordinates with the Railiance domain** — NetKingdom defines the
contract; Railiance publishes declarations (T6) and continues to own
execution.
- Parallels NK-WP-0012: same consumer-defines-contract pattern, same
conformance-check shape, applied to orchestration instead of identity.
## Resolved Questions
- Contract format and home: NetKingdom canon standard plus a
machine-readable JSON schema and standalone validator.
- Catalog mechanism: v0.1 uses file convention
`capabilities/playbooks/*.yaml`; a registry can be layered on later.
- Parameter sensitivity: tenant scenarios cannot override
`platform_only`, `forbidden`, `playbook_default`,
`security_sensitive`, or `secret_reference` parameters.
- Validator form: standalone NetKingdom tool for v0.1, mirroring
NK-WP-0012's executable-contract pattern.

View file

@ -0,0 +1,183 @@
---
id: NK-WP-0014
type: workplan
title: "User Engine Preparation And Boundary Contracts"
domain: infotech
repo: net-kingdom
status: finished
owner: codex
topic_slug: netkingdom
planning_priority: high
planning_order: 14
created: "2026-05-22"
updated: "2026-05-22"
depends_on:
- NK-WP-0012
- NK-WP-0013
state_hub_workstream_id: "b9bf56bc-7ef6-43eb-badc-fa0f4896c63c"
---
> **Terminology note:** Historical text in this archived workplan may use the legacy term "workstream". The fleet term is **workplan** (`canon/standards/workplan-terminology-fleet_v0.1.md`).
# NK-WP-0014 - User Engine Preparation And Boundary Contracts
## Goal
Prepare implementation of `/home/worsch/user-engine` by turning the current
architecture review into concrete contracts. This workplan must be completed
before production code is started, so the MVP does not duplicate IAM,
authorization, application registration, membership, audit, or deployment
responsibilities already owned by NetKingdom-aligned components.
## Context
The user-engine PRD and architecture blueprint define a headless user-domain
service for users, accounts, profiles, preferences, memberships, application
catalogs, projections, audit, and events.
The architecture review in
`docs/reviews/2026-05-22T19-19-59+0200-user-engine-architecture-review.md`
identified the main risk: duplicate truth across IAM providers, user-engine,
flex-auth, application registrations, OIDC clients, protected systems, and
profile projections.
NetKingdom keeps this workplan because it owns cross-repo boundary and
orchestration guidance. Implementation work now lives in the `user-engine`
repository as `USER-WP-0001` through `USER-WP-0006`.
## Scope
In scope:
- source-of-truth matrix;
- membership synchronization contract;
- application onboarding contract;
- projection boundary split;
- authorization performance model;
- audit correlation contract;
- user-engine repo preparation artifacts.
- NetKingdom/user-engine interface guidance.
Out of scope:
- implementing user-engine production code, which belongs in the user-engine
repository workplans;
- implementing UI repos;
- implementing SCIM or enterprise federation adapters;
- changing the NetKingdom IAM Profile.
## Tasks
```task
id: NK-WP-0014-T1
status: done
priority: high
state_hub_task_id: "4e941174-ac55-4f6e-8568-40f45b1ed821"
```
**Source-of-truth matrix.** Define which system owns each resource kind:
identity claims, human subjects, local user records, account lifecycle,
groups, roles, memberships, tenants, applications, OIDC clients,
flex-auth protected systems, catalog namespaces, profile values,
effective-profile projections, audit records, and events.
Initial guidance lives in `docs/user-engine-interface-guidance.md` and should
be hardened into versioned contracts as implementation feedback arrives.
```task
id: NK-WP-0014-T2
status: done
priority: high
state_hub_task_id: "5ddc46bb-6238-4944-a023-d8b46b410c76"
```
**Membership synchronization contract.** Specify which memberships are mastered
in user-engine, which are imported from IAM or provisioning systems, which are
exported to flex-auth, and how freshness, conflict handling, deletes, and
tenant boundaries are represented.
```task
id: NK-WP-0014-T3
status: done
priority: high
state_hub_task_id: "696bc65b-0f8d-47b5-bccc-65ed285b42e6"
```
**Application onboarding contract.** Define the binding between a user-engine
application, IAM OIDC client, flex-auth protected system, catalog namespace,
event/audit identity, and Railiance deployment metadata. Include a checklist
for adding one new application safely.
```task
id: NK-WP-0014-T4
status: done
priority: high
state_hub_task_id: "99ab4535-cbbf-4e13-a2c5-adfc814d5aeb"
```
**Projection and claims-enrichment boundaries.** Split projection types into
runtime, self-service UI, admin UI, audit, agent context, and optional claims
enrichment. Explicitly state that user-engine does not issue tokens and that
claims enrichment is adapter-owned and cache/freshness governed.
```task
id: NK-WP-0014-T5
status: done
priority: medium
state_hub_task_id: "d35a1356-a9fe-4cf3-8fb0-6f45cfbbccee"
```
**Authorization and audit contracts.** Define the user-engine resource/action
vocabulary for flex-auth, when checks are synchronous, when they may be
batched or cached, and how user-engine audit records correlate with flex-auth
decision IDs and platform audit sinks.
```task
id: NK-WP-0014-T6
status: done
priority: medium
state_hub_task_id: "04fd2f92-3aa4-468d-9e9e-9b092890507e"
```
**Prepare the user-engine repo.** Add or update user-engine `SCOPE.md`,
architecture notes, repo layout decision, local development contract, and
initial implementation readiness checklist. Do not add NetKingdom
orchestration relationships to user-engine `INTENT.md`; those belong in
NetKingdom documents per ADR-0010.
## Acceptance Criteria
- Boundary contracts exist and are reviewed against the PRD and architecture
review.
- user-engine responsibilities are distinct from key-cape, Keycloak,
flex-auth, OpenBao, Railiance, user-account, and user-manager.
- The first implementation slice can start without unresolved ownership of
memberships, applications, projections, authorization checks, or audit
correlation.
- user-engine repo-local workplans carry implementation tasks, while
NetKingdom retains only boundary, orchestration, and responsibility-map work.
- NetKingdom responsibility-map updates are either applied or explicitly
deferred until user-engine becomes a shared platform service.
## Completion Notes
Completed on 2026-05-22:
- Added the canonical versioned contract at
`canon/standards/user-engine-boundary-contract_v0.1.md`.
- Promoted `docs/user-engine-interface-guidance.md` to an implementation guide
that points at the canonical contract.
- Confirmed `docs/responsibility-map.md` already includes `user-engine` as an
orchestrated repository and names NetKingdom's boundary responsibilities.
- Confirmed `/home/worsch/user-engine` already carries the required repo-local
preparation artifacts: `SCOPE.md`, `wiki/ArchitectureBlueprint.md`,
`docs/development.md`, `docs/configuration.md`,
`docs/interfaces/netkingdom-integration.md`, and `USER-WP-0001` through
`USER-WP-0006`.
## Dependencies And Sequencing
- Depends on NK-WP-0012 for IAM Profile consumption rules.
- Depends on NK-WP-0013 for NetKingdom meta-orchestration conventions.
- Gates implementation work in `/home/worsch/user-engine`, now tracked as
`USER-WP-0001` through `USER-WP-0006`.

View file

@ -0,0 +1,7 @@
{
"exit_code": 0,
"commit": "3236d5000e52e0643f33906a26a7825aa0b67465",
"base": "001a38ca2aa85155ce4840c4da22aca6e2346171",
"stdout": "[main 3236d50] docs: update published Warden original-context checkpoint\n 1 file changed, 23 insertions(+), 10 deletions(-)\n",
"stderr": "{\"blocked_blob_ids\": [], \"scanned_blobs\": 1, \"scanner_sha256\": \"88f91962aa2f93ac6ab281d553b9e125f5197bbbce38f9f2437f7299c32e5509\", \"scanner_version\": \"8.30.1\", \"scope\": \"changed-staged-blobs\", \"status\": \"clean\"}\n"
}

View file

@ -0,0 +1,331 @@
{
"repo_slug": "net-kingdom",
"repo_path": "/home/worsch/net-kingdom",
"source_revision": "3236d5000e52e0643f33906a26a7825aa0b67465",
"source_revision_reason": null,
"issues": [
{
"severity": "WARN",
"check_id": "C-24",
"message": "Repo classification advisory: capability_tag 'security' is not a recommended family tag (allowed, check for synonym)",
"file_path": "",
"db_id": "",
"file_value": "",
"db_value": "",
"fixable": false
},
{
"severity": "WARN",
"check_id": "C-35",
"message": "Repo Manager warning: workplans/: repository uses more than one workplan prefix: ['NET-WP', 'NK-WP']",
"file_path": "workplans/",
"db_id": "",
"file_value": "",
"db_value": "",
"fixable": false
},
{
"severity": "WARN",
"check_id": "C-37",
"message": "Residual workplan 'nk-wp-0011' has no origin/origin_ref provenance (not invented)",
"file_path": "workplans/NK-WP-0011-enterprise-federation-saml.md",
"db_id": "1075448f-d533-5f9e-94b7-c3adfe151a07",
"file_value": "",
"db_value": "",
"fixable": false
},
{
"severity": "WARN",
"check_id": "C-20",
"message": "Workplan dependency target 'USER-WP-0020' is not linked to State Hub",
"file_path": "workplans/NK-WP-0022-railiance01-identity-cutover-and-coulombcore-retirement.md",
"db_id": "",
"file_value": "USER-WP-0020",
"db_value": "",
"fixable": false
},
{
"severity": "WARN",
"check_id": "C-20",
"message": "Workplan dependency target 'KEY-WP-0004' is not linked to State Hub",
"file_path": "workplans/NK-WP-0022-railiance01-identity-cutover-and-coulombcore-retirement.md",
"db_id": "",
"file_value": "KEY-WP-0004",
"db_value": "",
"fixable": false
},
{
"severity": "WARN",
"check_id": "C-20",
"message": "Workplan dependency target 'USER-WP-0020' is not linked to State Hub",
"file_path": "workplans/NK-WP-0023-user-engine-portal-platform-integration.md",
"db_id": "",
"file_value": "USER-WP-0020",
"db_value": "",
"fixable": false
},
{
"severity": "WARN",
"check_id": "C-20",
"message": "Workplan dependency target 'KEY-WP-0004' is not linked to State Hub",
"file_path": "workplans/NK-WP-0023-user-engine-portal-platform-integration.md",
"db_id": "",
"file_value": "KEY-WP-0004",
"db_value": "",
"fixable": false
},
{
"severity": "WARN",
"check_id": "C-20",
"message": "Workplan dependency target 'USER-WP-0021' is not linked to State Hub",
"file_path": "workplans/NK-WP-0024-user-engine-portal-integration-expansion.md",
"db_id": "",
"file_value": "USER-WP-0021",
"db_value": "",
"fixable": false
},
{
"severity": "WARN",
"check_id": "C-20",
"message": "Workplan dependency target 'FLEX-WP-0009' is not linked to State Hub",
"file_path": "workplans/NK-WP-0024-user-engine-portal-integration-expansion.md",
"db_id": "",
"file_value": "FLEX-WP-0009",
"db_value": "",
"fixable": false
},
{
"severity": "WARN",
"check_id": "C-20",
"message": "Workplan dependency target 'AUDIT-WP-0003' is not linked to State Hub",
"file_path": "workplans/NK-WP-0024-user-engine-portal-integration-expansion.md",
"db_id": "",
"file_value": "AUDIT-WP-0003",
"db_value": "",
"fixable": false
},
{
"severity": "WARN",
"check_id": "C-20",
"message": "Workplan dependency target 'EMAIL-WP-0004' is not linked to State Hub",
"file_path": "workplans/NK-WP-0024-user-engine-portal-integration-expansion.md",
"db_id": "",
"file_value": "EMAIL-WP-0004",
"db_value": "",
"fixable": false
},
{
"severity": "WARN",
"check_id": "C-20",
"message": "Workplan dependency target 'USER-WP-0022' is not linked to State Hub",
"file_path": "workplans/NK-WP-0025-public-self-registration-and-application-jit.md",
"db_id": "",
"file_value": "USER-WP-0022",
"db_value": "",
"fixable": false
},
{
"severity": "WARN",
"check_id": "C-20",
"message": "Workplan dependency target 'KEY-WP-0008' is not linked to State Hub",
"file_path": "workplans/NK-WP-0025-public-self-registration-and-application-jit.md",
"db_id": "",
"file_value": "KEY-WP-0008",
"db_value": "",
"fixable": false
},
{
"severity": "WARN",
"check_id": "C-20",
"message": "Workplan dependency target 'CSOC-WP-0003' is not linked to State Hub",
"file_path": "workplans/NK-WP-0025-public-self-registration-and-application-jit.md",
"db_id": "",
"file_value": "CSOC-WP-0003",
"db_value": "",
"fixable": false
},
{
"severity": "WARN",
"check_id": "C-37",
"message": "Residual workplan 'nk-wp-0027' has no origin/origin_ref provenance (not invented)",
"file_path": "workplans/NK-WP-0027-reef-placement-reconciliation.md",
"db_id": "965ad365-6b81-50a1-a2a3-2d0c1fcce0b4",
"file_value": "",
"db_value": "",
"fixable": false
},
{
"severity": "WARN",
"check_id": "C-37",
"message": "Residual workplan 'nk-wp-0031' has no origin/origin_ref provenance (not invented)",
"file_path": "workplans/NK-WP-0031-deterministic-posture-feedback.md",
"db_id": "9d7b04f9-3803-5613-b7a5-8bd606c77f5a",
"file_value": "",
"db_value": "",
"fixable": false
},
{
"severity": "WARN",
"check_id": "C-37",
"message": "Residual workplan 'nk-wp-0040' has no origin/origin_ref provenance (not invented)",
"file_path": "workplans/NK-WP-0040-execution-attribution-receipt.md",
"db_id": "e2533f3a-aa43-59b3-bff3-8e64b6149487",
"file_value": "",
"db_value": "",
"fixable": false
},
{
"severity": "WARN",
"check_id": "C-40",
"message": "blocker satisfied, task still wait: 'NK-WP-0048-T15' in workplan 'NK-WP-0048' \u2014 every depends_on target is terminal (NK-WP-0048-T31)",
"file_path": "workplans/NK-WP-0048-security-case-types.md#NK-WP-0048-T15",
"db_id": "",
"file_value": "NK-WP-0048-T31",
"db_value": "",
"fixable": false
},
{
"severity": "WARN",
"check_id": "C-22",
"message": "Task description drift 'NK-WP-0048-T15': file content differs from DB (file wins)",
"file_path": "workplans/NK-WP-0048-security-case-types.md#NK-WP-0048-T15",
"db_id": "1b825705-4848-5edc-832f-b1622cd9bdb7",
"file_value": "2026-10-17 source part merged (061461e via 65559ef). `build()` takes optional\npaired `holder`/`observe` capabilities and",
"db_value": "2026-10-17 source part merged (061461e via 65559ef). `build()` takes optional\npaired `holder`/`observe` capabilities and",
"fixable": true
},
{
"severity": "WARN",
"check_id": "C-20",
"message": "Workplan dependency target 'RAIL-PL-WP-0002' is not linked to State Hub",
"file_path": "workplans/archived/260702-NET-WP-0017-it-security-readiness-for-user-onboarding.md",
"db_id": "",
"file_value": "RAIL-PL-WP-0002",
"db_value": "",
"fixable": false
},
{
"severity": "INFO",
"check_id": "C-08",
"message": "Retired DB workstream 'nk-wp-0035@retired-20260908' (id=064c5e8b\u2026, status=archived) has no backing workplan file \u2014 projection tombstone, not live work",
"file_path": "",
"db_id": "064c5e8b-7852-4d7f-a5fa-e26e406ab8e0",
"file_value": "",
"db_value": "",
"fixable": false
},
{
"severity": "INFO",
"check_id": "C-08",
"message": "Retired DB workstream 'adhoc-2026-08-14@retired-20260827' (id=a5097121\u2026, status=finished) has no backing workplan file \u2014 projection tombstone, not live work",
"file_path": "",
"db_id": "a5097121-1461-59f8-81fa-e6ecef527337",
"file_value": "",
"db_value": "",
"fixable": false
},
{
"severity": "INFO",
"check_id": "C-08",
"message": "Retired DB workstream 'adhoc-2026-08-23@retired-20260827' (id=e25ba5fa\u2026, status=finished) has no backing workplan file \u2014 projection tombstone, not live work",
"file_path": "",
"db_id": "e25ba5fa-eaae-5039-8d93-a69c6d837fc4",
"file_value": "",
"db_value": "",
"fixable": false
},
{
"severity": "INFO",
"check_id": "C-08",
"message": "Retired DB workstream 'net-kingdom-adhoc-2026-06-14@retired-20260827' (id=c6f3d6bf\u2026, status=finished) has no backing workplan file \u2014 projection tombstone, not live work",
"file_path": "",
"db_id": "c6f3d6bf-4916-490d-96ce-092d2776d7e7",
"file_value": "",
"db_value": "",
"fixable": false
},
{
"severity": "INFO",
"check_id": "C-08",
"message": "Retired DB workstream 'net-kingdom-adhoc-2026-07-02@retired-20260827' (id=67c1c7ac\u2026, status=finished) has no backing workplan file \u2014 projection tombstone, not live work",
"file_path": "",
"db_id": "67c1c7ac-d8b1-41dc-a81a-4e43f1afd068",
"file_value": "",
"db_value": "",
"fixable": false
},
{
"severity": "WARN",
"check_id": "C-26",
"message": "Workplan id 'NET-WP-0020' uses prefix 'NET-WP' but repo canonical prefix is 'NK-WP' \u2014 new plans must conform",
"file_path": "workplans/NET-WP-0020-openbao-unseal-custody-and-ssh-automation.md",
"db_id": "",
"file_value": "NET-WP-0020",
"db_value": "NK-WP",
"fixable": false
},
{
"severity": "WARN",
"check_id": "C-26",
"message": "Workplan id 'NET-WP-0015' uses prefix 'NET-WP' but repo canonical prefix is 'NK-WP' \u2014 new plans must conform",
"file_path": "workplans/archived/260603-NET-WP-0015-platform-root-custody-and-openbao-identity-bootstrap.md",
"db_id": "",
"file_value": "NET-WP-0015",
"db_value": "NK-WP",
"fixable": false
},
{
"severity": "WARN",
"check_id": "C-26",
"message": "Workplan id 'NET-WP-0016' uses prefix 'NET-WP' but repo canonical prefix is 'NK-WP' \u2014 new plans must conform",
"file_path": "workplans/archived/260603-NET-WP-0016-guided-security-bootstrap-experience.md",
"db_id": "",
"file_value": "NET-WP-0016",
"db_value": "NK-WP",
"fixable": false
},
{
"severity": "WARN",
"check_id": "C-26",
"message": "Workplan id 'NET-WP-0018' uses prefix 'NET-WP' but repo canonical prefix is 'NK-WP' \u2014 new plans must conform",
"file_path": "workplans/archived/260604-NET-WP-0018-bootstrap-automation-and-rebuild-readiness.md",
"db_id": "",
"file_value": "NET-WP-0018",
"db_value": "NK-WP",
"fixable": false
},
{
"severity": "WARN",
"check_id": "C-26",
"message": "Workplan id 'NET-WP-0017' uses prefix 'NET-WP' but repo canonical prefix is 'NK-WP' \u2014 new plans must conform",
"file_path": "workplans/archived/260702-NET-WP-0017-it-security-readiness-for-user-onboarding.md",
"db_id": "",
"file_value": "NET-WP-0017",
"db_value": "NK-WP",
"fixable": false
},
{
"severity": "WARN",
"check_id": "C-26",
"message": "Workplan id 'NET-WP-0019' uses prefix 'NET-WP' but repo canonical prefix is 'NK-WP' \u2014 new plans must conform",
"file_path": "workplans/archived/260702-NET-WP-0019-t06-adjacent-user-lifecycle-dry-run-polish.md",
"db_id": "",
"file_value": "NET-WP-0019",
"db_value": "NK-WP",
"fixable": false
}
],
"fixes_applied": [
"bindings: synced 64/64",
"C-17 cleared: pushed 1 backlogged commit(s)",
"C-22 fixed: task 1b825705\u2026 description updated",
"push: pushed"
],
"summary": {
"fail": 0,
"automation_error": 0,
"warn": 26,
"info": 5
},
"result": "warn"
}

View file

@ -0,0 +1,27 @@
from pathlib import Path
import json,hashlib,subprocess,re,urllib.request
p=Path(__file__).resolve().parent;r=Path('/home/worsch/net-kingdom')
commit=json.loads((p/'commit-receipt.json').read_text())['commit']
def git(*a):return subprocess.check_output(['git','-C',str(r),*a]).decode().strip()
assert git('rev-parse','HEAD')==commit
assert git('ls-remote','origin','refs/heads/main').split()[0]==commit
projection=json.loads((p/'projection.json').read_text());receipt=projection['receipt']
assert projection['ok'] and projection['status'] in ('applied','noop')
assert receipt['expected_commit']==receipt['derived_commit']==commit
assert (receipt['instance_role'],receipt['instance_label'])==('primary','railiance01')
assert receipt['outcome']['counts']['retired']==0
before=json.loads((p/'tasks-before.json').read_text())
req=urllib.request.Request('http://127.0.0.1:8000/tasks/?workplan_id=e31f3f9d-0748-5137-b0a3-7b3ca46a66eb',headers={'X-StateHub-Component':'net-kingdom'})
after=json.load(urllib.request.urlopen(req,timeout=30));(p/'tasks-after.json').write_text(json.dumps(after,indent=2)+'\n')
def identity(rows):return sorted((x['id'],x['status']) for x in rows)
assert identity(before)==identity(after)
name='workplans/NK-WP-0048-security-case-types.md';original=(p/'backup'/name).read_text();current=(r/name).read_text()
blocks=lambda text:re.findall(r'```task\n.*?```',text,re.S)
assert blocks(original)==blocks(current)
assert (r/name).read_bytes()==(p/'candidate.md').read_bytes()
t15=[b for b in blocks(current) if 'id: NK-WP-0048-T15\n' in b][0]
summary={'status':'published-and-projected','commit':commit,'only_committed_path':git('diff-tree','--no-commit-id','--name-only','-r',commit),'projection_status':projection['status'],'instance_role':receipt['instance_role'],'instance_label':receipt['instance_label'],'expected_commit':receipt['expected_commit'],'derived_commit':receipt['derived_commit'],'original_task_count':len(before),'current_task_count':len(after),'all_task_ids_and_statuses_unchanged':True,'all_source_task_blocks_unchanged':True,'T15_task_block':t15,'preservation':json.loads((p/'preservation-verification.json').read_text()),'native_or_credential_or_adapter_changes':False,'root_git_brief_work_modified':False}
(p/'verification.json').write_text(json.dumps(summary,indent=2)+'\n')
manifest={'files':[{'path':str(f.relative_to(p)),'sha256':hashlib.sha256(f.read_bytes()).hexdigest()} for f in sorted(p.rglob('*')) if f.is_file() and f.name!='manifest.json']}
(p/'manifest.json').write_text(json.dumps(manifest,indent=2)+'\n')
print(json.dumps({'status':summary['status'],'commit':commit,'task_count':len(after),'projection':projection['status'],'manifest_sha256':hashlib.sha256((p/'manifest.json').read_bytes()).hexdigest()}))

View file

@ -0,0 +1,11 @@
{
"schema": "repo-manager.identifier-assignment.v1",
"ok": true,
"executed": false,
"repo": "net-kingdom",
"namespace": "helixforge",
"assignments": [],
"historical_invalid_identifiers": [],
"historical_identity_collisions": [],
"files_changed": []
}

View file

@ -0,0 +1,332 @@
{
"files": [
{
"path": "apply_commit.py",
"sha256": "ae5b4b42c44ca69e6b97ac0667401064eb81c22eae9ab2db3d579792e587b9a3"
},
{
"path": "approved.patch",
"sha256": "4402448cac9b50b745f247aec1c550a5fc3532e702ad4ceeae0812691278118c"
},
{
"path": "backup/.custodian-brief.md",
"sha256": "3eb7f91f2443090c9b859a716d83711310364897b6144dcf10d3254342fec3d1"
},
{
"path": "backup/WORK-RECORDS.md",
"sha256": "a1fec217a6e380f528778d781dbea1fc5a836fdefa1dd4dd0308100fbe08112a"
},
{
"path": "backup/workplans/ADHOC-2026-07-02.md",
"sha256": "f775fb97ce7c4d49f03f68dec86df8b2f1d0c265a6432d2b995d14852394db3d"
},
{
"path": "backup/workplans/ADHOC-2026-08-14.md",
"sha256": "24e73b2559fecb4da7818fd2dd75af413dfc30d761887029d8dda364cd0205ab"
},
{
"path": "backup/workplans/ADHOC-2026-08-23.md",
"sha256": "f3aabf4e36a27a4692b97d6cb7286f944681917cd3c31420dbb90d9b8a55f646"
},
{
"path": "backup/workplans/ADHOC-2026-10-03.md",
"sha256": "0591aa5c901f6adb73aa9ecbfa89f8e1cf81919ab2f0f2d5bdb6ff4934eef81c"
},
{
"path": "backup/workplans/ADHOC-2026-10-10.md",
"sha256": "01c42780f0299ec96febd083393d45a23da7d17674f8049374db1e4ef7dfb322"
},
{
"path": "backup/workplans/ADHOC-2026-10-11.md",
"sha256": "cdfce94de7390b7abd2a8d2cc10d3e770b718521dd34c69fda81fa0a1f1e83fd"
},
{
"path": "backup/workplans/ADHOC-2026-10-16.md",
"sha256": "4288f317ee4e66b332b5e3907d90878becb829d4492ccd5d86842a914667a9b8"
},
{
"path": "backup/workplans/NET-WP-0020-openbao-unseal-custody-and-ssh-automation.md",
"sha256": "fe8a6c450f734810c78b97eeca70dddcb7555cd16d9e3403b9b4bc8eca371ff8"
},
{
"path": "backup/workplans/NK-WP-0009-netkingdom-security-pattern-tutorials.md",
"sha256": "1d0f5f9674b20c3fbaa76e98010f63a2d83d081b0a1c1410ac6a38d49b3fc631"
},
{
"path": "backup/workplans/NK-WP-0011-enterprise-federation-saml.md",
"sha256": "e5692b737a1b2f0ca8c1ed9129d06929be74726e69baccea5520738b7e31a657"
},
{
"path": "backup/workplans/NK-WP-0021-activity-core-ops-sso-operators.md",
"sha256": "24fe6fd6a2bd0bf549c24523f4562e5fc8e1a3d317c6858f701f914b33b6059a"
},
{
"path": "backup/workplans/NK-WP-0022-railiance01-identity-cutover-and-coulombcore-retirement.md",
"sha256": "a44265859ecab3c65d95f9ea520950e48c223b64f3a5449ab2d4663a8efce336"
},
{
"path": "backup/workplans/NK-WP-0023-user-engine-portal-platform-integration.md",
"sha256": "9d1f43313f2b1d0d55ad3d69966397cd310e6c90d76f90c216fb75b5f7b1e053"
},
{
"path": "backup/workplans/NK-WP-0024-user-engine-portal-integration-expansion.md",
"sha256": "7899232d817fde7a0ac1be4d9511c1ba65f44428a08872befe30af0b06a3aac0"
},
{
"path": "backup/workplans/NK-WP-0025-public-self-registration-and-application-jit.md",
"sha256": "d3570990e1c4d4ee528c72f2db9116b57f9e6bfc76bac4fa881c362b10b90c63"
},
{
"path": "backup/workplans/NK-WP-0026-flex-auth-caller-identity-rollout.md",
"sha256": "52f0727defd43791c812e045e75eb5ebfb181183290a25f7841bccd1e250e0f4"
},
{
"path": "backup/workplans/NK-WP-0027-reef-placement-reconciliation.md",
"sha256": "3360b2bfeedd04ea5c3854dff0c01960f9c1d2e8433a71f393fc9c8c9253aca2"
},
{
"path": "backup/workplans/NK-WP-0028-canon-publication-and-grouping-semantics.md",
"sha256": "48548faf581e1bacb6952db0050f67b30e634830eb55d20289be85580afb6017"
},
{
"path": "backup/workplans/NK-WP-0029-scope-and-intent-reconciliation.md",
"sha256": "f2111f2a8c6661022755824091aa20413e10975ef940d5492ff6e9564d45c372"
},
{
"path": "backup/workplans/NK-WP-0030-deterministic-security-scenario-composition.md",
"sha256": "f82e1f33ae1ddf2305ce2efc567d2c55809669a47b91c0cabd3d0b41bd78ab3b"
},
{
"path": "backup/workplans/NK-WP-0031-deterministic-posture-feedback.md",
"sha256": "f2b465a883ab8e28ab84f0e94d95e23a15ad6d9b6e038068d96b36dcaa313b5e"
},
{
"path": "backup/workplans/NK-WP-0032-openbao-operator-loopback-callback.md",
"sha256": "a1955896b0ac0805c19bd97264e0e755f2d46a99687acdd2fcd6dd36947aa1bb"
},
{
"path": "backup/workplans/NK-WP-0033-keycape-secret-exposure-rotation.md",
"sha256": "8268aa86f7fa9f2a3848adfe2dc3022bcf2e9dc9197328993445f4138a40e513"
},
{
"path": "backup/workplans/NK-WP-0034-verification-that-verifies.md",
"sha256": "d31227ca44d697d9a3e7bef5931836ab0cc6d2c9641900ab1fa8f63307cb7c83"
},
{
"path": "backup/workplans/NK-WP-0035-emission-cadence-security-profile.md",
"sha256": "273a9154a37a7b9efd4fb199e7375d2a3d5cb6919eaa3a2fb8532745a90f83e9"
},
{
"path": "backup/workplans/NK-WP-0036-restore-user-portal-client-registration.md",
"sha256": "84019513b7099c39b6dc2daa286017fb48f1286b966fe7c7a142df7c914b575e"
},
{
"path": "backup/workplans/NK-WP-0037-vergabe-company-welcome.md",
"sha256": "f4fb6d7972f59afa550d6021a9297303e9329867027229512ec9f85b61dda286"
},
{
"path": "backup/workplans/NK-WP-0038-tenant-scoped-identity-lifecycle.md",
"sha256": "32811a635811c870795aba5d4d2fa6f3b0baecc0b3d270a7cfeb77dbba75206b"
},
{
"path": "backup/workplans/NK-WP-0039-flex-auth-access-engine-coordinate-intake.md",
"sha256": "31a0811bf36984f1ef3bdf3c7b7e68d46413909bfb4bc0d781bd7bf49d9bbabf"
},
{
"path": "backup/workplans/NK-WP-0040-execution-attribution-receipt.md",
"sha256": "8b0b653da2fc6ea62a2b804bdb8feb92046876f4e5e0afa96c7c53bc31945d2e"
},
{
"path": "backup/workplans/NK-WP-0041-onboarding-journey-usability.md",
"sha256": "b05d9e14028e83cebbe16b1efcee3477f49a99ae5d6dfc408c41c6cd0b3c3a83"
},
{
"path": "backup/workplans/NK-WP-0042-workload-mfa-step-up.md",
"sha256": "12c95fd8a2cbed6c521c1fbf5464d7cf6b7552d63c11992bc93ec88f2013c618"
},
{
"path": "backup/workplans/NK-WP-0043-cadence-assessment-and-operating-guidance.md",
"sha256": "bf75f9fdaf7745596b79843c33d6325236a0c7de27547169464c367f71100de1"
},
{
"path": "backup/workplans/NK-WP-0044-runbook-packs-for-runbook-tutorials.md",
"sha256": "071fe448f456b7622e4d6499dab6005af1e41e9c7cc516bc8389b2847e1c01d5"
},
{
"path": "backup/workplans/NK-WP-0045-root-grant-custody-record.md",
"sha256": "72957387424f36b376a3b66ea10381d40665497dbcdc7b029ba54fed87c522d1"
},
{
"path": "backup/workplans/NK-WP-0046-secrets-engine-openbao-client-registration.md",
"sha256": "ef38481d26e599802d94f8b06a4d89c7c99a83c81ca5be9bcf7422b885867479"
},
{
"path": "backup/workplans/NK-WP-0047-platform-password-reset-mail.md",
"sha256": "78b159076121c4e53fef8eadd6287b8c9e91a725203be88816840c9f9c1c8516"
},
{
"path": "backup/workplans/NK-WP-0048-security-case-types.md",
"sha256": "b682cd607d9ed9b232656cc7934ec09ac4e986c1c81131a44f80240342a0571c"
},
{
"path": "backup/workplans/NK-WP-0049-bootstrap-secret-free-recovery-handoff.md",
"sha256": "cba3233883e9a5b429aaea1b8eacd250c6efcf5e484c4284ddc97e8e52697085"
},
{
"path": "backup/workplans/NK-WP-0050-playwright-consumer-registration.md",
"sha256": "0be0b643409d0731d4924c95566facdef58b1c65c5c1276f7f308ebfb2271fb7"
},
{
"path": "backup/workplans/NK-WP-0051-sign-in-diagnosis.md",
"sha256": "736a06e798d9d15715490f8c3ed2f81a8d065e8446e046e36a2bd19353a083b9"
},
{
"path": "backup/workplans/archived/260522-NK-WP-0015-user-engine-isolated-mvp.md",
"sha256": "98e7ae719ae0282e80d541222d12805bebf2ef1abf9dca576f1e32c83d5d31bf"
},
{
"path": "backup/workplans/archived/260522-NK-WP-0016-user-engine-multi-tenancy.md",
"sha256": "be9490920a6c8bc1652c334c6b2b1480257b18fffe55406426b04ab240ba7430"
},
{
"path": "backup/workplans/archived/260522-NK-WP-0017-user-engine-multi-application-catalogs.md",
"sha256": "ab5c151034d6ceaf8bf6d4154944fa7406e2edb6127e6adc963429920c425270"
},
{
"path": "backup/workplans/archived/260522-NK-WP-0018-user-engine-integrated-test-scenarios.md",
"sha256": "2b83295aeaae5a58ad6cef6b0198e9abf8f57a8a9b0216bb166afb71d4d26e28"
},
{
"path": "backup/workplans/archived/260522-NK-WP-0019-user-engine-finalization-polish.md",
"sha256": "7db746783b2ad60110451b9b44a04471b188bb8a6b49d76c984a1cd4c72b1ae3"
},
{
"path": "backup/workplans/archived/260603-NET-WP-0015-platform-root-custody-and-openbao-identity-bootstrap.md",
"sha256": "014252768653440c1911512972022122b4f43c3c040c7da34d0f86bba71e1204"
},
{
"path": "backup/workplans/archived/260603-NET-WP-0016-guided-security-bootstrap-experience.md",
"sha256": "936b446483326b3dc7c1be94397f833a1e124311c98654d1877478a09b8b23e8"
},
{
"path": "backup/workplans/archived/260603-NK-WP-0003-keycape-privacyidea-cluster-deployment.md",
"sha256": "754955fe18c25c35a1c0036b25f889d281dd8442b86e1793583c97f83f8125c2"
},
{
"path": "backup/workplans/archived/260603-NK-WP-0004-credential-management-foundation.md",
"sha256": "62a69453f9dc5db8a208e01df83e198249074d921fa83cba9d919385208709fc"
},
{
"path": "backup/workplans/archived/260603-NK-WP-0005-agent-driven-credential-bootstrap.md",
"sha256": "f7cebada5f6344d0baa7625f66938cafd1f156bd20fe9b00f09c994f290fb4e0"
},
{
"path": "backup/workplans/archived/260604-NET-WP-0018-bootstrap-automation-and-rebuild-readiness.md",
"sha256": "784b034ba22125ea2098da40c3ece39f9e910c473d4a3f0f8f3c23250aae7e23"
},
{
"path": "backup/workplans/archived/260702-ADHOC-2026-06-14.md",
"sha256": "455b4cb77ec944551696203c79d3a229cbf9e5f2381931632ea1ce23c587e2fd"
},
{
"path": "backup/workplans/archived/260702-NET-WP-0017-it-security-readiness-for-user-onboarding.md",
"sha256": "74eafd43790bde4d31728518e1b875ecc8262e6af18e1cd5f81e0882178182be"
},
{
"path": "backup/workplans/archived/260702-NET-WP-0019-t06-adjacent-user-lifecycle-dry-run-polish.md",
"sha256": "61cd3135222696a7b6afd74b2f3a3fd717f5e7985f8ade2ccc66e119a43a9d14"
},
{
"path": "backup/workplans/archived/260702-NK-WP-0001-sso-mfa-platform.md",
"sha256": "c904ad4503b45ea64bc9d360c1cc8394398771cabf1a389dea41496714cde6e6"
},
{
"path": "backup/workplans/archived/260702-NK-WP-0002-local-identity.md",
"sha256": "fc2b924da22125a8d0374e795b962612dfd8e01f583b6a0eefbb827e338127d7"
},
{
"path": "backup/workplans/archived/260702-NK-WP-0006-recursive-platform-identity-security-architecture.md",
"sha256": "7a70d174baa28f399c63823c264cb1dfba9af69b61934ffc105cba56e4f34b47"
},
{
"path": "backup/workplans/archived/260702-NK-WP-0007-object-storage-sts-credential-vending.md",
"sha256": "d921c3d9c015027b99b30e7723acf6c71151a29927fcdbfaa124f776dcfbd64f"
},
{
"path": "backup/workplans/archived/260702-NK-WP-0008-it-security-architecture-patterns-infospace.md",
"sha256": "abacfb3651e56b233587492dda5fa6cbbd08e0c1fc49681a22373e156a630b36"
},
{
"path": "backup/workplans/archived/260702-NK-WP-0010-genesis-security-pattern-completion.md",
"sha256": "6a0b13e0f82af03e7461f4f433d7876e5f8d9a76acc8888709f4e130e13fb2e4"
},
{
"path": "backup/workplans/archived/260702-NK-WP-0012-iam-profile-specification.md",
"sha256": "1ca0aed6549d7cb2aeb490a4110fddfd0f5575832cb7e2f696724b3b4b4e79ba"
},
{
"path": "backup/workplans/archived/260702-NK-WP-0013-playbook-capability-contract.md",
"sha256": "5e69691251391706d3419349bc38cb13c6d910d623b03ba788d31dbcd5a7e3bf"
},
{
"path": "backup/workplans/archived/260702-NK-WP-0014-user-engine-preparation-boundary-contracts.md",
"sha256": "d4a6e9f60ccfe666645ebf37af0d49b50e692218de46539c50b8b22ec255030a"
},
{
"path": "candidate.md",
"sha256": "1502f1f474856172d969489cab8c0642d9456d93d326f6660df3772a4716d30b"
},
{
"path": "commit-receipt.json",
"sha256": "1ec30c07304b95ea7474c8e05d0d4770932e726d56d7a7a93356ac559058c797"
},
{
"path": "consistency.json",
"sha256": "bf4c3946f5080d8dc878599ab73053eeb8d1ce7f25717067a8cb837be61c5aa6"
},
{
"path": "consistency.stderr.txt",
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
{
"path": "final_verify.py",
"sha256": "00273ab7067452aafa200e6b5dcbb431a4041a8a6bfc1d4e3a6a69902e97bc10"
},
{
"path": "identifier-preview.json",
"sha256": "c7df3d4f74214943d11408c147f1d4331549ac7d9764667cf75bc58b4186b3b9"
},
{
"path": "preimage.json",
"sha256": "d223380325bc523c2226a0d4cf91be3c35b94a6db7ad42753c8ad359ecbdeb61"
},
{
"path": "preservation-verification.json",
"sha256": "0accde4df20981a3b8732aa5143beb7a9defb333d11c3481543950e676a4674d"
},
{
"path": "projection.json",
"sha256": "00a8832cd630b7fb42214883710cfcda6f653b1b22c417f952393d2a43876d39"
},
{
"path": "projection.stderr.txt",
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
{
"path": "restore_verify.py",
"sha256": "230bed15ab4388aaf7dd3452248fbdab30a14f0ecbbf79965fb609e050816e40"
},
{
"path": "tasks-after.json",
"sha256": "26bda42190983a07cb853c69b14635c69f4a4ec21f3bae7b4d1e72fbd3961e79"
},
{
"path": "tasks-before.json",
"sha256": "0c79d45200ff95d67558de103ea0a75b8450fcff4cea1e871a70e66c2edfe288"
},
{
"path": "verification.json",
"sha256": "6695016b43830abc79fb4da56697e51a59624ef7d0d345fa73afa2cd77fbd8d9"
}
]
}

View file

@ -0,0 +1,367 @@
{
"head": "001a38ca2aa85155ce4840c4da22aca6e2346171",
"remote": "001a38ca2aa85155ce4840c4da22aca6e2346171",
"status": "M .custodian-brief.md\n M WORK-RECORDS.md\n?? docs/evidence/2026-10-15-cadence-adoption/hourly-observation-capture/\n?? docs/evidence/2026-10-15-cadence-adoption/hourly-observation-inventory.jsonl\n?? docs/evidence/2026-10-15-cadence-adoption/hourly-observation-monitor.json\n?? intakes/NET-IN-0005-single-use-setup-link-mail-handoff.md",
"files": [
{
"path": ".custodian-brief.md",
"sha256": "3eb7f91f2443090c9b859a716d83711310364897b6144dcf10d3254342fec3d1",
"index": "100644 f60f8bad019e23e6f7e0e074745da0bb2fcbb870 0\t.custodian-brief.md"
},
{
"path": "WORK-RECORDS.md",
"sha256": "a1fec217a6e380f528778d781dbea1fc5a836fdefa1dd4dd0308100fbe08112a",
"index": "100644 76a6b7fc304c508f1b50010cb72d892826c6a831 0\tWORK-RECORDS.md"
},
{
"path": "workplans/ADHOC-2026-07-02.md",
"sha256": "f775fb97ce7c4d49f03f68dec86df8b2f1d0c265a6432d2b995d14852394db3d",
"index": "100644 66e748e1224a1c212a071a4e3c72d0d3404ed9a9 0\tworkplans/ADHOC-2026-07-02.md"
},
{
"path": "workplans/ADHOC-2026-08-14.md",
"sha256": "24e73b2559fecb4da7818fd2dd75af413dfc30d761887029d8dda364cd0205ab",
"index": "100644 91a3ea1a4256cf7d09d857500be99810c71009a5 0\tworkplans/ADHOC-2026-08-14.md"
},
{
"path": "workplans/ADHOC-2026-08-23.md",
"sha256": "f3aabf4e36a27a4692b97d6cb7286f944681917cd3c31420dbb90d9b8a55f646",
"index": "100644 21f20d066843b000c457851bd44e6ec217999228 0\tworkplans/ADHOC-2026-08-23.md"
},
{
"path": "workplans/ADHOC-2026-10-03.md",
"sha256": "0591aa5c901f6adb73aa9ecbfa89f8e1cf81919ab2f0f2d5bdb6ff4934eef81c",
"index": "100644 360faf210cc73613bf27b4f7f6655aa9cf8c511a 0\tworkplans/ADHOC-2026-10-03.md"
},
{
"path": "workplans/ADHOC-2026-10-10.md",
"sha256": "01c42780f0299ec96febd083393d45a23da7d17674f8049374db1e4ef7dfb322",
"index": "100644 7d350c2746dce164e8fe0c43677c346a68db5cf6 0\tworkplans/ADHOC-2026-10-10.md"
},
{
"path": "workplans/ADHOC-2026-10-11.md",
"sha256": "cdfce94de7390b7abd2a8d2cc10d3e770b718521dd34c69fda81fa0a1f1e83fd",
"index": "100644 94059eb7d549fda7a2a6550ecea896078e3a5f93 0\tworkplans/ADHOC-2026-10-11.md"
},
{
"path": "workplans/ADHOC-2026-10-16.md",
"sha256": "4288f317ee4e66b332b5e3907d90878becb829d4492ccd5d86842a914667a9b8",
"index": "100644 a38773aed4d12e9b214988d8fac1d7061eadc6fb 0\tworkplans/ADHOC-2026-10-16.md"
},
{
"path": "workplans/NET-WP-0020-openbao-unseal-custody-and-ssh-automation.md",
"sha256": "fe8a6c450f734810c78b97eeca70dddcb7555cd16d9e3403b9b4bc8eca371ff8",
"index": "100644 ffe7a7eeee1069f4bdf9511e2dd44e6eff5726f8 0\tworkplans/NET-WP-0020-openbao-unseal-custody-and-ssh-automation.md"
},
{
"path": "workplans/NK-WP-0009-netkingdom-security-pattern-tutorials.md",
"sha256": "1d0f5f9674b20c3fbaa76e98010f63a2d83d081b0a1c1410ac6a38d49b3fc631",
"index": "100644 6e55c842670a5f1153c2556495abbf9c78db866e 0\tworkplans/NK-WP-0009-netkingdom-security-pattern-tutorials.md"
},
{
"path": "workplans/NK-WP-0011-enterprise-federation-saml.md",
"sha256": "e5692b737a1b2f0ca8c1ed9129d06929be74726e69baccea5520738b7e31a657",
"index": "100644 f6dc921d804a45dbb4c225527f7ce5ddb5f53dc6 0\tworkplans/NK-WP-0011-enterprise-federation-saml.md"
},
{
"path": "workplans/NK-WP-0021-activity-core-ops-sso-operators.md",
"sha256": "24fe6fd6a2bd0bf549c24523f4562e5fc8e1a3d317c6858f701f914b33b6059a",
"index": "100644 31de057e004086584e85d14595269460896cd5ea 0\tworkplans/NK-WP-0021-activity-core-ops-sso-operators.md"
},
{
"path": "workplans/NK-WP-0022-railiance01-identity-cutover-and-coulombcore-retirement.md",
"sha256": "a44265859ecab3c65d95f9ea520950e48c223b64f3a5449ab2d4663a8efce336",
"index": "100644 d0616047e35b52257647ce72914584e32222a5c7 0\tworkplans/NK-WP-0022-railiance01-identity-cutover-and-coulombcore-retirement.md"
},
{
"path": "workplans/NK-WP-0023-user-engine-portal-platform-integration.md",
"sha256": "9d1f43313f2b1d0d55ad3d69966397cd310e6c90d76f90c216fb75b5f7b1e053",
"index": "100644 c08863a1b0cc9cd9ebf15ac09c07b29e7fbe46e1 0\tworkplans/NK-WP-0023-user-engine-portal-platform-integration.md"
},
{
"path": "workplans/NK-WP-0024-user-engine-portal-integration-expansion.md",
"sha256": "7899232d817fde7a0ac1be4d9511c1ba65f44428a08872befe30af0b06a3aac0",
"index": "100644 0b336e80dc4ad264f6aae2340f380fc041f54df0 0\tworkplans/NK-WP-0024-user-engine-portal-integration-expansion.md"
},
{
"path": "workplans/NK-WP-0025-public-self-registration-and-application-jit.md",
"sha256": "d3570990e1c4d4ee528c72f2db9116b57f9e6bfc76bac4fa881c362b10b90c63",
"index": "100644 9cd2e946519328b96910be0dbf87c35f7128a0ed 0\tworkplans/NK-WP-0025-public-self-registration-and-application-jit.md"
},
{
"path": "workplans/NK-WP-0026-flex-auth-caller-identity-rollout.md",
"sha256": "52f0727defd43791c812e045e75eb5ebfb181183290a25f7841bccd1e250e0f4",
"index": "100644 5aadafc881b7f79b0f432bae3eed46800222249e 0\tworkplans/NK-WP-0026-flex-auth-caller-identity-rollout.md"
},
{
"path": "workplans/NK-WP-0027-reef-placement-reconciliation.md",
"sha256": "3360b2bfeedd04ea5c3854dff0c01960f9c1d2e8433a71f393fc9c8c9253aca2",
"index": "100644 ea0b21e2685b8304c184103f67a013e8f7456ba9 0\tworkplans/NK-WP-0027-reef-placement-reconciliation.md"
},
{
"path": "workplans/NK-WP-0028-canon-publication-and-grouping-semantics.md",
"sha256": "48548faf581e1bacb6952db0050f67b30e634830eb55d20289be85580afb6017",
"index": "100644 e92df0c1de0c77be975f2e375221043598f0091d 0\tworkplans/NK-WP-0028-canon-publication-and-grouping-semantics.md"
},
{
"path": "workplans/NK-WP-0029-scope-and-intent-reconciliation.md",
"sha256": "f2111f2a8c6661022755824091aa20413e10975ef940d5492ff6e9564d45c372",
"index": "100644 fc1b60f6cafeb38dbaa403bce5e050dd631ad54e 0\tworkplans/NK-WP-0029-scope-and-intent-reconciliation.md"
},
{
"path": "workplans/NK-WP-0030-deterministic-security-scenario-composition.md",
"sha256": "f82e1f33ae1ddf2305ce2efc567d2c55809669a47b91c0cabd3d0b41bd78ab3b",
"index": "100644 f60bdbbb04d1c79ed17f40f41cb51c800d162470 0\tworkplans/NK-WP-0030-deterministic-security-scenario-composition.md"
},
{
"path": "workplans/NK-WP-0031-deterministic-posture-feedback.md",
"sha256": "f2b465a883ab8e28ab84f0e94d95e23a15ad6d9b6e038068d96b36dcaa313b5e",
"index": "100644 4cda818a55ff1e02f4a37a7ea24e8caa8d6190df 0\tworkplans/NK-WP-0031-deterministic-posture-feedback.md"
},
{
"path": "workplans/NK-WP-0032-openbao-operator-loopback-callback.md",
"sha256": "a1955896b0ac0805c19bd97264e0e755f2d46a99687acdd2fcd6dd36947aa1bb",
"index": "100644 ce46547934ea494938f818a41379327ed9f627a6 0\tworkplans/NK-WP-0032-openbao-operator-loopback-callback.md"
},
{
"path": "workplans/NK-WP-0033-keycape-secret-exposure-rotation.md",
"sha256": "8268aa86f7fa9f2a3848adfe2dc3022bcf2e9dc9197328993445f4138a40e513",
"index": "100644 1946d3221b8724907911d8b2a0f603583eb12af7 0\tworkplans/NK-WP-0033-keycape-secret-exposure-rotation.md"
},
{
"path": "workplans/NK-WP-0034-verification-that-verifies.md",
"sha256": "d31227ca44d697d9a3e7bef5931836ab0cc6d2c9641900ab1fa8f63307cb7c83",
"index": "100644 7302cd6a053bd1e9fa59d1187ee61f7440c3ef88 0\tworkplans/NK-WP-0034-verification-that-verifies.md"
},
{
"path": "workplans/NK-WP-0035-emission-cadence-security-profile.md",
"sha256": "273a9154a37a7b9efd4fb199e7375d2a3d5cb6919eaa3a2fb8532745a90f83e9",
"index": "100644 4c22c5376951efbf7f3877fc73cfb96a5cbf2769 0\tworkplans/NK-WP-0035-emission-cadence-security-profile.md"
},
{
"path": "workplans/NK-WP-0036-restore-user-portal-client-registration.md",
"sha256": "84019513b7099c39b6dc2daa286017fb48f1286b966fe7c7a142df7c914b575e",
"index": "100644 87b218549c1721ad73962922866b4f119786a475 0\tworkplans/NK-WP-0036-restore-user-portal-client-registration.md"
},
{
"path": "workplans/NK-WP-0037-vergabe-company-welcome.md",
"sha256": "f4fb6d7972f59afa550d6021a9297303e9329867027229512ec9f85b61dda286",
"index": "100644 27f964c0da1b2ff04014f954ee02ac7f5d132d4f 0\tworkplans/NK-WP-0037-vergabe-company-welcome.md"
},
{
"path": "workplans/NK-WP-0038-tenant-scoped-identity-lifecycle.md",
"sha256": "32811a635811c870795aba5d4d2fa6f3b0baecc0b3d270a7cfeb77dbba75206b",
"index": "100644 6b274dc6d6743a0d4c0d5c7b2fea9d8c844b7cad 0\tworkplans/NK-WP-0038-tenant-scoped-identity-lifecycle.md"
},
{
"path": "workplans/NK-WP-0039-flex-auth-access-engine-coordinate-intake.md",
"sha256": "31a0811bf36984f1ef3bdf3c7b7e68d46413909bfb4bc0d781bd7bf49d9bbabf",
"index": "100644 af85aaa2b5acc459ceb633f02465a953d0d84212 0\tworkplans/NK-WP-0039-flex-auth-access-engine-coordinate-intake.md"
},
{
"path": "workplans/NK-WP-0040-execution-attribution-receipt.md",
"sha256": "8b0b653da2fc6ea62a2b804bdb8feb92046876f4e5e0afa96c7c53bc31945d2e",
"index": "100644 541f7f2ebcc09e4cf92ca564d377fa26133c221f 0\tworkplans/NK-WP-0040-execution-attribution-receipt.md"
},
{
"path": "workplans/NK-WP-0041-onboarding-journey-usability.md",
"sha256": "b05d9e14028e83cebbe16b1efcee3477f49a99ae5d6dfc408c41c6cd0b3c3a83",
"index": "100644 549226d24984e4c8a6af8e9791723df4167cfc92 0\tworkplans/NK-WP-0041-onboarding-journey-usability.md"
},
{
"path": "workplans/NK-WP-0042-workload-mfa-step-up.md",
"sha256": "12c95fd8a2cbed6c521c1fbf5464d7cf6b7552d63c11992bc93ec88f2013c618",
"index": "100644 71856e4b4b5d7fc7bd943df27d1eff9ff0647bc2 0\tworkplans/NK-WP-0042-workload-mfa-step-up.md"
},
{
"path": "workplans/NK-WP-0043-cadence-assessment-and-operating-guidance.md",
"sha256": "bf75f9fdaf7745596b79843c33d6325236a0c7de27547169464c367f71100de1",
"index": "100644 814c11d1a3da13c2979e4b5d960ba5f72cba2e7b 0\tworkplans/NK-WP-0043-cadence-assessment-and-operating-guidance.md"
},
{
"path": "workplans/NK-WP-0044-runbook-packs-for-runbook-tutorials.md",
"sha256": "071fe448f456b7622e4d6499dab6005af1e41e9c7cc516bc8389b2847e1c01d5",
"index": "100644 6c9117281daf8de58783018fe5c23d8c58f09d96 0\tworkplans/NK-WP-0044-runbook-packs-for-runbook-tutorials.md"
},
{
"path": "workplans/NK-WP-0045-root-grant-custody-record.md",
"sha256": "72957387424f36b376a3b66ea10381d40665497dbcdc7b029ba54fed87c522d1",
"index": "100644 455c2fb2c64f350836b3b426acdb18bdf3ba3b37 0\tworkplans/NK-WP-0045-root-grant-custody-record.md"
},
{
"path": "workplans/NK-WP-0046-secrets-engine-openbao-client-registration.md",
"sha256": "ef38481d26e599802d94f8b06a4d89c7c99a83c81ca5be9bcf7422b885867479",
"index": "100644 56cdc6b3580a253b38d17dfe4dad007ca00f03ed 0\tworkplans/NK-WP-0046-secrets-engine-openbao-client-registration.md"
},
{
"path": "workplans/NK-WP-0047-platform-password-reset-mail.md",
"sha256": "78b159076121c4e53fef8eadd6287b8c9e91a725203be88816840c9f9c1c8516",
"index": "100644 bdb3c73b42cfe5c9b47c0d9ee77ee44b3a4e187e 0\tworkplans/NK-WP-0047-platform-password-reset-mail.md"
},
{
"path": "workplans/NK-WP-0048-security-case-types.md",
"sha256": "b682cd607d9ed9b232656cc7934ec09ac4e986c1c81131a44f80240342a0571c",
"index": "100644 71cba31e0bef994557e972df18a98d1f2002fa1b 0\tworkplans/NK-WP-0048-security-case-types.md"
},
{
"path": "workplans/NK-WP-0049-bootstrap-secret-free-recovery-handoff.md",
"sha256": "cba3233883e9a5b429aaea1b8eacd250c6efcf5e484c4284ddc97e8e52697085",
"index": "100644 2078d625443a6fcafb22b96f18e9b7bb5c45cc84 0\tworkplans/NK-WP-0049-bootstrap-secret-free-recovery-handoff.md"
},
{
"path": "workplans/NK-WP-0050-playwright-consumer-registration.md",
"sha256": "0be0b643409d0731d4924c95566facdef58b1c65c5c1276f7f308ebfb2271fb7",
"index": "100644 00d4833d270ed06f5e54ea992c175565a824d069 0\tworkplans/NK-WP-0050-playwright-consumer-registration.md"
},
{
"path": "workplans/NK-WP-0051-sign-in-diagnosis.md",
"sha256": "736a06e798d9d15715490f8c3ed2f81a8d065e8446e046e36a2bd19353a083b9",
"index": "100644 5844807b7de5f365fc5353b565e070823cc230b2 0\tworkplans/NK-WP-0051-sign-in-diagnosis.md"
},
{
"path": "workplans/archived/260522-NK-WP-0015-user-engine-isolated-mvp.md",
"sha256": "98e7ae719ae0282e80d541222d12805bebf2ef1abf9dca576f1e32c83d5d31bf",
"index": "100644 0fa1afc14b570ca23fd6f562ac6ae6d083231580 0\tworkplans/archived/260522-NK-WP-0015-user-engine-isolated-mvp.md"
},
{
"path": "workplans/archived/260522-NK-WP-0016-user-engine-multi-tenancy.md",
"sha256": "be9490920a6c8bc1652c334c6b2b1480257b18fffe55406426b04ab240ba7430",
"index": "100644 419f916829f6dc6b453f0988c5b736f79ec7a365 0\tworkplans/archived/260522-NK-WP-0016-user-engine-multi-tenancy.md"
},
{
"path": "workplans/archived/260522-NK-WP-0017-user-engine-multi-application-catalogs.md",
"sha256": "ab5c151034d6ceaf8bf6d4154944fa7406e2edb6127e6adc963429920c425270",
"index": "100644 a047efccf34c48a5900e3168f97345ef71776e4f 0\tworkplans/archived/260522-NK-WP-0017-user-engine-multi-application-catalogs.md"
},
{
"path": "workplans/archived/260522-NK-WP-0018-user-engine-integrated-test-scenarios.md",
"sha256": "2b83295aeaae5a58ad6cef6b0198e9abf8f57a8a9b0216bb166afb71d4d26e28",
"index": "100644 2d3b99d566519a03e5bf98972ab9b355f08fd560 0\tworkplans/archived/260522-NK-WP-0018-user-engine-integrated-test-scenarios.md"
},
{
"path": "workplans/archived/260522-NK-WP-0019-user-engine-finalization-polish.md",
"sha256": "7db746783b2ad60110451b9b44a04471b188bb8a6b49d76c984a1cd4c72b1ae3",
"index": "100644 d7135b4993398d9220e08f5c1f430220a46c114c 0\tworkplans/archived/260522-NK-WP-0019-user-engine-finalization-polish.md"
},
{
"path": "workplans/archived/260603-NET-WP-0015-platform-root-custody-and-openbao-identity-bootstrap.md",
"sha256": "014252768653440c1911512972022122b4f43c3c040c7da34d0f86bba71e1204",
"index": "100644 ef2a569259fd1a08577c09b6b143559ecba375f0 0\tworkplans/archived/260603-NET-WP-0015-platform-root-custody-and-openbao-identity-bootstrap.md"
},
{
"path": "workplans/archived/260603-NET-WP-0016-guided-security-bootstrap-experience.md",
"sha256": "936b446483326b3dc7c1be94397f833a1e124311c98654d1877478a09b8b23e8",
"index": "100644 b23e86009bcf6772faf6f939363897f913d45744 0\tworkplans/archived/260603-NET-WP-0016-guided-security-bootstrap-experience.md"
},
{
"path": "workplans/archived/260603-NK-WP-0003-keycape-privacyidea-cluster-deployment.md",
"sha256": "754955fe18c25c35a1c0036b25f889d281dd8442b86e1793583c97f83f8125c2",
"index": "100644 bd9bf9662654c80fafb192a927aeb35fefe56b2b 0\tworkplans/archived/260603-NK-WP-0003-keycape-privacyidea-cluster-deployment.md"
},
{
"path": "workplans/archived/260603-NK-WP-0004-credential-management-foundation.md",
"sha256": "62a69453f9dc5db8a208e01df83e198249074d921fa83cba9d919385208709fc",
"index": "100644 eea4583d2e6059bf9beee17083309eeb06740e78 0\tworkplans/archived/260603-NK-WP-0004-credential-management-foundation.md"
},
{
"path": "workplans/archived/260603-NK-WP-0005-agent-driven-credential-bootstrap.md",
"sha256": "f7cebada5f6344d0baa7625f66938cafd1f156bd20fe9b00f09c994f290fb4e0",
"index": "100644 6acf610042aa48292be0a589530ab64d3e6750f2 0\tworkplans/archived/260603-NK-WP-0005-agent-driven-credential-bootstrap.md"
},
{
"path": "workplans/archived/260604-NET-WP-0018-bootstrap-automation-and-rebuild-readiness.md",
"sha256": "784b034ba22125ea2098da40c3ece39f9e910c473d4a3f0f8f3c23250aae7e23",
"index": "100644 a781cb44597b2f87eeac5b88117fc506b20e2fbd 0\tworkplans/archived/260604-NET-WP-0018-bootstrap-automation-and-rebuild-readiness.md"
},
{
"path": "workplans/archived/260702-ADHOC-2026-06-14.md",
"sha256": "455b4cb77ec944551696203c79d3a229cbf9e5f2381931632ea1ce23c587e2fd",
"index": "100644 d2efa4d31679469804cf48b6eb56f14c9ccd442a 0\tworkplans/archived/260702-ADHOC-2026-06-14.md"
},
{
"path": "workplans/archived/260702-NET-WP-0017-it-security-readiness-for-user-onboarding.md",
"sha256": "74eafd43790bde4d31728518e1b875ecc8262e6af18e1cd5f81e0882178182be",
"index": "100644 7756f7dd4b7d44a30120b6339fce3e94852e08eb 0\tworkplans/archived/260702-NET-WP-0017-it-security-readiness-for-user-onboarding.md"
},
{
"path": "workplans/archived/260702-NET-WP-0019-t06-adjacent-user-lifecycle-dry-run-polish.md",
"sha256": "61cd3135222696a7b6afd74b2f3a3fd717f5e7985f8ade2ccc66e119a43a9d14",
"index": "100644 b4635dc00ab6a6d6fac0572495fbf6c4172384e7 0\tworkplans/archived/260702-NET-WP-0019-t06-adjacent-user-lifecycle-dry-run-polish.md"
},
{
"path": "workplans/archived/260702-NK-WP-0001-sso-mfa-platform.md",
"sha256": "c904ad4503b45ea64bc9d360c1cc8394398771cabf1a389dea41496714cde6e6",
"index": "100644 78d58cb5be90924c102ca9a57afe0e9af6a15380 0\tworkplans/archived/260702-NK-WP-0001-sso-mfa-platform.md"
},
{
"path": "workplans/archived/260702-NK-WP-0002-local-identity.md",
"sha256": "fc2b924da22125a8d0374e795b962612dfd8e01f583b6a0eefbb827e338127d7",
"index": "100644 a93af8cf2641144212f519bb7fbcb72ad14d2874 0\tworkplans/archived/260702-NK-WP-0002-local-identity.md"
},
{
"path": "workplans/archived/260702-NK-WP-0006-recursive-platform-identity-security-architecture.md",
"sha256": "7a70d174baa28f399c63823c264cb1dfba9af69b61934ffc105cba56e4f34b47",
"index": "100644 886d423af68c175cedc3a5daf28814ca673fafdf 0\tworkplans/archived/260702-NK-WP-0006-recursive-platform-identity-security-architecture.md"
},
{
"path": "workplans/archived/260702-NK-WP-0007-object-storage-sts-credential-vending.md",
"sha256": "d921c3d9c015027b99b30e7723acf6c71151a29927fcdbfaa124f776dcfbd64f",
"index": "100644 14689c43ac98730ad1ae2bd6aeb4648b87bee3eb 0\tworkplans/archived/260702-NK-WP-0007-object-storage-sts-credential-vending.md"
},
{
"path": "workplans/archived/260702-NK-WP-0008-it-security-architecture-patterns-infospace.md",
"sha256": "abacfb3651e56b233587492dda5fa6cbbd08e0c1fc49681a22373e156a630b36",
"index": "100644 88120ba4a87ed785ec63a9edd58b88ec3db6a2bc 0\tworkplans/archived/260702-NK-WP-0008-it-security-architecture-patterns-infospace.md"
},
{
"path": "workplans/archived/260702-NK-WP-0010-genesis-security-pattern-completion.md",
"sha256": "6a0b13e0f82af03e7461f4f433d7876e5f8d9a76acc8888709f4e130e13fb2e4",
"index": "100644 06daac6b1e143bc8505439566ae33eaed8d2fa9c 0\tworkplans/archived/260702-NK-WP-0010-genesis-security-pattern-completion.md"
},
{
"path": "workplans/archived/260702-NK-WP-0012-iam-profile-specification.md",
"sha256": "1ca0aed6549d7cb2aeb490a4110fddfd0f5575832cb7e2f696724b3b4b4e79ba",
"index": "100644 2f80c1f72c65723633fceb45f88195d6a3a131fe 0\tworkplans/archived/260702-NK-WP-0012-iam-profile-specification.md"
},
{
"path": "workplans/archived/260702-NK-WP-0013-playbook-capability-contract.md",
"sha256": "5e69691251391706d3419349bc38cb13c6d910d623b03ba788d31dbcd5a7e3bf",
"index": "100644 aa5edb5fcf8aa7d75220778c595cce455769c95e 0\tworkplans/archived/260702-NK-WP-0013-playbook-capability-contract.md"
},
{
"path": "workplans/archived/260702-NK-WP-0014-user-engine-preparation-boundary-contracts.md",
"sha256": "d4a6e9f60ccfe666645ebf37af0d49b50e692218de46539c50b8b22ec255030a",
"index": "100644 ab0652790e1456957a70cee59b84fb7810c3e9c5 0\tworkplans/archived/260702-NK-WP-0014-user-engine-preparation-boundary-contracts.md"
}
],
"untracked": [
{
"path": "docs/evidence/2026-10-15-cadence-adoption/hourly-observation-capture/capture-provenance.json",
"sha256": "b562f51c58c2114c2122286091dceebf3a107f0822b411cd2d8554d45d0555d5"
},
{
"path": "docs/evidence/2026-10-15-cadence-adoption/hourly-observation-capture/events.jsonl",
"sha256": "3664dc13a3ce3509ca87afc49c1b4c9095cc56cdfb6c37faa4c227556c7d3858"
},
{
"path": "docs/evidence/2026-10-15-cadence-adoption/hourly-observation-capture/receipts.jsonl",
"sha256": "060433115fb784eaf2e7bd7eab7a368d5b4439d925524b68aa4edf920b54b7aa"
},
{
"path": "docs/evidence/2026-10-15-cadence-adoption/hourly-observation-capture/snapshot.json",
"sha256": "210c0c5df320ce2c507eee764596b5928f59a99f938432de87811932d1896676"
},
{
"path": "docs/evidence/2026-10-15-cadence-adoption/hourly-observation-inventory.jsonl",
"sha256": "6588a0795b8374e6ee36e822de9a3f17e1a6c0a7852804c5aeea9f8edc18905e"
},
{
"path": "docs/evidence/2026-10-15-cadence-adoption/hourly-observation-monitor.json",
"sha256": "a1ed7d07bae1813315fa7b2a166f3125a6c0195b2ad468568718429381d77153"
},
{
"path": "intakes/NET-IN-0005-single-use-setup-link-mail-handoff.md",
"sha256": "988a2df3639f9f17d7c8b01621bf3185850f248778d6ccf34cb23001f7f7690d"
}
]
}

View file

@ -0,0 +1,7 @@
{
"head": "3236d5000e52e0643f33906a26a7825aa0b67465",
"restored_generated_paths": [],
"unrelated_tracked_files_preserved": 65,
"untracked_files_preserved": 7,
"status": "M .custodian-brief.md\n M WORK-RECORDS.md\n?? docs/evidence/2026-10-15-cadence-adoption/hourly-observation-capture/\n?? docs/evidence/2026-10-15-cadence-adoption/hourly-observation-inventory.jsonl\n?? docs/evidence/2026-10-15-cadence-adoption/hourly-observation-monitor.json\n?? intakes/NET-IN-0005-single-use-setup-link-mail-handoff.md"
}

View file

@ -0,0 +1,996 @@
{
"ok": true,
"status": "applied",
"repo_slug": "net-kingdom",
"commit": "3236d5000e52e0643f33906a26a7825aa0b67465",
"requests": 2,
"elapsed_ms": 11496.4,
"git": {
"upstream": "origin/main",
"behind": 0,
"ahead": 0
},
"identifiers": {
"schema": "repo-manager.identifier-assignment.v1",
"ok": true,
"executed": true,
"repo": "net-kingdom",
"namespace": "helixforge",
"assignments": [],
"historical_invalid_identifiers": [],
"historical_identity_collisions": [],
"files_changed": []
},
"receipt": {
"schema": "state-hub.repository-projection-reconcile.v1",
"instance_role": "primary",
"instance_label": "railiance01",
"expected_commit": "3236d5000e52e0643f33906a26a7825aa0b67465",
"derived_commit": "3236d5000e52e0643f33906a26a7825aa0b67465",
"outcome": {
"schema": "state-hub.projection-reset.v1",
"repo_slug": "net-kingdom",
"commit": "3236d5000e52e0643f33906a26a7825aa0b67465",
"status": "applied",
"counts": {
"created": 0,
"updated": 64,
"retired": 0,
"refused": 0,
"released": 0,
"created_tasks": 0,
"updated_tasks": 8,
"cancelled_tasks": 0,
"created_edges": 0,
"removed_edges": 0,
"unresolved_edges": 1,
"external_edges": 85
},
"created": [],
"updated": [
"NET-WP-0015",
"NET-WP-0016",
"NET-WP-0017",
"NET-WP-0018",
"NET-WP-0019",
"NET-WP-0020",
"NK-WP-0001",
"NK-WP-0002",
"NK-WP-0003",
"NK-WP-0004",
"NK-WP-0005",
"NK-WP-0006",
"NK-WP-0007",
"NK-WP-0008",
"NK-WP-0009",
"NK-WP-0010",
"NK-WP-0011",
"NK-WP-0012",
"NK-WP-0013",
"NK-WP-0014",
"NK-WP-0015",
"NK-WP-0016",
"NK-WP-0017",
"NK-WP-0018",
"NK-WP-0019",
"NK-WP-0021",
"NK-WP-0022",
"NK-WP-0023",
"NK-WP-0024",
"NK-WP-0025",
"NK-WP-0026",
"NK-WP-0027",
"NK-WP-0028",
"NK-WP-0029",
"NK-WP-0030",
"NK-WP-0031",
"NK-WP-0032",
"NK-WP-0033",
"NK-WP-0034",
"NK-WP-0035",
"NK-WP-0036",
"NK-WP-0037",
"NK-WP-0038",
"NK-WP-0039",
"NK-WP-0040",
"NK-WP-0041",
"NK-WP-0042",
"NK-WP-0043",
"NK-WP-0044",
"NK-WP-0045",
"NK-WP-0046",
"NK-WP-0047",
"NK-WP-0048",
"NK-WP-0049",
"NK-WP-0050",
"NK-WP-0051",
"NK-WP-ADHOC-2026-06-14",
"NK-WP-ADHOC-2026-07-02",
"NK-WP-ADHOC-2026-08-14",
"NK-WP-ADHOC-2026-08-23",
"NK-WP-ADHOC-2026-10-03",
"NK-WP-ADHOC-2026-10-10",
"NK-WP-ADHOC-2026-10-11",
"NK-WP-ADHOC-2026-10-16"
],
"retired": [],
"released": [],
"created_tasks": [],
"updated_tasks": [
"NK-WP-0048-T24",
"NK-WP-0048-T25",
"NK-WP-0048-T26",
"NK-WP-0048-T27",
"NK-WP-0048-T28",
"NK-WP-0048-T29",
"NK-WP-0048-T30",
"NK-WP-0048-T31"
],
"cancelled_tasks": [],
"created_edges": [],
"removed_edges": [],
"unresolved_edges": [
{
"workplan": "NK-WP-0006",
"from": "NK-WP-0006",
"target": "NK-WP-0001",
"reason": "missing"
}
],
"external_edges": [
{
"workplan": "NK-WP-0008",
"from": "NK-WP-0008",
"target": "NK-WP-0006",
"relationship_type": "blocks",
"from_workplan_id": "053c6d96-9396-40c9-a2e5-c36531e7810d",
"from_task_id": null,
"to_workplan_id": "2eb8a5e0-4e33-4ed3-8996-a2eec3aad862",
"to_task_id": null
},
{
"workplan": "NK-WP-0050",
"from": "NK-WP-0050-T03",
"target": "RPF-WP-0056-T03",
"relationship_type": "starts_after",
"from_workplan_id": "06ba98d5-609e-5aaa-9bf7-4c4f4460e377",
"from_task_id": "5a3aaf57-de5c-5a03-bc99-9bcf2fc5d95e",
"to_workplan_id": null,
"to_task_id": "a82762eb-bb6d-5600-89ca-a81ada2eba9f"
},
{
"workplan": "NK-WP-0050",
"from": "NK-WP-0050-T03",
"target": "NK-WP-0050-T02",
"relationship_type": "starts_after",
"from_workplan_id": "06ba98d5-609e-5aaa-9bf7-4c4f4460e377",
"from_task_id": "5a3aaf57-de5c-5a03-bc99-9bcf2fc5d95e",
"to_workplan_id": null,
"to_task_id": "a9dadd07-f136-5dc7-9229-7a9dbb941f0d"
},
{
"workplan": "NK-WP-0050",
"from": "NK-WP-0050-T02",
"target": "NK-WP-0050-T01",
"relationship_type": "starts_after",
"from_workplan_id": "06ba98d5-609e-5aaa-9bf7-4c4f4460e377",
"from_task_id": "a9dadd07-f136-5dc7-9229-7a9dbb941f0d",
"to_workplan_id": null,
"to_task_id": "64893d94-9717-5812-b8e3-7cabe095fcdc"
},
{
"workplan": "NK-WP-0017",
"from": "NK-WP-0017",
"target": "NK-WP-0015",
"relationship_type": "blocks",
"from_workplan_id": "08398d26-cadf-44bc-97ee-67da790040e6",
"from_task_id": null,
"to_workplan_id": "343e035d-41e1-4fc4-b209-6872e4a5fdc8",
"to_task_id": null
},
{
"workplan": "NK-WP-0011",
"from": "NK-WP-0011",
"target": "NK-WP-0006",
"relationship_type": "blocks",
"from_workplan_id": "1075448f-d533-5f9e-94b7-c3adfe151a07",
"from_task_id": null,
"to_workplan_id": "2eb8a5e0-4e33-4ed3-8996-a2eec3aad862",
"to_task_id": null
},
{
"workplan": "NK-WP-0011",
"from": "NK-WP-0011",
"target": "NK-WP-0004",
"relationship_type": "blocks",
"from_workplan_id": "1075448f-d533-5f9e-94b7-c3adfe151a07",
"from_task_id": null,
"to_workplan_id": "d9cf7c4b-886b-4cd1-ad7b-99c4e1929c9e",
"to_task_id": null
},
{
"workplan": "NK-WP-0011",
"from": "NK-WP-0011",
"target": "NK-WP-0003",
"relationship_type": "blocks",
"from_workplan_id": "1075448f-d533-5f9e-94b7-c3adfe151a07",
"from_task_id": null,
"to_workplan_id": "f24cefd4-a09b-4fa1-9b25-94bf783b425e",
"to_task_id": null
},
{
"workplan": "NK-WP-0011",
"from": "NK-WP-0011-T03",
"target": "NK-WP-0011-T02",
"relationship_type": "starts_after",
"from_workplan_id": "1075448f-d533-5f9e-94b7-c3adfe151a07",
"from_task_id": "32d1411b-10a4-5a8b-8f43-99ac46d83908",
"to_workplan_id": null,
"to_task_id": "2fe6f100-3a5d-563e-b033-7d7b846ae487"
},
{
"workplan": "NK-WP-0011",
"from": "NK-WP-0011-T07",
"target": "NK-WP-0011-T03",
"relationship_type": "starts_after",
"from_workplan_id": "1075448f-d533-5f9e-94b7-c3adfe151a07",
"from_task_id": "38998c68-29bf-50d2-8c8d-0c75184d5833",
"to_workplan_id": null,
"to_task_id": "32d1411b-10a4-5a8b-8f43-99ac46d83908"
},
{
"workplan": "NK-WP-0011",
"from": "NK-WP-0011-T07",
"target": "NK-WP-0011-T04",
"relationship_type": "starts_after",
"from_workplan_id": "1075448f-d533-5f9e-94b7-c3adfe151a07",
"from_task_id": "38998c68-29bf-50d2-8c8d-0c75184d5833",
"to_workplan_id": null,
"to_task_id": "6697a994-7343-5ea8-8b37-bc3b921e5a9b"
},
{
"workplan": "NK-WP-0011",
"from": "NK-WP-0011-T07",
"target": "NK-WP-0011-T05",
"relationship_type": "starts_after",
"from_workplan_id": "1075448f-d533-5f9e-94b7-c3adfe151a07",
"from_task_id": "38998c68-29bf-50d2-8c8d-0c75184d5833",
"to_workplan_id": null,
"to_task_id": "d845380d-3dbc-5e59-8f2b-5a4d1b32d89d"
},
{
"workplan": "NK-WP-0011",
"from": "NK-WP-0011-T04",
"target": "NK-WP-0011-T03",
"relationship_type": "starts_after",
"from_workplan_id": "1075448f-d533-5f9e-94b7-c3adfe151a07",
"from_task_id": "6697a994-7343-5ea8-8b37-bc3b921e5a9b",
"to_workplan_id": null,
"to_task_id": "32d1411b-10a4-5a8b-8f43-99ac46d83908"
},
{
"workplan": "NK-WP-0011",
"from": "NK-WP-0011-T06",
"target": "NK-WP-0011-T03",
"relationship_type": "starts_after",
"from_workplan_id": "1075448f-d533-5f9e-94b7-c3adfe151a07",
"from_task_id": "9cb7fd93-c16e-5102-83ce-195b3aa87446",
"to_workplan_id": null,
"to_task_id": "32d1411b-10a4-5a8b-8f43-99ac46d83908"
},
{
"workplan": "NK-WP-0011",
"from": "NK-WP-0011-T06",
"target": "NK-WP-0011-T04",
"relationship_type": "starts_after",
"from_workplan_id": "1075448f-d533-5f9e-94b7-c3adfe151a07",
"from_task_id": "9cb7fd93-c16e-5102-83ce-195b3aa87446",
"to_workplan_id": null,
"to_task_id": "6697a994-7343-5ea8-8b37-bc3b921e5a9b"
},
{
"workplan": "NK-WP-0011",
"from": "NK-WP-0011-T06",
"target": "NK-WP-0011-T05",
"relationship_type": "starts_after",
"from_workplan_id": "1075448f-d533-5f9e-94b7-c3adfe151a07",
"from_task_id": "9cb7fd93-c16e-5102-83ce-195b3aa87446",
"to_workplan_id": null,
"to_task_id": "d845380d-3dbc-5e59-8f2b-5a4d1b32d89d"
},
{
"workplan": "NK-WP-0011",
"from": "NK-WP-0011-T05",
"target": "NK-WP-0011-T04",
"relationship_type": "starts_after",
"from_workplan_id": "1075448f-d533-5f9e-94b7-c3adfe151a07",
"from_task_id": "d845380d-3dbc-5e59-8f2b-5a4d1b32d89d",
"to_workplan_id": null,
"to_task_id": "6697a994-7343-5ea8-8b37-bc3b921e5a9b"
},
{
"workplan": "NK-WP-0011",
"from": "NK-WP-0011-T09",
"target": "NK-WP-0011-T03",
"relationship_type": "starts_after",
"from_workplan_id": "1075448f-d533-5f9e-94b7-c3adfe151a07",
"from_task_id": "d9dc4292-6b66-5797-9ff9-a1a4a556278e",
"to_workplan_id": null,
"to_task_id": "32d1411b-10a4-5a8b-8f43-99ac46d83908"
},
{
"workplan": "NK-WP-0011",
"from": "NK-WP-0011-T09",
"target": "NK-WP-0011-T07",
"relationship_type": "starts_after",
"from_workplan_id": "1075448f-d533-5f9e-94b7-c3adfe151a07",
"from_task_id": "d9dc4292-6b66-5797-9ff9-a1a4a556278e",
"to_workplan_id": null,
"to_task_id": "38998c68-29bf-50d2-8c8d-0c75184d5833"
},
{
"workplan": "NK-WP-0011",
"from": "NK-WP-0011-T09",
"target": "NK-WP-0011-T08",
"relationship_type": "starts_after",
"from_workplan_id": "1075448f-d533-5f9e-94b7-c3adfe151a07",
"from_task_id": "d9dc4292-6b66-5797-9ff9-a1a4a556278e",
"to_workplan_id": null,
"to_task_id": "e5f44ddc-9645-5f61-b84c-da5ab9cccb6d"
},
{
"workplan": "NK-WP-0011",
"from": "NK-WP-0011-T08",
"target": "NK-WP-0011-T02",
"relationship_type": "starts_after",
"from_workplan_id": "1075448f-d533-5f9e-94b7-c3adfe151a07",
"from_task_id": "e5f44ddc-9645-5f61-b84c-da5ab9cccb6d",
"to_workplan_id": null,
"to_task_id": "2fe6f100-3a5d-563e-b033-7d7b846ae487"
},
{
"workplan": "NK-WP-0011",
"from": "NK-WP-0011-T08",
"target": "NK-WP-0011-T03",
"relationship_type": "starts_after",
"from_workplan_id": "1075448f-d533-5f9e-94b7-c3adfe151a07",
"from_task_id": "e5f44ddc-9645-5f61-b84c-da5ab9cccb6d",
"to_workplan_id": null,
"to_task_id": "32d1411b-10a4-5a8b-8f43-99ac46d83908"
},
{
"workplan": "NET-WP-0016",
"from": "NET-WP-0016",
"target": "NET-WP-0015",
"relationship_type": "blocks",
"from_workplan_id": "16069174-6698-4855-ad9e-5092c8571f38",
"from_task_id": null,
"to_workplan_id": "6b9c25e4-1008-429a-8de6-54361872c0dd",
"to_task_id": null
},
{
"workplan": "NET-WP-0016",
"from": "NET-WP-0016",
"target": "NK-WP-0012",
"relationship_type": "blocks",
"from_workplan_id": "16069174-6698-4855-ad9e-5092c8571f38",
"from_task_id": null,
"to_workplan_id": "9b8e4afc-eb71-47d9-8750-799a082b320a",
"to_task_id": null
},
{
"workplan": "NK-WP-0049",
"from": "NK-WP-0049-T18",
"target": "NK-WP-0049-T33",
"relationship_type": "starts_after",
"from_workplan_id": "17d315f0-829e-57c7-85cc-3a7914152804",
"from_task_id": "141dd773-c1fa-56c1-a852-bbe2372e5125",
"to_workplan_id": null,
"to_task_id": "56c8d469-7a10-5d50-a30e-95cbf3cd4756"
},
{
"workplan": "NK-WP-0049",
"from": "NK-WP-0049-T18",
"target": "NK-WP-0049-T32",
"relationship_type": "starts_after",
"from_workplan_id": "17d315f0-829e-57c7-85cc-3a7914152804",
"from_task_id": "141dd773-c1fa-56c1-a852-bbe2372e5125",
"to_workplan_id": null,
"to_task_id": "cd78dbb7-a8f2-5754-8788-6eb1b7d97741"
},
{
"workplan": "NK-WP-0049",
"from": "NK-WP-0049-T35",
"target": "NK-WP-0049-T34",
"relationship_type": "starts_after",
"from_workplan_id": "17d315f0-829e-57c7-85cc-3a7914152804",
"from_task_id": "1bfd1703-589f-5511-bad5-812d860e4a71",
"to_workplan_id": null,
"to_task_id": "821b3a56-6f36-5812-abc9-5a00e37cb2e7"
},
{
"workplan": "NK-WP-0049",
"from": "NK-WP-0049-T33",
"target": "NK-WP-0049-T35",
"relationship_type": "starts_after",
"from_workplan_id": "17d315f0-829e-57c7-85cc-3a7914152804",
"from_task_id": "56c8d469-7a10-5d50-a30e-95cbf3cd4756",
"to_workplan_id": null,
"to_task_id": "1bfd1703-589f-5511-bad5-812d860e4a71"
},
{
"workplan": "NK-WP-0049",
"from": "NK-WP-0049-T33",
"target": "NK-WP-0049-T34",
"relationship_type": "starts_after",
"from_workplan_id": "17d315f0-829e-57c7-85cc-3a7914152804",
"from_task_id": "56c8d469-7a10-5d50-a30e-95cbf3cd4756",
"to_workplan_id": null,
"to_task_id": "821b3a56-6f36-5812-abc9-5a00e37cb2e7"
},
{
"workplan": "NK-WP-0049",
"from": "NK-WP-0049-T33",
"target": "NK-WP-0049-T36",
"relationship_type": "starts_after",
"from_workplan_id": "17d315f0-829e-57c7-85cc-3a7914152804",
"from_task_id": "56c8d469-7a10-5d50-a30e-95cbf3cd4756",
"to_workplan_id": null,
"to_task_id": "8b72334b-fc27-5707-a189-bad345eaf3bc"
},
{
"workplan": "NK-WP-0049",
"from": "NK-WP-0049-T33",
"target": "NK-WP-0049-T32",
"relationship_type": "starts_after",
"from_workplan_id": "17d315f0-829e-57c7-85cc-3a7914152804",
"from_task_id": "56c8d469-7a10-5d50-a30e-95cbf3cd4756",
"to_workplan_id": null,
"to_task_id": "cd78dbb7-a8f2-5754-8788-6eb1b7d97741"
},
{
"workplan": "NK-WP-0049",
"from": "NK-WP-0049-T36",
"target": "NK-WP-0049-T34",
"relationship_type": "starts_after",
"from_workplan_id": "17d315f0-829e-57c7-85cc-3a7914152804",
"from_task_id": "8b72334b-fc27-5707-a189-bad345eaf3bc",
"to_workplan_id": null,
"to_task_id": "821b3a56-6f36-5812-abc9-5a00e37cb2e7"
},
{
"workplan": "NK-WP-0049",
"from": "NK-WP-0049-T03",
"target": "NK-WP-0049-T02",
"relationship_type": "starts_after",
"from_workplan_id": "17d315f0-829e-57c7-85cc-3a7914152804",
"from_task_id": "d68cd4d3-1ba3-530e-88f9-26ebb8dd6eac",
"to_workplan_id": null,
"to_task_id": "479d6970-6516-50f5-9436-bb5b56d58aad"
},
{
"workplan": "NK-WP-0025",
"from": "NK-WP-0025",
"target": "NK-WP-0024",
"relationship_type": "blocks",
"from_workplan_id": "2412a251-d6b5-5f05-8082-3eb7697c51dc",
"from_task_id": null,
"to_workplan_id": "635a73d4-b3cb-5c38-af22-56a6a66beb0e",
"to_task_id": null
},
{
"workplan": "NK-WP-0016",
"from": "NK-WP-0016",
"target": "NK-WP-0015",
"relationship_type": "blocks",
"from_workplan_id": "2d592e18-e63d-4856-97a1-f8c3e019e150",
"from_task_id": null,
"to_workplan_id": "343e035d-41e1-4fc4-b209-6872e4a5fdc8",
"to_task_id": null
},
{
"workplan": "NK-WP-0006",
"from": "NK-WP-0006",
"target": "NK-WP-0005",
"relationship_type": "blocks",
"from_workplan_id": "2eb8a5e0-4e33-4ed3-8996-a2eec3aad862",
"from_task_id": null,
"to_workplan_id": "75bc472b-cc0a-48f2-afb6-62b896f7cc19",
"to_task_id": null
},
{
"workplan": "NK-WP-0006",
"from": "NK-WP-0006",
"target": "NK-WP-0004",
"relationship_type": "blocks",
"from_workplan_id": "2eb8a5e0-4e33-4ed3-8996-a2eec3aad862",
"from_task_id": null,
"to_workplan_id": "d9cf7c4b-886b-4cd1-ad7b-99c4e1929c9e",
"to_task_id": null
},
{
"workplan": "NK-WP-0013",
"from": "NK-WP-0013",
"target": "NK-WP-0006",
"relationship_type": "blocks",
"from_workplan_id": "32a54d8e-8633-42a6-8ec1-104842c581c1",
"from_task_id": null,
"to_workplan_id": "2eb8a5e0-4e33-4ed3-8996-a2eec3aad862",
"to_task_id": null
},
{
"workplan": "NK-WP-0015",
"from": "NK-WP-0015",
"target": "NK-WP-0014",
"relationship_type": "blocks",
"from_workplan_id": "343e035d-41e1-4fc4-b209-6872e4a5fdc8",
"from_task_id": null,
"to_workplan_id": "b9bf56bc-7ef6-43eb-badc-fa0f4896c63c",
"to_task_id": null
},
{
"workplan": "NET-WP-0017",
"from": "NET-WP-0017",
"target": "NET-WP-0016",
"relationship_type": "blocks",
"from_workplan_id": "385de708-fd59-4bab-a4f4-28c1c476b3ea",
"from_task_id": null,
"to_workplan_id": "16069174-6698-4855-ad9e-5092c8571f38",
"to_task_id": null
},
{
"workplan": "NET-WP-0017",
"from": "NET-WP-0017",
"target": "NET-WP-0015",
"relationship_type": "blocks",
"from_workplan_id": "385de708-fd59-4bab-a4f4-28c1c476b3ea",
"from_task_id": null,
"to_workplan_id": "6b9c25e4-1008-429a-8de6-54361872c0dd",
"to_task_id": null
},
{
"workplan": "NK-WP-0007",
"from": "NK-WP-0007",
"target": "NK-WP-0006",
"relationship_type": "blocks",
"from_workplan_id": "3cbc81ec-7ad5-46cf-a4a0-fc5fe9873695",
"from_task_id": null,
"to_workplan_id": "2eb8a5e0-4e33-4ed3-8996-a2eec3aad862",
"to_task_id": null
},
{
"workplan": "NK-WP-0007",
"from": "NK-WP-0007",
"target": "NK-WP-0005",
"relationship_type": "blocks",
"from_workplan_id": "3cbc81ec-7ad5-46cf-a4a0-fc5fe9873695",
"from_task_id": null,
"to_workplan_id": "75bc472b-cc0a-48f2-afb6-62b896f7cc19",
"to_task_id": null
},
{
"workplan": "NK-WP-0007",
"from": "NK-WP-0007",
"target": "NK-WP-0004",
"relationship_type": "blocks",
"from_workplan_id": "3cbc81ec-7ad5-46cf-a4a0-fc5fe9873695",
"from_task_id": null,
"to_workplan_id": "d9cf7c4b-886b-4cd1-ad7b-99c4e1929c9e",
"to_task_id": null
},
{
"workplan": "NK-WP-0024",
"from": "NK-WP-0024",
"target": "NK-WP-0023",
"relationship_type": "blocks",
"from_workplan_id": "635a73d4-b3cb-5c38-af22-56a6a66beb0e",
"from_task_id": null,
"to_workplan_id": "fdb3deee-06c3-5d12-91ce-9c50b2ac0618",
"to_task_id": null
},
{
"workplan": "NET-WP-0015",
"from": "NET-WP-0015",
"target": "NK-WP-0006",
"relationship_type": "blocks",
"from_workplan_id": "6b9c25e4-1008-429a-8de6-54361872c0dd",
"from_task_id": null,
"to_workplan_id": "2eb8a5e0-4e33-4ed3-8996-a2eec3aad862",
"to_task_id": null
},
{
"workplan": "NET-WP-0015",
"from": "NET-WP-0015",
"target": "NK-WP-0012",
"relationship_type": "blocks",
"from_workplan_id": "6b9c25e4-1008-429a-8de6-54361872c0dd",
"from_task_id": null,
"to_workplan_id": "9b8e4afc-eb71-47d9-8750-799a082b320a",
"to_task_id": null
},
{
"workplan": "NK-WP-0018",
"from": "NK-WP-0018",
"target": "NK-WP-0017",
"relationship_type": "blocks",
"from_workplan_id": "6f75035a-e056-4eab-8fdb-00a18bacdf87",
"from_task_id": null,
"to_workplan_id": "08398d26-cadf-44bc-97ee-67da790040e6",
"to_task_id": null
},
{
"workplan": "NK-WP-0018",
"from": "NK-WP-0018",
"target": "NK-WP-0016",
"relationship_type": "blocks",
"from_workplan_id": "6f75035a-e056-4eab-8fdb-00a18bacdf87",
"from_task_id": null,
"to_workplan_id": "2d592e18-e63d-4856-97a1-f8c3e019e150",
"to_task_id": null
},
{
"workplan": "NK-WP-0005",
"from": "NK-WP-0005",
"target": "NK-WP-0004",
"relationship_type": "blocks",
"from_workplan_id": "75bc472b-cc0a-48f2-afb6-62b896f7cc19",
"from_task_id": null,
"to_workplan_id": "d9cf7c4b-886b-4cd1-ad7b-99c4e1929c9e",
"to_task_id": null
},
{
"workplan": "NET-WP-0019",
"from": "NET-WP-0019",
"target": "NET-WP-0017",
"relationship_type": "blocks",
"from_workplan_id": "75d388b6-7ec1-4e1b-8c87-6ff44f953210",
"from_task_id": null,
"to_workplan_id": "385de708-fd59-4bab-a4f4-28c1c476b3ea",
"to_task_id": null
},
{
"workplan": "NET-WP-0019",
"from": "NET-WP-0019",
"target": "NET-WP-0018",
"relationship_type": "blocks",
"from_workplan_id": "75d388b6-7ec1-4e1b-8c87-6ff44f953210",
"from_task_id": null,
"to_workplan_id": "800f9f16-bc44-4bbf-a771-58a630a3b698",
"to_task_id": null
},
{
"workplan": "NET-WP-0018",
"from": "NET-WP-0018",
"target": "NET-WP-0017",
"relationship_type": "blocks",
"from_workplan_id": "800f9f16-bc44-4bbf-a771-58a630a3b698",
"from_task_id": null,
"to_workplan_id": "385de708-fd59-4bab-a4f4-28c1c476b3ea",
"to_task_id": null
},
{
"workplan": "NET-WP-0018",
"from": "NET-WP-0018",
"target": "NET-WP-0015",
"relationship_type": "blocks",
"from_workplan_id": "800f9f16-bc44-4bbf-a771-58a630a3b698",
"from_task_id": null,
"to_workplan_id": "6b9c25e4-1008-429a-8de6-54361872c0dd",
"to_task_id": null
},
{
"workplan": "NK-WP-0027",
"from": "NK-WP-0027-T03",
"target": "NK-WP-0027-T02",
"relationship_type": "starts_after",
"from_workplan_id": "965ad365-6b81-50a1-a2a3-2d0c1fcce0b4",
"from_task_id": "e3f0bb0f-0c85-5cb9-a5ab-75f668cd3447",
"to_workplan_id": null,
"to_task_id": "5b35b646-a525-55da-852a-6005613d42ea"
},
{
"workplan": "NK-WP-0012",
"from": "NK-WP-0012",
"target": "NK-WP-0006",
"relationship_type": "blocks",
"from_workplan_id": "9b8e4afc-eb71-47d9-8750-799a082b320a",
"from_task_id": null,
"to_workplan_id": "2eb8a5e0-4e33-4ed3-8996-a2eec3aad862",
"to_task_id": null
},
{
"workplan": "NK-WP-0014",
"from": "NK-WP-0014",
"target": "NK-WP-0013",
"relationship_type": "blocks",
"from_workplan_id": "b9bf56bc-7ef6-43eb-badc-fa0f4896c63c",
"from_task_id": null,
"to_workplan_id": "32a54d8e-8633-42a6-8ec1-104842c581c1",
"to_task_id": null
},
{
"workplan": "NK-WP-0014",
"from": "NK-WP-0014",
"target": "NK-WP-0012",
"relationship_type": "blocks",
"from_workplan_id": "b9bf56bc-7ef6-43eb-badc-fa0f4896c63c",
"from_task_id": null,
"to_workplan_id": "9b8e4afc-eb71-47d9-8750-799a082b320a",
"to_task_id": null
},
{
"workplan": "NK-WP-0019",
"from": "NK-WP-0019",
"target": "NK-WP-0018",
"relationship_type": "blocks",
"from_workplan_id": "d2daa8b4-8ecf-4377-b382-492e653735f7",
"from_task_id": null,
"to_workplan_id": "6f75035a-e056-4eab-8fdb-00a18bacdf87",
"to_task_id": null
},
{
"workplan": "NK-WP-0009",
"from": "NK-WP-0009",
"target": "NK-WP-0008",
"relationship_type": "blocks",
"from_workplan_id": "d4d02dbf-3974-502d-8b87-b776fc63e17e",
"from_task_id": null,
"to_workplan_id": "053c6d96-9396-40c9-a2e5-c36531e7810d",
"to_task_id": null
},
{
"workplan": "NK-WP-0022",
"from": "NK-WP-0022",
"target": "NK-WP-0023",
"relationship_type": "blocks",
"from_workplan_id": "d76ddccc-00c8-548a-b141-2cd660fa38da",
"from_task_id": null,
"to_workplan_id": "fdb3deee-06c3-5d12-91ce-9c50b2ac0618",
"to_task_id": null
},
{
"workplan": "NK-WP-0048",
"from": "NK-WP-0048-T15",
"target": "NK-WP-0048-T31",
"relationship_type": "starts_after",
"from_workplan_id": "e31f3f9d-0748-5137-b0a3-7b3ca46a66eb",
"from_task_id": "1b825705-4848-5edc-832f-b1622cd9bdb7",
"to_workplan_id": null,
"to_task_id": "ed1ccd87-89a0-5e69-885c-0eaf5ab0bb5a"
},
{
"workplan": "NK-WP-0048",
"from": "NK-WP-0048-T16",
"target": "NK-WP-0048-T25",
"relationship_type": "starts_after",
"from_workplan_id": "e31f3f9d-0748-5137-b0a3-7b3ca46a66eb",
"from_task_id": "200bf500-5084-5ae7-be26-3033fe1f296e",
"to_workplan_id": null,
"to_task_id": "0de2a7d9-874d-578b-a076-f653fe42e30b"
},
{
"workplan": "NK-WP-0048",
"from": "NK-WP-0048-T16",
"target": "NK-WP-0048-T29",
"relationship_type": "starts_after",
"from_workplan_id": "e31f3f9d-0748-5137-b0a3-7b3ca46a66eb",
"from_task_id": "200bf500-5084-5ae7-be26-3033fe1f296e",
"to_workplan_id": null,
"to_task_id": "129db41d-4560-5e20-9f3b-c3c91e0a5601"
},
{
"workplan": "NK-WP-0048",
"from": "NK-WP-0048-T16",
"target": "NK-WP-0048-T24",
"relationship_type": "starts_after",
"from_workplan_id": "e31f3f9d-0748-5137-b0a3-7b3ca46a66eb",
"from_task_id": "200bf500-5084-5ae7-be26-3033fe1f296e",
"to_workplan_id": null,
"to_task_id": "1a3931ee-3b5f-52fc-9295-4073804f4bd2"
},
{
"workplan": "NK-WP-0048",
"from": "NK-WP-0048-T16",
"target": "NK-WP-0048-T28",
"relationship_type": "starts_after",
"from_workplan_id": "e31f3f9d-0748-5137-b0a3-7b3ca46a66eb",
"from_task_id": "200bf500-5084-5ae7-be26-3033fe1f296e",
"to_workplan_id": null,
"to_task_id": "6dab281c-ea9a-5a17-a83f-e8e9a4d4484f"
},
{
"workplan": "NK-WP-0048",
"from": "NK-WP-0048-T16",
"target": "NK-WP-0048-T30",
"relationship_type": "starts_after",
"from_workplan_id": "e31f3f9d-0748-5137-b0a3-7b3ca46a66eb",
"from_task_id": "200bf500-5084-5ae7-be26-3033fe1f296e",
"to_workplan_id": null,
"to_task_id": "6f6073ac-52dd-5b70-8874-6d76d4c072e4"
},
{
"workplan": "NK-WP-0048",
"from": "NK-WP-0048-T16",
"target": "NK-WP-0048-T26",
"relationship_type": "starts_after",
"from_workplan_id": "e31f3f9d-0748-5137-b0a3-7b3ca46a66eb",
"from_task_id": "200bf500-5084-5ae7-be26-3033fe1f296e",
"to_workplan_id": null,
"to_task_id": "94b3cbf0-c908-5ac6-b0db-67385c3e021c"
},
{
"workplan": "NK-WP-0048",
"from": "NK-WP-0048-T16",
"target": "NK-WP-0048-T27",
"relationship_type": "starts_after",
"from_workplan_id": "e31f3f9d-0748-5137-b0a3-7b3ca46a66eb",
"from_task_id": "200bf500-5084-5ae7-be26-3033fe1f296e",
"to_workplan_id": null,
"to_task_id": "e56365f8-29b5-5c89-a329-8115f9f3b2a7"
},
{
"workplan": "NK-WP-0048",
"from": "NK-WP-0048-T07",
"target": "NK-WP-0048-T06",
"relationship_type": "starts_after",
"from_workplan_id": "e31f3f9d-0748-5137-b0a3-7b3ca46a66eb",
"from_task_id": "c3c9c3ae-4f23-5ba7-9e6f-e63bcf29b9f7",
"to_workplan_id": null,
"to_task_id": "d9b26bcf-a7c6-59a2-92a0-f913d76a203c"
},
{
"workplan": "NK-WP-0048",
"from": "NK-WP-0048-T06",
"target": "NK-WP-0048-T09",
"relationship_type": "starts_after",
"from_workplan_id": "e31f3f9d-0748-5137-b0a3-7b3ca46a66eb",
"from_task_id": "d9b26bcf-a7c6-59a2-92a0-f913d76a203c",
"to_workplan_id": null,
"to_task_id": "0ee12dfc-8260-5038-bd39-cc7fb4113be0"
},
{
"workplan": "NK-WP-0048",
"from": "NK-WP-0048-T06",
"target": "NK-WP-0048-T15",
"relationship_type": "starts_after",
"from_workplan_id": "e31f3f9d-0748-5137-b0a3-7b3ca46a66eb",
"from_task_id": "d9b26bcf-a7c6-59a2-92a0-f913d76a203c",
"to_workplan_id": null,
"to_task_id": "1b825705-4848-5edc-832f-b1622cd9bdb7"
},
{
"workplan": "NK-WP-0048",
"from": "NK-WP-0048-T06",
"target": "NK-WP-0048-T16",
"relationship_type": "starts_after",
"from_workplan_id": "e31f3f9d-0748-5137-b0a3-7b3ca46a66eb",
"from_task_id": "d9b26bcf-a7c6-59a2-92a0-f913d76a203c",
"to_workplan_id": null,
"to_task_id": "200bf500-5084-5ae7-be26-3033fe1f296e"
},
{
"workplan": "NK-WP-0048",
"from": "NK-WP-0048-T06",
"target": "NK-WP-0048-T05",
"relationship_type": "starts_after",
"from_workplan_id": "e31f3f9d-0748-5137-b0a3-7b3ca46a66eb",
"from_task_id": "d9b26bcf-a7c6-59a2-92a0-f913d76a203c",
"to_workplan_id": null,
"to_task_id": "3d987d3d-0797-538b-86e4-51185a327ae2"
},
{
"workplan": "NK-WP-0048",
"from": "NK-WP-0048-T06",
"target": "MASON-WP-0010-T03",
"relationship_type": "starts_after",
"from_workplan_id": "e31f3f9d-0748-5137-b0a3-7b3ca46a66eb",
"from_task_id": "d9b26bcf-a7c6-59a2-92a0-f913d76a203c",
"to_workplan_id": null,
"to_task_id": "56cea6be-c613-586c-80cd-125340b374da"
},
{
"workplan": "NK-WP-0048",
"from": "NK-WP-0048-T06",
"target": "NK-WP-0048-T12",
"relationship_type": "starts_after",
"from_workplan_id": "e31f3f9d-0748-5137-b0a3-7b3ca46a66eb",
"from_task_id": "d9b26bcf-a7c6-59a2-92a0-f913d76a203c",
"to_workplan_id": null,
"to_task_id": "7ce4eee3-cd47-55a9-bfa5-4f1835d4d6fd"
},
{
"workplan": "NK-WP-0048",
"from": "NK-WP-0048-T06",
"target": "NK-WP-0048-T20",
"relationship_type": "starts_after",
"from_workplan_id": "e31f3f9d-0748-5137-b0a3-7b3ca46a66eb",
"from_task_id": "d9b26bcf-a7c6-59a2-92a0-f913d76a203c",
"to_workplan_id": null,
"to_task_id": "863fcbdb-e246-51ba-87ca-a2f44d01d6f8"
},
{
"workplan": "NK-WP-0048",
"from": "NK-WP-0048-T06",
"target": "NK-WP-0048-T17",
"relationship_type": "starts_after",
"from_workplan_id": "e31f3f9d-0748-5137-b0a3-7b3ca46a66eb",
"from_task_id": "d9b26bcf-a7c6-59a2-92a0-f913d76a203c",
"to_workplan_id": null,
"to_task_id": "8c3e4baa-a218-5996-af9e-fe1153a46dac"
},
{
"workplan": "NK-WP-0048",
"from": "NK-WP-0048-T06",
"target": "NK-WP-0048-T08",
"relationship_type": "starts_after",
"from_workplan_id": "e31f3f9d-0748-5137-b0a3-7b3ca46a66eb",
"from_task_id": "d9b26bcf-a7c6-59a2-92a0-f913d76a203c",
"to_workplan_id": null,
"to_task_id": "8e519082-dc8b-5e46-b660-03d03e55dcf6"
},
{
"workplan": "NK-WP-0048",
"from": "NK-WP-0048-T06",
"target": "NK-WP-0048-T18",
"relationship_type": "starts_after",
"from_workplan_id": "e31f3f9d-0748-5137-b0a3-7b3ca46a66eb",
"from_task_id": "d9b26bcf-a7c6-59a2-92a0-f913d76a203c",
"to_workplan_id": null,
"to_task_id": "9c45da71-fb4c-5f20-9065-90f448f37c64"
},
{
"workplan": "NK-WP-0048",
"from": "NK-WP-0048-T06",
"target": "NK-WP-0048-T13",
"relationship_type": "starts_after",
"from_workplan_id": "e31f3f9d-0748-5137-b0a3-7b3ca46a66eb",
"from_task_id": "d9b26bcf-a7c6-59a2-92a0-f913d76a203c",
"to_workplan_id": null,
"to_task_id": "b264c10b-565c-5d29-b788-03cf5fbd2883"
},
{
"workplan": "NK-WP-0048",
"from": "NK-WP-0048-T06",
"target": "WARDEN-WP-0044-T03",
"relationship_type": "starts_after",
"from_workplan_id": "e31f3f9d-0748-5137-b0a3-7b3ca46a66eb",
"from_task_id": "d9b26bcf-a7c6-59a2-92a0-f913d76a203c",
"to_workplan_id": null,
"to_task_id": "bcbf6c91-2c04-5c16-ae8c-5d6c06fd6b89"
},
{
"workplan": "NK-WP-0048",
"from": "NK-WP-0048-T06",
"target": "NK-WP-0048-T14",
"relationship_type": "starts_after",
"from_workplan_id": "e31f3f9d-0748-5137-b0a3-7b3ca46a66eb",
"from_task_id": "d9b26bcf-a7c6-59a2-92a0-f913d76a203c",
"to_workplan_id": null,
"to_task_id": "fce95440-a25b-5f27-8ef3-a3d182099113"
},
{
"workplan": "NK-WP-0048",
"from": "NK-WP-0048-T14",
"target": "NK-WP-0048-T20",
"relationship_type": "starts_after",
"from_workplan_id": "e31f3f9d-0748-5137-b0a3-7b3ca46a66eb",
"from_task_id": "fce95440-a25b-5f27-8ef3-a3d182099113",
"to_workplan_id": null,
"to_task_id": "863fcbdb-e246-51ba-87ca-a2f44d01d6f8"
},
{
"workplan": "NK-WP-0010",
"from": "NK-WP-0010",
"target": "NK-WP-0008",
"relationship_type": "blocks",
"from_workplan_id": "f4faf8b4-ae57-40cf-a881-6fe66ca6ad74",
"from_task_id": null,
"to_workplan_id": "053c6d96-9396-40c9-a2e5-c36531e7810d",
"to_task_id": null
}
],
"refused": [],
"notes": []
}
}
}

View file

@ -0,0 +1,23 @@
from pathlib import Path
import json,hashlib,subprocess
p=Path(__file__).resolve().parent;r=Path('/home/worsch/net-kingdom')
pre=json.loads((p/'preimage.json').read_text());head=json.loads((p/'commit-receipt.json').read_text())['commit']
def git(*a):return subprocess.check_output(['git','-C',str(r),*a]).decode().strip()
assert git('rev-parse','HEAD')==head,'HEAD changed concurrently; stop'
restored=[]
for row in pre['files']:
name=row['path']
if name=='workplans/NK-WP-0048-security-case-types.md':
assert (r/name).read_bytes()==(p/'candidate.md').read_bytes();continue
if name in ('.custodian-brief.md','WORK-RECORDS.md'):
if (r/name).read_bytes()!=(p/'backup'/name).read_bytes():
(p/(name.lstrip('.')+'.after-consistency')).write_bytes((r/name).read_bytes())
(r/name).write_bytes((p/'backup'/name).read_bytes());restored.append(name)
if git('ls-files','--stage','--',name)!=row['index']:
mode,oid,stage,path=row['index'].split();assert stage=='0';git('update-index','--cacheinfo',mode,oid,path)
assert hashlib.sha256((r/name).read_bytes()).hexdigest()==row['sha256'],name
assert git('ls-files','--stage','--',name)==row['index'],name
for row in pre['untracked']:
assert hashlib.sha256((r/row['path']).read_bytes()).hexdigest()==row['sha256'],row['path']
(p/'preservation-verification.json').write_text(json.dumps({'head':head,'restored_generated_paths':restored,'unrelated_tracked_files_preserved':len(pre['files'])-1,'untracked_files_preserved':len(pre['untracked']),'status':git('status','--short')},indent=2)+'\n')
print(json.dumps({'head':head,'restored':restored,'preserved':True}))

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,96 @@
{
"status": "published-and-projected",
"commit": "3236d5000e52e0643f33906a26a7825aa0b67465",
"only_committed_path": "workplans/NK-WP-0048-security-case-types.md",
"projection_status": "applied",
"instance_role": "primary",
"instance_label": "railiance01",
"expected_commit": "3236d5000e52e0643f33906a26a7825aa0b67465",
"derived_commit": "3236d5000e52e0643f33906a26a7825aa0b67465",
"original_task_count": 31,
"current_task_count": 31,
"all_task_ids_and_statuses_unchanged": true,
"all_source_task_blocks_unchanged": true,
"T15_task_block": "```task\nid: NK-WP-0048-T15\nstatus: wait\ndepends_on: [NK-WP-0048-T31]\nblocking_reason: \"Source candidate 061461e is merged. Waiting on the owner to select the real authenticated original-attempt holder and native readback, and on independent re-review of the changed T13 adapter source.\"\npriority: high\nstate_hub_task_id: \"1b825705-4848-5edc-832f-b1622cd9bdb7\"\n```",
"preservation": {
"head": "3236d5000e52e0643f33906a26a7825aa0b67465",
"restored_generated_paths": [],
"unrelated_tracked_files_preserved": 65,
"untracked_files_preserved": 7,
"status": "M .custodian-brief.md\n M WORK-RECORDS.md\n?? docs/evidence/2026-10-15-cadence-adoption/hourly-observation-capture/\n?? docs/evidence/2026-10-15-cadence-adoption/hourly-observation-inventory.jsonl\n?? docs/evidence/2026-10-15-cadence-adoption/hourly-observation-monitor.json\n?? intakes/NET-IN-0005-single-use-setup-link-mail-handoff.md"
},
"native_or_credential_or_adapter_changes": false,
"root_git_brief_work_modified": false,
"canonical_source_record_id_convergence_T24_T31": [
{
"id": "1a3931ee-3b5f-52fc-9295-4073804f4bd2",
"record_id": "NK-WP-0048-T24",
"status": "done",
"workplan_id": "e31f3f9d-0748-5137-b0a3-7b3ca46a66eb"
},
{
"id": "0de2a7d9-874d-578b-a076-f653fe42e30b",
"record_id": "NK-WP-0048-T25",
"status": "done",
"workplan_id": "e31f3f9d-0748-5137-b0a3-7b3ca46a66eb"
},
{
"id": "94b3cbf0-c908-5ac6-b0db-67385c3e021c",
"record_id": "NK-WP-0048-T26",
"status": "done",
"workplan_id": "e31f3f9d-0748-5137-b0a3-7b3ca46a66eb"
},
{
"id": "e56365f8-29b5-5c89-a329-8115f9f3b2a7",
"record_id": "NK-WP-0048-T27",
"status": "done",
"workplan_id": "e31f3f9d-0748-5137-b0a3-7b3ca46a66eb"
},
{
"id": "6dab281c-ea9a-5a17-a83f-e8e9a4d4484f",
"record_id": "NK-WP-0048-T28",
"status": "done",
"workplan_id": "e31f3f9d-0748-5137-b0a3-7b3ca46a66eb"
},
{
"id": "129db41d-4560-5e20-9f3b-c3c91e0a5601",
"record_id": "NK-WP-0048-T29",
"status": "done",
"workplan_id": "e31f3f9d-0748-5137-b0a3-7b3ca46a66eb"
},
{
"id": "6f6073ac-52dd-5b70-8874-6d76d4c072e4",
"record_id": "NK-WP-0048-T30",
"status": "done",
"workplan_id": "e31f3f9d-0748-5137-b0a3-7b3ca46a66eb"
},
{
"id": "ed1ccd87-89a0-5e69-885c-0eaf5ab0bb5a",
"record_id": "NK-WP-0048-T31",
"status": "done",
"workplan_id": "e31f3f9d-0748-5137-b0a3-7b3ca46a66eb"
}
],
"canonical_counts": {
"created": 0,
"updated": 64,
"retired": 0,
"refused": 0,
"released": 0,
"created_tasks": 0,
"updated_tasks": 8,
"cancelled_tasks": 0,
"created_edges": 0,
"removed_edges": 0,
"unresolved_edges": 1,
"external_edges": 85
},
"reported_unresolved_edges": [
{
"workplan": "NK-WP-0006",
"from": "NK-WP-0006",
"target": "NK-WP-0001",
"reason": "missing"
}
]
}

View file

@ -0,0 +1,164 @@
{
"schema": "custodian.warden-concurrent-original-context-comparison.v1",
"observed_at": "2026-10-17T05:56:50.251443+00:00",
"verdict": "Concurrent OriginalIntent variant solves local original-dispatch persistence, not independent original-creation authentication. Preserve its additive architecture; apply no older fingerprint-table replacement. Minimal artifact delta addresses concrete local consistency/privacy-contract defects only after root ownership/review.",
"base_state": {
"observed_at": "2026-10-17T05:53:20.364253+00:00",
"owner": "ops-warden",
"canonical_head": "a45cf475bc4dbc929e0eecbc1f806a9229d934e2",
"sources": [
{
"path": "src/warden/case_run.py",
"base_head": "a45cf475bc4dbc929e0eecbc1f806a9229d934e2",
"base_sha256": "sha256:0574036ca7b74bdb9124f6af4888e63ec231ee60f5c9f34cbe2fb1acee39f671",
"worktree_sha256": "sha256:0574036ca7b74bdb9124f6af4888e63ec231ee60f5c9f34cbe2fb1acee39f671",
"dirty": false
},
{
"path": "src/warden/case_receipt_state.py",
"base_head": "a45cf475bc4dbc929e0eecbc1f806a9229d934e2",
"base_sha256": "sha256:a2cda7f187e77bd76d4d209505638de44a587fae0bc033ec75c23ee9ea9f73bc",
"worktree_sha256": "sha256:a2cda7f187e77bd76d4d209505638de44a587fae0bc033ec75c23ee9ea9f73bc",
"dirty": false
},
{
"path": "src/warden/case_inputs.py",
"base_head": "a45cf475bc4dbc929e0eecbc1f806a9229d934e2",
"base_sha256": "sha256:1334b0cd9897e763cfea2d306e997c659f3f284ecc3f9612140c2104835da7c7",
"worktree_sha256": "sha256:1334b0cd9897e763cfea2d306e997c659f3f284ecc3f9612140c2104835da7c7",
"dirty": false
},
{
"path": "src/warden/__init__.py",
"base_head": "a45cf475bc4dbc929e0eecbc1f806a9229d934e2",
"base_sha256": "sha256:047e0feba479474235f0707a207655ecfddfb33cd4f54069134419b8ca4ea24a",
"worktree_sha256": "sha256:047e0feba479474235f0707a207655ecfddfb33cd4f54069134419b8ca4ea24a",
"dirty": false
},
{
"path": "tests/test_case_run.py",
"base_head": "a45cf475bc4dbc929e0eecbc1f806a9229d934e2",
"base_sha256": "sha256:bc7264848e76e3576821523fec0c4925c4446eaf470f859fe245c98ea072d139",
"worktree_sha256": "sha256:bc7264848e76e3576821523fec0c4925c4446eaf470f859fe245c98ea072d139",
"dirty": false
},
{
"path": "docs/security-case-execution-kernel-v1.md",
"base_head": "a45cf475bc4dbc929e0eecbc1f806a9229d934e2",
"base_sha256": "sha256:0eb563dbaea739fba928d04708c2c2bdac592783bbe68e1271041b0d1b1994cb",
"worktree_sha256": "sha256:0eb563dbaea739fba928d04708c2c2bdac592783bbe68e1271041b0d1b1994cb",
"dirty": false
},
{
"path": "workplans/WARDEN-WP-0044-security-case-follow-through.md",
"base_head": "a45cf475bc4dbc929e0eecbc1f806a9229d934e2",
"base_sha256": "sha256:44686df53dac792e46791878c3ccf8c187bb14e2de33eeac411be2005f7f2aa1",
"worktree_sha256": "sha256:44686df53dac792e46791878c3ccf8c187bb14e2de33eeac411be2005f7f2aa1",
"dirty": false
}
],
"canonical_edits_performed": false
},
"current_owner_head": "a45cf475bc4dbc929e0eecbc1f806a9229d934e2",
"current_owner_sources_match_snapshot": true,
"canonical_writes_or_user_tree_tests_performed": false,
"probes": {
"snapshot_diagnostic_probes": 13,
"scope": "Exact copied a45cf475 snapshot; probes passing for documented insecure behaviors mean finding reproduced, not secure/native acceptance.",
"minimal_delta_cases": 54,
"delta_case_scope": "43 existing kernel cases plus11 new metadata/context consistency checks; not additive to prior suites. Source-only generated data and existing synthetic owner trust.",
"lint": "Owner-installed Ruff check and format check pass after removing two unused test imports; no dependency installation.",
"extra_earlier_delta_cases": 56,
"extra_earlier_scope": "Retained diagnostic variant included tenant/realm and missing-original-purpose observations; excluded those from canonical regression proposal to avoid encoding missing native proof as a desired control."
},
"comparison": [
{
"topic": "Actual persistence and restart",
"concurrent": "OriginalIntent and running receipt share one SQLite transaction. Actual distinct interpreter retrieves original run identity after lost response. This solves the original local memory-loss/context seam.",
"fingerprint_candidate": "Atomic receipt-linked invocation fingerprint also survives actual distinct interpreter; avoids raw field storage but introduces a second table and a changed reconcile callback.",
"disposition": "Keep existing concurrent intents/reconcile_original surfaces; no duplicate context subsystem."
},
{
"topic": "Privacy and closed field contract",
"concurrent": "Normal Executor.admit produces bounded declared metadata strings plus empty tenant/realm, not arbitrary owner response payload. No observed real credential leak. OriginalIntent.payload/decode themselves accept arbitrary JSON-valued target and dynamically serialize all Invocation fields; a direct generated probe reproduces this missing public API invariant.",
"fingerprint_candidate": "Stores only a fixed validated projection fingerprint; safer raw-data retention but not necessary to replace the concurrent architecture unilaterally.",
"disposition": "Minimal delta validates exact Invocation/Pins and explicit field set/types/lengths/operations before payload/save and bounded duplicate-free decode. Keep raw identifiers only as the existing declared operational source contract; do not claim tenant/realm provenance from serialization."
},
{
"topic": "Actor consistency",
"concurrent": "original_intent compares principal/lane/tenant/realm but omits actor. A stored actor=agent is returned against current actor=human.",
"fingerprint_candidate": "Fixed exact invocation fingerprint covers actor.",
"disposition": "Add actor to existing equality comparison; no new permission or migration."
},
{
"topic": "Original attempt/intent lineage",
"concurrent": "Query reads only payload. Altered payload attempt_id can differ from intents.attempt_id and be returned; removing original running receipt leaves accepted orphan intent. Both reproduced in temporary SQLite fixtures.",
"fingerprint_candidate": "Intent sequence/fingerprint links its context to an original running receipt; no authority inference.",
"disposition": "Minimal delta checks SQL attempt_id equals payload and matches a bounded existing original running receipt with exact step/owner/pins/binding. Save validates intent, invocation and running state agree before atomic write."
},
{
"topic": "Principal, tenant, realm and current admission",
"concurrent": "Stored mismatched principal/tenant/realm is refused. However Executor.admit has no tenant/realm input or independent provenance; normal admitted values remain empty. Tests replacing the current Invocation fail at admission and do not prove authentic tenant claims.",
"fingerprint_candidate": "Introduces no new tenant/realm fields or migration. Exact current readmission/pins are retained.",
"disposition": "Keep tenant/realm explicitly unknown/reserved; do not add caller-settable claims or relax run-sheet matching. If future nonempty coordinates are needed, require existing authoritative claim/session owner contract and review."
},
{
"topic": "Independent original proof versus local correspondence",
"concurrent": "ReconcileContext reaches an owner callback, but Adapter.verify and evidence_verifier authenticate the fresh OwnerResult/current attempt and current revocations. No original-context-specific verifier purpose is emitted. Intent is not independent creation evidence and cannot itself establish created-only undo.",
"fingerprint_candidate": "Adds explicit original/fresh-context proof purpose; no actual native verifier/holder supplied.",
"disposition": "This is an unresolved native owner adapter/readback contract, not proof of a live bypass. Define exact independent original payload authentication in the admitted owner adapter/verification contract before native integration. Do not add an unadmitted second verifier/holder or treat callback context/JSON as assent. Minimal consistency delta intentionally adds no new native proof purpose."
},
{
"topic": "Legacy and API compatibility",
"concurrent": "Existing one-argument Adapter.reconcile remains usable; new reconcile_original opts into original-intent lookup and refuses missing records. Existing positional Adapter construction and Invocation defaults remain callable. v1 receipt JSON stays unchanged. Invocation.asdict now includes two extra default fields, so registration attempt payload/source consumers require explicit review before native admission.",
"fingerprint_candidate": "Changes reconcile callback signature to two arguments; existing injected one-argument callbacks fail closed.",
"disposition": "Retain additive callback compatibility. Missing legacy original intent is never backfilled for new original-aware path. No installed actual native adapters/verifier/CLI are found in inspected current sources."
},
{
"topic": "Parent sessions and unknown outcomes",
"concurrent": "Current caller/session checks and independent fresh parent-session/grant revocation remain enforced; withholding fresh parent revocation refuses. Original session proof is not retrieved/authenticated from intent; actual original holder must supply it. Lost reply and interrupted undo stay uncertainty gates.",
"fingerprint_candidate": "Same current checks plus explicit contextual proof purpose; no real original/session holder.",
"disposition": "Keep native gate closed until independently authenticated original result/revocation and current native UID/version checks exist. Changed session/run-sheet/caller pins cannot inherit source state automatically."
}
],
"minimal_delta": {
"path": "minimal-integration.patch",
"base_commit": "a45cf475bc4dbc929e0eecbc1f806a9229d934e2",
"changes": [
{
"path": "src/warden/case_run.py",
"before_sha256": "sha256:0574036ca7b74bdb9124f6af4888e63ec231ee60f5c9f34cbe2fb1acee39f671",
"after_sha256": "sha256:0cc62a33dbb3b90276b291f77fa5d0a906f19296874d68636957763f576d1ae2"
},
{
"path": "tests/test_case_original_context_consistency.py",
"before_sha256": null,
"after_sha256": "sha256:8483bb5915701e8bd0749e85097e11076ffd539084ca68e9ec1c565babc157d1"
}
],
"snapshot_patch_check": 0,
"scope": "Only original-intent validation and matching + new focused tests; keeps intents schema, Invocation fields and reconcile_original API. No owner adapter, credential, native source activation, original-proof grant, task UUID/status or production mutation.",
"apply_rule": "Root must recheck exact current hashes and coordinate implementation owner. This artifact is not an instruction to overwrite concurrent changes."
},
"actual_consumers_inspected": [
{
"path": "ops-warden/src/warden/case_run.py",
"finding": "No installed default adapters/verifier/CLI; interfaces are injected fixed owner source."
},
{
"path": "ops-warden/tests/test_case_run.py",
"finding": "Only inspected reconcile_original consumer is synthetic fixture by_original, which delegates to old.reconcile(ctx.attempt); it does not independently authenticate original custody."
},
{
"path": "net-kingdom/sso-mfa/k8s/keycape/keycape-registration-adapter.py",
"finding": "Maintained registration adapter builds existing six positional Adapter fields and has no reconcile callback. Process-local creation and post-restart undo refusal remain."
},
{
"path": "net-kingdom/tools/security-case-types/security_case_evidence.py",
"finding": "Reads unchanged v1 receipts only; native_authenticated remains false. It is no original context/owner authenticator."
}
],
"next_native_gate": "Unchanged NK48T15/T16/WARDEN44T03: actual independent original holder/readback, exact source/tenant/principal binding, original/current session proof and native revision/created-only custody remain absent. No gate closure or owner assent inferred.",
"older_candidate_disposition": "original-context-r1 remains retained for design/failure history only. Its replacement table/API patch must not be applied over a45cf475; minimal-integration.patch is the non-overwriting proposal on this actual variant.",
"failures_retained": "Initial minimal-delta lint found two unused test imports; removed. Snapshot diagnostic and changed-fixture probe results remain recorded separately."
}

View file

@ -0,0 +1,127 @@
# Closed case execution kernel v1 — 2026-10-11
Owner implementation record for WARDEN-WP-0044-T03. The architectural proposal
at SHA256 78ab1439e4c5beb205aeccf15b1b2e706511be55ab195c5a3aa682f326c7c77c
was accepted through memo `infd-20261010-security-case-execution`, version 1,
approval e46b149b-ec3c-4b3b-98a7-dcb4934448ca, confirmed disposition
disp-cf44dacb-2117-4de7-8f90-cfa99f84f325 at 2026-10-10T23:23:31Z. The original
approved proposal remains byte-identical. That decision accepts source design;
it grants no execution session, credential or deployment authority.
`src/warden/case_run.py` advances the pure reducer into an executable injected
owner harness with private durable receipts. Descriptor version
`warden.case.execution.v1` is a closed local implementation seam, not an accepted
NetKingdom type schema. It contains fixed owner/adapter/source digest, actor,
lane, target parameter, effect, reviewed created-object identifiers declared
retry safety and explicit required revocation scopes (parent-session and broker-grant).
A mint descriptor cannot omit either scope. Unknown fields, free shell text and secret parameters are refused.
An acknowledged type must additionally pin the descriptor bytes under its
`execution_descriptors` map and independent owner evidence must authenticate
that exact machine-seam revision. Existing descriptive types lack this map and
remain plan-only. Their acknowledged labels do not authorize this new seam.
There are no installed owner adapters, native provenance verifier or dispatch CLI
in this change. Callables are injected only through a fixed adapter registry,
with immutable owner reference/source pins. A real integration must supply
independent owner/native verification or explicit attended manual evidence;
a bare JSON receipt identifier is insufficient. Fixture verifiers in tests
are deliberately fake and attest no native case. Caller sessions are independently
verified for exact principal/actor/lane at admission and again before dispatch;
input actor labels alone are never sufficient. Agent mint is refused, including
when WARDEN_AGENT_ID appears after initial human admission.
Each admission pins exact case/type/descriptor/catalog bytes, acceptance reference
and run-sheet identity. Actual ops-mason materialization evidence is required
against the case source, separately from its status label. Case parameters supply
an exact metadata target. Source/session changes cannot inherit journal success.
Owner results have a closed metadata shape, result evidence fingerprint and
separate independently authenticated grant/parent-session revocation evidence
fingerprints. An aggregate revoked boolean alone cannot satisfy either scope. Unknown result payloads, unverified evidence, absent revocation and
created objects outside the reviewed scope become uncertain, never success.
Python and OS stdout/stderr, including inherited child-process output, are
discarded without buffering or retention under a serialized fd containment
context. Independent provenance verification uses the same containment and
sanitizes exceptions. All source inputs are capped at 256 KiB before parsing.
Error text is not copied to the journal. KeyboardInterrupt/SystemExit and other
owner interruptions are rethrown with a fixed message while retaining running
intent for crash recovery.
The journal uses an owner-private 0700 directory and 0600 files, refuses symlinks
and insecure modes, uses SQLite FULL synchronization and commits running intent
before calling the adapter. A separate process lock prevents concurrent mutation.
A crash between dispatch and final receipt leaves running; the next lock holder
persists uncertain before refusing replay. Both intent and outcome remain in
history. Each persisted attempt has a unique identity bound to all exact pins,
operation (run/reconcile/rollback), sequence and nonce. Adapter results and both
revocation proof purposes carry that identity. Prior-attempt evidence cannot
verify a safe retry, even if a caller rewrites result labels. Descriptor-created
objects are capped at 32 and histories at 128 transitions, with dispatch stopped
before archival is required. A throw or lost response is not failed-before-change. A safe retry needs
verified failed-before-change, unchanged pins, descriptor retry-safe and explicit
retry. Success and no-change cannot replay.
Reconciliation is an explicit fixed owner callback, never the mutation callback.
It may verify an already-present native CAS result as no-change/success, or prove
failed-before-change; it never tells Warden to regenerate a credential. Uncertain
or failed-after-change requires this owner-native inspection before any retry.
Owner proof and revocation remain mandatory. Rollback visits only objects in a
verified creation receipt, in reverse order; no-change has no undo and shared
objects are excluded. Unknown/lost undo blocks another rollback.
The kernel operates individual admitted steps. Full ordered run-sheet orchestration,
verification inventory, contained login integration, native owner adapters and
CLI activation remain WARDEN-WP-0044-T03; no overall native-complete result is
implemented. Current Forgejo source is not materialized and has no acknowledged
machine descriptors. Its first native run remains an acceptance requirement,
with real materialization, separately authenticated broker-grant and parent-session
revocation receipts, session/owner receipts and consumer enforcement. This
implementation neither promotes a type nor changes any case status.
Validation: 37 new kernel tests plus 14 reducer tests pass (51 total). Tests open
an independent SQLite connection inside dispatch to prove running was committed,
crash after mutation and reopen a fresh journal to prove no duplicate invocation,
lose a response then reconcile without mint, require explicit retry, check exact
pins/session expiry, withhold malicious output and unconfirmed revocation, and
prove created-only reverse undo plus uncertain-undo refusal. Ruff formatting and
checks pass. No live token or target action occurred.
## Browser input projection — 2026-10-16 source preparation
An explicitly configured `BrowserInputs(netkingdom_root)` now validates browser
cases before admission. It calls the real NetKingdom type/case validator over
verified producer bytes in a disposable Python process (`-I`, empty environment,
timeout, no inherited output). The validator, composer, capability contract and lazy evidence
modules have exact source pins; missing or changed code refuses. There is no
automatic discovery or download. A producer upgrade needs reviewed pin changes.
Only the exact reviewed 1.1/1.2 browser parameter definitions qualify. A digest
of each complete parameter definition list prevents reclassifying secrets as
metadata, loosening constraints, or adding fields under a recognized version.
The complete case passes producer validation, including required fields,
constraints and credential-shape checks. Explicit fixed/default overrides,
unknown fields and secret references refuse. Security-sensitive browser metadata
can therefore be present without being passed to an owner adapter: the only
projection is its descriptor's exact public/operational target identifier.
No raw parameter values are added to invocations or persisted receipts.
`require_implemented=False` validates the acknowledged type's source, not its
execution authority. Existing descriptor/type/source/catalog/caller provenance
gates stay mandatory. Neither historical browser type contains the required
exact machine-descriptor map, and neither is promoted by this change. There are
still no installed native owner adapters, authenticated provenance verifier,
contained session/ordered run orchestration or live CLI dispatch. A journal digest
is a fingerprint and cannot authenticate native evidence. Completion still needs
owner-admitted descriptors and actual structural, mint/delivery, consumer and
revocation/rollback evidence. Local fixture success is not native acceptance.
Tests use the actual producer checkout (override sibling location with
`WARDEN_TEST_NETKINGDOM_ROOT`), the real Executor, SQLite journal and injected
test-only owner adapter/evidence verifier. Their descriptor extensions and case
materialized labels exist only in memory. Canonical case/type bytes stay intact.
Producer integration refinement: the accepted NetKingdom browser-case patch
`d32a7f51cbf3012bee3e4bb329f4259dea867eff1c59a2b01a65d72774488d05`
is now the tested producer revision. Its evidence module is imported lazily only
by `check-evidence`, outside this admission path; Warden nevertheless pins and
copies it with the complete reviewed producer set. Missing or modified bytes in
any of the four modules refuse admission. The test covers every dependency.

View file

@ -0,0 +1,2 @@
[pytest]
pythonpath = src

View file

@ -0,0 +1,3 @@
"""OpsWarden — SSH CA and certificate lifecycle manager."""
__version__ = "0.1.0"

View file

@ -0,0 +1,98 @@
"""Reviewed browser metadata projection; no native trust or command dispatch.
The producer validator and all reviewed producer modules are pinned below.
Their verified bytes run in a disposable tree, without caller environment or
ambient Python imports. Type parameters must match the exact reviewed version.
Machine descriptor extensions still require Executor's independent admission.
"""
import hashlib
import json
from pathlib import Path
import subprocess
import sys
import tempfile
from .case_receipt_state import Refused
# Reviewed producer: net-kingdom 015694ee414c802dc2ef1fa0120dfed610086e69.
# Review: docs/reviews/2026-10-16-browser-producer-pin-refresh.md
SOURCE_PINS = {
"tools/security-case-types/security_case_evidence.py": "da8efa59c52ad73283397ebe639ae259d0cb9c6348b5cb829135c24230dcdc75",
"tools/security-case-types/security_case_validator.py": "1bcc62e9bc374c711363295549f3cd5bb0b32952671ed4b08fddc7f74742959b",
"tools/security-scenario-composer/security_scenario_composer.py": "9f0cc69930aa8ee2cc3fb92236e6a99728df17b8c0fe36e1250241c38fc01c4f",
"tools/playbook-capability-contract/playbook_contract_validator.py": "2e1e0c809d4bc9d64c2d974cc23fecd1c5636785154c2554edd9191852fd926d",
}
PARAMETER_PINS = {
"1.1": "9ec2d6113bf70dbd35cfc247412363ff187e792bc82e24159a6f78e090aa3e4c",
"1.2": "c04385d176f5f70257fb0fa6fef7e48ab26ed7cf26f6b1c7f14b16237b0ebea6",
}
_VALIDATE = """
import json, sys
from pathlib import Path
sys.path.insert(0, str(Path(sys.argv[1]) / 'tools/security-case-types'))
import security_case_validator as v
case, typ = json.load(sys.stdin)
issues = v.validate_type(typ) + v.validate_case(case, typ, require_implemented=False)
print('valid' if not v.has_errors(issues) else 'invalid')
"""
class BrowserInputs:
"""Explicit owner configuration, never inferred from a case-supplied path."""
def __init__(self, netkingdom_root: Path):
self.root = Path(netkingdom_root)
def target(self, case: dict, typ: dict, target_parameter: str) -> str:
try:
spec = typ["spec"]
parameters = spec["parameters"]
fingerprint = hashlib.sha256(
json.dumps(parameters, sort_keys=True, separators=(",", ":")).encode()
).hexdigest()
if (
spec["id"] != "oidc-browser-relying-party"
or PARAMETER_PINS.get(spec["version"]) != fingerprint
):
raise ValueError
declared = {item["name"]: item for item in parameters}
definition = declared.get(target_parameter, {})
if (
definition.get("sensitivity") not in ("public", "operational")
or definition.get("case_settable") is not True
):
raise ValueError
# No secret references or newly classified metadata are grandfathered.
for name in case["spec"]["parameters"]:
item = declared.get(name, {})
if item.get("case_settable") is not True or item.get(
"sensitivity"
) not in ("public", "operational", "security_sensitive"):
raise ValueError
with tempfile.TemporaryDirectory(
prefix="warden-case-validator-"
) as directory:
for relative, expected in SOURCE_PINS.items():
source = (self.root / relative).read_bytes()
if hashlib.sha256(source).hexdigest() != expected:
raise ValueError
dest = Path(directory) / relative
dest.parent.mkdir(parents=True, exist_ok=True)
dest.write_bytes(source)
result = subprocess.run(
[sys.executable, "-I", "-c", _VALIDATE, directory],
input=json.dumps([case, typ]),
text=True,
stdout=subprocess.PIPE,
stderr=subprocess.DEVNULL,
env={},
timeout=10,
check=True,
)
if result.stdout != "valid\n":
raise ValueError
return case["spec"]["parameters"][target_parameter]
except (OSError, ValueError, TypeError, KeyError, subprocess.SubprocessError):
raise Refused("browser metadata failed exact-version validation") from None

View file

@ -0,0 +1,146 @@
"""Proposed, pure case receipt reducer for WARDEN-WP-0044-T03.
This prototype executes nothing and implements no accepted owner adapter API.
Callers MUST durably persist a returned running receipt before a side effect.
Only metadata identifiers/digests enter this model; no command output is accepted.
"""
from __future__ import annotations
from dataclasses import dataclass, replace
from enum import Enum
import re
_ID = re.compile(r"[a-zA-Z0-9][a-zA-Z0-9_.:-]{0,127}\Z")
_DIGEST = re.compile(r"sha256:[0-9a-f]{64}\Z")
class Refused(ValueError):
"""A transition requires an independent owner reconciliation or new review."""
class Outcome(str, Enum):
RUNNING = "running"
SUCCESS = "verified-success"
NO_CHANGE = "verified-no-change"
FAILED_BEFORE = "failed-before-change"
FAILED_AFTER = "failed-after-change"
UNCERTAIN = "uncertain"
ROLLBACK_RUNNING = "rollback-running"
ROLLED_BACK = "verified-rolled-back"
ROLLBACK_UNCERTAIN = "rollback-uncertain"
@dataclass(frozen=True)
class Pins:
"""Exact reviewed case/type/adapter/catalog/acceptance/run-sheet digests."""
case: str
case_type: str
adapter: str
catalog: str
acceptance: str
run_sheet: str
def __post_init__(self) -> None:
if not all(_DIGEST.fullmatch(value) for value in vars(self).values()):
raise Refused("pins require sha256 digests")
@dataclass(frozen=True)
class Receipt:
attempt: int
outcome: Outcome
created: tuple[str, ...] = ()
@dataclass(frozen=True)
class StepState:
step_id: str
owner: str
pins: Pins
allowed_created: tuple[str, ...] = ()
retry_safe: bool = False
receipts: tuple[Receipt, ...] = ()
def __post_init__(self) -> None:
if not all(_ID.fullmatch(v) for v in (self.step_id, self.owner, *self.allowed_created)):
raise Refused("only metadata identifiers are supported")
if len(set(self.allowed_created)) != len(self.allowed_created):
raise Refused("duplicate reviewed object identifier")
@property
def last(self) -> Receipt | None:
return self.receipts[-1] if self.receipts else None
def _same_pins(state: StepState, pins: Pins) -> None:
if state.pins != pins:
raise Refused("pins changed; a newly reviewed sheet is required")
def _append(state: StepState, outcome: Outcome, created: tuple[str, ...] = ()) -> StepState:
receipt = Receipt(len(state.receipts) + 1, outcome, created)
return replace(state, receipts=(*state.receipts, receipt))
def begin(state: StepState, pins: Pins, *, retry: bool = False) -> StepState:
"""Return intent to dispatch. Persist before calling an owner adapter."""
_same_pins(state, pins)
last = state.last
if last is None:
if retry:
raise Refused("no failed attempt to retry")
elif not (last.outcome is Outcome.FAILED_BEFORE and state.retry_safe and retry):
raise Refused("step cannot dispatch or replay without owner reconciliation")
return _append(state, Outcome.RUNNING)
def finish(state: StepState, pins: Pins, outcome: Outcome,
*, created: tuple[str, ...] = ()) -> StepState:
"""Accept only an adapter's verified, closed metadata result, never output."""
_same_pins(state, pins)
if not state.last or state.last.outcome is not Outcome.RUNNING:
raise Refused("no running side effect")
if not isinstance(outcome, Outcome) or outcome not in (Outcome.SUCCESS, Outcome.NO_CHANGE, Outcome.FAILED_BEFORE,
Outcome.FAILED_AFTER, Outcome.UNCERTAIN):
raise Refused("unsupported adapter result")
if len(set(created)) != len(created) or not set(created) <= set(state.allowed_created):
raise Refused("created objects are outside the reviewed case")
if created and outcome not in (Outcome.SUCCESS, Outcome.FAILED_AFTER):
raise Refused("this result cannot claim created objects")
return _append(state, outcome, created)
def recover(state: StepState) -> StepState:
"""Lost result after persisted dispatch is uncertain, never safe to retry."""
if state.last and state.last.outcome is Outcome.RUNNING:
return _append(state, Outcome.UNCERTAIN)
if state.last and state.last.outcome is Outcome.ROLLBACK_RUNNING:
return _append(state, Outcome.ROLLBACK_UNCERTAIN, state.last.created)
return state
def rollback_objects(state: StepState, pins: Pins) -> tuple[str, ...]:
"""Reviewed identifiers only, reverse created order; no shared-object undo."""
_same_pins(state, pins)
last = state.last
if last is None or last.outcome is Outcome.NO_CHANGE:
return ()
if last.outcome is not Outcome.SUCCESS:
raise Refused("rollback needs a verified successful creation receipt")
return tuple(reversed(last.created))
def begin_rollback(state: StepState, pins: Pins) -> StepState:
objects = rollback_objects(state, pins)
if not objects:
raise Refused("no case-created objects to undo")
return _append(state, Outcome.ROLLBACK_RUNNING, objects)
def finish_rollback(state: StepState, pins: Pins, *, verified: bool) -> StepState:
_same_pins(state, pins)
if not state.last or state.last.outcome is not Outcome.ROLLBACK_RUNNING:
raise Refused("no running rollback")
outcome = Outcome.ROLLED_BACK if verified else Outcome.ROLLBACK_UNCERTAIN
return _append(state, outcome, state.last.created)

View file

@ -0,0 +1,981 @@
"""Closed local execution kernel v1; no installed adapters or live CLI dispatch.
An owner must acknowledge each descriptor and provide an independent provenance
verifier. Descriptive case types remain plan-only. Nothing executes shell prose.
"""
from __future__ import annotations
from contextlib import contextmanager, redirect_stderr, redirect_stdout
from dataclasses import asdict, dataclass, replace
import fcntl
import hashlib
import json
import os
from pathlib import Path
import re
import sqlite3
import threading
import uuid
from typing import Callable
import yaml
from .case_inputs import BrowserInputs
from .case_receipt_state import (
Outcome,
Pins,
Receipt,
Refused,
StepState,
begin,
finish,
recover,
begin_rollback,
finish_rollback,
)
IDENTIFIER = re.compile(r"[a-zA-Z0-9][a-zA-Z0-9_.:/@-]{0,191}\Z")
MAX_SOURCE_BYTES = 262144
MAX_HISTORY = 128
OUTPUT_LOCK = threading.RLock()
def bounded_source(value: bytes):
if type(value) is not bytes or len(value) > MAX_SOURCE_BYTES:
raise Refused("source exceeds bounded input contract")
@contextmanager
def contained_output():
"""Discard Python and inherited OS stdout/stderr; serialize process fd changes."""
with OUTPUT_LOCK:
saved = []
null = os.open(os.devnull, os.O_WRONLY)
try:
for target in (1, 2):
saved.append((target, os.dup(target)))
os.dup2(null, target)
with redirect_stdout(_Discard()), redirect_stderr(_Discard()):
try:
yield
except Exception:
raise Refused("owner callback failed") from None
except BaseException:
raise OwnerInterrupted() from None
finally:
for target, original in saved:
os.dup2(original, target)
os.close(original)
os.close(null)
DIGEST = re.compile(r"sha256:[0-9a-f]{64}\Z")
def digest(value: bytes) -> str:
return "sha256:" + hashlib.sha256(value).hexdigest()
@dataclass(frozen=True, slots=True)
class Descriptor:
version: str
step: str
owner: str
adapter: str
adapter_source: str
actor: str
lane: str
target_parameter: str
effect: str
allowed_created: tuple[str, ...]
retry_safe: bool
revocation_scopes: tuple[str, ...]
@classmethod
def decode(cls, source: bytes) -> Descriptor:
bounded_source(source)
try:
obj = json.loads(source)
if set(obj) != set(cls.__dataclass_fields__):
raise ValueError
if not isinstance(obj["allowed_created"], list):
raise ValueError
obj["allowed_created"] = tuple(obj["allowed_created"])
if not isinstance(obj["revocation_scopes"], list):
raise ValueError
obj["revocation_scopes"] = tuple(obj["revocation_scopes"])
result = cls(**obj)
identifiers = (
result.step,
result.owner,
result.adapter,
result.lane,
result.target_parameter,
*result.allowed_created,
)
if result.version != "warden.case.execution.v1" or not all(
isinstance(v, str) and IDENTIFIER.fullmatch(v) for v in identifiers
):
raise ValueError
if not DIGEST.fullmatch(result.adapter_source) or result.actor not in (
"human",
"agent",
):
raise ValueError
if (
result.effect not in ("read", "change", "mint")
or type(result.retry_safe) is not bool
):
raise ValueError
scopes = set(result.revocation_scopes)
if (
len(scopes) != len(result.revocation_scopes)
or not scopes <= {"parent-session", "broker-grant"}
or "parent-session" not in scopes
):
raise ValueError
if result.effect == "mint" and "broker-grant" not in scopes:
raise ValueError
if len(result.allowed_created) > 32:
raise ValueError
if len(set(result.allowed_created)) != len(result.allowed_created):
raise ValueError
return result
except (ValueError, TypeError, KeyError):
raise Refused("invalid closed execution descriptor") from None
@dataclass(frozen=True, slots=True)
class OwnerResult:
outcome: Outcome
evidence: str
created: tuple[str, ...] = ()
revoked: bool = False
session_revocation_evidence: str | None = None
grant_revocation_evidence: str | None = None
attempt_id: str = ""
operation: str = ""
@dataclass(frozen=True, slots=True)
class Invocation:
step: str
owner: str
target: str
actor: str
principal: str
lane: str
pins: Pins
attempt_id: str = ""
operation: str = "admission"
tenant: str = ""
realm: str = ""
INTENT_SCHEMA = "warden.case.original-intent.v1"
@dataclass(frozen=True, slots=True)
class OriginalIntent:
"""Durable record of the original mutating dispatch, written before dispatch.
Binds the original Invocation (attempt, step, owner, target, actor, principal,
lane), all pins, the admitted adapter source and the tenant/realm provenance
the caller was admitted with. It is evidence of what Warden dispatched, not
owner proof of creation: owners still authenticate created-only provenance.
"""
binding: str
invocation: Invocation
source: str
def validate(self) -> None:
"""Fixed bounded metadata only; tenant/realm are not authority claims.
Current admit leaves tenant/realm empty. Nonempty future coordinates need
separate owner provenance; serializability alone must never supply it.
"""
if (
type(self.invocation) is not Invocation
or type(self.invocation.pins) is not Pins
):
raise Refused("exact original invocation required")
i = self.invocation
fields = (i.step, i.owner, i.target, i.principal, i.lane, i.attempt_id)
if (
not all(
type(value) is str and IDENTIFIER.fullmatch(value) for value in fields
)
or type(i.actor) is not str
or i.actor not in ("human", "agent")
or type(i.operation) is not str
or i.operation not in ("run", "rollback")
or not all(
type(value) is str and (not value or IDENTIFIER.fullmatch(value))
for value in (i.tenant, i.realm)
)
or type(self.source) is not str
or not DIGEST.fullmatch(self.source)
or type(self.binding) is not str
or self.binding != f"{i.step}:{i.target}"
):
raise Refused("invalid original intent metadata")
if set(Invocation.__dataclass_fields__) != {
"step",
"owner",
"target",
"actor",
"principal",
"lane",
"pins",
"attempt_id",
"operation",
"tenant",
"realm",
}:
raise Refused("original invocation field contract changed")
if not all(
type(v) is str and DIGEST.fullmatch(v)
for v in (
i.pins.case,
i.pins.case_type,
i.pins.adapter,
i.pins.catalog,
i.pins.acceptance,
i.pins.run_sheet,
)
):
raise Refused("invalid original intent pins")
def payload(self) -> str:
self.validate()
return json.dumps(
{"schema": INTENT_SCHEMA, "binding": self.binding, "source": self.source}
| asdict(self.invocation),
separators=(",", ":"),
sort_keys=True,
)
@classmethod
def decode(cls, raw: str) -> OriginalIntent:
def unique(pairs):
result = {}
for key, value in pairs:
if key in result:
raise Refused("duplicate original intent field")
result[key] = value
return result
try:
if type(raw) is not str or len(raw.encode()) > MAX_SOURCE_BYTES:
raise Refused("original intent input exceeds bound")
obj = json.loads(raw, object_pairs_hook=unique)
fields = {
"step",
"owner",
"target",
"actor",
"principal",
"lane",
"pins",
"attempt_id",
"operation",
"tenant",
"realm",
}
if (
type(obj) is not dict
or set(obj) != fields | {"schema", "binding", "source"}
or obj["schema"] != INTENT_SCHEMA
):
raise Refused("unknown original intent schema")
inv = {k: obj[k] for k in fields}
inv["pins"] = Pins(**inv["pins"])
result = cls(obj["binding"], Invocation(**inv), obj["source"])
result.validate()
return result
except (TypeError, ValueError, KeyError):
raise Refused("invalid original intent record") from None
@dataclass(frozen=True, slots=True)
class ReconcileContext:
"""Original intent and the new reconciliation attempt, kept separate."""
original: OriginalIntent
attempt: Invocation
@dataclass(frozen=True, slots=True)
class Adapter:
reference: str
source: str
invoke: Callable[[Invocation], OwnerResult]
verify: Callable[[Invocation, OwnerResult], bool]
rollback: Callable[[Invocation, tuple[str, ...]], OwnerResult] | None = None
reconcile: Callable[[Invocation], OwnerResult] | None = None
reconcile_original: Callable[[ReconcileContext], OwnerResult] | None = None
class Journal:
"""Private SQLite journal plus process lock; transaction commits before dispatch."""
def __init__(self, directory: Path):
directory.mkdir(mode=0o700, parents=True, exist_ok=True)
if (
directory.is_symlink()
or directory.stat().st_uid != os.getuid()
or directory.stat().st_mode & 0o077
):
raise Refused("journal directory is not private")
self.directory = directory
for name in ("journal.sqlite", "execution.lock"):
path = directory / name
fd = os.open(path, os.O_CREAT | os.O_RDWR | os.O_NOFOLLOW, 0o600)
try:
if os.fstat(fd).st_uid != os.getuid() or os.fstat(fd).st_mode & 0o077:
raise Refused("journal file is not private")
finally:
os.close(fd)
self.db = sqlite3.connect(directory / "journal.sqlite", isolation_level=None)
self.db.execute("PRAGMA synchronous=FULL")
self.db.execute(
"CREATE TABLE IF NOT EXISTS receipts (seq INTEGER PRIMARY KEY, binding TEXT NOT NULL, payload TEXT NOT NULL)"
)
self.db.execute(
"CREATE TABLE IF NOT EXISTS intents (seq INTEGER PRIMARY KEY, attempt_id TEXT NOT NULL UNIQUE, binding TEXT NOT NULL, payload TEXT NOT NULL)"
)
def original_intent(
self, binding: str, current: Invocation, source: str
) -> OriginalIntent:
"""Latest original run intent for binding, refused unless it matches exactly.
Missing or mismatched records refuse; the step stays uncertain.
"""
row = self.db.execute(
"SELECT attempt_id,payload FROM intents WHERE binding=? ORDER BY seq DESC LIMIT 1",
(binding,),
).fetchone()
if row is None:
raise Refused("original intent record missing; step stays uncertain")
intent = OriginalIntent.decode(row[1])
o = intent.invocation
if row[0] != o.attempt_id:
raise Refused("original intent attempt identity differs")
if intent.binding != binding or o.operation != "run":
raise Refused("original intent binding mismatch")
if o.pins != current.pins:
raise Refused("original intent pins mismatch")
if intent.source != source:
raise Refused("original intent source mismatch")
for name in (
"step",
"owner",
"target",
"actor",
"principal",
"lane",
"tenant",
"realm",
):
if getattr(o, name) != getattr(current, name):
raise Refused(f"original intent {name} mismatch")
# Match the persisted original running receipt. An orphan context or a
# payload from another attempt cannot become the current lookup key.
receipts = self.db.execute(
"SELECT payload FROM receipts WHERE binding=? ORDER BY seq DESC LIMIT ?",
(binding, MAX_HISTORY + 1),
).fetchall()
if len(receipts) > MAX_HISTORY:
raise Refused("original intent receipt history exceeds bound")
matched = False
try:
for (raw,) in receipts:
if type(raw) is not str or len(raw.encode()) > MAX_SOURCE_BYTES:
raise Refused("original receipt input exceeds bound")
payload = json.loads(raw)
if (
payload.get("attempt_id") != o.attempt_id
or payload.get("operation") != "run"
):
continue
last = payload.get("receipts", [])[-1]
if last.get("outcome") != "running":
continue
if (
payload.get("journal_schema") != "warden.case.step-journal.v1"
or payload.get("step_id") != o.step
or payload.get("owner") != o.owner
or payload.get("pins") != asdict(o.pins)
):
raise Refused("original running receipt binding differs")
matched = True
break
except (TypeError, ValueError, KeyError, IndexError, AttributeError):
raise Refused("invalid original running receipt") from None
if not matched:
raise Refused("original running receipt missing; no backfill")
return intent
@contextmanager
def locked(self):
with (self.directory / "execution.lock").open("rb") as fh:
try:
fcntl.flock(fh, fcntl.LOCK_EX | fcntl.LOCK_NB)
except BlockingIOError:
raise Refused("case execution already active") from None
try:
yield
finally:
fcntl.flock(fh, fcntl.LOCK_UN)
def load(self, binding: str, initial: StepState) -> StepState:
row = self.db.execute(
"SELECT payload FROM receipts WHERE binding=? ORDER BY seq DESC LIMIT 1",
(binding,),
).fetchone()
if row is None:
return initial
obj = json.loads(row[0])
expected = {
"step_id",
"owner",
"pins",
"allowed_created",
"retry_safe",
"receipts",
"journal_schema",
"evidence_digest",
"session_revoked",
"session_revocation_digest",
"grant_revocation_digest",
"attempt_id",
"operation",
}
if (
set(obj) != expected
or obj["journal_schema"] != "warden.case.step-journal.v1"
):
raise Refused("unknown journal receipt schema")
state = StepState(
obj["step_id"],
obj["owner"],
Pins(**obj["pins"]),
tuple(obj["allowed_created"]),
obj["retry_safe"],
tuple(
Receipt(r["attempt"], Outcome(r["outcome"]), tuple(r["created"]))
for r in obj["receipts"]
),
)
if (
state.step_id,
state.owner,
state.pins,
state.allowed_created,
state.retry_safe,
) != (
initial.step_id,
initial.owner,
initial.pins,
initial.allowed_created,
initial.retry_safe,
):
raise Refused("journal pins changed")
return state
def save(
self,
binding: str,
state: StepState,
evidence: OwnerResult | None = None,
invocation: Invocation | None = None,
intent: OriginalIntent | None = None,
):
if intent is not None:
if type(intent) is not OriginalIntent:
raise Refused("exact original intent required")
intent.validate()
expected = (
Outcome.RUNNING
if intent.invocation.operation == "run"
else Outcome.ROLLBACK_RUNNING
)
if (
intent.binding != binding
or intent.invocation != invocation
or intent.invocation.pins != state.pins
or not state.last
or state.last.outcome is not expected
):
raise Refused("original intent and running receipt differ")
self.db.execute("BEGIN IMMEDIATE")
try:
if intent is not None:
self.db.execute(
"INSERT INTO intents(attempt_id,binding,payload) VALUES (?,?,?)",
(intent.invocation.attempt_id, binding, intent.payload()),
)
self.db.execute(
"INSERT INTO receipts(binding,payload) VALUES (?,?)",
(
binding,
json.dumps(
asdict(state)
| {
"journal_schema": "warden.case.step-journal.v1",
"attempt_id": invocation.attempt_id if invocation else None,
"operation": invocation.operation if invocation else None,
"evidence_digest": digest(evidence.evidence.encode())
if evidence
else None,
"session_revoked": evidence.revoked if evidence else None,
"session_revocation_digest": digest(
evidence.session_revocation_evidence.encode()
)
if evidence and evidence.session_revocation_evidence
else None,
"grant_revocation_digest": digest(
evidence.grant_revocation_evidence.encode()
)
if evidence and evidence.grant_revocation_evidence
else None,
},
separators=(",", ":"),
),
),
)
self.db.execute("COMMIT")
except BaseException:
self.db.execute("ROLLBACK")
raise
class Executor:
"""Injected fixed owner adapters and provenance verifier; none ship by default.
evidence verifier must authenticate owner custody/provenance or explicitly
attest attended manual evidence; a bare JSON reference is never sufficient.
It receives purpose, exact source digest, and named evidence reference.
"""
def __init__(
self,
journal: Journal,
adapters: dict[str, Adapter],
evidence_verifier: Callable[[str, str, str], bool],
*,
browser_inputs: BrowserInputs | None = None,
):
self.journal, self.adapters, self.evidence_verifier = (
journal,
dict(adapters),
evidence_verifier,
)
self._admitted = {}
self.browser_inputs = browser_inputs
def admit(
self,
case_source: bytes,
type_source: bytes,
descriptor_source: bytes,
catalog_source: bytes,
*,
principal: str,
actor: str,
lane: str,
acceptance_evidence: str,
materialization_evidence: str,
descriptor_evidence: str,
session_evidence: str,
) -> tuple[Descriptor, Invocation, StepState]:
for source in (case_source, type_source, descriptor_source, catalog_source):
bounded_source(source)
descriptor = Descriptor.decode(descriptor_source)
try:
case = yaml.safe_load(case_source)["spec"]
case_type = yaml.safe_load(type_source)["spec"]
if not isinstance(case, dict) or not isinstance(case_type, dict):
raise ValueError
except (yaml.YAMLError, KeyError, TypeError, ValueError):
raise Refused("invalid case or type source shape") from None
if case.get("status") != "materialized" or not case.get("acceptance"):
raise Refused("case is not accepted and structurally materialized")
if case_type.get("status") not in ("acknowledged", "implemented"):
raise Refused("type is not acknowledged")
if case.get("type") != f"{case_type['id']}@{case_type['version']}":
raise Refused("case type pin mismatch")
if case_type.get("execution_descriptors", {}).get(descriptor.step) != digest(
descriptor_source
):
raise Refused(
"type has no exact acknowledged machine descriptor; plan only"
)
for purpose, source, evidence in (
("case-acceptance", digest(case_source), acceptance_evidence),
(
"ops-mason-materialization",
digest(case_source),
materialization_evidence,
),
(
"owner-descriptor-acceptance:" + descriptor.owner,
digest(descriptor_source),
descriptor_evidence,
),
("type-machine-seam-acceptance", digest(type_source), descriptor_evidence),
("catalog-routing-acceptance", digest(catalog_source), descriptor_evidence),
(
f"caller-session:{actor}:{principal}:{lane}",
digest(case_source),
session_evidence,
),
):
if (
not isinstance(evidence, str)
or not IDENTIFIER.fullmatch(evidence)
or self._verify_evidence(purpose, source, evidence) is not True
):
raise Refused("independent owner evidence not verified")
if (
not IDENTIFIER.fullmatch(principal)
or actor != descriptor.actor
or lane != descriptor.lane
):
raise Refused("principal actor or lane mismatch")
if descriptor.effect == "mint" and (
actor != "human" or os.getenv("WARDEN_AGENT_ID")
):
raise Refused("agent mint is forbidden")
parameters = case.get("parameters", {})
declared = {
item["name"]: item
for item in case_type.get("parameters", [])
if isinstance(item, dict) and isinstance(item.get("name"), str)
}
if (
not isinstance(parameters, dict)
or descriptor.target_parameter not in declared
):
raise Refused("target parameter is not declared by acknowledged type")
if case_type.get("id") == "oidc-browser-relying-party":
if type(self.browser_inputs) is not BrowserInputs:
raise Refused("browser metadata validator is not configured")
target = self.browser_inputs.target(
yaml.safe_load(case_source),
yaml.safe_load(type_source),
descriptor.target_parameter,
)
else:
for name in parameters:
definition = declared.get(name)
if (
definition is None
or definition.get("sensitivity") not in ("public", "operational")
or definition.get("case_settable") is False
):
raise Refused("unknown, fixed or secret-sensitivity case parameter")
target = parameters.get(descriptor.target_parameter)
if not isinstance(target, str) or not IDENTIFIER.fullmatch(target):
raise Refused("target must be exact case metadata")
adapter = self.adapters.get(descriptor.adapter)
if adapter is None or (adapter.reference, adapter.source) != (
descriptor.adapter,
descriptor.adapter_source,
):
raise Refused("unknown adapter or owner source pin")
sheet = json.dumps(
[
descriptor.step,
descriptor.owner,
target,
actor,
principal,
lane,
acceptance_evidence,
materialization_evidence,
descriptor_evidence,
session_evidence,
],
separators=(",", ":"),
).encode()
pins = Pins(
digest(case_source),
digest(type_source),
digest(descriptor_source),
digest(catalog_source),
digest(acceptance_evidence.encode()),
digest(sheet),
)
invocation = Invocation(
descriptor.step, descriptor.owner, target, actor, principal, lane, pins
)
initial = StepState(
descriptor.step,
descriptor.owner,
pins,
descriptor.allowed_created,
descriptor.retry_safe,
)
self._admitted[invocation] = (descriptor, initial, session_evidence)
return descriptor, invocation, initial
def _result(
self, adapter: Adapter, invocation: Invocation, result: OwnerResult
) -> OwnerResult:
if type(result) is not OwnerResult or not isinstance(result.outcome, Outcome):
raise Refused("unknown owner result shape")
if type(result.created) is not tuple or not all(
isinstance(v, str) and IDENTIFIER.fullmatch(v) for v in result.created
):
raise Refused("owner created-object result invalid")
if not isinstance(result.evidence, str) or not IDENTIFIER.fullmatch(
result.evidence
):
raise Refused("owner evidence identifier invalid")
if adapter.verify(invocation, result) is not True or result.revoked is not True:
raise Refused("owner result or session revocation unverified")
if (result.attempt_id, result.operation) != (
invocation.attempt_id,
invocation.operation,
):
raise Refused("owner receipt belongs to another attempt")
descriptor = self._admitted[
replace(invocation, attempt_id="", operation="admission")
][0]
proof_fields = {
"parent-session": (
f"session-revocation:{invocation.lane}:{invocation.operation}:{invocation.attempt_id}",
result.session_revocation_evidence,
),
"broker-grant": (
f"grant-revocation:{invocation.lane}:{invocation.operation}:{invocation.attempt_id}",
result.grant_revocation_evidence,
),
}
proofs = [proof_fields[scope] for scope in descriptor.revocation_scopes]
for purpose, evidence in proofs:
if (
not isinstance(evidence, str)
or not IDENTIFIER.fullmatch(evidence)
or self._verify_evidence(purpose, invocation.pins.case, evidence)
is not True
):
raise Refused("independent grant or parent-session revocation absent")
return result
def _verify_evidence(self, purpose, source, evidence):
try:
with contained_output():
return self.evidence_verifier(purpose, source, evidence) is True
except Exception:
raise Refused("independent evidence verification failed") from None
def _admission(
self, descriptor: Descriptor, invocation: Invocation, initial: StepState
):
if self._admitted.get(invocation, ())[:2] != (descriptor, initial):
raise Refused("execution requires verified admission on this executor")
adapter = self.adapters.get(descriptor.adapter)
if adapter is None or (adapter.reference, adapter.source) != (
descriptor.adapter,
descriptor.adapter_source,
):
raise Refused("adapter changed after admission")
session = self._admitted[invocation][2]
if (
self._verify_evidence(
f"caller-session:{invocation.actor}:{invocation.principal}:{invocation.lane}",
invocation.pins.case,
session,
)
is not True
):
raise Refused("caller session no longer verified")
if descriptor.effect == "mint" and os.getenv("WARDEN_AGENT_ID"):
raise Refused("agent mint is forbidden")
return adapter
def _attempt(self, invocation: Invocation, state: StepState, operation: str):
identity = json.dumps(
[asdict(invocation.pins), operation, state.last.attempt, uuid.uuid4().hex],
separators=(",", ":"),
).encode()
return replace(
invocation,
attempt_id="attempt-" + hashlib.sha256(identity).hexdigest(),
operation=operation,
)
def run(
self,
descriptor: Descriptor,
invocation: Invocation,
initial: StepState,
*,
retry=False,
) -> StepState:
adapter = self._admission(descriptor, invocation, initial)
with self.journal.locked():
binding = f"{invocation.step}:{invocation.target}"
state = self.journal.load(binding, initial)
recovered = recover(state)
if recovered != state:
self.journal.save(binding, recovered)
state = recovered
if len(state.receipts) > MAX_HISTORY - 4:
raise Refused("bounded journal history requires owner archival")
running = begin(state, invocation.pins, retry=retry)
dispatched = self._attempt(invocation, running, "run")
self.journal.save(
binding,
running,
invocation=dispatched,
intent=OriginalIntent(binding, dispatched, adapter.source),
)
evidence = None
try:
with contained_output():
result = self._result(
adapter, dispatched, adapter.invoke(dispatched)
)
completed = finish(
running, invocation.pins, result.outcome, created=result.created
)
evidence = result
except Exception:
completed = finish(running, invocation.pins, Outcome.UNCERTAIN)
self.journal.save(binding, completed, evidence, dispatched)
return completed
def rollback(
self, descriptor: Descriptor, invocation: Invocation, initial: StepState
) -> StepState:
adapter = self._admission(descriptor, invocation, initial)
with self.journal.locked():
binding = f"{invocation.step}:{invocation.target}"
state = self.journal.load(binding, initial)
if recover(state) != state:
self.journal.save(binding, recover(state))
raise Refused("lost rollback result requires owner reconciliation")
if adapter.rollback is None:
raise Refused("owner has no reviewed undo adapter")
if len(state.receipts) > MAX_HISTORY - 4:
raise Refused("bounded journal history requires owner archival")
running = begin_rollback(state, invocation.pins)
dispatched = self._attempt(invocation, running, "rollback")
self.journal.save(
binding,
running,
invocation=dispatched,
intent=OriginalIntent(binding, dispatched, adapter.source),
)
evidence = None
try:
with contained_output():
result = self._result(
adapter,
dispatched,
adapter.rollback(dispatched, running.last.created),
)
verified = result.outcome is Outcome.ROLLED_BACK and not result.created
evidence = result if verified else None
except Exception:
verified = False
completed = finish_rollback(running, invocation.pins, verified=verified)
self.journal.save(binding, completed, evidence, dispatched)
return completed
def reconcile(
self, descriptor: Descriptor, invocation: Invocation, initial: StepState
) -> StepState:
"""Explicit owner-native state inspection; never redispatches the mutation."""
adapter = self._admission(descriptor, invocation, initial)
if adapter.reconcile is None and adapter.reconcile_original is None:
raise Refused("owner reconciliation adapter absent")
with self.journal.locked():
binding = f"{invocation.step}:{invocation.target}"
state = recover(self.journal.load(binding, initial))
if not state.last or state.last.outcome not in (
Outcome.UNCERTAIN,
Outcome.FAILED_AFTER,
):
raise Refused("no uncertain mutation to reconcile")
if len(state.receipts) > MAX_HISTORY - 4:
raise Refused("bounded journal history requires owner archival")
state = replace(
state,
receipts=(
*state.receipts,
Receipt(len(state.receipts) + 1, Outcome.UNCERTAIN),
),
)
original = (
self.journal.original_intent(binding, invocation, adapter.source)
if adapter.reconcile_original is not None
else None
)
dispatched = self._attempt(invocation, state, "reconcile")
self.journal.save(binding, state, invocation=dispatched)
with contained_output():
result = self._result(
adapter,
dispatched,
adapter.reconcile_original(ReconcileContext(original, dispatched))
if original is not None
else adapter.reconcile(dispatched),
)
if result.outcome not in (
Outcome.NO_CHANGE,
Outcome.SUCCESS,
Outcome.FAILED_BEFORE,
):
raise Refused("owner did not reconcile target state")
# Validate created-object scope using the same closed result reducer.
finish(
begin(
StepState(
state.step_id,
state.owner,
state.pins,
state.allowed_created,
state.retry_safe,
),
state.pins,
),
state.pins,
result.outcome,
created=result.created,
)
reconciled = StepState(
state.step_id,
state.owner,
state.pins,
state.allowed_created,
state.retry_safe,
(
*state.receipts,
Receipt(len(state.receipts) + 1, result.outcome, result.created),
),
)
self.journal.save(binding, reconciled, result, dispatched)
return reconciled
class OwnerInterrupted(KeyboardInterrupt):
"""Sanitized interruption preserves persisted running/crash recovery semantics."""
def __init__(self):
super().__init__("owner execution interrupted")
class _Discard:
"""Never retain or forward adapter output, including unbounded malicious text."""
def write(self, text):
return len(text)
def flush(self):
pass

View file

@ -0,0 +1,198 @@
"""Original-intent consistency checks with generated metadata only.
Reuse the existing synthetic owner rig. These checks do not provide a native
holder or independently authenticate original creation from local SQL/JSON.
"""
from dataclasses import asdict, replace
import json
from pathlib import Path
import sqlite3
import subprocess
import sys
import pytest
from test_case_run import rig as rig
from warden.case_receipt_state import Outcome, Refused
from warden.case_run import OriginalIntent
def interrupted(rig):
executor, args, calls, sources, kwargs = rig
old = executor.adapters[args[0].adapter]
seen = []
def lost(inv):
calls.append(inv)
raise TimeoutError("generated lost response")
def original(ctx):
seen.append(ctx)
return old.reconcile(ctx.attempt)
executor.adapters[old.reference] = replace(
old, invoke=lost, reconcile=None, reconcile_original=original
)
assert executor.run(*args).last.outcome is Outcome.UNCERTAIN
return executor, args, calls, old, seen
def alter_payload(executor, **changes):
row = executor.journal.db.execute(
"SELECT seq,payload FROM intents ORDER BY seq DESC LIMIT 1"
).fetchone()
obj = json.loads(row[1])
obj.update(changes)
executor.journal.db.execute(
"UPDATE intents SET payload=? WHERE seq=?", (json.dumps(obj), row[0])
)
def test_original_actor_mismatch_is_refused(rig):
executor, args, calls, old, _ = interrupted(rig)
alter_payload(executor, actor="agent")
with pytest.raises(Refused):
executor.journal.original_intent(
"mint-secret:fixture-client", args[1], old.source
)
def test_payload_attempt_id_must_match_sql_column_and_original_receipt(rig):
executor, args, calls, old, _ = interrupted(rig)
actual = calls[0].attempt_id
alter_payload(executor, attempt_id="attempt-unrelated")
with pytest.raises(Refused):
executor.journal.original_intent(
"mint-secret:fixture-client", args[1], old.source
)
assert (
executor.journal.db.execute("SELECT attempt_id FROM intents").fetchone()[0]
== actual
)
def test_orphan_intent_without_original_running_receipt_is_refused(rig):
executor, args, calls, old, _ = interrupted(rig)
executor.journal.db.execute(
"DELETE FROM receipts WHERE seq=(SELECT MIN(seq) FROM receipts)"
)
assert (
executor.journal.load("mint-secret:fixture-client", args[2]).last.outcome
is Outcome.UNCERTAIN
)
with pytest.raises(Refused):
executor.journal.original_intent(
"mint-secret:fixture-client", args[1], old.source
)
def test_serializer_refuses_arbitrary_values_outside_normal_admit(rig):
_, args, _, _, _ = rig
inv = replace(
args[1],
target={"unexpected": "synthetic-owner-payload"},
operation="run",
attempt_id="attempt-fixture",
)
record = OriginalIntent("mint-secret:fixture-client", inv, "sha256:" + "1" * 64)
with pytest.raises(Refused):
OriginalIntent.decode(record.payload())
# This is a direct serialization API gap, not an observed normal-admit leak.
# Owner trust is the existing synthetic fixture; this proves call shape only.
@pytest.mark.parametrize(
"field,value",
[
("principal", "another-person"),
("tenant", "another-tenant"),
("realm", "another-realm"),
],
)
def test_existing_lookup_does_refuse_stored_principal_tenant_realm_mismatch(
rig, field, value
):
executor, args, _, old, _ = interrupted(rig)
alter_payload(executor, **{field: value})
with pytest.raises(Refused):
executor.journal.original_intent(
"mint-secret:fixture-client", args[1], old.source
)
def test_existing_atomic_insert_failure_prevents_dispatch_and_both_records(rig):
executor, args, calls, _, _ = rig
executor.journal.db.execute(
"CREATE TRIGGER fail_receipt BEFORE INSERT ON receipts BEGIN SELECT RAISE(ABORT,'fixture'); END"
)
with pytest.raises(sqlite3.IntegrityError):
executor.run(*args)
assert not calls
assert executor.journal.db.execute("SELECT COUNT(*) FROM intents").fetchone() == (
0,
)
assert executor.journal.db.execute("SELECT COUNT(*) FROM receipts").fetchone() == (
0,
)
def test_existing_missing_original_refuses_before_callback(rig):
executor, args, _, _, seen = interrupted(rig)
executor.journal.db.execute("DELETE FROM intents")
with pytest.raises(Refused):
executor.reconcile(*args)
assert not seen
assert (
executor.journal.load("mint-secret:fixture-client", args[2]).last.outcome
is Outcome.UNCERTAIN
)
def test_existing_current_parent_revocation_remains_mandatory(rig):
executor, args, _, _, _ = interrupted(rig)
old = executor.evidence_verifier
def refuse_session(purpose, source, evidence):
return (
False
if purpose.startswith("session-revocation:")
else old(purpose, source, evidence)
)
executor.evidence_verifier = refuse_session
with pytest.raises(Refused):
executor.reconcile(*args)
assert (
executor.journal.load("mint-secret:fixture-client", args[2]).last.outcome
is Outcome.UNCERTAIN
)
def test_existing_intent_survives_actual_distinct_interpreter(rig):
executor, args, calls, old, _ = interrupted(rig)
code = """import json,sys
from pathlib import Path
from warden.case_run import Journal,Invocation
from warden.case_receipt_state import Pins
obj=json.load(sys.stdin);obj['pins']=Pins(**obj['pins']);j=Journal(Path(sys.argv[1]))
with j.locked():
i=j.original_intent('mint-secret:fixture-client',Invocation(**obj),sys.argv[2])
print(json.dumps({'attempt':i.invocation.attempt_id,'operation':i.invocation.operation}))
"""
result = subprocess.run(
[sys.executable, "-B", "-c", code, str(executor.journal.directory), old.source],
input=json.dumps(asdict(args[1])),
text=True,
capture_output=True,
timeout=15,
env={
"PATH": "/usr/bin:/bin",
"PYTHONPATH": str(Path(__file__).parents[1] / "src"),
"PYTHONDONTWRITEBYTECODE": "1",
},
check=True,
)
assert json.loads(result.stdout) == {
"attempt": calls[0].attempt_id,
"operation": "run",
}

View file

@ -0,0 +1,700 @@
"""Injected owner harness; these receipts are not native owner attestations."""
from dataclasses import asdict, replace
import json
import os
import subprocess
import sys
import sqlite3
import pytest
import yaml
from warden.case_receipt_state import Outcome, Refused
from warden.case_run import Adapter, Descriptor, Executor, Journal, OwnerResult, digest
@pytest.fixture
def rig(tmp_path):
desc = Descriptor(
"warden.case.execution.v1",
"mint-secret",
"owner",
"owner/mint@v1",
"sha256:" + "1" * 64,
"human",
"issuer-lane",
"client_id",
"mint",
("case-policy", "case-role"),
True,
("parent-session", "broker-grant"),
)
descriptor = json.dumps(asdict(desc)).encode()
typ = yaml.safe_dump(
{
"spec": {
"id": "test",
"version": "1",
"status": "acknowledged",
"parameters": [
{
"name": "client_id",
"sensitivity": "operational",
"case_settable": True,
}
],
"execution_descriptors": {"mint-secret": digest(descriptor)},
}
}
).encode()
case = yaml.safe_dump(
{
"spec": {
"id": "case-test",
"type": "test@1",
"status": "materialized",
"acceptance": "acceptance",
"parameters": {"client_id": "fixture-client"},
}
}
).encode()
calls = []
def invoke(inv):
calls.append(inv)
return bound(
inv,
OwnerResult(
Outcome.SUCCESS,
"owner-receipt",
("case-policy", "case-role"),
True,
session_revocation_evidence="session-revoked",
grant_revocation_evidence="grant-revoked",
),
)
adapter = Adapter(
"owner/mint@v1",
desc.adapter_source,
invoke,
lambda inv, result: result.evidence == "owner-receipt",
lambda inv, objects: bound(
inv,
OwnerResult(
Outcome.ROLLED_BACK,
"owner-receipt",
(),
True,
session_revocation_evidence="session-revoked",
grant_revocation_evidence="grant-revoked",
),
),
lambda inv: bound(
inv,
OwnerResult(
Outcome.NO_CHANGE,
"owner-receipt",
(),
True,
session_revocation_evidence="session-revoked",
grant_revocation_evidence="grant-revoked",
),
),
)
verified = {
("case-acceptance", digest(case), "acceptance"),
("ops-mason-materialization", digest(case), "materialization"),
("owner-descriptor-acceptance:owner", digest(descriptor), "descriptor"),
("type-machine-seam-acceptance", digest(typ), "descriptor"),
("catalog-routing-acceptance", digest(b"catalog"), "descriptor"),
("caller-session:human:operator:issuer-lane", digest(case), "session"),
("session-revocation:issuer-lane", digest(case), "session-revoked"),
("grant-revocation:issuer-lane", digest(case), "grant-revoked"),
}
def verifier(purpose, source, evidence):
if purpose.startswith(("session-revocation:", "grant-revocation:")):
scope, lane, operation, attempt = purpose.split(":")
return (
source == digest(case)
and lane == "issuer-lane"
and operation in ("run", "rollback", "reconcile")
and evidence
== ("session-" if scope == "session-revocation" else "grant-") + attempt
)
return (purpose, source, evidence) in verified
executor = Executor(
Journal(tmp_path / "private"), {"owner/mint@v1": adapter}, verifier
)
kwargs = dict(
principal="operator",
actor="human",
lane="issuer-lane",
acceptance_evidence="acceptance",
materialization_evidence="materialization",
descriptor_evidence="descriptor",
session_evidence="session",
)
admitted = executor.admit(case, typ, descriptor, b"catalog", **kwargs)
return (executor, admitted, calls, (case, typ, descriptor, b"catalog"), kwargs)
def test_commit_running_is_visible_from_separate_connection_before_dispatch(rig):
executor, args, calls, _, _ = rig
old = executor.adapters[args[0].adapter]
def inspect(inv):
other = sqlite3.connect(executor.journal.directory / "journal.sqlite")
payload = json.loads(
other.execute(
"SELECT payload FROM receipts ORDER BY seq DESC LIMIT 1"
).fetchone()[0]
)
assert payload["receipts"][-1]["outcome"] == "running"
return old.invoke(inv)
executor.adapters[old.reference] = replace(old, invoke=inspect)
assert executor.run(*args).last.outcome is Outcome.SUCCESS
with pytest.raises(Refused):
executor.run(*args)
assert len(calls) == 1
def test_crash_and_fresh_process_resume_never_duplicates_effect(rig):
executor, args, calls, sources, kwargs = rig
old = executor.adapters[args[0].adapter]
def crash(inv):
calls.append(inv)
raise KeyboardInterrupt
executor.adapters[old.reference] = replace(old, invoke=crash)
with pytest.raises(KeyboardInterrupt):
executor.run(*args)
fresh = Executor(
Journal(executor.journal.directory),
{old.reference: old},
executor.evidence_verifier,
)
admitted = fresh.admit(*sources, **kwargs)
with pytest.raises(Refused):
fresh.run(*admitted, retry=True)
state = fresh.journal.load("mint-secret:fixture-client", admitted[2])
assert state.last.outcome is Outcome.UNCERTAIN
assert len(calls) == 1
def test_lost_result_preserved_and_cas_reconciliation_does_not_mint(rig):
executor, args, calls, _, _ = rig
old = executor.adapters[args[0].adapter]
def lost(inv):
calls.append(inv)
raise TimeoutError("SECRET-HIDDEN")
executor.adapters[old.reference] = replace(old, invoke=lost)
assert executor.run(*args).last.outcome is Outcome.UNCERTAIN
assert executor.reconcile(*args).last.outcome is Outcome.NO_CHANGE
with pytest.raises(Refused):
executor.run(*args, retry=True)
assert len(calls) == 1
assert (
b"SECRET-HIDDEN"
not in (executor.journal.directory / "journal.sqlite").read_bytes()
)
def test_failed_before_change_requires_explicit_retry_and_safe_owner(rig):
executor, args, calls, _, _ = rig
old = executor.adapters[args[0].adapter]
def no_change(inv):
calls.append(inv)
return bound(
inv,
OwnerResult(
Outcome.FAILED_BEFORE,
"owner-receipt",
(),
True,
session_revocation_evidence="session-revoked",
grant_revocation_evidence="grant-revoked",
),
)
executor.adapters[old.reference] = replace(old, invoke=no_change)
assert executor.run(*args).last.outcome is Outcome.FAILED_BEFORE
with pytest.raises(Refused):
executor.run(*args)
assert executor.run(*args, retry=True).last.outcome is Outcome.FAILED_BEFORE
assert len(calls) == 2
@pytest.mark.parametrize(
"result",
[
OwnerResult(
Outcome.SUCCESS,
"owner-receipt",
("shared-policy",),
True,
session_revocation_evidence="session-revoked",
grant_revocation_evidence="grant-revoked",
),
OwnerResult(
Outcome.SUCCESS,
"owner-receipt",
(),
False,
session_revocation_evidence="session-revoked",
grant_revocation_evidence="grant-revoked",
),
OwnerResult(
Outcome.SUCCESS,
"unknown-receipt",
(),
True,
session_revocation_evidence="session-revoked",
grant_revocation_evidence="grant-revoked",
),
{"outcome": "verified-success", "stdout": "SECRET-HIDDEN"},
],
)
def test_unknown_secret_payload_created_scope_or_missing_revocation_never_succeeds(
rig, result, capsys
):
executor, args, _, _, _ = rig
old = executor.adapters[args[0].adapter]
def malicious(inv):
print("SECRET-HIDDEN" * 1000)
return result
executor.adapters[old.reference] = replace(old, invoke=malicious)
assert executor.run(*args).last.outcome is Outcome.UNCERTAIN
assert capsys.readouterr().out == ""
assert (
b"SECRET-HIDDEN"
not in (executor.journal.directory / "journal.sqlite").read_bytes()
)
def test_rollback_reverses_only_verified_case_created_objects(rig):
executor, args, _, _, _ = rig
old = executor.adapters[args[0].adapter]
undos = []
def undo(inv, objects):
undos.append(objects)
return old.rollback(inv, objects)
executor.adapters[old.reference] = replace(old, rollback=undo)
executor.run(*args)
assert executor.rollback(*args).last.outcome is Outcome.ROLLED_BACK
assert undos == [("case-role", "case-policy")]
assert "shared-policy" not in undos[0]
def test_uncertain_rollback_cannot_replay(rig):
executor, args, _, _, _ = rig
old = executor.adapters[args[0].adapter]
executor.run(*args)
executor.adapters[old.reference] = replace(
old,
rollback=lambda inv, objs: bound(
inv,
OwnerResult(
Outcome.ROLLED_BACK,
"owner-receipt",
(),
False,
session_revocation_evidence="session-revoked",
grant_revocation_evidence="grant-revoked",
),
),
)
assert executor.rollback(*args).last.outcome is Outcome.ROLLBACK_UNCERTAIN
with pytest.raises(Refused):
executor.rollback(*args)
@pytest.mark.parametrize(
"change", ["materialization", "type-prose", "actor", "lane", "source", "target"]
)
def test_exact_admission_requires_owner_evidence_and_closed_source_pins(rig, change):
executor, _, _, sources, kwargs = rig
case, typ, descriptor, catalog = sources
kwargs = dict(kwargs)
if change == "materialization":
kwargs["materialization_evidence"] = "bare-json"
if change == "type-prose":
obj = yaml.safe_load(typ)
obj["spec"].pop("execution_descriptors")
typ = yaml.safe_dump(obj).encode()
if change == "actor":
kwargs["actor"] = "agent"
if change == "lane":
kwargs["lane"] = "other-lane"
if change == "source":
obj = json.loads(descriptor)
obj["adapter_source"] = "sha256:" + "2" * 64
descriptor = json.dumps(obj).encode()
if change == "target":
obj = yaml.safe_load(case)
obj["spec"]["parameters"]["client_id"] = "other-target"
case = yaml.safe_dump(obj).encode()
with pytest.raises(Refused):
executor.admit(case, typ, descriptor, catalog, **kwargs)
def test_agent_env_cannot_dispatch_after_human_admission(rig, monkeypatch):
executor, args, calls, _, _ = rig
monkeypatch.setenv("WARDEN_AGENT_ID", "test-agent")
with pytest.raises(Refused):
executor.run(*args)
assert calls == []
def test_forged_invocation_cannot_bypass_admission(rig):
executor, args, calls, _, _ = rig
with pytest.raises(Refused):
executor.run(args[0], replace(args[1], target="other-target"), args[2])
assert calls == []
def test_journal_rejects_unsafe_directory_and_symlink(tmp_path):
unsafe = tmp_path / "unsafe"
unsafe.mkdir(mode=493)
with pytest.raises(Refused):
Journal(unsafe)
private = tmp_path / "private"
private.mkdir(mode=448)
(private / "journal.sqlite").symlink_to(tmp_path / "outside")
with pytest.raises(OSError):
Journal(private)
def test_process_lock_blocks_parallel_dispatch(rig):
executor, args, calls, _, _ = rig
with executor.journal.locked():
with pytest.raises(Refused):
executor.run(*args)
assert calls == []
def test_changed_catalog_pins_cannot_inherit_old_success(rig):
executor, args, calls, sources, kwargs = rig
executor.run(*args)
with pytest.raises(Refused):
executor.admit(*sources[:3], b"changed-catalog", **kwargs)
assert len(calls) == 1
def test_private_journal_does_not_retain_owner_payload_or_accept_unknown_schema(rig):
executor, args, _, _, _ = rig
executor.run(*args)
row = executor.journal.db.execute(
"SELECT seq,payload FROM receipts ORDER BY seq DESC LIMIT 1"
).fetchone()
payload = json.loads(row[1])
assert payload["journal_schema"] == "warden.case.step-journal.v1"
assert payload["evidence_digest"] == digest(b"owner-receipt")
assert payload["session_revoked"] is True
assert "owner-receipt" not in row[1]
payload["stdout"] = "UNTRUSTED-OUTPUT"
executor.journal.db.execute(
"UPDATE receipts SET payload=? WHERE seq=?", (json.dumps(payload), row[0])
)
with pytest.raises(Refused):
executor.run(*args)
def test_expired_caller_session_cannot_use_cached_admission(rig):
executor, args, calls, _, _ = rig
old = executor.evidence_verifier
executor.evidence_verifier = lambda purpose, source, evidence: (
False
if purpose.startswith("caller-session:")
else old(purpose, source, evidence)
)
with pytest.raises(Refused):
executor.run(*args)
assert calls == []
@pytest.mark.parametrize("index", [0, 1, 2, 3])
def test_source_sizes_are_bounded_before_parsing(rig, index):
executor, _, _, sources, kwargs = rig
oversized = list(sources)
oversized[index] = b"x" * 262145
with pytest.raises(Refused, match="bounded"):
executor.admit(*oversized, **kwargs)
def test_owner_fd_and_inherited_subprocess_output_is_contained(rig, capfd):
executor, args, _, _, _ = rig
old = executor.adapters[args[0].adapter]
def leaking(inv):
os.write(1, b"SYNTHETIC-SECRET")
os.write(2, b"SYNTHETIC-SECRET")
subprocess.run([sys.executable, "-c", 'print("SYNTHETIC-SECRET")'], check=True)
return old.invoke(inv)
executor.adapters[old.reference] = replace(old, invoke=leaking)
assert executor.run(*args).last.outcome is Outcome.SUCCESS
observed = capfd.readouterr()
assert "SYNTHETIC-SECRET" not in observed.out + observed.err
def test_evidence_provider_output_and_error_never_escape(rig, capfd):
executor, _, calls, sources, kwargs = rig
def broken(*args):
print("SYNTHETIC-SECRET")
os.write(2, b"SYNTHETIC-SECRET")
raise RuntimeError("SYNTHETIC-SECRET")
executor.evidence_verifier = broken
with pytest.raises(Refused) as caught:
executor.admit(*sources, **kwargs)
assert "SYNTHETIC-SECRET" not in str(caught.value)
observed = capfd.readouterr()
assert "SYNTHETIC-SECRET" not in observed.out + observed.err
assert calls == []
@pytest.mark.parametrize("missing", ["session", "grant"])
def test_broker_grant_and_parent_session_have_separate_required_evidence(rig, missing):
executor, args, _, _, _ = rig
old = executor.adapters[args[0].adapter]
result = old.invoke(args[1])
if missing == "session":
result = replace(result, session_revocation_evidence=None)
else:
result = replace(result, grant_revocation_evidence=None)
executor.adapters[old.reference] = replace(old, invoke=lambda inv: result)
assert executor.run(*args).last.outcome is Outcome.UNCERTAIN
def test_mint_descriptor_cannot_omit_broker_grant_scope(rig):
descriptor = json.loads(rig[3][2])
descriptor["revocation_scopes"] = ["parent-session"]
with pytest.raises(Refused):
Descriptor.decode(json.dumps(descriptor).encode())
def test_unsafe_owner_step_cannot_retry_even_after_verified_failed_before(
rig, tmp_path
):
executor, args, _, sources, kwargs = rig
descriptor = replace(args[0], retry_safe=False)
descriptor_source = json.dumps(asdict(descriptor)).encode()
type_doc = yaml.safe_load(sources[1])
type_doc["spec"]["execution_descriptors"][descriptor.step] = digest(
descriptor_source
)
type_source = yaml.safe_dump(type_doc).encode()
old_verifier = executor.evidence_verifier
def verifier(purpose, source, evidence):
if purpose == "owner-descriptor-acceptance:owner":
return source == digest(descriptor_source) and evidence == "descriptor"
if purpose == "type-machine-seam-acceptance":
return source == digest(type_source) and evidence == "descriptor"
return old_verifier(purpose, source, evidence)
adapter = executor.adapters[descriptor.adapter]
def failed(inv):
return bound(
inv,
OwnerResult(
Outcome.FAILED_BEFORE,
"owner-receipt",
(),
True,
"session-revoked",
"grant-revoked",
),
)
fresh = Executor(
Journal(tmp_path / "unsafe-retry"),
{adapter.reference: replace(adapter, invoke=failed)},
verifier,
)
admitted = fresh.admit(
sources[0], type_source, descriptor_source, sources[3], **kwargs
)
assert fresh.run(*admitted).last.outcome is Outcome.FAILED_BEFORE
with pytest.raises(Refused):
fresh.run(*admitted, retry=True)
def bound(inv, result):
return replace(
result,
attempt_id=inv.attempt_id,
operation=inv.operation,
session_revocation_evidence=("session-" + inv.attempt_id)
if result.session_revocation_evidence
else None,
grant_revocation_evidence=("grant-" + inv.attempt_id)
if result.grant_revocation_evidence
else None,
)
def test_old_grant_and_session_proofs_cannot_verify_a_new_retry(rig):
executor, args, _, _, _ = rig
adapter = executor.adapters[args[0].adapter]
retained = []
def attempts(inv):
if not retained:
result = bound(
inv,
OwnerResult(
Outcome.FAILED_BEFORE,
"owner-receipt",
(),
True,
"session-revoked",
"grant-revoked",
),
)
retained.append(result)
return result
# Even a caller rewriting labels cannot authenticate prior revocation
# evidence for the newly persisted attempt identity.
return replace(retained[0], attempt_id=inv.attempt_id, operation=inv.operation)
executor.adapters[adapter.reference] = replace(adapter, invoke=attempts)
assert executor.run(*args).last.outcome is Outcome.FAILED_BEFORE
assert executor.run(*args, retry=True).last.outcome is Outcome.UNCERTAIN
def test_owner_interrupt_payload_is_sanitized_with_running_intent_retained(rig, capfd):
executor, args, _, _, _ = rig
adapter = executor.adapters[args[0].adapter]
def interrupted(inv):
os.write(2, b"SYNTHETIC-SECRET")
raise KeyboardInterrupt("SYNTHETIC-SECRET")
executor.adapters[adapter.reference] = replace(adapter, invoke=interrupted)
with pytest.raises(KeyboardInterrupt) as caught:
executor.run(*args)
assert "SYNTHETIC-SECRET" not in str(caught.value)
assert "SYNTHETIC-SECRET" not in "".join(capfd.readouterr())
assert (
executor.journal.load("mint-secret:fixture-client", args[2]).last.outcome
is Outcome.RUNNING
)
def test_attempt_identity_changes_with_exact_catalog_revision_and_new_journal(
rig, tmp_path
):
executor, args, calls, sources, kwargs = rig
executor.run(*args)
original_attempt = calls[-1].attempt_id
new_catalog = b"independently-reviewed-catalog-v2"
old_verifier = executor.evidence_verifier
def verifier(purpose, source, evidence):
if purpose == "catalog-routing-acceptance":
return source == digest(new_catalog) and evidence == "descriptor"
return old_verifier(purpose, source, evidence)
fresh = Executor(Journal(tmp_path / "new-revision"), executor.adapters, verifier)
revised = fresh.admit(*sources[:3], new_catalog, **kwargs)
assert fresh.run(*revised).last.outcome is Outcome.SUCCESS
assert calls[-1].attempt_id != original_attempt
assert calls[-1].pins.catalog != calls[0].pins.catalog
def test_secret_sensitivity_parameter_cannot_reach_admission_or_journal(rig):
executor, _, _, sources, kwargs = rig
type_doc = yaml.safe_load(sources[1])
type_doc["spec"]["parameters"][0]["sensitivity"] = "secret"
source = yaml.safe_dump(type_doc).encode()
old = executor.evidence_verifier
executor.evidence_verifier = lambda purpose, digest_value, evidence: (
True
if purpose == "type-machine-seam-acceptance"
else old(purpose, digest_value, evidence)
)
with pytest.raises(Refused, match="secret-sensitivity"):
executor.admit(sources[0], source, sources[2], sources[3], **kwargs)
def _lose_result(executor, args, calls):
old = executor.adapters[args[0].adapter]
def lost(inv):
calls.append(inv)
raise TimeoutError("lost")
seen = []
def by_original(ctx):
seen.append(ctx)
return old.reconcile(ctx.attempt)
executor.adapters[old.reference] = replace(
old, invoke=lost, reconcile=None, reconcile_original=by_original
)
assert executor.run(*args).last.outcome is Outcome.UNCERTAIN
return seen
def test_original_intent_survives_restart_separate_from_reconcile_attempt(rig):
executor, args, calls, _, _ = rig
seen = _lose_result(executor, args, calls)
executor.journal = Journal(executor.journal.directory) # restart: fresh handle
assert executor.reconcile(*args).last.outcome is Outcome.NO_CHANGE
(ctx,) = seen
original = ctx.original.invocation
assert original.attempt_id == calls[0].attempt_id
assert original.operation == "run" and ctx.attempt.operation == "reconcile"
assert ctx.attempt.attempt_id != original.attempt_id
assert original.pins == args[1].pins
assert (original.principal, original.tenant, original.realm) == (
args[1].principal,
args[1].tenant,
args[1].realm,
)
assert ctx.original.source == executor.adapters[args[0].adapter].source
def test_missing_original_intent_refuses_and_stays_uncertain(rig):
executor, args, calls, _, _ = rig
seen = _lose_result(executor, args, calls)
executor.journal.db.execute("DELETE FROM intents")
with pytest.raises(Refused, match="original intent record missing"):
executor.reconcile(*args)
assert seen == []
binding = f"{args[1].step}:{args[1].target}"
assert executor.journal.load(binding, args[2]).last.outcome is Outcome.UNCERTAIN
@pytest.mark.parametrize(
"change", [{"tenant": "other-tenant"}, {"realm": "other-realm"}, {"lane": "x"}]
)
def test_original_intent_mismatch_refuses(rig, change):
executor, args, calls, _, _ = rig
seen = _lose_result(executor, args, calls)
with pytest.raises(Refused):
executor.reconcile(args[0], replace(args[1], **change), args[2])
assert seen == []
def test_original_intent_source_mismatch_refuses(rig):
executor, args, calls, _, _ = rig
_lose_result(executor, args, calls)
binding = f"{args[1].step}:{args[1].target}"
with pytest.raises(Refused, match="source mismatch"):
executor.journal.original_intent(binding, calls[0], "other-source")

View file

@ -0,0 +1,131 @@
"""Observed source behavior of exact concurrent snapshot, not secure acceptance.
Counterexamples use generated metadata and the owner's existing synthetic rig.
Passing a counterexample means the documented gap reproduced; it is not a native
holder, an owner attestation or permission to trust local SQL/JSON.
"""
from dataclasses import asdict, replace
import inspect
import json
from pathlib import Path
import sqlite3
import subprocess
import sys
import pytest
from test_case_run import rig as rig
from warden.case_receipt_state import Outcome, Refused
from warden.case_run import Executor, Journal, OriginalIntent
def interrupted(rig):
executor,args,calls,sources,kwargs=rig
old=executor.adapters[args[0].adapter];seen=[]
def lost(inv):calls.append(inv);raise TimeoutError('generated lost response')
def original(ctx):seen.append(ctx);return old.reconcile(ctx.attempt)
executor.adapters[old.reference]=replace(old,invoke=lost,reconcile=None,reconcile_original=original)
assert executor.run(*args).last.outcome is Outcome.UNCERTAIN
return executor,args,calls,old,seen
def alter_payload(executor,**changes):
row=executor.journal.db.execute('SELECT seq,payload FROM intents ORDER BY seq DESC LIMIT 1').fetchone()
obj=json.loads(row[1]);obj.update(changes)
executor.journal.db.execute('UPDATE intents SET payload=? WHERE seq=?',(json.dumps(obj),row[0]))
def test_observed_original_actor_mismatch_is_accepted_by_lookup(rig):
executor,args,calls,old,_=interrupted(rig)
alter_payload(executor,actor='agent')
with pytest.raises(Refused):
executor.journal.original_intent('mint-secret:fixture-client',args[1],old.source)
def test_observed_payload_attempt_id_is_not_checked_against_sql_column_or_receipt(rig):
executor,args,calls,old,_=interrupted(rig)
actual=calls[0].attempt_id;alter_payload(executor,attempt_id='attempt-unrelated')
with pytest.raises(Refused):
executor.journal.original_intent('mint-secret:fixture-client',args[1],old.source)
assert executor.journal.db.execute('SELECT attempt_id FROM intents').fetchone()[0]==actual
def test_observed_orphan_intent_without_original_running_receipt_is_accepted(rig):
executor,args,calls,old,_=interrupted(rig)
executor.journal.db.execute('DELETE FROM receipts WHERE seq=(SELECT MIN(seq) FROM receipts)')
assert executor.journal.load('mint-secret:fixture-client',args[2]).last.outcome is Outcome.UNCERTAIN
with pytest.raises(Refused):
executor.journal.original_intent('mint-secret:fixture-client',args[1],old.source)
def test_observed_serializer_accepts_arbitrary_values_outside_normal_admit(rig):
_,args,_,_,_=rig
inv=replace(args[1],target={'unexpected':'synthetic-owner-payload'},operation='run',attempt_id='attempt-fixture')
record=OriginalIntent('mint-secret:fixture-client',inv,'sha256:'+'1'*64)
with pytest.raises(Refused):
OriginalIntent.decode(record.payload())
# This is a direct serialization API gap, not an observed normal-admit leak.
def test_observed_tenant_realm_not_admitted_and_remain_empty(rig):
_,args,_,_,_=rig
params=inspect.signature(Executor.admit).parameters
assert 'tenant' not in params and 'realm' not in params
assert args[1].tenant==args[1].realm==''
def test_observed_no_original_context_purpose_is_requested(rig):
executor,args,_,_,seen=interrupted(rig);old=executor.evidence_verifier;purposes=[]
def trace(purpose,source,evidence):purposes.append(purpose);return old(purpose,source,evidence)
executor.evidence_verifier=trace
assert executor.reconcile(*args).last.outcome is Outcome.NO_CHANGE
assert seen and any(p.startswith('session-revocation:') for p in purposes)
assert not any('original' in p for p in purposes)
# Owner trust is the existing synthetic fixture; this proves call shape only.
@pytest.mark.parametrize('field,value',[('principal','another-person'),('tenant','another-tenant'),('realm','another-realm')])
def test_existing_lookup_does_refuse_stored_principal_tenant_realm_mismatch(rig,field,value):
executor,args,_,old,_=interrupted(rig);alter_payload(executor,**{field:value})
with pytest.raises(Refused):executor.journal.original_intent('mint-secret:fixture-client',args[1],old.source)
def test_existing_atomic_insert_failure_prevents_dispatch_and_both_records(rig):
executor,args,calls,_,_=rig
executor.journal.db.execute("CREATE TRIGGER fail_receipt BEFORE INSERT ON receipts BEGIN SELECT RAISE(ABORT,'fixture'); END")
with pytest.raises(sqlite3.IntegrityError):executor.run(*args)
assert not calls
assert executor.journal.db.execute('SELECT COUNT(*) FROM intents').fetchone()==(0,)
assert executor.journal.db.execute('SELECT COUNT(*) FROM receipts').fetchone()==(0,)
def test_existing_missing_original_refuses_before_callback(rig):
executor,args,_,_,seen=interrupted(rig)
executor.journal.db.execute('DELETE FROM intents')
with pytest.raises(Refused):executor.reconcile(*args)
assert not seen
assert executor.journal.load('mint-secret:fixture-client',args[2]).last.outcome is Outcome.UNCERTAIN
def test_existing_current_parent_revocation_remains_mandatory(rig):
executor,args,_,_,_=interrupted(rig);old=executor.evidence_verifier
def refuse_session(purpose,source,evidence):
return False if purpose.startswith('session-revocation:') else old(purpose,source,evidence)
executor.evidence_verifier=refuse_session
with pytest.raises(Refused):executor.reconcile(*args)
assert executor.journal.load('mint-secret:fixture-client',args[2]).last.outcome is Outcome.UNCERTAIN
def test_existing_intent_survives_actual_distinct_interpreter(rig):
executor,args,calls,old,_=interrupted(rig)
code='''import json,sys
from pathlib import Path
from warden.case_run import Journal,Invocation
from warden.case_receipt_state import Pins
obj=json.load(sys.stdin);obj['pins']=Pins(**obj['pins']);j=Journal(Path(sys.argv[1]))
with j.locked():
i=j.original_intent('mint-secret:fixture-client',Invocation(**obj),sys.argv[2])
print(json.dumps({'attempt':i.invocation.attempt_id,'operation':i.invocation.operation}))
'''
result=subprocess.run([sys.executable,'-B','-c',code,str(executor.journal.directory),old.source],
input=json.dumps(asdict(args[1])),text=True,capture_output=True,timeout=15,
env={'PATH':'/usr/bin:/bin','PYTHONPATH':str(Path(__file__).parents[1]/'src'),'PYTHONDONTWRITEBYTECODE':'1'},check=True)
assert json.loads(result.stdout)=={'attempt':calls[0].attempt_id,'operation':'run'}

View file

@ -0,0 +1,289 @@
---
id: WARDEN-WP-0044
type: workplan
title: "Follow through on KnownSecurityCases along their type's route"
domain: infotech
repo: ops-warden
status: active
flavor: implementation
owner: claude-code
topic_slug: netkingdom
created: "2026-10-08"
updated: "2026-10-11"
depends_on: []
related_repos:
- net-kingdom
- ops-mason
- key-cape
- railiance-platform
state_hub_workstream_id: "f7e81013-6868-5d99-8528-ba75a442eca9"
---
# WARDEN-WP-0044 — Follow through on KnownSecurityCases along their type's route
## Why
NetKingdom is introducing SecurityCaseTypes (net-kingdom `NK-WP-0048`, canon
`security-case-types_v0.1`, proposed). Once a case of an implemented type is
accepted and ops-mason has materialized its structure (`MASON-WP-0010`),
ops-warden carries out the remaining steps. These are the owners' declared entry
points, run on the authentication path the type defines, followed by the type's
verification.
Today ops-warden routes needs and, for `exec_capable` lanes, proxies fetches as
the caller. It does not yet know about cases, and each new integration ends with
a founder running a hand-written script (for example the proposed KEY-WP-0038-T02
rollout). This plan gives ops-warden the follow-through role, without widening
what it may do: each step still runs under its owner's entry point and the
caller's identity.
## Tasks
```task
id: WARDEN-WP-0044-T01
status: done
depends_on: [NK-WP-0048-T03]
priority: high
state_hub_task_id: "ef0920fc-418e-52cb-acff-9a5c0c728bf5"
```
### T01 — Define the type's follow-through section
Propose the `follow_through` part of the SecurityCaseType schema together with
net-kingdom. For each step it names the owner entry point, `warden_executes`,
the auth method and lane, whether an attended human login is unavoidable (with
the type's justification), and the verification command. Write it for the first
type, `oidc-browser-relying-party`, covering key-cape client registration,
custody minting and LLDAP group membership.
2026-10-08: NK-WP-0048-T03/T04 landed with a drafted section. Review is in
`history/2026-10-08-oidc-rp-follow-through-review.md`. It requires three
changes before T02: a per-step `lane`, a narrow `warden_executes`, and
`value_handling`. It also lists four refinements. This task is done when
net-kingdom acknowledges the review (NK-WP-0048-T05).
2026-10-09: R4 was withdrawn in favour of ops-mason's per-case
`{consuming_service}-keycape-client`, with the entry body templated in the type
(R4′, see the addendum in the review).
2026-10-09: the revised 1.0 type and canon now carry R1–R3, R4′, R5–R7.
`warden case check-type <type.yaml>` (`src/warden/case_type.py`, tests in
`tests/test_case_type.py`) checks a type's follow-through mechanically: the
live type is schema-conformant, with one attended session
(`key-cape-oidc-login`). It is not yet plannable, because two lanes are not
in the catalog: `identity-provisioner-groups` (net-kingdom) and
`keycape-client-secret-generate` (railiance-platform). These gate T02, not
T01. T01 still closes on net-kingdom's acknowledgement (NK-WP-0048-T05).
2026-10-09: ops-warden cannot add `identity-provisioner-groups` as the type
declares it. The provisioner accepts only user-engine's runtime token and
admits only user-engine pods, so no caller-identity path exists. R8 (review
addendum) asks net-kingdom either to move `ensure-groups` into the existing
attended session (recommended) or to give the provisioner an operator
credential. `keycape-client-secret-generate` needs a generate-in-custody entry
point from railiance-platform, and the broker does not have one yet. Both were
sent to their owners.
2026-10-09: done. net-kingdom took R8 option 1, so `ensure-groups` runs attended
in the `register-client` session and `identity-provisioner-groups` is dropped
(net-kingdom `0e86f95`). The founder acknowledged the type with memo r4 (hub
decision `e418263e`, NK-WP-0048-T05 done).
```task
id: WARDEN-WP-0044-T02
status: done
depends_on: [WARDEN-WP-0044-T01]
priority: high
state_hub_task_id: "5f68c991-f490-58f8-a121-92f74073d272"
```
### T02 — Plan a case run
`warden case plan <case.yaml>` checks that the case is accepted and materialized,
resolves each step to its catalog entry and entry point, and prints the run:
which steps warden executes, which run as the attended caller, what the
verification is. No secret values; no execution.
Tests: refuse an unaccepted or unmaterialized case; refuse a step whose catalog
entry is missing or not reviewed; show attended steps explicitly.
2026-10-09: done. `warden case plan <case.yaml> [--type] [--json]`
(`src/warden/case_plan.py`, 14 tests in `tests/test_case_plan.py`). It refuses:
- a case that is not `materialized`, or has no acceptance record
- a type that is mismatched or not acknowledged
- any `case check-type` finding, including a missing or unreviewed lane
- undeclared, type-fixed or secret-sensitivity parameters
- a placeholder the case does not set, or an unsupported `when`
It fills type defaults (`issuer`), evaluates `<param> == <value>` conditions,
renders owner, entry point, auth and ready_check, groups attended steps per
lane, and lists the applicable verification.
The live Forgejo case is correctly refused: it is `accepted`, not
materialized. A materialized copy, with a stand-in lane for
`keycape-client-secret-generate`, renders six steps: two attended steps plus
`register-client` in one `key-cape-oidc-login` session, one warden step
(`mint-secret`), and two owner steps. Seven checks follow.
Observation for net-kingdom (not blocking): `bind-env` runs before
`register-client`, in type order. Its entry carries a literal
`KEYCAPE_<CLIENT_ID>_CLIENT_SECRET`, which is not a `{param}` placeholder, so it
reaches the plan unrendered.
2026-10-09 follow-up:
- **Format specs.** `_render` supports net-kingdom's `{param:env}` spec (upper
case, `-` as `_`, the same as `keycape-client.py env_name`) and refuses any
other spec or `!conversion`.
- **Case reference.** The plan prints `case-ref: <case_id>@sha256:<hex>` over the
case file's exact bytes. This is the reference proposed to railiance-platform
for `credential.py generate --case-ref` (RPF-WP-0054-T01); the broker
re-derives it from the file.
- 18 tests now.
```task
id: WARDEN-WP-0044-T03
status: progress
depends_on: [WARDEN-WP-0044-T02, MASON-WP-0010-T03]
blocking_reason: "Local durable execution kernel and injected failure harness implemented. Native acceptance still requires authenticated owner machine descriptors/adapters, actual Forgejo materialization receipt, contained session integration, ordered verification and first native run."
priority: high
state_hub_task_id: "bcbf6c91-2c04-5c16-ae8c-5d6c06fd6b89"
```
### T03 — Run and verify a case
`warden case run <case.yaml>` executes the plan. Owner entry points run through
the existing proxy as the caller; steps that need an attended login use the
existing contained login envelope (silent command, session revoked afterwards),
grouped into as few attended sessions as possible. Then it runs the type's
verification and writes a receipt without values. `warden case rollback`
reverses exactly this case's steps.
Acceptance: the Forgejo reference case (NK-WP-0048-T06) reaches `live` through
this path, with no case-specific script.
2026-10-17: original-intent lookup/context interface for NK-WP-0048-T15, source
and synthetic tests only. `src/warden/case_run.py`: `Executor.run` writes an
`OriginalIntent` (schema `warden.case.original-intent.v1`: the dispatched run
Invocation — attempt, step, owner, target, actor, principal, lane, all six pins,
tenant, realm — plus admitted adapter source) in the same SQLite transaction as
the pre-dispatch journal row. `Journal.original_intent(binding, current, source)`
returns it after restart and refuses on a missing record or any
pins/source/step/owner/target/principal/lane/tenant/realm mismatch, before any
journal write, so the step stays uncertain. An adapter's
`reconcile_original(ReconcileContext(original, attempt))` receives the original
intent separately from the new reconcile attempt. This is Warden's record of what
it dispatched, not owner created-only provenance; tenant/realm are as supplied at
admission. Owner descriptors/adapters, contained session integration, Forgejo
materialization and the native run remain open.
Agreed with railiance-platform (RPF-WP-0054-T01, 2026-10-09):
- `mint-secret` runs `credential.py generate --grant keycape/client-secret-generate
--client-id <id> --case-ref <case-ref> --case-file <case.yaml>` as the caller's
child process. The broker re-derives the case-ref and checks status and
client_id.
- warden refuses that step when `WARDEN_AGENT_ID` is set.
2026-10-10: railiance-platform implemented the command (RPF-WP-0054-T03). It is
catalogued as draft `keycape-client-secret-generate`, with `exec_owner`
railiance-platform and `exec_capable: false`. `warden case check-type` now
reports the lane as LANE-UNREVIEWED rather than LANE-MISSING. Before it can be
activated:
- the founder binds the issuer policy to the operator OIDC role
- key-cape confirms the secret format
- the RPF-WP-0054-T05 probe passes
2026-10-10 (later):
- **Broker lane.** The issuer role is bound (CCR-2026-0043) and the T05 probe
passed (railiance-platform `21b8af3`). Only key-cape's format confirmation is
left. The playbook now includes the issuer-role login, a 15m token with
unlimited uses that `warden case run` must group with the attended session.
- **Env spec.** net-kingdom adopted `{client_id:env}` as a 1.0 patch
(`9a9b8e3`). The plan renders `KEYCAPE_FORGEJO_CLIENT_SECRET`.
- **Forgejo case.** Rendered and built by ops-mason. It is not yet
`materialized`: MASON-WP-0010-T03 waits on the railiance-platform CCRs and
their founder apply.
2026-10-10: `keycape-client-secret-generate` activated on railiance-platform's
go-ahead (message 20973a9c) after key-cape confirmed the format (4e0213b3).
`warden case check-type` on the live type now reports `plannable=True`. The
only thing T03 still waits on is the Forgejo case reaching `materialized`
(MASON-WP-0010-T03).
2026-10-10: net-kingdom moved the type to 1.1 (`e2174ce`) and re-pinned the
Forgejo case. 1.1 adds the verification `consumer-enforces-groups` and requires
the hand-over to enforce `access_groups`. `check-type` on 1.1 reports
`plannable=True`, and a materialized copy renders six steps and the new check.
The case-ref digest covers the whole case file, including `status`, so it
changes when the case becomes `materialized`. `warden case run` therefore takes
it from the file at run time, and the broker re-derives it from the same file.
```task
id: WARDEN-WP-0044-T04
status: wait
depends_on: [WARDEN-WP-0044-T03]
blocking_reason: "Catalog integration follows a proven run."
priority: medium
state_hub_task_id: "4a0fa4a7-5ca9-518a-ab92-a79a5e2cf93e"
```
### T04 — Catalog entries from types
Let a type contribute reviewed catalog entries once, so that every case of that
type routes without a new catalog edit. Cases add parameter values, not routes.
`warden route find` should be able to answer "which SecurityCaseType covers this
need?" before anyone builds by hand.
2026-10-10 consolidation source prototype (not an accepted owner adapter API):
`src/warden/case_receipt_state.py` provides a pure immutable receipt reducer,
with exact case/type/adapter/catalog/acceptance/run-sheet pins, running intent
before dispatch, uncertain recovery after a lost result, no success replay,
explicit retry-safe failed-before-change retry and created-only reverse undo.
It executes nothing and accepts no command output. The caller must durably
persist running before any future side effect; storage/authenticated owner
receipts/live adapters are not implemented. Focused offline tests cover changed
pins, lost receipts, retry/refusal, uncertain rollback and shared-object
preservation. Source proposal: `docs/security-case-execution-proposal.md`.
T03 remains open: typed owner execution/receipt contracts require review, the
Forgejo structural materialization needs owner receipts, and CLI dispatch,
contained sessions, native verification and provenance remain unimplemented.
There is a circularity to resolve with net-kingdom/ops-mason: materialization
cannot require mint-secret if mint-secret is itself a follow-through step whose
planning requires materialized. No case status is changed by this prototype.
2026-10-11: the exact execution-design memo version1 has confirmed native human
acceptance (approval e46b149b-ec3c-4b3b-98a7-dcb4934448ca). The approved proposal
bytes remain unchanged. `src/warden/case_run.py` now implements a closed v1 local
execution seam, independent admission/evidence callbacks, private transactional
SQLite receipt storage, process locking, running-before-dispatch, crash recovery
to uncertainty, explicit safe retry, separately required broker-grant and parent-session revocation
proofs, native owner reconciliation and created-only
reverse rollback. Thirty-seven kernel tests and fourteen reducer tests pass;
ruff checks pass. See `docs/security-case-execution-kernel-v1.md` for exact scope
and receipt provenance. No installed native adapter or live CLI execution is
claimed. Current prose types stay plan-only; acknowledged descriptor/type machine
seams and authenticated owner/caller receipts are still required. T03 progresses
for implementation but cannot finish before ordered native Forgejo acceptance.
2026-10-16 source preparation (isolated checkout; no native acceptance):
T03's browser parameter mismatch now has a producer-validator-backed projection
in `case_inputs.py`, explicitly configured on the real Executor. Exact 1.1/1.2
parameter definitions and all four reviewed producer modules are pinned; full case
validation admits reviewed security-sensitive metadata while unknown/fixed/secret
inputs and type/producer drift refuse. Only the reviewed descriptor target
reaches the owner callback; no parameter journal payload is added. Actual
Executor/producer tests cover positive versions and refusal/containment paths.
Acknowledged machine descriptors, authenticated owner evidence, real Forgejo
materialization and contained native sessions remain mandatory and unimplemented;
T03 stays progress, T04 stays wait. No type or case status changed.
2026-10-16 producer source refresh: independently reviewed NetKingdom
`015694ee414c802dc2ef1fa0120dfed610086e69` optional descriptor-map repair.
Only the validator/evidence source pins change; exact parameter and transitive
source identity remain enforced. Actual canonical producer, Executor and reducer
suite passes 87 checks, including 14 new malformed-map integration cases; all
four missing/changed modules still refuse. Review:
`docs/reviews/2026-10-16-browser-producer-pin-refresh.md`. No adapter attestation,
native acceptance, credential use or privileged dispatch. T03 remains progress.

View file

@ -0,0 +1,17 @@
{
"argv": [
"python3",
"-B",
"-m",
"pytest",
"-q",
"-c",
"pytest.ini",
"tests/test_case_run.py",
"tests/test_context_compare_probes.py"
],
"exit_code": 0,
"stdout": "........................................................ [100%]\n56 passed in 2.18s\n",
"stderr": "",
"scope": "Changed concurrent source snapshot only; no canonical mutation or independent owner proof claimed."
}

View file

@ -0,0 +1,2 @@
........................................................ [100%]
56 passed in 2.18s

View file

@ -0,0 +1,124 @@
{
"files": [
{
"path": "comparison-review.json",
"sha256": "sha256:2f1763a685f1ce1da2f42421d3a1cdd2d3a7253be1fb39c6b48194ff29f1ed85"
},
{
"path": "delta-fixture/docs/security-case-execution-kernel-v1.md",
"sha256": "sha256:0eb563dbaea739fba928d04708c2c2bdac592783bbe68e1271041b0d1b1994cb"
},
{
"path": "delta-fixture/pytest.ini",
"sha256": "sha256:363381771127e3479fe49773659cc2a8dc2b2f727459ebd057ac39e79e98a94e"
},
{
"path": "delta-fixture/src/warden/__init__.py",
"sha256": "sha256:047e0feba479474235f0707a207655ecfddfb33cd4f54069134419b8ca4ea24a"
},
{
"path": "delta-fixture/src/warden/case_inputs.py",
"sha256": "sha256:1334b0cd9897e763cfea2d306e997c659f3f284ecc3f9612140c2104835da7c7"
},
{
"path": "delta-fixture/src/warden/case_receipt_state.py",
"sha256": "sha256:a2cda7f187e77bd76d4d209505638de44a587fae0bc033ec75c23ee9ea9f73bc"
},
{
"path": "delta-fixture/src/warden/case_run.py",
"sha256": "sha256:0cc62a33dbb3b90276b291f77fa5d0a906f19296874d68636957763f576d1ae2"
},
{
"path": "delta-fixture/tests/test_case_original_context_consistency.py",
"sha256": "sha256:8483bb5915701e8bd0749e85097e11076ffd539084ca68e9ec1c565babc157d1"
},
{
"path": "delta-fixture/tests/test_case_run.py",
"sha256": "sha256:bc7264848e76e3576821523fec0c4925c4446eaf470f859fe245c98ea072d139"
},
{
"path": "delta-fixture/tests/test_context_compare_probes.py",
"sha256": "sha256:ce64b52ba98d559f4e13f382f7c204a38d6779e0958f37e215b43ec4cfe5fc39"
},
{
"path": "delta-fixture/workplans/WARDEN-WP-0044-security-case-follow-through.md",
"sha256": "sha256:44686df53dac792e46791878c3ccf8c187bb14e2de33eeac411be2005f7f2aa1"
},
{
"path": "delta-probe-results.json",
"sha256": "sha256:b5cc1e7fc2f4bba33ce9256d4780149c5c3f8b850b7d666f5de15e582ebad774"
},
{
"path": "delta-probes.stderr.txt",
"sha256": "sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
{
"path": "delta-probes.stdout.txt",
"sha256": "sha256:3f7dcab165b24572fff8cfcb6aa0fbe74509c434f163475bf1fbe87c051c6b8d"
},
{
"path": "minimal-delta-tests.json",
"sha256": "sha256:0016cc87173f7485a94b2695c48c7df4fd699743b19b530164229bbc2c4ffd18"
},
{
"path": "minimal-integration.patch",
"sha256": "sha256:d058f7f5da015d9dc3fe406982e83f52d0c1b2acb33f0e41861a7bd0fdf8f02e"
},
{
"path": "patch-check.json",
"sha256": "sha256:7eb832e50261c31f86d01e7e45bfc30197647417086d927e3f72a397e09e11c4"
},
{
"path": "probe-results.json",
"sha256": "sha256:d6dc95750038ce5f26fa4bdb1f7954959270eb74b4bb90b0939677896480fec5"
},
{
"path": "probes.stderr.txt",
"sha256": "sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
{
"path": "probes.stdout.txt",
"sha256": "sha256:6bf1b3ccd554890c5dc39fed048dbb793b2b82ca9135cd4376303c55798d6139"
},
{
"path": "snapshot/docs/security-case-execution-kernel-v1.md",
"sha256": "sha256:0eb563dbaea739fba928d04708c2c2bdac592783bbe68e1271041b0d1b1994cb"
},
{
"path": "snapshot/pytest.ini",
"sha256": "sha256:363381771127e3479fe49773659cc2a8dc2b2f727459ebd057ac39e79e98a94e"
},
{
"path": "snapshot/src/warden/__init__.py",
"sha256": "sha256:047e0feba479474235f0707a207655ecfddfb33cd4f54069134419b8ca4ea24a"
},
{
"path": "snapshot/src/warden/case_inputs.py",
"sha256": "sha256:1334b0cd9897e763cfea2d306e997c659f3f284ecc3f9612140c2104835da7c7"
},
{
"path": "snapshot/src/warden/case_receipt_state.py",
"sha256": "sha256:a2cda7f187e77bd76d4d209505638de44a587fae0bc033ec75c23ee9ea9f73bc"
},
{
"path": "snapshot/src/warden/case_run.py",
"sha256": "sha256:0574036ca7b74bdb9124f6af4888e63ec231ee60f5c9f34cbe2fb1acee39f671"
},
{
"path": "snapshot/tests/test_case_run.py",
"sha256": "sha256:bc7264848e76e3576821523fec0c4925c4446eaf470f859fe245c98ea072d139"
},
{
"path": "snapshot/tests/test_context_compare_probes.py",
"sha256": "sha256:85dd7b7ea80c5c2f29fd7125e067c1fa765c99741d15d0a543a238dac2bc524a"
},
{
"path": "snapshot/workplans/WARDEN-WP-0044-security-case-follow-through.md",
"sha256": "sha256:44686df53dac792e46791878c3ccf8c187bb14e2de33eeac411be2005f7f2aa1"
},
{
"path": "source-state.json",
"sha256": "sha256:1d0df4438451b1d0b688d66f09cf924f0b009ce326535c31af30dcdf2d466443"
}
]
}

View file

@ -0,0 +1,17 @@
{
"argv": [
"python3",
"-B",
"-m",
"pytest",
"-q",
"-c",
"pytest.ini",
"tests/test_case_run.py",
"tests/test_case_original_context_consistency.py"
],
"exit_code": 0,
"stdout": "...................................................... [100%]\n54 passed in 1.98s\n",
"stderr": "",
"scope": "Exact modified temporary snapshot only; no canonical or native invocation."
}

View file

@ -0,0 +1,427 @@
--- a/src/warden/case_run.py
+++ b/src/warden/case_run.py
@@ -189,7 +189,66 @@
invocation: Invocation
source: str
+ def validate(self) -> None:
+ """Fixed bounded metadata only; tenant/realm are not authority claims.
+
+ Current admit leaves tenant/realm empty. Nonempty future coordinates need
+ separate owner provenance; serializability alone must never supply it.
+ """
+ if (
+ type(self.invocation) is not Invocation
+ or type(self.invocation.pins) is not Pins
+ ):
+ raise Refused("exact original invocation required")
+ i = self.invocation
+ fields = (i.step, i.owner, i.target, i.principal, i.lane, i.attempt_id)
+ if (
+ not all(
+ type(value) is str and IDENTIFIER.fullmatch(value) for value in fields
+ )
+ or type(i.actor) is not str
+ or i.actor not in ("human", "agent")
+ or type(i.operation) is not str
+ or i.operation not in ("run", "rollback")
+ or not all(
+ type(value) is str and (not value or IDENTIFIER.fullmatch(value))
+ for value in (i.tenant, i.realm)
+ )
+ or type(self.source) is not str
+ or not DIGEST.fullmatch(self.source)
+ or type(self.binding) is not str
+ or self.binding != f"{i.step}:{i.target}"
+ ):
+ raise Refused("invalid original intent metadata")
+ if set(Invocation.__dataclass_fields__) != {
+ "step",
+ "owner",
+ "target",
+ "actor",
+ "principal",
+ "lane",
+ "pins",
+ "attempt_id",
+ "operation",
+ "tenant",
+ "realm",
+ }:
+ raise Refused("original invocation field contract changed")
+ if not all(
+ type(v) is str and DIGEST.fullmatch(v)
+ for v in (
+ i.pins.case,
+ i.pins.case_type,
+ i.pins.adapter,
+ i.pins.catalog,
+ i.pins.acceptance,
+ i.pins.run_sheet,
+ )
+ ):
+ raise Refused("invalid original intent pins")
+
def payload(self) -> str:
+ self.validate()
return json.dumps(
{"schema": INTENT_SCHEMA, "binding": self.binding, "source": self.source}
| asdict(self.invocation),
@@ -199,13 +258,44 @@
@classmethod
def decode(cls, raw: str) -> OriginalIntent:
- obj = json.loads(raw)
- fields = {f for f in Invocation.__dataclass_fields__}
- if set(obj) != fields | {"schema", "binding", "source"} or obj["schema"] != INTENT_SCHEMA:
- raise Refused("unknown original intent schema")
- inv = {k: obj[k] for k in fields}
- inv["pins"] = Pins(**inv["pins"])
- return cls(obj["binding"], Invocation(**inv), obj["source"])
+ def unique(pairs):
+ result = {}
+ for key, value in pairs:
+ if key in result:
+ raise Refused("duplicate original intent field")
+ result[key] = value
+ return result
+
+ try:
+ if type(raw) is not str or len(raw.encode()) > MAX_SOURCE_BYTES:
+ raise Refused("original intent input exceeds bound")
+ obj = json.loads(raw, object_pairs_hook=unique)
+ fields = {
+ "step",
+ "owner",
+ "target",
+ "actor",
+ "principal",
+ "lane",
+ "pins",
+ "attempt_id",
+ "operation",
+ "tenant",
+ "realm",
+ }
+ if (
+ type(obj) is not dict
+ or set(obj) != fields | {"schema", "binding", "source"}
+ or obj["schema"] != INTENT_SCHEMA
+ ):
+ raise Refused("unknown original intent schema")
+ inv = {k: obj[k] for k in fields}
+ inv["pins"] = Pins(**inv["pins"])
+ result = cls(obj["binding"], Invocation(**inv), obj["source"])
+ result.validate()
+ return result
+ except (TypeError, ValueError, KeyError):
+ raise Refused("invalid original intent record") from None
@dataclass(frozen=True, slots=True)
@@ -256,28 +346,76 @@
"CREATE TABLE IF NOT EXISTS intents (seq INTEGER PRIMARY KEY, attempt_id TEXT NOT NULL UNIQUE, binding TEXT NOT NULL, payload TEXT NOT NULL)"
)
- def original_intent(self, binding: str, current: Invocation, source: str) -> OriginalIntent:
+ def original_intent(
+ self, binding: str, current: Invocation, source: str
+ ) -> OriginalIntent:
"""Latest original run intent for binding, refused unless it matches exactly.
Missing or mismatched records refuse; the step stays uncertain.
"""
row = self.db.execute(
- "SELECT payload FROM intents WHERE binding=? ORDER BY seq DESC LIMIT 1",
+ "SELECT attempt_id,payload FROM intents WHERE binding=? ORDER BY seq DESC LIMIT 1",
(binding,),
).fetchone()
if row is None:
raise Refused("original intent record missing; step stays uncertain")
- intent = OriginalIntent.decode(row[0])
+ intent = OriginalIntent.decode(row[1])
o = intent.invocation
+ if row[0] != o.attempt_id:
+ raise Refused("original intent attempt identity differs")
if intent.binding != binding or o.operation != "run":
raise Refused("original intent binding mismatch")
if o.pins != current.pins:
raise Refused("original intent pins mismatch")
if intent.source != source:
raise Refused("original intent source mismatch")
- for name in ("step", "owner", "target", "principal", "lane", "tenant", "realm"):
+ for name in (
+ "step",
+ "owner",
+ "target",
+ "actor",
+ "principal",
+ "lane",
+ "tenant",
+ "realm",
+ ):
if getattr(o, name) != getattr(current, name):
raise Refused(f"original intent {name} mismatch")
+ # Match the persisted original running receipt. An orphan context or a
+ # payload from another attempt cannot become the current lookup key.
+ receipts = self.db.execute(
+ "SELECT payload FROM receipts WHERE binding=? ORDER BY seq DESC LIMIT ?",
+ (binding, MAX_HISTORY + 1),
+ ).fetchall()
+ if len(receipts) > MAX_HISTORY:
+ raise Refused("original intent receipt history exceeds bound")
+ matched = False
+ try:
+ for (raw,) in receipts:
+ if type(raw) is not str or len(raw.encode()) > MAX_SOURCE_BYTES:
+ raise Refused("original receipt input exceeds bound")
+ payload = json.loads(raw)
+ if (
+ payload.get("attempt_id") != o.attempt_id
+ or payload.get("operation") != "run"
+ ):
+ continue
+ last = payload.get("receipts", [])[-1]
+ if last.get("outcome") != "running":
+ continue
+ if (
+ payload.get("journal_schema") != "warden.case.step-journal.v1"
+ or payload.get("step_id") != o.step
+ or payload.get("owner") != o.owner
+ or payload.get("pins") != asdict(o.pins)
+ ):
+ raise Refused("original running receipt binding differs")
+ matched = True
+ break
+ except (TypeError, ValueError, KeyError, IndexError, AttributeError):
+ raise Refused("invalid original running receipt") from None
+ if not matched:
+ raise Refused("original running receipt missing; no backfill")
return intent
@contextmanager
@@ -355,6 +493,23 @@
invocation: Invocation | None = None,
intent: OriginalIntent | None = None,
):
+ if intent is not None:
+ if type(intent) is not OriginalIntent:
+ raise Refused("exact original intent required")
+ intent.validate()
+ expected = (
+ Outcome.RUNNING
+ if intent.invocation.operation == "run"
+ else Outcome.ROLLBACK_RUNNING
+ )
+ if (
+ intent.binding != binding
+ or intent.invocation != invocation
+ or intent.invocation.pins != state.pins
+ or not state.last
+ or state.last.outcome is not expected
+ ):
+ raise Refused("original intent and running receipt differ")
self.db.execute("BEGIN IMMEDIATE")
try:
if intent is not None:
--- /dev/null
+++ b/tests/test_case_original_context_consistency.py
@@ -0,0 +1,198 @@
+"""Original-intent consistency checks with generated metadata only.
+
+Reuse the existing synthetic owner rig. These checks do not provide a native
+holder or independently authenticate original creation from local SQL/JSON.
+"""
+
+from dataclasses import asdict, replace
+import json
+from pathlib import Path
+import sqlite3
+import subprocess
+import sys
+import pytest
+from test_case_run import rig as rig
+from warden.case_receipt_state import Outcome, Refused
+from warden.case_run import OriginalIntent
+
+
+def interrupted(rig):
+ executor, args, calls, sources, kwargs = rig
+ old = executor.adapters[args[0].adapter]
+ seen = []
+
+ def lost(inv):
+ calls.append(inv)
+ raise TimeoutError("generated lost response")
+
+ def original(ctx):
+ seen.append(ctx)
+ return old.reconcile(ctx.attempt)
+
+ executor.adapters[old.reference] = replace(
+ old, invoke=lost, reconcile=None, reconcile_original=original
+ )
+ assert executor.run(*args).last.outcome is Outcome.UNCERTAIN
+ return executor, args, calls, old, seen
+
+
+def alter_payload(executor, **changes):
+ row = executor.journal.db.execute(
+ "SELECT seq,payload FROM intents ORDER BY seq DESC LIMIT 1"
+ ).fetchone()
+ obj = json.loads(row[1])
+ obj.update(changes)
+ executor.journal.db.execute(
+ "UPDATE intents SET payload=? WHERE seq=?", (json.dumps(obj), row[0])
+ )
+
+
+def test_original_actor_mismatch_is_refused(rig):
+ executor, args, calls, old, _ = interrupted(rig)
+ alter_payload(executor, actor="agent")
+ with pytest.raises(Refused):
+ executor.journal.original_intent(
+ "mint-secret:fixture-client", args[1], old.source
+ )
+
+
+def test_payload_attempt_id_must_match_sql_column_and_original_receipt(rig):
+ executor, args, calls, old, _ = interrupted(rig)
+ actual = calls[0].attempt_id
+ alter_payload(executor, attempt_id="attempt-unrelated")
+ with pytest.raises(Refused):
+ executor.journal.original_intent(
+ "mint-secret:fixture-client", args[1], old.source
+ )
+ assert (
+ executor.journal.db.execute("SELECT attempt_id FROM intents").fetchone()[0]
+ == actual
+ )
+
+
+def test_orphan_intent_without_original_running_receipt_is_refused(rig):
+ executor, args, calls, old, _ = interrupted(rig)
+ executor.journal.db.execute(
+ "DELETE FROM receipts WHERE seq=(SELECT MIN(seq) FROM receipts)"
+ )
+ assert (
+ executor.journal.load("mint-secret:fixture-client", args[2]).last.outcome
+ is Outcome.UNCERTAIN
+ )
+ with pytest.raises(Refused):
+ executor.journal.original_intent(
+ "mint-secret:fixture-client", args[1], old.source
+ )
+
+
+def test_serializer_refuses_arbitrary_values_outside_normal_admit(rig):
+ _, args, _, _, _ = rig
+ inv = replace(
+ args[1],
+ target={"unexpected": "synthetic-owner-payload"},
+ operation="run",
+ attempt_id="attempt-fixture",
+ )
+ record = OriginalIntent("mint-secret:fixture-client", inv, "sha256:" + "1" * 64)
+ with pytest.raises(Refused):
+ OriginalIntent.decode(record.payload())
+ # This is a direct serialization API gap, not an observed normal-admit leak.
+
+ # Owner trust is the existing synthetic fixture; this proves call shape only.
+
+
+@pytest.mark.parametrize(
+ "field,value",
+ [
+ ("principal", "another-person"),
+ ("tenant", "another-tenant"),
+ ("realm", "another-realm"),
+ ],
+)
+def test_existing_lookup_does_refuse_stored_principal_tenant_realm_mismatch(
+ rig, field, value
+):
+ executor, args, _, old, _ = interrupted(rig)
+ alter_payload(executor, **{field: value})
+ with pytest.raises(Refused):
+ executor.journal.original_intent(
+ "mint-secret:fixture-client", args[1], old.source
+ )
+
+
+def test_existing_atomic_insert_failure_prevents_dispatch_and_both_records(rig):
+ executor, args, calls, _, _ = rig
+ executor.journal.db.execute(
+ "CREATE TRIGGER fail_receipt BEFORE INSERT ON receipts BEGIN SELECT RAISE(ABORT,'fixture'); END"
+ )
+ with pytest.raises(sqlite3.IntegrityError):
+ executor.run(*args)
+ assert not calls
+ assert executor.journal.db.execute("SELECT COUNT(*) FROM intents").fetchone() == (
+ 0,
+ )
+ assert executor.journal.db.execute("SELECT COUNT(*) FROM receipts").fetchone() == (
+ 0,
+ )
+
+
+def test_existing_missing_original_refuses_before_callback(rig):
+ executor, args, _, _, seen = interrupted(rig)
+ executor.journal.db.execute("DELETE FROM intents")
+ with pytest.raises(Refused):
+ executor.reconcile(*args)
+ assert not seen
+ assert (
+ executor.journal.load("mint-secret:fixture-client", args[2]).last.outcome
+ is Outcome.UNCERTAIN
+ )
+
+
+def test_existing_current_parent_revocation_remains_mandatory(rig):
+ executor, args, _, _, _ = interrupted(rig)
+ old = executor.evidence_verifier
+
+ def refuse_session(purpose, source, evidence):
+ return (
+ False
+ if purpose.startswith("session-revocation:")
+ else old(purpose, source, evidence)
+ )
+
+ executor.evidence_verifier = refuse_session
+ with pytest.raises(Refused):
+ executor.reconcile(*args)
+ assert (
+ executor.journal.load("mint-secret:fixture-client", args[2]).last.outcome
+ is Outcome.UNCERTAIN
+ )
+
+
+def test_existing_intent_survives_actual_distinct_interpreter(rig):
+ executor, args, calls, old, _ = interrupted(rig)
+ code = """import json,sys
+from pathlib import Path
+from warden.case_run import Journal,Invocation
+from warden.case_receipt_state import Pins
+obj=json.load(sys.stdin);obj['pins']=Pins(**obj['pins']);j=Journal(Path(sys.argv[1]))
+with j.locked():
+ i=j.original_intent('mint-secret:fixture-client',Invocation(**obj),sys.argv[2])
+ print(json.dumps({'attempt':i.invocation.attempt_id,'operation':i.invocation.operation}))
+"""
+ result = subprocess.run(
+ [sys.executable, "-B", "-c", code, str(executor.journal.directory), old.source],
+ input=json.dumps(asdict(args[1])),
+ text=True,
+ capture_output=True,
+ timeout=15,
+ env={
+ "PATH": "/usr/bin:/bin",
+ "PYTHONPATH": str(Path(__file__).parents[1] / "src"),
+ "PYTHONDONTWRITEBYTECODE": "1",
+ },
+ check=True,
+ )
+ assert json.loads(result.stdout) == {
+ "attempt": calls[0].attempt_id,
+ "operation": "run",
+ }

View file

@ -0,0 +1,7 @@
{
"base": "a45cf475bc4dbc929e0eecbc1f806a9229d934e2",
"exit_code": 0,
"stdout": "",
"stderr": "",
"current_source_unchanged": true
}

View file

@ -0,0 +1,17 @@
{
"observed_at": "2026-10-17T05:53:57.282196+00:00",
"argv": [
"python3",
"-B",
"-m",
"pytest",
"-q",
"-c",
"pytest.ini",
"tests/test_context_compare_probes.py"
],
"exit_code": 0,
"stdout": "............. [100%]\n13 passed in 0.71s\n",
"stderr": "",
"scope": "Only exact snapshot; no tests against canonical user tree. Passing counterexample probes reproduce documented source gaps, not security/native acceptance."
}

View file

@ -0,0 +1,2 @@
............. [100%]
13 passed in 0.71s

View file

@ -0,0 +1,127 @@
# Closed case execution kernel v1 — 2026-10-11
Owner implementation record for WARDEN-WP-0044-T03. The architectural proposal
at SHA256 78ab1439e4c5beb205aeccf15b1b2e706511be55ab195c5a3aa682f326c7c77c
was accepted through memo `infd-20261010-security-case-execution`, version 1,
approval e46b149b-ec3c-4b3b-98a7-dcb4934448ca, confirmed disposition
disp-cf44dacb-2117-4de7-8f90-cfa99f84f325 at 2026-10-10T23:23:31Z. The original
approved proposal remains byte-identical. That decision accepts source design;
it grants no execution session, credential or deployment authority.
`src/warden/case_run.py` advances the pure reducer into an executable injected
owner harness with private durable receipts. Descriptor version
`warden.case.execution.v1` is a closed local implementation seam, not an accepted
NetKingdom type schema. It contains fixed owner/adapter/source digest, actor,
lane, target parameter, effect, reviewed created-object identifiers declared
retry safety and explicit required revocation scopes (parent-session and broker-grant).
A mint descriptor cannot omit either scope. Unknown fields, free shell text and secret parameters are refused.
An acknowledged type must additionally pin the descriptor bytes under its
`execution_descriptors` map and independent owner evidence must authenticate
that exact machine-seam revision. Existing descriptive types lack this map and
remain plan-only. Their acknowledged labels do not authorize this new seam.
There are no installed owner adapters, native provenance verifier or dispatch CLI
in this change. Callables are injected only through a fixed adapter registry,
with immutable owner reference/source pins. A real integration must supply
independent owner/native verification or explicit attended manual evidence;
a bare JSON receipt identifier is insufficient. Fixture verifiers in tests
are deliberately fake and attest no native case. Caller sessions are independently
verified for exact principal/actor/lane at admission and again before dispatch;
input actor labels alone are never sufficient. Agent mint is refused, including
when WARDEN_AGENT_ID appears after initial human admission.
Each admission pins exact case/type/descriptor/catalog bytes, acceptance reference
and run-sheet identity. Actual ops-mason materialization evidence is required
against the case source, separately from its status label. Case parameters supply
an exact metadata target. Source/session changes cannot inherit journal success.
Owner results have a closed metadata shape, result evidence fingerprint and
separate independently authenticated grant/parent-session revocation evidence
fingerprints. An aggregate revoked boolean alone cannot satisfy either scope. Unknown result payloads, unverified evidence, absent revocation and
created objects outside the reviewed scope become uncertain, never success.
Python and OS stdout/stderr, including inherited child-process output, are
discarded without buffering or retention under a serialized fd containment
context. Independent provenance verification uses the same containment and
sanitizes exceptions. All source inputs are capped at 256 KiB before parsing.
Error text is not copied to the journal. KeyboardInterrupt/SystemExit and other
owner interruptions are rethrown with a fixed message while retaining running
intent for crash recovery.
The journal uses an owner-private 0700 directory and 0600 files, refuses symlinks
and insecure modes, uses SQLite FULL synchronization and commits running intent
before calling the adapter. A separate process lock prevents concurrent mutation.
A crash between dispatch and final receipt leaves running; the next lock holder
persists uncertain before refusing replay. Both intent and outcome remain in
history. Each persisted attempt has a unique identity bound to all exact pins,
operation (run/reconcile/rollback), sequence and nonce. Adapter results and both
revocation proof purposes carry that identity. Prior-attempt evidence cannot
verify a safe retry, even if a caller rewrites result labels. Descriptor-created
objects are capped at 32 and histories at 128 transitions, with dispatch stopped
before archival is required. A throw or lost response is not failed-before-change. A safe retry needs
verified failed-before-change, unchanged pins, descriptor retry-safe and explicit
retry. Success and no-change cannot replay.
Reconciliation is an explicit fixed owner callback, never the mutation callback.
It may verify an already-present native CAS result as no-change/success, or prove
failed-before-change; it never tells Warden to regenerate a credential. Uncertain
or failed-after-change requires this owner-native inspection before any retry.
Owner proof and revocation remain mandatory. Rollback visits only objects in a
verified creation receipt, in reverse order; no-change has no undo and shared
objects are excluded. Unknown/lost undo blocks another rollback.
The kernel operates individual admitted steps. Full ordered run-sheet orchestration,
verification inventory, contained login integration, native owner adapters and
CLI activation remain WARDEN-WP-0044-T03; no overall native-complete result is
implemented. Current Forgejo source is not materialized and has no acknowledged
machine descriptors. Its first native run remains an acceptance requirement,
with real materialization, separately authenticated broker-grant and parent-session
revocation receipts, session/owner receipts and consumer enforcement. This
implementation neither promotes a type nor changes any case status.
Validation: 37 new kernel tests plus 14 reducer tests pass (51 total). Tests open
an independent SQLite connection inside dispatch to prove running was committed,
crash after mutation and reopen a fresh journal to prove no duplicate invocation,
lose a response then reconcile without mint, require explicit retry, check exact
pins/session expiry, withhold malicious output and unconfirmed revocation, and
prove created-only reverse undo plus uncertain-undo refusal. Ruff formatting and
checks pass. No live token or target action occurred.
## Browser input projection — 2026-10-16 source preparation
An explicitly configured `BrowserInputs(netkingdom_root)` now validates browser
cases before admission. It calls the real NetKingdom type/case validator over
verified producer bytes in a disposable Python process (`-I`, empty environment,
timeout, no inherited output). The validator, composer, capability contract and lazy evidence
modules have exact source pins; missing or changed code refuses. There is no
automatic discovery or download. A producer upgrade needs reviewed pin changes.
Only the exact reviewed 1.1/1.2 browser parameter definitions qualify. A digest
of each complete parameter definition list prevents reclassifying secrets as
metadata, loosening constraints, or adding fields under a recognized version.
The complete case passes producer validation, including required fields,
constraints and credential-shape checks. Explicit fixed/default overrides,
unknown fields and secret references refuse. Security-sensitive browser metadata
can therefore be present without being passed to an owner adapter: the only
projection is its descriptor's exact public/operational target identifier.
No raw parameter values are added to invocations or persisted receipts.
`require_implemented=False` validates the acknowledged type's source, not its
execution authority. Existing descriptor/type/source/catalog/caller provenance
gates stay mandatory. Neither historical browser type contains the required
exact machine-descriptor map, and neither is promoted by this change. There are
still no installed native owner adapters, authenticated provenance verifier,
contained session/ordered run orchestration or live CLI dispatch. A journal digest
is a fingerprint and cannot authenticate native evidence. Completion still needs
owner-admitted descriptors and actual structural, mint/delivery, consumer and
revocation/rollback evidence. Local fixture success is not native acceptance.
Tests use the actual producer checkout (override sibling location with
`WARDEN_TEST_NETKINGDOM_ROOT`), the real Executor, SQLite journal and injected
test-only owner adapter/evidence verifier. Their descriptor extensions and case
materialized labels exist only in memory. Canonical case/type bytes stay intact.
Producer integration refinement: the accepted NetKingdom browser-case patch
`d32a7f51cbf3012bee3e4bb329f4259dea867eff1c59a2b01a65d72774488d05`
is now the tested producer revision. Its evidence module is imported lazily only
by `check-evidence`, outside this admission path; Warden nevertheless pins and
copies it with the complete reviewed producer set. Missing or modified bytes in
any of the four modules refuse admission. The test covers every dependency.

View file

@ -0,0 +1,2 @@
[pytest]
pythonpath = src

View file

@ -0,0 +1,3 @@
"""OpsWarden — SSH CA and certificate lifecycle manager."""
__version__ = "0.1.0"

View file

@ -0,0 +1,98 @@
"""Reviewed browser metadata projection; no native trust or command dispatch.
The producer validator and all reviewed producer modules are pinned below.
Their verified bytes run in a disposable tree, without caller environment or
ambient Python imports. Type parameters must match the exact reviewed version.
Machine descriptor extensions still require Executor's independent admission.
"""
import hashlib
import json
from pathlib import Path
import subprocess
import sys
import tempfile
from .case_receipt_state import Refused
# Reviewed producer: net-kingdom 015694ee414c802dc2ef1fa0120dfed610086e69.
# Review: docs/reviews/2026-10-16-browser-producer-pin-refresh.md
SOURCE_PINS = {
"tools/security-case-types/security_case_evidence.py": "da8efa59c52ad73283397ebe639ae259d0cb9c6348b5cb829135c24230dcdc75",
"tools/security-case-types/security_case_validator.py": "1bcc62e9bc374c711363295549f3cd5bb0b32952671ed4b08fddc7f74742959b",
"tools/security-scenario-composer/security_scenario_composer.py": "9f0cc69930aa8ee2cc3fb92236e6a99728df17b8c0fe36e1250241c38fc01c4f",
"tools/playbook-capability-contract/playbook_contract_validator.py": "2e1e0c809d4bc9d64c2d974cc23fecd1c5636785154c2554edd9191852fd926d",
}
PARAMETER_PINS = {
"1.1": "9ec2d6113bf70dbd35cfc247412363ff187e792bc82e24159a6f78e090aa3e4c",
"1.2": "c04385d176f5f70257fb0fa6fef7e48ab26ed7cf26f6b1c7f14b16237b0ebea6",
}
_VALIDATE = """
import json, sys
from pathlib import Path
sys.path.insert(0, str(Path(sys.argv[1]) / 'tools/security-case-types'))
import security_case_validator as v
case, typ = json.load(sys.stdin)
issues = v.validate_type(typ) + v.validate_case(case, typ, require_implemented=False)
print('valid' if not v.has_errors(issues) else 'invalid')
"""
class BrowserInputs:
"""Explicit owner configuration, never inferred from a case-supplied path."""
def __init__(self, netkingdom_root: Path):
self.root = Path(netkingdom_root)
def target(self, case: dict, typ: dict, target_parameter: str) -> str:
try:
spec = typ["spec"]
parameters = spec["parameters"]
fingerprint = hashlib.sha256(
json.dumps(parameters, sort_keys=True, separators=(",", ":")).encode()
).hexdigest()
if (
spec["id"] != "oidc-browser-relying-party"
or PARAMETER_PINS.get(spec["version"]) != fingerprint
):
raise ValueError
declared = {item["name"]: item for item in parameters}
definition = declared.get(target_parameter, {})
if (
definition.get("sensitivity") not in ("public", "operational")
or definition.get("case_settable") is not True
):
raise ValueError
# No secret references or newly classified metadata are grandfathered.
for name in case["spec"]["parameters"]:
item = declared.get(name, {})
if item.get("case_settable") is not True or item.get(
"sensitivity"
) not in ("public", "operational", "security_sensitive"):
raise ValueError
with tempfile.TemporaryDirectory(
prefix="warden-case-validator-"
) as directory:
for relative, expected in SOURCE_PINS.items():
source = (self.root / relative).read_bytes()
if hashlib.sha256(source).hexdigest() != expected:
raise ValueError
dest = Path(directory) / relative
dest.parent.mkdir(parents=True, exist_ok=True)
dest.write_bytes(source)
result = subprocess.run(
[sys.executable, "-I", "-c", _VALIDATE, directory],
input=json.dumps([case, typ]),
text=True,
stdout=subprocess.PIPE,
stderr=subprocess.DEVNULL,
env={},
timeout=10,
check=True,
)
if result.stdout != "valid\n":
raise ValueError
return case["spec"]["parameters"][target_parameter]
except (OSError, ValueError, TypeError, KeyError, subprocess.SubprocessError):
raise Refused("browser metadata failed exact-version validation") from None

View file

@ -0,0 +1,146 @@
"""Proposed, pure case receipt reducer for WARDEN-WP-0044-T03.
This prototype executes nothing and implements no accepted owner adapter API.
Callers MUST durably persist a returned running receipt before a side effect.
Only metadata identifiers/digests enter this model; no command output is accepted.
"""
from __future__ import annotations
from dataclasses import dataclass, replace
from enum import Enum
import re
_ID = re.compile(r"[a-zA-Z0-9][a-zA-Z0-9_.:-]{0,127}\Z")
_DIGEST = re.compile(r"sha256:[0-9a-f]{64}\Z")
class Refused(ValueError):
"""A transition requires an independent owner reconciliation or new review."""
class Outcome(str, Enum):
RUNNING = "running"
SUCCESS = "verified-success"
NO_CHANGE = "verified-no-change"
FAILED_BEFORE = "failed-before-change"
FAILED_AFTER = "failed-after-change"
UNCERTAIN = "uncertain"
ROLLBACK_RUNNING = "rollback-running"
ROLLED_BACK = "verified-rolled-back"
ROLLBACK_UNCERTAIN = "rollback-uncertain"
@dataclass(frozen=True)
class Pins:
"""Exact reviewed case/type/adapter/catalog/acceptance/run-sheet digests."""
case: str
case_type: str
adapter: str
catalog: str
acceptance: str
run_sheet: str
def __post_init__(self) -> None:
if not all(_DIGEST.fullmatch(value) for value in vars(self).values()):
raise Refused("pins require sha256 digests")
@dataclass(frozen=True)
class Receipt:
attempt: int
outcome: Outcome
created: tuple[str, ...] = ()
@dataclass(frozen=True)
class StepState:
step_id: str
owner: str
pins: Pins
allowed_created: tuple[str, ...] = ()
retry_safe: bool = False
receipts: tuple[Receipt, ...] = ()
def __post_init__(self) -> None:
if not all(_ID.fullmatch(v) for v in (self.step_id, self.owner, *self.allowed_created)):
raise Refused("only metadata identifiers are supported")
if len(set(self.allowed_created)) != len(self.allowed_created):
raise Refused("duplicate reviewed object identifier")
@property
def last(self) -> Receipt | None:
return self.receipts[-1] if self.receipts else None
def _same_pins(state: StepState, pins: Pins) -> None:
if state.pins != pins:
raise Refused("pins changed; a newly reviewed sheet is required")
def _append(state: StepState, outcome: Outcome, created: tuple[str, ...] = ()) -> StepState:
receipt = Receipt(len(state.receipts) + 1, outcome, created)
return replace(state, receipts=(*state.receipts, receipt))
def begin(state: StepState, pins: Pins, *, retry: bool = False) -> StepState:
"""Return intent to dispatch. Persist before calling an owner adapter."""
_same_pins(state, pins)
last = state.last
if last is None:
if retry:
raise Refused("no failed attempt to retry")
elif not (last.outcome is Outcome.FAILED_BEFORE and state.retry_safe and retry):
raise Refused("step cannot dispatch or replay without owner reconciliation")
return _append(state, Outcome.RUNNING)
def finish(state: StepState, pins: Pins, outcome: Outcome,
*, created: tuple[str, ...] = ()) -> StepState:
"""Accept only an adapter's verified, closed metadata result, never output."""
_same_pins(state, pins)
if not state.last or state.last.outcome is not Outcome.RUNNING:
raise Refused("no running side effect")
if not isinstance(outcome, Outcome) or outcome not in (Outcome.SUCCESS, Outcome.NO_CHANGE, Outcome.FAILED_BEFORE,
Outcome.FAILED_AFTER, Outcome.UNCERTAIN):
raise Refused("unsupported adapter result")
if len(set(created)) != len(created) or not set(created) <= set(state.allowed_created):
raise Refused("created objects are outside the reviewed case")
if created and outcome not in (Outcome.SUCCESS, Outcome.FAILED_AFTER):
raise Refused("this result cannot claim created objects")
return _append(state, outcome, created)
def recover(state: StepState) -> StepState:
"""Lost result after persisted dispatch is uncertain, never safe to retry."""
if state.last and state.last.outcome is Outcome.RUNNING:
return _append(state, Outcome.UNCERTAIN)
if state.last and state.last.outcome is Outcome.ROLLBACK_RUNNING:
return _append(state, Outcome.ROLLBACK_UNCERTAIN, state.last.created)
return state
def rollback_objects(state: StepState, pins: Pins) -> tuple[str, ...]:
"""Reviewed identifiers only, reverse created order; no shared-object undo."""
_same_pins(state, pins)
last = state.last
if last is None or last.outcome is Outcome.NO_CHANGE:
return ()
if last.outcome is not Outcome.SUCCESS:
raise Refused("rollback needs a verified successful creation receipt")
return tuple(reversed(last.created))
def begin_rollback(state: StepState, pins: Pins) -> StepState:
objects = rollback_objects(state, pins)
if not objects:
raise Refused("no case-created objects to undo")
return _append(state, Outcome.ROLLBACK_RUNNING, objects)
def finish_rollback(state: StepState, pins: Pins, *, verified: bool) -> StepState:
_same_pins(state, pins)
if not state.last or state.last.outcome is not Outcome.ROLLBACK_RUNNING:
raise Refused("no running rollback")
outcome = Outcome.ROLLED_BACK if verified else Outcome.ROLLBACK_UNCERTAIN
return _append(state, outcome, state.last.created)

View file

@ -0,0 +1,826 @@
"""Closed local execution kernel v1; no installed adapters or live CLI dispatch.
An owner must acknowledge each descriptor and provide an independent provenance
verifier. Descriptive case types remain plan-only. Nothing executes shell prose.
"""
from __future__ import annotations
from contextlib import contextmanager, redirect_stderr, redirect_stdout
from dataclasses import asdict, dataclass, replace
import fcntl
import hashlib
import json
import os
from pathlib import Path
import re
import sqlite3
import threading
import uuid
from typing import Callable
import yaml
from .case_inputs import BrowserInputs
from .case_receipt_state import (
Outcome,
Pins,
Receipt,
Refused,
StepState,
begin,
finish,
recover,
begin_rollback,
finish_rollback,
)
IDENTIFIER = re.compile(r"[a-zA-Z0-9][a-zA-Z0-9_.:/@-]{0,191}\Z")
MAX_SOURCE_BYTES = 262144
MAX_HISTORY = 128
OUTPUT_LOCK = threading.RLock()
def bounded_source(value: bytes):
if type(value) is not bytes or len(value) > MAX_SOURCE_BYTES:
raise Refused("source exceeds bounded input contract")
@contextmanager
def contained_output():
"""Discard Python and inherited OS stdout/stderr; serialize process fd changes."""
with OUTPUT_LOCK:
saved = []
null = os.open(os.devnull, os.O_WRONLY)
try:
for target in (1, 2):
saved.append((target, os.dup(target)))
os.dup2(null, target)
with redirect_stdout(_Discard()), redirect_stderr(_Discard()):
try:
yield
except Exception:
raise Refused("owner callback failed") from None
except BaseException:
raise OwnerInterrupted() from None
finally:
for target, original in saved:
os.dup2(original, target)
os.close(original)
os.close(null)
DIGEST = re.compile(r"sha256:[0-9a-f]{64}\Z")
def digest(value: bytes) -> str:
return "sha256:" + hashlib.sha256(value).hexdigest()
@dataclass(frozen=True, slots=True)
class Descriptor:
version: str
step: str
owner: str
adapter: str
adapter_source: str
actor: str
lane: str
target_parameter: str
effect: str
allowed_created: tuple[str, ...]
retry_safe: bool
revocation_scopes: tuple[str, ...]
@classmethod
def decode(cls, source: bytes) -> Descriptor:
bounded_source(source)
try:
obj = json.loads(source)
if set(obj) != set(cls.__dataclass_fields__):
raise ValueError
if not isinstance(obj["allowed_created"], list):
raise ValueError
obj["allowed_created"] = tuple(obj["allowed_created"])
if not isinstance(obj["revocation_scopes"], list):
raise ValueError
obj["revocation_scopes"] = tuple(obj["revocation_scopes"])
result = cls(**obj)
identifiers = (
result.step,
result.owner,
result.adapter,
result.lane,
result.target_parameter,
*result.allowed_created,
)
if result.version != "warden.case.execution.v1" or not all(
isinstance(v, str) and IDENTIFIER.fullmatch(v) for v in identifiers
):
raise ValueError
if not DIGEST.fullmatch(result.adapter_source) or result.actor not in (
"human",
"agent",
):
raise ValueError
if (
result.effect not in ("read", "change", "mint")
or type(result.retry_safe) is not bool
):
raise ValueError
scopes = set(result.revocation_scopes)
if (
len(scopes) != len(result.revocation_scopes)
or not scopes <= {"parent-session", "broker-grant"}
or "parent-session" not in scopes
):
raise ValueError
if result.effect == "mint" and "broker-grant" not in scopes:
raise ValueError
if len(result.allowed_created) > 32:
raise ValueError
if len(set(result.allowed_created)) != len(result.allowed_created):
raise ValueError
return result
except (ValueError, TypeError, KeyError):
raise Refused("invalid closed execution descriptor") from None
@dataclass(frozen=True, slots=True)
class OwnerResult:
outcome: Outcome
evidence: str
created: tuple[str, ...] = ()
revoked: bool = False
session_revocation_evidence: str | None = None
grant_revocation_evidence: str | None = None
attempt_id: str = ""
operation: str = ""
@dataclass(frozen=True, slots=True)
class Invocation:
step: str
owner: str
target: str
actor: str
principal: str
lane: str
pins: Pins
attempt_id: str = ""
operation: str = "admission"
tenant: str = ""
realm: str = ""
INTENT_SCHEMA = "warden.case.original-intent.v1"
@dataclass(frozen=True, slots=True)
class OriginalIntent:
"""Durable record of the original mutating dispatch, written before dispatch.
Binds the original Invocation (attempt, step, owner, target, actor, principal,
lane), all pins, the admitted adapter source and the tenant/realm provenance
the caller was admitted with. It is evidence of what Warden dispatched, not
owner proof of creation: owners still authenticate created-only provenance.
"""
binding: str
invocation: Invocation
source: str
def payload(self) -> str:
return json.dumps(
{"schema": INTENT_SCHEMA, "binding": self.binding, "source": self.source}
| asdict(self.invocation),
separators=(",", ":"),
sort_keys=True,
)
@classmethod
def decode(cls, raw: str) -> OriginalIntent:
obj = json.loads(raw)
fields = {f for f in Invocation.__dataclass_fields__}
if set(obj) != fields | {"schema", "binding", "source"} or obj["schema"] != INTENT_SCHEMA:
raise Refused("unknown original intent schema")
inv = {k: obj[k] for k in fields}
inv["pins"] = Pins(**inv["pins"])
return cls(obj["binding"], Invocation(**inv), obj["source"])
@dataclass(frozen=True, slots=True)
class ReconcileContext:
"""Original intent and the new reconciliation attempt, kept separate."""
original: OriginalIntent
attempt: Invocation
@dataclass(frozen=True, slots=True)
class Adapter:
reference: str
source: str
invoke: Callable[[Invocation], OwnerResult]
verify: Callable[[Invocation, OwnerResult], bool]
rollback: Callable[[Invocation, tuple[str, ...]], OwnerResult] | None = None
reconcile: Callable[[Invocation], OwnerResult] | None = None
reconcile_original: Callable[[ReconcileContext], OwnerResult] | None = None
class Journal:
"""Private SQLite journal plus process lock; transaction commits before dispatch."""
def __init__(self, directory: Path):
directory.mkdir(mode=0o700, parents=True, exist_ok=True)
if (
directory.is_symlink()
or directory.stat().st_uid != os.getuid()
or directory.stat().st_mode & 0o077
):
raise Refused("journal directory is not private")
self.directory = directory
for name in ("journal.sqlite", "execution.lock"):
path = directory / name
fd = os.open(path, os.O_CREAT | os.O_RDWR | os.O_NOFOLLOW, 0o600)
try:
if os.fstat(fd).st_uid != os.getuid() or os.fstat(fd).st_mode & 0o077:
raise Refused("journal file is not private")
finally:
os.close(fd)
self.db = sqlite3.connect(directory / "journal.sqlite", isolation_level=None)
self.db.execute("PRAGMA synchronous=FULL")
self.db.execute(
"CREATE TABLE IF NOT EXISTS receipts (seq INTEGER PRIMARY KEY, binding TEXT NOT NULL, payload TEXT NOT NULL)"
)
self.db.execute(
"CREATE TABLE IF NOT EXISTS intents (seq INTEGER PRIMARY KEY, attempt_id TEXT NOT NULL UNIQUE, binding TEXT NOT NULL, payload TEXT NOT NULL)"
)
def original_intent(self, binding: str, current: Invocation, source: str) -> OriginalIntent:
"""Latest original run intent for binding, refused unless it matches exactly.
Missing or mismatched records refuse; the step stays uncertain.
"""
row = self.db.execute(
"SELECT payload FROM intents WHERE binding=? ORDER BY seq DESC LIMIT 1",
(binding,),
).fetchone()
if row is None:
raise Refused("original intent record missing; step stays uncertain")
intent = OriginalIntent.decode(row[0])
o = intent.invocation
if intent.binding != binding or o.operation != "run":
raise Refused("original intent binding mismatch")
if o.pins != current.pins:
raise Refused("original intent pins mismatch")
if intent.source != source:
raise Refused("original intent source mismatch")
for name in ("step", "owner", "target", "principal", "lane", "tenant", "realm"):
if getattr(o, name) != getattr(current, name):
raise Refused(f"original intent {name} mismatch")
return intent
@contextmanager
def locked(self):
with (self.directory / "execution.lock").open("rb") as fh:
try:
fcntl.flock(fh, fcntl.LOCK_EX | fcntl.LOCK_NB)
except BlockingIOError:
raise Refused("case execution already active") from None
try:
yield
finally:
fcntl.flock(fh, fcntl.LOCK_UN)
def load(self, binding: str, initial: StepState) -> StepState:
row = self.db.execute(
"SELECT payload FROM receipts WHERE binding=? ORDER BY seq DESC LIMIT 1",
(binding,),
).fetchone()
if row is None:
return initial
obj = json.loads(row[0])
expected = {
"step_id",
"owner",
"pins",
"allowed_created",
"retry_safe",
"receipts",
"journal_schema",
"evidence_digest",
"session_revoked",
"session_revocation_digest",
"grant_revocation_digest",
"attempt_id",
"operation",
}
if (
set(obj) != expected
or obj["journal_schema"] != "warden.case.step-journal.v1"
):
raise Refused("unknown journal receipt schema")
state = StepState(
obj["step_id"],
obj["owner"],
Pins(**obj["pins"]),
tuple(obj["allowed_created"]),
obj["retry_safe"],
tuple(
Receipt(r["attempt"], Outcome(r["outcome"]), tuple(r["created"]))
for r in obj["receipts"]
),
)
if (
state.step_id,
state.owner,
state.pins,
state.allowed_created,
state.retry_safe,
) != (
initial.step_id,
initial.owner,
initial.pins,
initial.allowed_created,
initial.retry_safe,
):
raise Refused("journal pins changed")
return state
def save(
self,
binding: str,
state: StepState,
evidence: OwnerResult | None = None,
invocation: Invocation | None = None,
intent: OriginalIntent | None = None,
):
self.db.execute("BEGIN IMMEDIATE")
try:
if intent is not None:
self.db.execute(
"INSERT INTO intents(attempt_id,binding,payload) VALUES (?,?,?)",
(intent.invocation.attempt_id, binding, intent.payload()),
)
self.db.execute(
"INSERT INTO receipts(binding,payload) VALUES (?,?)",
(
binding,
json.dumps(
asdict(state)
| {
"journal_schema": "warden.case.step-journal.v1",
"attempt_id": invocation.attempt_id if invocation else None,
"operation": invocation.operation if invocation else None,
"evidence_digest": digest(evidence.evidence.encode())
if evidence
else None,
"session_revoked": evidence.revoked if evidence else None,
"session_revocation_digest": digest(
evidence.session_revocation_evidence.encode()
)
if evidence and evidence.session_revocation_evidence
else None,
"grant_revocation_digest": digest(
evidence.grant_revocation_evidence.encode()
)
if evidence and evidence.grant_revocation_evidence
else None,
},
separators=(",", ":"),
),
),
)
self.db.execute("COMMIT")
except BaseException:
self.db.execute("ROLLBACK")
raise
class Executor:
"""Injected fixed owner adapters and provenance verifier; none ship by default.
evidence verifier must authenticate owner custody/provenance or explicitly
attest attended manual evidence; a bare JSON reference is never sufficient.
It receives purpose, exact source digest, and named evidence reference.
"""
def __init__(
self,
journal: Journal,
adapters: dict[str, Adapter],
evidence_verifier: Callable[[str, str, str], bool],
*,
browser_inputs: BrowserInputs | None = None,
):
self.journal, self.adapters, self.evidence_verifier = (
journal,
dict(adapters),
evidence_verifier,
)
self._admitted = {}
self.browser_inputs = browser_inputs
def admit(
self,
case_source: bytes,
type_source: bytes,
descriptor_source: bytes,
catalog_source: bytes,
*,
principal: str,
actor: str,
lane: str,
acceptance_evidence: str,
materialization_evidence: str,
descriptor_evidence: str,
session_evidence: str,
) -> tuple[Descriptor, Invocation, StepState]:
for source in (case_source, type_source, descriptor_source, catalog_source):
bounded_source(source)
descriptor = Descriptor.decode(descriptor_source)
try:
case = yaml.safe_load(case_source)["spec"]
case_type = yaml.safe_load(type_source)["spec"]
if not isinstance(case, dict) or not isinstance(case_type, dict):
raise ValueError
except (yaml.YAMLError, KeyError, TypeError, ValueError):
raise Refused("invalid case or type source shape") from None
if case.get("status") != "materialized" or not case.get("acceptance"):
raise Refused("case is not accepted and structurally materialized")
if case_type.get("status") not in ("acknowledged", "implemented"):
raise Refused("type is not acknowledged")
if case.get("type") != f"{case_type['id']}@{case_type['version']}":
raise Refused("case type pin mismatch")
if case_type.get("execution_descriptors", {}).get(descriptor.step) != digest(
descriptor_source
):
raise Refused(
"type has no exact acknowledged machine descriptor; plan only"
)
for purpose, source, evidence in (
("case-acceptance", digest(case_source), acceptance_evidence),
(
"ops-mason-materialization",
digest(case_source),
materialization_evidence,
),
(
"owner-descriptor-acceptance:" + descriptor.owner,
digest(descriptor_source),
descriptor_evidence,
),
("type-machine-seam-acceptance", digest(type_source), descriptor_evidence),
("catalog-routing-acceptance", digest(catalog_source), descriptor_evidence),
(
f"caller-session:{actor}:{principal}:{lane}",
digest(case_source),
session_evidence,
),
):
if (
not isinstance(evidence, str)
or not IDENTIFIER.fullmatch(evidence)
or self._verify_evidence(purpose, source, evidence) is not True
):
raise Refused("independent owner evidence not verified")
if (
not IDENTIFIER.fullmatch(principal)
or actor != descriptor.actor
or lane != descriptor.lane
):
raise Refused("principal actor or lane mismatch")
if descriptor.effect == "mint" and (
actor != "human" or os.getenv("WARDEN_AGENT_ID")
):
raise Refused("agent mint is forbidden")
parameters = case.get("parameters", {})
declared = {
item["name"]: item
for item in case_type.get("parameters", [])
if isinstance(item, dict) and isinstance(item.get("name"), str)
}
if (
not isinstance(parameters, dict)
or descriptor.target_parameter not in declared
):
raise Refused("target parameter is not declared by acknowledged type")
if case_type.get("id") == "oidc-browser-relying-party":
if type(self.browser_inputs) is not BrowserInputs:
raise Refused("browser metadata validator is not configured")
target = self.browser_inputs.target(
yaml.safe_load(case_source),
yaml.safe_load(type_source),
descriptor.target_parameter,
)
else:
for name in parameters:
definition = declared.get(name)
if (
definition is None
or definition.get("sensitivity") not in ("public", "operational")
or definition.get("case_settable") is False
):
raise Refused("unknown, fixed or secret-sensitivity case parameter")
target = parameters.get(descriptor.target_parameter)
if not isinstance(target, str) or not IDENTIFIER.fullmatch(target):
raise Refused("target must be exact case metadata")
adapter = self.adapters.get(descriptor.adapter)
if adapter is None or (adapter.reference, adapter.source) != (
descriptor.adapter,
descriptor.adapter_source,
):
raise Refused("unknown adapter or owner source pin")
sheet = json.dumps(
[
descriptor.step,
descriptor.owner,
target,
actor,
principal,
lane,
acceptance_evidence,
materialization_evidence,
descriptor_evidence,
session_evidence,
],
separators=(",", ":"),
).encode()
pins = Pins(
digest(case_source),
digest(type_source),
digest(descriptor_source),
digest(catalog_source),
digest(acceptance_evidence.encode()),
digest(sheet),
)
invocation = Invocation(
descriptor.step, descriptor.owner, target, actor, principal, lane, pins
)
initial = StepState(
descriptor.step,
descriptor.owner,
pins,
descriptor.allowed_created,
descriptor.retry_safe,
)
self._admitted[invocation] = (descriptor, initial, session_evidence)
return descriptor, invocation, initial
def _result(
self, adapter: Adapter, invocation: Invocation, result: OwnerResult
) -> OwnerResult:
if type(result) is not OwnerResult or not isinstance(result.outcome, Outcome):
raise Refused("unknown owner result shape")
if type(result.created) is not tuple or not all(
isinstance(v, str) and IDENTIFIER.fullmatch(v) for v in result.created
):
raise Refused("owner created-object result invalid")
if not isinstance(result.evidence, str) or not IDENTIFIER.fullmatch(
result.evidence
):
raise Refused("owner evidence identifier invalid")
if adapter.verify(invocation, result) is not True or result.revoked is not True:
raise Refused("owner result or session revocation unverified")
if (result.attempt_id, result.operation) != (
invocation.attempt_id,
invocation.operation,
):
raise Refused("owner receipt belongs to another attempt")
descriptor = self._admitted[
replace(invocation, attempt_id="", operation="admission")
][0]
proof_fields = {
"parent-session": (
f"session-revocation:{invocation.lane}:{invocation.operation}:{invocation.attempt_id}",
result.session_revocation_evidence,
),
"broker-grant": (
f"grant-revocation:{invocation.lane}:{invocation.operation}:{invocation.attempt_id}",
result.grant_revocation_evidence,
),
}
proofs = [proof_fields[scope] for scope in descriptor.revocation_scopes]
for purpose, evidence in proofs:
if (
not isinstance(evidence, str)
or not IDENTIFIER.fullmatch(evidence)
or self._verify_evidence(purpose, invocation.pins.case, evidence)
is not True
):
raise Refused("independent grant or parent-session revocation absent")
return result
def _verify_evidence(self, purpose, source, evidence):
try:
with contained_output():
return self.evidence_verifier(purpose, source, evidence) is True
except Exception:
raise Refused("independent evidence verification failed") from None
def _admission(
self, descriptor: Descriptor, invocation: Invocation, initial: StepState
):
if self._admitted.get(invocation, ())[:2] != (descriptor, initial):
raise Refused("execution requires verified admission on this executor")
adapter = self.adapters.get(descriptor.adapter)
if adapter is None or (adapter.reference, adapter.source) != (
descriptor.adapter,
descriptor.adapter_source,
):
raise Refused("adapter changed after admission")
session = self._admitted[invocation][2]
if (
self._verify_evidence(
f"caller-session:{invocation.actor}:{invocation.principal}:{invocation.lane}",
invocation.pins.case,
session,
)
is not True
):
raise Refused("caller session no longer verified")
if descriptor.effect == "mint" and os.getenv("WARDEN_AGENT_ID"):
raise Refused("agent mint is forbidden")
return adapter
def _attempt(self, invocation: Invocation, state: StepState, operation: str):
identity = json.dumps(
[asdict(invocation.pins), operation, state.last.attempt, uuid.uuid4().hex],
separators=(",", ":"),
).encode()
return replace(
invocation,
attempt_id="attempt-" + hashlib.sha256(identity).hexdigest(),
operation=operation,
)
def run(
self,
descriptor: Descriptor,
invocation: Invocation,
initial: StepState,
*,
retry=False,
) -> StepState:
adapter = self._admission(descriptor, invocation, initial)
with self.journal.locked():
binding = f"{invocation.step}:{invocation.target}"
state = self.journal.load(binding, initial)
recovered = recover(state)
if recovered != state:
self.journal.save(binding, recovered)
state = recovered
if len(state.receipts) > MAX_HISTORY - 4:
raise Refused("bounded journal history requires owner archival")
running = begin(state, invocation.pins, retry=retry)
dispatched = self._attempt(invocation, running, "run")
self.journal.save(
binding,
running,
invocation=dispatched,
intent=OriginalIntent(binding, dispatched, adapter.source),
)
evidence = None
try:
with contained_output():
result = self._result(
adapter, dispatched, adapter.invoke(dispatched)
)
completed = finish(
running, invocation.pins, result.outcome, created=result.created
)
evidence = result
except Exception:
completed = finish(running, invocation.pins, Outcome.UNCERTAIN)
self.journal.save(binding, completed, evidence, dispatched)
return completed
def rollback(
self, descriptor: Descriptor, invocation: Invocation, initial: StepState
) -> StepState:
adapter = self._admission(descriptor, invocation, initial)
with self.journal.locked():
binding = f"{invocation.step}:{invocation.target}"
state = self.journal.load(binding, initial)
if recover(state) != state:
self.journal.save(binding, recover(state))
raise Refused("lost rollback result requires owner reconciliation")
if adapter.rollback is None:
raise Refused("owner has no reviewed undo adapter")
if len(state.receipts) > MAX_HISTORY - 4:
raise Refused("bounded journal history requires owner archival")
running = begin_rollback(state, invocation.pins)
dispatched = self._attempt(invocation, running, "rollback")
self.journal.save(
binding,
running,
invocation=dispatched,
intent=OriginalIntent(binding, dispatched, adapter.source),
)
evidence = None
try:
with contained_output():
result = self._result(
adapter,
dispatched,
adapter.rollback(dispatched, running.last.created),
)
verified = result.outcome is Outcome.ROLLED_BACK and not result.created
evidence = result if verified else None
except Exception:
verified = False
completed = finish_rollback(running, invocation.pins, verified=verified)
self.journal.save(binding, completed, evidence, dispatched)
return completed
def reconcile(
self, descriptor: Descriptor, invocation: Invocation, initial: StepState
) -> StepState:
"""Explicit owner-native state inspection; never redispatches the mutation."""
adapter = self._admission(descriptor, invocation, initial)
if adapter.reconcile is None and adapter.reconcile_original is None:
raise Refused("owner reconciliation adapter absent")
with self.journal.locked():
binding = f"{invocation.step}:{invocation.target}"
state = recover(self.journal.load(binding, initial))
if not state.last or state.last.outcome not in (
Outcome.UNCERTAIN,
Outcome.FAILED_AFTER,
):
raise Refused("no uncertain mutation to reconcile")
if len(state.receipts) > MAX_HISTORY - 4:
raise Refused("bounded journal history requires owner archival")
state = replace(
state,
receipts=(
*state.receipts,
Receipt(len(state.receipts) + 1, Outcome.UNCERTAIN),
),
)
original = (
self.journal.original_intent(binding, invocation, adapter.source)
if adapter.reconcile_original is not None
else None
)
dispatched = self._attempt(invocation, state, "reconcile")
self.journal.save(binding, state, invocation=dispatched)
with contained_output():
result = self._result(
adapter,
dispatched,
adapter.reconcile_original(ReconcileContext(original, dispatched))
if original is not None
else adapter.reconcile(dispatched),
)
if result.outcome not in (
Outcome.NO_CHANGE,
Outcome.SUCCESS,
Outcome.FAILED_BEFORE,
):
raise Refused("owner did not reconcile target state")
# Validate created-object scope using the same closed result reducer.
finish(
begin(
StepState(
state.step_id,
state.owner,
state.pins,
state.allowed_created,
state.retry_safe,
),
state.pins,
),
state.pins,
result.outcome,
created=result.created,
)
reconciled = StepState(
state.step_id,
state.owner,
state.pins,
state.allowed_created,
state.retry_safe,
(
*state.receipts,
Receipt(len(state.receipts) + 1, result.outcome, result.created),
),
)
self.journal.save(binding, reconciled, result, dispatched)
return reconciled
class OwnerInterrupted(KeyboardInterrupt):
"""Sanitized interruption preserves persisted running/crash recovery semantics."""
def __init__(self):
super().__init__("owner execution interrupted")
class _Discard:
"""Never retain or forward adapter output, including unbounded malicious text."""
def write(self, text):
return len(text)
def flush(self):
pass

View file

@ -0,0 +1,700 @@
"""Injected owner harness; these receipts are not native owner attestations."""
from dataclasses import asdict, replace
import json
import os
import subprocess
import sys
import sqlite3
import pytest
import yaml
from warden.case_receipt_state import Outcome, Refused
from warden.case_run import Adapter, Descriptor, Executor, Journal, OwnerResult, digest
@pytest.fixture
def rig(tmp_path):
desc = Descriptor(
"warden.case.execution.v1",
"mint-secret",
"owner",
"owner/mint@v1",
"sha256:" + "1" * 64,
"human",
"issuer-lane",
"client_id",
"mint",
("case-policy", "case-role"),
True,
("parent-session", "broker-grant"),
)
descriptor = json.dumps(asdict(desc)).encode()
typ = yaml.safe_dump(
{
"spec": {
"id": "test",
"version": "1",
"status": "acknowledged",
"parameters": [
{
"name": "client_id",
"sensitivity": "operational",
"case_settable": True,
}
],
"execution_descriptors": {"mint-secret": digest(descriptor)},
}
}
).encode()
case = yaml.safe_dump(
{
"spec": {
"id": "case-test",
"type": "test@1",
"status": "materialized",
"acceptance": "acceptance",
"parameters": {"client_id": "fixture-client"},
}
}
).encode()
calls = []
def invoke(inv):
calls.append(inv)
return bound(
inv,
OwnerResult(
Outcome.SUCCESS,
"owner-receipt",
("case-policy", "case-role"),
True,
session_revocation_evidence="session-revoked",
grant_revocation_evidence="grant-revoked",
),
)
adapter = Adapter(
"owner/mint@v1",
desc.adapter_source,
invoke,
lambda inv, result: result.evidence == "owner-receipt",
lambda inv, objects: bound(
inv,
OwnerResult(
Outcome.ROLLED_BACK,
"owner-receipt",
(),
True,
session_revocation_evidence="session-revoked",
grant_revocation_evidence="grant-revoked",
),
),
lambda inv: bound(
inv,
OwnerResult(
Outcome.NO_CHANGE,
"owner-receipt",
(),
True,
session_revocation_evidence="session-revoked",
grant_revocation_evidence="grant-revoked",
),
),
)
verified = {
("case-acceptance", digest(case), "acceptance"),
("ops-mason-materialization", digest(case), "materialization"),
("owner-descriptor-acceptance:owner", digest(descriptor), "descriptor"),
("type-machine-seam-acceptance", digest(typ), "descriptor"),
("catalog-routing-acceptance", digest(b"catalog"), "descriptor"),
("caller-session:human:operator:issuer-lane", digest(case), "session"),
("session-revocation:issuer-lane", digest(case), "session-revoked"),
("grant-revocation:issuer-lane", digest(case), "grant-revoked"),
}
def verifier(purpose, source, evidence):
if purpose.startswith(("session-revocation:", "grant-revocation:")):
scope, lane, operation, attempt = purpose.split(":")
return (
source == digest(case)
and lane == "issuer-lane"
and operation in ("run", "rollback", "reconcile")
and evidence
== ("session-" if scope == "session-revocation" else "grant-") + attempt
)
return (purpose, source, evidence) in verified
executor = Executor(
Journal(tmp_path / "private"), {"owner/mint@v1": adapter}, verifier
)
kwargs = dict(
principal="operator",
actor="human",
lane="issuer-lane",
acceptance_evidence="acceptance",
materialization_evidence="materialization",
descriptor_evidence="descriptor",
session_evidence="session",
)
admitted = executor.admit(case, typ, descriptor, b"catalog", **kwargs)
return (executor, admitted, calls, (case, typ, descriptor, b"catalog"), kwargs)
def test_commit_running_is_visible_from_separate_connection_before_dispatch(rig):
executor, args, calls, _, _ = rig
old = executor.adapters[args[0].adapter]
def inspect(inv):
other = sqlite3.connect(executor.journal.directory / "journal.sqlite")
payload = json.loads(
other.execute(
"SELECT payload FROM receipts ORDER BY seq DESC LIMIT 1"
).fetchone()[0]
)
assert payload["receipts"][-1]["outcome"] == "running"
return old.invoke(inv)
executor.adapters[old.reference] = replace(old, invoke=inspect)
assert executor.run(*args).last.outcome is Outcome.SUCCESS
with pytest.raises(Refused):
executor.run(*args)
assert len(calls) == 1
def test_crash_and_fresh_process_resume_never_duplicates_effect(rig):
executor, args, calls, sources, kwargs = rig
old = executor.adapters[args[0].adapter]
def crash(inv):
calls.append(inv)
raise KeyboardInterrupt
executor.adapters[old.reference] = replace(old, invoke=crash)
with pytest.raises(KeyboardInterrupt):
executor.run(*args)
fresh = Executor(
Journal(executor.journal.directory),
{old.reference: old},
executor.evidence_verifier,
)
admitted = fresh.admit(*sources, **kwargs)
with pytest.raises(Refused):
fresh.run(*admitted, retry=True)
state = fresh.journal.load("mint-secret:fixture-client", admitted[2])
assert state.last.outcome is Outcome.UNCERTAIN
assert len(calls) == 1
def test_lost_result_preserved_and_cas_reconciliation_does_not_mint(rig):
executor, args, calls, _, _ = rig
old = executor.adapters[args[0].adapter]
def lost(inv):
calls.append(inv)
raise TimeoutError("SECRET-HIDDEN")
executor.adapters[old.reference] = replace(old, invoke=lost)
assert executor.run(*args).last.outcome is Outcome.UNCERTAIN
assert executor.reconcile(*args).last.outcome is Outcome.NO_CHANGE
with pytest.raises(Refused):
executor.run(*args, retry=True)
assert len(calls) == 1
assert (
b"SECRET-HIDDEN"
not in (executor.journal.directory / "journal.sqlite").read_bytes()
)
def test_failed_before_change_requires_explicit_retry_and_safe_owner(rig):
executor, args, calls, _, _ = rig
old = executor.adapters[args[0].adapter]
def no_change(inv):
calls.append(inv)
return bound(
inv,
OwnerResult(
Outcome.FAILED_BEFORE,
"owner-receipt",
(),
True,
session_revocation_evidence="session-revoked",
grant_revocation_evidence="grant-revoked",
),
)
executor.adapters[old.reference] = replace(old, invoke=no_change)
assert executor.run(*args).last.outcome is Outcome.FAILED_BEFORE
with pytest.raises(Refused):
executor.run(*args)
assert executor.run(*args, retry=True).last.outcome is Outcome.FAILED_BEFORE
assert len(calls) == 2
@pytest.mark.parametrize(
"result",
[
OwnerResult(
Outcome.SUCCESS,
"owner-receipt",
("shared-policy",),
True,
session_revocation_evidence="session-revoked",
grant_revocation_evidence="grant-revoked",
),
OwnerResult(
Outcome.SUCCESS,
"owner-receipt",
(),
False,
session_revocation_evidence="session-revoked",
grant_revocation_evidence="grant-revoked",
),
OwnerResult(
Outcome.SUCCESS,
"unknown-receipt",
(),
True,
session_revocation_evidence="session-revoked",
grant_revocation_evidence="grant-revoked",
),
{"outcome": "verified-success", "stdout": "SECRET-HIDDEN"},
],
)
def test_unknown_secret_payload_created_scope_or_missing_revocation_never_succeeds(
rig, result, capsys
):
executor, args, _, _, _ = rig
old = executor.adapters[args[0].adapter]
def malicious(inv):
print("SECRET-HIDDEN" * 1000)
return result
executor.adapters[old.reference] = replace(old, invoke=malicious)
assert executor.run(*args).last.outcome is Outcome.UNCERTAIN
assert capsys.readouterr().out == ""
assert (
b"SECRET-HIDDEN"
not in (executor.journal.directory / "journal.sqlite").read_bytes()
)
def test_rollback_reverses_only_verified_case_created_objects(rig):
executor, args, _, _, _ = rig
old = executor.adapters[args[0].adapter]
undos = []
def undo(inv, objects):
undos.append(objects)
return old.rollback(inv, objects)
executor.adapters[old.reference] = replace(old, rollback=undo)
executor.run(*args)
assert executor.rollback(*args).last.outcome is Outcome.ROLLED_BACK
assert undos == [("case-role", "case-policy")]
assert "shared-policy" not in undos[0]
def test_uncertain_rollback_cannot_replay(rig):
executor, args, _, _, _ = rig
old = executor.adapters[args[0].adapter]
executor.run(*args)
executor.adapters[old.reference] = replace(
old,
rollback=lambda inv, objs: bound(
inv,
OwnerResult(
Outcome.ROLLED_BACK,
"owner-receipt",
(),
False,
session_revocation_evidence="session-revoked",
grant_revocation_evidence="grant-revoked",
),
),
)
assert executor.rollback(*args).last.outcome is Outcome.ROLLBACK_UNCERTAIN
with pytest.raises(Refused):
executor.rollback(*args)
@pytest.mark.parametrize(
"change", ["materialization", "type-prose", "actor", "lane", "source", "target"]
)
def test_exact_admission_requires_owner_evidence_and_closed_source_pins(rig, change):
executor, _, _, sources, kwargs = rig
case, typ, descriptor, catalog = sources
kwargs = dict(kwargs)
if change == "materialization":
kwargs["materialization_evidence"] = "bare-json"
if change == "type-prose":
obj = yaml.safe_load(typ)
obj["spec"].pop("execution_descriptors")
typ = yaml.safe_dump(obj).encode()
if change == "actor":
kwargs["actor"] = "agent"
if change == "lane":
kwargs["lane"] = "other-lane"
if change == "source":
obj = json.loads(descriptor)
obj["adapter_source"] = "sha256:" + "2" * 64
descriptor = json.dumps(obj).encode()
if change == "target":
obj = yaml.safe_load(case)
obj["spec"]["parameters"]["client_id"] = "other-target"
case = yaml.safe_dump(obj).encode()
with pytest.raises(Refused):
executor.admit(case, typ, descriptor, catalog, **kwargs)
def test_agent_env_cannot_dispatch_after_human_admission(rig, monkeypatch):
executor, args, calls, _, _ = rig
monkeypatch.setenv("WARDEN_AGENT_ID", "test-agent")
with pytest.raises(Refused):
executor.run(*args)
assert calls == []
def test_forged_invocation_cannot_bypass_admission(rig):
executor, args, calls, _, _ = rig
with pytest.raises(Refused):
executor.run(args[0], replace(args[1], target="other-target"), args[2])
assert calls == []
def test_journal_rejects_unsafe_directory_and_symlink(tmp_path):
unsafe = tmp_path / "unsafe"
unsafe.mkdir(mode=493)
with pytest.raises(Refused):
Journal(unsafe)
private = tmp_path / "private"
private.mkdir(mode=448)
(private / "journal.sqlite").symlink_to(tmp_path / "outside")
with pytest.raises(OSError):
Journal(private)
def test_process_lock_blocks_parallel_dispatch(rig):
executor, args, calls, _, _ = rig
with executor.journal.locked():
with pytest.raises(Refused):
executor.run(*args)
assert calls == []
def test_changed_catalog_pins_cannot_inherit_old_success(rig):
executor, args, calls, sources, kwargs = rig
executor.run(*args)
with pytest.raises(Refused):
executor.admit(*sources[:3], b"changed-catalog", **kwargs)
assert len(calls) == 1
def test_private_journal_does_not_retain_owner_payload_or_accept_unknown_schema(rig):
executor, args, _, _, _ = rig
executor.run(*args)
row = executor.journal.db.execute(
"SELECT seq,payload FROM receipts ORDER BY seq DESC LIMIT 1"
).fetchone()
payload = json.loads(row[1])
assert payload["journal_schema"] == "warden.case.step-journal.v1"
assert payload["evidence_digest"] == digest(b"owner-receipt")
assert payload["session_revoked"] is True
assert "owner-receipt" not in row[1]
payload["stdout"] = "UNTRUSTED-OUTPUT"
executor.journal.db.execute(
"UPDATE receipts SET payload=? WHERE seq=?", (json.dumps(payload), row[0])
)
with pytest.raises(Refused):
executor.run(*args)
def test_expired_caller_session_cannot_use_cached_admission(rig):
executor, args, calls, _, _ = rig
old = executor.evidence_verifier
executor.evidence_verifier = lambda purpose, source, evidence: (
False
if purpose.startswith("caller-session:")
else old(purpose, source, evidence)
)
with pytest.raises(Refused):
executor.run(*args)
assert calls == []
@pytest.mark.parametrize("index", [0, 1, 2, 3])
def test_source_sizes_are_bounded_before_parsing(rig, index):
executor, _, _, sources, kwargs = rig
oversized = list(sources)
oversized[index] = b"x" * 262145
with pytest.raises(Refused, match="bounded"):
executor.admit(*oversized, **kwargs)
def test_owner_fd_and_inherited_subprocess_output_is_contained(rig, capfd):
executor, args, _, _, _ = rig
old = executor.adapters[args[0].adapter]
def leaking(inv):
os.write(1, b"SYNTHETIC-SECRET")
os.write(2, b"SYNTHETIC-SECRET")
subprocess.run([sys.executable, "-c", 'print("SYNTHETIC-SECRET")'], check=True)
return old.invoke(inv)
executor.adapters[old.reference] = replace(old, invoke=leaking)
assert executor.run(*args).last.outcome is Outcome.SUCCESS
observed = capfd.readouterr()
assert "SYNTHETIC-SECRET" not in observed.out + observed.err
def test_evidence_provider_output_and_error_never_escape(rig, capfd):
executor, _, calls, sources, kwargs = rig
def broken(*args):
print("SYNTHETIC-SECRET")
os.write(2, b"SYNTHETIC-SECRET")
raise RuntimeError("SYNTHETIC-SECRET")
executor.evidence_verifier = broken
with pytest.raises(Refused) as caught:
executor.admit(*sources, **kwargs)
assert "SYNTHETIC-SECRET" not in str(caught.value)
observed = capfd.readouterr()
assert "SYNTHETIC-SECRET" not in observed.out + observed.err
assert calls == []
@pytest.mark.parametrize("missing", ["session", "grant"])
def test_broker_grant_and_parent_session_have_separate_required_evidence(rig, missing):
executor, args, _, _, _ = rig
old = executor.adapters[args[0].adapter]
result = old.invoke(args[1])
if missing == "session":
result = replace(result, session_revocation_evidence=None)
else:
result = replace(result, grant_revocation_evidence=None)
executor.adapters[old.reference] = replace(old, invoke=lambda inv: result)
assert executor.run(*args).last.outcome is Outcome.UNCERTAIN
def test_mint_descriptor_cannot_omit_broker_grant_scope(rig):
descriptor = json.loads(rig[3][2])
descriptor["revocation_scopes"] = ["parent-session"]
with pytest.raises(Refused):
Descriptor.decode(json.dumps(descriptor).encode())
def test_unsafe_owner_step_cannot_retry_even_after_verified_failed_before(
rig, tmp_path
):
executor, args, _, sources, kwargs = rig
descriptor = replace(args[0], retry_safe=False)
descriptor_source = json.dumps(asdict(descriptor)).encode()
type_doc = yaml.safe_load(sources[1])
type_doc["spec"]["execution_descriptors"][descriptor.step] = digest(
descriptor_source
)
type_source = yaml.safe_dump(type_doc).encode()
old_verifier = executor.evidence_verifier
def verifier(purpose, source, evidence):
if purpose == "owner-descriptor-acceptance:owner":
return source == digest(descriptor_source) and evidence == "descriptor"
if purpose == "type-machine-seam-acceptance":
return source == digest(type_source) and evidence == "descriptor"
return old_verifier(purpose, source, evidence)
adapter = executor.adapters[descriptor.adapter]
def failed(inv):
return bound(
inv,
OwnerResult(
Outcome.FAILED_BEFORE,
"owner-receipt",
(),
True,
"session-revoked",
"grant-revoked",
),
)
fresh = Executor(
Journal(tmp_path / "unsafe-retry"),
{adapter.reference: replace(adapter, invoke=failed)},
verifier,
)
admitted = fresh.admit(
sources[0], type_source, descriptor_source, sources[3], **kwargs
)
assert fresh.run(*admitted).last.outcome is Outcome.FAILED_BEFORE
with pytest.raises(Refused):
fresh.run(*admitted, retry=True)
def bound(inv, result):
return replace(
result,
attempt_id=inv.attempt_id,
operation=inv.operation,
session_revocation_evidence=("session-" + inv.attempt_id)
if result.session_revocation_evidence
else None,
grant_revocation_evidence=("grant-" + inv.attempt_id)
if result.grant_revocation_evidence
else None,
)
def test_old_grant_and_session_proofs_cannot_verify_a_new_retry(rig):
executor, args, _, _, _ = rig
adapter = executor.adapters[args[0].adapter]
retained = []
def attempts(inv):
if not retained:
result = bound(
inv,
OwnerResult(
Outcome.FAILED_BEFORE,
"owner-receipt",
(),
True,
"session-revoked",
"grant-revoked",
),
)
retained.append(result)
return result
# Even a caller rewriting labels cannot authenticate prior revocation
# evidence for the newly persisted attempt identity.
return replace(retained[0], attempt_id=inv.attempt_id, operation=inv.operation)
executor.adapters[adapter.reference] = replace(adapter, invoke=attempts)
assert executor.run(*args).last.outcome is Outcome.FAILED_BEFORE
assert executor.run(*args, retry=True).last.outcome is Outcome.UNCERTAIN
def test_owner_interrupt_payload_is_sanitized_with_running_intent_retained(rig, capfd):
executor, args, _, _, _ = rig
adapter = executor.adapters[args[0].adapter]
def interrupted(inv):
os.write(2, b"SYNTHETIC-SECRET")
raise KeyboardInterrupt("SYNTHETIC-SECRET")
executor.adapters[adapter.reference] = replace(adapter, invoke=interrupted)
with pytest.raises(KeyboardInterrupt) as caught:
executor.run(*args)
assert "SYNTHETIC-SECRET" not in str(caught.value)
assert "SYNTHETIC-SECRET" not in "".join(capfd.readouterr())
assert (
executor.journal.load("mint-secret:fixture-client", args[2]).last.outcome
is Outcome.RUNNING
)
def test_attempt_identity_changes_with_exact_catalog_revision_and_new_journal(
rig, tmp_path
):
executor, args, calls, sources, kwargs = rig
executor.run(*args)
original_attempt = calls[-1].attempt_id
new_catalog = b"independently-reviewed-catalog-v2"
old_verifier = executor.evidence_verifier
def verifier(purpose, source, evidence):
if purpose == "catalog-routing-acceptance":
return source == digest(new_catalog) and evidence == "descriptor"
return old_verifier(purpose, source, evidence)
fresh = Executor(Journal(tmp_path / "new-revision"), executor.adapters, verifier)
revised = fresh.admit(*sources[:3], new_catalog, **kwargs)
assert fresh.run(*revised).last.outcome is Outcome.SUCCESS
assert calls[-1].attempt_id != original_attempt
assert calls[-1].pins.catalog != calls[0].pins.catalog
def test_secret_sensitivity_parameter_cannot_reach_admission_or_journal(rig):
executor, _, _, sources, kwargs = rig
type_doc = yaml.safe_load(sources[1])
type_doc["spec"]["parameters"][0]["sensitivity"] = "secret"
source = yaml.safe_dump(type_doc).encode()
old = executor.evidence_verifier
executor.evidence_verifier = lambda purpose, digest_value, evidence: (
True
if purpose == "type-machine-seam-acceptance"
else old(purpose, digest_value, evidence)
)
with pytest.raises(Refused, match="secret-sensitivity"):
executor.admit(sources[0], source, sources[2], sources[3], **kwargs)
def _lose_result(executor, args, calls):
old = executor.adapters[args[0].adapter]
def lost(inv):
calls.append(inv)
raise TimeoutError("lost")
seen = []
def by_original(ctx):
seen.append(ctx)
return old.reconcile(ctx.attempt)
executor.adapters[old.reference] = replace(
old, invoke=lost, reconcile=None, reconcile_original=by_original
)
assert executor.run(*args).last.outcome is Outcome.UNCERTAIN
return seen
def test_original_intent_survives_restart_separate_from_reconcile_attempt(rig):
executor, args, calls, _, _ = rig
seen = _lose_result(executor, args, calls)
executor.journal = Journal(executor.journal.directory) # restart: fresh handle
assert executor.reconcile(*args).last.outcome is Outcome.NO_CHANGE
(ctx,) = seen
original = ctx.original.invocation
assert original.attempt_id == calls[0].attempt_id
assert original.operation == "run" and ctx.attempt.operation == "reconcile"
assert ctx.attempt.attempt_id != original.attempt_id
assert original.pins == args[1].pins
assert (original.principal, original.tenant, original.realm) == (
args[1].principal,
args[1].tenant,
args[1].realm,
)
assert ctx.original.source == executor.adapters[args[0].adapter].source
def test_missing_original_intent_refuses_and_stays_uncertain(rig):
executor, args, calls, _, _ = rig
seen = _lose_result(executor, args, calls)
executor.journal.db.execute("DELETE FROM intents")
with pytest.raises(Refused, match="original intent record missing"):
executor.reconcile(*args)
assert seen == []
binding = f"{args[1].step}:{args[1].target}"
assert executor.journal.load(binding, args[2]).last.outcome is Outcome.UNCERTAIN
@pytest.mark.parametrize(
"change", [{"tenant": "other-tenant"}, {"realm": "other-realm"}, {"lane": "x"}]
)
def test_original_intent_mismatch_refuses(rig, change):
executor, args, calls, _, _ = rig
seen = _lose_result(executor, args, calls)
with pytest.raises(Refused):
executor.reconcile(args[0], replace(args[1], **change), args[2])
assert seen == []
def test_original_intent_source_mismatch_refuses(rig):
executor, args, calls, _, _ = rig
_lose_result(executor, args, calls)
binding = f"{args[1].step}:{args[1].target}"
with pytest.raises(Refused, match="source mismatch"):
executor.journal.original_intent(binding, calls[0], "other-source")

View file

@ -0,0 +1,131 @@
"""Observed source behavior of exact concurrent snapshot, not secure acceptance.
Counterexamples use generated metadata and the owner's existing synthetic rig.
Passing a counterexample means the documented gap reproduced; it is not a native
holder, an owner attestation or permission to trust local SQL/JSON.
"""
from dataclasses import asdict, replace
import inspect
import json
from pathlib import Path
import sqlite3
import subprocess
import sys
import pytest
from test_case_run import rig as rig
from warden.case_receipt_state import Outcome, Refused
from warden.case_run import Executor, Journal, OriginalIntent
def interrupted(rig):
executor,args,calls,sources,kwargs=rig
old=executor.adapters[args[0].adapter];seen=[]
def lost(inv):calls.append(inv);raise TimeoutError('generated lost response')
def original(ctx):seen.append(ctx);return old.reconcile(ctx.attempt)
executor.adapters[old.reference]=replace(old,invoke=lost,reconcile=None,reconcile_original=original)
assert executor.run(*args).last.outcome is Outcome.UNCERTAIN
return executor,args,calls,old,seen
def alter_payload(executor,**changes):
row=executor.journal.db.execute('SELECT seq,payload FROM intents ORDER BY seq DESC LIMIT 1').fetchone()
obj=json.loads(row[1]);obj.update(changes)
executor.journal.db.execute('UPDATE intents SET payload=? WHERE seq=?',(json.dumps(obj),row[0]))
def test_observed_original_actor_mismatch_is_accepted_by_lookup(rig):
executor,args,calls,old,_=interrupted(rig)
alter_payload(executor,actor='agent')
result=executor.journal.original_intent('mint-secret:fixture-client',args[1],old.source)
assert result.invocation.actor=='agent' and args[1].actor=='human'
def test_observed_payload_attempt_id_is_not_checked_against_sql_column_or_receipt(rig):
executor,args,calls,old,_=interrupted(rig)
actual=calls[0].attempt_id;alter_payload(executor,attempt_id='attempt-unrelated')
result=executor.journal.original_intent('mint-secret:fixture-client',args[1],old.source)
sql_id=executor.journal.db.execute('SELECT attempt_id FROM intents').fetchone()[0]
assert sql_id==actual and result.invocation.attempt_id=='attempt-unrelated'
def test_observed_orphan_intent_without_original_running_receipt_is_accepted(rig):
executor,args,calls,old,_=interrupted(rig)
executor.journal.db.execute('DELETE FROM receipts WHERE seq=(SELECT MIN(seq) FROM receipts)')
assert executor.journal.load('mint-secret:fixture-client',args[2]).last.outcome is Outcome.UNCERTAIN
result=executor.journal.original_intent('mint-secret:fixture-client',args[1],old.source)
assert result.invocation.attempt_id==calls[0].attempt_id
def test_observed_serializer_accepts_arbitrary_values_outside_normal_admit(rig):
_,args,_,_,_=rig
inv=replace(args[1],target={'unexpected':'synthetic-owner-payload'},operation='run',attempt_id='attempt-fixture')
record=OriginalIntent('mint-secret:fixture-client',inv,'sha256:'+'1'*64)
decoded=OriginalIntent.decode(record.payload())
assert decoded.invocation.target=={'unexpected':'synthetic-owner-payload'}
# This is a direct serialization API gap, not an observed normal-admit leak.
def test_observed_tenant_realm_not_admitted_and_remain_empty(rig):
_,args,_,_,_=rig
params=inspect.signature(Executor.admit).parameters
assert 'tenant' not in params and 'realm' not in params
assert args[1].tenant==args[1].realm==''
def test_observed_no_original_context_purpose_is_requested(rig):
executor,args,_,_,seen=interrupted(rig);old=executor.evidence_verifier;purposes=[]
def trace(purpose,source,evidence):purposes.append(purpose);return old(purpose,source,evidence)
executor.evidence_verifier=trace
assert executor.reconcile(*args).last.outcome is Outcome.NO_CHANGE
assert seen and any(p.startswith('session-revocation:') for p in purposes)
assert not any('original' in p for p in purposes)
# Owner trust is the existing synthetic fixture; this proves call shape only.
@pytest.mark.parametrize('field,value',[('principal','another-person'),('tenant','another-tenant'),('realm','another-realm')])
def test_existing_lookup_does_refuse_stored_principal_tenant_realm_mismatch(rig,field,value):
executor,args,_,old,_=interrupted(rig);alter_payload(executor,**{field:value})
with pytest.raises(Refused):executor.journal.original_intent('mint-secret:fixture-client',args[1],old.source)
def test_existing_atomic_insert_failure_prevents_dispatch_and_both_records(rig):
executor,args,calls,_,_=rig
executor.journal.db.execute("CREATE TRIGGER fail_receipt BEFORE INSERT ON receipts BEGIN SELECT RAISE(ABORT,'fixture'); END")
with pytest.raises(sqlite3.IntegrityError):executor.run(*args)
assert not calls
assert executor.journal.db.execute('SELECT COUNT(*) FROM intents').fetchone()==(0,)
assert executor.journal.db.execute('SELECT COUNT(*) FROM receipts').fetchone()==(0,)
def test_existing_missing_original_refuses_before_callback(rig):
executor,args,_,_,seen=interrupted(rig)
executor.journal.db.execute('DELETE FROM intents')
with pytest.raises(Refused):executor.reconcile(*args)
assert not seen
assert executor.journal.load('mint-secret:fixture-client',args[2]).last.outcome is Outcome.UNCERTAIN
def test_existing_current_parent_revocation_remains_mandatory(rig):
executor,args,_,_,_=interrupted(rig);old=executor.evidence_verifier
def refuse_session(purpose,source,evidence):
return False if purpose.startswith('session-revocation:') else old(purpose,source,evidence)
executor.evidence_verifier=refuse_session
with pytest.raises(Refused):executor.reconcile(*args)
assert executor.journal.load('mint-secret:fixture-client',args[2]).last.outcome is Outcome.UNCERTAIN
def test_existing_intent_survives_actual_distinct_interpreter(rig):
executor,args,calls,old,_=interrupted(rig)
code='''import json,sys
from pathlib import Path
from warden.case_run import Journal,Invocation
from warden.case_receipt_state import Pins
obj=json.load(sys.stdin);obj['pins']=Pins(**obj['pins']);j=Journal(Path(sys.argv[1]))
with j.locked():
i=j.original_intent('mint-secret:fixture-client',Invocation(**obj),sys.argv[2])
print(json.dumps({'attempt':i.invocation.attempt_id,'operation':i.invocation.operation}))
'''
result=subprocess.run([sys.executable,'-B','-c',code,str(executor.journal.directory),old.source],
input=json.dumps(asdict(args[1])),text=True,capture_output=True,timeout=15,
env={'PATH':'/usr/bin:/bin','PYTHONPATH':str(Path(__file__).parents[1]/'src'),'PYTHONDONTWRITEBYTECODE':'1'},check=True)
assert json.loads(result.stdout)=={'attempt':calls[0].attempt_id,'operation':'run'}

View file

@ -0,0 +1,289 @@
---
id: WARDEN-WP-0044
type: workplan
title: "Follow through on KnownSecurityCases along their type's route"
domain: infotech
repo: ops-warden
status: active
flavor: implementation
owner: claude-code
topic_slug: netkingdom
created: "2026-10-08"
updated: "2026-10-11"
depends_on: []
related_repos:
- net-kingdom
- ops-mason
- key-cape
- railiance-platform
state_hub_workstream_id: "f7e81013-6868-5d99-8528-ba75a442eca9"
---
# WARDEN-WP-0044 — Follow through on KnownSecurityCases along their type's route
## Why
NetKingdom is introducing SecurityCaseTypes (net-kingdom `NK-WP-0048`, canon
`security-case-types_v0.1`, proposed). Once a case of an implemented type is
accepted and ops-mason has materialized its structure (`MASON-WP-0010`),
ops-warden carries out the remaining steps. These are the owners' declared entry
points, run on the authentication path the type defines, followed by the type's
verification.
Today ops-warden routes needs and, for `exec_capable` lanes, proxies fetches as
the caller. It does not yet know about cases, and each new integration ends with
a founder running a hand-written script (for example the proposed KEY-WP-0038-T02
rollout). This plan gives ops-warden the follow-through role, without widening
what it may do: each step still runs under its owner's entry point and the
caller's identity.
## Tasks
```task
id: WARDEN-WP-0044-T01
status: done
depends_on: [NK-WP-0048-T03]
priority: high
state_hub_task_id: "ef0920fc-418e-52cb-acff-9a5c0c728bf5"
```
### T01 — Define the type's follow-through section
Propose the `follow_through` part of the SecurityCaseType schema together with
net-kingdom. For each step it names the owner entry point, `warden_executes`,
the auth method and lane, whether an attended human login is unavoidable (with
the type's justification), and the verification command. Write it for the first
type, `oidc-browser-relying-party`, covering key-cape client registration,
custody minting and LLDAP group membership.
2026-10-08: NK-WP-0048-T03/T04 landed with a drafted section. Review is in
`history/2026-10-08-oidc-rp-follow-through-review.md`. It requires three
changes before T02: a per-step `lane`, a narrow `warden_executes`, and
`value_handling`. It also lists four refinements. This task is done when
net-kingdom acknowledges the review (NK-WP-0048-T05).
2026-10-09: R4 was withdrawn in favour of ops-mason's per-case
`{consuming_service}-keycape-client`, with the entry body templated in the type
(R4′, see the addendum in the review).
2026-10-09: the revised 1.0 type and canon now carry R1–R3, R4′, R5–R7.
`warden case check-type <type.yaml>` (`src/warden/case_type.py`, tests in
`tests/test_case_type.py`) checks a type's follow-through mechanically: the
live type is schema-conformant, with one attended session
(`key-cape-oidc-login`). It is not yet plannable, because two lanes are not
in the catalog: `identity-provisioner-groups` (net-kingdom) and
`keycape-client-secret-generate` (railiance-platform). These gate T02, not
T01. T01 still closes on net-kingdom's acknowledgement (NK-WP-0048-T05).
2026-10-09: ops-warden cannot add `identity-provisioner-groups` as the type
declares it. The provisioner accepts only user-engine's runtime token and
admits only user-engine pods, so no caller-identity path exists. R8 (review
addendum) asks net-kingdom either to move `ensure-groups` into the existing
attended session (recommended) or to give the provisioner an operator
credential. `keycape-client-secret-generate` needs a generate-in-custody entry
point from railiance-platform, and the broker does not have one yet. Both were
sent to their owners.
2026-10-09: done. net-kingdom took R8 option 1, so `ensure-groups` runs attended
in the `register-client` session and `identity-provisioner-groups` is dropped
(net-kingdom `0e86f95`). The founder acknowledged the type with memo r4 (hub
decision `e418263e`, NK-WP-0048-T05 done).
```task
id: WARDEN-WP-0044-T02
status: done
depends_on: [WARDEN-WP-0044-T01]
priority: high
state_hub_task_id: "5f68c991-f490-58f8-a121-92f74073d272"
```
### T02 — Plan a case run
`warden case plan <case.yaml>` checks that the case is accepted and materialized,
resolves each step to its catalog entry and entry point, and prints the run:
which steps warden executes, which run as the attended caller, what the
verification is. No secret values; no execution.
Tests: refuse an unaccepted or unmaterialized case; refuse a step whose catalog
entry is missing or not reviewed; show attended steps explicitly.
2026-10-09: done. `warden case plan <case.yaml> [--type] [--json]`
(`src/warden/case_plan.py`, 14 tests in `tests/test_case_plan.py`). It refuses:
- a case that is not `materialized`, or has no acceptance record
- a type that is mismatched or not acknowledged
- any `case check-type` finding, including a missing or unreviewed lane
- undeclared, type-fixed or secret-sensitivity parameters
- a placeholder the case does not set, or an unsupported `when`
It fills type defaults (`issuer`), evaluates `<param> == <value>` conditions,
renders owner, entry point, auth and ready_check, groups attended steps per
lane, and lists the applicable verification.
The live Forgejo case is correctly refused: it is `accepted`, not
materialized. A materialized copy, with a stand-in lane for
`keycape-client-secret-generate`, renders six steps: two attended steps plus
`register-client` in one `key-cape-oidc-login` session, one warden step
(`mint-secret`), and two owner steps. Seven checks follow.
Observation for net-kingdom (not blocking): `bind-env` runs before
`register-client`, in type order. Its entry carries a literal
`KEYCAPE_<CLIENT_ID>_CLIENT_SECRET`, which is not a `{param}` placeholder, so it
reaches the plan unrendered.
2026-10-09 follow-up:
- **Format specs.** `_render` supports net-kingdom's `{param:env}` spec (upper
case, `-` as `_`, the same as `keycape-client.py env_name`) and refuses any
other spec or `!conversion`.
- **Case reference.** The plan prints `case-ref: <case_id>@sha256:<hex>` over the
case file's exact bytes. This is the reference proposed to railiance-platform
for `credential.py generate --case-ref` (RPF-WP-0054-T01); the broker
re-derives it from the file.
- 18 tests now.
```task
id: WARDEN-WP-0044-T03
status: progress
depends_on: [WARDEN-WP-0044-T02, MASON-WP-0010-T03]
blocking_reason: "Local durable execution kernel and injected failure harness implemented. Native acceptance still requires authenticated owner machine descriptors/adapters, actual Forgejo materialization receipt, contained session integration, ordered verification and first native run."
priority: high
state_hub_task_id: "bcbf6c91-2c04-5c16-ae8c-5d6c06fd6b89"
```
### T03 — Run and verify a case
`warden case run <case.yaml>` executes the plan. Owner entry points run through
the existing proxy as the caller; steps that need an attended login use the
existing contained login envelope (silent command, session revoked afterwards),
grouped into as few attended sessions as possible. Then it runs the type's
verification and writes a receipt without values. `warden case rollback`
reverses exactly this case's steps.
Acceptance: the Forgejo reference case (NK-WP-0048-T06) reaches `live` through
this path, with no case-specific script.
2026-10-17: original-intent lookup/context interface for NK-WP-0048-T15, source
and synthetic tests only. `src/warden/case_run.py`: `Executor.run` writes an
`OriginalIntent` (schema `warden.case.original-intent.v1`: the dispatched run
Invocation — attempt, step, owner, target, actor, principal, lane, all six pins,
tenant, realm — plus admitted adapter source) in the same SQLite transaction as
the pre-dispatch journal row. `Journal.original_intent(binding, current, source)`
returns it after restart and refuses on a missing record or any
pins/source/step/owner/target/principal/lane/tenant/realm mismatch, before any
journal write, so the step stays uncertain. An adapter's
`reconcile_original(ReconcileContext(original, attempt))` receives the original
intent separately from the new reconcile attempt. This is Warden's record of what
it dispatched, not owner created-only provenance; tenant/realm are as supplied at
admission. Owner descriptors/adapters, contained session integration, Forgejo
materialization and the native run remain open.
Agreed with railiance-platform (RPF-WP-0054-T01, 2026-10-09):
- `mint-secret` runs `credential.py generate --grant keycape/client-secret-generate
--client-id <id> --case-ref <case-ref> --case-file <case.yaml>` as the caller's
child process. The broker re-derives the case-ref and checks status and
client_id.
- warden refuses that step when `WARDEN_AGENT_ID` is set.
2026-10-10: railiance-platform implemented the command (RPF-WP-0054-T03). It is
catalogued as draft `keycape-client-secret-generate`, with `exec_owner`
railiance-platform and `exec_capable: false`. `warden case check-type` now
reports the lane as LANE-UNREVIEWED rather than LANE-MISSING. Before it can be
activated:
- the founder binds the issuer policy to the operator OIDC role
- key-cape confirms the secret format
- the RPF-WP-0054-T05 probe passes
2026-10-10 (later):
- **Broker lane.** The issuer role is bound (CCR-2026-0043) and the T05 probe
passed (railiance-platform `21b8af3`). Only key-cape's format confirmation is
left. The playbook now includes the issuer-role login, a 15m token with
unlimited uses that `warden case run` must group with the attended session.
- **Env spec.** net-kingdom adopted `{client_id:env}` as a 1.0 patch
(`9a9b8e3`). The plan renders `KEYCAPE_FORGEJO_CLIENT_SECRET`.
- **Forgejo case.** Rendered and built by ops-mason. It is not yet
`materialized`: MASON-WP-0010-T03 waits on the railiance-platform CCRs and
their founder apply.
2026-10-10: `keycape-client-secret-generate` activated on railiance-platform's
go-ahead (message 20973a9c) after key-cape confirmed the format (4e0213b3).
`warden case check-type` on the live type now reports `plannable=True`. The
only thing T03 still waits on is the Forgejo case reaching `materialized`
(MASON-WP-0010-T03).
2026-10-10: net-kingdom moved the type to 1.1 (`e2174ce`) and re-pinned the
Forgejo case. 1.1 adds the verification `consumer-enforces-groups` and requires
the hand-over to enforce `access_groups`. `check-type` on 1.1 reports
`plannable=True`, and a materialized copy renders six steps and the new check.
The case-ref digest covers the whole case file, including `status`, so it
changes when the case becomes `materialized`. `warden case run` therefore takes
it from the file at run time, and the broker re-derives it from the same file.
```task
id: WARDEN-WP-0044-T04
status: wait
depends_on: [WARDEN-WP-0044-T03]
blocking_reason: "Catalog integration follows a proven run."
priority: medium
state_hub_task_id: "4a0fa4a7-5ca9-518a-ab92-a79a5e2cf93e"
```
### T04 — Catalog entries from types
Let a type contribute reviewed catalog entries once, so that every case of that
type routes without a new catalog edit. Cases add parameter values, not routes.
`warden route find` should be able to answer "which SecurityCaseType covers this
need?" before anyone builds by hand.
2026-10-10 consolidation source prototype (not an accepted owner adapter API):
`src/warden/case_receipt_state.py` provides a pure immutable receipt reducer,
with exact case/type/adapter/catalog/acceptance/run-sheet pins, running intent
before dispatch, uncertain recovery after a lost result, no success replay,
explicit retry-safe failed-before-change retry and created-only reverse undo.
It executes nothing and accepts no command output. The caller must durably
persist running before any future side effect; storage/authenticated owner
receipts/live adapters are not implemented. Focused offline tests cover changed
pins, lost receipts, retry/refusal, uncertain rollback and shared-object
preservation. Source proposal: `docs/security-case-execution-proposal.md`.
T03 remains open: typed owner execution/receipt contracts require review, the
Forgejo structural materialization needs owner receipts, and CLI dispatch,
contained sessions, native verification and provenance remain unimplemented.
There is a circularity to resolve with net-kingdom/ops-mason: materialization
cannot require mint-secret if mint-secret is itself a follow-through step whose
planning requires materialized. No case status is changed by this prototype.
2026-10-11: the exact execution-design memo version1 has confirmed native human
acceptance (approval e46b149b-ec3c-4b3b-98a7-dcb4934448ca). The approved proposal
bytes remain unchanged. `src/warden/case_run.py` now implements a closed v1 local
execution seam, independent admission/evidence callbacks, private transactional
SQLite receipt storage, process locking, running-before-dispatch, crash recovery
to uncertainty, explicit safe retry, separately required broker-grant and parent-session revocation
proofs, native owner reconciliation and created-only
reverse rollback. Thirty-seven kernel tests and fourteen reducer tests pass;
ruff checks pass. See `docs/security-case-execution-kernel-v1.md` for exact scope
and receipt provenance. No installed native adapter or live CLI execution is
claimed. Current prose types stay plan-only; acknowledged descriptor/type machine
seams and authenticated owner/caller receipts are still required. T03 progresses
for implementation but cannot finish before ordered native Forgejo acceptance.
2026-10-16 source preparation (isolated checkout; no native acceptance):
T03's browser parameter mismatch now has a producer-validator-backed projection
in `case_inputs.py`, explicitly configured on the real Executor. Exact 1.1/1.2
parameter definitions and all four reviewed producer modules are pinned; full case
validation admits reviewed security-sensitive metadata while unknown/fixed/secret
inputs and type/producer drift refuse. Only the reviewed descriptor target
reaches the owner callback; no parameter journal payload is added. Actual
Executor/producer tests cover positive versions and refusal/containment paths.
Acknowledged machine descriptors, authenticated owner evidence, real Forgejo
materialization and contained native sessions remain mandatory and unimplemented;
T03 stays progress, T04 stays wait. No type or case status changed.
2026-10-16 producer source refresh: independently reviewed NetKingdom
`015694ee414c802dc2ef1fa0120dfed610086e69` optional descriptor-map repair.
Only the validator/evidence source pins change; exact parameter and transitive
source identity remain enforced. Actual canonical producer, Executor and reducer
suite passes 87 checks, including 14 new malformed-map integration cases; all
four missing/changed modules still refuse. Review:
`docs/reviews/2026-10-16-browser-producer-pin-refresh.md`. No adapter attestation,
native acceptance, credential use or privileged dispatch. T03 remains progress.

View file

@ -0,0 +1,57 @@
{
"observed_at": "2026-10-17T05:53:20.364253+00:00",
"owner": "ops-warden",
"canonical_head": "a45cf475bc4dbc929e0eecbc1f806a9229d934e2",
"sources": [
{
"path": "src/warden/case_run.py",
"base_head": "a45cf475bc4dbc929e0eecbc1f806a9229d934e2",
"base_sha256": "sha256:0574036ca7b74bdb9124f6af4888e63ec231ee60f5c9f34cbe2fb1acee39f671",
"worktree_sha256": "sha256:0574036ca7b74bdb9124f6af4888e63ec231ee60f5c9f34cbe2fb1acee39f671",
"dirty": false
},
{
"path": "src/warden/case_receipt_state.py",
"base_head": "a45cf475bc4dbc929e0eecbc1f806a9229d934e2",
"base_sha256": "sha256:a2cda7f187e77bd76d4d209505638de44a587fae0bc033ec75c23ee9ea9f73bc",
"worktree_sha256": "sha256:a2cda7f187e77bd76d4d209505638de44a587fae0bc033ec75c23ee9ea9f73bc",
"dirty": false
},
{
"path": "src/warden/case_inputs.py",
"base_head": "a45cf475bc4dbc929e0eecbc1f806a9229d934e2",
"base_sha256": "sha256:1334b0cd9897e763cfea2d306e997c659f3f284ecc3f9612140c2104835da7c7",
"worktree_sha256": "sha256:1334b0cd9897e763cfea2d306e997c659f3f284ecc3f9612140c2104835da7c7",
"dirty": false
},
{
"path": "src/warden/__init__.py",
"base_head": "a45cf475bc4dbc929e0eecbc1f806a9229d934e2",
"base_sha256": "sha256:047e0feba479474235f0707a207655ecfddfb33cd4f54069134419b8ca4ea24a",
"worktree_sha256": "sha256:047e0feba479474235f0707a207655ecfddfb33cd4f54069134419b8ca4ea24a",
"dirty": false
},
{
"path": "tests/test_case_run.py",
"base_head": "a45cf475bc4dbc929e0eecbc1f806a9229d934e2",
"base_sha256": "sha256:bc7264848e76e3576821523fec0c4925c4446eaf470f859fe245c98ea072d139",
"worktree_sha256": "sha256:bc7264848e76e3576821523fec0c4925c4446eaf470f859fe245c98ea072d139",
"dirty": false
},
{
"path": "docs/security-case-execution-kernel-v1.md",
"base_head": "a45cf475bc4dbc929e0eecbc1f806a9229d934e2",
"base_sha256": "sha256:0eb563dbaea739fba928d04708c2c2bdac592783bbe68e1271041b0d1b1994cb",
"worktree_sha256": "sha256:0eb563dbaea739fba928d04708c2c2bdac592783bbe68e1271041b0d1b1994cb",
"dirty": false
},
{
"path": "workplans/WARDEN-WP-0044-security-case-follow-through.md",
"base_head": "a45cf475bc4dbc929e0eecbc1f806a9229d934e2",
"base_sha256": "sha256:44686df53dac792e46791878c3ccf8c187bb14e2de33eeac411be2005f7f2aa1",
"worktree_sha256": "sha256:44686df53dac792e46791878c3ccf8c187bb14e2de33eeac411be2005f7f2aa1",
"dirty": false
}
],
"canonical_edits_performed": false
}

View file

@ -0,0 +1,37 @@
{
"observed_at": "2026-10-17T06:50:09.029792+00:00",
"base_head": "a45cf475bc4dbc929e0eecbc1f806a9229d934e2",
"origin_main": "a45cf475bc4dbc929e0eecbc1f806a9229d934e2",
"changed_paths": [
{
"path": "src/warden/case_run.py",
"before_sha256": "sha256:0574036ca7b74bdb9124f6af4888e63ec231ee60f5c9f34cbe2fb1acee39f671",
"after_sha256": "sha256:77e8117a1fb4e039815b555797778f7180f11e30f64cebe51b350b3eb7e46768"
},
{
"path": "tests/test_case_original_context_consistency.py",
"before_sha256": null,
"after_sha256": "sha256:10c5187cbc49222017319249ccb408816497ec6e006859d23003f3b2b375445b"
},
{
"path": "docs/security-case-execution-kernel-v1.md",
"before_sha256": "sha256:0eb563dbaea739fba928d04708c2c2bdac592783bbe68e1271041b0d1b1994cb",
"after_sha256": "sha256:e5570f542ec3ef4e6c11332cfe48fea16bf90cde5b9a5d926f5a068b7cafdbc7"
},
{
"path": "workplans/WARDEN-WP-0044-security-case-follow-through.md",
"before_sha256": "sha256:44686df53dac792e46791878c3ccf8c187bb14e2de33eeac411be2005f7f2aa1",
"after_sha256": "sha256:721a90b2ed8c896257c34a1451eb642cb8824c8263e37c483fb61b36adc54088"
}
],
"all_task_blocks_byte_identical": true,
"task_blocks": 4,
"unrelated_WORK_RECORDS_worktree_and_index_unchanged": true,
"diff_check": 0,
"status": " M WORK-RECORDS.md\n M docs/security-case-execution-kernel-v1.md\n M src/warden/case_run.py\n M workplans/WARDEN-WP-0044-security-case-follow-through.md\n?? tests/test_case_original_context_consistency.py\n",
"native_actions": false,
"commit_or_sync": false,
"git_metadata_edited": false,
"retained_packets_unchanged": true,
"refinement": "New test fixture import corrected for canonical tests package after retained failed collection; no source control was weakened."
}

View file

@ -0,0 +1,29 @@
{
"base_head": "a45cf475bc4dbc929e0eecbc1f806a9229d934e2",
"origin_main": "a45cf475bc4dbc929e0eecbc1f806a9229d934e2",
"paths": [
{
"path": "src/warden/case_run.py",
"existed": true,
"before_sha256": "sha256:0574036ca7b74bdb9124f6af4888e63ec231ee60f5c9f34cbe2fb1acee39f671"
},
{
"path": "tests/test_case_original_context_consistency.py",
"existed": false,
"before_sha256": null
},
{
"path": "docs/security-case-execution-kernel-v1.md",
"existed": true,
"before_sha256": "sha256:0eb563dbaea739fba928d04708c2c2bdac592783bbe68e1271041b0d1b1994cb"
},
{
"path": "workplans/WARDEN-WP-0044-security-case-follow-through.md",
"existed": true,
"before_sha256": "sha256:44686df53dac792e46791878c3ccf8c187bb14e2de33eeac411be2005f7f2aa1"
}
],
"status": " M WORK-RECORDS.md\n",
"unrelated_worktree_sha256": "sha256:b6af9b1cb21e3a64b2ef8a5e732bc35c39cdeaef6af7a18f24824e8ec9fb5a76",
"unrelated_index_sha256": "sha256:c61591efad763a3dcb86751f5bf46f03fec8a162bfe06c4272032fea15d2988f"
}