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 2s
Reject generated-only commits / generated-commit-guard (push) Successful in 13s

This commit is contained in:
codex 2026-11-01 22:46:55 +01:00
parent 3add9f8790
commit b53eed4073
43 changed files with 4653 additions and 0 deletions

View file

@ -0,0 +1,27 @@
{
"baseline_regressions": {
"failed": 5,
"passed": 2
},
"focused": {
"passed": 89,
"command": "python3 -m pytest -q tests/test_timestamp_precision.py tests/test_consume_provenance.py tests/test_execution_confirmation.py tests/test_cas.py tests/test_outbox.py tests/test_reconciliation.py"
},
"full": {
"passed": 298,
"failed": 1,
"failure": "tests/test_deploy_manifest.py::test_pinned_image_schema_drift_is_acknowledged",
"preexisting": "same 16e5d manifest vs 251941 historical release evidence mismatch previously reproduced unchanged"
},
"retained_refinement": "initial expiry regression issued already-expired object after repaired clock; corrected fixture issues before expiry and then advances; original failure not scored as code regression",
"patch_check_exit": 0,
"native_accepted": false,
"access_r3_review": {
"full_patch_sha256": "46bfeb706d3a88bf6054309cc9303eb360a91e57dda3b0fcbb7b80d551a75db6",
"source_hashes_matched": 31,
"independent_command": "go test -race -count=1 ./internal/decision ./cmd/access-engine -run TestTrusted",
"result": "passed",
"source_normalized_preapproval_proof": "../access-native-source/b2-b3/r3/actual-retained-python-source/receipt.json",
"independent_actual_immediate_cas_full_chain": "pending Secrets/Platform remeasurement; not claimed"
}
}

View file

@ -0,0 +1,57 @@
# Approval owner review of Access trusted source join
Disposition: **approved for Approval's source-fact contract only**, exact Access
patch `6079ed2ff40b131aa2c5efc8d33608ecb3475c8158f0486b44ec4469e9f222c1`.
All 30 frozen source file hashes match; vendored Approval helper files match
their owner pins. Access policy, other-owner behavior, trust/custody admission,
deployment and native effect are outside this review approval.
`owner-review.json` records the INTENT basis and live native gates.
`owner-review-record.patch` adds the Approval-owned T04 work record and formal
review after the helper package. It applies to that owner source without
canonical mutation; registrar-generated identifiers must be retained during
coordinator integration. The review ran from an isolated Approval checkout with
its instructions/intent loaded and work item created before the review.
Then apply `source-closure-after-review.patch` to close scoped WP0005 source
delivery. Sequential application was checked against the current canonical
workplan and preserves all four registrar-written UUIDs. It cites the exact
published helper commit and normal 7/7 reconciliation, including the receipt's
dirty-workplan/null revision and generated-only commit refusal. This closes no
native gate. `source-closure-manifest.json` records the exact evidence and hashes.
The source consumes the existing fixed GET claim endpoint with Bearer read
authority. Actual App enforces exact tenant before lookup. The exact shared
helper validates original and fetched claims separately at a post-I/O instant,
with stable act/PDP/declarations/validity correspondence and no refreshed request.
Source provenance stays outside the immutable submitted context and binds fetched
bytes, source/configuration and deadlines. Signing/deadline clamps do not turn
an observation into permission to execute.
Independent disposable actual Python App/TLS → actual Access serve proof:
- Service creates an approval, configured synthetic human binds it, and the
existing read route supplies a valid human-controlled PDP claim.
- Successful Check leaves Approval approved and emits no `use` event.
- Changing native target `1.0` to `1` keeps the legacy PDP digest equal but
refuses the native correspondence; no new decision record is written.
- A stale original observation cannot be rescued by a fresh valid provider.
- A read-scoped identity in a foreign store tenant is refused.
- Actual source revocation is fetched and refused despite the carried claim.
- Existing producer DecodeEnvelope/Verify validates the returned signature and
canonical equality with the recorded envelope; no new verifier algorithm.
The actual proof's source, binary and result hashes are pinned in `manifest.json`
and `actual-proof/source-dependencies.json`. Go race taskexecution/HTTP command
tests passed. An initial test-fixture0440 replacement permission failure is
retained; corrected test-only rotation passed without any reviewed source fix.
The local signature verifier's shared Go cache sandbox refusal is also retained
in validation evidence; the authorized retry passed.
This is synthetic source validation. StaticTokenAuthenticator and a disposable CA
prove mechanism, not KeyCape issuer admission or actual native source identity.
Installed source labels/paths are configuration, not proof of owner custody.
Exact native read client/profile/tenant/CA/server/image/config pins and actual
served PEP/CAS/journal/effect/cleanup remain existing APPROVAL-WP-0002-T01/T04/T05
and Secrets/Platform obligations. Same-digest historical consume evidence cannot
renew an expired original request or authorize replay after an unknown effect.

View file

@ -0,0 +1,40 @@
{
"approval_id": "aaaaaaaa-bbbb-4ccc-8ddd-eeeeeeeeeeee",
"binding": {
"action": "execute-ccr",
"actor": "secrets-engine",
"digest": "sha256:7639448d8f6c32fb677047a346206c521f3cb765c63b98bfac6043bf5eb0762b",
"human_control": true,
"pdp_digest": "sha256:7b91ba0487409fdbad42764fb95d10432bdb151a8a716ab1e947a3f861cad680",
"pdp_path": true,
"principal": "secrets-engine",
"purpose": "actual Python App source-only synthetic proof",
"target": {
"attributes": {
"numeric_kind_fixture": 1.0,
"stage": "prod"
},
"id": "catalog:synthetic",
"system": "secrets-engine",
"tenant": "tenant:platform",
"type": "secret-catalog-lane"
}
},
"consumed": false,
"freshness": {
"not_after": "2026-10-16T14:17:31+00:00",
"observed_at": "2026-10-16T14:16:31+00:00",
"ttl_seconds": 60
},
"issuer": "approval-engine",
"kind": "approval-claim",
"reason_code": "ok",
"schema_version": "0.1",
"state": "valid",
"valid_now": true,
"validity": {
"expires_at": "2026-10-16T14:19:30.803007+00:00",
"not_before": "2026-10-16T14:15:30.803007+00:00"
},
"yields_to": "net-kingdom taxonomy request-claim schema (statute \u00a717; unassigned)"
}

View file

@ -0,0 +1,27 @@
{
"scope": "disposable synthetic only",
"actual_source": "Approval App over TLS with authenticated create, configured synthetic human entry, read; actual SQLite engine",
"actual_access": "production serve binary from frozen B2/B3 R1",
"allow": true,
"original_context_unchanged": true,
"published_digest_match": true,
"returned_source_record_match": true,
"actual_source_revoke_refused": true,
"native_float_to_integer_drift_refused_despite_equal_pdp_digest": true,
"check_did_not_consume_approval": true,
"fresh_source_cannot_rescue_stale_original": true,
"foreign_store_tenant_read_refused": true,
"added_negative_http_statuses": {
"native_numeric_kind_drift": 500,
"stale_original": 500,
"foreign_store_tenant": 500
},
"no_record_after_refusal": true,
"native_admission": false,
"files_sha256": {
"source-record.json": "sha256:b4174adf927e4a9d1350d3c0f74657e6abd664ad4ffbd5066376e1d0b80da6e4",
"response.json": "sha256:b4174adf927e4a9d1350d3c0f74657e6abd664ad4ffbd5066376e1d0b80da6e4",
"original-approval-claim.json": "sha256:bc6ef42913c7e0ac55de722acf7643f8451f4f7ab484734a54de5bec310c15b6",
"request.json": "sha256:5da56e054c699627fd55b38156c6c91a50f9febc966fb9519207e9240bea5706"
}
}

View file

@ -0,0 +1,144 @@
{
"tenant": "tenant:platform",
"subject": {
"id": "secrets-engine",
"type": "service",
"tenant": "tenant:platform"
},
"action": "execute-ccr",
"resource": {
"id": "catalog:synthetic",
"type": "secret-catalog-lane",
"system": "secrets-engine",
"attributes": {
"stage": "prod",
"numeric_kind_fixture": 1.0
},
"tenant": "tenant:platform"
},
"context": {
"execution_contract": {
"backend_budget": {
"ttl_seconds": 120,
"uses": 12
},
"backend_origin": "http://127.0.0.1:18200",
"catalog_sha256": "sha256:290e55b2258d66980f9443ba7d1436adfc77b8814bd161004d5af2ba272bc9cc",
"ccr_id": "CCR-2099-0001",
"ccr_immutable_sha256": "sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"cluster_uid": "synthetic-not-native",
"contract_version": "SECRETS-EXEC-20261011-v1",
"execution_actor": "service:secrets-engine",
"execution_grant_ccr_id": "CCR-2099-0002",
"expected_after": "sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"expected_before": "sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"grant_immutable_sha256": "sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"operation": "metadata-apply-ccr",
"operation_deadline": "2026-10-16T14:18:11.115366+00:00",
"operation_id": "cbfbced0-09d5-48c8-a1e7-a2ea4dc69153",
"operations": [
{
"method": "GET",
"path": "sys/policies/acl/synthetic",
"payload_sha256": "sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
},
{
"method": "PUT",
"path": "sys/policies/acl/synthetic",
"payload_sha256": "sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
},
{
"method": "GET",
"path": "sys/policies/acl/synthetic",
"payload_sha256": "sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
},
{
"method": "GET",
"path": "auth/synthetic/role/synthetic",
"payload_sha256": "sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
},
{
"method": "PUT",
"path": "auth/synthetic/role/synthetic",
"payload_sha256": "sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
},
{
"method": "GET",
"path": "auth/synthetic/role/synthetic",
"payload_sha256": "sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
}
],
"source_bundle": {
"engine_dispatcher": {
"path": "/synthetic/engine_dispatcher.py",
"sha256": "sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
},
"platform_mediator": {
"path": "/synthetic/platform_mediator.py",
"sha256": "sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
},
"policy_auth": {
"path": "/synthetic/policy_auth.py",
"sha256": "sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
},
"typed_ccr": {
"path": "/synthetic/typed_ccr.py",
"sha256": "sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
}
}
},
"catalog_target": {
"lane": "synthetic",
"stage": "prod"
},
"human_control": true,
"service_actor_binding": {
"version": "proposed-service-task-caller/v1",
"transport_principal": "system:serviceaccount:secrets-engine:secrets-engine",
"subject_id": "secrets-engine",
"subject_type": "service",
"tenant": "tenant:platform"
},
"purpose": "actual Python App source-only synthetic proof",
"approval": {
"approval_id": "aaaaaaaa-bbbb-4ccc-8ddd-eeeeeeeeeeee",
"binding": {
"action": "execute-ccr",
"actor": "secrets-engine",
"digest": "sha256:7639448d8f6c32fb677047a346206c521f3cb765c63b98bfac6043bf5eb0762b",
"human_control": true,
"pdp_digest": "sha256:7b91ba0487409fdbad42764fb95d10432bdb151a8a716ab1e947a3f861cad680",
"pdp_path": true,
"principal": "secrets-engine",
"purpose": "actual Python App source-only synthetic proof",
"target": {
"attributes": {
"numeric_kind_fixture": 1.0,
"stage": "prod"
},
"id": "catalog:synthetic",
"system": "secrets-engine",
"tenant": "tenant:platform",
"type": "secret-catalog-lane"
}
},
"consumed": false,
"freshness": {
"not_after": "2026-10-16T14:17:31+00:00",
"observed_at": "2026-10-16T14:16:31+00:00",
"ttl_seconds": 60
},
"issuer": "approval-engine",
"kind": "approval-claim",
"reason_code": "ok",
"schema_version": "0.1",
"state": "valid",
"valid_now": true,
"validity": {
"expires_at": "2026-10-16T14:19:30.803007+00:00",
"not_before": "2026-10-16T14:15:30.803007+00:00"
},
"yields_to": "net-kingdom taxonomy request-claim schema (statute \u00a717; unassigned)"
}
}
}

View file

@ -0,0 +1,232 @@
{
"id": "decision:cd3bf7bad0422143",
"contract_version": "flex-auth.decision-record.v1",
"effect": "allow",
"reason": "exact_task_execution_matched",
"matched_policy_version": "v2",
"matched_rule": "exact_task_execution_matched",
"resource": {
"id": "catalog:synthetic",
"type": "secret-catalog-lane",
"system": "secrets-engine",
"tenant": "tenant:platform",
"attributes": {
"numeric_kind_fixture": 1.0,
"stage": "prod"
}
},
"subject": {
"id": "secrets-engine",
"type": "service",
"tenant": "tenant:platform"
},
"binding": {
"tenant": "tenant:platform",
"subject": {
"id": "secrets-engine",
"type": "service",
"tenant": "tenant:platform"
},
"action": "execute-ccr",
"resource": {
"id": "catalog:synthetic",
"type": "secret-catalog-lane",
"system": "secrets-engine",
"tenant": "tenant:platform",
"attributes": {
"numeric_kind_fixture": 1.0,
"stage": "prod"
}
},
"context": {
"approval": {
"approval_id": "aaaaaaaa-bbbb-4ccc-8ddd-eeeeeeeeeeee",
"binding": {
"action": "execute-ccr",
"actor": "secrets-engine",
"digest": "sha256:7639448d8f6c32fb677047a346206c521f3cb765c63b98bfac6043bf5eb0762b",
"human_control": true,
"pdp_digest": "sha256:7b91ba0487409fdbad42764fb95d10432bdb151a8a716ab1e947a3f861cad680",
"pdp_path": true,
"principal": "secrets-engine",
"purpose": "actual Python App source-only synthetic proof",
"target": {
"attributes": {
"numeric_kind_fixture": 1.0,
"stage": "prod"
},
"id": "catalog:synthetic",
"system": "secrets-engine",
"tenant": "tenant:platform",
"type": "secret-catalog-lane"
}
},
"consumed": false,
"freshness": {
"not_after": "2026-10-16T14:17:31+00:00",
"observed_at": "2026-10-16T14:16:31+00:00",
"ttl_seconds": 60
},
"issuer": "approval-engine",
"kind": "approval-claim",
"reason_code": "ok",
"schema_version": "0.1",
"state": "valid",
"valid_now": true,
"validity": {
"expires_at": "2026-10-16T14:19:30.803007+00:00",
"not_before": "2026-10-16T14:15:30.803007+00:00"
},
"yields_to": "net-kingdom taxonomy request-claim schema (statute \u00a717; unassigned)"
},
"catalog_target": {
"lane": "synthetic",
"stage": "prod"
},
"execution_contract": {
"backend_budget": {
"ttl_seconds": 120,
"uses": 12
},
"backend_origin": "http://127.0.0.1:18200",
"catalog_sha256": "sha256:290e55b2258d66980f9443ba7d1436adfc77b8814bd161004d5af2ba272bc9cc",
"ccr_id": "CCR-2099-0001",
"ccr_immutable_sha256": "sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"cluster_uid": "synthetic-not-native",
"contract_version": "SECRETS-EXEC-20261011-v1",
"execution_actor": "service:secrets-engine",
"execution_grant_ccr_id": "CCR-2099-0002",
"expected_after": "sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"expected_before": "sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"grant_immutable_sha256": "sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"operation": "metadata-apply-ccr",
"operation_deadline": "2026-10-16T14:18:11.115366+00:00",
"operation_id": "cbfbced0-09d5-48c8-a1e7-a2ea4dc69153",
"operations": [
{
"method": "GET",
"path": "sys/policies/acl/synthetic",
"payload_sha256": "sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
},
{
"method": "PUT",
"path": "sys/policies/acl/synthetic",
"payload_sha256": "sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
},
{
"method": "GET",
"path": "sys/policies/acl/synthetic",
"payload_sha256": "sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
},
{
"method": "GET",
"path": "auth/synthetic/role/synthetic",
"payload_sha256": "sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
},
{
"method": "PUT",
"path": "auth/synthetic/role/synthetic",
"payload_sha256": "sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
},
{
"method": "GET",
"path": "auth/synthetic/role/synthetic",
"payload_sha256": "sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
}
],
"source_bundle": {
"engine_dispatcher": {
"path": "/synthetic/engine_dispatcher.py",
"sha256": "sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
},
"platform_mediator": {
"path": "/synthetic/platform_mediator.py",
"sha256": "sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
},
"policy_auth": {
"path": "/synthetic/policy_auth.py",
"sha256": "sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
},
"typed_ccr": {
"path": "/synthetic/typed_ccr.py",
"sha256": "sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
}
}
},
"human_control": true,
"purpose": "actual Python App source-only synthetic proof",
"service_actor_binding": {
"subject_id": "secrets-engine",
"subject_type": "service",
"tenant": "tenant:platform",
"transport_principal": "system:serviceaccount:secrets-engine:secrets-engine",
"version": "proposed-service-task-caller/v1"
}
},
"request_digest": "sha256:5a6a2d1f4b2a6a791bf1da63cb0c9dfc107d6a00d5be80570be418a7afbdf469",
"approval_binding_digest": "sha256:7b91ba0487409fdbad42764fb95d10432bdb151a8a716ab1e947a3f861cad680",
"submitted_request_digest": "sha256:5a6a2d1f4b2a6a791bf1da63cb0c9dfc107d6a00d5be80570be418a7afbdf469"
},
"lifetime": {
"kind": "ttl",
"ttl": "15s",
"not_before": "2026-10-16T14:16:31Z",
"expires_at": "2026-10-16T14:16:46Z"
},
"diagnostics": {
"action": "execute-ccr",
"matched_relationship": "",
"policy_package": "secrets-engine.task-execution.service-pilot",
"policy_status": "proposed",
"registry_overrode": [],
"registry_resource": false,
"registry_subject": false
},
"provenance": {
"evaluator": "flex-auth/local",
"mode": "standalone",
"policy_package": "secrets-engine.task-execution.service-pilot",
"policy_version": "v2",
"policy_package_digest": "sha256:fc5a8769886b72006ba298bc0799741d0f1ed327dde9e36a6c35d26be4ea0bdc",
"registry_snapshot_digest": "sha256:44136fa355b3678a1146ad16f7e8649e94fb4fc21fe77e8310c060f61caaff8a",
"input_claim_digests": {
"context": "sha256:3d24a8e36f181f5843138bdc7388cea7673e34405662fadb2d2c02e6b976e41f"
},
"decision_time": "2026-10-16T14:16:31Z",
"approval_observation": {
"source_id": "synthetic-actual-approval-app",
"source_revision": "actual-owner-python-source-fixture",
"configuration_digest": "sha256:1dbfcebaa4267654828237f382d5b9070eaa91bdab43649923c8493629943dcf",
"claim_digest": "sha256:0b48130564c61d2ef2753e37c66763adb9c311b7e50d14ae9387f3c7ed9bb376",
"native_binding_digest": "sha256:7639448d8f6c32fb677047a346206c521f3cb765c63b98bfac6043bf5eb0762b",
"observed_at": "2026-10-16T14:16:31Z",
"not_after": "2026-10-16T14:17:31Z",
"validated_at": "2026-10-16T14:16:31.234881787Z"
},
"caller": {
"mode": "enforce",
"principal": "system:serviceaccount:secrets-engine:secrets-engine",
"audience": "flex-auth",
"not_after": "2026-10-16T14:18:30Z"
}
},
"signature": {
"mode": "signed",
"alg": "ed25519",
"kid": "synthetic-v2",
"value": "98SuexFSF4rnN0GHrZLQym-Jd5hI-Zq5UZuHcNXPKMw7qTqoI5DphubdYpITsvvhhpdE8BOR8PicMF50cx6TCg"
},
"caring": {
"profile": "caring-0.4.0-rc2",
"conformance_findings": [
{
"code": "CARING-DESCRIPTOR-MISSING",
"severity": "warning",
"message": "no CARING descriptor matched the request",
"fields": [
"caring_context"
]
}
]
}
}

View file

@ -0,0 +1 @@
{"existing_producer_signature_verified": true, "independent_synthetic_public_fixture": true, "returned_record_canonical_bytes_match": true, "new_signature_implementation": false}

View file

@ -0,0 +1,232 @@
{
"id": "decision:cd3bf7bad0422143",
"contract_version": "flex-auth.decision-record.v1",
"effect": "allow",
"reason": "exact_task_execution_matched",
"matched_policy_version": "v2",
"matched_rule": "exact_task_execution_matched",
"resource": {
"id": "catalog:synthetic",
"type": "secret-catalog-lane",
"system": "secrets-engine",
"tenant": "tenant:platform",
"attributes": {
"numeric_kind_fixture": 1.0,
"stage": "prod"
}
},
"subject": {
"id": "secrets-engine",
"type": "service",
"tenant": "tenant:platform"
},
"binding": {
"tenant": "tenant:platform",
"subject": {
"id": "secrets-engine",
"type": "service",
"tenant": "tenant:platform"
},
"action": "execute-ccr",
"resource": {
"id": "catalog:synthetic",
"type": "secret-catalog-lane",
"system": "secrets-engine",
"tenant": "tenant:platform",
"attributes": {
"numeric_kind_fixture": 1.0,
"stage": "prod"
}
},
"context": {
"approval": {
"approval_id": "aaaaaaaa-bbbb-4ccc-8ddd-eeeeeeeeeeee",
"binding": {
"action": "execute-ccr",
"actor": "secrets-engine",
"digest": "sha256:7639448d8f6c32fb677047a346206c521f3cb765c63b98bfac6043bf5eb0762b",
"human_control": true,
"pdp_digest": "sha256:7b91ba0487409fdbad42764fb95d10432bdb151a8a716ab1e947a3f861cad680",
"pdp_path": true,
"principal": "secrets-engine",
"purpose": "actual Python App source-only synthetic proof",
"target": {
"attributes": {
"numeric_kind_fixture": 1.0,
"stage": "prod"
},
"id": "catalog:synthetic",
"system": "secrets-engine",
"tenant": "tenant:platform",
"type": "secret-catalog-lane"
}
},
"consumed": false,
"freshness": {
"not_after": "2026-10-16T14:17:31+00:00",
"observed_at": "2026-10-16T14:16:31+00:00",
"ttl_seconds": 60
},
"issuer": "approval-engine",
"kind": "approval-claim",
"reason_code": "ok",
"schema_version": "0.1",
"state": "valid",
"valid_now": true,
"validity": {
"expires_at": "2026-10-16T14:19:30.803007+00:00",
"not_before": "2026-10-16T14:15:30.803007+00:00"
},
"yields_to": "net-kingdom taxonomy request-claim schema (statute \u00a717; unassigned)"
},
"catalog_target": {
"lane": "synthetic",
"stage": "prod"
},
"execution_contract": {
"backend_budget": {
"ttl_seconds": 120,
"uses": 12
},
"backend_origin": "http://127.0.0.1:18200",
"catalog_sha256": "sha256:290e55b2258d66980f9443ba7d1436adfc77b8814bd161004d5af2ba272bc9cc",
"ccr_id": "CCR-2099-0001",
"ccr_immutable_sha256": "sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"cluster_uid": "synthetic-not-native",
"contract_version": "SECRETS-EXEC-20261011-v1",
"execution_actor": "service:secrets-engine",
"execution_grant_ccr_id": "CCR-2099-0002",
"expected_after": "sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"expected_before": "sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"grant_immutable_sha256": "sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"operation": "metadata-apply-ccr",
"operation_deadline": "2026-10-16T14:18:11.115366+00:00",
"operation_id": "cbfbced0-09d5-48c8-a1e7-a2ea4dc69153",
"operations": [
{
"method": "GET",
"path": "sys/policies/acl/synthetic",
"payload_sha256": "sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
},
{
"method": "PUT",
"path": "sys/policies/acl/synthetic",
"payload_sha256": "sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
},
{
"method": "GET",
"path": "sys/policies/acl/synthetic",
"payload_sha256": "sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
},
{
"method": "GET",
"path": "auth/synthetic/role/synthetic",
"payload_sha256": "sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
},
{
"method": "PUT",
"path": "auth/synthetic/role/synthetic",
"payload_sha256": "sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
},
{
"method": "GET",
"path": "auth/synthetic/role/synthetic",
"payload_sha256": "sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
}
],
"source_bundle": {
"engine_dispatcher": {
"path": "/synthetic/engine_dispatcher.py",
"sha256": "sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
},
"platform_mediator": {
"path": "/synthetic/platform_mediator.py",
"sha256": "sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
},
"policy_auth": {
"path": "/synthetic/policy_auth.py",
"sha256": "sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
},
"typed_ccr": {
"path": "/synthetic/typed_ccr.py",
"sha256": "sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
}
}
},
"human_control": true,
"purpose": "actual Python App source-only synthetic proof",
"service_actor_binding": {
"subject_id": "secrets-engine",
"subject_type": "service",
"tenant": "tenant:platform",
"transport_principal": "system:serviceaccount:secrets-engine:secrets-engine",
"version": "proposed-service-task-caller/v1"
}
},
"request_digest": "sha256:5a6a2d1f4b2a6a791bf1da63cb0c9dfc107d6a00d5be80570be418a7afbdf469",
"approval_binding_digest": "sha256:7b91ba0487409fdbad42764fb95d10432bdb151a8a716ab1e947a3f861cad680",
"submitted_request_digest": "sha256:5a6a2d1f4b2a6a791bf1da63cb0c9dfc107d6a00d5be80570be418a7afbdf469"
},
"lifetime": {
"kind": "ttl",
"ttl": "15s",
"not_before": "2026-10-16T14:16:31Z",
"expires_at": "2026-10-16T14:16:46Z"
},
"diagnostics": {
"action": "execute-ccr",
"matched_relationship": "",
"policy_package": "secrets-engine.task-execution.service-pilot",
"policy_status": "proposed",
"registry_overrode": [],
"registry_resource": false,
"registry_subject": false
},
"provenance": {
"evaluator": "flex-auth/local",
"mode": "standalone",
"policy_package": "secrets-engine.task-execution.service-pilot",
"policy_version": "v2",
"policy_package_digest": "sha256:fc5a8769886b72006ba298bc0799741d0f1ed327dde9e36a6c35d26be4ea0bdc",
"registry_snapshot_digest": "sha256:44136fa355b3678a1146ad16f7e8649e94fb4fc21fe77e8310c060f61caaff8a",
"input_claim_digests": {
"context": "sha256:3d24a8e36f181f5843138bdc7388cea7673e34405662fadb2d2c02e6b976e41f"
},
"decision_time": "2026-10-16T14:16:31Z",
"approval_observation": {
"source_id": "synthetic-actual-approval-app",
"source_revision": "actual-owner-python-source-fixture",
"configuration_digest": "sha256:1dbfcebaa4267654828237f382d5b9070eaa91bdab43649923c8493629943dcf",
"claim_digest": "sha256:0b48130564c61d2ef2753e37c66763adb9c311b7e50d14ae9387f3c7ed9bb376",
"native_binding_digest": "sha256:7639448d8f6c32fb677047a346206c521f3cb765c63b98bfac6043bf5eb0762b",
"observed_at": "2026-10-16T14:16:31Z",
"not_after": "2026-10-16T14:17:31Z",
"validated_at": "2026-10-16T14:16:31.234881787Z"
},
"caller": {
"mode": "enforce",
"principal": "system:serviceaccount:secrets-engine:secrets-engine",
"audience": "flex-auth",
"not_after": "2026-10-16T14:18:30Z"
}
},
"signature": {
"mode": "signed",
"alg": "ed25519",
"kid": "synthetic-v2",
"value": "98SuexFSF4rnN0GHrZLQym-Jd5hI-Zq5UZuHcNXPKMw7qTqoI5DphubdYpITsvvhhpdE8BOR8PicMF50cx6TCg"
},
"caring": {
"profile": "caring-0.4.0-rc2",
"conformance_findings": [
{
"code": "CARING-DESCRIPTOR-MISSING",
"severity": "warning",
"message": "no CARING descriptor matched the request",
"fields": [
"caring_context"
]
}
]
}
}

