feat: rehearse approved proposal apply and rollback

This commit is contained in:
twentyOne2x 2026-07-15 03:59:47 +02:00
parent e4348a0071
commit db64500a12
16 changed files with 7507 additions and 941 deletions

View file

@ -0,0 +1,120 @@
begin;
set local standard_conforming_strings = on;
set local lock_timeout = '5s';
select pg_advisory_xact_lock(hashtextextended('proposal-rollback:' || E'9b2b5fa4-0e0d-5db0-aa4d-6fd102889946', 0));
do $rollback$
declare
affected integer;
approval_now jsonb;
begin
perform 1 from kb_stage.kb_proposals
where id = E'9b2b5fa4-0e0d-5db0-aa4d-6fd102889946'::uuid
for update;
if not found then
raise exception 'proposal rollback: proposal row missing';
end if;
if not exists (
select 1 from kb_stage.kb_proposals
where id = E'9b2b5fa4-0e0d-5db0-aa4d-6fd102889946'::uuid
and proposal_type = 'approve_claim'
and status = 'applied'
and payload = E'{"apply_payload":{"agent_id":null,"claims":[{"confidence":0.9,"created_by":null,"id":"38dead14-6b1d-5909-99c4-3c45ad2dd21f","status":"open","superseded_by":null,"tags":["working-leo","clone-canary"],"text":"An approved strict proposal can create exact canonical rows atomically.","type":"structural"},{"confidence":0.85,"created_by":null,"id":"71a3331b-fb75-5e18-aa61-b256bc38af36","status":"open","superseded_by":null,"tags":["working-leo","row-proof"],"text":"Row-level proof is the authority for canonical KB state.","type":"concept"}],"contract_version":2,"edges":[{"created_by":null,"edge_type":"supports","from_claim":"38dead14-6b1d-5909-99c4-3c45ad2dd21f","to_claim":"71a3331b-fb75-5e18-aa61-b256bc38af36","weight":0.75}],"evidence":[{"claim_id":"38dead14-6b1d-5909-99c4-3c45ad2dd21f","created_by":null,"role":"grounds","source_id":"ed9da5f1-846e-5298-8689-15027a7ce56d","weight":0.9},{"claim_id":"71a3331b-fb75-5e18-aa61-b256bc38af36","created_by":null,"role":"illustrates","source_id":"a86f55dc-5058-585d-b492-a4f1d932670f","weight":0.8}],"reasoning_tools":[{"agent_id":null,"category":"verification","description":"Verify approved proposal to canonical graph lifecycle in a disposable clone.","id":"2b8a01ea-125c-5d90-a9b9-39ccb0a1c9e0","name":"Canonical row proof canary"}],"sources":[{"created_by":null,"excerpt":"Disposable clone lifecycle canary source A.","hash":"approve-claim-canary-08c2358330-a","id":"ed9da5f1-846e-5298-8689-15027a7ce56d","source_type":"observation","storage_path":null,"url":null},{"created_by":null,"excerpt":"Disposable clone lifecycle canary source B.","hash":"approve-claim-canary-08c2358330-b","id":"a86f55dc-5058-585d-b492-a4f1d932670f","source_type":"observation","storage_path":null,"url":null}]}}'::jsonb
and reviewed_by_handle is not distinct from E'm3ta'
and reviewed_by_agent_id is not distinct from E'11111111-1111-4111-8111-111111111111'::uuid
and reviewed_at is not distinct from E'2026-07-15 01:59:03.105846+00'::timestamptz
and review_note is not distinct from E'Reviewed exact strict payload inside the disposable clone.'
and applied_by_handle is not distinct from E'kb-apply'
and applied_by_agent_id is not distinct from E'44444444-4444-4444-4444-444444444444'::uuid
and applied_at is not distinct from E'2026-07-15 01:59:04.449051+00'::timestamptz
) then
raise exception 'proposal rollback: applied ledger does not match apply receipt';
end if;
select jsonb_build_object(
'proposal_id', proposal_id::text,
'proposal_type', proposal_type,
'payload', payload,
'reviewed_by_handle', reviewed_by_handle,
'reviewed_by_agent_id', reviewed_by_agent_id::text,
'reviewed_by_db_role', reviewed_by_db_role::text,
'reviewed_at', reviewed_at::text,
'review_note', review_note
) into approval_now
from kb_stage.kb_proposal_approvals
where proposal_id = E'9b2b5fa4-0e0d-5db0-aa4d-6fd102889946'::uuid;
if approval_now is distinct from E'{"payload":{"apply_payload":{"agent_id":null,"claims":[{"confidence":0.9,"created_by":null,"id":"38dead14-6b1d-5909-99c4-3c45ad2dd21f","status":"open","superseded_by":null,"tags":["working-leo","clone-canary"],"text":"An approved strict proposal can create exact canonical rows atomically.","type":"structural"},{"confidence":0.85,"created_by":null,"id":"71a3331b-fb75-5e18-aa61-b256bc38af36","status":"open","superseded_by":null,"tags":["working-leo","row-proof"],"text":"Row-level proof is the authority for canonical KB state.","type":"concept"}],"contract_version":2,"edges":[{"created_by":null,"edge_type":"supports","from_claim":"38dead14-6b1d-5909-99c4-3c45ad2dd21f","to_claim":"71a3331b-fb75-5e18-aa61-b256bc38af36","weight":0.75}],"evidence":[{"claim_id":"38dead14-6b1d-5909-99c4-3c45ad2dd21f","created_by":null,"role":"grounds","source_id":"ed9da5f1-846e-5298-8689-15027a7ce56d","weight":0.9},{"claim_id":"71a3331b-fb75-5e18-aa61-b256bc38af36","created_by":null,"role":"illustrates","source_id":"a86f55dc-5058-585d-b492-a4f1d932670f","weight":0.8}],"reasoning_tools":[{"agent_id":null,"category":"verification","description":"Verify approved proposal to canonical graph lifecycle in a disposable clone.","id":"2b8a01ea-125c-5d90-a9b9-39ccb0a1c9e0","name":"Canonical row proof canary"}],"sources":[{"created_by":null,"excerpt":"Disposable clone lifecycle canary source A.","hash":"approve-claim-canary-08c2358330-a","id":"ed9da5f1-846e-5298-8689-15027a7ce56d","source_type":"observation","storage_path":null,"url":null},{"created_by":null,"excerpt":"Disposable clone lifecycle canary source B.","hash":"approve-claim-canary-08c2358330-b","id":"a86f55dc-5058-585d-b492-a4f1d932670f","source_type":"observation","storage_path":null,"url":null}]}},"proposal_id":"9b2b5fa4-0e0d-5db0-aa4d-6fd102889946","proposal_type":"approve_claim","review_note":"Reviewed exact strict payload inside the disposable clone.","reviewed_at":"2026-07-15 01:59:03.105846+00","reviewed_by_agent_id":"11111111-1111-4111-8111-111111111111","reviewed_by_db_role":"kb_review","reviewed_by_handle":"m3ta"}'::jsonb then
raise exception 'proposal rollback: immutable approval snapshot drifted';
end if;
if (select count(*) from public.claim_evidence t
where t.id = E'dac3934f-b7ad-5205-8efe-a00163370a54'::uuid and to_jsonb(t) = E'{"claim_id":"38dead14-6b1d-5909-99c4-3c45ad2dd21f","created_at":"2026-07-15T01:59:04.44165+00:00","created_by":null,"id":"dac3934f-b7ad-5205-8efe-a00163370a54","role":"grounds","source_id":"ed9da5f1-846e-5298-8689-15027a7ce56d","weight":0.9}'::jsonb) <> 1 then
raise exception 'proposal rollback drift: claim_evidence[0] row does not match apply receipt';
end if;
if (select count(*) from public.claim_evidence t
where t.id = E'13e580c5-458d-5146-aef3-8c74ffc43b7c'::uuid and to_jsonb(t) = E'{"claim_id":"71a3331b-fb75-5e18-aa61-b256bc38af36","created_at":"2026-07-15T01:59:04.44165+00:00","created_by":null,"id":"13e580c5-458d-5146-aef3-8c74ffc43b7c","role":"illustrates","source_id":"a86f55dc-5058-585d-b492-a4f1d932670f","weight":0.8}'::jsonb) <> 1 then
raise exception 'proposal rollback drift: claim_evidence[1] row does not match apply receipt';
end if;
if (select count(*) from public.claim_edges t
where t.id = E'b28d8770-9ac9-5b5f-bfe2-7280d7422a21'::uuid and to_jsonb(t) = E'{"created_at":"2026-07-15T01:59:04.44165+00:00","created_by":null,"edge_type":"supports","from_claim":"38dead14-6b1d-5909-99c4-3c45ad2dd21f","id":"b28d8770-9ac9-5b5f-bfe2-7280d7422a21","to_claim":"71a3331b-fb75-5e18-aa61-b256bc38af36","weight":0.75}'::jsonb) <> 1 then
raise exception 'proposal rollback drift: claim_edges[0] row does not match apply receipt';
end if;
if (select count(*) from public.reasoning_tools t
where t.id = E'2b8a01ea-125c-5d90-a9b9-39ccb0a1c9e0'::uuid and to_jsonb(t) = E'{"agent_id":null,"category":"verification","created_at":"2026-07-15T01:59:04.44165+00:00","description":"Verify approved proposal to canonical graph lifecycle in a disposable clone.","id":"2b8a01ea-125c-5d90-a9b9-39ccb0a1c9e0","name":"Canonical row proof canary"}'::jsonb) <> 1 then
raise exception 'proposal rollback drift: reasoning_tools[0] row does not match apply receipt';
end if;
if (select count(*) from public.sources t
where t.id = E'ed9da5f1-846e-5298-8689-15027a7ce56d'::uuid and to_jsonb(t) = E'{"captured_at":null,"created_at":"2026-07-15T01:59:04.44165+00:00","created_by":null,"excerpt":"Disposable clone lifecycle canary source A.","hash":"approve-claim-canary-08c2358330-a","id":"ed9da5f1-846e-5298-8689-15027a7ce56d","source_type":"observation","storage_path":null,"url":null}'::jsonb) <> 1 then
raise exception 'proposal rollback drift: sources[0] row does not match apply receipt';
end if;
if (select count(*) from public.sources t
where t.id = E'a86f55dc-5058-585d-b492-a4f1d932670f'::uuid and to_jsonb(t) = E'{"captured_at":null,"created_at":"2026-07-15T01:59:04.44165+00:00","created_by":null,"excerpt":"Disposable clone lifecycle canary source B.","hash":"approve-claim-canary-08c2358330-b","id":"a86f55dc-5058-585d-b492-a4f1d932670f","source_type":"observation","storage_path":null,"url":null}'::jsonb) <> 1 then
raise exception 'proposal rollback drift: sources[1] row does not match apply receipt';
end if;
if (select count(*) from public.claims t
where t.id = E'71a3331b-fb75-5e18-aa61-b256bc38af36'::uuid and to_jsonb(t) = E'{"confidence":0.85,"created_at":"2026-07-15T01:59:04.44165+00:00","created_by":null,"id":"71a3331b-fb75-5e18-aa61-b256bc38af36","status":"open","superseded_by":null,"tags":["working-leo","row-proof"],"text":"Row-level proof is the authority for canonical KB state.","type":"concept","updated_at":"2026-07-15T01:59:04.44165+00:00"}'::jsonb) <> 1 then
raise exception 'proposal rollback drift: claims[0] row does not match apply receipt';
end if;
if (select count(*) from public.claims t
where t.id = E'38dead14-6b1d-5909-99c4-3c45ad2dd21f'::uuid and to_jsonb(t) = E'{"confidence":0.9,"created_at":"2026-07-15T01:59:04.44165+00:00","created_by":null,"id":"38dead14-6b1d-5909-99c4-3c45ad2dd21f","status":"open","superseded_by":null,"tags":["working-leo","clone-canary"],"text":"An approved strict proposal can create exact canonical rows atomically.","type":"structural","updated_at":"2026-07-15T01:59:04.44165+00:00"}'::jsonb) <> 1 then
raise exception 'proposal rollback drift: claims[1] row does not match apply receipt';
end if;
delete from public.claim_evidence where id in (E'dac3934f-b7ad-5205-8efe-a00163370a54'::uuid, E'13e580c5-458d-5146-aef3-8c74ffc43b7c'::uuid);
get diagnostics affected = row_count;
if affected <> 2 then
raise exception 'proposal rollback count mismatch for claim_evidence: expected 2, got %', affected;
end if;
delete from public.claim_edges where id in (E'b28d8770-9ac9-5b5f-bfe2-7280d7422a21'::uuid);
get diagnostics affected = row_count;
if affected <> 1 then
raise exception 'proposal rollback count mismatch for claim_edges: expected 1, got %', affected;
end if;
delete from public.reasoning_tools where id in (E'2b8a01ea-125c-5d90-a9b9-39ccb0a1c9e0'::uuid);
get diagnostics affected = row_count;
if affected <> 1 then
raise exception 'proposal rollback count mismatch for reasoning_tools: expected 1, got %', affected;
end if;
delete from public.sources where id in (E'ed9da5f1-846e-5298-8689-15027a7ce56d'::uuid, E'a86f55dc-5058-585d-b492-a4f1d932670f'::uuid);
get diagnostics affected = row_count;
if affected <> 2 then
raise exception 'proposal rollback count mismatch for sources: expected 2, got %', affected;
end if;
delete from public.claims where id in (E'71a3331b-fb75-5e18-aa61-b256bc38af36'::uuid, E'38dead14-6b1d-5909-99c4-3c45ad2dd21f'::uuid);
get diagnostics affected = row_count;
if affected <> 2 then
raise exception 'proposal rollback count mismatch for claims: expected 2, got %', affected;
end if;
update kb_stage.kb_proposals
set status = 'approved',
applied_by_handle = null,
applied_by_agent_id = null,
applied_at = null,
updated_at = now()
where id = E'9b2b5fa4-0e0d-5db0-aa4d-6fd102889946'::uuid
and status = 'applied'
and payload = E'{"apply_payload":{"agent_id":null,"claims":[{"confidence":0.9,"created_by":null,"id":"38dead14-6b1d-5909-99c4-3c45ad2dd21f","status":"open","superseded_by":null,"tags":["working-leo","clone-canary"],"text":"An approved strict proposal can create exact canonical rows atomically.","type":"structural"},{"confidence":0.85,"created_by":null,"id":"71a3331b-fb75-5e18-aa61-b256bc38af36","status":"open","superseded_by":null,"tags":["working-leo","row-proof"],"text":"Row-level proof is the authority for canonical KB state.","type":"concept"}],"contract_version":2,"edges":[{"created_by":null,"edge_type":"supports","from_claim":"38dead14-6b1d-5909-99c4-3c45ad2dd21f","to_claim":"71a3331b-fb75-5e18-aa61-b256bc38af36","weight":0.75}],"evidence":[{"claim_id":"38dead14-6b1d-5909-99c4-3c45ad2dd21f","created_by":null,"role":"grounds","source_id":"ed9da5f1-846e-5298-8689-15027a7ce56d","weight":0.9},{"claim_id":"71a3331b-fb75-5e18-aa61-b256bc38af36","created_by":null,"role":"illustrates","source_id":"a86f55dc-5058-585d-b492-a4f1d932670f","weight":0.8}],"reasoning_tools":[{"agent_id":null,"category":"verification","description":"Verify approved proposal to canonical graph lifecycle in a disposable clone.","id":"2b8a01ea-125c-5d90-a9b9-39ccb0a1c9e0","name":"Canonical row proof canary"}],"sources":[{"created_by":null,"excerpt":"Disposable clone lifecycle canary source A.","hash":"approve-claim-canary-08c2358330-a","id":"ed9da5f1-846e-5298-8689-15027a7ce56d","source_type":"observation","storage_path":null,"url":null},{"created_by":null,"excerpt":"Disposable clone lifecycle canary source B.","hash":"approve-claim-canary-08c2358330-b","id":"a86f55dc-5058-585d-b492-a4f1d932670f","source_type":"observation","storage_path":null,"url":null}]}}'::jsonb
and applied_at is not distinct from E'2026-07-15 01:59:04.449051+00'::timestamptz;
get diagnostics affected = row_count;
if affected <> 1 then
raise exception 'proposal rollback: expected one applied ledger row, got %', affected;
end if;
end
$rollback$;
commit;

View file

@ -0,0 +1,217 @@
{
"applied_row_ids": {
"claim_edges": [
"b28d8770-9ac9-5b5f-bfe2-7280d7422a21"
],
"claim_evidence": [
"13e580c5-458d-5146-aef3-8c74ffc43b7c",
"dac3934f-b7ad-5205-8efe-a00163370a54"
],
"claims": [
"38dead14-6b1d-5909-99c4-3c45ad2dd21f",
"71a3331b-fb75-5e18-aa61-b256bc38af36"
],
"reasoning_tools": [
"2b8a01ea-125c-5d90-a9b9-39ccb0a1c9e0"
],
"sources": [
"a86f55dc-5058-585d-b492-a4f1d932670f",
"ed9da5f1-846e-5298-8689-15027a7ce56d"
]
},
"applied_row_sha256": {
"claim_edges": [
"60d14cbc45d424fa1eb62db6478f185bf2c2d86559e57ffa77474e8d0b3c527c"
],
"claim_evidence": [
"e97de162c0730da69b357e1350f0da7e5843c4e67d498c12d731a0f04a8868d7",
"3054718195abe3f78e08cfcacd59902d41eb91c7153c6c63f9bcb3bc7c6902ac"
],
"claims": [
"e593b9cf7b0bc9267f3e48d8173129b84b09c028f290f1abc97ccb73940b31dc",
"24280b5159cbbf75e00eb24ae50ab69994397a583f347a241a5e262cf0c03179"
],
"reasoning_tools": [
"257924b236c3c27289b9ae2314687be0e96779415fc6ff87faada22893b757ba"
],
"sources": [
"d7a690c2b18701db5b48e8189b1621c8025c1ed75889a4d0a3a4c9761c03dc3b",
"bee048794799006bd00bf4bb02ae57998e670f5bcdfb140dff871dcb042d0198"
]
},
"apply_payload_sha256": "c89bc03ce7714f325293329a0bf95eaba0a56c596ef021d731b48dab0447c684",
"apply_receipt_sha256": "2aa65fe4509c6699af34e418de27c0225efe751223aaebf3f9b545fa159c754e",
"apply_sql_sha256": "1a7d65870e415ee8891b6dd84732a29bcee00412c10862d3d1db4b191a8ade38",
"approval_snapshot_sha256": "310b54030e26ed43d7226f2e803610586e80d21ff064c67e11ea21e93ef40bd9",
"artifact": "proposal_apply_lifecycle_receipt",
"checks": {
"apply_receipt_replay_ready": true,
"apply_rows_have_exact_ids": true,
"fresh_owned_targets": true,
"immutable_approval_unchanged": true,
"rollback_counts_restored": true,
"rollback_ledger_restored_to_approved": true,
"rollback_replay_refused_without_mutation": true,
"rollback_sql_exact_for_bound_rows": true,
"rollback_target_rows_absent": true,
"unrelated_rows_unchanged": true
},
"current_tier": "T2_runtime",
"fresh_preflight_artifact_sha256": "1d5e7eed7355aa94ecfa213422e6178aecdeee70628994596e852bd7569d6a2d",
"fresh_preflight_sha256": "29a80dc9422af45fd067e98621442d31c60161f34deb5845aa410659a9c5de3a",
"generated_at_utc": "2026-07-15T01:59:05.526171+00:00",
"lifecycle_receipt_sha256": "8e74cf1f5c372633f9b6f15363ff759ba6ce9bf42df51288bb9be70ddabe49b3",
"pass": true,
"production_apply_authorization_present": false,
"production_apply_executed": false,
"proposal_before_apply": {
"applied_at": null,
"applied_by_agent_id": null,
"applied_by_handle": null,
"id": "9b2b5fa4-0e0d-5db0-aa4d-6fd102889946",
"payload": {
"apply_payload": {
"agent_id": null,
"claims": [
{
"confidence": 0.9,
"created_by": null,
"id": "38dead14-6b1d-5909-99c4-3c45ad2dd21f",
"status": "open",
"superseded_by": null,
"tags": [
"working-leo",
"clone-canary"
],
"text": "An approved strict proposal can create exact canonical rows atomically.",
"type": "structural"
},
{
"confidence": 0.85,
"created_by": null,
"id": "71a3331b-fb75-5e18-aa61-b256bc38af36",
"status": "open",
"superseded_by": null,
"tags": [
"working-leo",
"row-proof"
],
"text": "Row-level proof is the authority for canonical KB state.",
"type": "concept"
}
],
"contract_version": 2,
"edges": [
{
"created_by": null,
"edge_type": "supports",
"from_claim": "38dead14-6b1d-5909-99c4-3c45ad2dd21f",
"to_claim": "71a3331b-fb75-5e18-aa61-b256bc38af36",
"weight": 0.75
}
],
"evidence": [
{
"claim_id": "38dead14-6b1d-5909-99c4-3c45ad2dd21f",
"created_by": null,
"role": "grounds",
"source_id": "ed9da5f1-846e-5298-8689-15027a7ce56d",
"weight": 0.9
},
{
"claim_id": "71a3331b-fb75-5e18-aa61-b256bc38af36",
"created_by": null,
"role": "illustrates",
"source_id": "a86f55dc-5058-585d-b492-a4f1d932670f",
"weight": 0.8
}
],
"reasoning_tools": [
{
"agent_id": null,
"category": "verification",
"description": "Verify approved proposal to canonical graph lifecycle in a disposable clone.",
"id": "2b8a01ea-125c-5d90-a9b9-39ccb0a1c9e0",
"name": "Canonical row proof canary"
}
],
"sources": [
{
"created_by": null,
"excerpt": "Disposable clone lifecycle canary source A.",
"hash": "approve-claim-canary-08c2358330-a",
"id": "ed9da5f1-846e-5298-8689-15027a7ce56d",
"source_type": "observation",
"storage_path": null,
"url": null
},
{
"created_by": null,
"excerpt": "Disposable clone lifecycle canary source B.",
"hash": "approve-claim-canary-08c2358330-b",
"id": "a86f55dc-5058-585d-b492-a4f1d932670f",
"source_type": "observation",
"storage_path": null,
"url": null
}
]
}
},
"proposal_type": "approve_claim",
"review_note": "Reviewed exact strict payload inside the disposable clone.",
"reviewed_at": "2026-07-15 01:59:03.105846+00",
"reviewed_by_agent_id": "11111111-1111-4111-8111-111111111111",
"reviewed_by_handle": "m3ta",
"status": "approved"
},
"proposal_payload_sha256": "6fba5e8e105a28dfaf5733ff7c9f85a20d31d653add0bc4a0f81e4b08de803af",
"required_tier": "T2_runtime",
"rollback": {
"counts_after_rollback": {
"kb_stage.kb_proposals": 1,
"public.claim_edges": 0,
"public.claim_evidence": 1,
"public.claims": 1,
"public.reasoning_tools": 0,
"public.sources": 1
},
"counts_before_apply": {
"kb_stage.kb_proposals": 1,
"public.claim_edges": 0,
"public.claim_evidence": 1,
"public.claims": 1,
"public.reasoning_tools": 0,
"public.sources": 1
},
"delete_order": [
"claim_evidence",
"claim_edges",
"reasoning_tools",
"sources",
"claims"
],
"proposal_after": {
"applied_at": null,
"applied_by_agent_id": null,
"applied_by_handle": null,
"id": "9b2b5fa4-0e0d-5db0-aa4d-6fd102889946",
"proposal_type": "approve_claim",
"review_note": "Reviewed exact strict payload inside the disposable clone.",
"reviewed_at": "2026-07-15 01:59:03.105846+00",
"reviewed_by_agent_id": "11111111-1111-4111-8111-111111111111",
"reviewed_by_handle": "m3ta",
"status": "approved"
},
"rollback_sql_sha256": "ef2464a6802426509333861cf0768ca64184901ab7bd2030529e7356a35d9cb3",
"schema": "livingip.proposalApplyRollback.v1",
"target_rows_after": {
"claim_edges": [],
"claim_evidence": [],
"claims": [],
"reasoning_tools": [],
"sources": []
}
},
"schema": "livingip.proposalApplyLifecycleReceipt.v1",
"strongest_claim_allowed": "deterministic disposable-clone apply and compensating rollback"
}

View file

@ -0,0 +1,32 @@
{
"artifact": "proposal_apply_production_target_readback",
"schema": "livingip.proposalApplyProductionTargetReadback.v1",
"observed_at_utc": "2026-07-15T00:45:59.238006+00:00",
"transport": "ssh_readonly_transaction",
"read_only_transaction": true,
"read_only_setting": "on",
"container": "teleo-pg",
"database": "teleo",
"system_identifier": "7649789040005668902",
"server_version_num": "160014",
"approval_gate": {
"immutable_approval_table_present": false,
"approve_function_present": false,
"assert_function_present": false,
"finish_function_present": false,
"review_role_present": false,
"apply_role_present": true
},
"approved_strict_candidate_count": 0,
"approved_strict_candidates": [],
"attempted_recovery": {
"strict_immutable_approval_join_attempted": true,
"strict_join_failed": true,
"strict_join_exact_gate": "relation kb_stage.kb_proposal_approvals does not exist",
"fallback_read_only_gate_and_candidate_count_succeeded": true
},
"production_mutated": false,
"production_apply_authorization_present": false,
"production_apply_executed": false,
"claim_ceiling": "Fresh T3 live read-only identity and gate readback only. The immutable approval gate is absent and there are zero approved strict approve_claim candidates; production apply is neither authorized nor executed."
}

View file