View file

@ -0,0 +1,5 @@
{
"scope": "synthetic disposable fixture only; no native key admission",
"kid": "synthetic-v2",
"public_key": "Zs1gi5KLiOUODv6qM_rxxDzv4HKUsLh-n-CrpqPPdjM"
}

View file

@ -0,0 +1,109 @@
"""Disposable synthetic proof: actual Approval App HTTPS -> actual Access serve.
No native config, credential environment, approval or backend effect is used.
"""
import base64, hashlib, http.server, io, json, os, pathlib, socket, ssl, subprocess, sys, tempfile, threading, time
from datetime import datetime, timedelta, timezone
from dataclasses import replace
from wsgiref.simple_server import make_server, WSGIRequestHandler
from cryptography import x509
from cryptography.x509.oid import NameOID
from cryptography.hazmat.primitives import hashes, serialization
from cryptography.hazmat.primitives.asymmetric import rsa
sys.path.insert(0, '/home/worsch/approval-engine')
sys.path.insert(0, '/home/worsch/secrets-engine/src')
from approval_engine.binding import binding_digest
from approval_engine.api import App
from approval_engine.auth import Identity, StaticTokenAuthenticator
from approval_engine.store import Engine
from secrets_engine.authorization import request_digest, approval_binding_digest
from urllib.request import Request, urlopen
from urllib.error import HTTPError
OUT=pathlib.Path(sys.argv[1]);OUT.mkdir(exist_ok=True)
def digest(raw):return 'sha256:'+hashlib.sha256(raw).hexdigest()
def write(path,raw,mode=0o600):
if path.exists():path.chmod(0o600)
path.write_bytes(raw);path.chmod(mode)
def identity(subject,kind,scopes):return Identity(subject=subject,issuer='synthetic-test-only',audiences=('approval-engine',),principal_type=kind,tenant='tenant:platform',roles=frozenset(),scopes=frozenset(scopes),assurance={'level':'synthetic'},evidence_ref='synthetic-test-only',tenant_source='directory')
class Quiet(WSGIRequestHandler):
def log_message(self,*args):pass
class Review(http.server.BaseHTTPRequestHandler):
def do_POST(self):
raw=self.rfile.read(int(self.headers['Content-Length']));body=json.loads(raw)
assert self.path=='/apis/authentication.k8s.io/v1/tokenreviews'
assert self.headers['Authorization']=='Bearer synthetic-reviewer'
assert body['spec']['audiences']==['flex-auth','access-engine']
self.send_response(200);self.send_header('Content-Type','application/json');self.end_headers();self.wfile.write(json.dumps({'status':{'authenticated':True,'audiences':['flex-auth'],'user':{'username':'system:serviceaccount:secrets-engine:secrets-engine'}}}).encode())
def log_message(self,*args):pass
with tempfile.TemporaryDirectory(prefix='access-actual-python-source-') as folder:
root=pathlib.Path(folder);now=datetime.now(timezone.utc)
key=rsa.generate_private_key(public_exponent=65537,key_size=2048);name=x509.Name([x509.NameAttribute(NameOID.COMMON_NAME,'localhost')]);cert=(x509.CertificateBuilder().subject_name(name).issuer_name(name).public_key(key.public_key()).serial_number(x509.random_serial_number()).not_valid_before(now-timedelta(minutes=1)).not_valid_after(now+timedelta(hours=1)).add_extension(x509.SubjectAlternativeName([x509.DNSName('localhost')]),critical=False).sign(key,hashes.SHA256()))
ca=root/'ca.pem';private=root/'tls-key.pem';write(ca,cert.public_bytes(serialization.Encoding.PEM));write(private,key.private_bytes(serialization.Encoding.PEM,serialization.PrivateFormat.PKCS8,serialization.NoEncryption()))
tls=ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER);tls.load_cert_chain(ca,private)
ctx=ssl.create_default_context(cafile=str(ca))
def start(server):server.socket=tls.wrap_socket(server.socket,server_side=True);threading.Thread(target=server.serve_forever,daemon=True).start();return 'https://localhost:'+str(server.server_port)
review=http.server.HTTPServer(('127.0.0.1',0),Review);review_origin=start(review)
engine=Engine(root/'approval.sqlite3',freshness_ttl=60)
auth=StaticTokenAuthenticator({'synthetic-creator':identity('secrets-engine','service',{'approval:create'}),'synthetic-human':identity('synthetic-human','human',{'approval:approve'}),'synthetic-reader':identity('synthetic-access-reader','service',{'approval:read'}),'synthetic-foreign-reader':replace(identity('synthetic-foreign-reader','service',{'approval:read'}),tenant='tenant:foreign')})
app=App(engine,auth)
source=make_server('127.0.0.1',0,app,handler_class=Quiet);origin=start(source)
def source_call(method,path,body,token):
request=Request(origin+path,data=json.dumps(body).encode() if body is not None else None,method=method,headers={'Authorization':'Bearer '+token,'Content-Type':'application/json'})
with urlopen(request,context=ctx,timeout=3) as response:return response.status,json.load(response)
# Reuse existing owner interoperability contract generator; it has synthetic metadata only.
generated=subprocess.check_output([sys.executable,'/tmp/access-trusted-b2-b3/tools/service_task_execution_fixture.py'],env={'PATH':os.defpath})
request=json.loads(generated)['request'];request['subject']['tenant']='tenant:platform';request['resource']['tenant']='tenant:platform';request['context']['purpose']='actual Python App source-only synthetic proof';del request['context']['approval']
request['resource']['attributes']['numeric_kind_fixture']=1.0
native={'action':request['action'],'actor':'secrets-engine','principal':'secrets-engine','purpose':request['context']['purpose'],'target':request['resource']}
aid='aaaaaaaa-bbbb-4ccc-8ddd-eeeeeeeeeeee'
status,created=source_call('POST','/v1/approvals',{'id':aid,'binding':native,'validity':{'not_before':(now-timedelta(minutes=1)).isoformat(),'expires_at':(now+timedelta(minutes=3)).isoformat()},'required_count':1,'pdp_digest':approval_binding_digest(request),'pdp_path':True,'human_control':True},'synthetic-creator');assert status==201
status,_=source_call('POST',f'/v1/approvals/{aid}/entries',{},'synthetic-human');assert status==200
status,claim=source_call('GET',f'/v1/approvals/{aid}/claim',None,'synthetic-reader');assert status==200 and claim['valid_now'] is True and claim['binding']['human_control'] is True
request['context']['approval']=claim
seed=root/'seed';write(seed,base64.urlsafe_b64encode(bytes([19])*32).rstrip(b'='),0o440)
reviewer_token=root/'review-token';write(reviewer_token,b'synthetic-reviewer',0o440)
reader_token=root/'reader-token';write(reader_token,b'synthetic-reader',0o440)
registry=root/'registry.json';write(registry,b'{}')
config=root/'source.json';write(config,json.dumps({'source_id':'synthetic-actual-approval-app','source_revision':'actual-owner-python-source-fixture','origin':origin,'store_tenant':'tenant:platform','ca_file':str(ca),'token_file':str(reader_token)}).encode())
listener=socket.socket();listener.bind(('127.0.0.1',0));port=listener.getsockname()[1];listener.close()
record=root/'record.jsonl';url=f'http://127.0.0.1:{port}'
command=['/tmp/approval-owner-access-review-bin','serve','--addr',f'127.0.0.1:{port}','--registry',str(registry),'--policy','/tmp/access-trusted-b2-b3/examples/secrets-engine-service-task-execution-v2/policy_package.md','--log',str(record),'--caller-auth-mode','enforce','--caller-audience','flex-auth','--caller-kubernetes-url',review_origin,'--caller-reviewer-token-file',str(reviewer_token),'--caller-ca-file',str(ca),'--caller-binding','secrets-engine=system:serviceaccount:secrets-engine:secrets-engine','--envelope-signing-key-file',str(seed),'--envelope-signing-kid','synthetic-v2','--approval-source-file',str(config)]
child=subprocess.Popen(command,env={},stdout=subprocess.DEVNULL,stderr=subprocess.DEVNULL)
try:
for _ in range(100):
try:
with urlopen(url+'/healthz',timeout=.2):break
except Exception:time.sleep(.02)
jwt='synthetic.'+base64.urlsafe_b64encode(json.dumps({'exp':int((now+timedelta(minutes=2)).timestamp())}).encode()).decode().rstrip('=')+'.synthetic'
def check(value):
req=Request(url+'/v1/check',data=json.dumps(value).encode(),headers={'Authorization':'Bearer '+jwt,'Content-Type':'application/json'})
try:
with urlopen(req,timeout=5) as response:return response.status,response.read()
except HTTPError as error:return error.code,error.read()
status,raw=check(request);assert status==200,(status,raw)
response=json.loads(raw);assert response['effect']=='allow' and response['signature']['mode']=='signed'
assert response['binding']['context']==request['context'];assert response['binding']['submitted_request_digest']==request_digest(request);assert response['binding']['approval_binding_digest']==approval_binding_digest(request)
assert response['provenance']['approval_observation']['source_id']=='synthetic-actual-approval-app'
saved=record.read_bytes();assert json.loads(saved)==response
assert engine.get(aid).status=='approved'
assert not any(row['class']=='use' for row in engine.undrained())
# Integer/float drift is invisible to the legacy PDP digest, but native act must still refuse.
numeric=json.loads(json.dumps(request));numeric['resource']['attributes']['numeric_kind_fixture']=1
assert approval_binding_digest(numeric)==approval_binding_digest(request)
assert binding_digest({**native,'target':numeric['resource']})!=binding_digest(native)
numeric_status,_=check(numeric);assert numeric_status!=200 and record.read_bytes()==saved
# Independent Approval owner negative: valid fresh provider cannot renew a stale original observation.
stale=json.loads(json.dumps(request));stale['context']['approval']['freshness']={'observed_at':(now-timedelta(seconds=120)).isoformat(),'ttl_seconds':60,'not_after':(now-timedelta(seconds=60)).isoformat()}
stale_status,_=check(stale);assert stale_status!=200 and record.read_bytes()==saved
# Correct read scope but wrong store tenant is denied by actual App before object lookup.
write(reader_token,b'synthetic-foreign-reader',0o440)
tenant_status,_=check(request);assert tenant_status!=200 and record.read_bytes()==saved
write(reader_token,b'synthetic-reader',0o440)
# Actual producer state transition is fetched anew and cannot be rescued by carried claim.
engine.revoke(aid)
refused,_=check(request);assert refused!=200 and record.read_bytes()==saved
for name,value in [('request.json',request),('response.json',response),('source-record.json',json.loads(saved)),('original-approval-claim.json',claim)]:write(OUT/name,(json.dumps(value,indent=2)+'\n').encode(),0o644)
receipt={'scope':'disposable synthetic only','actual_source':'Approval App over TLS with authenticated create, configured synthetic human entry, read; actual SQLite engine','actual_access':'production serve binary from frozen B2/B3 R1','allow':True,'original_context_unchanged':True,'published_digest_match':True,'returned_source_record_match':True,'actual_source_revoke_refused':True,'native_float_to_integer_drift_refused_despite_equal_pdp_digest':True,'check_did_not_consume_approval':True,'fresh_source_cannot_rescue_stale_original':True,'foreign_store_tenant_read_refused':True,'added_negative_http_statuses':{'native_numeric_kind_drift':numeric_status,'stale_original':stale_status,'foreign_store_tenant':tenant_status},'no_record_after_refusal':True,'native_admission':False,'files_sha256':{p.name:digest(p.read_bytes()) for p in OUT.iterdir() if p.suffix=='.json'}}
write(OUT/'receipt.json',(json.dumps(receipt,indent=2)+'\n').encode(),0o644);print(json.dumps(receipt,indent=2))
finally:
child.terminate();child.wait(timeout=5);source.shutdown();review.shutdown();engine.close()

View file

@ -0,0 +1,71 @@
--- a/workplans/APPROVAL-WP-0005-access-claim-fact-contract.md
+++ b/workplans/APPROVAL-WP-0005-access-claim-fact-contract.md
@@ -81,3 +81,32 @@
digest substitution, foreign review, runtime enable or live proof is invented.
T02 still owns independent source integration/handoff; existing T01/T05 native
residual obligations and actual Access conformance/integration remain unchanged.
+
+## Review Access trusted source join against Approval's fact boundary
+
+```task
+id: APPROVAL-WP-0005-T04
+status: done
+priority: high
+```
+
+Explicit bounded CUST-WP-0080 owner crossreview of Access B2/B3 frozen patch
+6079ed2ff40b131aa2c5efc8d33608ecb3475c8158f0486b44ec4469e9f222c1.
+Approval scope only: authenticated fixed claim endpoint/store isolation,
+original/fresh fact correspondence, exact helper pinning and factual deadline/
+provenance/consume boundary. Access policy, native trust and other-owner assent
+are excluded. Review and disposable actual App proof use synthetic identities;
+no canonical owner source, live credentials, approval or runtime is mutated.
+
+Approval-only disposition: approved for the exact source fact boundary, not
+Access policy, deployment, identity/custody admission or protected execution.
+Review entry: docs/reviews/2026-10-16-access-trusted-source-approval-owner-review.json.
+Frozen source/hash and exact helper pins verified. Independent actual Python
+App over TLS to actual Access serve passes, with numeric 1.0-to-1 drift refused
+despite equal legacy PDP digest, stale original refused despite fresh provider,
+foreign tenant read refused and actual source revocation refused. Denials append
+no decision record; successful Check leaves approval unconsumed/no use event.
+Existing producer signature verification and source record match pass. Go race
+taskexecution and actual HTTP command suites pass. Initial synthetic0440 token
+replacement fixture failure was corrected and retained; no reviewed source fix
+was required. Native T01/T04/T05 obligations and T02 integration stay open.
--- /dev/null
+++ b/docs/reviews/2026-10-16-access-trusted-source-approval-owner-review.json
@@ -0,0 +1,33 @@
+{
+ "reviewer": "approval-engine-owner (agent approval-engine, codex)",
+ "decision": "approved",
+ "comment": "INTENT Purpose, The Claim Shape and Consumption Ordering: the exact reviewed Access source reads factual Approval claims from the existing authenticated fixed endpoint and validates exact human/PDP act correspondence while preserving the submitted claim/context and original deadlines. Review under APPROVAL-WP-0005-T04 of Access patch SHA256 6079ed2ff40b131aa2c5efc8d33608ecb3475c8158f0486b44ec4469e9f222c1, with all manifest source hashes independently matched. This judgement approves only Approval-owned fact-source/correspondence boundaries; it grants no Access policy assent, native identity/custody admission, human approval, deployment or protected effect.",
+ "exact_reviewed_patch_sha256": "6079ed2ff40b131aa2c5efc8d33608ecb3475c8158f0486b44ec4469e9f222c1",
+ "source_file_hashes_matched": 30,
+ "approval_helper_files_exact": {
+ "canonical.go": "d48588fb26e9037c8e83421586b8a818f4c0a52afb874f3fadf7229fc971c282",
+ "claim.go": "007a2494f79c47c104635402407e9e68f17d8599d23e0f2c8ebf6cb1b47e3621",
+ "go.mod": "bb09c53ffea926fbfba6e580ed3bd71ca358575401717389b3c7c49c0c674b43",
+ "README.md": "5d936b7f3de87bbf4e946f0dc44823d2f69b62b4122b55b9064791b7a19fd4f5"
+ },
+ "approval_contract_findings": [
+ "GET /v1/approvals/{UUID}/claim with existing Bearer approval:read scope; exact service store tenant checked by actual App before lookup",
+ "Installed fixed HTTPS origin/customCA, no redirect/proxy and bounded strict JSON; configuration/source labels describe owner admission and cannot establish native admission by themselves",
+ "Both original and fetched facts independently validate at one post-I/O instant; exact nonfreshness authority matches; fetched observation never replaces carried context or renews original freshness",
+ "Native five-field digest independently recomputed; original/fetched digest plus actual approval-free PDP correspondence checked; native1.0/1 drift is refused even where legacy PDP digest conflates it",
+ "Decision provenance binds fetched-byte digest/source/config/native digest/observation/validation/deadline outside unchanged request; signature includes that provenance",
+ "Effective fact deadline is min original/source freshness and approval validity; Access further caps identity/operation/policy deadlines and rechecks before return",
+ "Access Check does not consume; approvals remain PIP state and PEP still owns one CAS before effect with original decision correspondence and separate live one-shot journal"
+ ],
+ "independent_proof": "actual-proof/receipt.json",
+ "independent_signature_proof": "actual-proof/signature-verification.json",
+ "retained_fixture_failure": "retained-fixture-failure.json",
+ "native_gates_still_open": [
+ "APPROVAL-WP-0002-T01 exact issuer/human-profile, requester/actor mapping and admitted schema/image/migration; synthetic StaticTokenAuthenticator is not native KeyCape evidence",
+ "Actual approval:read service identity/audience/storetenant custody and trustedCA/server/image/config source admission; source labels/config alone prove none of these",
+ "APPROVAL-WP-0002-T04 source/use outbox and actual audit receiver lifecycle/readback/reconciliation acceptance",
+ "APPROVAL-WP-0002-T05 named actual PEP, strict Secrets successor producer-format trust acceptance and Platform original CAS/journal/effect/cleanup proof at final integrated source pins"
+ ],
+ "source_policy_scope": "Access eligibility/policy and other-owner implementation are outside Approval approval",
+ "native_accepted": false
+}

View file

@ -0,0 +1,33 @@
{
"reviewer": "approval-engine-owner (agent approval-engine, codex)",
"decision": "approved",
"comment": "INTENT Purpose, The Claim Shape and Consumption Ordering: the exact reviewed Access source reads factual Approval claims from the existing authenticated fixed endpoint and validates exact human/PDP act correspondence while preserving the submitted claim/context and original deadlines. Review under APPROVAL-WP-0005-T04 of Access patch SHA256 6079ed2ff40b131aa2c5efc8d33608ecb3475c8158f0486b44ec4469e9f222c1, with all manifest source hashes independently matched. This judgement approves only Approval-owned fact-source/correspondence boundaries; it grants no Access policy assent, native identity/custody admission, human approval, deployment or protected effect.",
"exact_reviewed_patch_sha256": "6079ed2ff40b131aa2c5efc8d33608ecb3475c8158f0486b44ec4469e9f222c1",
"source_file_hashes_matched": 30,
"approval_helper_files_exact": {
"canonical.go": "d48588fb26e9037c8e83421586b8a818f4c0a52afb874f3fadf7229fc971c282",
"claim.go": "007a2494f79c47c104635402407e9e68f17d8599d23e0f2c8ebf6cb1b47e3621",
"go.mod": "bb09c53ffea926fbfba6e580ed3bd71ca358575401717389b3c7c49c0c674b43",
"README.md": "5d936b7f3de87bbf4e946f0dc44823d2f69b62b4122b55b9064791b7a19fd4f5"
},
"approval_contract_findings": [
"GET /v1/approvals/{UUID}/claim with existing Bearer approval:read scope; exact service store tenant checked by actual App before lookup",
"Installed fixed HTTPS origin/customCA, no redirect/proxy and bounded strict JSON; configuration/source labels describe owner admission and cannot establish native admission by themselves",
"Both original and fetched facts independently validate at one post-I/O instant; exact nonfreshness authority matches; fetched observation never replaces carried context or renews original freshness",
"Native five-field digest independently recomputed; original/fetched digest plus actual approval-free PDP correspondence checked; native1.0/1 drift is refused even where legacy PDP digest conflates it",
"Decision provenance binds fetched-byte digest/source/config/native digest/observation/validation/deadline outside unchanged request; signature includes that provenance",
"Effective fact deadline is min original/source freshness and approval validity; Access further caps identity/operation/policy deadlines and rechecks before return",
"Access Check does not consume; approvals remain PIP state and PEP still owns one CAS before effect with original decision correspondence and separate live one-shot journal"
],
"independent_proof": "actual-proof/receipt.json",
"independent_signature_proof": "actual-proof/signature-verification.json",
"retained_fixture_failure": "retained-fixture-failure.json",
"native_gates_still_open": [
"APPROVAL-WP-0002-T01 exact issuer/human-profile, requester/actor mapping and admitted schema/image/migration; synthetic StaticTokenAuthenticator is not native KeyCape evidence",
"Actual approval:read service identity/audience/storetenant custody and trustedCA/server/image/config source admission; source labels/config alone prove none of these",
"APPROVAL-WP-0002-T04 source/use outbox and actual audit receiver lifecycle/readback/reconciliation acceptance",
"APPROVAL-WP-0002-T05 named actual PEP, strict Secrets successor producer-format trust acceptance and Platform original CAS/journal/effect/cleanup proof at final integrated source pins"
],
"source_policy_scope": "Access eligibility/policy and other-owner implementation are outside Approval approval",
"native_accepted": false
}

View file

@ -0,0 +1,12 @@
{
"stage": "first independent proof attempt",
"failure": "PermissionError writing synthetic reader-token after fixture initially set0440",
"cause": "proof attempted in-place replacement without restoring fixture-owner write permission",
"repair": "test-only writer chmods own synthetic file0600, replaces bytes, then restores0440; no provider/Access source changed",
"passed_before_fixture_failure": [
"actual source positive signed response",
"native float/int drift refused despite equal PDP digest",
"stale original refused despite fresh provider"
],
"result": "not scored as complete; rerun required"
}

View file

@ -0,0 +1,43 @@
--- a/workplans/APPROVAL-WP-0005-access-claim-fact-contract.md
+++ b/workplans/APPROVAL-WP-0005-access-claim-fact-contract.md
@@ -6,3 +6,3 @@
repo: approval-engine
-status: active
+status: finished
flavor: implementation
@@ -43,3 +43,3 @@
id: APPROVAL-WP-0005-T02
-status: todo
+status: done
priority: high
@@ -48,4 +48,19 @@
-Coordinator reviews/integrates these source records. Access owns the thin Go
-reader/normalization and conformance implementation under FLEX-WP-0024-T06;
+Completed source integration and handoff: coordinator independently reviewed
+and integrated the exact contract/helper combined patch
+096de94db8afff6b429215d951a98b94cd501cc6a7e1c374420e546169df2179 as owner commit
+3485415b823faf4f3b682079195e186666b0ed2b. Integration receipt:
+the-custodian/docs/changes/netkingdom-target-2026-10-16/approval-go-fact/
+canonical-integration.json. Independent origin HEAD readback matched that commit.
+Normal State Hub reconciliation in the same directory's normal-sync.json
+completed bindings 7/7 and pushed the source commit, with zero failures/errors
+and seven warnings. The receipt's null source_revision/dirty_workplans and
+refused generated-only writeback commit are retained; registrar-written UUIDs
+are preserved. No clean exact-revision DB acknowledgement is inferred from that
+receipt. Coordinator Go suite, 14,114-case actual Python differential and two
+producer vector checks passed. Access received the agreed API, exact source pins
+and golden vectors; Approval T04 independently reviewed its frozen successor.
+Source publication, normal reconciliation and conformance handoff are complete;
+this closure update still follows coordinator review/commit/synchronization.
+Access owns successor reader/normalization integration under FLEX-WP-0024-T06;
Secrets owns strict immutable handoff and Platform owns provider origin/custody
@@ -116 +131,8 @@
was required. Native T01/T04/T05 obligations and T02 integration stay open.
+
+No scoped source work remains in APPROVAL-WP-0005 after T01-T04 delivery.
+Native issuer/provenance, audit delivery and actual served-PEP/CAS/effect gates
+remain existing live APPROVAL-WP-0002-T01/T04/T05 and Secrets/Access/Platform
+records. They are not newly discovered leftovers and need no duplicate residual
+record or broad promotion. This closure authorizes no credential, source trust,
+policy deployment, approval mutation or protected operation.

View file

@ -0,0 +1,33 @@
{
"source_commit": "3485415b823faf4f3b682079195e186666b0ed2b",
"publication_readback": "origin HEAD matched independently",
"sync_receipt": "../approval-go-fact/normal-sync.json",
"normal_sync_result": {
"bindings": "7/7",
"fail": 0,
"automation_error": 0,
"warn": 7,
"source_revision": null,
"source_revision_reason": "dirty_workplans",
"generated_only_writeback_commit": "refused; preserved"
},
"patch_sha256": "e74adc6f02c5400da083e071736c4814769678489c46043362d37a94c578a6e7",
"apply_after": "owner-review-record.patch",
"preserved_generated_ids": [
"777b17de-2c1e-5ce5-aa82-c99e5137e956",
"24bf384a-fdd0-566d-a1d3-5e89023a7521",
"3275354d-d781-53cf-aec6-975c0d4a601a",
"362bfe75-1cd7-5081-971b-b55ce483c802"
],
"final_task_statuses": [
"T01 done",
"T02 done",
"T03 done",
"T04 done"
],
"final_workplan_status": "finished",
"sequential_apply_check": "passed against exact current canonical workplan including all four generated UUIDs",
"canonical_written": false,
"native_accepted": false,
"residual_promotion": "none; existing WP0002 native obligations remain live"
}

View file

@ -0,0 +1,87 @@
---
id: APPROVAL-WP-0005
type: workplan
title: "Approval fact contract and reusable Go data adapter"
domain: infotech
repo: approval-engine
status: active
flavor: implementation
owner: codex
topic_slug: netkingdom
created: "2026-10-16"
updated: "2026-10-16"
depends_on: []
state_hub_workstream_id: "777b17de-2c1e-5ce5-aa82-c99e5137e956"
---
CUST-WP-0080 explicitly selects the necessary Approval-WP-0002-T01/T05 source
contract subset for the Access service HTTP B2 join. Initial scope is owner
review and producer fixtures; subsequent explicit CUST-WP-0080 demand selects
T03's pure reusable data adapter, agreed with Access before implementation.
No broad residual activation, credential transport runtime, trust admission,
policy eligibility or live action is included.
## Review authoritative claim guarantees and publish thin consumer vectors
```task
id: APPROVAL-WP-0005-T01
status: done
priority: high
state_hub_task_id: "24bf384a-fdd0-566d-a1d3-5e89023a7521"
```
INTENT basis: factual exact-bound approval claims supplied to Access, never a
second PDP. Source contract documents verified human-control semantics and their
issuer admission limit, both original/subsequent observation bounds, exact
native/PDP correspondence and immutable original submitted context. Producer
vectors cover current lifecycle and canonical types. The superseded proposal's
request-refresh design requires change; fresh facts are verified out-of-band.
## Independently integrate owner contract and coordinate Access reader conformance
```task
id: APPROVAL-WP-0005-T02
status: todo
priority: high
state_hub_task_id: "3275354d-d781-53cf-aec6-975c0d4a601a"
```
Coordinator reviews/integrates these source records. Access owns the thin Go
reader/normalization and conformance implementation under FLEX-WP-0024-T06;
Secrets owns strict immutable handoff and Platform owns provider origin/custody
and final client pin. Native issuer/profile and served-PEP obligations remain
live under APPROVAL-WP-0002-T01/T05, with audit under T04. No new native residual
is created, promoted or marked complete by these source-only fixtures.
## Supply producer-owned reusable Go claim and native binding data adapter
```task
id: APPROVAL-WP-0005-T03
status: done
priority: high
state_hub_task_id: "362bfe75-1cd7-5081-971b-b55ce483c802"
```
Explicit bounded implementation demand after Access confirmed the exact module
and raw-JSON API: adapters/go/approvalfact contains the existing Python-native
five-field canonicalization port and strict human/PDP-path typed claim validation
plus original/fresh fact matching. It is pure data code, not a source transport,
credential runtime, policy evaluator or consume service. Fact means validated
shape/correspondence, never authenticated provider origin.
Fourteen pinned native vectors and 24 claim cases pass in Go, with strict
duplicate/Unicode/type/expiry defenses and detached original bytes. A 14,114-case
deterministic differential corpus matches actual Python producer canonical bytes
and digests; Go race tests pass. This is source sample evidence, not exhaustive
proof or native acceptance. An initial module toolchain selection failure and
shared cache sandbox refusal are retained in preparation evidence; final module
uses Access's existing Go1.26.7 and completed tests.
Access explicitly retains the expected-native-raw-source correspondence gate:
its current decoded float64 maps cannot recover Python float/int identity.
The current pilot's raw resource may be used only with proof of no active target
registry override plus exact existing tenant normalization. Other enrichment
needs authoritative raw source/compiler representation. No numeric restriction,
digest substitution, foreign review, runtime enable or live proof is invented.
T02 still owns independent source integration/handoff; existing T01/T05 native
residual obligations and actual Access conformance/integration remain unchanged.

View file

@ -0,0 +1,138 @@
---
id: APPROVAL-WP-0005
type: workplan
title: "Approval fact contract and reusable Go data adapter"
domain: infotech
repo: approval-engine
status: finished
flavor: implementation
owner: codex
topic_slug: netkingdom
created: "2026-10-16"
updated: "2026-10-16"
depends_on: []
state_hub_workstream_id: "777b17de-2c1e-5ce5-aa82-c99e5137e956"
---
CUST-WP-0080 explicitly selects the necessary Approval-WP-0002-T01/T05 source
contract subset for the Access service HTTP B2 join. Initial scope is owner
review and producer fixtures; subsequent explicit CUST-WP-0080 demand selects
T03's pure reusable data adapter, agreed with Access before implementation.
No broad residual activation, credential transport runtime, trust admission,
policy eligibility or live action is included.
## Review authoritative claim guarantees and publish thin consumer vectors
```task
id: APPROVAL-WP-0005-T01
status: done
priority: high
state_hub_task_id: "24bf384a-fdd0-566d-a1d3-5e89023a7521"
```
INTENT basis: factual exact-bound approval claims supplied to Access, never a
second PDP. Source contract documents verified human-control semantics and their
issuer admission limit, both original/subsequent observation bounds, exact
native/PDP correspondence and immutable original submitted context. Producer
vectors cover current lifecycle and canonical types. The superseded proposal's
request-refresh design requires change; fresh facts are verified out-of-band.
## Independently integrate owner contract and coordinate Access reader conformance
```task
id: APPROVAL-WP-0005-T02
status: done
priority: high
state_hub_task_id: "3275354d-d781-53cf-aec6-975c0d4a601a"
```
Completed source integration and handoff: coordinator independently reviewed
and integrated the exact contract/helper combined patch
096de94db8afff6b429215d951a98b94cd501cc6a7e1c374420e546169df2179 as owner commit
3485415b823faf4f3b682079195e186666b0ed2b. Integration receipt:
the-custodian/docs/changes/netkingdom-target-2026-10-16/approval-go-fact/
canonical-integration.json. Independent origin HEAD readback matched that commit.
Normal State Hub reconciliation in the same directory's normal-sync.json
completed bindings 7/7 and pushed the source commit, with zero failures/errors
and seven warnings. The receipt's null source_revision/dirty_workplans and
refused generated-only writeback commit are retained; registrar-written UUIDs
are preserved. No clean exact-revision DB acknowledgement is inferred from that
receipt. Coordinator Go suite, 14,114-case actual Python differential and two
producer vector checks passed. Access received the agreed API, exact source pins
and golden vectors; Approval T04 independently reviewed its frozen successor.
Source publication, normal reconciliation and conformance handoff are complete;
this closure update still follows coordinator review/commit/synchronization.
Access owns successor reader/normalization integration under FLEX-WP-0024-T06;
Secrets owns strict immutable handoff and Platform owns provider origin/custody
and final client pin. Native issuer/profile and served-PEP obligations remain
live under APPROVAL-WP-0002-T01/T05, with audit under T04. No new native residual
is created, promoted or marked complete by these source-only fixtures.
## Supply producer-owned reusable Go claim and native binding data adapter
```task
id: APPROVAL-WP-0005-T03
status: done
priority: high
state_hub_task_id: "362bfe75-1cd7-5081-971b-b55ce483c802"
```
Explicit bounded implementation demand after Access confirmed the exact module
and raw-JSON API: adapters/go/approvalfact contains the existing Python-native
five-field canonicalization port and strict human/PDP-path typed claim validation
plus original/fresh fact matching. It is pure data code, not a source transport,
credential runtime, policy evaluator or consume service. Fact means validated
shape/correspondence, never authenticated provider origin.
Fourteen pinned native vectors and 24 claim cases pass in Go, with strict
duplicate/Unicode/type/expiry defenses and detached original bytes. A 14,114-case
deterministic differential corpus matches actual Python producer canonical bytes
and digests; Go race tests pass. This is source sample evidence, not exhaustive
proof or native acceptance. An initial module toolchain selection failure and
shared cache sandbox refusal are retained in preparation evidence; final module
uses Access's existing Go1.26.7 and completed tests.
Access explicitly retains the expected-native-raw-source correspondence gate:
its current decoded float64 maps cannot recover Python float/int identity.
The current pilot's raw resource may be used only with proof of no active target
registry override plus exact existing tenant normalization. Other enrichment
needs authoritative raw source/compiler representation. No numeric restriction,
digest substitution, foreign review, runtime enable or live proof is invented.
T02 still owns independent source integration/handoff; existing T01/T05 native
residual obligations and actual Access conformance/integration remain unchanged.
## Review Access trusted source join against Approval's fact boundary
```task
id: APPROVAL-WP-0005-T04
status: done
priority: high
```
Explicit bounded CUST-WP-0080 owner crossreview of Access B2/B3 frozen patch
6079ed2ff40b131aa2c5efc8d33608ecb3475c8158f0486b44ec4469e9f222c1.
Approval scope only: authenticated fixed claim endpoint/store isolation,
original/fresh fact correspondence, exact helper pinning and factual deadline/
provenance/consume boundary. Access policy, native trust and other-owner assent
are excluded. Review and disposable actual App proof use synthetic identities;
no canonical owner source, live credentials, approval or runtime is mutated.
Approval-only disposition: approved for the exact source fact boundary, not
Access policy, deployment, identity/custody admission or protected execution.
Review entry: docs/reviews/2026-10-16-access-trusted-source-approval-owner-review.json.
Frozen source/hash and exact helper pins verified. Independent actual Python
App over TLS to actual Access serve passes, with numeric 1.0-to-1 drift refused
despite equal legacy PDP digest, stale original refused despite fresh provider,
foreign tenant read refused and actual source revocation refused. Denials append
no decision record; successful Check leaves approval unconsumed/no use event.
Existing producer signature verification and source record match pass. Go race
taskexecution and actual HTTP command suites pass. Initial synthetic0440 token
replacement fixture failure was corrected and retained; no reviewed source fix
was required. Native T01/T04/T05 obligations and T02 integration stay open.
No scoped source work remains in APPROVAL-WP-0005 after T01-T04 delivery.
Native issuer/provenance, audit delivery and actual served-PEP/CAS/effect gates
remain existing live APPROVAL-WP-0002-T01/T04/T05 and Secrets/Access/Platform
records. They are not newly discovered leftovers and need no duplicate residual
record or broad promotion. This closure authorizes no credential, source trust,
policy deployment, approval mutation or protected operation.

View file

@ -0,0 +1,17 @@
{
"reviewed_patch_sha256": "6079ed2ff40b131aa2c5efc8d33608ecb3475c8158f0486b44ec4469e9f222c1",
"reviewed_source_hashes_matched": 30,
"go_race": {
"command": "go test -race -count=1 ./internal/taskexecution ./cmd/access-engine",
"result": "passed"
},
"actual_producer_proof": "actual-proof/receipt.json",
"signature_verifier": "Access existing internal/sign DecodeEnvelope+Verify; same synthetic public key fixture; response/source canonical equality",
"owner_review_record_patch_applies_after": "approval-go-fact/implementation.patch",
"patch_check_exit": 0,
"canonical_written": false,
"native_accepted": false,
"binary_sha256": "e0d0f4860363a468e82bc54eb4ae9e270bd508b582949206b58fb7e2e8ce0dd0",
"proof_script_sha256": "8b17be2da79cd1c458cc92e3a79b2247f0d6c8f0d90b59f349386369c5fca1eb",
"retained_tool_failure": "Signature verifier initially refused shared Go cache sandbox write; authorized local retry passed"
}

View file

@ -0,0 +1,134 @@
# First protected workflow: Audit Core admission packet
Prepared 2026-10-16 for TSA-09, AUDIT-WP-0013-T02, FLEX-WP-0031-T02/T06/T08,
SECRETS-WP-0013 and RPF-WP-0035-T12. This packet grants no sender, observer,
credential, deployment or protected effect authority. T02 remains waiting.
## Exact source and receiver compatibility
Reviewed Access source `0a05383195213e7eaacd08388ce1d7892ce756df`, particularly
`internal/emission/outbox.go` and `delivery.go`; Audit base
`2e97f37c01b583ac779310a2aa0d938bb9816604`. The protected consumer pin is
`flex-auth.secrets-engine`, distinct from generic `flex-auth` and other pins.
Access emits the existing eight-field contract in `docs/event-envelope.md`.
No translating adapter or second event schema is needed. Preserve event id,
Idempotency-Key, source, tenant, correlation, original time and data; the archive
does not authenticate a decision signature or establish approval validity.
Inventory: `flex-auth.decision.allow`, `.deny`, `.redact`, `.not_applicable`,
`.audit_only`, plus transport class `audit-core.heartbeat`. Heartbeat data.class
names one exact rare class, with assertion, committed and released_uncommitted
counts. Four heartbeats are four retained events, not four decision counts.
Outbox sequence and committed_at are local entry fields; the current wire event
has no stream_instance_id or sequence. Do not promise native receiver instance
filtering or wire sequence-gap detection for this source merely because the
receiver has that optional filter. Scope, lifetime and boundary are required
before comparing cumulative source counts.
The new isolated receiver tests exercise all five decision types: first202,
same-id duplicate200, changed-body409, write-only read403, independent fixture
readback, exact source/tenant, once-only counts and half-open acceptance-time
boundaries. They exercise wrong scope refusals and class-specific silence.
The identities and narrowed tenant:platform in tests are synthetic fixtures,
not proposed production grants. No live record or real decision validation is
claimed by these tests.
## Existing deployed evidence and its limit
Audit `docs/evidence/2026-10-15-cadence-admission/receiver-cadence-release-native.json`
records image `sha256:b479801b0bc76df66a36a85376c45aaf399c6d82feade9ba81430b774c4a8271`,
Deployment UID `b85fe3d0-75c9-4e0d-8c34-c6f1df0881bb`, source5227fb1 and
synthetic native cadence/heartbeat/exact-scope/SQLite/PostgreSQL feature probes.
The same folder records migration0007 and admitted Qonto/Approval metadata.
These are historical receiver capability receipts, not fresh flex-auth admission
or independent protected-workflow acceptance. Revalidate deployed image, readyz,
configuration metadata and migration compatibility before using them for native
acceptance. No production inspection was performed for this packet.
## Metadata prerequisites before any custody change
Access owner must return one reviewed per-pin registration payload and canonical
cadence bytes/digest for this pin, plus authoritative retained deployment source,
image, namespace `flex-auth`, exact AND namespace/pod selectors and configured
emission source. Do not derive pod selectors solely from a Helm release name.
Existing six-pin commitment in docs/cross-repo-evidence-admission.md requests
write true/read false, exact per-pin source, tenants ["*"] on the recorded
deny-before-tenant-creation justification, explicit redact and load-bearing.
This packet neither narrows that accepted scope to the fixture tenant nor widens
it; a revised scope requires its owner review. Retention/access/export policy
and owner must be explicit; an intake accepting custody is not that policy.
Current `docs/contracts/decision-emission-cadence.json` declares generic
source flex-auth, four heartbeat intervals86400 and allow expected_min1 per3600;
its source state and observer status remain pending. It is not a final per-pin
payload. Its daily source heartbeat cannot be registered as hourly f3600 without
an Access-owned runtime/declaration update and provenance. If hourly frame is
adopted, record f3600/wait7200/effective10800 and prove actual runtime adoption.
Do not silently apply Approval Engine's `cadence_registration.prepare`: that
helper deliberately validates source=approval-engine and its own class set.
The generic SenderRegistry parser already supports the reviewed flex-auth
metadata; custody tooling can validate an in-memory candidate with it.
Platform owns contained sender seed/delivery, registry CAS/readback/ESO reload,
transport and PVC admission. Resolve the actual usable custody route with
`warden route find` and `show` before any credential/access request. Historical
AUDIT-WP-0013-T02 names an unusable draft audit-core-senders route; do not assume
it is corrected. Obtain current route evidence and required scoped approval.
Never copy a registry/token to this packet or give a writer archive-read scope.
Receiver ingress must pair namespace AND exact pod selector to port8080;
source egress and receiver service DNS are separately admitted. Source-owned
single-writer flock/64MiB bound is source progress; actual mounted durable PVC,
restart, full/fenced failure, bounded drain and retained cursor need native proof.
## Native writer acceptance, followed by independent readback
1. Retain source/deployment/configuration pins, registry metadata version/digest,
source declaration digest, original exact change authorization and rollback.
Check accepted source/class/tenant/retention/secret policy inventory against
actual receiver configuration without exporting credentials.
2. Owner runs the approved bounded fixture through its contained existing lane.
Record durable event IDs, original correlation/decision/approval/operation
references, source class/tenant, local outbox identity/lifetime and entry
sequence/committed_at; retain before/after cursor, pending, lag, counters and
sanitized first202/duplicate200/refusal receipts. No new metadata operation
is authorized by this packet; where native effect is unadmitted, retain wait.
3. Exercise wrong source/tenant400, invalid/expired bearer401, writer read403,
payload conflict409 and formerly-valid bearer refusal after owner revocation.
A dead letter is not accepted custody and a source stdout202 is not readback.
4. Existing independently authorized read-only owner retrieves each exact ID via
GET /v1/events/{id}; compare source, tenant, action, correlation and normalized
original payload/hash, plus accepted_at. GET /v1/events?correlation_id=... can
enumerate related records within that reader's actual authorized scope.
Record reader identity/role separation metadata and original receiver receipt
references; credentials stay contained. Existing operator reader is evidence
of a past lane, not automatic current access. If no admitted scoped reader
exists, this gate waits on that owner; never upgrade the source writer.
5. Compare exact event-ID sets first: local committed records versus independently
retained records, after explicitly declared bounded drain lag. Missing pending
IDs are lag until the bound expires, then a finding; acknowledged-but-missing
IDs, conflicts and unexpected IDs are separate findings. Exclude four heartbeat
transport events from decision-effect totals. Preserve duplicate attempt counts
while accepted IDs count once. Keep nonzero released_uncommitted as a finding;
zero observed after restart does not establish its historical absence.
6. For aggregate GET /v1/reconciliation name exact source/tenant and explicit
[since,until) accepted_at bounds. Derive the local comparison set by the same
independently read accepted_at of the exact retained IDs, not occurred_at,
local commit time or a cumulative GET /v1/emission snapshot. Report unresolved
boundary arrivals separately and repeat after bounded drain. Source status
lacks tenant/window splits and persisted remote acceptance times; its raw
total cannot be compared to an arbitrary receiver time-window total. This
event-ID/accepted_at method closes a bounded admitted run without claiming a
general unattended reconciliation implementation. Concurrent unrelated writes
must be enumerated or isolated by an admitted outbox lifetime and exact IDs.
7. Independently observe four distinct rare-class heartbeats, actual configured
cadence and lag. A controlled withheld-heartbeat check belongs in an admitted
non-production exercise; do not suppress production evidence. Keep never-seen,
stale, missing-class, duplicate, count and boundary findings distinct. King's
Guard owns independent operational observer acceptance under KG-WP-0005.
Rollback restores only the exact earlier admitted scope/configuration, records
uncertain delivery and retains outbox/cursor/events. It never deletes evidence,
replays an uncertain protected effect, accepts unsigned decisions, widens a grant
or revives a revoked credential. Audit arrival proves custody after arrival;
neither arrival nor an empty finding set proves source completeness. Independent
chain-head/offsite custody remains AUDIT-WP-0015-T01's separate open boundary.

View file