@ -14,6 +14,7 @@ dependencies = [
[project.optional-dependencies] [project.optional-dependencies]
dev = [ dev = [
"hypothesis>=6,<7",
"pytest>=8", "pytest>=8",
"pytest-asyncio>=0.23", "pytest-asyncio>=0.23",
"ruff>=0.3", "ruff>=0.3",

View file

@ -111,8 +111,17 @@ CLAIM_TYPES = {"empirical", "structural", "normative", "meta", "concept"}
SOURCE_TYPES = {"paper", "article", "transcript", "observation", "dataset", "post", "dm", "other"} SOURCE_TYPES = {"paper", "article", "transcript", "observation", "dataset", "post", "dm", "other"}
EVIDENCE_ROLES = {"grounds", "illustrates", "contradicts"} EVIDENCE_ROLES = {"grounds", "illustrates", "contradicts"}
EDGE_TYPES = { EDGE_TYPES = {
"supports", "challenges", "requires", "relates", "contradicts", "supports",
"supersedes", "derives_from", "cites", "causes", "constrains", "accelerates", "challenges",
"requires",
"relates",
"contradicts",
"supersedes",
"derives_from",
"cites",
"causes",
"constrains",
"accelerates",
} }
MAX_BUNDLE_ROWS = { MAX_BUNDLE_ROWS = {
@ -143,6 +152,21 @@ def _jsonb(value: Any) -> str:
return sql_literal(json.dumps(value, sort_keys=True)) + "::jsonb" return sql_literal(json.dumps(value, sort_keys=True)) + "::jsonb"
def deterministic_row_uuid(proposal_id: str, row_kind: str, *semantic_key: Any) -> str:
"""Derive a stable persisted row id from the proposal and semantic key.
Evidence and edge ids are not part of the reviewed v2 payload. Deriving
them here makes clone/production receipts and a pre-authorized rollback
packet bind the same exact ids instead of relying on database randomness.
"""
material = json.dumps(
["livingip", "kb-apply", str(proposal_id), row_kind, *semantic_key],
ensure_ascii=True,
separators=(",", ":"),
)
return str(uuid.uuid5(uuid.NAMESPACE_URL, material))
def _text_array(values: list[str]) -> str: def _text_array(values: list[str]) -> str:
if not values: if not values:
return "'{}'::text[]" return "'{}'::text[]"
@ -196,9 +220,7 @@ def _reject_unknown(mapping: dict[str, Any], allowed: set[str], path: str) -> No
raise ValueError(f"{path} contains unknown fields: {unknown}") raise ValueError(f"{path} contains unknown fields: {unknown}")
def _validate_approval_meta( def _validate_approval_meta(approval: dict[str, Any], proposal_type: str, apply_payload: dict[str, Any]) -> None:
approval: dict[str, Any], proposal_type: str, apply_payload: dict[str, Any]
) -> None:
if not isinstance(approval, dict): if not isinstance(approval, dict):
raise ValueError("approved proposal metadata is required") raise ValueError("approved proposal metadata is required")
if approval.get("proposal_type") != proposal_type: if approval.get("proposal_type") != proposal_type:
@ -222,12 +244,12 @@ def _validate_approval_meta(
def _approval_guard_sql(proposal_id: str, approval: dict[str, Any]) -> str: def _approval_guard_sql(proposal_id: str, approval: dict[str, Any]) -> str:
return f"""select kb_stage.assert_approved_proposal( return f"""select kb_stage.assert_approved_proposal(
{sql_literal(proposal_id)}::uuid, {sql_literal(proposal_id)}::uuid,
{sql_literal(approval['proposal_type'])}, {sql_literal(approval["proposal_type"])},
{_jsonb(approval['payload'])}, {_jsonb(approval["payload"])},
{sql_literal(approval['reviewed_by_handle'])}, {sql_literal(approval["reviewed_by_handle"])},
{sql_literal(approval.get('reviewed_by_agent_id'))}::uuid, {sql_literal(approval.get("reviewed_by_agent_id"))}::uuid,
{sql_literal(approval['reviewed_at'])}::timestamptz, {sql_literal(approval["reviewed_at"])}::timestamptz,
{sql_literal(approval['review_note'])} {sql_literal(approval["review_note"])}
);""" );"""
@ -245,12 +267,12 @@ end
$verify$;""" $verify$;"""
finish_sql = f"""select kb_stage.finish_approved_proposal( finish_sql = f"""select kb_stage.finish_approved_proposal(
{sql_literal(proposal_id)}::uuid, {sql_literal(proposal_id)}::uuid,
{sql_literal(approval['proposal_type'])}, {sql_literal(approval["proposal_type"])},
{_jsonb(approval['payload'])}, {_jsonb(approval["payload"])},
{sql_literal(approval['reviewed_by_handle'])}, {sql_literal(approval["reviewed_by_handle"])},
{sql_literal(approval.get('reviewed_by_agent_id'))}::uuid, {sql_literal(approval.get("reviewed_by_agent_id"))}::uuid,
{sql_literal(approval['reviewed_at'])}::timestamptz, {sql_literal(approval["reviewed_at"])}::timestamptz,
{sql_literal(approval['review_note'])}, {sql_literal(approval["review_note"])},
{sql_literal(applied_by)} {sql_literal(applied_by)}
);""" );"""
return checks_sql + "\n" + finish_sql return checks_sql + "\n" + finish_sql
@ -301,9 +323,9 @@ update public.strategies
insert into public.strategies insert into public.strategies
(agent_id, diagnosis, guiding_policy, proximate_objectives, version, active) (agent_id, diagnosis, guiding_policy, proximate_objectives, version, active)
select {sql_literal(agent_id)}::uuid, select {sql_literal(agent_id)}::uuid,
{sql_literal(strategy['diagnosis'])}, {sql_literal(strategy["diagnosis"])},
{sql_literal(strategy['guiding_policy'])}, {sql_literal(strategy["guiding_policy"])},
{_jsonb(strategy['proximate_objectives'])}, {_jsonb(strategy["proximate_objectives"])},
coalesce(max(version), 0) + 1, coalesce(max(version), 0) + 1,
true true
from public.strategies from public.strategies
@ -325,9 +347,7 @@ values
raise exception 'apply_proposal: expected exactly one active strategy for agent %', {sql_literal(agent_id)}; raise exception 'apply_proposal: expected exactly one active strategy for agent %', {sql_literal(agent_id)};
end if;""" end if;"""
ledger = _ledger_and_verify( ledger = _ledger_and_verify(proposal_id, applied_by or SERVICE_AGENT_HANDLE, checks, approval)
proposal_id, applied_by or SERVICE_AGENT_HANDLE, checks, approval
)
return _wrap_txn(canonical, ledger, _approval_guard_sql(proposal_id, approval)) return _wrap_txn(canonical, ledger, _approval_guard_sql(proposal_id, approval))
@ -338,14 +358,16 @@ def build_add_edge_sql(
approval: dict[str, Any], approval: dict[str, Any],
) -> str: ) -> str:
_validate_approval_meta(approval, "add_edge", apply_payload) _validate_approval_meta(approval, "add_edge", apply_payload)
f = apply_payload.get("from_claim") _reject_unknown(apply_payload, {"from_claim", "to_claim", "edge_type", "weight"}, "add_edge apply_payload")
t = apply_payload.get("to_claim") f = _uuid(apply_payload.get("from_claim"), "add_edge.from_claim")
t = _uuid(apply_payload.get("to_claim"), "add_edge.to_claim")
et = apply_payload.get("edge_type") et = apply_payload.get("edge_type")
w = apply_payload.get("weight") if et not in EDGE_TYPES:
if not (f and t and et): raise ValueError(f"add_edge.edge_type must be one of {sorted(EDGE_TYPES)}")
raise ValueError("add_edge apply_payload requires 'from_claim', 'to_claim', 'edge_type'") w = _weight(apply_payload.get("weight"), "add_edge.weight")
if f == t: if f == t:
raise ValueError("add_edge from_claim and to_claim must differ") raise ValueError("add_edge from_claim and to_claim must differ")
row_id = deterministic_row_uuid(proposal_id, "claim_edge", f, t, et)
edge_lock_key = f"claim_edge:{f}:{t}:{et}" edge_lock_key = f"claim_edge:{f}:{t}:{et}"
canonical = f""" canonical = f"""
@ -354,8 +376,8 @@ def build_add_edge_sql(
select pg_advisory_xact_lock(hashtextextended({sql_literal(edge_lock_key)}, 0)); select pg_advisory_xact_lock(hashtextextended({sql_literal(edge_lock_key)}, 0));
-- insert the edge unless an identical (from,to,type) edge already exists -- insert the edge unless an identical (from,to,type) edge already exists
insert into public.claim_edges (from_claim, to_claim, edge_type, weight) insert into public.claim_edges (id, from_claim, to_claim, edge_type, weight)
select {sql_literal(f)}::uuid, {sql_literal(t)}::uuid, select {sql_literal(row_id)}::uuid, {sql_literal(f)}::uuid, {sql_literal(t)}::uuid,
{sql_literal(et)}::edge_type, {sql_literal(w)} {sql_literal(et)}::edge_type, {sql_literal(w)}
where not exists ( where not exists (
select 1 from public.claim_edges select 1 from public.claim_edges
@ -364,7 +386,15 @@ select {sql_literal(f)}::uuid, {sql_literal(t)}::uuid,
and edge_type = {sql_literal(et)}::edge_type); and edge_type = {sql_literal(et)}::edge_type);
""".rstrip() """.rstrip()
checks = f""" if exists (select 1 from public.claim_edges checks = f""" -- Historical replay receipts can carry a pre-deterministic row id.
-- Require one exact semantic row; fresh applies still insert row_id above.
if (select count(*) from public.claim_edges
where from_claim = {sql_literal(f)}::uuid
and to_claim = {sql_literal(t)}::uuid
and edge_type = {sql_literal(et)}::edge_type) <> 1 then
raise exception 'apply_proposal: claim_edge row does not match strict apply payload';
end if;
if exists (select 1 from public.claim_edges
where from_claim = {sql_literal(f)}::uuid where from_claim = {sql_literal(f)}::uuid
and to_claim = {sql_literal(t)}::uuid and to_claim = {sql_literal(t)}::uuid
and edge_type = {sql_literal(et)}::edge_type and edge_type = {sql_literal(et)}::edge_type
@ -379,9 +409,7 @@ select {sql_literal(f)}::uuid, {sql_literal(t)}::uuid,
raise exception 'apply_proposal: claim_edge row does not match strict apply payload'; raise exception 'apply_proposal: claim_edge row does not match strict apply payload';
end if;""" end if;"""
ledger = _ledger_and_verify( ledger = _ledger_and_verify(proposal_id, applied_by or SERVICE_AGENT_HANDLE, checks, approval)
proposal_id, applied_by or SERVICE_AGENT_HANDLE, checks, approval
)
return _wrap_txn(canonical, ledger, _approval_guard_sql(proposal_id, approval)) return _wrap_txn(canonical, ledger, _approval_guard_sql(proposal_id, approval))
@ -392,6 +420,7 @@ def build_attach_evidence_sql(
approval: dict[str, Any], approval: dict[str, Any],
) -> str: ) -> str:
_validate_approval_meta(approval, "attach_evidence", apply_payload) _validate_approval_meta(approval, "attach_evidence", apply_payload)
_reject_unknown(apply_payload, {"evidence"}, "attach_evidence apply_payload")
evidence: list[dict[str, Any]] = apply_payload.get("evidence") or [] evidence: list[dict[str, Any]] = apply_payload.get("evidence") or []
if not evidence: if not evidence:
raise ValueError("attach_evidence apply_payload requires non-empty 'evidence'") raise ValueError("attach_evidence apply_payload requires non-empty 'evidence'")
@ -399,25 +428,33 @@ def build_attach_evidence_sql(
statements = [] statements = []
checks = [] checks = []
for i, ev in enumerate(evidence): for i, ev in enumerate(evidence):
claim_id = ev.get("claim_id") _reject_unknown(
source_id = ev.get("source_id") ev,
role = ev.get("role") or "grounds" {"claim_id", "source_id", "role", "weight"},
weight = ev.get("weight") f"attach_evidence.evidence[{i}]",
if not claim_id:
raise ValueError(f"evidence[{i}] requires 'claim_id'")
if not source_id:
raise ValueError(
f"evidence[{i}] requires an existing 'source_id'. "
"kb_apply cannot create public.sources; mint the source upstream first."
) )
claim_id = _uuid(ev.get("claim_id"), f"attach_evidence.evidence[{i}].claim_id")
source_id = _uuid(ev.get("source_id"), f"attach_evidence.evidence[{i}].source_id")
role = ev.get("role") or "grounds"
if role not in EVIDENCE_ROLES:
raise ValueError(f"attach_evidence.evidence[{i}].role must be one of {sorted(EVIDENCE_ROLES)}")
weight = _weight(ev.get("weight"), f"attach_evidence.evidence[{i}].weight")
row_id = deterministic_row_uuid(proposal_id, "claim_evidence", claim_id, source_id, role)
statements.append( statements.append(
f"""insert into public.claim_evidence (claim_id, source_id, role, weight) f"""insert into public.claim_evidence (id, claim_id, source_id, role, weight)
select {sql_literal(claim_id)}::uuid, {sql_literal(source_id)}::uuid, select {sql_literal(row_id)}::uuid, {sql_literal(claim_id)}::uuid, {sql_literal(source_id)}::uuid,
{sql_literal(role)}::evidence_role, {sql_literal(weight)} {sql_literal(role)}::evidence_role, {sql_literal(weight)}
on conflict (claim_id, source_id, role) do nothing;""" on conflict (claim_id, source_id, role) do nothing;"""
) )
checks.append( checks.append(
f""" if exists (select 1 from public.claim_evidence f""" -- Accept a legacy receipt id only when exactly one semantic row matches.
if (select count(*) from public.claim_evidence
where claim_id = {sql_literal(claim_id)}::uuid
and source_id = {sql_literal(source_id)}::uuid
and role = {sql_literal(role)}::evidence_role) <> 1 then
raise exception 'apply_proposal: evidence row % does not match strict apply payload', {i};
end if;
if exists (select 1 from public.claim_evidence
where claim_id = {sql_literal(claim_id)}::uuid where claim_id = {sql_literal(claim_id)}::uuid
and source_id = {sql_literal(source_id)}::uuid and source_id = {sql_literal(source_id)}::uuid
and role = {sql_literal(role)}::evidence_role and role = {sql_literal(role)}::evidence_role
@ -434,9 +471,7 @@ on conflict (claim_id, source_id, role) do nothing;"""
) )
canonical = "\n".join(statements) canonical = "\n".join(statements)
ledger = _ledger_and_verify( ledger = _ledger_and_verify(proposal_id, applied_by or SERVICE_AGENT_HANDLE, "\n".join(checks), approval)
proposal_id, applied_by or SERVICE_AGENT_HANDLE, "\n".join(checks), approval
)
return _wrap_txn(canonical, ledger, _approval_guard_sql(proposal_id, approval)) return _wrap_txn(canonical, ledger, _approval_guard_sql(proposal_id, approval))
@ -509,12 +544,8 @@ def build_approve_claim_sql(
"status": status, "status": status,
"confidence": _weight(row.get("confidence"), f"{path}.confidence"), "confidence": _weight(row.get("confidence"), f"{path}.confidence"),
"tags": tags, "tags": tags,
"created_by": _uuid( "created_by": _uuid(row.get("created_by", agent_id), f"{path}.created_by", nullable=True),
row.get("created_by", agent_id), f"{path}.created_by", nullable=True "superseded_by": _uuid(row.get("superseded_by"), f"{path}.superseded_by", nullable=True),
),
"superseded_by": _uuid(
row.get("superseded_by"), f"{path}.superseded_by", nullable=True
),
} }
) )
@ -543,9 +574,7 @@ def build_approve_claim_sql(
"storage_path": row.get("storage_path"), "storage_path": row.get("storage_path"),
"excerpt": row.get("excerpt"), "excerpt": row.get("excerpt"),
"hash": source_hash, "hash": source_hash,
"created_by": _uuid( "created_by": _uuid(row.get("created_by", agent_id), f"{path}.created_by", nullable=True),
row.get("created_by", agent_id), f"{path}.created_by", nullable=True
),
} }
) )
@ -562,13 +591,18 @@ def build_approve_claim_sql(
raise ValueError(f"{path}.role must be one of {sorted(EVIDENCE_ROLES)}") raise ValueError(f"{path}.role must be one of {sorted(EVIDENCE_ROLES)}")
evidence.append( evidence.append(
{ {
"id": deterministic_row_uuid(
proposal_id,
"claim_evidence",
_uuid(row.get("claim_id"), f"{path}.claim_id"),
_uuid(row.get("source_id"), f"{path}.source_id"),
role,
),
"claim_id": _uuid(row.get("claim_id"), f"{path}.claim_id"), "claim_id": _uuid(row.get("claim_id"), f"{path}.claim_id"),
"source_id": _uuid(row.get("source_id"), f"{path}.source_id"), "source_id": _uuid(row.get("source_id"), f"{path}.source_id"),
"role": role, "role": role,
"weight": _weight(row.get("weight"), f"{path}.weight"), "weight": _weight(row.get("weight"), f"{path}.weight"),
"created_by": _uuid( "created_by": _uuid(row.get("created_by", agent_id), f"{path}.created_by", nullable=True),
row.get("created_by", agent_id), f"{path}.created_by", nullable=True
),
} }
) )
@ -589,13 +623,12 @@ def build_approve_claim_sql(
raise ValueError(f"{path} cannot be a self-edge") raise ValueError(f"{path} cannot be a self-edge")
edges.append( edges.append(
{ {
"id": deterministic_row_uuid(proposal_id, "claim_edge", from_claim, to_claim, edge_type),
"from_claim": from_claim, "from_claim": from_claim,
"to_claim": to_claim, "to_claim": to_claim,
"edge_type": edge_type, "edge_type": edge_type,
"weight": _weight(row.get("weight"), f"{path}.weight"), "weight": _weight(row.get("weight"), f"{path}.weight"),
"created_by": _uuid( "created_by": _uuid(row.get("created_by", agent_id), f"{path}.created_by", nullable=True),
row.get("created_by", agent_id), f"{path}.created_by", nullable=True
),
} }
) )
@ -647,150 +680,156 @@ def build_approve_claim_sql(
for row in sources: for row in sources:
collision_checks.append( collision_checks.append(
f""" if exists (select 1 from public.sources f""" if exists (select 1 from public.sources
where hash = {sql_literal(row['hash'])} where hash = {sql_literal(row["hash"])}
and id <> {sql_literal(row['id'])}::uuid) then and id <> {sql_literal(row["id"])}::uuid) then
raise exception 'approve_claim: source hash collision for source %', {sql_literal(row['id'])}; raise exception 'approve_claim: source hash collision for source %', {sql_literal(row["id"])};
end if;""" end if;"""
) )
statements.append( statements.append("do $source_conflicts$\nbegin\n" + "\n".join(collision_checks) + "\nend\n$source_conflicts$;")
"do $source_conflicts$\nbegin\n"
+ "\n".join(collision_checks)
+ "\nend\n$source_conflicts$;"
)
for row in claims: for row in claims:
tags = _text_array(row["tags"]) tags = _text_array(row["tags"])
statements.append( statements.append(
f"""insert into public.claims (id, type, text, status, confidence, tags, created_by, superseded_by) f"""insert into public.claims (id, type, text, status, confidence, tags, created_by, superseded_by)
select {sql_literal(row['id'])}::uuid, {sql_literal(row['type'])}, {sql_literal(row['text'])}, select {sql_literal(row["id"])}::uuid, {sql_literal(row["type"])}, {sql_literal(row["text"])},
{sql_literal(row['status'])}, {sql_literal(row['confidence'])}, {tags}, {sql_literal(row["status"])}, {sql_literal(row["confidence"])}, {tags},
{sql_literal(row['created_by'])}::uuid, {sql_literal(row['superseded_by'])}::uuid {sql_literal(row["created_by"])}::uuid, {sql_literal(row["superseded_by"])}::uuid
on conflict (id) do nothing;""" on conflict (id) do nothing;"""
) )
checks.append( checks.append(
f""" if not exists (select 1 from public.claims f""" if not exists (select 1 from public.claims
where id = {sql_literal(row['id'])}::uuid where id = {sql_literal(row["id"])}::uuid
and type = {sql_literal(row['type'])} and type = {sql_literal(row["type"])}
and text = {sql_literal(row['text'])} and text = {sql_literal(row["text"])}
and status = {sql_literal(row['status'])} and status = {sql_literal(row["status"])}
and confidence is not distinct from {sql_literal(row['confidence'])} and confidence is not distinct from {sql_literal(row["confidence"])}
and tags is not distinct from {tags} and tags is not distinct from {tags}
and created_by is not distinct from {sql_literal(row['created_by'])}::uuid and created_by is not distinct from {sql_literal(row["created_by"])}::uuid
and superseded_by is not distinct from {sql_literal(row['superseded_by'])}::uuid) then and superseded_by is not distinct from {sql_literal(row["superseded_by"])}::uuid) then
raise exception 'approve_claim: claim row does not match strict apply payload: %', {sql_literal(row['id'])}; raise exception 'approve_claim: claim row does not match strict apply payload: %', {sql_literal(row["id"])};
end if;""" end if;"""
) )
for row in sources: for row in sources:
statements.append( statements.append(
f"""insert into public.sources (id, source_type, url, storage_path, excerpt, hash, created_by) f"""insert into public.sources (id, source_type, url, storage_path, excerpt, hash, created_by)
select {sql_literal(row['id'])}::uuid, {sql_literal(row['source_type'])}, {sql_literal(row['url'])}, select {sql_literal(row["id"])}::uuid, {sql_literal(row["source_type"])}, {sql_literal(row["url"])},
{sql_literal(row['storage_path'])}, {sql_literal(row['excerpt'])}, {sql_literal(row['hash'])}, {sql_literal(row["storage_path"])}, {sql_literal(row["excerpt"])}, {sql_literal(row["hash"])},
{sql_literal(row['created_by'])}::uuid {sql_literal(row["created_by"])}::uuid
on conflict do nothing;""" on conflict do nothing;"""
) )
checks.append( checks.append(
f""" if exists (select 1 from public.sources f""" if exists (select 1 from public.sources
where hash = {sql_literal(row['hash'])} where hash = {sql_literal(row["hash"])}
and id <> {sql_literal(row['id'])}::uuid) then and id <> {sql_literal(row["id"])}::uuid) then
raise exception 'approve_claim: source hash collision for source %', {sql_literal(row['id'])}; raise exception 'approve_claim: source hash collision for source %', {sql_literal(row["id"])};
end if; end if;
if not exists (select 1 from public.sources if not exists (select 1 from public.sources
where id = {sql_literal(row['id'])}::uuid where id = {sql_literal(row["id"])}::uuid
and source_type = {sql_literal(row['source_type'])} and source_type = {sql_literal(row["source_type"])}
and url is not distinct from {sql_literal(row['url'])} and url is not distinct from {sql_literal(row["url"])}
and storage_path is not distinct from {sql_literal(row['storage_path'])} and storage_path is not distinct from {sql_literal(row["storage_path"])}
and excerpt is not distinct from {sql_literal(row['excerpt'])} and excerpt is not distinct from {sql_literal(row["excerpt"])}
and hash = {sql_literal(row['hash'])} and hash = {sql_literal(row["hash"])}
and created_by is not distinct from {sql_literal(row['created_by'])}::uuid) then and created_by is not distinct from {sql_literal(row["created_by"])}::uuid) then
raise exception 'approve_claim: source row does not match strict apply payload: %', {sql_literal(row['id'])}; raise exception 'approve_claim: source row does not match strict apply payload: %', {sql_literal(row["id"])};
end if;""" end if;"""
) )
for row in reasoning_tools: for row in reasoning_tools:
statements.append( statements.append(
f"""insert into public.reasoning_tools (id, agent_id, name, description, category) f"""insert into public.reasoning_tools (id, agent_id, name, description, category)
select {sql_literal(row['id'])}::uuid, {sql_literal(row['agent_id'])}::uuid, select {sql_literal(row["id"])}::uuid, {sql_literal(row["agent_id"])}::uuid,
{sql_literal(row['name'])}, {sql_literal(row['description'])}, {sql_literal(row['category'])} {sql_literal(row["name"])}, {sql_literal(row["description"])}, {sql_literal(row["category"])}
on conflict (id) do nothing;""" on conflict (id) do nothing;"""
) )
checks.append( checks.append(
f""" if not exists (select 1 from public.reasoning_tools f""" if not exists (select 1 from public.reasoning_tools
where id = {sql_literal(row['id'])}::uuid where id = {sql_literal(row["id"])}::uuid
and agent_id is not distinct from {sql_literal(row['agent_id'])}::uuid and agent_id is not distinct from {sql_literal(row["agent_id"])}::uuid
and name = {sql_literal(row['name'])} and name = {sql_literal(row["name"])}
and description = {sql_literal(row['description'])} and description = {sql_literal(row["description"])}
and category is not distinct from {sql_literal(row['category'])}) then and category is not distinct from {sql_literal(row["category"])}) then
raise exception 'approve_claim: reasoning tool row does not match strict apply payload: %', {sql_literal(row['id'])}; raise exception 'approve_claim: reasoning tool row does not match strict apply payload: %', {sql_literal(row["id"])};
end if;""" end if;"""
) )
for row in evidence: for row in evidence:
statements.append( statements.append(
f"""insert into public.claim_evidence (claim_id, source_id, role, weight, created_by) f"""insert into public.claim_evidence (id, claim_id, source_id, role, weight, created_by)
select {sql_literal(row['claim_id'])}::uuid, {sql_literal(row['source_id'])}::uuid, select {sql_literal(row["id"])}::uuid, {sql_literal(row["claim_id"])}::uuid, {sql_literal(row["source_id"])}::uuid,
{sql_literal(row['role'])}::evidence_role, {sql_literal(row['weight'])}, {sql_literal(row["role"])}::evidence_role, {sql_literal(row["weight"])},
{sql_literal(row['created_by'])}::uuid {sql_literal(row["created_by"])}::uuid
on conflict (claim_id, source_id, role) do nothing;""" on conflict (claim_id, source_id, role) do nothing;"""
) )
checks.append( checks.append(
f""" if exists (select 1 from public.claim_evidence f""" -- Accept a legacy receipt id only when exactly one semantic row matches.
where claim_id = {sql_literal(row['claim_id'])}::uuid if (select count(*) from public.claim_evidence
and source_id = {sql_literal(row['source_id'])}::uuid where claim_id = {sql_literal(row["claim_id"])}::uuid
and role = {sql_literal(row['role'])}::evidence_role and source_id = {sql_literal(row["source_id"])}::uuid
and (weight is distinct from {sql_literal(row['weight'])} and role = {sql_literal(row["role"])}::evidence_role) <> 1 then
or created_by is distinct from {sql_literal(row['created_by'])}::uuid)) then raise exception 'approve_claim: evidence row does not match strict apply payload';
end if;
if exists (select 1 from public.claim_evidence
where claim_id = {sql_literal(row["claim_id"])}::uuid
and source_id = {sql_literal(row["source_id"])}::uuid
and role = {sql_literal(row["role"])}::evidence_role
and (weight is distinct from {sql_literal(row["weight"])}
or created_by is distinct from {sql_literal(row["created_by"])}::uuid)) then
raise exception 'approve_claim: evidence row does not match strict apply payload'; raise exception 'approve_claim: evidence row does not match strict apply payload';
end if; end if;
if not exists (select 1 from public.claim_evidence if not exists (select 1 from public.claim_evidence
where claim_id = {sql_literal(row['claim_id'])}::uuid where claim_id = {sql_literal(row["claim_id"])}::uuid
and source_id = {sql_literal(row['source_id'])}::uuid and source_id = {sql_literal(row["source_id"])}::uuid
and role = {sql_literal(row['role'])}::evidence_role and role = {sql_literal(row["role"])}::evidence_role
and weight is not distinct from {sql_literal(row['weight'])} and weight is not distinct from {sql_literal(row["weight"])}
and created_by is not distinct from {sql_literal(row['created_by'])}::uuid) then and created_by is not distinct from {sql_literal(row["created_by"])}::uuid) then
raise exception 'approve_claim: evidence row does not match strict apply payload'; raise exception 'approve_claim: evidence row does not match strict apply payload';
end if;""" end if;"""
) )
for row in edges: for row in edges:
edge_lock_key = ( edge_lock_key = f"claim_edge:{row['from_claim']}:{row['to_claim']}:{row['edge_type']}"
f"claim_edge:{row['from_claim']}:{row['to_claim']}:{row['edge_type']}"
)
statements.append( statements.append(
f"""select pg_advisory_xact_lock(hashtextextended({sql_literal(edge_lock_key)}, 0)); f"""select pg_advisory_xact_lock(hashtextextended({sql_literal(edge_lock_key)}, 0));
insert into public.claim_edges (from_claim, to_claim, edge_type, weight, created_by) insert into public.claim_edges (id, from_claim, to_claim, edge_type, weight, created_by)
select {sql_literal(row['from_claim'])}::uuid, {sql_literal(row['to_claim'])}::uuid, select {sql_literal(row["id"])}::uuid, {sql_literal(row["from_claim"])}::uuid, {sql_literal(row["to_claim"])}::uuid,
{sql_literal(row['edge_type'])}::edge_type, {sql_literal(row['weight'])}, {sql_literal(row["edge_type"])}::edge_type, {sql_literal(row["weight"])},
{sql_literal(row['created_by'])}::uuid {sql_literal(row["created_by"])}::uuid
where not exists ( where not exists (
select 1 from public.claim_edges select 1 from public.claim_edges
where from_claim = {sql_literal(row['from_claim'])}::uuid where from_claim = {sql_literal(row["from_claim"])}::uuid
and to_claim = {sql_literal(row['to_claim'])}::uuid and to_claim = {sql_literal(row["to_claim"])}::uuid
and edge_type = {sql_literal(row['edge_type'])}::edge_type);""" and edge_type = {sql_literal(row["edge_type"])}::edge_type);"""
) )
checks.append( checks.append(
f""" if exists (select 1 from public.claim_edges f""" -- Accept a legacy receipt id only when exactly one semantic row matches.
where from_claim = {sql_literal(row['from_claim'])}::uuid if (select count(*) from public.claim_edges
and to_claim = {sql_literal(row['to_claim'])}::uuid where from_claim = {sql_literal(row["from_claim"])}::uuid
and edge_type = {sql_literal(row['edge_type'])}::edge_type and to_claim = {sql_literal(row["to_claim"])}::uuid
and (weight is distinct from {sql_literal(row['weight'])} and edge_type = {sql_literal(row["edge_type"])}::edge_type) <> 1 then
or created_by is distinct from {sql_literal(row['created_by'])}::uuid)) then raise exception 'approve_claim: edge row does not match strict apply payload';
end if;
if exists (select 1 from public.claim_edges
where from_claim = {sql_literal(row["from_claim"])}::uuid
and to_claim = {sql_literal(row["to_claim"])}::uuid
and edge_type = {sql_literal(row["edge_type"])}::edge_type
and (weight is distinct from {sql_literal(row["weight"])}
or created_by is distinct from {sql_literal(row["created_by"])}::uuid)) then
raise exception 'approve_claim: edge row does not match strict apply payload'; raise exception 'approve_claim: edge row does not match strict apply payload';
end if; end if;
if not exists (select 1 from public.claim_edges if not exists (select 1 from public.claim_edges
where from_claim = {sql_literal(row['from_claim'])}::uuid where from_claim = {sql_literal(row["from_claim"])}::uuid
and to_claim = {sql_literal(row['to_claim'])}::uuid and to_claim = {sql_literal(row["to_claim"])}::uuid
and edge_type = {sql_literal(row['edge_type'])}::edge_type and edge_type = {sql_literal(row["edge_type"])}::edge_type
and weight is not distinct from {sql_literal(row['weight'])} and weight is not distinct from {sql_literal(row["weight"])}
and created_by is not distinct from {sql_literal(row['created_by'])}::uuid) then and created_by is not distinct from {sql_literal(row["created_by"])}::uuid) then
raise exception 'approve_claim: edge row does not match strict apply payload'; raise exception 'approve_claim: edge row does not match strict apply payload';
end if;""" end if;"""
) )
canonical = "\n\n".join(statements) canonical = "\n\n".join(statements)
ledger = _ledger_and_verify( ledger = _ledger_and_verify(proposal_id, applied_by or SERVICE_AGENT_HANDLE, "\n".join(checks), approval)
proposal_id, applied_by or SERVICE_AGENT_HANDLE, "\n".join(checks), approval
)
return _wrap_txn(canonical, ledger, _approval_guard_sql(proposal_id, approval)) return _wrap_txn(canonical, ledger, _approval_guard_sql(proposal_id, approval))
@ -837,9 +876,7 @@ def assert_applyable(proposal: dict[str, Any]) -> None:
if status == "applied": if status == "applied":
raise SystemExit(f"proposal {proposal['id']} is already applied (idempotent no-op)") raise SystemExit(f"proposal {proposal['id']} is already applied (idempotent no-op)")
if status != "approved": if status != "approved":
raise SystemExit( raise SystemExit(f"proposal {proposal['id']} has status {status!r}; only 'approved' proposals apply")
f"proposal {proposal['id']} has status {status!r}; only 'approved' proposals apply"
)
def assert_receiptable(proposal: dict[str, Any]) -> None: def assert_receiptable(proposal: dict[str, Any]) -> None:
@ -877,23 +914,36 @@ def run_psql(
) -> str: ) -> str:
docker_binary = shutil.which("docker") or "docker" docker_binary = shutil.which("docker") or "docker"
command = [ command = [
docker_binary, "exec", "-e", "PGPASSWORD", "-i", args.container, docker_binary,
"psql", "-U", args.role, "-h", args.host, "-d", args.db, "exec",
"-v", "ON_ERROR_STOP=1", "-At", "-q", "-e",
"PGPASSWORD",
"-i",
args.container,
"psql",
"-U",
args.role,
"-h",
args.host,
"-d",
args.db,
"-v",
"ON_ERROR_STOP=1",
"-At",
"-q",
] ]
result = subprocess.run( result = subprocess.run(
command, input=sql, text=True, capture_output=True, command,
input=sql,
text=True,
capture_output=True,
env={"PGPASSWORD": password, "PATH": "/usr/bin:/bin:/usr/local/bin"}, env={"PGPASSWORD": password, "PATH": "/usr/bin:/bin:/usr/local/bin"},
check=False, check=False,
) )
if result.returncode != 0: if result.returncode != 0:
if redact_output_on_error: if redact_output_on_error:
raise SystemExit( raise SystemExit(f"psql failed ({result.returncode}); private postflight output redacted")
f"psql failed ({result.returncode}); private postflight output redacted" raise SystemExit(f"psql failed ({result.returncode})\nSTDOUT:\n{result.stdout}\nSTDERR:\n{result.stderr}")
)
raise SystemExit(
f"psql failed ({result.returncode})\nSTDOUT:\n{result.stdout}\nSTDERR:\n{result.stderr}"
)
return result.stdout return result.stdout
@ -980,8 +1030,7 @@ def parse_args(argv: list[str]) -> argparse.Namespace:
p.add_argument( p.add_argument(
"--receipt-dir", "--receipt-dir",
default=None, default=None,
help="private receipt directory (default: KB_APPLY_RECEIPT_DIR or " help=f"private receipt directory (default: KB_APPLY_RECEIPT_DIR or {replay_receipt.DEFAULT_RECEIPT_DIR})",
f"{replay_receipt.DEFAULT_RECEIPT_DIR})",
) )
p.add_argument( p.add_argument(
"--receipt-out", "--receipt-out",

View file

@ -35,6 +35,7 @@ from __future__ import annotations
import argparse import argparse
import json import json
import os import os
import stat
import subprocess import subprocess
import sys import sys
from pathlib import Path from pathlib import Path
@ -53,6 +54,13 @@ WORKER_TYPES = ap.APPLYABLE_TYPES
# bundles and evidence/edge applies do not trigger a generic identity render. # bundles and evidence/edge applies do not trigger a generic identity render.
RENDER_TYPES = ("revise_strategy",) RENDER_TYPES = ("revise_strategy",)
POSTCOMMIT_RECEIPT_FAILURE_MARKER = "committed, but private replay receipt capture failed"
POSTCOMMIT_RECEIPT_RECOVERY_MARKER = ". Recover without reapplying via: "
class PostCommitReceiptError(RuntimeError):
"""The proposal committed, but its private row-level receipt is unavailable."""
# --------------------------------------------------------------------------- # # --------------------------------------------------------------------------- #
# Pure helpers (unit-tested without a DB) # # Pure helpers (unit-tested without a DB) #
@ -160,14 +168,69 @@ def partition_candidates(
return {"poisoned": poisoned, "to_apply": eligible[: max(0, max_per_tick)]} return {"poisoned": poisoned, "to_apply": eligible[: max(0, max_per_tick)]}
def has_exact_postcommit_receipt_failure(stderr: str | None, proposal_id: str) -> bool:
"""Recognize only the proposal-bound post-COMMIT message from apply_proposal.
The old marker can occur inside payload-validation tracebacks (for example,
as an attacker-controlled unknown field name). Requiring the complete
engine message shape prevents those pre-COMMIT failures from bypassing the
normal failure and poison-pill accounting.
"""
prefix = f"proposal {proposal_id} {POSTCOMMIT_RECEIPT_FAILURE_MARKER}: "
recovery_suffix = f" {proposal_id} --receipt-only"
for line in (stderr or "").splitlines():
candidate = line.rstrip("\r")
if (
candidate.startswith(prefix)
and POSTCOMMIT_RECEIPT_RECOVERY_MARKER in candidate[len(prefix) :]
and candidate.endswith(recovery_suffix)
):
return True
return False
def receipt_path_for_proposal(args: argparse.Namespace, proposal_id: str) -> Path:
"""Return the explicit, deterministic private receipt path for one proposal."""
receipt_dir = (
getattr(args, "receipt_dir", None)
or os.environ.get("KB_APPLY_WORKER_RECEIPT_DIR")
or os.environ.get("KB_APPLY_RECEIPT_DIR")
or ap.replay_receipt.DEFAULT_RECEIPT_DIR
)
return Path(receipt_dir).expanduser().resolve() / f"{proposal_id}.json"
def assert_private_replay_receipt(path: Path, proposal_id: str) -> None:
"""Verify the worker can rely on the exact private row-level receipt."""
try:
path_stat = path.lstat()
except OSError as exc:
raise RuntimeError("private replay receipt was not written") from exc
if not stat.S_ISREG(path_stat.st_mode) or path.is_symlink():
raise RuntimeError("private replay receipt is not a regular file")
if stat.S_IMODE(path_stat.st_mode) & 0o077:
raise RuntimeError("private replay receipt permissions are broader than 0600")
try:
receipt = json.loads(path.read_text(encoding="utf-8"))
except (OSError, json.JSONDecodeError) as exc:
raise RuntimeError("private replay receipt is unreadable or invalid") from exc
if not isinstance(receipt, dict):
raise RuntimeError("private replay receipt is not a JSON object")
try:
ap.replay_receipt.validate_replay_receipt(
receipt,
expected_proposal_id=str(proposal_id),
)
except ValueError as exc:
raise RuntimeError("private replay receipt row-level contract is invalid") from exc
# --------------------------------------------------------------------------- # # --------------------------------------------------------------------------- #
# Side-effecting steps # # Side-effecting steps #
# --------------------------------------------------------------------------- # # --------------------------------------------------------------------------- #
def _psql_args(args: argparse.Namespace) -> argparse.Namespace: def _psql_args(args: argparse.Namespace) -> argparse.Namespace:
"""Namespace shaped for ap.run_psql (reuses the kb_apply connection path).""" """Namespace shaped for ap.run_psql (reuses the kb_apply connection path)."""
return argparse.Namespace( return argparse.Namespace(container=args.container, db=args.db, host=args.host, role=args.role)
container=args.container, db=args.db, host=args.host, role=args.role
)
def fetch_candidates( def fetch_candidates(
@ -181,19 +244,72 @@ def fetch_candidates(
def apply_one(args: argparse.Namespace, proposal_id: str) -> None: def apply_one(args: argparse.Namespace, proposal_id: str) -> None:
"""Apply via the audited apply_proposal.py CLI -- same txn + rowcount guard.""" """Apply once and retain or safely recover the exact private replay receipt."""
receipt_path = receipt_path_for_proposal(args, proposal_id)
cmd = [ cmd = [
sys.executable, str(args.apply_script), proposal_id, sys.executable,
"--applied-by", args.applied_by, str(args.apply_script),
"--secrets-file", args.secrets_file, proposal_id,
"--container", args.container, "--db", args.db, "--applied-by",
"--host", args.host, "--role", args.role, args.applied_by,
"--secrets-file",
args.secrets_file,
"--container",
args.container,
"--db",
args.db,
"--host",
args.host,
"--role",
args.role,
"--receipt-dir",
str(receipt_path.parent),
"--receipt-out",
str(receipt_path),
] ]
result = subprocess.run(cmd, text=True, capture_output=True, check=False) result = subprocess.run(cmd, text=True, capture_output=True, check=False)
if result.returncode != 0: committed = result.returncode == 0 or has_exact_postcommit_receipt_failure(
raise RuntimeError( result.stderr,
f"apply failed for {proposal_id}: {result.stdout.strip()} {result.stderr.strip()}" proposal_id,
) )
if not committed:
raise RuntimeError(
f"apply failed for {proposal_id}: {(result.stdout or '').strip()} {(result.stderr or '').strip()}"
)
if result.returncode == 0:
try:
assert_private_replay_receipt(receipt_path, proposal_id)
return
except RuntimeError:
# The engine returned only after COMMIT. A missing/invalid receipt is
# recoverable without replaying the apply transaction.
pass
try:
recovery = subprocess.run(
[*cmd, "--receipt-only"],
text=True,
capture_output=True,
check=False,
)
except OSError as exc:
raise PostCommitReceiptError(
f"proposal {proposal_id} committed, but the read-only receipt recovery "
"command could not start; do not retry the apply transaction"
) from exc
if recovery.returncode != 0:
raise PostCommitReceiptError(
f"proposal {proposal_id} committed, but read-only receipt recovery "
f"failed (exit {recovery.returncode}); do not retry the apply transaction"
)
try:
assert_private_replay_receipt(receipt_path, proposal_id)
except RuntimeError as exc:
raise PostCommitReceiptError(
f"proposal {proposal_id} committed, but receipt recovery did not produce "
"a valid private row-level receipt; do not retry the apply transaction"
) from exc
def render_one(args: argparse.Namespace, agent_id: str | None) -> str: def render_one(args: argparse.Namespace, agent_id: str | None) -> str:
@ -202,9 +318,7 @@ def render_one(args: argparse.Namespace, agent_id: str | None) -> str:
return "render skipped (no render-cmd configured; PR2 renderer not deployed)" return "render skipped (no render-cmd configured; PR2 renderer not deployed)"
result = subprocess.run(cmd, text=True, capture_output=True, check=False) result = subprocess.run(cmd, text=True, capture_output=True, check=False)
if result.returncode != 0: if result.returncode != 0:
raise RuntimeError( raise RuntimeError(f"render failed for agent {agent_id}: {result.stdout.strip()} {result.stderr.strip()}")
f"render failed for agent {agent_id}: {result.stdout.strip()} {result.stderr.strip()}"
)
return f"rendered agent {agent_id}" return f"rendered agent {agent_id}"
@ -214,11 +328,7 @@ def render_one(args: argparse.Namespace, agent_id: str | None) -> str:
def run(args: argparse.Namespace) -> int: def run(args: argparse.Namespace) -> int:
password = ap.load_password(args.secrets_file) password = ap.load_password(args.secrets_file)
failure_counts = load_failure_state(args.failure_state_file) failure_counts = load_failure_state(args.failure_state_file)
exhausted_ids = tuple( exhausted_ids = tuple(proposal_id for proposal_id, count in failure_counts.items() if count >= args.max_attempts)
proposal_id
for proposal_id, count in failure_counts.items()
if count >= args.max_attempts
)
candidates = fetch_candidates(args, password, exhausted_ids) candidates = fetch_candidates(args, password, exhausted_ids)
for proposal_id in exhausted_ids: for proposal_id in exhausted_ids:
@ -263,6 +373,15 @@ def run(args: argparse.Namespace) -> int:
print(f"applied {pid} ({ptype})") print(f"applied {pid} ({ptype})")
if ptype in RENDER_TYPES: if ptype in RENDER_TYPES:
print(" " + render_one(args, agent_id)) print(" " + render_one(args, agent_id))
except PostCommitReceiptError as exc:
failures += 1
# The canonical transaction already committed. Do not classify this
# as an apply failure or poison/retry the proposal; receipt-only is
# the sole safe recovery path.
print(
f"POST-COMMIT RECEIPT ERROR for {pid} ({ptype}): {exc}",
file=sys.stderr,
)
except Exception as exc: except Exception as exc:
failures += 1 failures += 1
# Leave the proposal at 'approved' so a fixed one reapplies next tick # Leave the proposal at 'approved' so a fixed one reapplies next tick
@ -270,48 +389,65 @@ def run(args: argparse.Namespace) -> int:
# so a deterministically-failing proposal hits the ceiling instead of # so a deterministically-failing proposal hits the ceiling instead of
# retrying forever. Surface loudly for the operator. # retrying forever. Surface loudly for the operator.
failure_counts[pid] = failure_counts.get(pid, 0) + 1 failure_counts[pid] = failure_counts.get(pid, 0) + 1
print(f"ERROR applying {pid} ({ptype}) [attempt {failure_counts[pid]}/" print(
f"{args.max_attempts}]: {exc}", file=sys.stderr) f"ERROR applying {pid} ({ptype}) [attempt {failure_counts[pid]}/{args.max_attempts}]: {exc}",
file=sys.stderr,
)
save_failure_state(args.failure_state_file, failure_counts) save_failure_state(args.failure_state_file, failure_counts)
return 1 if failures else 0 return 1 if failures else 0
def parse_args(argv: list[str]) -> argparse.Namespace: def parse_args(argv: list[str]) -> argparse.Namespace:
p = argparse.ArgumentParser( p = argparse.ArgumentParser(description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter)
description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter
)
p.add_argument( p.add_argument(
"--enable", action="store_true", "--enable",
action="store_true",
help="actually apply (default: report-only). Also honored via KB_APPLY_WORKER_ENABLED=1.", help="actually apply (default: report-only). Also honored via KB_APPLY_WORKER_ENABLED=1.",
) )
p.add_argument("--limit", type=int, default=20, help="max candidates fetched per tick") p.add_argument("--limit", type=int, default=20, help="max candidates fetched per tick")
p.add_argument( p.add_argument(
"--max-per-tick", type=int, default=1, "--max-per-tick",
type=int,
default=1,
help="max proposals actually APPLIED per tick (default 1: applies land " help="max proposals actually APPLIED per tick (default 1: applies land "
"one-at-a-time and observably, not a whole-queue drain)", "one-at-a-time and observably, not a whole-queue drain)",
) )
p.add_argument( p.add_argument(
"--max-attempts", type=int, default=3, "--max-attempts",
type=int,
default=3,
help="consecutive apply failures before a proposal is treated as a " help="consecutive apply failures before a proposal is treated as a "
"poison pill and skipped (needs a human fix, not endless retries)", "poison pill and skipped (needs a human fix, not endless retries)",
) )
p.add_argument( p.add_argument(
"--failure-state-file", "--failure-state-file",
default=os.environ.get("KB_APPLY_WORKER_STATE", "/opt/teleo-eval/logs/kb-apply-worker-failures.json"), default=os.environ.get("KB_APPLY_WORKER_STATE", "/opt/teleo-eval/logs/kb-apply-worker-failures.json"),
help="persisted per-proposal failure counts (survives oneshot ticks so " help="persisted per-proposal failure counts (survives oneshot ticks so the poison-pill ceiling actually bites)",
"the poison-pill ceiling actually bites)",
) )
p.add_argument( p.add_argument(
"--applied-by", default=ap.SERVICE_AGENT_HANDLE, "--applied-by",
default=ap.SERVICE_AGENT_HANDLE,
help="handle recorded as applied_by (default: the kb-apply service agent)", help="handle recorded as applied_by (default: the kb-apply service agent)",
) )
p.add_argument( p.add_argument(
"--apply-script", default=str(HERE / "apply_proposal.py"), "--apply-script",
default=str(HERE / "apply_proposal.py"),
help="path to the apply_proposal.py engine (the sole apply path)", help="path to the apply_proposal.py engine (the sole apply path)",
) )
p.add_argument( p.add_argument(
"--render-cmd", default=os.environ.get("KB_APPLY_RENDER_CMD", ""), "--receipt-dir",
default=(
os.environ.get("KB_APPLY_WORKER_RECEIPT_DIR")
or os.environ.get("KB_APPLY_RECEIPT_DIR")
or ap.replay_receipt.DEFAULT_RECEIPT_DIR
),
help="private replay receipt directory; each apply writes the deterministic "
"<proposal-id>.json path and verifies 0600 permissions",
)
p.add_argument(
"--render-cmd",
default=os.environ.get("KB_APPLY_RENDER_CMD", ""),
help="render hook template, e.g. 'python3 render_soul.py --agent-id {agent_id}'. " help="render hook template, e.g. 'python3 render_soul.py --agent-id {agent_id}'. "
"Empty (default) skips render until the SOUL renderer is deployed.", "Empty (default) skips render until the SOUL renderer is deployed.",
) )

View file

@ -0,0 +1,230 @@
#!/usr/bin/env python3
"""Finalize outer isolation and cleanup evidence for the clone canary."""
from __future__ import annotations
import hashlib
import json
import os
import sys
from collections.abc import Mapping
from pathlib import Path
from typing import Any
def _service(raw: str) -> dict[str, str]:
return dict(line.split("=", 1) for line in raw.splitlines() if "=" in line)
def _table_deltas(before: dict[str, int], after: dict[str, int]) -> dict[str, int]:
if set(before) != set(after):
raise ValueError(
f"live source count keys changed during the canary: before={sorted(before)} after={sorted(after)}"
)
return {key: after[key] - before[key] for key in sorted(before)}
def _verify_source_binding(root: Path, records: list[dict[str, object]]) -> dict[str, object]:
readbacks = []
for record in records:
relative_text = str(record.get("repo_relative_path", ""))
relative = Path(relative_text)
if not relative_text or relative.is_absolute() or ".." in relative.parts:
raise ValueError(f"unsafe repo-relative source path: {relative_text!r}")
candidate = (root / relative).resolve()
try:
candidate.relative_to(root)
except ValueError as exc:
raise ValueError(f"source path escaped repository root: {relative_text}") from exc
if not candidate.is_file():
readbacks.append(
{
"repo_relative_path": relative.as_posix(),
"expected_sha256": record.get("sha256"),
"actual_sha256": None,
"matches": False,
}
)
continue
content = candidate.read_bytes()
actual_sha256 = hashlib.sha256(content).hexdigest()
readbacks.append(
{
"repo_relative_path": relative.as_posix(),
"expected_sha256": record.get("sha256"),
"actual_sha256": actual_sha256,
"size_bytes": len(content),
"matches": (actual_sha256 == record.get("sha256") and len(content) == record.get("size_bytes")),
}
)
return {
"files": readbacks,
"all_match": bool(readbacks) and all(bool(row["matches"]) for row in readbacks),
}
def _contains_ephemeral_path(value: object) -> bool:
if isinstance(value, str):
return "/tmp/" in value
if isinstance(value, dict):
return any(_contains_ephemeral_path(item) for item in value.values())
if isinstance(value, list):
return any(_contains_ephemeral_path(item) for item in value)
return False
def finalize(path: Path, env: Mapping[str, str]) -> dict[str, Any]:
if not path.is_file():
raise ValueError("inner canary did not produce a report")
data = json.loads(path.read_text(encoding="utf-8"))
if not isinstance(data, dict):
raise ValueError("inner canary report must be a JSON object")
before_counts = json.loads(env["SOURCE_COUNTS_BEFORE"])
after_counts = json.loads(env["SOURCE_COUNTS_AFTER"])
live_table_deltas = _table_deltas(before_counts, after_counts)
before_service = _service(env["SERVICE_BEFORE"])
after_service = _service(env["SERVICE_AFTER"])
source_tier = env["SOURCE_TIER"]
source_network_mode = env["SOURCE_NETWORK_MODE"]
source_canary_label = env["SOURCE_CANARY_LABEL"]
container_network_mode = env["CANARY_NETWORK_MODE"]
container_mounts = json.loads(env["CANARY_MOUNTS_JSON"])
container_canary_label = env["CANARY_LABEL"]
container_instance_label = env["CANARY_INSTANCE_LABEL"]
container_volume_mounts = [mount for mount in container_mounts if mount.get("Type") == "volume"]
container_isolated = container_network_mode == "none" and not container_volume_mounts
container_labeled = container_canary_label == "proposal-apply-lifecycle" and container_instance_label.startswith(
"working-leo-approve-claim-"
)
source_tier_enforced = source_tier != "isolated-local" or (
source_network_mode == "none" and source_canary_label == "working-leo-approved-source"
)
service_observable = before_service.get("Available") == "true" and after_service.get("Available") == "true"
service_stable = (
all(
before_service.get(key) == after_service.get(key)
for key in ("ActiveState", "SubState", "MainPID", "NRestarts")
)
if service_observable
else None
)
service_gate_passes = service_stable is True if source_tier == "live-readonly" else service_stable is not False
container_absent = int(env["CONTAINER_NAME_READBACK_RC"]) == 0 and not env["CONTAINER_NAME_READBACK"].strip()
label_scoped_orphan_count = int(env["CONTAINER_LABEL_ORPHAN_COUNT"])
label_scoped_container_absent = (
int(env["CONTAINER_LABEL_READBACK_RC"]) == 0
and label_scoped_orphan_count == 0
and not env["CONTAINER_LABEL_READBACK"].strip()
)
workdir_absent = env["OUTER_WORKDIR_LEXISTS"] == "false"
source_binding = _verify_source_binding(
Path(env["REPO_ROOT"]).resolve(),
data.get("source_binding", {}).get("files", []),
)
data["source_binding"]["independent_post_cleanup_verification"] = source_binding
source_binding_ok = (
data["source_binding"].get("unchanged_during_run") is True and source_binding["all_match"] is True
)
stale_ephemeral_paths_absent = not _contains_ephemeral_path(data)
inner_runtime_pass = data.get("status") == "pass" and int(env["CANARY_RC"]) == 0
outer_ok = (
before_counts == after_counts
and all(delta == 0 for delta in live_table_deltas.values())
and service_gate_passes
and container_absent
and label_scoped_container_absent
and workdir_absent
and source_binding_ok
and stale_ephemeral_paths_absent
and container_isolated
and container_labeled
and source_tier_enforced
)
if source_tier == "isolated-local":
data["required_tier"] = "T2_runtime"
data["required_tiers"] = ["T2_runtime"]
data["runtime_scope"] = "isolated_postgres_container_from_readonly_local_fixture"
else:
data["required_tier"] = "T3_live_readonly"
data["required_tiers"] = ["T2_runtime", "T3_live_readonly"]
data["runtime_scope"] = "isolated_postgres_container_from_readonly_live_schema"
data["outer_isolation"] = {
"source_container": env.get("SOURCE_CONTAINER", "teleo-pg"),
"source_database": env.get("SOURCE_DB", "teleo"),
"source_counts_before": before_counts,
"source_counts_after": after_counts,
"canonical_table_deltas": live_table_deltas,
"source_counts_unchanged": before_counts == after_counts,
"service_before": before_service,
"service_after": after_service,
"service_required": source_tier == "live-readonly",
"service_observable": service_observable,
"service_stable": service_stable,
"service_gate_passes": service_gate_passes,
"source_boundary": {
"source_tier": source_tier,
"network_mode": source_network_mode,
"canary_label": source_canary_label,
"tier_enforced": source_tier_enforced,
},
"container_isolation": {
"network_mode": container_network_mode,
"volume_mounts": container_volume_mounts,
"canary_label": container_canary_label,
"instance_label": container_instance_label,
"lifecycle_labeled": container_labeled,
"network_disabled": container_network_mode == "none",
"no_docker_volumes": not container_volume_mounts,
},
"cleanup_readback": {
"container_remove_returncode": int(env["OUTER_CONTAINER_REMOVE_RC"]),
"container_name_query_returncode": int(env["CONTAINER_NAME_READBACK_RC"]),
"container_name_query_stdout": env["CONTAINER_NAME_READBACK"],
"temporary_container_absent": container_absent,
"label_scoped_query_returncode": int(env["CONTAINER_LABEL_READBACK_RC"]),
"label_scoped_query_stdout": env["CONTAINER_LABEL_READBACK"],
"label_scoped_orphan_count": label_scoped_orphan_count,
"label_scoped_temporary_container_absent": label_scoped_container_absent,
"workdir_remove_returncode": int(env["OUTER_WORKDIR_REMOVE_RC"]),
"workdir_lexists_after_cleanup": not workdir_absent,
"temporary_workdir_absent": workdir_absent,
},
}
checks = data["checks"]
checks["outer_live_counts_exactly_unchanged"] = before_counts == after_counts
checks["outer_live_table_deltas_exactly_zero"] = all(delta == 0 for delta in live_table_deltas.values())
checks["outer_service_observed_if_required"] = source_tier != "live-readonly" or service_observable
checks["outer_service_stable_if_observed"] = service_gate_passes
checks["outer_container_absent_independent_readback"] = container_absent
checks["outer_labeled_container_absent_independent_readback"] = label_scoped_container_absent
checks["outer_workdir_absent_independent_readback"] = workdir_absent
checks["source_binding_independently_verified"] = source_binding_ok
checks["stale_ephemeral_paths_absent"] = stale_ephemeral_paths_absent
checks["outer_source_tier_enforced"] = source_tier_enforced
checks["outer_container_network_disabled"] = container_network_mode == "none"
checks["outer_container_lifecycle_labeled"] = container_labeled
checks["outer_container_has_no_docker_volumes"] = not container_volume_mounts
checks["outer_isolation_complete"] = outer_ok
if outer_ok and inner_runtime_pass:
data["current_tier"] = "T2_runtime" if source_tier == "isolated-local" else "T3_live_readonly"
else:
data["status"] = "fail"
data["current_tier"] = "T2_runtime" if inner_runtime_pass else "T1_model"
path.write_text(json.dumps(data, indent=2, sort_keys=True) + "\n", encoding="utf-8")
return data
def main(argv: list[str] | None = None) -> int:
arguments = sys.argv[1:] if argv is None else argv
if len(arguments) != 1:
raise SystemExit("usage: finalize_approve_claim_isolated_canary.py REPORT.json")
try:
data = finalize(Path(arguments[0]), os.environ)
except (KeyError, OSError, ValueError, json.JSONDecodeError) as exc:
raise SystemExit(str(exc)) from exc
return 0 if data["status"] == "pass" else 1
if __name__ == "__main__":
raise SystemExit(main())

View file

@ -446,6 +446,41 @@ def build_replay_receipt(
} }
def validate_replay_receipt(
receipt: dict[str, Any],
*,
expected_proposal_id: str | None = None,
) -> dict[str, Any]:
"""Rebuild and require the exact private replay-receipt contract.
Canonical JSON comparison is deliberate: Python equality treats booleans
and integers as interchangeable, which is unsafe for authorization and
receipt fields.
"""
if not isinstance(receipt, dict):
raise ValueError("replay receipt must be an object")
proposal = receipt.get("proposal")
rows = receipt.get("canonical_rows")
apply_engine = receipt.get("apply_engine")
if not isinstance(proposal, dict) or not isinstance(rows, dict) or not isinstance(apply_engine, dict):
raise ValueError("replay receipt is missing proposal, canonical rows, or apply-engine metadata")
if expected_proposal_id is not None and proposal.get("id") != expected_proposal_id:
raise ValueError("replay receipt proposal id does not match")
try:
rebuilt = build_replay_receipt(
proposal,
rows,
apply_sql_sha256=apply_engine.get("apply_sql_sha256"),
apply_sql_source=apply_engine.get("source"),
exported_at_utc=receipt.get("exported_at_utc"),
)
except (KeyError, TypeError, ValueError) as exc:
raise ValueError("replay receipt failed full contract validation") from exc
if _canonical_json(receipt) != _canonical_json(rebuilt):
raise ValueError("replay receipt hashes, counts, rows, or contract fields are internally inconsistent")
return rebuilt
def resolve_receipt_path( def resolve_receipt_path(
proposal_id: str, proposal_id: str,
*, *,

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -9,6 +9,8 @@ image="${POSTGRES_CANARY_IMAGE:-postgres:16}"
source_tier="${SOURCE_TIER:-live-readonly}" source_tier="${SOURCE_TIER:-live-readonly}"
normalization_json="" normalization_json=""
output="${repo_root}/docs/reports/leo-working-state-20260709/approve-claim-clone-canary-current.json" output="${repo_root}/docs/reports/leo-working-state-20260709/approve-claim-clone-canary-current.json"
lifecycle_receipt_output=""
rollback_sql_output=""
while [[ $# -gt 0 ]]; do while [[ $# -gt 0 ]]; do
case "$1" in case "$1" in
@ -20,6 +22,14 @@ while [[ $# -gt 0 ]]; do
output="$2" output="$2"
shift 2 shift 2
;; ;;
--lifecycle-receipt-output)
lifecycle_receipt_output="$2"
shift 2
;;
--rollback-sql-output)
rollback_sql_output="$2"
shift 2
;;
--source-container) --source-container)
source_container="$2" source_container="$2"
shift 2 shift 2
@ -99,11 +109,19 @@ service_state() {
} }
mkdir -p "$workdir" "$(dirname "$output")" mkdir -p "$workdir" "$(dirname "$output")"
if [[ -n "$lifecycle_receipt_output" ]]; then
mkdir -p "$(dirname "$lifecycle_receipt_output")"
fi
if [[ -n "$rollback_sql_output" ]]; then
mkdir -p "$(dirname "$rollback_sql_output")"
fi
source_counts_before="$(source_counts)" source_counts_before="$(source_counts)"
service_before="$(service_state)" service_before="$(service_state)"
docker run -d --name "$container" \ docker run -d --name "$container" \
--network none \ --network none \
--label livingip.canary=proposal-apply-lifecycle \
--label "livingip.canary.instance=${container}" \
--tmpfs /var/lib/postgresql/data:rw,nosuid,size=512m \ --tmpfs /var/lib/postgresql/data:rw,nosuid,size=512m \
-e POSTGRES_PASSWORD="isolated-postgres-${RANDOM}-${RANDOM}" \ -e POSTGRES_PASSWORD="isolated-postgres-${RANDOM}-${RANDOM}" \
-e POSTGRES_DB=teleo \ -e POSTGRES_DB=teleo \
@ -127,6 +145,12 @@ if [[ "$ready_streak" -lt 2 ]]; then
fi fi
container_network_mode="$(docker inspect -f '{{.HostConfig.NetworkMode}}' "$container")" container_network_mode="$(docker inspect -f '{{.HostConfig.NetworkMode}}' "$container")"
container_mounts_json="$(docker inspect -f '{{json .Mounts}}' "$container")" container_mounts_json="$(docker inspect -f '{{json .Mounts}}' "$container")"
container_canary_label="$(
docker inspect -f '{{index .Config.Labels "livingip.canary"}}' "$container"
)"
container_instance_label="$(
docker inspect -f '{{index .Config.Labels "livingip.canary.instance"}}' "$container"
)"
docker exec "$source_container" pg_dump -U postgres -d "$source_db" \ docker exec "$source_container" pg_dump -U postgres -d "$source_db" \
--schema-only --no-owner --no-privileges >"$workdir/schema.sql" --schema-only --no-owner --no-privileges >"$workdir/schema.sql"
@ -165,6 +189,13 @@ normalization_args=()
if [[ -n "$normalization_json" ]]; then if [[ -n "$normalization_json" ]]; then
normalization_args=(--normalization-json "$normalization_json") normalization_args=(--normalization-json "$normalization_json")
fi fi
artifact_args=()
if [[ -n "$lifecycle_receipt_output" ]]; then
artifact_args+=(--lifecycle-receipt-output "$lifecycle_receipt_output")
fi
if [[ -n "$rollback_sql_output" ]]; then
artifact_args+=(--rollback-sql-output "$rollback_sql_output")
fi
set +e set +e
python3 "$repo_root/scripts/run_approve_claim_clone_canary.py" \ python3 "$repo_root/scripts/run_approve_claim_clone_canary.py" \
@ -178,6 +209,7 @@ python3 "$repo_root/scripts/run_approve_claim_clone_canary.py" \
--review-secrets-file "$workdir/kb-review.env" \ --review-secrets-file "$workdir/kb-review.env" \
--secrets-file "$workdir/kb-apply.env" \ --secrets-file "$workdir/kb-apply.env" \
"${normalization_args[@]}" \ "${normalization_args[@]}" \
"${artifact_args[@]}" \
--output "$output" \ --output "$output" \
>"$workdir/stdout.json" 2>"$workdir/stderr.log" >"$workdir/stdout.json" 2>"$workdir/stderr.log"
canary_rc=$? canary_rc=$?
@ -192,6 +224,20 @@ container_name_readback="$(
docker container ls -a --filter "name=^/${container}$" --format '{{.Names}}' 2>&1 docker container ls -a --filter "name=^/${container}$" --format '{{.Names}}' 2>&1
)" )"
container_name_readback_rc=$? container_name_readback_rc=$?
container_label_readback="$(
docker container ls -a \
--filter "label=livingip.canary=proposal-apply-lifecycle" \
--filter "label=livingip.canary.instance=${container}" \
--format '{{.Names}}' 2>&1
)"
container_label_readback_rc=$?
if [[ "$container_label_readback_rc" -eq 0 ]]; then
container_label_orphan_count="$(
awk 'NF { count += 1 } END { print count + 0 }' <<<"$container_label_readback"
)"
else
container_label_orphan_count=-1
fi
if [[ -e "$workdir" || -L "$workdir" ]]; then if [[ -e "$workdir" || -L "$workdir" ]]; then
outer_workdir_lexists=true outer_workdir_lexists=true
else else
@ -214,6 +260,9 @@ OUTER_CONTAINER_REMOVE_RC="$outer_container_remove_rc" \
OUTER_WORKDIR_REMOVE_RC="$outer_workdir_remove_rc" \ OUTER_WORKDIR_REMOVE_RC="$outer_workdir_remove_rc" \
CONTAINER_NAME_READBACK="$container_name_readback" \ CONTAINER_NAME_READBACK="$container_name_readback" \
CONTAINER_NAME_READBACK_RC="$container_name_readback_rc" \ CONTAINER_NAME_READBACK_RC="$container_name_readback_rc" \
CONTAINER_LABEL_READBACK="$container_label_readback" \
CONTAINER_LABEL_READBACK_RC="$container_label_readback_rc" \
CONTAINER_LABEL_ORPHAN_COUNT="$container_label_orphan_count" \
OUTER_WORKDIR_LEXISTS="$outer_workdir_lexists" \ OUTER_WORKDIR_LEXISTS="$outer_workdir_lexists" \
CANARY_RC="$canary_rc" \ CANARY_RC="$canary_rc" \
SOURCE_TIER="$source_tier" \ SOURCE_TIER="$source_tier" \
@ -221,219 +270,6 @@ SOURCE_NETWORK_MODE="$source_network_mode" \
SOURCE_CANARY_LABEL="$source_canary_label" \ SOURCE_CANARY_LABEL="$source_canary_label" \
CANARY_NETWORK_MODE="$container_network_mode" \ CANARY_NETWORK_MODE="$container_network_mode" \
CANARY_MOUNTS_JSON="$container_mounts_json" \ CANARY_MOUNTS_JSON="$container_mounts_json" \
python3 - "$output" <<'PY' CANARY_LABEL="$container_canary_label" \
import hashlib CANARY_INSTANCE_LABEL="$container_instance_label" \
import json python3 "$repo_root/scripts/finalize_approve_claim_isolated_canary.py" "$output"
import os
import sys
from pathlib import Path
path = Path(sys.argv[1])
if not path.is_file():
raise SystemExit("inner canary did not produce a report")
data = json.loads(path.read_text(encoding="utf-8"))
def service(raw: str) -> dict[str, str]:
return dict(line.split("=", 1) for line in raw.splitlines() if "=" in line)
def table_deltas(before: dict[str, int], after: dict[str, int]) -> dict[str, int]:
if set(before) != set(after):
raise SystemExit(
"live source count keys changed during the canary: "
f"before={sorted(before)} after={sorted(after)}"
)
return {key: after[key] - before[key] for key in sorted(before)}
def verify_source_binding(root: Path, records: list[dict[str, object]]) -> dict[str, object]:
readbacks = []
for record in records:
relative_text = str(record.get("repo_relative_path", ""))
relative = Path(relative_text)
if not relative_text or relative.is_absolute() or ".." in relative.parts:
raise SystemExit(f"unsafe repo-relative source path: {relative_text!r}")
candidate = (root / relative).resolve()
try:
candidate.relative_to(root)
except ValueError as exc:
raise SystemExit(
f"source path escaped repository root: {relative_text}"
) from exc
if not candidate.is_file():
readbacks.append(
{
"repo_relative_path": relative.as_posix(),
"expected_sha256": record.get("sha256"),
"actual_sha256": None,
"matches": False,
}
)
continue
content = candidate.read_bytes()
actual_sha256 = hashlib.sha256(content).hexdigest()
readbacks.append(
{
"repo_relative_path": relative.as_posix(),
"expected_sha256": record.get("sha256"),
"actual_sha256": actual_sha256,
"size_bytes": len(content),
"matches": (
actual_sha256 == record.get("sha256")
and len(content) == record.get("size_bytes")
),
}
)
return {
"files": readbacks,
"all_match": bool(readbacks) and all(row["matches"] for row in readbacks),
}
def contains_ephemeral_path(value: object) -> bool:
if isinstance(value, str):
return "/tmp/" in value
if isinstance(value, dict):
return any(contains_ephemeral_path(item) for item in value.values())
if isinstance(value, list):
return any(contains_ephemeral_path(item) for item in value)
return False
before_counts = json.loads(os.environ["SOURCE_COUNTS_BEFORE"])
after_counts = json.loads(os.environ["SOURCE_COUNTS_AFTER"])
live_table_deltas = table_deltas(before_counts, after_counts)
before_service = service(os.environ["SERVICE_BEFORE"])
after_service = service(os.environ["SERVICE_AFTER"])
source_tier = os.environ["SOURCE_TIER"]
source_network_mode = os.environ["SOURCE_NETWORK_MODE"]
source_canary_label = os.environ["SOURCE_CANARY_LABEL"]
container_network_mode = os.environ["CANARY_NETWORK_MODE"]
container_mounts = json.loads(os.environ["CANARY_MOUNTS_JSON"])
container_volume_mounts = [
mount for mount in container_mounts if mount.get("Type") == "volume"
]
container_isolated = (
container_network_mode == "none" and not container_volume_mounts
)
source_tier_enforced = (
source_tier != "isolated-local"
or (
source_network_mode == "none"
and source_canary_label == "working-leo-approved-source"
)
)
service_observable = (
before_service.get("Available") == "true"
and after_service.get("Available") == "true"
)
service_stable = (
all(
before_service.get(key) == after_service.get(key)
for key in ("ActiveState", "SubState", "MainPID", "NRestarts")
)
if service_observable
else None
)
service_gate_passes = (
service_stable is True
if source_tier == "live-readonly"
else service_stable is not False
)
container_absent = (
int(os.environ["CONTAINER_NAME_READBACK_RC"]) == 0
and not os.environ["CONTAINER_NAME_READBACK"].strip()
)
workdir_absent = os.environ["OUTER_WORKDIR_LEXISTS"] == "false"
source_binding = verify_source_binding(
Path(os.environ["REPO_ROOT"]).resolve(),
data.get("source_binding", {}).get("files", []),
)
data["source_binding"]["independent_post_cleanup_verification"] = source_binding
source_binding_ok = (
data["source_binding"].get("unchanged_during_run") is True
and source_binding["all_match"] is True
)
stale_ephemeral_paths_absent = not contains_ephemeral_path(data)
inner_runtime_pass = data.get("status") == "pass" and int(os.environ["CANARY_RC"]) == 0
outer_ok = (
before_counts == after_counts
and all(delta == 0 for delta in live_table_deltas.values())
and service_gate_passes
and container_absent
and workdir_absent
and source_binding_ok
and stale_ephemeral_paths_absent
and container_isolated
and source_tier_enforced
)
if source_tier == "isolated-local":
data["required_tier"] = "T2_runtime"
data["required_tiers"] = ["T2_runtime"]
data["runtime_scope"] = "isolated_postgres_container_from_readonly_local_fixture"
else:
data["required_tier"] = "T3_live_readonly"
data["required_tiers"] = ["T2_runtime", "T3_live_readonly"]
data["runtime_scope"] = "isolated_postgres_container_from_readonly_live_schema"
data["outer_isolation"] = {
"source_container": os.environ.get("SOURCE_CONTAINER", "teleo-pg"),
"source_database": os.environ.get("SOURCE_DB", "teleo"),
"source_counts_before": before_counts,
"source_counts_after": after_counts,
"canonical_table_deltas": live_table_deltas,
"source_counts_unchanged": before_counts == after_counts,
"service_before": before_service,
"service_after": after_service,
"service_required": source_tier == "live-readonly",
"service_observable": service_observable,
"service_stable": service_stable,
"service_gate_passes": service_gate_passes,
"source_boundary": {
"source_tier": source_tier,
"network_mode": source_network_mode,
"canary_label": source_canary_label,
"tier_enforced": source_tier_enforced,
},
"container_isolation": {
"network_mode": container_network_mode,
"volume_mounts": container_volume_mounts,
"network_disabled": container_network_mode == "none",
"no_docker_volumes": not container_volume_mounts,
},
"cleanup_readback": {
"container_remove_returncode": int(os.environ["OUTER_CONTAINER_REMOVE_RC"]),
"container_name_query_returncode": int(
os.environ["CONTAINER_NAME_READBACK_RC"]
),
"container_name_query_stdout": os.environ["CONTAINER_NAME_READBACK"],
"temporary_container_absent": container_absent,
"workdir_remove_returncode": int(os.environ["OUTER_WORKDIR_REMOVE_RC"]),
"workdir_lexists_after_cleanup": not workdir_absent,
"temporary_workdir_absent": workdir_absent,
},
}
data["checks"]["outer_live_counts_exactly_unchanged"] = before_counts == after_counts
data["checks"]["outer_live_table_deltas_exactly_zero"] = all(
delta == 0 for delta in live_table_deltas.values()
)
data["checks"]["outer_service_observed_if_required"] = (
source_tier != "live-readonly" or service_observable
)
data["checks"]["outer_service_stable_if_observed"] = service_gate_passes
data["checks"]["outer_container_absent_independent_readback"] = container_absent
data["checks"]["outer_workdir_absent_independent_readback"] = workdir_absent
data["checks"]["source_binding_independently_verified"] = source_binding_ok
data["checks"]["stale_ephemeral_paths_absent"] = stale_ephemeral_paths_absent
data["checks"]["outer_source_tier_enforced"] = source_tier_enforced
data["checks"]["outer_container_network_disabled"] = (
container_network_mode == "none"
)
data["checks"]["outer_container_has_no_docker_volumes"] = not container_volume_mounts
data["checks"]["outer_isolation_complete"] = outer_ok
if outer_ok and inner_runtime_pass:
data["current_tier"] = (
"T2_runtime" if source_tier == "isolated-local" else "T3_live_readonly"
)
else:
data["status"] = "fail"
data["current_tier"] = "T2_runtime" if inner_runtime_pass else "T1_model"
path.write_text(json.dumps(data, indent=2, sort_keys=True) + "\n", encoding="utf-8")
raise SystemExit(0 if data["status"] == "pass" else 1)
PY

View file

@ -30,6 +30,10 @@ sys.path.insert(0, str(REPO_ROOT / "scripts"))
import apply_proposal as ap # noqa: E402 import apply_proposal as ap # noqa: E402
CLAIM_A = "aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa"
CLAIM_B = "bbbbbbbb-bbbb-4bbb-8bbb-bbbbbbbbbbbb"
SOURCE_A = "cccccccc-cccc-4ccc-8ccc-cccccccccccc"
def _approval_meta(proposal_type, apply_payload): def _approval_meta(proposal_type, apply_payload):
return { return {
@ -112,7 +116,7 @@ def test_revise_strategy_rejects_bad_node_type():
# --- add_edge ------------------------------------------------------------- # # --- add_edge ------------------------------------------------------------- #
def test_add_edge_sql_dedup_guard(): def test_add_edge_sql_dedup_guard():
payload = {"from_claim": "aaaa", "to_claim": "bbbb", "edge_type": "supersedes", "weight": 0.9} payload = {"from_claim": CLAIM_A, "to_claim": CLAIM_B, "edge_type": "supersedes", "weight": 0.9}
sql = ap.build_add_edge_sql(payload, "pid-2", None, _approval_meta("add_edge", payload)) sql = ap.build_add_edge_sql(payload, "pid-2", None, _approval_meta("add_edge", payload))
assert "insert into public.claim_edges" in sql assert "insert into public.claim_edges" in sql
assert "not exists" in sql assert "not exists" in sql
@ -122,7 +126,7 @@ def test_add_edge_sql_dedup_guard():
def test_add_edge_semantic_row_accepts_match_and_rejects_weight_mismatch(): def test_add_edge_semantic_row_accepts_match_and_rejects_weight_mismatch():
payload = {"from_claim": "aaaa", "to_claim": "bbbb", "edge_type": "supports", "weight": 0.9} payload = {"from_claim": CLAIM_A, "to_claim": CLAIM_B, "edge_type": "supports", "weight": 0.9}
sql = ap.build_add_edge_sql(payload, "pid-2", None, _approval_meta("add_edge", payload)) sql = ap.build_add_edge_sql(payload, "pid-2", None, _approval_meta("add_edge", payload))
verify = sql[sql.index("do $verify$") : sql.index("kb_stage.finish_approved_proposal")] verify = sql[sql.index("do $verify$") : sql.index("kb_stage.finish_approved_proposal")]
@ -131,9 +135,7 @@ def test_add_edge_semantic_row_accepts_match_and_rejects_weight_mismatch():
assert "claim_edge row does not match strict apply payload" in verify assert "claim_edge row does not match strict apply payload" in verify
assert sql.startswith("begin;") assert sql.startswith("begin;")
assert sql.rstrip().endswith("commit;") assert sql.rstrip().endswith("commit;")
assert sql.index("raise exception 'apply_proposal: claim_edge row") < sql.index( assert sql.index("raise exception 'apply_proposal: claim_edge row") < sql.index("kb_stage.finish_approved_proposal")
"kb_stage.finish_approved_proposal"
)
def test_add_edge_rejects_self_loop(): def test_add_edge_rejects_self_loop():
@ -144,7 +146,7 @@ def test_add_edge_rejects_self_loop():
# --- attach_evidence ------------------------------------------------------ # # --- attach_evidence ------------------------------------------------------ #
def test_attach_evidence_sql_with_source_id(): def test_attach_evidence_sql_with_source_id():
payload = {"evidence": [{"claim_id": "cccc", "source_id": "dddd", "role": "grounds", "weight": 0.78}]} payload = {"evidence": [{"claim_id": CLAIM_A, "source_id": SOURCE_A, "role": "grounds", "weight": 0.78}]}
sql = ap.build_attach_evidence_sql(payload, "pid-3", None, _approval_meta("attach_evidence", payload)) sql = ap.build_attach_evidence_sql(payload, "pid-3", None, _approval_meta("attach_evidence", payload))
assert "insert into public.claim_evidence" in sql assert "insert into public.claim_evidence" in sql
assert "::evidence_role" in sql assert "::evidence_role" in sql
@ -152,14 +154,8 @@ def test_attach_evidence_sql_with_source_id():
def test_attach_evidence_semantic_row_accepts_match_and_rejects_weight_mismatch(): def test_attach_evidence_semantic_row_accepts_match_and_rejects_weight_mismatch():
payload = { payload = {"evidence": [{"claim_id": CLAIM_A, "source_id": SOURCE_A, "role": "grounds", "weight": 0.78}]}
"evidence": [ sql = ap.build_attach_evidence_sql(payload, "pid-3", None, _approval_meta("attach_evidence", payload))
{"claim_id": "cccc", "source_id": "dddd", "role": "grounds", "weight": 0.78}
]
}
sql = ap.build_attach_evidence_sql(
payload, "pid-3", None, _approval_meta("attach_evidence", payload)
)
verify = sql[sql.index("do $verify$") : sql.index("kb_stage.finish_approved_proposal")] verify = sql[sql.index("do $verify$") : sql.index("kb_stage.finish_approved_proposal")]
assert "weight is not distinct from 0.78" in verify assert "weight is not distinct from 0.78" in verify
@ -167,9 +163,7 @@ def test_attach_evidence_semantic_row_accepts_match_and_rejects_weight_mismatch(
assert "evidence row % does not match strict apply payload" in verify assert "evidence row % does not match strict apply payload" in verify
assert sql.startswith("begin;") assert sql.startswith("begin;")
assert sql.rstrip().endswith("commit;") assert sql.rstrip().endswith("commit;")
assert sql.index("raise exception 'apply_proposal: evidence row") < sql.index( assert sql.index("raise exception 'apply_proposal: evidence row") < sql.index("kb_stage.finish_approved_proposal")
"kb_stage.finish_approved_proposal"
)
def test_attach_evidence_requires_source_id(): def test_attach_evidence_requires_source_id():
@ -231,9 +225,7 @@ def _approve_claim_bundle():
{"claim_id": claim_a, "source_id": source_a, "role": "grounds", "weight": 0.9}, {"claim_id": claim_a, "source_id": source_a, "role": "grounds", "weight": 0.9},
{"claim_id": claim_b, "source_id": source_b, "role": "illustrates", "weight": None}, {"claim_id": claim_b, "source_id": source_b, "role": "illustrates", "weight": None},
], ],
"edges": [ "edges": [{"from_claim": claim_a, "to_claim": claim_b, "edge_type": "supports", "weight": 0.7}],
{"from_claim": claim_a, "to_claim": claim_b, "edge_type": "supports", "weight": 0.7}
],
"reasoning_tools": [ "reasoning_tools": [
{ {
"id": "eeeeeeee-eeee-4eee-8eee-eeeeeeeeeeee", "id": "eeeeeeee-eeee-4eee-8eee-eeeeeeeeeeee",
@ -291,9 +283,7 @@ def test_approve_claim_semantic_rows_accept_matches_and_reject_payload_mismatche
assert "approve_claim: edge row does not match strict apply payload" in verify assert "approve_claim: edge row does not match strict apply payload" in verify
assert sql.startswith("begin;") assert sql.startswith("begin;")
assert sql.rstrip().endswith("commit;") assert sql.rstrip().endswith("commit;")
assert sql.index("raise exception 'approve_claim: evidence row") < sql.index( assert sql.index("raise exception 'approve_claim: evidence row") < sql.index("kb_stage.finish_approved_proposal")
"kb_stage.finish_approved_proposal"
)
def test_approve_claim_bundle_rejects_duplicate_source_hashes(): def test_approve_claim_bundle_rejects_duplicate_source_hashes():
@ -445,7 +435,7 @@ def test_assert_applyable_allows_approved():
# --- ledger flip: concurrency guard + FK stamp --------------------------- # # --- ledger flip: concurrency guard + FK stamp --------------------------- #
def test_ledger_transition_uses_payload_bound_security_functions(): def test_ledger_transition_uses_payload_bound_security_functions():
payload = {"from_claim": "a", "to_claim": "b", "edge_type": "supports"} payload = {"from_claim": CLAIM_A, "to_claim": CLAIM_B, "edge_type": "supports"}
sql = ap.build_add_edge_sql(payload, "pid", None, _approval_meta("add_edge", payload)) sql = ap.build_add_edge_sql(payload, "pid", None, _approval_meta("add_edge", payload))
assert "kb_stage.assert_approved_proposal" in sql assert "kb_stage.assert_approved_proposal" in sql
assert "kb_stage.finish_approved_proposal" in sql assert "kb_stage.finish_approved_proposal" in sql
@ -459,7 +449,7 @@ def test_ledger_transition_uses_payload_bound_security_functions():
def test_ledger_flip_stamps_agent_fk(): def test_ledger_flip_stamps_agent_fk():
payload = {"from_claim": "a", "to_claim": "b", "edge_type": "supports"} payload = {"from_claim": CLAIM_A, "to_claim": CLAIM_B, "edge_type": "supports"}
sql = ap.build_add_edge_sql(payload, "pid", "kb-apply", _approval_meta("add_edge", payload)) sql = ap.build_add_edge_sql(payload, "pid", "kb-apply", _approval_meta("add_edge", payload))
# Hard resolve into a variable + NOT-NULL assert, never a silent inline # Hard resolve into a variable + NOT-NULL assert, never a silent inline
# subselect that would stamp NULL on an unresolved handle. # subselect that would stamp NULL on an unresolved handle.
@ -468,7 +458,7 @@ def test_ledger_flip_stamps_agent_fk():
def test_build_apply_sql_defaults_applied_by_to_service_agent(): def test_build_apply_sql_defaults_applied_by_to_service_agent():
payload = {"from_claim": "a", "to_claim": "b", "edge_type": "supports"} payload = {"from_claim": CLAIM_A, "to_claim": CLAIM_B, "edge_type": "supports"}
proposal = { proposal = {
"id": "pid", "id": "pid",
"proposal_type": "add_edge", "proposal_type": "add_edge",

View file

@ -6,7 +6,10 @@ standalone (`python3 tests/test_apply_worker.py`).
""" """
import argparse import argparse
import json
import stat
import sys import sys
import tempfile
from pathlib import Path from pathlib import Path
try: try:
@ -40,19 +43,33 @@ sys.path.insert(0, str(REPO_ROOT / "scripts"))
import apply_worker as w # noqa: E402 import apply_worker as w # noqa: E402
@pytest.fixture(autouse=True) def _dependency_restore():
def restore_apply_worker_dependencies():
original_load_password = w.ap.load_password original_load_password = w.ap.load_password
original_load_failure_state = w.load_failure_state original_load_failure_state = w.load_failure_state
original_fetch_candidates = w.fetch_candidates original_fetch_candidates = w.fetch_candidates
original_apply_one = w.apply_one original_apply_one = w.apply_one
original_render_one = w.render_one original_render_one = w.render_one
original_subprocess_run = w.subprocess.run
yield yield
w.ap.load_password = original_load_password w.ap.load_password = original_load_password
w.load_failure_state = original_load_failure_state w.load_failure_state = original_load_failure_state
w.fetch_candidates = original_fetch_candidates w.fetch_candidates = original_fetch_candidates
w.apply_one = original_apply_one w.apply_one = original_apply_one
w.render_one = original_render_one w.render_one = original_render_one
w.subprocess.run = original_subprocess_run
@pytest.fixture(autouse=True)
def restore_apply_worker_dependencies():
restore = _dependency_restore()
next(restore)
try:
yield
finally:
try:
next(restore)
except StopIteration:
pass
# --- candidate query ------------------------------------------------------ # # --- candidate query ------------------------------------------------------ #
@ -116,22 +133,283 @@ def test_render_command_expands_agent_id():
# --- enablement gate ------------------------------------------------------ # # --- enablement gate ------------------------------------------------------ #
def _args(**over): def _args(**over):
base = dict( base = dict(
enable=False, limit=20, max_per_tick=1, max_attempts=3, enable=False,
failure_state_file=None, applied_by="kb-apply", limit=20,
apply_script="apply_proposal.py", render_cmd="", max_per_tick=1,
secrets_file="x", container="teleo-pg", db="teleo", max_attempts=3,
host="127.0.0.1", role="kb_apply", failure_state_file=None,
applied_by="kb-apply",
apply_script="apply_proposal.py",
render_cmd="",
receipt_dir="/private/tmp/kb-apply-worker-test-receipts",
secrets_file="x",
container="teleo-pg",
db="teleo",
host="127.0.0.1",
role="kb_apply",
) )
base.update(over) base.update(over)
return argparse.Namespace(**base) return argparse.Namespace(**base)
def _write_valid_private_receipt(path: Path, proposal_id: str) -> None:
from_claim = "11111111-1111-4111-8111-111111111111"
to_claim = "22222222-2222-4222-8222-222222222222"
proposal = {
"id": proposal_id,
"proposal_type": "add_edge",
"status": "applied",
"payload": {
"apply_payload": {
"from_claim": from_claim,
"to_claim": to_claim,
"edge_type": "supports",
"weight": 0.75,
}
},
"reviewed_by_handle": "reviewer",
"reviewed_by_agent_id": None,
"reviewed_at": "2026-07-15T10:00:00+00:00",
"review_note": "Approved for worker receipt testing.",
"applied_by_handle": "kb-apply",
"applied_by_agent_id": None,
"applied_at": "2026-07-15T10:01:00+00:00",
}
receipt = w.ap.replay_receipt.build_replay_receipt(
proposal,
{
"claim_edges": [
{
"id": "33333333-3333-4333-8333-333333333333",
"from_claim": from_claim,
"to_claim": to_claim,
"edge_type": "supports",
"weight": 0.75,
"created_by": None,
}
]
},
apply_sql_sha256="a" * 64,
apply_sql_source="exact_executed_sql",
exported_at_utc="2026-07-15T10:02:00+00:00",
)
path.parent.mkdir(parents=True, exist_ok=True, mode=0o700)
path.write_text(json.dumps(receipt), encoding="utf-8")
path.chmod(0o600)
def _load_private_receipt(path: Path) -> dict:
return json.loads(path.read_text(encoding="utf-8"))
def _write_private_receipt(path: Path, receipt: dict) -> None:
path.write_text(json.dumps(receipt), encoding="utf-8")
path.chmod(0o600)
def _completed(returncode: int, *, stdout: str = "", stderr: str = ""):
return w.subprocess.CompletedProcess([], returncode, stdout=stdout, stderr=stderr)
def _postcommit_receipt_failure(proposal_id: str, detail: str = "receipt write failed") -> str:
return (
f"proposal {proposal_id} {w.POSTCOMMIT_RECEIPT_FAILURE_MARKER}: {detail}"
f"{w.POSTCOMMIT_RECEIPT_RECOVERY_MARKER}"
f"apply_proposal.py {proposal_id} --receipt-only"
)
# --- private receipt and post-COMMIT recovery ---------------------------- #
def test_private_receipt_requires_complete_canonical_rows_and_hashes():
proposal_id = "99999999-9999-4999-8999-999999999999"
receipt_path = Path(tempfile.mkdtemp()) / "receipt.json"
_write_valid_private_receipt(receipt_path, proposal_id)
missing_rows = _load_private_receipt(receipt_path)
missing_rows.pop("canonical_rows")
_write_private_receipt(receipt_path, missing_rows)
with pytest.raises(RuntimeError, match="row-level contract is invalid"):
w.assert_private_replay_receipt(receipt_path, proposal_id)
_write_valid_private_receipt(receipt_path, proposal_id)
missing_hashes = _load_private_receipt(receipt_path)
missing_hashes.pop("hashes")
_write_private_receipt(receipt_path, missing_hashes)
with pytest.raises(RuntimeError, match="row-level contract is invalid"):
w.assert_private_replay_receipt(receipt_path, proposal_id)
def test_private_receipt_rejects_canonical_row_tampering_without_recomputed_hashes():
proposal_id = "88888888-8888-4888-8888-888888888888"
receipt_path = Path(tempfile.mkdtemp()) / "receipt.json"
_write_valid_private_receipt(receipt_path, proposal_id)
tampered = _load_private_receipt(receipt_path)
tampered["canonical_rows"]["claim_edges"][0]["weight"] = 0.5
_write_private_receipt(receipt_path, tampered)
with pytest.raises(RuntimeError, match="row-level contract is invalid|internally inconsistent"):
w.assert_private_replay_receipt(receipt_path, proposal_id)
def test_apply_one_supplies_deterministic_private_receipt_path():
proposal_id = "aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa"
receipt_dir = Path(tempfile.mkdtemp()) / "receipts"
calls = []
def _run(cmd, **_kwargs):
calls.append(cmd)
receipt_path = Path(cmd[cmd.index("--receipt-out") + 1])
_write_valid_private_receipt(receipt_path, proposal_id)
return _completed(0, stdout='{"applied": true}')
w.subprocess.run = _run
w.apply_one(_args(receipt_dir=str(receipt_dir)), proposal_id)
expected = receipt_dir.resolve() / f"{proposal_id}.json"
assert len(calls) == 1
assert calls[0][calls[0].index("--receipt-dir") + 1] == str(expected.parent)
assert calls[0][calls[0].index("--receipt-out") + 1] == str(expected)
assert stat.S_IMODE(expected.stat().st_mode) == 0o600
def test_apply_one_recovers_postcommit_receipt_failure_without_reapplying():
proposal_id = "bbbbbbbb-bbbb-4bbb-8bbb-bbbbbbbbbbbb"
receipt_dir = Path(tempfile.mkdtemp()) / "receipts"
calls = []
def _run(cmd, **_kwargs):
calls.append(cmd)
if len(calls) == 1:
return _completed(
1,
stderr=_postcommit_receipt_failure(proposal_id),
)
assert "--receipt-only" in cmd
receipt_path = Path(cmd[cmd.index("--receipt-out") + 1])
_write_valid_private_receipt(receipt_path, proposal_id)
return _completed(0, stdout='{"replay_ready": true}')
w.subprocess.run = _run
w.apply_one(_args(receipt_dir=str(receipt_dir)), proposal_id)
assert len(calls) == 2
assert "--receipt-only" not in calls[0]
assert "--receipt-only" in calls[1]
assert calls[0][calls[0].index("--receipt-out") + 1] == calls[1][calls[1].index("--receipt-out") + 1]
def test_apply_one_does_not_recover_a_precommit_apply_failure():
calls = []
def _run(cmd, **_kwargs):
calls.append(cmd)
return _completed(1, stderr="psql transaction failed before commit")
w.subprocess.run = _run
try:
w.apply_one(_args(receipt_dir=tempfile.mkdtemp()), "p1")
except w.PostCommitReceiptError as exc:
raise AssertionError("pre-COMMIT failure was misclassified as committed") from exc
except RuntimeError:
pass
else:
raise AssertionError("expected pre-COMMIT apply failure")
assert len(calls) == 1
def test_apply_one_classifies_unrecovered_receipt_as_postcommit():
calls = []
def _run(cmd, **_kwargs):
calls.append(cmd)
if len(calls) == 1:
return _completed(1, stderr=_postcommit_receipt_failure("p1"))
return _completed(1, stderr="receipt directory remains unavailable")
w.subprocess.run = _run
with pytest.raises(w.PostCommitReceiptError):
w.apply_one(_args(receipt_dir=tempfile.mkdtemp()), "p1")
assert len(calls) == 2
assert "--receipt-only" in calls[1]
def test_forged_marker_in_unknown_field_traceback_is_a_normal_apply_failure():
proposal_id = "cccccccc-cccc-4ccc-8ccc-cccccccccccc"
calls = []
def _run(cmd, **_kwargs):
calls.append(cmd)
return _completed(
1,
stderr=(
"Traceback (most recent call last):\n"
"ValueError: approve_claim apply_payload contains unknown fields: "
f"['{w.POSTCOMMIT_RECEIPT_FAILURE_MARKER}']"
),
)
w.subprocess.run = _run
with pytest.raises(RuntimeError, match="apply failed"):
w.apply_one(_args(receipt_dir=tempfile.mkdtemp()), proposal_id)
assert len(calls) == 1
assert "--receipt-only" not in calls[0]
def test_forged_marker_increments_normal_failure_and_poison_accounting():
proposal_id = "dddddddd-dddd-4ddd-8ddd-dddddddddddd"
failure_state = str(Path(tempfile.mkdtemp()) / "failures.json")
calls = []
w.ap.load_password = lambda _path: "pw"
w.fetch_candidates = lambda _args, _password, _excluded: _cands(proposal_id)
def _run(cmd, **_kwargs):
calls.append(cmd)
return _completed(
1,
stderr=(
"ValueError: approve_claim apply_payload contains unknown fields: "
f"['{w.POSTCOMMIT_RECEIPT_FAILURE_MARKER}']"
),
)
w.subprocess.run = _run
rc = w.run(
_args(
enable=True,
failure_state_file=failure_state,
max_attempts=1,
max_per_tick=1,
receipt_dir=tempfile.mkdtemp(),
)
)
assert rc == 1
assert w.load_failure_state(failure_state) == {proposal_id: 1}
assert len(calls) == 1
def test_postcommit_receipt_error_does_not_increment_apply_failure_count():
path = str(Path(tempfile.mkdtemp()) / "failures.json")
w.ap.load_password = lambda _f: "pw"
w.fetch_candidates = lambda a, p, excluded: _cands("committed")
def _postcommit(_args, _proposal_id):
raise w.PostCommitReceiptError("committed; receipt recovery failed")
w.apply_one = _postcommit
rc = w.run(_args(enable=True, failure_state_file=path, max_per_tick=1))
assert rc == 1
assert w.load_failure_state(path) == {}
def test_report_only_gate_does_not_apply(monkeypatch=None): def test_report_only_gate_does_not_apply(monkeypatch=None):
calls = [] calls = []
w.ap.load_password = lambda _f: "pw" w.ap.load_password = lambda _f: "pw"
w.fetch_candidates = lambda a, p, excluded: [ w.fetch_candidates = lambda a, p, excluded: [{"id": "p1", "proposal_type": "revise_strategy", "agent_id": "ag"}]
{"id": "p1", "proposal_type": "revise_strategy", "agent_id": "ag"}
]
w.apply_one = lambda a, pid: calls.append(pid) w.apply_one = lambda a, pid: calls.append(pid)
rc = w.run(_args(enable=False)) rc = w.run(_args(enable=False))
@ -142,9 +420,7 @@ def test_report_only_gate_does_not_apply(monkeypatch=None):
def test_enabled_worker_applies_and_renders(): def test_enabled_worker_applies_and_renders():
applied, rendered = [], [] applied, rendered = [], []
w.ap.load_password = lambda _f: "pw" w.ap.load_password = lambda _f: "pw"
w.fetch_candidates = lambda a, p, excluded: [ w.fetch_candidates = lambda a, p, excluded: [{"id": "p1", "proposal_type": "revise_strategy", "agent_id": "ag"}]
{"id": "p1", "proposal_type": "revise_strategy", "agent_id": "ag"}
]
w.apply_one = lambda a, pid: applied.append(pid) w.apply_one = lambda a, pid: applied.append(pid)
w.render_one = lambda a, agent_id: rendered.append(agent_id) or "ok" w.render_one = lambda a, agent_id: rendered.append(agent_id) or "ok"
@ -157,9 +433,7 @@ def test_enabled_worker_applies_and_renders():
def test_enabled_worker_skips_render_for_add_edge(): def test_enabled_worker_skips_render_for_add_edge():
applied, rendered = [], [] applied, rendered = [], []
w.ap.load_password = lambda _f: "pw" w.ap.load_password = lambda _f: "pw"
w.fetch_candidates = lambda a, p, excluded: [ w.fetch_candidates = lambda a, p, excluded: [{"id": "e1", "proposal_type": "add_edge", "agent_id": None}]
{"id": "e1", "proposal_type": "add_edge", "agent_id": None}
]
w.apply_one = lambda a, pid: applied.append(pid) w.apply_one = lambda a, pid: applied.append(pid)
w.render_one = lambda a, agent_id: rendered.append(agent_id) or "ok" w.render_one = lambda a, agent_id: rendered.append(agent_id) or "ok"
@ -172,9 +446,7 @@ def test_enabled_worker_skips_render_for_add_edge():
def test_enabled_worker_skips_render_for_approve_claim(): def test_enabled_worker_skips_render_for_approve_claim():
applied, rendered = [], [] applied, rendered = [], []
w.ap.load_password = lambda _f: "pw" w.ap.load_password = lambda _f: "pw"
w.fetch_candidates = lambda a, p, excluded: [ w.fetch_candidates = lambda a, p, excluded: [{"id": "c1", "proposal_type": "approve_claim", "agent_id": "ag"}]
{"id": "c1", "proposal_type": "approve_claim", "agent_id": "ag"}
]
w.apply_one = lambda a, pid: applied.append(pid) w.apply_one = lambda a, pid: applied.append(pid)
w.render_one = lambda a, agent_id: rendered.append(agent_id) or "ok" w.render_one = lambda a, agent_id: rendered.append(agent_id) or "ok"
@ -263,7 +535,7 @@ if __name__ == "__main__":
failures = 0 failures = 0
for name, fn in sorted(globals().items()): for name, fn in sorted(globals().items()):
if name.startswith("test_") and callable(fn): if name.startswith("test_") and callable(fn):
restore = restore_apply_worker_dependencies() restore = _dependency_restore()
next(restore) next(restore)
try: try:
fn() fn()

View file

@ -0,0 +1,846 @@
"""Deterministic and property-based tests for proposal apply rollback evidence."""
from __future__ import annotations
import copy
import hashlib
import json
import string
import sys
from datetime import datetime, timezone
from pathlib import Path
import pytest
from hypothesis import given, settings
from hypothesis import strategies as st
REPO_ROOT = Path(__file__).resolve().parents[1]
sys.path.insert(0, str(REPO_ROOT / "scripts"))
import apply_proposal as apply # noqa: E402
import proposal_apply_lifecycle as lifecycle # noqa: E402
PROPOSAL_ID = "99999999-9999-4999-8999-999999999999"
CLAIM_A = "aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa"
CLAIM_B = "bbbbbbbb-bbbb-4bbb-8bbb-bbbbbbbbbbbb"
SOURCE_ID = "cccccccc-cccc-4ccc-8ccc-cccccccccccc"
TOOL_ID = "dddddddd-dddd-4ddd-8ddd-dddddddddddd"
AGENT_ID = "11111111-1111-4111-8111-111111111111"
APPLIED_AT = "2026-07-15T10:15:00+00:00"
REVIEWED_AT = "2026-07-15T09:30:00+00:00"
ROW_FAMILIES = tuple(lifecycle.ROW_TABLES)
def _apply_payload() -> dict:
return {
"contract_version": 2,
"agent_id": AGENT_ID,
"claims": [
{
"id": CLAIM_A,
"type": "structural",
"text": "Canonical claim A",
"status": "open",
"confidence": 0.8,
"tags": ["working-leo", "lifecycle"],
"created_by": AGENT_ID,
},
{
"id": CLAIM_B,
"type": "concept",
"text": "Canonical claim B",
"status": "open",
"confidence": None,
"tags": [],
"created_by": AGENT_ID,
},
],
"sources": [
{
"id": SOURCE_ID,
"source_type": "paper",
"url": "https://example.test/lifecycle",
"storage_path": None,
"excerpt": "Bound lifecycle evidence.",
"hash": "sha256:lifecycle-source",
"created_by": AGENT_ID,
}
],
"evidence": [
{
"claim_id": CLAIM_A,
"source_id": SOURCE_ID,
"role": "grounds",
"weight": 0.9,
"created_by": AGENT_ID,
}
],
"edges": [
{
"from_claim": CLAIM_A,
"to_claim": CLAIM_B,
"edge_type": "supports",
"weight": 0.7,
"created_by": AGENT_ID,
}
],
"reasoning_tools": [
{
"id": TOOL_ID,
"agent_id": AGENT_ID,
"name": "Lifecycle verifier",
"description": "Checks the apply and compensating rollback boundary.",
"category": "verification",
}
],
}
def _proposal_before() -> dict:
return {
"id": PROPOSAL_ID,
"proposal_type": "approve_claim",
"status": "approved",
"payload": {"apply_payload": _apply_payload()},
"reviewed_by_handle": "independent-reviewer",
"reviewed_by_agent_id": None,
"reviewed_at": REVIEWED_AT,
"review_note": "Approved this exact strict payload.",
"applied_by_handle": None,
"applied_by_agent_id": None,
"applied_at": None,
}
def _approval_snapshot(proposal: dict) -> dict:
return {
"proposal_id": proposal["id"],
"proposal_type": proposal["proposal_type"],
"payload": copy.deepcopy(proposal["payload"]),
"reviewed_by_handle": proposal["reviewed_by_handle"],
"reviewed_by_agent_id": proposal["reviewed_by_agent_id"],
"reviewed_by_db_role": "kb_reviewer",
"reviewed_at": proposal["reviewed_at"],
"review_note": proposal["review_note"],
}
def _canonical_rows() -> dict[str, list[dict]]:
evidence_id = apply.deterministic_row_uuid(PROPOSAL_ID, "claim_evidence", CLAIM_A, SOURCE_ID, "grounds")
edge_id = apply.deterministic_row_uuid(PROPOSAL_ID, "claim_edge", CLAIM_A, CLAIM_B, "supports")
return {
"claims": [
{
"id": CLAIM_A,
"type": "structural",
"text": "Canonical claim A",
"status": "open",
"confidence": 0.8,
"tags": ["working-leo", "lifecycle"],
"created_by": AGENT_ID,
"superseded_by": None,
"created_at": APPLIED_AT,
"updated_at": APPLIED_AT,
},
{
"id": CLAIM_B,
"type": "concept",
"text": "Canonical claim B",
"status": "open",
"confidence": None,
"tags": [],
"created_by": AGENT_ID,
"superseded_by": None,
"created_at": APPLIED_AT,
"updated_at": APPLIED_AT,
},
],
"sources": [
{
"id": SOURCE_ID,
"source_type": "paper",
"url": "https://example.test/lifecycle",
"storage_path": None,
"excerpt": "Bound lifecycle evidence.",
"hash": "sha256:lifecycle-source",
"created_by": AGENT_ID,
"created_at": APPLIED_AT,
}
],
"claim_evidence": [
{
"id": evidence_id,
"claim_id": CLAIM_A,
"source_id": SOURCE_ID,
"role": "grounds",
"weight": 0.9,
"created_by": AGENT_ID,
"created_at": APPLIED_AT,
}
],
"claim_edges": [
{
"id": edge_id,
"from_claim": CLAIM_A,
"to_claim": CLAIM_B,
"edge_type": "supports",
"weight": 0.7,
"created_by": AGENT_ID,
"created_at": APPLIED_AT,
}
],
"reasoning_tools": [
{
"id": TOOL_ID,
"agent_id": AGENT_ID,
"name": "Lifecycle verifier",
"description": "Checks the apply and compensating rollback boundary.",
"category": "verification",
"created_at": APPLIED_AT,
"updated_at": APPLIED_AT,
}
],
}
def _empty_targets() -> dict[str, list[dict]]:
return {family: [] for family in ROW_FAMILIES}
def _apply_receipt(proposal: dict, rows: dict[str, list[dict]]) -> dict:
applied = copy.deepcopy(proposal)
applied.update(
{
"status": "applied",
"applied_by_handle": apply.SERVICE_AGENT_HANDLE,
"applied_by_agent_id": AGENT_ID,
"applied_at": APPLIED_AT,
}
)
apply_sql = apply.build_apply_sql(proposal, apply.SERVICE_AGENT_HANDLE)
return apply.replay_receipt.build_replay_receipt(
applied,
copy.deepcopy(rows),
apply_sql_sha256=lifecycle.sha256_text(apply_sql),
apply_sql_source="exact_executed_sql",
exported_at_utc="2026-07-15T10:16:00+00:00",
)
def _materials() -> tuple[dict, dict, dict, dict, str]:
proposal = _proposal_before()
approval = _approval_snapshot(proposal)
preflight = lifecycle.build_fresh_preflight(
proposal,
_empty_targets(),
captured_at_utc="2026-07-15T10:00:00+00:00",
)
receipt = _apply_receipt(proposal, _canonical_rows())
rollback_sql = lifecycle.build_compensating_rollback_sql(proposal, approval, preflight, receipt)
return proposal, approval, preflight, receipt, rollback_sql
def _passing_lifecycle_receipt() -> dict:
proposal, approval, preflight, receipt, rollback_sql = _materials()
proposal_after = copy.deepcopy(proposal)
return lifecycle.build_lifecycle_receipt(
proposal_before=proposal,
approval_before=approval,
preflight=preflight,
apply_receipt=receipt,
rollback_sql=rollback_sql,
proposal_after=proposal_after,
approval_after=copy.deepcopy(approval),
target_rows_after=_empty_targets(),
counts_before={family: 7 + index for index, family in enumerate(ROW_FAMILIES)},
counts_after={family: 7 + index for index, family in enumerate(ROW_FAMILIES)},
unrelated_before={"fingerprint": "same", "row_count": 17},
unrelated_after={"fingerprint": "same", "row_count": 17},
rollback_replay_refused=True,
generated_at_utc="2026-07-15T10:30:00+00:00",
)
def _destination(*, candidate_present: bool = True) -> dict:
lifecycle_receipt = _passing_lifecycle_receipt()
candidates = []
if candidate_present:
candidates.append(
{
"id": PROPOSAL_ID,
"proposal_type": "approve_claim",
"status": "approved",
"applied_at": None,
"proposal_payload_sha256": lifecycle_receipt["proposal_payload_sha256"],
"apply_payload_sha256": lifecycle_receipt["apply_payload_sha256"],
"approval_snapshot_sha256": lifecycle_receipt["approval_snapshot_sha256"],
"reviewed_by_handle": "independent-reviewer",
"reviewed_by_agent_id": None,
"reviewed_at": REVIEWED_AT,
"review_note": "Approved this exact strict payload.",
"immutable_approval_exact": True,
}
)
return {
"observed_at_utc": "2026-07-15T10:45:00+00:00",
"read_only_transaction": True,
"container": "teleo-pg",
"database": "teleo",
"system_identifier": "7649789040005668902",
"server_version_num": "160014",
"approval_gate": {
"immutable_approval_table_present": True,
"approve_function_present": True,
"assert_function_present": True,
"finish_function_present": True,
"review_role_present": True,
"apply_role_present": True,
},
"approved_strict_candidates": candidates,
}
def _authorization_materials() -> tuple[dict, dict, dict, dict]:
proposal, approval, preflight, apply_receipt, _production_rollback_sql = _materials()
receipt = _passing_lifecycle_receipt()
destination = _destination()
destination_identity = {
key: destination[key] for key in ("container", "database", "system_identifier", "server_version_num")
}
production_rollback_artifact = lifecycle.build_production_rollback_artifact(
proposal_before=proposal,
approval_snapshot=approval,
preflight=preflight,
apply_receipt=apply_receipt,
destination=destination_identity,
generated_at_utc="2026-07-15T10:49:00+00:00",
)
packet = lifecycle.build_authorization_packet(
receipt,
destination,
repo_git_sha=lifecycle.current_git_sha(REPO_ROOT),
apply_engine_path=REPO_ROOT / "scripts" / "apply_proposal.py",
production_rollback_artifact=production_rollback_artifact,
generated_at_utc="2026-07-15T10:50:00+00:00",
)
record = {
"authorized": True,
"rollback_authorized": True,
"binding_sha256": packet["binding_sha256"],
"production_rollback_sql_sha256": production_rollback_artifact["rollback_sql_sha256"],
"operator_identity": "release-operator@example.test",
"received_at_utc": "2026-07-15T11:00:00+00:00",
"expires_at_utc": "2026-07-15T13:00:00+00:00",
}
record["authorization_text"] = lifecycle.expected_authorization_text(packet, record)
destination["observed_at_utc"] = "2026-07-15T11:30:00+00:00"
return packet, record, destination, production_rollback_artifact
def test_fresh_preflight_requires_every_owned_target_to_be_absent_and_is_deterministic():
proposal = _proposal_before()
first = lifecycle.build_fresh_preflight(
proposal,
_empty_targets(),
captured_at_utc="2026-07-15T10:00:00+00:00",
)
second = lifecycle.build_fresh_preflight(
proposal,
_empty_targets(),
captured_at_utc="2026-07-15T10:01:00+00:00",
)
assert first["fresh_owned_targets"] is True
assert first["preflight_sha256"] == second["preflight_sha256"]
assert first["preflight_artifact_sha256"] != second["preflight_artifact_sha256"]
assert first["captured_at_utc"] != second["captured_at_utc"]
nonfresh = _empty_targets()
nonfresh["claims"] = [{"id": CLAIM_A}]
with pytest.raises(ValueError, match="absent target rows"):
lifecycle.build_fresh_preflight(proposal, nonfresh)
incomplete = _empty_targets()
incomplete.pop("claim_edges")
with pytest.raises(ValueError, match="every approve_claim target table"):
lifecycle.build_fresh_preflight(proposal, incomplete)
@pytest.mark.parametrize(
"mutation",
(
"artifact",
"schema",
"captured_at_utc",
"proposal_id",
"proposal_payload_sha256",
"apply_payload_sha256",
"target_family_missing",
"target_row_present",
"fresh_flag_type",
"state_hash",
"artifact_hash",
"extra_field",
),
)
def test_rollback_refuses_every_preflight_contract_mutation(mutation: str):
proposal, approval, preflight, receipt, _rollback_sql = _materials()
changed = copy.deepcopy(preflight)
if mutation == "artifact":
changed["artifact"] = "proposal_apply_fresh_preflight_tampered"
elif mutation == "schema":
changed["schema"] = "livingip.proposalApplyFreshPreflight.v0"
elif mutation == "captured_at_utc":
changed["captured_at_utc"] = "2026-07-15T10:00:01+00:00"
elif mutation == "proposal_id":
changed["proposal_id"] = CLAIM_A
elif mutation == "proposal_payload_sha256":
changed["proposal_payload_sha256"] = "0" * 64
elif mutation == "apply_payload_sha256":
changed["apply_payload_sha256"] = "0" * 64
elif mutation == "target_family_missing":
changed["target_rows_before"].pop("claim_edges")
elif mutation == "target_row_present":
changed["target_rows_before"]["claims"] = [{"id": CLAIM_A}]
elif mutation == "fresh_flag_type":
changed["fresh_owned_targets"] = 1
elif mutation == "state_hash":
changed["preflight_sha256"] = "0" * 64
elif mutation == "artifact_hash":
changed["preflight_artifact_sha256"] = "0" * 64
else:
changed["unexpected"] = True
with pytest.raises(ValueError):
lifecycle.build_compensating_rollback_sql(proposal, approval, changed, receipt)
def test_compensating_rollback_is_atomic_deterministic_and_refuses_state_drift():
proposal, approval, preflight, receipt, rollback_sql = _materials()
assert rollback_sql == lifecycle.build_compensating_rollback_sql(proposal, approval, preflight, receipt)
assert rollback_sql.startswith("begin;")
assert rollback_sql.rstrip().endswith("commit;")
assert "proposal rollback drift:" in rollback_sql
assert "to_jsonb(t)" in rollback_sql
assert rollback_sql.index("proposal rollback drift:") < rollback_sql.index("delete from public.claim_evidence")
delete_positions = [
rollback_sql.index(f"delete from {lifecycle.ROW_TABLES[family]}") for family in lifecycle.DELETE_ORDER
]
assert delete_positions == sorted(delete_positions)
assert "set status = 'approved'" in rollback_sql
assert "immutable approval snapshot drifted" in rollback_sql
drifted_receipt = copy.deepcopy(receipt)
drifted_receipt["proposal"]["payload"]["apply_payload"]["claims"][0]["text"] = "drift"
with pytest.raises(ValueError, match="payload does not match preflight"):
lifecycle.build_compensating_rollback_sql(proposal, approval, preflight, drifted_receipt)
@given(
suffix=st.text(
alphabet=string.ascii_letters + string.digits + " -_",
min_size=1,
max_size=32,
)
)
@settings(max_examples=30, deadline=None)
def test_rollback_refuses_any_canonical_row_tampering_without_rebuilt_receipt(suffix: str):
proposal, approval, preflight, receipt, _rollback_sql = _materials()
changed = copy.deepcopy(receipt)
changed["canonical_rows"]["claims"][0]["text"] = f"mutated:{suffix}"
with pytest.raises(ValueError, match="replay-contract validation"):
lifecycle.build_compensating_rollback_sql(proposal, approval, preflight, changed)
@pytest.mark.parametrize(
"mutation",
("contract_bool", "expected_count_bool", "actual_count_float", "check_integer"),
)
def test_replay_receipt_json_types_are_exact_not_python_equal(mutation: str):
proposal, approval, preflight, receipt, _rollback_sql = _materials()
changed = copy.deepcopy(receipt)
if mutation == "contract_bool":
changed["receipt_contract_version"] = True
elif mutation == "expected_count_bool":
changed["expected_row_counts"]["sources"] = True
elif mutation == "actual_count_float":
changed["actual_row_counts"]["sources"] = 1.0
else:
changed["checks"]["proposal_applied"] = 1
with pytest.raises(ValueError, match="replay-contract validation"):
lifecycle.build_compensating_rollback_sql(proposal, approval, preflight, changed)
def test_rollback_sql_hash_binds_every_receipt_observed_field():
proposal, approval, preflight, receipt, rollback_sql = _materials()
changed_rows = copy.deepcopy(receipt["canonical_rows"])
changed_rows["claims"][0]["created_at"] = "2026-07-15T10:15:00.123456+00:00"
changed_receipt = _apply_receipt(proposal, changed_rows)
changed_sql = lifecycle.build_compensating_rollback_sql(
proposal,
approval,
preflight,
changed_receipt,
)
assert lifecycle.sha256_text(changed_sql) != lifecycle.sha256_text(rollback_sql)
assert "to_jsonb(t)" in changed_sql
assert "proposal rollback drift: claims[0] row does not match apply receipt" in changed_sql
@pytest.mark.parametrize("family", ("claim_evidence", "claim_edges"))
def test_fresh_apply_receipt_requires_deterministic_generated_row_ids(family: str):
proposal, approval, preflight, receipt, _rollback_sql = _materials()
changed_rows = copy.deepcopy(receipt["canonical_rows"])
changed_rows[family][0]["id"] = "eeeeeeee-eeee-4eee-8eee-eeeeeeeeeeee"
changed_receipt = _apply_receipt(proposal, changed_rows)
with pytest.raises(ValueError, match="is not deterministic"):
lifecycle.build_compensating_rollback_sql(
proposal,
approval,
preflight,
changed_receipt,
)
def test_production_rollback_artifact_reconstructs_exact_sql_and_rejects_noop_substitution():
proposal, approval, preflight, apply_receipt, rollback_sql = _materials()
destination = {
"container": "teleo-pg",
"database": "teleo",
"system_identifier": "7649789040005668902",
"server_version_num": "160014",
}
artifact = lifecycle.build_production_rollback_artifact(
proposal_before=proposal,
approval_snapshot=approval,
preflight=preflight,
apply_receipt=apply_receipt,
destination=destination,
generated_at_utc="2026-07-15T10:49:00+00:00",
)
assert (
lifecycle.validate_production_rollback_artifact(
artifact,
expected_destination=destination,
)
== artifact
)
assert artifact["rollback_sql"] == rollback_sql
noop = copy.deepcopy(artifact)
noop["rollback_sql"] = (
"begin; -- proposal rollback drift: -- immutable approval snapshot drifted "
"-- set status = 'approved'\ncommit;\n"
)
noop["rollback_sql_sha256"] = lifecycle.sha256_text(noop["rollback_sql"])
unsigned = dict(noop)
unsigned.pop("artifact_sha256")
noop["artifact_sha256"] = lifecycle.sha256_json(unsigned)
with pytest.raises(ValueError, match="reconstructed exact SQL"):
lifecycle.validate_production_rollback_artifact(noop, expected_destination=destination)
def test_lifecycle_receipt_proves_inverse_and_has_self_consistent_hashes():
receipt = _passing_lifecycle_receipt()
unsigned = dict(receipt)
receipt_hash = unsigned.pop("lifecycle_receipt_sha256")
assert receipt["pass"] is True
assert receipt["current_tier"] == "T2_runtime"
assert all(receipt["checks"].values())
assert all(not rows for rows in receipt["rollback"]["target_rows_after"].values())
assert receipt["rollback"]["counts_after_rollback"] == receipt["rollback"]["counts_before_apply"]
assert receipt["production_apply_executed"] is False
assert receipt["production_apply_authorization_present"] is False
assert receipt_hash == lifecycle.sha256_json(unsigned)
def test_lifecycle_receipt_downgrades_when_unrelated_state_changes():
proposal, approval, preflight, receipt, rollback_sql = _materials()
result = lifecycle.build_lifecycle_receipt(
proposal_before=proposal,
approval_before=approval,
preflight=preflight,
apply_receipt=receipt,
rollback_sql=rollback_sql,
proposal_after=copy.deepcopy(proposal),
approval_after=copy.deepcopy(approval),
target_rows_after=_empty_targets(),
counts_before={family: 1 for family in ROW_FAMILIES},
counts_after={family: 1 for family in ROW_FAMILIES},
unrelated_before={"fingerprint": "before"},
unrelated_after={"fingerprint": "after"},
rollback_replay_refused=True,
)
assert result["pass"] is False
assert result["current_tier"] == "T1_model"
assert result["checks"]["unrelated_rows_unchanged"] is False
def test_retained_current_lifecycle_evidence_is_self_consistent():
report_dir = REPO_ROOT / "docs" / "reports" / "leo-working-state-20260709"
canary = json.loads((report_dir / "proposal-apply-lifecycle-canary-current.json").read_text(encoding="utf-8"))
receipt = json.loads((report_dir / "proposal-apply-lifecycle-receipt-current.json").read_text(encoding="utf-8"))
rollback = (report_dir / "proposal-apply-clone-rollback-current.sql").read_text(encoding="utf-8")
unsigned = dict(receipt)
receipt_sha256 = unsigned.pop("lifecycle_receipt_sha256")
assert canary["status"] == "pass"
assert canary["current_tier"] == "T2_runtime"
assert canary["applied_rollback_receipt"] == receipt
assert canary["outer_isolation"]["cleanup_readback"]["label_scoped_orphan_count"] == 0
assert all(delta == 0 for delta in canary["outer_isolation"]["canonical_table_deltas"].values())
assert receipt["pass"] is True
assert receipt["production_apply_executed"] is False
assert receipt_sha256 == lifecycle.sha256_json(unsigned)
assert hashlib.sha256(rollback.encode("utf-8")).hexdigest() == receipt["rollback"]["rollback_sql_sha256"]
def test_authorization_packet_is_exact_but_never_self_authorizes_production():
packet, record, destination, production_rollback_artifact = _authorization_materials()
verification = lifecycle.verify_authorization_record(
packet,
record,
observed_destination=destination,
apply_engine_path=REPO_ROOT / "scripts" / "apply_proposal.py",
production_rollback_artifact=production_rollback_artifact,
now=datetime(2026, 7, 15, 12, 0, tzinfo=timezone.utc),
)
assert packet["required_tier"] == "T6_authorized_production"
assert packet["current_tier"] == "T3_live_readonly"
assert packet["safe_to_enter_apply_window"] is False
assert packet["production_apply_authorization_present"] is False
assert packet["production_apply_executed"] is False
assert verification["safe_to_enter_apply_window"] is True
assert verification["production_apply_executed"] is False
assert all(verification["checks"].values())
def test_authorization_packet_names_missing_live_gate_before_requesting_auth(tmp_path):
receipt = _passing_lifecycle_receipt()
destination = _destination(candidate_present=False)
destination["approval_gate"] = {key: False for key in destination["approval_gate"]}
packet = lifecycle.build_authorization_packet(
receipt,
destination,
repo_git_sha=lifecycle.current_git_sha(REPO_ROOT),
apply_engine_path=REPO_ROOT / "scripts" / "apply_proposal.py",
)
markdown_path = tmp_path / "authorization.md"
lifecycle.write_authorization_markdown(markdown_path, packet)
assert packet["production_preconditions"]["approval_gate_ready"] is False
assert packet["production_preconditions"]["matching_candidate_count"] == 0
assert packet["production_preconditions"]["exact_production_rollback_packet_ready"] is False
assert packet["binding"]["production_rollback"]["rollback_sql_sha256"] is None
assert lifecycle.sha256_json(packet["binding"]) == packet["binding_sha256"]
assert packet["safe_to_enter_apply_window"] is False
assert packet["production_apply_authorization_present"] is False
assert packet["production_apply_executed"] is False
assert packet["next_exact_action"].startswith("deploy and independently verify")
assert "This text is not actionable" in markdown_path.read_text(encoding="utf-8")
@given(value=st.sampled_from([False, None, 0, 1, "true", "yes", [], {}]))
@settings(max_examples=8, deadline=None)
def test_authorized_field_requires_the_exact_boolean_true(value):
packet, record, destination, production_rollback_artifact = _authorization_materials()
record["authorized"] = value
record["authorization_text"] = lifecycle.expected_authorization_text(packet, record)
verification = lifecycle.verify_authorization_record(
packet,
record,
observed_destination=destination,
apply_engine_path=REPO_ROOT / "scripts" / "apply_proposal.py",
production_rollback_artifact=production_rollback_artifact,
now=datetime(2026, 7, 15, 12, 0, tzinfo=timezone.utc),
)
assert verification["checks"]["authorized_is_exact_true"] is False
assert verification["safe_to_enter_apply_window"] is False
AUTHORIZATION_MUTATIONS = (
"packet_schema",
"packet_readonly",
"approval_gate_packet",
"production_rollback_packet",
"strict_candidate",
"rollback_authorized",
"production_rollback_sha256",
"binding_sha256",
"operator_identity",
"authorization_window",
"authorization_text",
"destination_container",
"destination_database",
"destination_system_identifier",
"destination_server_version",
"approval_gate_action",
"strict_candidate_action",
"apply_engine_sha256",
"approval_gate_sha256",
"binding_proposal",
"binding_gate_false",
"binding_preconditions",
"packet_safe_flag",
"scope_exclusion",
"authorization_template",
"record_extra_field",
"action_readback_stale",
"production_rollback_binding",
)
@given(mutation=st.sampled_from(AUTHORIZATION_MUTATIONS))
@settings(max_examples=len(AUTHORIZATION_MUTATIONS), deadline=None)
def test_every_authorization_binding_field_fails_closed_when_mutated(mutation: str):
packet, record, destination, production_rollback_artifact = _authorization_materials()
expected_failed_check = {
"packet_schema": "packet_schema_exact",
"packet_readonly": "packet_destination_readback_was_read_only",
"approval_gate_packet": "approval_gate_ready_at_packet",
"production_rollback_packet": "exact_production_rollback_packet_ready",
"strict_candidate": "strict_proposal_present_and_approved",
"rollback_authorized": "rollback_authorized_is_exact_true",
"production_rollback_sha256": "production_rollback_sql_sha256_exact",
"binding_sha256": "binding_sha256_exact",
"operator_identity": "operator_identity_present",
"authorization_window": "authorization_window_valid",
"authorization_text": "authorization_text_exact",
"destination_container": "destination_identity_exact",
"destination_database": "destination_identity_exact",
"destination_system_identifier": "destination_identity_exact",
"destination_server_version": "destination_identity_exact",
"approval_gate_action": "approval_gate_identity_exact_at_action",
"strict_candidate_action": "strict_proposal_exact_at_action",
"apply_engine_sha256": "apply_engine_sha256_exact",
"approval_gate_sha256": "approval_gate_prerequisite_sha256_exact",
"binding_proposal": "packet_binding_sha256_self_consistent",
"binding_gate_false": "approval_gate_ready_at_packet",
"binding_preconditions": "packet_preconditions_bound_exactly",
"packet_safe_flag": "packet_never_self_authorizes_or_expands_scope",
"scope_exclusion": "packet_never_self_authorizes_or_expands_scope",
"authorization_template": "authorization_text_template_exact",
"record_extra_field": "authorization_record_contract_exact",
"action_readback_stale": "destination_readback_fresh_and_read_only_at_action",
"production_rollback_binding": "production_rollback_sql_sha256_exact",
}[mutation]
if mutation == "packet_schema":
packet["schema"] = "livingip.proposalApplyAuthorizationPacket.v0"
elif mutation == "packet_readonly":
packet["production_preconditions"]["destination_readback_was_read_only"] = False
elif mutation == "approval_gate_packet":
packet["production_preconditions"]["approval_gate_ready"] = False
elif mutation == "production_rollback_packet":
packet["production_preconditions"]["exact_production_rollback_packet_ready"] = False
elif mutation == "strict_candidate":
packet["production_preconditions"]["strict_proposal_present_and_approved"] = False
elif mutation == "rollback_authorized":
record["rollback_authorized"] = False
elif mutation == "production_rollback_sha256":
record["production_rollback_sql_sha256"] = "f" * 64
elif mutation == "binding_sha256":
record["binding_sha256"] = "0" * 64
elif mutation == "operator_identity":
record["operator_identity"] = " "
elif mutation == "authorization_window":
record["expires_at_utc"] = "2026-07-15T11:30:00+00:00"
elif mutation == "authorization_text":
record["authorization_text"] += " altered"
elif mutation.startswith("destination_"):
key = {
"destination_container": "container",
"destination_database": "database",
"destination_system_identifier": "system_identifier",
"destination_server_version": "server_version_num",
}[mutation]
destination[key] = f"wrong-{key}"
elif mutation == "approval_gate_action":
destination["approval_gate"]["review_role_present"] = False
elif mutation == "strict_candidate_action":
destination["approved_strict_candidates"] = []
elif mutation == "apply_engine_sha256":
packet["binding"]["engine"]["apply_engine_sha256"] = "0" * 64
elif mutation == "approval_gate_sha256":
packet["binding"]["approval_gate_dependency"]["sha256"] = "0" * 64
elif mutation == "binding_proposal":
packet["binding"]["proposal"]["id"] = CLAIM_A
elif mutation == "binding_gate_false":
packet["binding"]["approval_gate"]["review_role_present"] = False
elif mutation == "binding_preconditions":
packet["binding"]["production_preconditions"]["approval_gate_ready"] = False
elif mutation == "packet_safe_flag":
packet["safe_to_enter_apply_window"] = True
elif mutation == "scope_exclusion":
packet["scope_exclusions"]["telegram_send_authorized"] = True
elif mutation == "authorization_template":
packet["authorization_text_template"] += " Also authorize all other mutations."
elif mutation == "record_extra_field":
record["unexpected"] = True
elif mutation == "action_readback_stale":
destination["observed_at_utc"] = "2026-07-15T10:59:59+00:00"
elif mutation == "production_rollback_binding":
packet["binding"]["production_rollback"]["rollback_sql_sha256"] = "f" * 64
verification = lifecycle.verify_authorization_record(
packet,
record,
observed_destination=destination,
apply_engine_path=REPO_ROOT / "scripts" / "apply_proposal.py",
production_rollback_artifact=production_rollback_artifact,
now=datetime(2026, 7, 15, 12, 0, tzinfo=timezone.utc),
)
assert verification["checks"][expected_failed_check] is False
assert verification["safe_to_enter_apply_window"] is False
assert verification["production_apply_authorization_present"] is False
def test_false_bound_gate_cannot_pass_even_after_packet_and_record_are_rehashed():
packet, record, destination, production_rollback_artifact = _authorization_materials()
packet["binding"]["approval_gate"]["review_role_present"] = False
destination["approval_gate"]["review_role_present"] = False
packet["binding_sha256"] = lifecycle.sha256_json(packet["binding"])
packet["authorization_record_required"]["binding_sha256"] = packet["binding_sha256"]
packet["authorization_text_template"] = lifecycle._authorization_text_template(
packet["binding"],
packet["binding_sha256"],
)
record["binding_sha256"] = packet["binding_sha256"]
record["authorization_text"] = lifecycle.expected_authorization_text(packet, record)
verification = lifecycle.verify_authorization_record(
packet,
record,
observed_destination=destination,
apply_engine_path=REPO_ROOT / "scripts" / "apply_proposal.py",
production_rollback_artifact=production_rollback_artifact,
now=datetime(2026, 7, 15, 12, 0, tzinfo=timezone.utc),
)
assert verification["checks"]["packet_binding_sha256_self_consistent"] is True
assert verification["checks"]["approval_gate_ready_at_packet"] is False
assert verification["safe_to_enter_apply_window"] is False
def test_authorization_packet_uses_repo_relative_dependency_paths_only():
packet, _record, _destination, _production_rollback_artifact = _authorization_materials()
encoded = json.dumps(packet, sort_keys=True)
assert packet["binding"]["engine"]["apply_engine_path"] == "scripts/apply_proposal.py"
assert packet["binding"]["approval_gate_dependency"]["path"] == "scripts/kb_apply_prereqs.sql"
assert "/private/tmp" not in encoded
assert "/tmp" not in encoded

View file

@ -2,6 +2,8 @@
from __future__ import annotations from __future__ import annotations
import hashlib
import json
import subprocess import subprocess
import sys import sys
from pathlib import Path from pathlib import Path
@ -11,8 +13,10 @@ import pytest
ROOT = Path(__file__).resolve().parents[1] ROOT = Path(__file__).resolve().parents[1]
sys.path.insert(0, str(ROOT / "scripts")) sys.path.insert(0, str(ROOT / "scripts"))
WRAPPER = ROOT / "scripts" / "run_approve_claim_isolated_container_canary.sh" WRAPPER = ROOT / "scripts" / "run_approve_claim_isolated_container_canary.sh"
FINALIZER = ROOT / "scripts" / "finalize_approve_claim_isolated_canary.py"
import apply_proposal as apply # noqa: E402 import apply_proposal as apply # noqa: E402
import finalize_approve_claim_isolated_canary as finalizer # noqa: E402
import run_approve_claim_clone_canary as canary # noqa: E402 import run_approve_claim_clone_canary as canary # noqa: E402
@ -24,9 +28,7 @@ def test_role_psql_resolves_docker_before_scrubbing_path(
monkeypatch.setattr( monkeypatch.setattr(
canary.shutil, canary.shutil,
"which", "which",
lambda executable: "/opt/homebrew/bin/docker" lambda executable: "/opt/homebrew/bin/docker" if executable == "docker" else None,
if executable == "docker"
else None,
) )
def fake_run(command: list[str], **kwargs: object) -> subprocess.CompletedProcess[str]: def fake_run(command: list[str], **kwargs: object) -> subprocess.CompletedProcess[str]:
@ -58,9 +60,7 @@ def test_apply_tool_resolves_docker_before_scrubbing_path(
monkeypatch.setattr( monkeypatch.setattr(
apply.shutil, apply.shutil,
"which", "which",
lambda executable: "/opt/homebrew/bin/docker" lambda executable: "/opt/homebrew/bin/docker" if executable == "docker" else None,
if executable == "docker"
else None,
) )
def fake_run(command: list[str], **kwargs: object) -> subprocess.CompletedProcess[str]: def fake_run(command: list[str], **kwargs: object) -> subprocess.CompletedProcess[str]:
@ -89,14 +89,76 @@ def test_apply_tool_resolves_docker_before_scrubbing_path(
def test_outer_wrapper_enforces_local_source_and_networkless_tmpfs() -> None: def test_outer_wrapper_enforces_local_source_and_networkless_tmpfs() -> None:
text = WRAPPER.read_text(encoding="utf-8") wrapper = WRAPPER.read_text(encoding="utf-8")
finalizer = FINALIZER.read_text(encoding="utf-8")
text = wrapper + "\n" + finalizer
assert 'source_canary_label" != "working-leo-approved-source"' in text assert 'source_canary_label" != "working-leo-approved-source"' in text
assert "--network none" in text assert "--network none" in text
assert "--tmpfs /var/lib/postgresql/data:rw,nosuid,size=512m" in text assert "--tmpfs /var/lib/postgresql/data:rw,nosuid,size=512m" in text
assert 'CANARY_NETWORK_MODE="$container_network_mode"' in text assert 'CANARY_NETWORK_MODE="$container_network_mode"' in text
assert 'CANARY_MOUNTS_JSON="$container_mounts_json"' in text assert 'CANARY_MOUNTS_JSON="$container_mounts_json"' in text
assert 'data["checks"]["outer_source_tier_enforced"]' in text assert 'checks["outer_source_tier_enforced"]' in text
assert 'data["checks"]["outer_container_network_disabled"]' in text assert 'checks["outer_container_network_disabled"]' in text
assert 'data["checks"]["outer_container_has_no_docker_volumes"]' in text assert 'checks["outer_container_has_no_docker_volumes"]' in text
assert 'source_tier != "live-readonly" or service_observable' in text assert 'source_tier != "live-readonly" or service_observable' in text
assert "<<'PY'" not in wrapper
assert "finalize_approve_claim_isolated_canary.py" in wrapper
def test_outer_finalizer_runs_from_a_normal_file_without_heredoc(tmp_path: Path) -> None:
content = FINALIZER.read_bytes()
report = tmp_path / "canary.json"
report.write_text(
json.dumps(
{
"status": "pass",
"checks": {},
"source_binding": {
"unchanged_during_run": True,
"files": [
{
"repo_relative_path": FINALIZER.relative_to(ROOT).as_posix(),
"sha256": hashlib.sha256(content).hexdigest(),
"size_bytes": len(content),
}
],
},
}
),
encoding="utf-8",
)
counts = json.dumps({"public.claims": 2, "kb_stage.kb_proposals": 0})
data = finalizer.finalize(
report,
{
"SOURCE_COUNTS_BEFORE": counts,
"SOURCE_COUNTS_AFTER": counts,
"SOURCE_CONTAINER": "isolated-source",
"SOURCE_DB": "teleo",
"SERVICE_BEFORE": "Available=false\nReason=systemctl_unavailable\n",
"SERVICE_AFTER": "Available=false\nReason=systemctl_unavailable\n",
"REPO_ROOT": str(ROOT),
"OUTER_CONTAINER_REMOVE_RC": "0",
"OUTER_WORKDIR_REMOVE_RC": "0",
"CONTAINER_NAME_READBACK": "",
"CONTAINER_NAME_READBACK_RC": "0",
"CONTAINER_LABEL_READBACK": "",
"CONTAINER_LABEL_READBACK_RC": "0",
"CONTAINER_LABEL_ORPHAN_COUNT": "0",
"OUTER_WORKDIR_LEXISTS": "false",
"CANARY_RC": "0",
"SOURCE_TIER": "isolated-local",
"SOURCE_NETWORK_MODE": "none",
"SOURCE_CANARY_LABEL": "working-leo-approved-source",
"CANARY_NETWORK_MODE": "none",
"CANARY_MOUNTS_JSON": "[]",
"CANARY_LABEL": "proposal-apply-lifecycle",
"CANARY_INSTANCE_LABEL": "working-leo-approve-claim-test",
},
)
assert data["status"] == "pass"
assert data["current_tier"] == "T2_runtime"
assert data["checks"]["outer_isolation_complete"] is True
assert data["outer_isolation"]["cleanup_readback"]["label_scoped_orphan_count"] == 0