@ -0,0 +1,183 @@
# First protected workflow: Audit Core admission packet
Prepared 2026-10-16 for TSA-09, AUDIT-WP-0013-T02, FLEX-WP-0031-T02/T06/T08,
SECRETS-WP-0013 and RPF-WP-0035-T12. This packet grants no sender, observer,
credential, deployment or protected effect authority. T02 remains waiting.
## Exact source and receiver compatibility
Reviewed Access source `0a05383195213e7eaacd08388ce1d7892ce756df`, particularly
`internal/emission/outbox.go` and `delivery.go`; Audit base
`2e97f37c01b583ac779310a2aa0d938bb9816604`. The protected consumer pin is
`flex-auth.secrets-engine`, distinct from generic `flex-auth` and other pins.
Access emits the existing eight-field contract in `docs/event-envelope.md`.
No translating adapter or second event schema is needed. Preserve event id,
Idempotency-Key, source, tenant, correlation, original time and data; the archive
does not authenticate a decision signature or establish approval validity.
Inventory: `flex-auth.decision.allow`, `.deny`, `.redact`, `.not_applicable`,
`.audit_only`, plus transport class `audit-core.heartbeat`. Heartbeat data.class
names one exact rare class, with assertion, committed and released_uncommitted
counts. Four heartbeats are four retained events, not four decision counts.
Outbox sequence and committed_at are local entry fields; the current wire event
has no stream_instance_id or sequence. Do not promise native receiver instance
filtering or wire sequence-gap detection for this source merely because the
receiver has that optional filter. Scope, lifetime and boundary are required
before comparing cumulative source counts.
The new isolated receiver tests exercise all five decision types: first202,
same-id duplicate200, changed-body409, write-only read403, independent fixture
readback, exact source/tenant, once-only counts and half-open acceptance-time
boundaries. They exercise wrong scope refusals and class-specific silence.
The identities and narrowed tenant:platform in tests are synthetic fixtures,
not proposed production grants. No live record or real decision validation is
claimed by these tests.
## Existing deployed evidence and its limit
Audit `docs/evidence/2026-10-15-cadence-admission/receiver-cadence-release-native.json`
records image `sha256:b479801b0bc76df66a36a85376c45aaf399c6d82feade9ba81430b774c4a8271`,
Deployment UID `b85fe3d0-75c9-4e0d-8c34-c6f1df0881bb`, source5227fb1 and
synthetic native cadence/heartbeat/exact-scope/SQLite/PostgreSQL feature probes.
The same folder records migration0007 and admitted Qonto/Approval metadata.
These are historical receiver capability receipts, not fresh flex-auth admission
or independent protected-workflow acceptance. Revalidate deployed image, readyz,
configuration metadata and migration compatibility before using them for native
acceptance. No production inspection was performed for this packet.
## Metadata prerequisites before any custody change
Access owner must return one reviewed per-pin registration payload and canonical
cadence bytes/digest for this pin, plus authoritative retained deployment source,
image, namespace `flex-auth`, exact AND namespace/pod selectors and configured
emission source. Do not derive pod selectors solely from a Helm release name.
Existing six-pin commitment in docs/cross-repo-evidence-admission.md requests
write true/read false, exact per-pin source, tenants ["*"] on the recorded
deny-before-tenant-creation justification, explicit redact and load-bearing.
This packet neither narrows that accepted scope to the fixture tenant nor widens
it; a revised scope requires its owner review. Retention/access/export policy
and owner must be explicit; an intake accepting custody is not that policy.
Current `docs/contracts/decision-emission-cadence.json` declares generic
source flex-auth, four heartbeat intervals86400 and allow expected_min1 per3600;
its source state and observer status remain pending. It is not a final per-pin
payload. Its daily source heartbeat cannot be registered as hourly f3600 without
an Access-owned runtime/declaration update and provenance. If hourly frame is
adopted, record f3600/wait7200/effective10800 and prove actual runtime adoption.
Do not silently apply Approval Engine's `cadence_registration.prepare`: that
helper deliberately validates source=approval-engine and its own class set.
The generic SenderRegistry parser already supports the reviewed flex-auth
metadata; custody tooling can validate an in-memory candidate with it.
Platform owns contained sender seed/delivery, registry CAS/readback/ESO reload,
transport and PVC admission. Resolve the actual usable custody route with
`warden route find` and `show` before any credential/access request. Historical
AUDIT-WP-0013-T02 names an unusable draft audit-core-senders route; do not assume
it is corrected. Obtain current route evidence and required scoped approval.
Never copy a registry/token to this packet or give a writer archive-read scope.
Receiver ingress must pair namespace AND exact pod selector to port8080;
source egress and receiver service DNS are separately admitted. Source-owned
single-writer flock/64MiB bound is source progress; actual mounted durable PVC,
restart, full/fenced failure, bounded drain and retained cursor need native proof.
## Native writer acceptance, followed by independent readback
1. Retain source/deployment/configuration pins, registry metadata version/digest,
source declaration digest, original exact change authorization and rollback.
Check accepted source/class/tenant/retention/secret policy inventory against
actual receiver configuration without exporting credentials.
2. Owner runs the approved bounded fixture through its contained existing lane.
Record durable event IDs, original correlation/decision/approval/operation
references, source class/tenant, local outbox identity/lifetime and entry
sequence/committed_at; retain before/after cursor, pending, lag, counters and
sanitized first202/duplicate200/refusal receipts. No new metadata operation
is authorized by this packet; where native effect is unadmitted, retain wait.
3. Exercise wrong source/tenant400, invalid/expired bearer401, writer read403,
payload conflict409 and formerly-valid bearer refusal after owner revocation.
A dead letter is not accepted custody and a source stdout202 is not readback.
4. Existing independently authorized read-only owner retrieves each exact ID via
GET /v1/events/{id}; compare source, tenant, action, correlation and normalized
original payload/hash, plus accepted_at. GET /v1/events?correlation_id=... can
enumerate related records within that reader's actual authorized scope.
Record reader identity/role separation metadata and original receiver receipt
references; credentials stay contained. Existing operator reader is evidence
of a past lane, not automatic current access. If no admitted scoped reader
exists, this gate waits on that owner; never upgrade the source writer.
5. Establish the full producer denominator before matching any chosen IDs. The
independent owner retains the complete producer outbox.jsonl snapshot, source
revision, outbox/PVC lifetime identity and bytes/SHA256/EOF high-water H. Check
every newline-terminated entry, contiguous seq1..H, exact source, unique event
IDs, valid committed_at and complete inventory including zero classes. Pin
drain cursor seq/offset, committed counters and pending/lag to that snapshot;
cursor must refer to a real entry boundary and never exceed H. This is an
independently retained full ledger, not a producer-selected list of successful
IDs. An arbitrary chosen-ID readback cannot satisfy this denominator. Retain
independent transition/effect-owner receipts too: an omitted transition never
queued by a compromised producer remains outside the archive guarantee.
Compare all ledger IDs versus independently retained receiver records, after
explicitly declared bounded drain lag. Missing pending
IDs are lag until the bound expires, then a finding; acknowledged-but-missing
IDs, conflicts and unexpected IDs are separate findings. Exclude four heartbeat
transport events from decision-effect totals. Preserve duplicate attempt counts
while accepted IDs count once. Keep nonzero released_uncommitted as a finding;
zero observed after restart does not establish its historical absence.
6. For aggregate GET /v1/reconciliation name exact source/tenant and explicit
[since,until) accepted_at bounds. Derive the local comparison set by the same
independently read accepted_at of the exact retained IDs, not occurred_at,
local commit time or a cumulative GET /v1/emission snapshot. Report unresolved
boundary arrivals separately and repeat after bounded drain. Source status
lacks tenant/window splits and persisted remote acceptance times; its raw
total cannot be compared to an arbitrary receiver time-window total. This
event-ID/accepted_at method supports a bounded admitted run without claiming a
general unattended reconciliation implementation. Compare the complete map of
all classes, including unexpected classes, against receiver aggregate counts:
all expected IDs must exist, and any receiver count above the independently
enumerated expected map is an unaccounted-record finding. This detects extras
without pretending GET-by-ID itself enumerates the receiver. Correlation search
has a1000 ceiling and no pagination; it is not a complete source export.
Concurrent arrivals require a second independently retained complete ledger
watermark H2 covering the same receiver window, or an approved quiescent
bounded run. Do not report agreement while that boundary remains unsettled.
Independently retained full snapshots, repeated cadence execution, actual
missing-class observation and independent observer adoption remain required
for operational TSA-09 acceptance; this packet alone closes none of them.
7. Independently observe four distinct rare-class heartbeats, actual configured
cadence and lag. A controlled withheld-heartbeat check belongs in an admitted
non-production exercise; do not suppress production evidence. Keep never-seen,
stale, missing-class, duplicate, count and boundary findings distinct. King's
Guard owns independent operational observer acceptance under KG-WP-0005.
Rollback restores only the exact earlier admitted scope/configuration, records
uncertain delivery and retains outbox/cursor/events. It never deletes evidence,
replays an uncertain protected effect, accepts unsigned decisions, widens a grant
or revives a revoked credential. Audit arrival proves custody after arrival;
neither arrival nor an empty finding set proves source completeness. Independent
chain-head/offsite custody remains AUDIT-WP-0015-T01's separate open boundary.
## Cross-owner accounting review — 2026-10-16
Access owner confirms the initial lifecycle signer slice keeps auditDelivery
disabled. Its current native package has no wire/accounting extension and makes
no G2/hourly-adoption claim. Audit owner accepts the complete independently
retained ledger + exact-ID readback + all-class receiver-count protocol above
for a bounded source-to-receiver reconciliation. A source self-selected receipt
list is insufficient. This is an evidence protocol using existing APIs, not a
new assertion format or permission. Audit has no current source-wide paginated
export endpoint or canonical producer-accounting receipt schema. Original owner
ledger bytes and receiver records are authoritative; a Custodian summary is not.
For future unattended monitoring, Access may separately propose durable
outbox-lifetime stream identity and sequence metadata, but must preserve signed
DecisionEnvelope bytes. A receiver-compatible wrapper would need a source-owned
versioned wire contract and fixture changes; post-sign insertion into decision
data is refused. An emitter restart is not automatically a new outbox lifetime.
No producer extension is mandatory for the bounded full-ledger protocol above;
repeated complete producer ledger capture/independent retention and source-owned
per-pin cadence/runtime adoption are mandatory operational work still missing.
The previously skipped existing cross-owner test was run directly from the real
canonical Audit checkout using its actual sibling NetKingdom/Approval fixtures:
`python3 -m pytest -q tests/test_cadence_registration.py::test_real_owner_proposal_when_checkout_available`
passed1. This makes114 tested cases across the focused isolated run and the
canonical owner-fixture check; the isolated run itself remains113 pass/1 skip.
No foreign source was changed (pytest cache writes were denied by the sandbox).

View file

@ -0,0 +1,257 @@
diff --git a/docs/flex-auth-secrets-engine-admission.md b/docs/flex-auth-secrets-engine-admission.md
new file mode 100644
index 0000000..6530d7f
--- /dev/null
+++ b/docs/flex-auth-secrets-engine-admission.md
@@ -0,0 +1,134 @@
+# First protected workflow: Audit Core admission packet
+
+Prepared 2026-10-16 for TSA-09, AUDIT-WP-0013-T02, FLEX-WP-0031-T02/T06/T08,
+SECRETS-WP-0013 and RPF-WP-0035-T12. This packet grants no sender, observer,
+credential, deployment or protected effect authority. T02 remains waiting.
+
+## Exact source and receiver compatibility
+
+Reviewed Access source `0a05383195213e7eaacd08388ce1d7892ce756df`, particularly
+`internal/emission/outbox.go` and `delivery.go`; Audit base
+`2e97f37c01b583ac779310a2aa0d938bb9816604`. The protected consumer pin is
+`flex-auth.secrets-engine`, distinct from generic `flex-auth` and other pins.
+Access emits the existing eight-field contract in `docs/event-envelope.md`.
+No translating adapter or second event schema is needed. Preserve event id,
+Idempotency-Key, source, tenant, correlation, original time and data; the archive
+does not authenticate a decision signature or establish approval validity.
+
+Inventory: `flex-auth.decision.allow`, `.deny`, `.redact`, `.not_applicable`,
+`.audit_only`, plus transport class `audit-core.heartbeat`. Heartbeat data.class
+names one exact rare class, with assertion, committed and released_uncommitted
+counts. Four heartbeats are four retained events, not four decision counts.
+Outbox sequence and committed_at are local entry fields; the current wire event
+has no stream_instance_id or sequence. Do not promise native receiver instance
+filtering or wire sequence-gap detection for this source merely because the
+receiver has that optional filter. Scope, lifetime and boundary are required
+before comparing cumulative source counts.
+
+The new isolated receiver tests exercise all five decision types: first202,
+same-id duplicate200, changed-body409, write-only read403, independent fixture
+readback, exact source/tenant, once-only counts and half-open acceptance-time
+boundaries. They exercise wrong scope refusals and class-specific silence.
+The identities and narrowed tenant:platform in tests are synthetic fixtures,
+not proposed production grants. No live record or real decision validation is
+claimed by these tests.
+
+## Existing deployed evidence and its limit
+
+Audit `docs/evidence/2026-10-15-cadence-admission/receiver-cadence-release-native.json`
+records image `sha256:b479801b0bc76df66a36a85376c45aaf399c6d82feade9ba81430b774c4a8271`,
+Deployment UID `b85fe3d0-75c9-4e0d-8c34-c6f1df0881bb`, source5227fb1 and
+synthetic native cadence/heartbeat/exact-scope/SQLite/PostgreSQL feature probes.
+The same folder records migration0007 and admitted Qonto/Approval metadata.
+These are historical receiver capability receipts, not fresh flex-auth admission
+or independent protected-workflow acceptance. Revalidate deployed image, readyz,
+configuration metadata and migration compatibility before using them for native
+acceptance. No production inspection was performed for this packet.
+
+## Metadata prerequisites before any custody change
+
+Access owner must return one reviewed per-pin registration payload and canonical
+cadence bytes/digest for this pin, plus authoritative retained deployment source,
+image, namespace `flex-auth`, exact AND namespace/pod selectors and configured
+emission source. Do not derive pod selectors solely from a Helm release name.
+Existing six-pin commitment in docs/cross-repo-evidence-admission.md requests
+write true/read false, exact per-pin source, tenants ["*"] on the recorded
+deny-before-tenant-creation justification, explicit redact and load-bearing.
+This packet neither narrows that accepted scope to the fixture tenant nor widens
+it; a revised scope requires its owner review. Retention/access/export policy
+and owner must be explicit; an intake accepting custody is not that policy.
+
+Current `docs/contracts/decision-emission-cadence.json` declares generic
+source flex-auth, four heartbeat intervals86400 and allow expected_min1 per3600;
+its source state and observer status remain pending. It is not a final per-pin
+payload. Its daily source heartbeat cannot be registered as hourly f3600 without
+an Access-owned runtime/declaration update and provenance. If hourly frame is
+adopted, record f3600/wait7200/effective10800 and prove actual runtime adoption.
+Do not silently apply Approval Engine's `cadence_registration.prepare`: that
+helper deliberately validates source=approval-engine and its own class set.
+The generic SenderRegistry parser already supports the reviewed flex-auth
+metadata; custody tooling can validate an in-memory candidate with it.
+
+Platform owns contained sender seed/delivery, registry CAS/readback/ESO reload,
+transport and PVC admission. Resolve the actual usable custody route with
+`warden route find` and `show` before any credential/access request. Historical
+AUDIT-WP-0013-T02 names an unusable draft audit-core-senders route; do not assume
+it is corrected. Obtain current route evidence and required scoped approval.
+Never copy a registry/token to this packet or give a writer archive-read scope.
+Receiver ingress must pair namespace AND exact pod selector to port8080;
+source egress and receiver service DNS are separately admitted. Source-owned
+single-writer flock/64MiB bound is source progress; actual mounted durable PVC,
+restart, full/fenced failure, bounded drain and retained cursor need native proof.
+
+## Native writer acceptance, followed by independent readback
+
+1. Retain source/deployment/configuration pins, registry metadata version/digest,
+ source declaration digest, original exact change authorization and rollback.
+ Check accepted source/class/tenant/retention/secret policy inventory against
+ actual receiver configuration without exporting credentials.
+2. Owner runs the approved bounded fixture through its contained existing lane.
+ Record durable event IDs, original correlation/decision/approval/operation
+ references, source class/tenant, local outbox identity/lifetime and entry
+ sequence/committed_at; retain before/after cursor, pending, lag, counters and
+ sanitized first202/duplicate200/refusal receipts. No new metadata operation
+ is authorized by this packet; where native effect is unadmitted, retain wait.
+3. Exercise wrong source/tenant400, invalid/expired bearer401, writer read403,
+ payload conflict409 and formerly-valid bearer refusal after owner revocation.
+ A dead letter is not accepted custody and a source stdout202 is not readback.
+4. Existing independently authorized read-only owner retrieves each exact ID via
+ GET /v1/events/{id}; compare source, tenant, action, correlation and normalized
+ original payload/hash, plus accepted_at. GET /v1/events?correlation_id=... can
+ enumerate related records within that reader's actual authorized scope.
+ Record reader identity/role separation metadata and original receiver receipt
+ references; credentials stay contained. Existing operator reader is evidence
+ of a past lane, not automatic current access. If no admitted scoped reader
+ exists, this gate waits on that owner; never upgrade the source writer.
+5. Compare exact event-ID sets first: local committed records versus independently
+ retained records, after explicitly declared bounded drain lag. Missing pending
+ IDs are lag until the bound expires, then a finding; acknowledged-but-missing
+ IDs, conflicts and unexpected IDs are separate findings. Exclude four heartbeat
+ transport events from decision-effect totals. Preserve duplicate attempt counts
+ while accepted IDs count once. Keep nonzero released_uncommitted as a finding;
+ zero observed after restart does not establish its historical absence.
+6. For aggregate GET /v1/reconciliation name exact source/tenant and explicit
+ [since,until) accepted_at bounds. Derive the local comparison set by the same
+ independently read accepted_at of the exact retained IDs, not occurred_at,
+ local commit time or a cumulative GET /v1/emission snapshot. Report unresolved
+ boundary arrivals separately and repeat after bounded drain. Source status
+ lacks tenant/window splits and persisted remote acceptance times; its raw
+ total cannot be compared to an arbitrary receiver time-window total. This
+ event-ID/accepted_at method closes a bounded admitted run without claiming a
+ general unattended reconciliation implementation. Concurrent unrelated writes
+ must be enumerated or isolated by an admitted outbox lifetime and exact IDs.
+7. Independently observe four distinct rare-class heartbeats, actual configured
+ cadence and lag. A controlled withheld-heartbeat check belongs in an admitted
+ non-production exercise; do not suppress production evidence. Keep never-seen,
+ stale, missing-class, duplicate, count and boundary findings distinct. King's
+ Guard owns independent operational observer acceptance under KG-WP-0005.
+
+Rollback restores only the exact earlier admitted scope/configuration, records
+uncertain delivery and retains outbox/cursor/events. It never deletes evidence,
+replays an uncertain protected effect, accepts unsigned decisions, widens a grant
+or revives a revoked credential. Audit arrival proves custody after arrival;
+neither arrival nor an empty finding set proves source completeness. Independent
+chain-head/offsite custody remains AUDIT-WP-0015-T01's separate open boundary.
diff --git a/tests/test_flex_auth_native_contract.py b/tests/test_flex_auth_native_contract.py
new file mode 100644
index 0000000..93f7559
--- /dev/null
+++ b/tests/test_flex_auth_native_contract.py
@@ -0,0 +1,90 @@
+"""AUDIT-WP-0013-T02: wire compatibility, never live sender admission.
+
+Fixture field mapping is pinned in docs/flex-auth-secrets-engine-admission.md.
+All identities/tokens below exist only in the isolated test receiver.
+"""
+from datetime import datetime, timedelta, timezone
+from urllib.parse import urlencode
+
+import pytest
+
+from audit_core.ingestion import IngestionApplication
+from audit_core.senders import SenderIdentity, SenderRegistry
+from audit_core.sqlite_backend import SQLiteAuditBackend
+from audit_core.stream_findings import evaluate, NEVER_HEARTBEAT
+from test_stream_findings import invoke
+
+SOURCE = "flex-auth.secrets-engine"
+RARE = tuple("flex-auth.decision." + name for name in ("deny", "redact", "not_applicable", "audit_only"))
+CLASSES = RARE + ("flex-auth.decision.allow",)
+
+
+@pytest.fixture
+def receiver(tmp_path):
+ writer = SenderIdentity(name=SOURCE, tokens=("fixture-writer",), sources=frozenset({SOURCE}),
+ tenants=frozenset({"tenant:platform"}), may_read=False,
+ evidence_kind="load-bearing", heartbeat_classes=tuple((c, 86400) for c in RARE))
+ reader = SenderIdentity(name="fixture-independent-reader", tokens=("fixture-reader",),
+ sources=frozenset({SOURCE}), tenants=frozenset({"tenant:platform"}),
+ may_write=False, may_read=True)
+ return IngestionApplication(SQLiteAuditBackend(str(tmp_path / "events.db")), SenderRegistry([writer, reader])), writer
+
+
+def envelope(kind, event_id="fixture-event"):
+ # outbox.go Event + event(): no receiver-derived fields or invented sequence.
+ return dict(id=event_id, type=kind, source=SOURCE, subject="openbao/metadata/fixture",
+ tenant="tenant:platform", correlation_id="fixture-decision",
+ occurred_at="2026-10-16T00:00:00.123456789Z",
+ data={"id": "fixture-decision", "effect": kind.rsplit(".", 1)[-1]})
+
+
+def post(app, event):
+ return invoke(app, "/v1/events", token="fixture-writer", method="POST", payload=event, key=event["id"])
+
+
+def count(app, since, until, source=SOURCE, tenant="tenant:platform"):
+ return invoke(app, "/v1/reconciliation?" + urlencode(dict(source=source, tenant=tenant, since=since, until=until)), token="fixture-writer")
+
+
+@pytest.mark.parametrize("kind", CLASSES)
+def test_exact_pin_wire_duplicate_and_independent_readback(receiver, kind):
+ app, _ = receiver
+ event = envelope(kind)
+ assert post(app, event)[0].startswith("202")
+ assert post(app, event)[0].startswith("200")
+ assert post(app, dict(event, subject="changed"))[0].startswith("409")
+ assert invoke(app, "/v1/events/fixture-event", token="fixture-writer")[0].startswith("403")
+ status, retained = invoke(app, "/v1/events/fixture-event", token="fixture-reader")
+ assert status.startswith("200")
+ assert (retained["source"], retained["tenant"], retained["action"]) == (SOURCE, "tenant:platform", kind)
+ assert retained["details"]["data"] == event["data"]
+ accepted = datetime.fromisoformat(retained["accepted_at"])
+ before, after = ((accepted + timedelta(seconds=n)).isoformat() for n in (-1, 1))
+ status, counts = count(app, before, after)
+ assert status.startswith("200")
+ assert counts["counts"] == [{"class": kind, "count": 1}]
+ # Acceptance-time [since, until): source occurred_at is deliberately older.
+ assert count(app, before, accepted.isoformat())[1]["counts"] == []
+ assert count(app, accepted.isoformat(), after)[1]["counts"] == [{"class": kind, "count": 1}]
+
+
+def test_wrong_scope_refusals_are_not_empty_counts(receiver):
+ app, _ = receiver
+ assert post(app, dict(envelope(CLASSES[0]), source="flex-auth.other"))[0].startswith("400")
+ assert post(app, dict(envelope(CLASSES[0]), tenant="tenant:other"))[0].startswith("400")
+ window = ("2026-10-15T00:00:00Z", "2027-01-01T00:00:00Z")
+ assert count(app, *window, source="flex-auth.other")[0].startswith("403")
+ assert count(app, *window, tenant="tenant:other")[0].startswith("403")
+
+
+def test_each_rare_class_must_have_its_own_positive_claim(receiver):
+ app, writer = receiver
+ now = datetime.now(timezone.utc)
+ covered = RARE[0]
+ event = dict(envelope("audit-core.heartbeat"), subject=SOURCE,
+ data={"class": covered, "assertion": "nothing-to-report", "committed": 0, "released_uncommitted": 0})
+ assert post(app, event)[0].startswith("202")
+ # Source/class finding evaluator; a heartbeat for deny cannot cover redact.
+ findings = evaluate([writer], {(SOURCE, covered): now.isoformat()}, now=now)
+ assert {f.event_class for f in findings} == set(RARE) - {covered}
+ assert all(f.kind == NEVER_HEARTBEAT for f in findings)
diff --git a/workplans/AUDIT-WP-0013-cross-repo-sender-admission.md b/workplans/AUDIT-WP-0013-cross-repo-sender-admission.md
index a663791..07e4fff 100644
--- a/workplans/AUDIT-WP-0013-cross-repo-sender-admission.md
+++ b/workplans/AUDIT-WP-0013-cross-repo-sender-admission.md
@@ -131,3 +131,16 @@ not independent receiver readback. Real elapsed hourly observation, independent
active-instance/class-silence/sequence/count/lag assessment and Approval lifecycle
acceptance remain with NK-WP-0035/KG-WP-0005. Source-global receiver findings must
not misclassify intentional Qonto scale-to-zero as an active-instance omission.
+
+### First protected pin admission preparation — 2026-10-16
+
+T02 remains wait. Prepared docs/flex-auth-secrets-engine-admission.md against
+Access0a05383195213e7eaacd08388ce1d7892ce756df and Audit2e97f37. Existing wire
+contracts need no adapter. Seven local tests cover all five decision classes,
+retry/conflict, independent fixture readback, writer-read and wrong-scope refusal,
+half-open acceptance-time accounting and rare-class silence. This does not grant
+or admit a sender. Per-pin source/cadence/policy/selectors, usable attended custody
+route, source deployment/PVC and independent native readback remain owner gates.
+Generic source cadence remains daily and cannot stand in for admitted hourly
+runtime. Source outbox sequence is not on the wire; exact event-ID/accepted_at
+comparison is the bounded readback method, not cumulative-time-window equality.

View file

@ -0,0 +1,316 @@
diff --git a/docs/flex-auth-secrets-engine-admission.md b/docs/flex-auth-secrets-engine-admission.md
new file mode 100644
index 0000000..a998e68
--- /dev/null
+++ b/docs/flex-auth-secrets-engine-admission.md
@@ -0,0 +1,183 @@
+# First protected workflow: Audit Core admission packet
+
+Prepared 2026-10-16 for TSA-09, AUDIT-WP-0013-T02, FLEX-WP-0031-T02/T06/T08,
+SECRETS-WP-0013 and RPF-WP-0035-T12. This packet grants no sender, observer,
+credential, deployment or protected effect authority. T02 remains waiting.
+
+## Exact source and receiver compatibility
+
+Reviewed Access source `0a05383195213e7eaacd08388ce1d7892ce756df`, particularly
+`internal/emission/outbox.go` and `delivery.go`; Audit base
+`2e97f37c01b583ac779310a2aa0d938bb9816604`. The protected consumer pin is
+`flex-auth.secrets-engine`, distinct from generic `flex-auth` and other pins.
+Access emits the existing eight-field contract in `docs/event-envelope.md`.
+No translating adapter or second event schema is needed. Preserve event id,
+Idempotency-Key, source, tenant, correlation, original time and data; the archive
+does not authenticate a decision signature or establish approval validity.
+
+Inventory: `flex-auth.decision.allow`, `.deny`, `.redact`, `.not_applicable`,
+`.audit_only`, plus transport class `audit-core.heartbeat`. Heartbeat data.class
+names one exact rare class, with assertion, committed and released_uncommitted
+counts. Four heartbeats are four retained events, not four decision counts.
+Outbox sequence and committed_at are local entry fields; the current wire event
+has no stream_instance_id or sequence. Do not promise native receiver instance
+filtering or wire sequence-gap detection for this source merely because the
+receiver has that optional filter. Scope, lifetime and boundary are required
+before comparing cumulative source counts.
+
+The new isolated receiver tests exercise all five decision types: first202,
+same-id duplicate200, changed-body409, write-only read403, independent fixture
+readback, exact source/tenant, once-only counts and half-open acceptance-time
+boundaries. They exercise wrong scope refusals and class-specific silence.
+The identities and narrowed tenant:platform in tests are synthetic fixtures,
+not proposed production grants. No live record or real decision validation is
+claimed by these tests.
+
+## Existing deployed evidence and its limit
+
+Audit `docs/evidence/2026-10-15-cadence-admission/receiver-cadence-release-native.json`
+records image `sha256:b479801b0bc76df66a36a85376c45aaf399c6d82feade9ba81430b774c4a8271`,
+Deployment UID `b85fe3d0-75c9-4e0d-8c34-c6f1df0881bb`, source5227fb1 and
+synthetic native cadence/heartbeat/exact-scope/SQLite/PostgreSQL feature probes.
+The same folder records migration0007 and admitted Qonto/Approval metadata.
+These are historical receiver capability receipts, not fresh flex-auth admission
+or independent protected-workflow acceptance. Revalidate deployed image, readyz,
+configuration metadata and migration compatibility before using them for native
+acceptance. No production inspection was performed for this packet.
+
+## Metadata prerequisites before any custody change
+
+Access owner must return one reviewed per-pin registration payload and canonical
+cadence bytes/digest for this pin, plus authoritative retained deployment source,
+image, namespace `flex-auth`, exact AND namespace/pod selectors and configured
+emission source. Do not derive pod selectors solely from a Helm release name.
+Existing six-pin commitment in docs/cross-repo-evidence-admission.md requests
+write true/read false, exact per-pin source, tenants ["*"] on the recorded
+deny-before-tenant-creation justification, explicit redact and load-bearing.
+This packet neither narrows that accepted scope to the fixture tenant nor widens
+it; a revised scope requires its owner review. Retention/access/export policy
+and owner must be explicit; an intake accepting custody is not that policy.
+
+Current `docs/contracts/decision-emission-cadence.json` declares generic
+source flex-auth, four heartbeat intervals86400 and allow expected_min1 per3600;
+its source state and observer status remain pending. It is not a final per-pin
+payload. Its daily source heartbeat cannot be registered as hourly f3600 without
+an Access-owned runtime/declaration update and provenance. If hourly frame is
+adopted, record f3600/wait7200/effective10800 and prove actual runtime adoption.
+Do not silently apply Approval Engine's `cadence_registration.prepare`: that
+helper deliberately validates source=approval-engine and its own class set.
+The generic SenderRegistry parser already supports the reviewed flex-auth
+metadata; custody tooling can validate an in-memory candidate with it.
+
+Platform owns contained sender seed/delivery, registry CAS/readback/ESO reload,
+transport and PVC admission. Resolve the actual usable custody route with
+`warden route find` and `show` before any credential/access request. Historical
+AUDIT-WP-0013-T02 names an unusable draft audit-core-senders route; do not assume
+it is corrected. Obtain current route evidence and required scoped approval.
+Never copy a registry/token to this packet or give a writer archive-read scope.
+Receiver ingress must pair namespace AND exact pod selector to port8080;
+source egress and receiver service DNS are separately admitted. Source-owned
+single-writer flock/64MiB bound is source progress; actual mounted durable PVC,
+restart, full/fenced failure, bounded drain and retained cursor need native proof.
+
+## Native writer acceptance, followed by independent readback
+
+1. Retain source/deployment/configuration pins, registry metadata version/digest,
+ source declaration digest, original exact change authorization and rollback.
+ Check accepted source/class/tenant/retention/secret policy inventory against
+ actual receiver configuration without exporting credentials.
+2. Owner runs the approved bounded fixture through its contained existing lane.
+ Record durable event IDs, original correlation/decision/approval/operation
+ references, source class/tenant, local outbox identity/lifetime and entry
+ sequence/committed_at; retain before/after cursor, pending, lag, counters and
+ sanitized first202/duplicate200/refusal receipts. No new metadata operation
+ is authorized by this packet; where native effect is unadmitted, retain wait.
+3. Exercise wrong source/tenant400, invalid/expired bearer401, writer read403,
+ payload conflict409 and formerly-valid bearer refusal after owner revocation.
+ A dead letter is not accepted custody and a source stdout202 is not readback.
+4. Existing independently authorized read-only owner retrieves each exact ID via
+ GET /v1/events/{id}; compare source, tenant, action, correlation and normalized
+ original payload/hash, plus accepted_at. GET /v1/events?correlation_id=... can
+ enumerate related records within that reader's actual authorized scope.
+ Record reader identity/role separation metadata and original receiver receipt
+ references; credentials stay contained. Existing operator reader is evidence
+ of a past lane, not automatic current access. If no admitted scoped reader
+ exists, this gate waits on that owner; never upgrade the source writer.
+5. Establish the full producer denominator before matching any chosen IDs. The
+ independent owner retains the complete producer outbox.jsonl snapshot, source
+ revision, outbox/PVC lifetime identity and bytes/SHA256/EOF high-water H. Check
+ every newline-terminated entry, contiguous seq1..H, exact source, unique event
+ IDs, valid committed_at and complete inventory including zero classes. Pin
+ drain cursor seq/offset, committed counters and pending/lag to that snapshot;
+ cursor must refer to a real entry boundary and never exceed H. This is an
+ independently retained full ledger, not a producer-selected list of successful
+ IDs. An arbitrary chosen-ID readback cannot satisfy this denominator. Retain
+ independent transition/effect-owner receipts too: an omitted transition never
+ queued by a compromised producer remains outside the archive guarantee.
+ Compare all ledger IDs versus independently retained receiver records, after
+ explicitly declared bounded drain lag. Missing pending
+ IDs are lag until the bound expires, then a finding; acknowledged-but-missing
+ IDs, conflicts and unexpected IDs are separate findings. Exclude four heartbeat
+ transport events from decision-effect totals. Preserve duplicate attempt counts
+ while accepted IDs count once. Keep nonzero released_uncommitted as a finding;
+ zero observed after restart does not establish its historical absence.
+6. For aggregate GET /v1/reconciliation name exact source/tenant and explicit
+ [since,until) accepted_at bounds. Derive the local comparison set by the same
+ independently read accepted_at of the exact retained IDs, not occurred_at,
+ local commit time or a cumulative GET /v1/emission snapshot. Report unresolved
+ boundary arrivals separately and repeat after bounded drain. Source status
+ lacks tenant/window splits and persisted remote acceptance times; its raw
+ total cannot be compared to an arbitrary receiver time-window total. This
+ event-ID/accepted_at method supports a bounded admitted run without claiming a
+ general unattended reconciliation implementation. Compare the complete map of
+ all classes, including unexpected classes, against receiver aggregate counts:
+ all expected IDs must exist, and any receiver count above the independently
+ enumerated expected map is an unaccounted-record finding. This detects extras
+ without pretending GET-by-ID itself enumerates the receiver. Correlation search
+ has a1000 ceiling and no pagination; it is not a complete source export.
+ Concurrent arrivals require a second independently retained complete ledger
+ watermark H2 covering the same receiver window, or an approved quiescent
+ bounded run. Do not report agreement while that boundary remains unsettled.
+ Independently retained full snapshots, repeated cadence execution, actual
+ missing-class observation and independent observer adoption remain required
+ for operational TSA-09 acceptance; this packet alone closes none of them.
+7. Independently observe four distinct rare-class heartbeats, actual configured
+ cadence and lag. A controlled withheld-heartbeat check belongs in an admitted
+ non-production exercise; do not suppress production evidence. Keep never-seen,
+ stale, missing-class, duplicate, count and boundary findings distinct. King's
+ Guard owns independent operational observer acceptance under KG-WP-0005.
+
+Rollback restores only the exact earlier admitted scope/configuration, records
+uncertain delivery and retains outbox/cursor/events. It never deletes evidence,
+replays an uncertain protected effect, accepts unsigned decisions, widens a grant
+or revives a revoked credential. Audit arrival proves custody after arrival;
+neither arrival nor an empty finding set proves source completeness. Independent
+chain-head/offsite custody remains AUDIT-WP-0015-T01's separate open boundary.
+
+## Cross-owner accounting review — 2026-10-16
+
+Access owner confirms the initial lifecycle signer slice keeps auditDelivery
+disabled. Its current native package has no wire/accounting extension and makes
+no G2/hourly-adoption claim. Audit owner accepts the complete independently
+retained ledger + exact-ID readback + all-class receiver-count protocol above
+for a bounded source-to-receiver reconciliation. A source self-selected receipt
+list is insufficient. This is an evidence protocol using existing APIs, not a
+new assertion format or permission. Audit has no current source-wide paginated
+export endpoint or canonical producer-accounting receipt schema. Original owner
+ledger bytes and receiver records are authoritative; a Custodian summary is not.
+
+For future unattended monitoring, Access may separately propose durable
+outbox-lifetime stream identity and sequence metadata, but must preserve signed
+DecisionEnvelope bytes. A receiver-compatible wrapper would need a source-owned
+versioned wire contract and fixture changes; post-sign insertion into decision
+data is refused. An emitter restart is not automatically a new outbox lifetime.
+No producer extension is mandatory for the bounded full-ledger protocol above;
+repeated complete producer ledger capture/independent retention and source-owned
+per-pin cadence/runtime adoption are mandatory operational work still missing.
+
+The previously skipped existing cross-owner test was run directly from the real
+canonical Audit checkout using its actual sibling NetKingdom/Approval fixtures:
+`python3 -m pytest -q tests/test_cadence_registration.py::test_real_owner_proposal_when_checkout_available`
+passed1. This makes114 tested cases across the focused isolated run and the
+canonical owner-fixture check; the isolated run itself remains113 pass/1 skip.
+No foreign source was changed (pytest cache writes were denied by the sandbox).
diff --git a/tests/test_flex_auth_native_contract.py b/tests/test_flex_auth_native_contract.py
new file mode 100644
index 0000000..93f7559
--- /dev/null
+++ b/tests/test_flex_auth_native_contract.py
@@ -0,0 +1,90 @@
+"""AUDIT-WP-0013-T02: wire compatibility, never live sender admission.
+
+Fixture field mapping is pinned in docs/flex-auth-secrets-engine-admission.md.
+All identities/tokens below exist only in the isolated test receiver.
+"""
+from datetime import datetime, timedelta, timezone
+from urllib.parse import urlencode
+
+import pytest
+
+from audit_core.ingestion import IngestionApplication
+from audit_core.senders import SenderIdentity, SenderRegistry
+from audit_core.sqlite_backend import SQLiteAuditBackend
+from audit_core.stream_findings import evaluate, NEVER_HEARTBEAT
+from test_stream_findings import invoke
+
+SOURCE = "flex-auth.secrets-engine"
+RARE = tuple("flex-auth.decision." + name for name in ("deny", "redact", "not_applicable", "audit_only"))
+CLASSES = RARE + ("flex-auth.decision.allow",)
+
+
+@pytest.fixture
+def receiver(tmp_path):
+ writer = SenderIdentity(name=SOURCE, tokens=("fixture-writer",), sources=frozenset({SOURCE}),
+ tenants=frozenset({"tenant:platform"}), may_read=False,
+ evidence_kind="load-bearing", heartbeat_classes=tuple((c, 86400) for c in RARE))
+ reader = SenderIdentity(name="fixture-independent-reader", tokens=("fixture-reader",),
+ sources=frozenset({SOURCE}), tenants=frozenset({"tenant:platform"}),
+ may_write=False, may_read=True)
+ return IngestionApplication(SQLiteAuditBackend(str(tmp_path / "events.db")), SenderRegistry([writer, reader])), writer
+
+
+def envelope(kind, event_id="fixture-event"):
+ # outbox.go Event + event(): no receiver-derived fields or invented sequence.
+ return dict(id=event_id, type=kind, source=SOURCE, subject="openbao/metadata/fixture",
+ tenant="tenant:platform", correlation_id="fixture-decision",
+ occurred_at="2026-10-16T00:00:00.123456789Z",
+ data={"id": "fixture-decision", "effect": kind.rsplit(".", 1)[-1]})
+
+
+def post(app, event):
+ return invoke(app, "/v1/events", token="fixture-writer", method="POST", payload=event, key=event["id"])
+
+
+def count(app, since, until, source=SOURCE, tenant="tenant:platform"):
+ return invoke(app, "/v1/reconciliation?" + urlencode(dict(source=source, tenant=tenant, since=since, until=until)), token="fixture-writer")
+
+
+@pytest.mark.parametrize("kind", CLASSES)
+def test_exact_pin_wire_duplicate_and_independent_readback(receiver, kind):
+ app, _ = receiver
+ event = envelope(kind)
+ assert post(app, event)[0].startswith("202")
+ assert post(app, event)[0].startswith("200")
+ assert post(app, dict(event, subject="changed"))[0].startswith("409")
+ assert invoke(app, "/v1/events/fixture-event", token="fixture-writer")[0].startswith("403")
+ status, retained = invoke(app, "/v1/events/fixture-event", token="fixture-reader")
+ assert status.startswith("200")
+ assert (retained["source"], retained["tenant"], retained["action"]) == (SOURCE, "tenant:platform", kind)
+ assert retained["details"]["data"] == event["data"]
+ accepted = datetime.fromisoformat(retained["accepted_at"])
+ before, after = ((accepted + timedelta(seconds=n)).isoformat() for n in (-1, 1))
+ status, counts = count(app, before, after)
+ assert status.startswith("200")
+ assert counts["counts"] == [{"class": kind, "count": 1}]
+ # Acceptance-time [since, until): source occurred_at is deliberately older.
+ assert count(app, before, accepted.isoformat())[1]["counts"] == []
+ assert count(app, accepted.isoformat(), after)[1]["counts"] == [{"class": kind, "count": 1}]
+
+
+def test_wrong_scope_refusals_are_not_empty_counts(receiver):
+ app, _ = receiver
+ assert post(app, dict(envelope(CLASSES[0]), source="flex-auth.other"))[0].startswith("400")
+ assert post(app, dict(envelope(CLASSES[0]), tenant="tenant:other"))[0].startswith("400")
+ window = ("2026-10-15T00:00:00Z", "2027-01-01T00:00:00Z")
+ assert count(app, *window, source="flex-auth.other")[0].startswith("403")
+ assert count(app, *window, tenant="tenant:other")[0].startswith("403")
+
+
+def test_each_rare_class_must_have_its_own_positive_claim(receiver):
+ app, writer = receiver
+ now = datetime.now(timezone.utc)
+ covered = RARE[0]
+ event = dict(envelope("audit-core.heartbeat"), subject=SOURCE,
+ data={"class": covered, "assertion": "nothing-to-report", "committed": 0, "released_uncommitted": 0})
+ assert post(app, event)[0].startswith("202")
+ # Source/class finding evaluator; a heartbeat for deny cannot cover redact.
+ findings = evaluate([writer], {(SOURCE, covered): now.isoformat()}, now=now)
+ assert {f.event_class for f in findings} == set(RARE) - {covered}
+ assert all(f.kind == NEVER_HEARTBEAT for f in findings)
diff --git a/workplans/AUDIT-WP-0013-cross-repo-sender-admission.md b/workplans/AUDIT-WP-0013-cross-repo-sender-admission.md
index a663791..4867973 100644
--- a/workplans/AUDIT-WP-0013-cross-repo-sender-admission.md
+++ b/workplans/AUDIT-WP-0013-cross-repo-sender-admission.md
@@ -131,3 +131,26 @@ not independent receiver readback. Real elapsed hourly observation, independent
active-instance/class-silence/sequence/count/lag assessment and Approval lifecycle
acceptance remain with NK-WP-0035/KG-WP-0005. Source-global receiver findings must
not misclassify intentional Qonto scale-to-zero as an active-instance omission.
+
+### First protected pin admission preparation — 2026-10-16
+
+T02 remains wait. Prepared docs/flex-auth-secrets-engine-admission.md against
+Access0a05383195213e7eaacd08388ce1d7892ce756df and Audit2e97f37. Existing wire
+contracts need no adapter. Seven local tests cover all five decision classes,
+retry/conflict, independent fixture readback, writer-read and wrong-scope refusal,
+half-open acceptance-time accounting and rare-class silence. This does not grant
+or admit a sender. Per-pin source/cadence/policy/selectors, usable attended custody
+route, source deployment/PVC and independent native readback remain owner gates.
+Generic source cadence remains daily and cannot stand in for admitted hourly
+runtime. Source outbox sequence is not on the wire; exact event-ID/accepted_at
+comparison is the bounded readback method, not cumulative-time-window equality.
+
+Cross-owner follow-up: Access confirms auditDelivery remains disabled in the
+initial signer slice. The packet now requires independently retained complete
+producer JSONL with contiguous sequence/high-water and lifetime identity, not a
+selected-ID list. Existing exact-ID reads plus all-class accepted-time count
+comparison support bounded full-ledger reconciliation; correlation search is
+capped and cannot serve as complete export. Operational repeated ledger custody,
+per-pin source cadence/runtime adoption and independent observation still wait.
+The canonical sibling-owner fixture check passed1, resolving the isolated
+checkout's expected skip without modifying foreign source.

View file

@ -0,0 +1,17 @@
{
"session_id": 2244,
"exit_code": 0,
"source_revision": "64509d2c4039ca1249f9e8aabf2bae030e3640cf",
"summary": {
"fail": 0,
"automation_error": 0,
"warn": 10,
"info": 0
},
"fixes_applied": [
"bindings: synced 18/18",
"C-17 cleared: pushed 1 backlogged commit(s)",
"C-22 fixed: task 76b59808… description updated",
"push: pushed"
]
}

View file

@ -0,0 +1,11 @@
{
"new_command": "python3 -m pytest -q tests/test_flex_auth_native_contract.py",
"new_result": "7 passed in 0.37s",
"focused_command": "python3 -m pytest -q tests/test_flex_auth_native_contract.py tests/test_stream_findings.py tests/test_emission_cadence.py tests/test_cadence_registration.py tests/test_senders.py",
"focused_result": "113 passed, 1 skipped in 1.57s",
"postgres_current_run": false,
"native_acceptance": false,
"diff_check": "passed",
"canonical_apply_check": "passed against /home/worsch/audit-core; no canonical writes",
"skip_reason": "tests/test_cadence_registration.py:74: owner checkouts unavailable (isolated /tmp path)"
}

View file

@ -0,0 +1,14 @@
{
"new_command": "python3 -m pytest -q tests/test_flex_auth_native_contract.py",
"new_result": "7 passed in 0.37s",
"focused_command": "python3 -m pytest -q tests/test_flex_auth_native_contract.py tests/test_stream_findings.py tests/test_emission_cadence.py tests/test_cadence_registration.py tests/test_senders.py",
"focused_result": "113 passed, 1 skipped in 1.57s",
"postgres_current_run": false,
"native_acceptance": false,
"diff_check": "passed",
"canonical_apply_check": "passed against /home/worsch/audit-core; no canonical writes",
"skip_reason": "tests/test_cadence_registration.py:74: owner checkouts unavailable (isolated /tmp path)",
"canonical_cross_owner_command": "python3 -m pytest -q tests/test_cadence_registration.py::test_real_owner_proposal_when_checkout_available",
"canonical_cross_owner_result": "1 passed in0.04s; cache write warnings only; no source changed",
"r2_diff_check": "passed"
}

View file

@ -0,0 +1,265 @@
diff --git a/canon/schemas/security-case-type_v0.1.schema.json b/canon/schemas/security-case-type_v0.1.schema.json
index 22ab31c..3575d8a 100644
--- a/canon/schemas/security-case-type_v0.1.schema.json
+++ b/canon/schemas/security-case-type_v0.1.schema.json
@@ -132,6 +132,24 @@
"items": {
"type": "object"
}
+ },
+ "execution_descriptors": {
+ "type": "object",
+ "maxProperties": 128,
+ "propertyNames": {
+ "type": "string",
+ "pattern": "^[a-z0-9][a-z0-9-]*$",
+ "not": {
+ "pattern": "[^a-z0-9-]"
+ }
+ },
+ "additionalProperties": {
+ "type": "string",
+ "pattern": "^sha256:[0-9a-f]{64}$",
+ "minLength": 71,
+ "maxLength": 71
+ },
+ "description": "Optional exact owner machine-descriptor byte digests keyed by declared follow-through step. A pin alone is not owner acknowledgment, execution authority or native evidence."
}
}
}
diff --git a/tools/security-case-types/README.md b/tools/security-case-types/README.md
index dc4fc91..d25d2e9 100644
--- a/tools/security-case-types/README.md
+++ b/tools/security-case-types/README.md
@@ -95,3 +95,18 @@ Integration tests invoke actual sibling Mason `prepare` and Warden `Journal.save
with metadata fixtures only. They need those owner source checkouts, and existing
type suites need the public KeyCape request file and provider declarations beside
the checkout. `NET_KINGDOM_ROOT` selects the source root for the 1.2 package tests.
+
+## Machine descriptor source pins
+
+The optional `spec.execution_descriptors` map uses the existing Warden kernel's
+step-to-exact-descriptor-byte SHA-256 contract. The JSON schema accepts at most
+128 lowercase `sha256:<64 hex>` pins. The semantic validator additionally requires
+every key to name a declared follow-through step. Malformed maps are refused by
+the direct evidence API too. Absent and partial maps remain legal for source
+preparation; missing steps remain explicit in the evidence report.
+
+A valid pin is source metadata. It does not authenticate its owner, acknowledge
+a machine seam, admit an adapter or change the implemented-type requirement.
+The existing browser types contain no descriptors; their bytes and lifecycle
+states are unchanged. Owner descriptor/provenance acceptance and actual native
+receipts remain prerequisites to execution and acceptance.
diff --git a/tools/security-case-types/security_case_evidence.py b/tools/security-case-types/security_case_evidence.py
index 0bf0a84..5f25577 100644
--- a/tools/security-case-types/security_case_evidence.py
+++ b/tools/security-case-types/security_case_evidence.py
@@ -135,6 +135,11 @@ def check_steps(rows, case_source, type_source, rendered):
"journal_schema", "evidence_digest", "session_revoked", "session_revocation_digest",
"grant_revocation_digest", "attempt_id", "operation"}
type_spec = yaml.safe_load(type_source)["spec"]
+ # The direct API must refuse malformed maps too, without AttributeError or
+ # treating an undeclared step as an admitted descriptor.
+ from security_case_validator import validate_execution_descriptors
+ if validate_execution_descriptors(type_spec):
+ raise EvidenceRefused("invalid type machine descriptor pins")
descriptors = type_spec.get("execution_descriptors", {})
seen, result = set(), []
for row in rows:
diff --git a/tools/security-case-types/security_case_validator.py b/tools/security-case-types/security_case_validator.py
index 1dc63d6..06cfff4 100644
--- a/tools/security-case-types/security_case_validator.py
+++ b/tools/security-case-types/security_case_validator.py
@@ -151,6 +151,7 @@ def validate_type(data: dict[str, Any], type_dir: Path | None = None) -> list[Is
params = _validate_type_parameters(spec["parameters"], issues)
step_ids = _validate_follow_through(spec["follow_through"], issues)
+ issues.extend(validate_execution_descriptors(spec))
_validate_composition(spec["composition"], params, issues)
_validate_materialization(spec["materialization"], params, issues)
_validate_verification(spec["verification"], params, issues)
@@ -190,6 +191,30 @@ def validate_type(data: dict[str, Any], type_dir: Path | None = None) -> list[Is
return issues
+def validate_execution_descriptors(spec: dict[str, Any]) -> list[Issue]:
+ """Validate optional source pins; never infer acknowledgment or authority.
+
+ Incomplete/absent maps remain legal for plan-only types. Admission and
+ provenance remain the executing owner's responsibility.
+ """
+ if "execution_descriptors" not in spec:
+ return []
+ path = "type.spec.execution_descriptors"
+ pins = spec["execution_descriptors"]
+ if type(pins) is not dict or len(pins) > 128:
+ return [err(path, "must be a mapping of at most 128 step descriptor pins")]
+ steps = spec.get("follow_through")
+ declared = {step.get("id") for step in steps
+ if type(step) is dict and type(step.get("id")) is str} if type(steps) is list else set()
+ issues = []
+ for step, pin in pins.items():
+ if type(step) is not str or not ID.fullmatch(step) or step not in declared:
+ issues.append(err(path, "descriptor key must identify a declared follow-through step"))
+ if type(pin) is not str or re.fullmatch(r"sha256:[0-9a-f]{64}", pin) is None:
+ issues.append(err(path, "descriptor pin must be a lowercase SHA-256 byte digest"))
+ return issues
+
+
def _validate_type_parameters(params: Any, issues: list[Issue]) -> dict[str, dict]:
out: dict[str, dict] = {}
if not isinstance(params, list) or not params:
diff --git a/workplans/NK-WP-0048-security-case-types.md b/workplans/NK-WP-0048-security-case-types.md
index 074efd1..72f1a9b 100644
--- a/workplans/NK-WP-0048-security-case-types.md
+++ b/workplans/NK-WP-0048-security-case-types.md
@@ -9,7 +9,7 @@ flavor: implementation
owner: claude-code
topic_slug: netkingdom
created: "2026-10-08"
-updated: "2026-10-10"
+updated: "2026-10-16"
depends_on: []
related_repos:
- ops-mason
@@ -323,7 +323,7 @@ the rationale. The type is `acknowledged`; it becomes `implemented` with T06.
```task
id: NK-WP-0048-T06
status: wait
-depends_on: [NK-WP-0048-T05, NK-WP-0048-T08, NK-WP-0048-T09, MASON-WP-0010-T03, WARDEN-WP-0044-T03]
+depends_on: [NK-WP-0048-T05, NK-WP-0048-T08, NK-WP-0048-T09, NK-WP-0048-T12, MASON-WP-0010-T03, WARDEN-WP-0044-T03]
blocking_reason: "Type1.2 architecture has a confirmed source-only founder acknowledgment; canonical1.1 remains unchanged/default and the1.2 reference case stays proposed. Needs explicit version selection/reference-source integration without normal admission bypass, closed owner adapters plus global/native receipt verifier (WARDEN-WP-0044-T03), independently verified six-object structural materialization and CCR42 claims/created-only provenance, exact broker/case/source reconciliation, then separately authorized native mint/delivery and attended registry/consumer verification. Source acknowledgment, a bundle or local tests do not prove implemented/materialized/live status."
priority: high
state_hub_task_id: "d9b26bcf-a7c6-59a2-92a0-f913d76a203c"
@@ -584,3 +584,61 @@ validator, then project only descriptor-declared safe target metadata; do not
remove the credential/value refusal or copy complete parameters into journals.
Actual owner descriptor acknowledgment and independent evidence admission remain
prerequisites, with normal admission still refusing unimplemented types.
+
+
+## T10 — Source compatibility checker for Mason and Warden evidence
+
+```task
+id: NK-WP-0048-T10
+status: done
+priority: high
+```
+
+Completed 2026-10-16 in published source `c31d21ba`. The read-only
+`check-evidence` command checks the actual Mason structural request and Warden
+journal source protocols against an exact version/render. Independent source
+review passed 103 tests at that checkpoint. It always reports native completion
+false and execution prohibited. Fixtures and local journal fingerprints do not
+provide authenticated owner/native evidence. This records completed source scope
+previously described under T06; it does not duplicate native acceptance credit.
+
+## T11 — Validate the optional machine-descriptor pin contract
+
+```task
+id: NK-WP-0048-T11
+status: done
+priority: high
+```
+
+Completed 2026-10-16. Reproduced the JSON schema rejecting a valid
+`execution_descriptors` map while the Python validator accepted malformed maps.
+The schema now supports the existing Warden optional exact-byte pin map; semantic
+validation binds keys to declared steps, bounds the map and checks digest shape.
+The direct evidence API refuses malformed maps before accessing them. Twenty-one
+new checks and all 127 affected source checks passed. No current type/case bytes,
+status, owner descriptors or native acceptance changed. Source evidence and
+publication receipt: Custodian
+`docs/changes/netkingdom-target-2026-10-16/browser-acceptance-next/`.
+
+## T12 — Prepare NetKingdom-owned attended step adapters
+
+```task
+id: NK-WP-0048-T12
+status: todo
+priority: high
+```
+
+Owner: NetKingdom. Next action: wrap the existing contained `keycape-client.py`
+registration/config/env and identity-provisioner ensure/revoke entry points in
+bounded owner adapters or receipt-only attended steps for Warden's closed kernel.
+Reuse the existing caller/session boundary, CAS/readback and status-only outputs;
+never acquire user-engine's runtime identity or expose registry/client secrets.
+Completion requires exact adapter/source descriptors, positive and refusal source
+checks, uncertainty/created-only rollback behavior and a separate owner review of
+the proposed machine seam. Source preparation can begin without credentials.
+Warden independently owns global provenance/admission integration; Platform owns
+mint/broker and native structural receipts; Apps owns consumer delivery/group
+acceptance. Their assent is not supplied by this task. Pinning descriptors into
+an acknowledged type remains a separately reviewed type-source change. Actual
+attended execution still requires its existing owner authorization and native
+receipts. T06 retains all native/reference lifecycle acceptance scope.
diff --git atools/security-case-types/tests/test_descriptor_pins.py btools/security-case-types/tests/test_descriptor_pins.py
new file mode 100644
index 0000000..8980425
--- /dev/null
+++ btools/security-case-types/tests/test_descriptor_pins.py
@@ -0,0 +1,64 @@
+"""Owner pin contract parity; synthetic pins never establish native acceptance."""
+import copy
+import json
+from pathlib import Path
+import sys
+
+import jsonschema
+import pytest
+import yaml
+
+TOOL = Path(__file__).resolve().parents[1]
+REPO = TOOL.parents[1]
+sys.path.insert(0, str(TOOL))
+import security_case_validator as v
+import security_case_evidence as e
+
+TYPE = yaml.safe_load((REPO / 'security-case-types/_template/type.yaml').read_bytes())
+SCHEMA = json.loads((REPO / 'canon/schemas/security-case-type_v0.1.schema.json').read_bytes())
+PIN = 'sha256:' + 'a' * 64
+STEP = TYPE['spec']['follow_through'][0]['id']
+
+
+def with_pins(pins):
+ doc = copy.deepcopy(TYPE)
+ doc['spec']['execution_descriptors'] = pins
+ return doc
+
+
+@pytest.mark.parametrize('pins', [{}, {STEP: PIN}])
+def test_optional_partial_pin_contract_has_schema_semantic_parity(pins):
+ doc = with_pins(pins)
+ jsonschema.validate(doc, SCHEMA)
+ assert not v.has_errors(v.validate_type(doc))
+ assert doc['spec']['status'] == TYPE['spec']['status']
+
+
+@pytest.mark.parametrize('pins', [None, [], 'digest', {STEP: True}, {STEP: None},
+ {STEP: 17}, {STEP: 'a' * 64}, {STEP: PIN.upper()}, {STEP: PIN + '\n'},
+ {STEP + '\n': PIN}, {7: PIN}, {'../escape': PIN},
+ {f'step-{i}': PIN for i in range(129)}])
+def test_malformed_descriptor_contract_refused_by_both_validators(pins):
+ doc = with_pins(pins)
+ assert v.has_errors(v.validate_type(doc))
+ with pytest.raises(jsonschema.ValidationError):
+ jsonschema.validate(doc, SCHEMA)
+
+
+def test_well_shaped_unknown_step_is_semantic_refusal():
+ doc = with_pins({'not-a-declared-step': PIN})
+ jsonschema.validate(doc, SCHEMA)
+ assert v.has_errors(v.validate_type(doc))
+
+
+@pytest.mark.parametrize('pins', [None, [], {STEP: 'bad'}, {'undeclared-step': PIN}])
+def test_direct_evidence_api_refuses_bad_map_without_crashing_or_needing_rows(pins):
+ with pytest.raises(e.EvidenceRefused, match='machine descriptor pins'):
+ e.check_steps((), b'case', yaml.safe_dump(with_pins(pins)).encode(), {'follow_through': []})
+
+
+def test_partial_pin_cannot_bypass_ordinary_case_admission():
+ doc = with_pins({STEP: PIN})
+ case = yaml.safe_load((REPO / 'security-case-types/_template/examples/example-operator.yaml').read_bytes())
+ issues = v.validate_case(case, doc)
+ assert any('only implemented types' in issue.message for issue in issues)

View file

@ -0,0 +1,52 @@
# NetKingdom registration adapter source candidate R3
Source-only candidate awaiting independent root review. No canonical owner file,
type/case bytes or status changed; no credential or live action was used.
Exercise status: unexercised.
The patch adds a fixed attended registration adapter around actual maintained
`keycape-client.run`, its contract notes and 16 new fixture checks. The 20
existing helper checks also pass. Three new checks exercise actual Warden
admission/dispatch/rollback and uncertain transitions with synthetic owner trust
with unchanged published Warden d97652a producer pins. No replacement of adapter
callables after admission is used: the proposed Invocation is built first, and
normal admission independently derives the same full binding.
R1's root review found an unbound config-checker executable: the caller could
supply another binary and its matching hash under the same descriptor. That
rejected revision remains in `rejected-r1/`; the superseded R2 source/fixture
packet remains in `reviewed-r2/`. R2 corrected the custody finding; R3 retains that correction and includes the exact selected
checker hash in the adapter source-composition pin and descriptor. Substitution
under the original descriptor is now refused before tooling. The descriptor
retained here uses a synthetic checker digest only; native executable selection
and owner acknowledgment remain outstanding.
Reproduce from current pinned owner dependencies:
```bash
python3 docs/changes/netkingdom-target-2026-10-16/browser-adapter-next/verify_candidate.py
```
`implementation.patch` adds three files and proposes an exact owner workplan edit
against retained `preimages/`. No canonical workplan changed. `postimages/` holds the exact proposed
bytes. `manifest.json` binds all source/fixture hashes and the observed owner
state at packaging; this is not a reconstructed session-start dirty-state
snapshot. `tests.txt` retains the 36 passing checks. Warden/source owner heads
and current canonical changes remain outside this patch.
The owner contract in `postimages/sso-mfa/k8s/keycape/registration-adapter.md`
records required native callbacks and remaining scope. In particular: published Warden d97652a now admits the exact producer source
bytes through its normal pins, without attesting this adapter; group ensure
has no created-membership provenance; group revoke can remove a pre-existing
membership; env/config/restart adapters remain; durable post-restart creation
reconciliation is absent. Platform/Apps native acceptance remains separately
owned. None of these gaps is supplied by the fixture proof.
The exact workplan proposal preserves existing T10/T11/T12 Hub UUIDs and all
other prior bytes outside T06 dependencies/T12 prose. T13 records source
implementation and fixture proof as done, explicitly excluding independent
review/publication. T12 retains env/config/restart work, while T14 tracks group
creation provenance, T15 durable registration recovery and T16 actual descriptor/
checker artifact selection and owner review. T06 retains all source dependencies
and native acceptance scope. No acknowledged type/case bytes or statuses change.
Root review and publication receipts must be added when integration is approved.

View file

@ -0,0 +1,32 @@
from pathlib import Path
from collections import Counter
import hashlib,json,re,subprocess,urllib.request
import yaml
p=Path(__file__).resolve().parent;owner=Path('/home/worsch/net-kingdom');backup=p/'publication-backup';manifest=json.loads((p/'manifest.json').read_text());wp='e31f3f9d-0748-5137-b0a3-7b3ca46a66eb'
sha=lambda data:'sha256:'+hashlib.sha256(data).hexdigest()
git=lambda *args:subprocess.check_output(['git','-C',str(owner),*args])
get=lambda path:json.load(urllib.request.urlopen('http://127.0.0.1:8000'+path,timeout=10))
final=json.loads((p/'normal-final.stdout.json').read_text());
if final['summary']['fail'] or final['summary']['automation_error']:raise SystemExit('final sync failed')
text=(owner/'workplans/NK-WP-0048-security-case-types.md').read_text();blocks=[yaml.safe_load(block) for block in re.findall(r'```task\n(.*?)```',text,re.S)];rows=get('/tasks/?workplan_id='+wp);by_uuid={r['id']:r for r in rows}
for b in blocks:
if b['state_hub_task_id'] not in by_uuid or by_uuid[b['state_hub_task_id']]['status']!=b['status']:raise SystemExit('task status or UUID mismatch '+b['id'])
original=(p/'preimages/workplans/NK-WP-0048-security-case-types.md').read_text();old={b['id']:b for b in [yaml.safe_load(t) for t in re.findall(r'```task\n(.*?)```',original,re.S)]}
for name in ('NK-WP-0048-T10','NK-WP-0048-T11','NK-WP-0048-T12'):
actual=next(b for b in blocks if b['id']==name)
if actual['state_hub_task_id']!=old[name]['state_hub_task_id']:raise SystemExit('prior UUID changed')
if git('show',':.custodian-brief.md') != (backup/'brief.index').read_bytes() or (owner/'.custodian-brief.md').read_bytes() != (backup/'brief.worktree').read_bytes():raise SystemExit('brief not preserved')
for rel,h in manifest['postimages'].items():
if not rel.startswith('workplans/') and sha((owner/rel).read_bytes())!=h:raise SystemExit('reviewed source drift')
source_commit='0775c2bfa41af236301155bb5a69bbf088bdf823';current=git('rev-parse','HEAD').decode().strip();published=git('rev-parse','origin/main').decode().strip()
if current!=published:raise SystemExit('owner not published')
deps=get('/workplans/'+wp+'/dependencies/')
(p/'projection-tasks.json').write_text(json.dumps([{'id':b['id'],'uuid':b['state_hub_task_id'],'status':b['status'],'depends_on':b.get('depends_on',[])} for b in blocks],indent=2)+'\n')
(p/'projection-dependencies.json').write_text(json.dumps(deps,indent=2)+'\n')
summary='NetKingdom reviewed registration adapter source published as '+source_commit+'; source task/projection receipt '+current+'. 36 fixtures pass with canonical Warden d97652a producer pins. T13 source done; T12/T14/T15/T16 remain todo and T06 native acceptance remains wait. R1 checker-binding refusal preserved, corrected R2/R3. Both generated-only sync hook refusals and exact staged/working brief preservation retained; no credentials or native action.'
task=next(b for b in blocks if b['id']=='NK-WP-0048-T13')['state_hub_task_id']
req=urllib.request.Request('http://127.0.0.1:8000/progress/',data=json.dumps({'summary':summary,'event_type':'note','author':'codex','workplan_id':wp,'task_id':task}).encode(),headers={'Content-Type':'application/json'},method='POST')
progress=json.load(urllib.request.urlopen(req,timeout=10));(p/'owner-progress.json').write_text(json.dumps(progress,indent=2)+'\n')
syncs={name:{'exit_code':json.loads((p/(name+'.exit.json')).read_text())['exit_code'],'summary':json.loads((p/(name+'.stdout.json')).read_text())['summary'],'result':json.loads((p/(name+'.stdout.json')).read_text())['result'],'stderr':(p/(name+'.stderr.txt')).read_text()} for name in ('normal-sync','normal-writeback','normal-final')}
receipt={'schema':'custodian.netkingdom.registration-source-integration.v1','source_commit':source_commit,'publication_record_commit':current,'published_origin':published,'reviewed_r3_manifest_sha256':sha((p/'reviewed-r3/manifest.json').read_bytes()),'root_review':'coordinator-review-r3.json','source_integration':True,'normal_syncs':syncs,'file_task_count':len(blocks),'projected_task_count':len(rows),'status_counts':dict(Counter(b['status'] for b in blocks)),'prior_T10_T11_T12_UUIDs_preserved':True,'reviewed_source_hashes_preserved':True,'exact_original_staged_brief_preserved':True,'exact_original_working_brief_preserved':True,'final_source_hashes':{rel:sha((owner/rel).read_bytes()) for rel in manifest['postimages']},'status_after':git('status','--porcelain=v1').decode(),'tests':{'passed':36,'synthetic':True,'producer_pins_overridden':False},'native_acceptance':False,'new_credential_or_live_action':False,'next_tasks':['NK-WP-0048-T12','NK-WP-0048-T14','NK-WP-0048-T15','NK-WP-0048-T16'],'retained_failed_revision':'rejected-r1/','progress_id':progress.get('id')}
(p/'canonical-integration.json').write_text(json.dumps(receipt,indent=2)+'\n');print(json.dumps({'source_commit':source_commit,'final_commit':current,'count':len(blocks),'statuses':receipt['status_counts'],'progress_id':progress.get('id')}))

View file

@ -0,0 +1,669 @@
--- /dev/null
+++ b/sso-mfa/k8s/keycape/keycape-registration-adapter.py
@@ -0,0 +1,180 @@
+"""Unexercised, injection-only attended registration seam for Warden's v1 kernel.
+
+No CLI, credentials, evidence trust root or live registration is installed here.
+Owner publication/authentication and parent-session revocation are mandatory
+injected capabilities. The kernel must independently admit both evidence kinds.
+"""
+from __future__ import annotations
+
+import argparse
+from dataclasses import asdict, replace
+import json
+import importlib.util
+from pathlib import Path
+
+import yaml
+
+from warden.case_run import Adapter, Descriptor, Invocation, OwnerResult, contained_output, digest, IDENTIFIER, DIGEST
+from warden.case_receipt_state import Outcome, Refused
+
+ROOT = Path(__file__).resolve().parent
+SOURCE_FILES = ('keycape-registration-adapter.py', 'keycape-client.py',
+ 'portal-client-rollout.py', 'openbao-client-config.py',
+ 'register-user-engine-portal.py')
+REFERENCE = 'net-kingdom/keycape-registration@v1'
+
+# Importing the maintained helper performs no tooling operation.
+_spec = importlib.util.spec_from_file_location('registration_owner_helper', ROOT / 'keycape-client.py')
+helper = importlib.util.module_from_spec(_spec)
+_spec.loader.exec_module(helper)
+
+
+def source_digest(check_config_digest):
+ """Pin adapter plus the complete local helper import closure, in filename order."""
+ if not isinstance(check_config_digest, str) or not DIGEST.fullmatch(check_config_digest):
+ raise Refused('exact reviewed checker digest required')
+ composition = {'files': {name: digest((ROOT / name).read_bytes()) for name in SOURCE_FILES},
+ 'check_config_binary': check_config_digest}
+ return digest(json.dumps(composition, sort_keys=True, separators=(',', ':')).encode())
+
+
+def descriptor(check_config_digest):
+ return Descriptor('warden.case.execution.v1', 'register-client', 'net-kingdom',
+ REFERENCE, source_digest(check_config_digest), 'human', 'key-cape-oidc-login',
+ 'client_id', 'change', ('keycape-client',), False,
+ ('parent-session',))
+
+
+def build(*, admitted: Invocation, case_source: bytes, expected_uid: str,
+ expected_resource_version: str, case_acceptance: str,
+ check_config: Path, check_config_digest: str, publish, authenticate,
+ revoke_session):
+ """Bind one admitted case and observed revision; return a closed kernel Adapter.
+
+ publish(bytes)->identifier durably retains only the closed metadata payload.
+ authenticate(identifier, bytes)->True must verify independent owner custody.
+ revoke_session(invocation)->identifier must revoke this attempt's parent
+ session; Warden independently authenticates it using its own evidence verifier.
+ These callbacks are capabilities, never command strings or case parameters.
+
+ Only a verified creation in this process may be rolled back. Process loss,
+ write/readback ambiguity, publication/revocation failure and source drift
+ require owner reconciliation; none are converted to retry-safe failures.
+ """
+ reviewed_source = source_digest(check_config_digest)
+ desc = descriptor(check_config_digest)
+ if type(admitted) is not Invocation or not all(
+ isinstance(value, str) and IDENTIFIER.fullmatch(value)
+ for value in (admitted.step, admitted.owner, admitted.target,
+ admitted.actor, admitted.principal, admitted.lane)):
+ raise Refused('bounded invocation required')
+ if desc.adapter_source != reviewed_source:
+ raise Refused('owner source changed during binding')
+ if (admitted.step, admitted.owner, admitted.actor, admitted.lane) != (
+ desc.step, desc.owner, desc.actor, desc.lane):
+ raise Refused('registration invocation boundary differs')
+ if admitted.operation != 'admission' or admitted.attempt_id:
+ raise Refused('expected admission invocation')
+ if type(case_source) is not bytes or len(case_source) > 262144 or digest(case_source) != admitted.pins.case:
+ raise Refused('case source pin differs')
+ # Pins.adapter is the descriptor digest, not the owner source digest.
+ descriptor_bytes = json.dumps(asdict(desc), sort_keys=True, separators=(',', ':')).encode()
+ if admitted.pins.adapter != digest(descriptor_bytes):
+ raise Refused('descriptor pin differs')
+ if not all(isinstance(x, str) and 0 < len(x) <= 192 for x in
+ (expected_uid, expected_resource_version, case_acceptance)):
+ raise Refused('bounded attended binding required')
+ if digest(case_acceptance.encode()) != admitted.pins.acceptance:
+ raise Refused('acceptance evidence binding differs')
+ if not all(callable(x) for x in (publish, authenticate, revoke_session)):
+ raise Refused('owner evidence and revocation capabilities required')
+ with contained_output():
+ case = yaml.safe_load(case_source)
+ client = helper.client_from_case(case)
+ if admitted.target != client['clientId']:
+ raise Refused('case target differs')
+ check_config = Path(check_config)
+ records = {}
+ creation = None
+
+ def binding(inv, operation):
+ if (replace(inv, attempt_id='', operation='admission') != admitted
+ or inv.operation != operation or not IDENTIFIER.fullmatch(inv.attempt_id)):
+ raise Refused('attempt binding differs')
+ if source_digest(check_config_digest) != reviewed_source:
+ raise Refused('owner source changed')
+ if digest(check_config.read_bytes()) != check_config_digest:
+ raise Refused('check-config binary changed')
+
+ def execute(inv, operation, created=()):
+ nonlocal creation
+ try:
+ with contained_output():
+ binding(inv, 'run' if operation == 'add' else 'rollback')
+ uid, revision = expected_uid, expected_resource_version
+ if operation == 'remove':
+ if (created != ('keycape-client',) or creation is None
+ or not verify(*creation)):
+ raise Refused('no authenticated case-created client')
+ original_payload = json.loads(records[creation[1].evidence][1])
+ uid, revision = original_payload['after']['uid'], original_payload['after']['resource_version']
+ args = argparse.Namespace(mode='apply', operation=operation,
+ expected_uid=uid, expected_resource_version=revision,
+ case_acceptance=case_acceptance, check_config=str(check_config))
+ receipt = helper.run(args, client)
+ # The helper has completed CAS, whole-data readback and preservation.
+ # Never retain check-config diagnostics or arbitrary helper fields.
+ if not (receipt['schema'] == 'netkingdom.keycape-client.v1'
+ and receipt['target'] == 'sso/keycape-config'
+ and receipt['client_id'] == admitted.target
+ and receipt['mode'] == 'apply' and receipt['operation'] == operation
+ and receipt['values_emitted'] is False
+ and type(receipt['changed']) is bool
+ and receipt['unrelated_config_bytes_preserved'] is True
+ and receipt['other_secret_data_unchanged'] is True
+ and receipt['before'] == {'uid': uid, 'resource_version': revision}
+ and receipt['after']['uid'] == uid
+ and receipt['check_config']['proposed']['valid'] is True):
+ raise Refused('owner readback contract differs')
+ after = receipt['after']
+ if (set(after) != {'uid', 'resource_version'} or
+ not all(isinstance(v, str) and 0 < len(v) <= 192 for v in after.values())):
+ raise Refused('owner revision contract differs')
+ changed = receipt['changed']
+ outcome = (Outcome.ROLLED_BACK if operation == 'remove' else
+ Outcome.SUCCESS if changed else Outcome.NO_CHANGE)
+ objects = ('keycape-client',) if operation == 'add' and changed else ()
+ finally:
+ # Even helper failure must end the parent session. Failures propagate
+ # contained to the kernel and become uncertain, never safe to replay.
+ with contained_output():
+ revocation = revoke_session(inv)
+ if not isinstance(revocation, str) or not IDENTIFIER.fullmatch(revocation):
+ raise Refused('session revocation evidence missing')
+ payload = json.dumps({'schema': 'netkingdom.keycape-registration.attempt.v1',
+ 'invocation': asdict(inv), 'source': reviewed_source,
+ 'outcome': outcome.value, 'created': objects, 'before': receipt['before'],
+ 'after': after, 'session_revocation': revocation},
+ sort_keys=True, separators=(',', ':')).encode()
+ with contained_output():
+ evidence = publish(payload)
+ if not isinstance(evidence, str) or not IDENTIFIER.fullmatch(evidence) or evidence in records:
+ raise Refused('owner evidence identifier invalid or reused')
+ result = OwnerResult(outcome, evidence, objects, True, revocation,
+ attempt_id=inv.attempt_id, operation=inv.operation)
+ records[evidence] = (inv, payload, result)
+ if operation == 'add' and changed:
+ creation = (inv, result)
+ elif operation == 'remove':
+ creation = None
+ return result
+
+ def verify(inv, result):
+ record = records.get(result.evidence) if type(result) is OwnerResult else None
+ if record is None or record[0] != inv or record[2] != result:
+ return False
+ with contained_output():
+ return authenticate(result.evidence, record[1]) is True
+
+ return Adapter(REFERENCE, reviewed_source, lambda inv: execute(inv, 'add'),
+ verify, lambda inv, created: execute(inv, 'remove', created))
--- /dev/null
+++ b/sso-mfa/k8s/keycape/test_keycape_registration_adapter.py
@@ -0,0 +1,289 @@
+"""Actual helper/CAS execution against synthetic Kubernetes objects only."""
+from dataclasses import asdict, replace
+import copy
+import importlib.util
+import json
+from pathlib import Path
+import tempfile
+import unittest
+from unittest.mock import patch
+
+from warden.case_run import Invocation, digest
+from warden.case_receipt_state import Outcome, Pins, Refused
+import yaml
+
+ROOT = Path(__file__).parent
+spec = importlib.util.spec_from_file_location('registration_adapter', ROOT / 'keycape-registration-adapter.py')
+a = importlib.util.module_from_spec(spec)
+spec.loader.exec_module(a)
+spec = importlib.util.spec_from_file_location('registration_fixture', ROOT / 'test_keycape_client.py')
+f = importlib.util.module_from_spec(spec)
+spec.loader.exec_module(f)
+
+
+class RegistrationTests(unittest.TestCase):
+ def setUp(self):
+ self.temp = tempfile.TemporaryDirectory()
+ self.binary = Path(self.temp.name) / 'keycape'
+ self.binary.write_bytes(b'synthetic checker binary')
+ self.case = yaml.safe_dump({'spec': {'type': 'oidc-browser-relying-party@1.1',
+ 'parameters': f.FORGEJO_PARAMS}}).encode()
+ desc = a.descriptor(digest(self.binary.read_bytes()))
+ self.desc_bytes = json.dumps(asdict(desc), sort_keys=True, separators=(',', ':')).encode()
+ pins = Pins(digest(self.case), digest(b'type'), digest(self.desc_bytes),
+ digest(b'catalog'), digest(b'case-acceptance:test'), digest(b'run sheet'))
+ self.admitted = Invocation('register-client', 'net-kingdom', 'forgejo', 'human',
+ 'founder', 'key-cape-oidc-login', pins)
+ self.inv = replace(self.admitted, attempt_id='attempt-one', operation='run')
+ self.secret, self.raw = f.fixture()
+ self.effects = []
+ self.evidence = {}
+ self.revocations = []
+ self.kw = dict(admitted=self.admitted, case_source=self.case,
+ expected_uid=f.UID, expected_resource_version='7', case_acceptance='case-acceptance:test',
+ check_config=self.binary, check_config_digest=digest(self.binary.read_bytes()),
+ publish=self.publish, authenticate=lambda ref, payload: self.evidence.get(ref) == payload,
+ revoke_session=self.revoke)
+ self.check_patch = patch.object(a.helper, 'check_config', return_value={'valid': True})
+ self.kube_patch = patch.object(a.helper.lane, 'kubectl', side_effect=self.kube)
+ self.check_patch.start()
+ self.kube_patch.start()
+ self.addCleanup(self.check_patch.stop)
+ self.addCleanup(self.kube_patch.stop)
+ self.addCleanup(self.temp.cleanup)
+
+ def publish(self, payload):
+ ref = 'owner-evidence:attempt-' + str(len(self.evidence))
+ self.evidence[ref] = payload
+ return ref
+
+ def revoke(self, inv):
+ self.revocations.append(inv)
+ return 'session-revoked:' + inv.operation + ':' + inv.attempt_id
+
+ def kube(self, args, payload=None):
+ if args[:3] == ['get', 'namespace', 'kube-system']:
+ return {'metadata': {'uid': a.helper.lane.CLUSTER_UID}}
+ if args[:5] == ['-n', 'sso', 'get', 'secret', 'keycape-config']:
+ return copy.deepcopy(self.secret)
+ if args[:5] == ['-n', 'sso', 'get', 'deployment', 'keycape']:
+ return {'spec': {'template': {'spec': {'containers': [{'name': 'keycape',
+ 'env': [a.helper.env_binding(f.FORGEJO)]}]}}}}
+ if args[:5] == ['-n', 'sso', 'patch', 'secret', 'keycape-config']:
+ self.assertEqual(payload[:2], [
+ {'op': 'test', 'path': '/metadata/uid', 'value': self.secret['metadata']['uid']},
+ {'op': 'test', 'path': '/metadata/resourceVersion', 'value': self.secret['metadata']['resourceVersion']}])
+ self.effects.append(copy.deepcopy(payload))
+ self.secret['data']['config.yaml'] = payload[2]['value']
+ self.secret['metadata']['resourceVersion'] = str(int(self.secret['metadata']['resourceVersion']) + 1)
+ return copy.deepcopy(self.secret)
+ raise AssertionError('unexpected tooling operation')
+
+ def test_actual_add_and_created_only_rollback_preserve_original_bytes(self):
+ adapter = a.build(**self.kw)
+ original = copy.deepcopy(self.secret['data'])
+ result = adapter.invoke(self.inv)
+ self.assertEqual(result.outcome, Outcome.SUCCESS)
+ self.assertEqual(result.created, ('keycape-client',))
+ self.assertTrue(adapter.verify(self.inv, result))
+ undone = adapter.rollback(replace(self.inv, attempt_id='attempt-two', operation='rollback'), result.created)
+ self.assertEqual(undone.outcome, Outcome.ROLLED_BACK)
+ self.assertEqual(self.secret['data'], original)
+ self.assertEqual(len(self.effects), 2)
+ self.assertEqual(len(self.revocations), 2)
+ for payload in self.evidence.values():
+ self.assertNotIn(b'synthetic-marker', payload)
+ self.assertNotIn(b'config.yaml', payload)
+ self.assertNotIn(b'signing-key', payload)
+
+ def test_identical_client_is_no_change_and_cannot_be_removed(self):
+ self.secret, _ = f.fixture(f.EXISTING + [f.FORGEJO])
+ adapter = a.build(**self.kw)
+ result = adapter.invoke(self.inv)
+ self.assertEqual(result.outcome, Outcome.NO_CHANGE)
+ self.assertEqual(result.created, ())
+ with self.assertRaises(Refused):
+ adapter.rollback(replace(self.inv, operation='rollback'), ('keycape-client',))
+ self.assertFalse(self.effects)
+
+ def test_existing_drift_refused_and_session_revoked(self):
+ self.secret, _ = f.fixture(f.EXISTING + [dict(f.FORGEJO, displayName='Drift')])
+ with self.assertRaises(Refused):
+ a.build(**self.kw).invoke(self.inv)
+ self.assertFalse(self.effects)
+ self.assertEqual(self.revocations, [self.inv])
+
+ def test_invocation_rebinding_refused_before_tooling(self):
+ for changes in ({'target': 'other'}, {'principal': 'other'}, {'actor': 'agent'},
+ {'lane': 'other'}, {'operation': 'rollback'}, {'attempt_id': ''},
+ {'pins': replace(self.inv.pins, case=digest(b'other'))}):
+ with self.subTest(changes=changes), self.assertRaises(Refused):
+ a.build(**self.kw).invoke(replace(self.inv, **changes))
+ self.assertFalse(self.effects)
+
+ def test_initial_case_descriptor_and_target_pins_are_required(self):
+ for changes in ({'case_source': b'{}'}, {'case_acceptance': 'other'}, {'admitted': replace(self.admitted, target='other')},
+ {'admitted': replace(self.admitted, actor='agent')},
+ {'admitted': replace(self.admitted, pins=replace(self.admitted.pins, adapter=digest(b'wrong')))}):
+ with self.subTest(changes=changes), self.assertRaises(Refused):
+ a.build(**dict(self.kw, **changes))
+ self.assertFalse(self.effects)
+
+ def test_binary_or_source_drift_refused_before_tooling(self):
+ adapter = a.build(**self.kw)
+ self.binary.write_bytes(b'changed')
+ with self.assertRaises(Refused):
+ adapter.invoke(self.inv)
+ self.binary.write_bytes(b'synthetic checker binary')
+ with patch.object(a, 'source_digest', return_value=digest(b'changed')):
+ with self.assertRaises(Refused):
+ adapter.invoke(self.inv)
+ self.assertFalse(self.effects)
+
+ def test_substituting_caller_selected_checker_under_same_descriptor_is_refused(self):
+ substitute = Path(self.temp.name) / 'other-checker'
+ substitute.write_bytes(b'caller-selected executable')
+ with self.assertRaisesRegex(Refused, 'descriptor pin differs'):
+ a.build(**dict(self.kw, check_config=substitute,
+ check_config_digest=digest(substitute.read_bytes())))
+ self.assertFalse(self.effects)
+
+ def test_stale_revision_refuses_mutation(self):
+ adapter = a.build(**self.kw)
+ self.secret['metadata']['resourceVersion'] = '8'
+ with self.assertRaises(Refused):
+ adapter.invoke(self.inv)
+ self.assertFalse(self.effects)
+
+ def test_rollback_requires_exact_provenance_and_postcreation_revision(self):
+ adapter = a.build(**self.kw)
+ result = adapter.invoke(self.inv)
+ rollback = replace(self.inv, attempt_id='attempt-two', operation='rollback')
+ for created in ((), ('other',), ('keycape-client', 'other')):
+ with self.subTest(created=created), self.assertRaises(Refused):
+ adapter.rollback(rollback, created)
+ self.secret['metadata']['resourceVersion'] = '9'
+ with self.assertRaises(Refused):
+ adapter.rollback(rollback, result.created)
+ self.assertEqual(len(self.effects), 1)
+
+ def test_missing_or_tampered_evidence_never_verifies_or_authorizes_undo(self):
+ adapter = a.build(**self.kw)
+ result = adapter.invoke(self.inv)
+ self.assertFalse(adapter.verify(replace(self.inv, attempt_id='other'), result))
+ self.assertFalse(adapter.verify(self.inv, replace(result, revoked=False)))
+ self.evidence[result.evidence] = b'forged'
+ self.assertFalse(adapter.verify(self.inv, result))
+ with self.assertRaises(Refused):
+ adapter.rollback(replace(self.inv, operation='rollback'), result.created)
+ self.assertEqual(len(self.effects), 1)
+
+ def test_process_loss_does_not_reconstruct_created_authority(self):
+ result = a.build(**self.kw).invoke(self.inv)
+ fresh = a.build(**self.kw)
+ with self.assertRaises(Refused):
+ fresh.rollback(replace(self.inv, operation='rollback'), result.created)
+ self.assertIsNone(fresh.reconcile)
+ self.assertEqual(len(self.effects), 1)
+
+ def test_failed_readback_is_uncertain_and_never_provides_creation(self):
+ original_kube = self.kube
+ def lost(args, payload=None):
+ if self.effects and args[:5] == ['-n', 'sso', 'get', 'secret', 'keycape-config']:
+ raise RuntimeError('synthetic sensitive detail')
+ return original_kube(args, payload)
+ with patch.object(a.helper.lane, 'kubectl', side_effect=lost):
+ adapter = a.build(**self.kw)
+ with self.assertRaisesRegex(Refused, '^owner callback failed$'):
+ adapter.invoke(self.inv)
+ self.assertEqual(len(self.effects), 1)
+ self.assertFalse(self.evidence)
+ self.assertEqual(self.revocations, [self.inv])
+
+ def test_revocation_or_publication_failure_cannot_produce_verified_success(self):
+ for capability in ('publish', 'revoke_session'):
+ self.secret, _ = f.fixture()
+ with self.subTest(capability=capability):
+ kw = dict(self.kw, **{capability: lambda *args: (_ for _ in ()).throw(RuntimeError('private'))})
+ adapter = a.build(**kw)
+ with self.assertRaisesRegex(Refused, '^owner callback failed$'):
+ adapter.invoke(self.inv)
+ self.assertFalse(self.evidence)
+
+ def kernel_fixture(self):
+ # Fixture-only proposed type/case; canonical files are never edited.
+ # Warden's published producer pins apply unchanged. Owner trust and
+ # proposed descriptor/type/case are fixture-only, never native admission.
+ import warden.case_inputs as inputs
+ from warden.case_run import Executor, Journal
+ root = ROOT.parents[2]
+ case = yaml.safe_load((root / 'security-cases/forgejo-netkingdom-oidc.yaml').read_bytes())
+ case['spec']['status'] = 'materialized'
+ case_source = yaml.safe_dump(case).encode()
+ typ = yaml.safe_load((root / 'security-case-types/oidc-browser-relying-party/type.yaml').read_bytes())
+ typ['spec']['execution_descriptors'] = {'register-client': digest(self.desc_bytes)}
+ type_source = yaml.safe_dump(typ).encode()
+ catalog = b'fixture-only-catalog'
+ sheet = json.dumps(['register-client', 'net-kingdom', 'forgejo', 'human',
+ 'founder', 'key-cape-oidc-login', 'fixture-acceptance', 'fixture-materialization',
+ 'fixture-descriptor', 'fixture-session'], separators=(',', ':')).encode()
+ pins = Pins(digest(case_source), digest(type_source), digest(self.desc_bytes),
+ digest(catalog), digest(b'fixture-acceptance'), digest(sheet))
+ invocation = replace(self.admitted, pins=pins)
+ adapter = a.build(**dict(self.kw, admitted=invocation, case_source=case_source,
+ case_acceptance='fixture-acceptance'))
+ def fixture_verifier(purpose, source, evidence):
+ if purpose.startswith('session-revocation:'):
+ _, lane, operation, attempt = purpose.split(':')
+ return source == digest(case_source) and lane == invocation.lane and evidence == (
+ 'session-revoked:' + operation + ':' + attempt)
+ return evidence in {'fixture-acceptance', 'fixture-materialization',
+ 'fixture-descriptor', 'fixture-session'}
+ executor = Executor(Journal(Path(self.temp.name) / 'private'),
+ {adapter.reference: adapter}, fixture_verifier, browser_inputs=inputs.BrowserInputs(root))
+ admitted = executor.admit(case_source, type_source, self.desc_bytes, catalog,
+ principal='founder', actor='human', lane=invocation.lane,
+ acceptance_evidence='fixture-acceptance', materialization_evidence='fixture-materialization',
+ descriptor_evidence='fixture-descriptor', session_evidence='fixture-session')
+ self.assertEqual(admitted[1], invocation)
+ return executor, admitted
+
+ def test_actual_kernel_admission_dispatch_and_rollback_with_fixture_only_trust(self):
+ executor, admitted = self.kernel_fixture()
+ result = executor.run(*admitted)
+ self.assertEqual(result.last.outcome, Outcome.SUCCESS)
+ self.assertEqual(result.last.created, ('keycape-client',))
+ undone = executor.rollback(*admitted)
+ self.assertEqual(undone.last.outcome, Outcome.ROLLED_BACK)
+ self.assertEqual(len(self.effects), 2)
+ self.assertEqual(len(self.revocations), 2)
+
+ def test_kernel_lost_readback_retains_uncertain_and_refuses_replay_and_undo(self):
+ executor, admitted = self.kernel_fixture()
+ original_kube = self.kube
+ def lost(args, payload=None):
+ if self.effects and args[:5] == ['-n', 'sso', 'get', 'secret', 'keycape-config']:
+ raise RuntimeError('synthetic sensitive detail')
+ return original_kube(args, payload)
+ with patch.object(a.helper.lane, 'kubectl', side_effect=lost):
+ result = executor.run(*admitted)
+ self.assertEqual(result.last.outcome, Outcome.UNCERTAIN)
+ self.assertFalse(result.last.created)
+ with self.assertRaises(Refused):
+ executor.run(*admitted, retry=True)
+ with self.assertRaises(Refused):
+ executor.rollback(*admitted)
+ self.assertEqual(len(self.effects), 1)
+ self.assertEqual(len(self.revocations), 1)
+
+ def test_kernel_external_revision_change_retains_uncertain_rollback(self):
+ executor, admitted = self.kernel_fixture()
+ self.assertEqual(executor.run(*admitted).last.outcome, Outcome.SUCCESS)
+ self.secret['metadata']['resourceVersion'] = '9'
+ self.assertEqual(executor.rollback(*admitted).last.outcome, Outcome.ROLLBACK_UNCERTAIN)
+ self.assertEqual(len(self.effects), 1)
+ self.assertEqual(len(self.revocations), 2)
+
+
+if __name__ == '__main__':
+ unittest.main()
--- /dev/null
+++ b/sso-mfa/k8s/keycape/registration-adapter.md
@@ -0,0 +1,59 @@
+# Attended registration adapter candidate
+
+Exercise status: unexercised
+
+This is a source-only, injection-only adapter for the existing Warden closed
+kernel. It installs no command, runtime dispatcher, credential provider, evidence
+trust root or new service. NetKingdom type/case status and bytes remain unchanged.
+The generated descriptor is a proposal; it is not owner acknowledgment.
+
+`keycape-registration-adapter.py` wraps maintained `keycape-client.run` in apply
+mode. A fixed invocation binds principal, human actor, lane, case/type/descriptor/
+catalog/acceptance/run-sheet digests and target. The descriptor pins this adapter
+and its complete local helper import closure together with the exact reviewed
+`check-config` executable digest. Changing that digest changes the descriptor
+source pin and descriptor bytes, requiring independently reviewed admission.
+The fixed executable is rehashed before each attempt. The caller constructs the
+proposed invocation from exact source inputs, installs the fixed adapter once,
+and calls normal `Executor.admit`; independently derived admission must match.
+No callable replacement after admission is required or supported by this recipe.
+
+The operation uses existing cluster/issuer checks, byte-preserving merge,
+Deployment secret-env prerequisite, config validation, UID/resourceVersion CAS
+and whole-data readback. Only closed metadata is passed to the injected durable
+owner publisher. The owner authenticator must independently authenticate those
+exact bytes. The session-revocation capability must end the same attempt's
+parent session; Warden separately verifies its exact revocation evidence.
+These capabilities are owner-selected callables, never case-supplied commands.
+No implementation of these native capabilities is supplied or implied here.
+
+An identical existing client returns no change and creates no rollback authority.
+Removal requires this process's independently authenticated successful creation
+receipt, exact created-object label, unchanged postcreation UID/resourceVersion,
+and the original exact client record. External drift, a lost readback, receipt
+publication/revocation failure or process loss requires owner reconciliation.
+No uncertainty is labeled retry-safe. No automatic reconciliation is installed.
+Rollback after restart intentionally remains unavailable until an owner supplies
+independently authenticated durable creation provenance and reviews recovery.
+
+The source tests execute actual maintained helper CAS/readback against synthetic
+Kubernetes objects. Three checks exercise actual Warden admission/run/rollback
+and uncertainty transitions with synthetic owner trust. Warden d97652a's exact
+published producer source pins apply unchanged through actual BrowserInputs.
+This is a source compatibility fixture, not acknowledgment, owner provenance,
+normal native admission or deployment acceptance.
+
+Remaining work belongs in live work records before T12 closure:
+
+- Warden owns global evidence admission and exact native evidence/session
+ capabilities. Published d97652a refreshes BrowserInputs producer pins for
+ NetKingdom 015694ee; that source assent does not attest this new adapter.
+- NetKingdom owns separately reviewed descriptor/type pin selection, the env
+ binding/config/restart steps, and group ensure/revoke provenance. Current group
+ ensure does not report newly added memberships; current revoke can remove
+ memberships that predate the case. Wrapping these as reversible creation would
+ be unsound. Preserve them until a reviewed created-only contract exists.
+- Platform owns structural/mint/broker and secret delivery evidence; Apps owns
+ actual consumer login and group enforcement. No assent is supplied here.
+- Attended use still requires existing owner authorization, current caller
+ identity, native source/config/image pins, native receipts and cleanup proof.
--- a/workplans/NK-WP-0048-security-case-types.md
+++ b/workplans/NK-WP-0048-security-case-types.md
@@ -323,7 +323,7 @@
```task
id: NK-WP-0048-T06
status: wait
-depends_on: [NK-WP-0048-T05, NK-WP-0048-T08, NK-WP-0048-T09, NK-WP-0048-T12, MASON-WP-0010-T03, WARDEN-WP-0044-T03]
+depends_on: [NK-WP-0048-T05, NK-WP-0048-T08, NK-WP-0048-T09, NK-WP-0048-T12, NK-WP-0048-T13, NK-WP-0048-T14, NK-WP-0048-T15, NK-WP-0048-T16, MASON-WP-0010-T03, WARDEN-WP-0044-T03]
blocking_reason: "Type1.2 architecture has a confirmed source-only founder acknowledgment; canonical1.1 remains unchanged/default and the1.2 reference case stays proposed. Needs explicit version selection/reference-source integration without normal admission bypass, closed owner adapters plus global/native receipt verifier (WARDEN-WP-0044-T03), independently verified six-object structural materialization and CCR42 claims/created-only provenance, exact broker/case/source reconciliation, then separately authorized native mint/delivery and attended registry/consumer verification. Source acknowledgment, a bundle or local tests do not prove implemented/materialized/live status."
priority: high
state_hub_task_id: "d9b26bcf-a7c6-59a2-92a0-f913d76a203c"
@@ -631,17 +631,106 @@
state_hub_task_id: "7ce4eee3-cd47-55a9-bfa5-4f1835d4d6fd"
```
-Owner: NetKingdom. Next action: wrap the existing contained `keycape-client.py`
-registration/config/env and identity-provisioner ensure/revoke entry points in
-bounded owner adapters or receipt-only attended steps for Warden's closed kernel.
-Reuse the existing caller/session boundary, CAS/readback and status-only outputs;
-never acquire user-engine's runtime identity or expose registry/client secrets.
-Completion requires exact adapter/source descriptors, positive and refusal source
-checks, uncertainty/created-only rollback behavior and a separate owner review of
-the proposed machine seam. Source preparation can begin without credentials.
-Warden independently owns global provenance/admission integration; Platform owns
-mint/broker and native structural receipts; Apps owns consumer delivery/group
-acceptance. Their assent is not supplied by this task. Pinning descriptors into
-an acknowledged type remains a separately reviewed type-source change. Actual
-attended execution still requires its existing owner authorization and native
-receipts. T06 retains all native/reference lifecycle acceptance scope.
+Owner: NetKingdom. Retained scope: prepare bounded attended Deployment env,
+config verification and restart/readiness steps around the existing helpers.
+Next action: identify exact current entry points and their revision/readback
+contracts, then implement fixed source-pinned callbacks or receipt-only attended
+steps. Completion requires positive/refusal checks, exact target/source pins and
+uncertainty behavior without acquiring user-engine runtime identity or exposing
+registry/client secrets. Existing caller/session, cluster/issuer, CAS/readback
+and status-only output boundaries remain mandatory.
+
+2026-10-16 task refinement: the original broad adapter scope is split into T13
+(completed registration source candidate), T14 (group creation provenance), T15
+(durable registration recovery) and T16 (descriptor/artifact selection and owner
+review). This preserves T12's task ID and Hub UUID while giving each remaining
+outcome an owner and completion gate. T06 now names every source dependency;
+its native/reference lifecycle acceptance scope remains unchanged. Completion
+of any source task supplies no Warden, Platform or Apps assent and no native
+execution authority.
+
+## T13 — Prepare the fixed registration adapter source candidate
+
+```task
+id: NK-WP-0048-T13
+status: done
+priority: high
+```
+
+Completed 2026-10-16, source implementation and synthetic fixture proof only.
+Added an injection-only adapter around actual `keycape-client.run`: fixed
+case/principal/human/lane/source/acceptance binding, existing CAS/readback,
+metadata-only owner evidence and per-attempt parent-session revocation boundary.
+The descriptor source composition pins the exact checker executable digest
+alongside adapter/helper source. Creation-only rollback authenticates its
+creation receipt and refuses changed postcreation UID/resourceVersion;
+pre-existing clients confer no rollback authority. Missing readback, evidence,
+revocation or process-local creation provenance cannot become retry-safe success.
+
+Evidence: Custodian `docs/changes/netkingdom-target-2026-10-16/browser-adapter-next/`
+R3 candidate, explicit patch and postimages, retained R1 rejected custody finding
+and R2 revision, and 36 passing source checks (16 new, 20 existing). Three checks
+use actual Warden kernel admission/dispatch/rollback with published Warden
+`d97652a3bb5fa733b063d71a1b74068efcccf572` producer pins unchanged. Owner trust,
+descriptor/type/case and Kubernetes objects remain synthetic fixtures. This
+records a completed source deliverable, not independent review, publication,
+type acknowledgment, exercised procedure, identity admission or native browser
+acceptance. Exact root review/publication receipts are required on integration.
+
+## T14 — Preserve created-only provenance for group ensure and revoke
+
+```task
+id: NK-WP-0048-T14
+status: todo
+priority: high
+```
+
+Owner: NetKingdom. Next action: extend or wrap the existing identity-provisioner
+ensure/revoke contract with independently retained prestate and exact newly
+created groups/memberships before exposing reversible owner callbacks. Current
+ensure returns no membership-creation inventory; current revoke may remove a
+membership that predated this case. Completion requires actual helper-backed
+positive/refusal fixtures, all validation before mutation, per-attempt evidence
+and revocation, readback, ambiguity handling, and rollback that preserves every
+pre-existing/shared group and membership. No existing endpoint or service token
+is treated as new authorization.
+
+## T15 — Define authenticated recovery for lost registration process state
+
+```task
+id: NK-WP-0048-T15
+status: todo
+priority: high
+```
+
+Owner: NetKingdom for registration state, with Warden owning kernel evidence
+admission. Next action: select the exact existing owner evidence holder/readback
+contract and define authenticated lookup for the original creation attempt.
+Completion requires restart/lost-receipt fixtures that bind case/source/principal,
+original created-only provenance and current native revision before any undo;
+uncertain outcomes remain non-replayable. The T13 adapter deliberately refuses
+post-restart rollback and installs no reconciliation callback. A new broker or
+unverified JSON receipt is not a recovery contract. Actual evidence-holder
+acceptance and attended recovery remain separately authorized native work.
+
+## T16 — Select and review the actual machine descriptor composition
+
+```task
+id: NK-WP-0048-T16
+status: todo
+priority: high
+```
+
+Owner: NetKingdom for descriptor/type source and exact checker artifact; Warden
+independently owns global provenance/admission. Next action: identify the exact
+reviewed checker executable artifact and native owner evidence/session callback
+contracts, then assemble the complete step descriptor set and a proposed explicit
+type version selection. T13's retained descriptor pins a synthetic checker only.
+Completion requires separate owner source review of exact machine descriptors,
+artifact/source/config pins, normal type/version admission and independent
+evidence-verification boundaries. Warden d97652a refreshes producer validator
+pins for NetKingdom 015694ee; it does not attest T13's new adapter. Pinning any
+machine descriptor into an acknowledged type is a separately reviewed source
+change. Platform owns structural/mint/broker/delivery evidence; Apps owns actual
+consumer login/group enforcement. Neither their assent nor native acceptance is
+supplied by this task.

View file

@ -0,0 +1,28 @@
from pathlib import Path
import hashlib,json,subprocess
packet=Path(__file__).resolve().parent
owner=Path('/home/worsch/net-kingdom')
manifest=json.loads((packet/'manifest.json').read_text())
review=json.loads((packet/'coordinator-review-r3.json').read_text())
sha=lambda data:'sha256:'+hashlib.sha256(data).hexdigest()
if sha((packet/'manifest.json').read_bytes()) != review['manifest_sha256']:raise SystemExit('review manifest drift')
for rel,expected in manifest['postimages'].items():
if sha((packet/'postimages'/rel).read_bytes()) != expected: raise SystemExit('postimage drift '+rel)
current=owner/rel
if rel in manifest['preimages']:
if sha(current.read_bytes()) != manifest['preimages'][rel]:raise SystemExit('preimage drift '+rel)
elif current.exists():raise SystemExit('unexpected existing path '+rel)
backup=packet/'publication-backup';backup.mkdir(exist_ok=False)
git=lambda *args:subprocess.check_output(['git','-C',str(owner),*args])
(backup/'brief.worktree').write_bytes((owner/'.custodian-brief.md').read_bytes())
(backup/'brief.index').write_bytes(git('show',':.custodian-brief.md'))
(backup/'index-record.txt').write_bytes(git('ls-files','--stage','.custodian-brief.md'))
(backup/'status.txt').write_bytes(git('status','--porcelain=v1'))
(backup/'work-records.preimage').write_bytes((owner/'WORK-RECORDS.md').read_bytes())
for rel in manifest['postimages']:
data=(packet/'postimages'/rel).read_bytes()
if rel.startswith('workplans/'):
data=data.replace(b'Exact root review/publication receipts are required on integration.',b'Independent root source review: Custodian browser-adapter-next/coordinator-review-r3.json. Source integration and normal publication/synchronization receipts: Custodian browser-adapter-next/canonical-integration.json. These receipts supply no other-owner assent or native authority.')
dest=owner/rel;dest.parent.mkdir(parents=True,exist_ok=True);dest.write_bytes(data)
(packet/'integrated-source-hashes.json').write_text(json.dumps({rel:sha((owner/rel).read_bytes()) for rel in manifest['postimages']},indent=2)+'\n')
print('Integrated four reviewed source files; retained exact brief/index and work-record preimages.')

View file

@ -0,0 +1,6 @@
{
"sso-mfa/k8s/keycape/keycape-registration-adapter.py": "sha256:8a6bd0ea111d67a0df89c7e3cd968e7bf81d29c2f2a70adf08eb747e1d1a5bdc",
"sso-mfa/k8s/keycape/test_keycape_registration_adapter.py": "sha256:beabe9fe3d2c43d296fcac475d1d0c97ebb9829debdf68846c7f32b15958641c",
"sso-mfa/k8s/keycape/registration-adapter.md": "sha256:5dc28ecc87d029d42a7bd5a02501ee2665b956e1201b8fceddb5854214d26bf8",
"workplans/NK-WP-0048-security-case-types.md": "sha256:c6ef142267f4232fe99d13edc9c9b02eb78ea89e2f3aff0bddf5436d09440e30"
}

View file

@ -0,0 +1 @@
{"exit_code": 0}

View file

@ -0,0 +1 @@
WARN: git commit failed for writeback: Generated-only commits rejected: staged

View file

@ -0,0 +1,321 @@
{
"repo_slug": "net-kingdom",
"repo_path": "/home/worsch/net-kingdom",
"source_revision": "0394484b924c82abaaa4b01716d84a0930cc4fdf",
"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-22",
"message": "Task description drift 'NK-WP-0048-T13': file content differs from DB (file wins)",
"file_path": "workplans/NK-WP-0048-security-case-types.md#NK-WP-0048-T13",
"db_id": "b264c10b-565c-5d29-b788-03cf5fbd2883",
"file_value": "Completed 2026-10-16, source implementation and synthetic fixture proof only.\nAdded an injection-only adapter around act",
"db_value": "Completed 2026-10-16, source implementation and synthetic fixture proof only.\nAdded an injection-only adapter around act",
"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-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": "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": "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-22 fixed: task b264c10b\u2026 description updated",
"brief: .custodian-brief.md updated",
"push: pushed"
],
"summary": {
"fail": 0,
"automation_error": 0,
"warn": 25,
"info": 5
},
"result": "warn"
}

View file

@ -0,0 +1 @@
{"exit_code": 0}

View file

@ -0,0 +1 @@
WARN: git commit failed for writeback: Generated-only commits rejected: staged

View file

@ -0,0 +1,427 @@
{
"repo_slug": "net-kingdom",
"repo_path": "/home/worsch/net-kingdom",
"source_revision": "0775c2bfa41af236301155bb5a69bbf088bdf823",
"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-33",
"message": "WORK-RECORDS.md is missing or stale \u2014 regenerate via fix-consistency (CUST-WP-0061-T04 generated work-record index)",
"file_path": "WORK-RECORDS.md",
"db_id": "",
"file_value": "",
"db_value": "",
"fixable": true
},
{
"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-20",
"message": "Missing DB dependency edge: task 'NK-WP-0048-T06' starts after task NK-WP-0048-T12",
"file_path": "workplans/NK-WP-0048-security-case-types.md#NK-WP-0048-T06",
"db_id": "e31f3f9d-0748-5137-b0a3-7b3ca46a66eb",
"file_value": "NK-WP-0048-T12",
"db_value": "",
"fixable": true
},
{
"severity": "WARN",
"check_id": "C-20",
"message": "Task dependency target 'NK-WP-0048-T13' of task 'NK-WP-0048-T06' is not linked to State Hub",
"file_path": "workplans/NK-WP-0048-security-case-types.md#NK-WP-0048-T06",
"db_id": "",
"file_value": "NK-WP-0048-T13",
"db_value": "",
"fixable": false
},
{
"severity": "WARN",
"check_id": "C-20",
"message": "Task dependency target 'NK-WP-0048-T14' of task 'NK-WP-0048-T06' is not linked to State Hub",
"file_path": "workplans/NK-WP-0048-security-case-types.md#NK-WP-0048-T06",
"db_id": "",
"file_value": "NK-WP-0048-T14",
"db_value": "",
"fixable": false
},
{
"severity": "WARN",
"check_id": "C-20",
"message": "Task dependency target 'NK-WP-0048-T15' of task 'NK-WP-0048-T06' is not linked to State Hub",
"file_path": "workplans/NK-WP-0048-security-case-types.md#NK-WP-0048-T06",
"db_id": "",
"file_value": "NK-WP-0048-T15",
"db_value": "",
"fixable": false
},
{
"severity": "WARN",
"check_id": "C-20",
"message": "Task dependency target 'NK-WP-0048-T16' of task 'NK-WP-0048-T06' is not linked to State Hub",
"file_path": "workplans/NK-WP-0048-security-case-types.md#NK-WP-0048-T06",
"db_id": "",
"file_value": "NK-WP-0048-T16",
"db_value": "",
"fixable": false
},
{
"severity": "WARN",
"check_id": "C-22",
"message": "Task description drift 'NK-WP-0048-T12': file content differs from DB (file wins)",
"file_path": "workplans/NK-WP-0048-security-case-types.md#NK-WP-0048-T12",
"db_id": "7ce4eee3-cd47-55a9-bfa5-4f1835d4d6fd",
"file_value": "Owner: NetKingdom. Retained scope: prepare bounded attended Deployment env,\nconfig verification and restart/readiness st",
"db_value": "Owner: NetKingdom. Next action: wrap the existing contained `keycape-client.py`\nregistration/config/env and identity-pro",
"fixable": true
},
{
"severity": "WARN",
"check_id": "C-11",
"message": "Task 'NK-WP-0048-T13' has no state_hub_task_id",
"file_path": "workplans/NK-WP-0048-security-case-types.md#NK-WP-0048-T13",
"db_id": "",
"file_value": "",
"db_value": "",
"fixable": true
},
{
"severity": "WARN",
"check_id": "C-11",
"message": "Task 'NK-WP-0048-T14' has no state_hub_task_id",
"file_path": "workplans/NK-WP-0048-security-case-types.md#NK-WP-0048-T14",
"db_id": "",
"file_value": "",
"db_value": "",
"fixable": true
},
{
"severity": "WARN",
"check_id": "C-11",
"message": "Task 'NK-WP-0048-T15' has no state_hub_task_id",
"file_path": "workplans/NK-WP-0048-security-case-types.md#NK-WP-0048-T15",
"db_id": "",
"file_value": "",
"db_value": "",
"fixable": true
},
{
"severity": "WARN",
"check_id": "C-11",
"message": "Task 'NK-WP-0048-T16' has no state_hub_task_id",
"file_path": "workplans/NK-WP-0048-security-case-types.md#NK-WP-0048-T16",
"db_id": "",
"file_value": "",
"db_value": "",
"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-33 fixed: regenerated WORK-RECORDS.md",
"C-20 fixed: dependency e31f3f9d\u2026 starts_after \u2192 7ce4eee3\u2026",
"C-22 fixed: task 7ce4eee3\u2026 description updated",
"C-11 fixed: task 'NK-WP-0048-T13' \u2192 b264c10b\u2026",
"C-11 fixed: task 'NK-WP-0048-T14' \u2192 fce95440\u2026",
"C-11 fixed: task 'NK-WP-0048-T15' \u2192 1b825705\u2026",
"C-11 fixed: task 'NK-WP-0048-T16' \u2192 200bf500\u2026",
"brief: .custodian-brief.md updated",
"push: pushed"
],
"summary": {
"fail": 0,
"automation_error": 0,
"warn": 35,
"info": 5
},
"result": "warn"
}

View file

@ -0,0 +1 @@
WARN: git commit failed for writeback: Generated-only commits rejected: staged

View file

@ -0,0 +1,354 @@
{
"repo_slug": "net-kingdom",
"repo_path": "/home/worsch/net-kingdom",
"source_revision": null,
"source_revision_reason": "dirty_workplans",
"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-20",
"message": "Missing DB dependency edge: task 'NK-WP-0048-T06' starts after task NK-WP-0048-T13",
"file_path": "workplans/NK-WP-0048-security-case-types.md#NK-WP-0048-T06",
"db_id": "e31f3f9d-0748-5137-b0a3-7b3ca46a66eb",
"file_value": "NK-WP-0048-T13",
"db_value": "",
"fixable": true
},
{
"severity": "WARN",
"check_id": "C-20",
"message": "Missing DB dependency edge: task 'NK-WP-0048-T06' starts after task NK-WP-0048-T14",
"file_path": "workplans/NK-WP-0048-security-case-types.md#NK-WP-0048-T06",
"db_id": "e31f3f9d-0748-5137-b0a3-7b3ca46a66eb",
"file_value": "NK-WP-0048-T14",
"db_value": "",
"fixable": true
},
{
"severity": "WARN",
"check_id": "C-20",
"message": "Missing DB dependency edge: task 'NK-WP-0048-T06' starts after task NK-WP-0048-T15",
"file_path": "workplans/NK-WP-0048-security-case-types.md#NK-WP-0048-T06",
"db_id": "e31f3f9d-0748-5137-b0a3-7b3ca46a66eb",
"file_value": "NK-WP-0048-T15",
"db_value": "",
"fixable": true
},
{
"severity": "WARN",
"check_id": "C-20",
"message": "Missing DB dependency edge: task 'NK-WP-0048-T06' starts after task NK-WP-0048-T16",
"file_path": "workplans/NK-WP-0048-security-case-types.md#NK-WP-0048-T06",
"db_id": "e31f3f9d-0748-5137-b0a3-7b3ca46a66eb",
"file_value": "NK-WP-0048-T16",
"db_value": "",
"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 '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": "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": "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-20 fixed: dependency e31f3f9d\u2026 starts_after \u2192 b264c10b\u2026",
"C-20 fixed: dependency e31f3f9d\u2026 starts_after \u2192 fce95440\u2026",
"C-20 fixed: dependency e31f3f9d\u2026 starts_after \u2192 1b825705\u2026",
"C-20 fixed: dependency e31f3f9d\u2026 starts_after \u2192 200bf500\u2026",
"brief: .custodian-brief.md updated",
"push: pushed"
],
"summary": {
"fail": 0,
"automation_error": 0,
"warn": 28,
"info": 5
},
"result": "warn"
}

View file

@ -0,0 +1,14 @@
{
"workplan_id": "e31f3f9d-0748-5137-b0a3-7b3ca46a66eb",
"id": "500aa2a3-21ca-4bb5-93ab-278f24fcaf32",
"topic_id": null,
"task_id": "b264c10b-565c-5d29-b788-03cf5fbd2883",
"decision_id": null,
"event_type": "note",
"summary": "NetKingdom reviewed registration adapter source published as 0775c2bfa41af236301155bb5a69bbf088bdf823; source task/projection receipt 0394484b924c82abaaa4b01716d84a0930cc4fdf. 36 fixtures pass with canonical Warden d97652a producer pins. T13 source done; T12/T14/T15/T16 remain todo and T06 native acceptance remains wait. R1 checker-binding refusal preserved, corrected R2/R3. Both generated-only sync hook refusals and exact staged/working brief preservation retained; no credentials or native action.",
"detail": null,
"author": "codex",
"session_id": null,
"created_at": "2026-10-16T19:53:37.620699Z",
"workstream_id": "e31f3f9d-0748-5137-b0a3-7b3ca46a66eb"
}

View file

@ -0,0 +1,180 @@
"""Unexercised, injection-only attended registration seam for Warden's v1 kernel.
No CLI, credentials, evidence trust root or live registration is installed here.
Owner publication/authentication and parent-session revocation are mandatory
injected capabilities. The kernel must independently admit both evidence kinds.
"""
from __future__ import annotations
import argparse
from dataclasses import asdict, replace
import json
import importlib.util
from pathlib import Path
import yaml
from warden.case_run import Adapter, Descriptor, Invocation, OwnerResult, contained_output, digest, IDENTIFIER, DIGEST
from warden.case_receipt_state import Outcome, Refused
ROOT = Path(__file__).resolve().parent
SOURCE_FILES = ('keycape-registration-adapter.py', 'keycape-client.py',
'portal-client-rollout.py', 'openbao-client-config.py',
'register-user-engine-portal.py')
REFERENCE = 'net-kingdom/keycape-registration@v1'
# Importing the maintained helper performs no tooling operation.
_spec = importlib.util.spec_from_file_location('registration_owner_helper', ROOT / 'keycape-client.py')
helper = importlib.util.module_from_spec(_spec)
_spec.loader.exec_module(helper)
def source_digest(check_config_digest):
"""Pin adapter plus the complete local helper import closure, in filename order."""
if not isinstance(check_config_digest, str) or not DIGEST.fullmatch(check_config_digest):
raise Refused('exact reviewed checker digest required')
composition = {'files': {name: digest((ROOT / name).read_bytes()) for name in SOURCE_FILES},
'check_config_binary': check_config_digest}
return digest(json.dumps(composition, sort_keys=True, separators=(',', ':')).encode())
def descriptor(check_config_digest):
return Descriptor('warden.case.execution.v1', 'register-client', 'net-kingdom',
REFERENCE, source_digest(check_config_digest), 'human', 'key-cape-oidc-login',
'client_id', 'change', ('keycape-client',), False,
('parent-session',))
def build(*, admitted: Invocation, case_source: bytes, expected_uid: str,
expected_resource_version: str, case_acceptance: str,
check_config: Path, check_config_digest: str, publish, authenticate,
revoke_session):
"""Bind one admitted case and observed revision; return a closed kernel Adapter.
publish(bytes)->identifier durably retains only the closed metadata payload.
authenticate(identifier, bytes)->True must verify independent owner custody.
revoke_session(invocation)->identifier must revoke this attempt's parent
session; Warden independently authenticates it using its own evidence verifier.
These callbacks are capabilities, never command strings or case parameters.
Only a verified creation in this process may be rolled back. Process loss,
write/readback ambiguity, publication/revocation failure and source drift
require owner reconciliation; none are converted to retry-safe failures.
"""
reviewed_source = source_digest(check_config_digest)
desc = descriptor(check_config_digest)
if type(admitted) is not Invocation or not all(
isinstance(value, str) and IDENTIFIER.fullmatch(value)
for value in (admitted.step, admitted.owner, admitted.target,
admitted.actor, admitted.principal, admitted.lane)):
raise Refused('bounded invocation required')
if desc.adapter_source != reviewed_source:
raise Refused('owner source changed during binding')
if (admitted.step, admitted.owner, admitted.actor, admitted.lane) != (
desc.step, desc.owner, desc.actor, desc.lane):
raise Refused('registration invocation boundary differs')
if admitted.operation != 'admission' or admitted.attempt_id:
raise Refused('expected admission invocation')
if type(case_source) is not bytes or len(case_source) > 262144 or digest(case_source) != admitted.pins.case:
raise Refused('case source pin differs')
# Pins.adapter is the descriptor digest, not the owner source digest.
descriptor_bytes = json.dumps(asdict(desc), sort_keys=True, separators=(',', ':')).encode()
if admitted.pins.adapter != digest(descriptor_bytes):
raise Refused('descriptor pin differs')
if not all(isinstance(x, str) and 0 < len(x) <= 192 for x in
(expected_uid, expected_resource_version, case_acceptance)):
raise Refused('bounded attended binding required')
if digest(case_acceptance.encode()) != admitted.pins.acceptance:
raise Refused('acceptance evidence binding differs')
if not all(callable(x) for x in (publish, authenticate, revoke_session)):
raise Refused('owner evidence and revocation capabilities required')
with contained_output():
case = yaml.safe_load(case_source)
client = helper.client_from_case(case)
if admitted.target != client['clientId']:
raise Refused('case target differs')
check_config = Path(check_config)
records = {}
creation = None
def binding(inv, operation):
if (replace(inv, attempt_id='', operation='admission') != admitted
or inv.operation != operation or not IDENTIFIER.fullmatch(inv.attempt_id)):
raise Refused('attempt binding differs')
if source_digest(check_config_digest) != reviewed_source:
raise Refused('owner source changed')
if digest(check_config.read_bytes()) != check_config_digest:
raise Refused('check-config binary changed')
def execute(inv, operation, created=()):
nonlocal creation
try:
with contained_output():
binding(inv, 'run' if operation == 'add' else 'rollback')
uid, revision = expected_uid, expected_resource_version
if operation == 'remove':
if (created != ('keycape-client',) or creation is None
or not verify(*creation)):
raise Refused('no authenticated case-created client')
original_payload = json.loads(records[creation[1].evidence][1])
uid, revision = original_payload['after']['uid'], original_payload['after']['resource_version']
args = argparse.Namespace(mode='apply', operation=operation,
expected_uid=uid, expected_resource_version=revision,
case_acceptance=case_acceptance, check_config=str(check_config))
receipt = helper.run(args, client)
# The helper has completed CAS, whole-data readback and preservation.
# Never retain check-config diagnostics or arbitrary helper fields.
if not (receipt['schema'] == 'netkingdom.keycape-client.v1'
and receipt['target'] == 'sso/keycape-config'
and receipt['client_id'] == admitted.target
and receipt['mode'] == 'apply' and receipt['operation'] == operation
and receipt['values_emitted'] is False
and type(receipt['changed']) is bool
and receipt['unrelated_config_bytes_preserved'] is True
and receipt['other_secret_data_unchanged'] is True
and receipt['before'] == {'uid': uid, 'resource_version': revision}
and receipt['after']['uid'] == uid
and receipt['check_config']['proposed']['valid'] is True):
raise Refused('owner readback contract differs')
after = receipt['after']
if (set(after) != {'uid', 'resource_version'} or
not all(isinstance(v, str) and 0 < len(v) <= 192 for v in after.values())):
raise Refused('owner revision contract differs')
changed = receipt['changed']
outcome = (Outcome.ROLLED_BACK if operation == 'remove' else
Outcome.SUCCESS if changed else Outcome.NO_CHANGE)
objects = ('keycape-client',) if operation == 'add' and changed else ()
finally:
# Even helper failure must end the parent session. Failures propagate
# contained to the kernel and become uncertain, never safe to replay.
with contained_output():
revocation = revoke_session(inv)
if not isinstance(revocation, str) or not IDENTIFIER.fullmatch(revocation):
raise Refused('session revocation evidence missing')
payload = json.dumps({'schema': 'netkingdom.keycape-registration.attempt.v1',
'invocation': asdict(inv), 'source': reviewed_source,
'outcome': outcome.value, 'created': objects, 'before': receipt['before'],
'after': after, 'session_revocation': revocation},
sort_keys=True, separators=(',', ':')).encode()
with contained_output():
evidence = publish(payload)
if not isinstance(evidence, str) or not IDENTIFIER.fullmatch(evidence) or evidence in records:
raise Refused('owner evidence identifier invalid or reused')
result = OwnerResult(outcome, evidence, objects, True, revocation,
attempt_id=inv.attempt_id, operation=inv.operation)
records[evidence] = (inv, payload, result)
if operation == 'add' and changed:
creation = (inv, result)
elif operation == 'remove':
creation = None
return result
def verify(inv, result):
record = records.get(result.evidence) if type(result) is OwnerResult else None
if record is None or record[0] != inv or record[2] != result:
return False
with contained_output():
return authenticate(result.evidence, record[1]) is True
return Adapter(REFERENCE, reviewed_source, lambda inv: execute(inv, 'add'),
verify, lambda inv, created: execute(inv, 'remove', created))

View file

@ -0,0 +1,59 @@
# Attended registration adapter candidate
Exercise status: unexercised
This is a source-only, injection-only adapter for the existing Warden closed
kernel. It installs no command, runtime dispatcher, credential provider, evidence
trust root or new service. NetKingdom type/case status and bytes remain unchanged.
The generated descriptor is a proposal; it is not owner acknowledgment.
`keycape-registration-adapter.py` wraps maintained `keycape-client.run` in apply
mode. A fixed invocation binds principal, human actor, lane, case/type/descriptor/
catalog/acceptance/run-sheet digests and target. The descriptor pins this adapter
and its complete local helper import closure together with the exact reviewed
`check-config` executable digest. Changing that digest changes the descriptor
source pin and descriptor bytes, requiring independently reviewed admission.
The fixed executable is rehashed before each attempt. The caller constructs the
proposed invocation from exact source inputs, installs the fixed adapter once,
and calls normal `Executor.admit`; independently derived admission must match.
No callable replacement after admission is required or supported by this recipe.
The operation uses existing cluster/issuer checks, byte-preserving merge,
Deployment secret-env prerequisite, config validation, UID/resourceVersion CAS
and whole-data readback. Only closed metadata is passed to the injected durable
owner publisher. The owner authenticator must independently authenticate those
exact bytes. The session-revocation capability must end the same attempt's
parent session; Warden separately verifies its exact revocation evidence.
These capabilities are owner-selected callables, never case-supplied commands.
No implementation of these native capabilities is supplied or implied here.
An identical existing client returns no change and creates no rollback authority.
Removal requires this process's independently authenticated successful creation
receipt, exact created-object label, unchanged postcreation UID/resourceVersion,
and the original exact client record. External drift, a lost readback, receipt
publication/revocation failure or process loss requires owner reconciliation.
No uncertainty is labeled retry-safe. No automatic reconciliation is installed.
Rollback after restart intentionally remains unavailable until an owner supplies
independently authenticated durable creation provenance and reviews recovery.
The source tests execute actual maintained helper CAS/readback against synthetic
Kubernetes objects. Three checks exercise actual Warden admission/run/rollback
and uncertainty transitions with synthetic owner trust. Warden d97652a's exact
published producer source pins apply unchanged through actual BrowserInputs.
This is a source compatibility fixture, not acknowledgment, owner provenance,
normal native admission or deployment acceptance.
Remaining work belongs in live work records before T12 closure:
- Warden owns global evidence admission and exact native evidence/session
capabilities. Published d97652a refreshes BrowserInputs producer pins for
NetKingdom 015694ee; that source assent does not attest this new adapter.
- NetKingdom owns separately reviewed descriptor/type pin selection, the env
binding/config/restart steps, and group ensure/revoke provenance. Current group
ensure does not report newly added memberships; current revoke can remove
memberships that predate the case. Wrapping these as reversible creation would
be unsound. Preserve them until a reviewed created-only contract exists.
- Platform owns structural/mint/broker and secret delivery evidence; Apps owns
actual consumer login and group enforcement. No assent is supplied here.
- Attended use still requires existing owner authorization, current caller
identity, native source/config/image pins, native receipts and cleanup proof.