From dc42ff45ae912dbb89115712ef78cdeb3a1b1c28 Mon Sep 17 00:00:00 2001 From: twentyOne2x Date: Fri, 10 Jul 2026 04:14:17 +0200 Subject: [PATCH] Add Leo production receipt assembler --- .../current-truth-index.md | 3 + .../working-leo-current-state-20260709.md | 10 +- .../working-leo-execution-plan-current.md | 5 +- ...uction-apply-receipt-assembly-current.json | 74 +++++ ...oduction-apply-receipt-assembly-current.md | 56 ++++ ...le_working_leo_production_apply_receipt.py | 262 ++++++++++++++++++ ...le_working_leo_production_apply_receipt.py | 123 ++++++++ 7 files changed, 530 insertions(+), 3 deletions(-) create mode 100644 docs/reports/leo-working-state-20260709/working-leo-production-apply-receipt-assembly-current.json create mode 100644 docs/reports/leo-working-state-20260709/working-leo-production-apply-receipt-assembly-current.md create mode 100644 scripts/assemble_working_leo_production_apply_receipt.py create mode 100644 tests/test_assemble_working_leo_production_apply_receipt.py diff --git a/docs/reports/leo-working-state-20260709/current-truth-index.md b/docs/reports/leo-working-state-20260709/current-truth-index.md index ca238e3..706b001 100644 --- a/docs/reports/leo-working-state-20260709/current-truth-index.md +++ b/docs/reports/leo-working-state-20260709/current-truth-index.md @@ -86,6 +86,8 @@ Use this file before making status claims. Prefer fresh VPS/GCP readbacks when c - Working Leo live production preflight baseline JSON: `docs/reports/leo-working-state-20260709/working-leo-production-preflight-current.json` - Working Leo production apply receipt template, not executed: `docs/reports/leo-working-state-20260709/working-leo-production-apply-receipt-template-current.md` - Working Leo production apply receipt template JSON: `docs/reports/leo-working-state-20260709/working-leo-production-apply-receipt-template-current.json` +- Working Leo production apply receipt assembly, currently not ready: `docs/reports/leo-working-state-20260709/working-leo-production-apply-receipt-assembly-current.md` +- Working Leo production apply receipt assembly JSON: `docs/reports/leo-working-state-20260709/working-leo-production-apply-receipt-assembly-current.json` - Working Leo production apply receipt validation, currently missing receipt: `docs/reports/leo-working-state-20260709/working-leo-production-apply-receipt-validation-current.md` - Working Leo production apply receipt validation JSON: `docs/reports/leo-working-state-20260709/working-leo-production-apply-receipt-validation-current.json` - Working Leo cleanup readback: `docs/reports/leo-working-state-20260709/working-leo-cleanup-readback-current.md` @@ -139,6 +141,7 @@ Use this file before making status claims. Prefer fresh VPS/GCP readbacks when c - The production apply authorization verifier currently refuses the apply window: deployed SHA shape is valid and the auth packet is ready/not-executed/not-authorized, but `authorization_text_present=false`, `operator_identity_present=false`, `authorization_text_matches_expected=false`, `safe_to_enter_apply_window=false`, and `production_apply_executed=false`. - The live production preflight baseline now passes through the read-only collector: `5/5` preflight files executed on the VPS with `begin transaction read only`, `mutates_production_db=false`, `applies_production_packet=false`, and `production_apply_executed=false`. Current production still has generated base rows `0/0/0/0`, Helmer rows `0/0/0/0/0`, no generated governance/concept tables, and dependent Rio/cross-surface/governance base rows absent before any apply, as expected. - The production apply receipt template is generated but intentionally invalid as a final receipt: `production_apply_executed=false`, `valid_production_receipt=false`, and it names the fields that must only be filled after authorized apply execution (`explicit_authorization_record`, `operator_identity`, `apply_output_paths`, `postflight_output_paths`, `actual_after_apply_counts`, `telegram_or_handler_regression_paths`, `service_readback`, `cleanup_readback`). +- The production apply receipt assembler currently refuses final receipt emission: `receipt_ready=false`, `authorization_verified=false`, `all_session_artifacts_exist=false`, `actual_counts_match_expected=false`, no apply/postflight/regression/service/cleanup logs exist, and `production_apply_executed=false`. - The production-apply receipt validator currently reports `missing_receipt`, which is correct because no production apply has been authorized or executed. - DB-first identity rendering is now documented from the July 9 PDFs plus VPS readback: canonical identity rows feed rendered `SOUL.md`, direct SOUL edits are not canonical DB updates, and no active renderer/timer/hook is proven in the current VPS readback. - The decision-matrix approval schema is still a target design on the current VPS: `kb_stage.matrix_voters`, `kb_stage.proposal_votes`, and `kb_stage.proposal_decisions` were not present in live schema readback. diff --git a/docs/reports/leo-working-state-20260709/working-leo-current-state-20260709.md b/docs/reports/leo-working-state-20260709/working-leo-current-state-20260709.md index 89eba86..7b0c122 100644 --- a/docs/reports/leo-working-state-20260709/working-leo-current-state-20260709.md +++ b/docs/reports/leo-working-state-20260709/working-leo-current-state-20260709.md @@ -1,6 +1,6 @@ # Working Leo Current State - 2026-07-09 -Generated UTC: `2026-07-10T02:08:33Z` +Generated UTC: `2026-07-10T02:12:56Z` ## Current Working Definition @@ -175,6 +175,13 @@ A working Leo, for Cory/m3taversal's current expectation, is a Telegram-facing a - pre-filled/baseline fields are current git SHA, preflight output paths, expected counts, current direct-claim score path, rollback packet paths, and known residual risks - after-apply fields still required are explicit authorization record, operator identity, apply outputs, postflight outputs, actual counts, post-apply regression paths, service readback, and cleanup readback - this is a template, not a receipt and not a substitute for `working-leo-production-apply-receipt-current.json` +- Production apply receipt assembly is now retained: + - `mode=receipt_assembly_offline` + - `status=not_ready_missing_or_unverified_session_evidence` + - `receipt_ready=false` + - `production_apply_executed=false` + - current blockers are unverified authorization, missing session logs, and missing actual after-apply counts + - when those artifacts exist, the assembler can emit `working-leo-production-apply-receipt-current.json` for the existing offline validator - VPS/Hermes/DB identity and document-linking map is now documented: - the supplied July 9 master/build and database-reference PDFs confirm the intended architecture is DB-first identity: canonical Postgres identity graph rows render to `SOUL.md`, and evidence depth remains on demand through `teleo-kb` - direct `SOUL.md` edits are profile/runtime artifact edits, not canonical DB updates; they can drift or be overwritten unless represented in canonical rows first @@ -225,6 +232,7 @@ A working Leo, for Cory/m3taversal's current expectation, is a Telegram-facing a - Production apply authorization verification: `work/teleo-infra-main/docs/reports/leo-working-state-20260709/working-leo-production-apply-authorization-verification-current.md` - Live production preflight baseline: `work/teleo-infra-main/docs/reports/leo-working-state-20260709/working-leo-production-preflight-current.md` - Production apply receipt template: `work/teleo-infra-main/docs/reports/leo-working-state-20260709/working-leo-production-apply-receipt-template-current.md` +- Production apply receipt assembly: `work/teleo-infra-main/docs/reports/leo-working-state-20260709/working-leo-production-apply-receipt-assembly-current.md` - Production apply receipt validation: `work/teleo-infra-main/docs/reports/leo-working-state-20260709/working-leo-production-apply-receipt-validation-current.md` - Cleanup readback: `work/teleo-infra-main/docs/reports/leo-working-state-20260709/working-leo-cleanup-readback-current.md` - VPS/Hermes/DB mapping: `outputs/vps-hermes-db-mapping-20260709.md` diff --git a/docs/reports/leo-working-state-20260709/working-leo-execution-plan-current.md b/docs/reports/leo-working-state-20260709/working-leo-execution-plan-current.md index 04820fa..99a7c61 100644 --- a/docs/reports/leo-working-state-20260709/working-leo-execution-plan-current.md +++ b/docs/reports/leo-working-state-20260709/working-leo-execution-plan-current.md @@ -1,6 +1,6 @@ # Working Leo Execution Plan - 2026-07-09 -Claim ceiling: VPS Telegram memory/KB audit, full live-safe open-ended Telegram suite, full mixed-evidence Cory-style outcome/direct-claim sandbox benchmark, live VPS GatewayRunner no-context direct-claim suite, Telegram-to-`kb_stage` proposal staging, and strict existing-ID apply are working. The live VPS handler suite for exact `DC-01` through `DC-06` prompts strict-scores `6/6` after the authorized-session-plan deploy and scorer refresh, with no Telegram post, no live profile write, no production DB apply, unchanged DB counts, temp profile cleanup, and unchanged gateway service state during the harness. The full prepared DB packet set is integrated-clone-proven in dependency order: mapped rich base, cross-surface anchor, Rio strategy context, governance/concept schema, and Helmer 7 Powers. A read-only live production preflight baseline now passes `5/5`, an authorized apply operator runbook is generated, an authorized apply session plan maps every apply-window output path with authorization gates, a production apply authorization packet is ready-to-request, and the authorization verifier refuses the current apply window because no exact authorization text/operator identity is present. None of those packets are production-applied or authorized. GCP parity remains pending. +Claim ceiling: VPS Telegram memory/KB audit, full live-safe open-ended Telegram suite, full mixed-evidence Cory-style outcome/direct-claim sandbox benchmark, live VPS GatewayRunner no-context direct-claim suite, Telegram-to-`kb_stage` proposal staging, and strict existing-ID apply are working. The live VPS handler suite for exact `DC-01` through `DC-06` prompts strict-scores `6/6` after the authorized-session-plan deploy and scorer refresh, with no Telegram post, no live profile write, no production DB apply, unchanged DB counts, temp profile cleanup, and unchanged gateway service state during the harness. The full prepared DB packet set is integrated-clone-proven in dependency order: mapped rich base, cross-surface anchor, Rio strategy context, governance/concept schema, and Helmer 7 Powers. A read-only live production preflight baseline now passes `5/5`, an authorized apply operator runbook is generated, an authorized apply session plan maps every apply-window output path with authorization gates, a production apply authorization packet is ready-to-request, the authorization verifier refuses the current apply window because no exact authorization text/operator identity is present, and the receipt assembler refuses final receipt emission because post-apply session artifacts/counts are absent. None of those packets are production-applied or authorized. GCP parity remains pending. ## WL-EXEC-01 - VPS Telegram-visible memory + KB audit - Status: `done` @@ -96,7 +96,7 @@ Claim ceiling: VPS Telegram memory/KB audit, full live-safe open-ended Telegram ## WL-EXEC-06B - Integrated production-order packet rehearsal - Status: `done_integrated_clone_ready_not_executed` -- Result: Applied the full prepared packet set in one disposable clone in dependency order: mapped base, cross-surface anchor, Rio strategy context, governance/concept schema, and Helmer 7 Powers. Expected integrated footprint was `12` claims, `28` sources, `18` claim edges, `34` claim evidence rows, `1` reasoning tool, `2` Rio strategy nodes, `5` Rio strategy anchors, `1` concept map, `1` concept link, `2` governance links, one Helmer ledger row marked applied, and one cross-surface anchor update. Reverse rollback restored all generated rows/schema to zero/absent, restored the cross-surface anchor to the old claim, restored the Helmer ledger to `approved`, dropped the disposable DB, removed temp files, and left production unchanged. The apply-readiness verifier now passes over the retained manifest/files/logs with `ready_for_authorized_production_apply_packet=true`, `production_apply_executed=false`, and `production_apply_authorization_present=false`. The authorized apply runbook now emits preflight/apply/postflight/rollback command templates in manifest order, a read-only pre-apply production baseline collector, a post-apply regression command bundle, a required production-apply receipt schema, and an offline receipt validator with `status=ready_not_executed`. The authorized apply session plan maps concrete output paths for pre-apply validation, preflight, apply, postflight, post-apply regression, service readback, cleanup readback, receipt validation, and rollback; apply and rollback steps require explicit authorization, non-apply steps are non-mutating, and `production_apply_executed=false`. The production apply authorization packet now passes all evidence gates and retains the operator authorization template plus fresh deployed-SHA requirement while keeping `production_apply_executed=false` and `production_apply_authorization_present=false`. The authorization verifier constructs the exact expected text for deployed SHA `427a9f1a1e114814c750bb3e9e99e3456a6c1539` but refuses the apply window with `safe_to_enter_apply_window=false` because authorization text and operator identity are absent. The live production preflight baseline ran through `begin transaction read only` and passed `5/5` with no production apply executed. +- Result: Applied the full prepared packet set in one disposable clone in dependency order: mapped base, cross-surface anchor, Rio strategy context, governance/concept schema, and Helmer 7 Powers. Expected integrated footprint was `12` claims, `28` sources, `18` claim edges, `34` claim evidence rows, `1` reasoning tool, `2` Rio strategy nodes, `5` Rio strategy anchors, `1` concept map, `1` concept link, `2` governance links, one Helmer ledger row marked applied, and one cross-surface anchor update. Reverse rollback restored all generated rows/schema to zero/absent, restored the cross-surface anchor to the old claim, restored the Helmer ledger to `approved`, dropped the disposable DB, removed temp files, and left production unchanged. The apply-readiness verifier now passes over the retained manifest/files/logs with `ready_for_authorized_production_apply_packet=true`, `production_apply_executed=false`, and `production_apply_authorization_present=false`. The authorized apply runbook now emits preflight/apply/postflight/rollback command templates in manifest order, a read-only pre-apply production baseline collector, a post-apply regression command bundle, a required production-apply receipt schema, and an offline receipt validator with `status=ready_not_executed`. The authorized apply session plan maps concrete output paths for pre-apply validation, preflight, apply, postflight, post-apply regression, service readback, cleanup readback, receipt validation, and rollback; apply and rollback steps require explicit authorization, non-apply steps are non-mutating, and `production_apply_executed=false`. The production apply authorization packet now passes all evidence gates and retains the operator authorization template plus fresh deployed-SHA requirement while keeping `production_apply_executed=false` and `production_apply_authorization_present=false`. The authorization verifier constructs the exact expected text for deployed SHA `427a9f1a1e114814c750bb3e9e99e3456a6c1539` but refuses the apply window with `safe_to_enter_apply_window=false` because authorization text and operator identity are absent. The receipt assembler now proves no final receipt can be emitted yet: `receipt_ready=false`, `authorization_verified=false`, `all_session_artifacts_exist=false`, `actual_counts_match_expected=false`, and `production_apply_executed=false`. The live production preflight baseline ran through `begin transaction read only` and passed `5/5` with no production apply executed. - Next action: If production apply is explicitly authorized, use the generated runbook order, run every postflight SQL file, run the post-apply regression bundle, retain the production receipt, and then rerun any user-visible Telegram canary needed for the demo/meeting tier. - Not done condition: Production canonical rows/schema remain unapplied until explicit production apply authorization. - Evidence: @@ -107,6 +107,7 @@ Claim ceiling: VPS Telegram memory/KB audit, full live-safe open-ended Telegram - `/Users/user/Documents/Codex/2026-07-09/019f34eb-d297-72d0-b7e2-b222d5515ab9-load/work/teleo-infra-main/docs/reports/leo-working-state-20260709/working-leo-authorized-apply-session-plan-current.md` - `/Users/user/Documents/Codex/2026-07-09/019f34eb-d297-72d0-b7e2-b222d5515ab9-load/work/teleo-infra-main/docs/reports/leo-working-state-20260709/working-leo-production-apply-authorization-packet-current.md` - `/Users/user/Documents/Codex/2026-07-09/019f34eb-d297-72d0-b7e2-b222d5515ab9-load/work/teleo-infra-main/docs/reports/leo-working-state-20260709/working-leo-production-apply-authorization-verification-current.md` + - `/Users/user/Documents/Codex/2026-07-09/019f34eb-d297-72d0-b7e2-b222d5515ab9-load/work/teleo-infra-main/docs/reports/leo-working-state-20260709/working-leo-production-apply-receipt-assembly-current.md` - `/Users/user/Documents/Codex/2026-07-09/019f34eb-d297-72d0-b7e2-b222d5515ab9-load/work/teleo-infra-main/docs/reports/leo-working-state-20260709/working-leo-production-preflight-current.md` - `/Users/user/Documents/Codex/2026-07-09/019f34eb-d297-72d0-b7e2-b222d5515ab9-load/work/teleo-infra-main/docs/reports/leo-working-state-20260709/working-leo-production-apply-receipt-validation-current.md` diff --git a/docs/reports/leo-working-state-20260709/working-leo-production-apply-receipt-assembly-current.json b/docs/reports/leo-working-state-20260709/working-leo-production-apply-receipt-assembly-current.json new file mode 100644 index 0000000..798e322 --- /dev/null +++ b/docs/reports/leo-working-state-20260709/working-leo-production-apply-receipt-assembly-current.json @@ -0,0 +1,74 @@ +{ + "actual_after_apply_counts": {}, + "assembled_receipt": {}, + "checks": { + "actual_counts_match_expected": false, + "all_session_artifacts_exist": false, + "authorization_not_executed_by_verifier": true, + "authorization_verified": false, + "receipt_template_not_final_receipt": true, + "session_plan_not_executed": true + }, + "claim_ceiling": "This assembler only builds a receipt from retained post-apply artifacts. It does not run SQL, does not mutate production, and does not prove canonical rows changed unless receipt_ready=true and the output receipt validates.", + "expected_after_apply_counts": { + "claim_concept_map_links": 1, + "claim_edges": 18, + "claim_evidence": 34, + "claim_governance_gate_links": 2, + "claims": 12, + "concept_maps": 1, + "cross_surface_anchor_updates": 1, + "helmer_ledger_rows_marked_applied": 1, + "reasoning_tools": 1, + "rio_strategy_anchors": 5, + "rio_strategy_nodes": 2, + "sources": 28 + }, + "generated_at_utc": "2026-07-10T02:12:31.599618+00:00", + "missing_paths_by_group": { + "actual_counts_path": [ + "docs/reports/leo-working-state-20260709/production-apply-session-artifacts/actual-after-apply-counts.json" + ], + "apply_output_paths": [ + "docs/reports/leo-working-state-20260709/production-apply-session-artifacts/01-apply-mapped-rich-base.log", + "docs/reports/leo-working-state-20260709/production-apply-session-artifacts/02-apply-cross-surface-anchor.log", + "docs/reports/leo-working-state-20260709/production-apply-session-artifacts/03-apply-rio-strategy-context.log", + "docs/reports/leo-working-state-20260709/production-apply-session-artifacts/04-apply-governance-concept-schema.log", + "docs/reports/leo-working-state-20260709/production-apply-session-artifacts/05-apply-helmer-7powers.log" + ], + "cleanup_log_path": [ + "docs/reports/leo-working-state-20260709/production-apply-session-artifacts/post-apply-cleanup-readback.log" + ], + "direct_claim_score_path": [], + "postflight_output_paths": [ + "docs/reports/leo-working-state-20260709/production-apply-session-artifacts/01-postflight-mapped-rich-base.log", + "docs/reports/leo-working-state-20260709/production-apply-session-artifacts/02-postflight-cross-surface-anchor.log", + "docs/reports/leo-working-state-20260709/production-apply-session-artifacts/03-postflight-rio-strategy-context.log", + "docs/reports/leo-working-state-20260709/production-apply-session-artifacts/04-postflight-governance-concept-schema.log", + "docs/reports/leo-working-state-20260709/production-apply-session-artifacts/05-postflight-helmer-7powers.log" + ], + "preflight_output_paths": [ + "docs/reports/leo-working-state-20260709/production-apply-session-artifacts/01-preflight-mapped-rich-base.log", + "docs/reports/leo-working-state-20260709/production-apply-session-artifacts/02-preflight-cross-surface-anchor.log", + "docs/reports/leo-working-state-20260709/production-apply-session-artifacts/03-preflight-rio-strategy-context.log", + "docs/reports/leo-working-state-20260709/production-apply-session-artifacts/04-preflight-governance-concept-schema.log", + "docs/reports/leo-working-state-20260709/production-apply-session-artifacts/05-preflight-helmer-7powers.log" + ], + "rollback_packet_paths": [], + "service_log_path": [ + "docs/reports/leo-working-state-20260709/production-apply-session-artifacts/post-apply-service-readback.log" + ], + "telegram_or_handler_regression_paths": [ + "docs/reports/leo-working-state-20260709/production-apply-session-artifacts/post-apply-regression-01-direct_claim_handler_suite.log", + "docs/reports/leo-working-state-20260709/production-apply-session-artifacts/post-apply-regression-02-direct_claim_strict_score.log", + "docs/reports/leo-working-state-20260709/production-apply-session-artifacts/post-apply-regression-03-focused_local_regression_tests.log", + "docs/reports/leo-working-state-20260709/production-apply-session-artifacts/post-apply-regression-04-gateway_service_readback.log", + "docs/reports/leo-working-state-20260709/production-apply-session-artifacts/post-apply-regression-05-production_receipt_validator.log" + ] + }, + "mode": "receipt_assembly_offline", + "production_apply_executed": false, + "receipt_out": "docs/reports/leo-working-state-20260709/working-leo-production-apply-receipt-current.json", + "receipt_ready": false, + "status": "not_ready_missing_or_unverified_session_evidence" +} diff --git a/docs/reports/leo-working-state-20260709/working-leo-production-apply-receipt-assembly-current.md b/docs/reports/leo-working-state-20260709/working-leo-production-apply-receipt-assembly-current.md new file mode 100644 index 0000000..d411015 --- /dev/null +++ b/docs/reports/leo-working-state-20260709/working-leo-production-apply-receipt-assembly-current.md @@ -0,0 +1,56 @@ +# Working Leo Production Apply Receipt Assembly + +Generated UTC: `2026-07-10T02:12:31.599618+00:00` +Mode: `receipt_assembly_offline` +Status: `not_ready_missing_or_unverified_session_evidence` +Receipt ready: `False` +Production apply executed according to assembled evidence: `False` +Receipt output: `docs/reports/leo-working-state-20260709/working-leo-production-apply-receipt-current.json` + +## Checks + +- `actual_counts_match_expected`: `False` +- `all_session_artifacts_exist`: `False` +- `authorization_not_executed_by_verifier`: `True` +- `authorization_verified`: `False` +- `receipt_template_not_final_receipt`: `True` +- `session_plan_not_executed`: `True` + +## Missing Paths By Group + +- `actual_counts_path`: `1` missing + - `docs/reports/leo-working-state-20260709/production-apply-session-artifacts/actual-after-apply-counts.json` +- `apply_output_paths`: `5` missing + - `docs/reports/leo-working-state-20260709/production-apply-session-artifacts/01-apply-mapped-rich-base.log` + - `docs/reports/leo-working-state-20260709/production-apply-session-artifacts/02-apply-cross-surface-anchor.log` + - `docs/reports/leo-working-state-20260709/production-apply-session-artifacts/03-apply-rio-strategy-context.log` + - `docs/reports/leo-working-state-20260709/production-apply-session-artifacts/04-apply-governance-concept-schema.log` + - `docs/reports/leo-working-state-20260709/production-apply-session-artifacts/05-apply-helmer-7powers.log` +- `cleanup_log_path`: `1` missing + - `docs/reports/leo-working-state-20260709/production-apply-session-artifacts/post-apply-cleanup-readback.log` +- `direct_claim_score_path`: `0` missing +- `postflight_output_paths`: `5` missing + - `docs/reports/leo-working-state-20260709/production-apply-session-artifacts/01-postflight-mapped-rich-base.log` + - `docs/reports/leo-working-state-20260709/production-apply-session-artifacts/02-postflight-cross-surface-anchor.log` + - `docs/reports/leo-working-state-20260709/production-apply-session-artifacts/03-postflight-rio-strategy-context.log` + - `docs/reports/leo-working-state-20260709/production-apply-session-artifacts/04-postflight-governance-concept-schema.log` + - `docs/reports/leo-working-state-20260709/production-apply-session-artifacts/05-postflight-helmer-7powers.log` +- `preflight_output_paths`: `5` missing + - `docs/reports/leo-working-state-20260709/production-apply-session-artifacts/01-preflight-mapped-rich-base.log` + - `docs/reports/leo-working-state-20260709/production-apply-session-artifacts/02-preflight-cross-surface-anchor.log` + - `docs/reports/leo-working-state-20260709/production-apply-session-artifacts/03-preflight-rio-strategy-context.log` + - `docs/reports/leo-working-state-20260709/production-apply-session-artifacts/04-preflight-governance-concept-schema.log` + - `docs/reports/leo-working-state-20260709/production-apply-session-artifacts/05-preflight-helmer-7powers.log` +- `rollback_packet_paths`: `0` missing +- `service_log_path`: `1` missing + - `docs/reports/leo-working-state-20260709/production-apply-session-artifacts/post-apply-service-readback.log` +- `telegram_or_handler_regression_paths`: `5` missing + - `docs/reports/leo-working-state-20260709/production-apply-session-artifacts/post-apply-regression-01-direct_claim_handler_suite.log` + - `docs/reports/leo-working-state-20260709/production-apply-session-artifacts/post-apply-regression-02-direct_claim_strict_score.log` + - `docs/reports/leo-working-state-20260709/production-apply-session-artifacts/post-apply-regression-03-focused_local_regression_tests.log` + - `docs/reports/leo-working-state-20260709/production-apply-session-artifacts/post-apply-regression-04-gateway_service_readback.log` + - `docs/reports/leo-working-state-20260709/production-apply-session-artifacts/post-apply-regression-05-production_receipt_validator.log` + +## Claim Ceiling + +This assembler only builds a receipt from retained post-apply artifacts. It does not run SQL, does not mutate production, and does not prove canonical rows changed unless receipt_ready=true and the output receipt validates. diff --git a/scripts/assemble_working_leo_production_apply_receipt.py b/scripts/assemble_working_leo_production_apply_receipt.py new file mode 100644 index 0000000..7bf9689 --- /dev/null +++ b/scripts/assemble_working_leo_production_apply_receipt.py @@ -0,0 +1,262 @@ +#!/usr/bin/env python3 +"""Assemble a Working Leo production-apply receipt from retained artifacts. + +This is an offline assembler, not an executor. It refuses to emit a production +receipt unless authorization verification is valid and every expected session +artifact exists. It never opens a database connection, never runs SQL, and +never posts to Telegram. +""" + +from __future__ import annotations + +import argparse +import json +from datetime import datetime, timezone +from pathlib import Path +from typing import Any + +REPORT_DIR = Path("docs/reports/leo-working-state-20260709") +DEFAULT_RUNBOOK = REPORT_DIR / "working-leo-authorized-apply-runbook-current.json" +DEFAULT_SESSION_PLAN = REPORT_DIR / "working-leo-authorized-apply-session-plan-current.json" +DEFAULT_RECEIPT_TEMPLATE = REPORT_DIR / "working-leo-production-apply-receipt-template-current.json" +DEFAULT_AUTH_VERIFICATION = REPORT_DIR / "working-leo-production-apply-authorization-verification-current.json" +DEFAULT_ACTUAL_COUNTS = REPORT_DIR / "production-apply-session-artifacts" / "actual-after-apply-counts.json" +DEFAULT_OUT = REPORT_DIR / "working-leo-production-apply-receipt-assembly-current.json" +DEFAULT_MARKDOWN_OUT = REPORT_DIR / "working-leo-production-apply-receipt-assembly-current.md" +DEFAULT_RECEIPT_OUT = REPORT_DIR / "working-leo-production-apply-receipt-current.json" + + +def _load_json(path: Path) -> dict[str, Any]: + return json.loads(path.read_text(encoding="utf-8")) + + +def _resolve(path: str | Path, *, repo_root: Path) -> Path: + candidate = Path(path) + return candidate if candidate.is_absolute() else repo_root / candidate + + +def _path_exists(path: str, *, repo_root: Path) -> bool: + return _resolve(path, repo_root=repo_root).exists() + + +def _missing_paths(paths: list[str], *, repo_root: Path) -> list[str]: + return [path for path in paths if not _path_exists(path, repo_root=repo_root)] + + +def _read_service_log(path: str, *, repo_root: Path) -> dict[str, str]: + result: dict[str, str] = {} + resolved = _resolve(path, repo_root=repo_root) + if not resolved.exists(): + return result + for line in resolved.read_text(encoding="utf-8").splitlines(): + if "=" in line: + key, value = line.split("=", 1) + result[key.strip()] = value.strip() + return result + + +def _read_cleanup_log(path: str, *, repo_root: Path) -> dict[str, Any]: + resolved = _resolve(path, repo_root=repo_root) + if not resolved.exists(): + return {"checks": {"cleanup_ok": False, "leftover_rehearsal_clone_or_staging_databases": []}} + leftovers = [line.strip() for line in resolved.read_text(encoding="utf-8").splitlines() if line.strip()] + return { + "checks": { + "cleanup_ok": leftovers == [], + "leftover_rehearsal_clone_or_staging_databases": leftovers, + } + } + + +def _direct_score_path(template: dict[str, Any]) -> str: + return str(template.get("receipt_template", {}).get("direct_claim_score_path") or "") + + +def _receipt_paths(session_plan: dict[str, Any], template: dict[str, Any]) -> dict[str, Any]: + sources = session_plan["receipt_field_sources_after_execution"] + return { + "preflight_output_paths": list(sources["preflight_output_paths"]), + "apply_output_paths": list(sources["apply_output_paths"]), + "postflight_output_paths": list(sources["postflight_output_paths"]), + "telegram_or_handler_regression_paths": list(sources["telegram_or_handler_regression_paths"]), + "direct_claim_score_path": _direct_score_path(template), + "service_log_path": str(sources["service_readback"]), + "cleanup_log_path": str(sources["cleanup_readback"]), + "rollback_packet_paths": list(sources["rollback_packet_paths"]), + } + + +def _counts_match(expected: dict[str, Any], actual: dict[str, Any]) -> bool: + try: + normalized_expected = {str(key): int(value) for key, value in expected.items()} + normalized_actual = {str(key): int(value) for key, value in actual.items()} + except (TypeError, ValueError): + return False + return normalized_actual == normalized_expected + + +def build_assembly( + *, + runbook_path: Path = DEFAULT_RUNBOOK, + session_plan_path: Path = DEFAULT_SESSION_PLAN, + receipt_template_path: Path = DEFAULT_RECEIPT_TEMPLATE, + auth_verification_path: Path = DEFAULT_AUTH_VERIFICATION, + actual_counts_path: Path = DEFAULT_ACTUAL_COUNTS, + receipt_out: Path = DEFAULT_RECEIPT_OUT, + repo_root: Path = Path("."), +) -> dict[str, Any]: + repo_root = repo_root.resolve() + runbook = _load_json(runbook_path) + session_plan = _load_json(session_plan_path) + receipt_template = _load_json(receipt_template_path) + auth_verification = _load_json(auth_verification_path) + paths = _receipt_paths(session_plan, receipt_template) + expected_counts = dict(runbook["expected_after_apply_counts"]) + actual_counts = _load_json(actual_counts_path) if _resolve(actual_counts_path, repo_root=repo_root).exists() else {} + path_groups = { + "preflight_output_paths": paths["preflight_output_paths"], + "apply_output_paths": paths["apply_output_paths"], + "postflight_output_paths": paths["postflight_output_paths"], + "telegram_or_handler_regression_paths": paths["telegram_or_handler_regression_paths"], + "rollback_packet_paths": paths["rollback_packet_paths"], + "direct_claim_score_path": [paths["direct_claim_score_path"]], + "service_log_path": [paths["service_log_path"]], + "cleanup_log_path": [paths["cleanup_log_path"]], + "actual_counts_path": [str(actual_counts_path)], + } + missing_by_group = { + group: _missing_paths([path for path in group_paths if path], repo_root=repo_root) + for group, group_paths in path_groups.items() + } + checks = { + "authorization_verified": auth_verification.get("safe_to_enter_apply_window") is True, + "authorization_not_executed_by_verifier": auth_verification.get("production_apply_executed") is False, + "all_session_artifacts_exist": all(not missing for missing in missing_by_group.values()), + "actual_counts_match_expected": _counts_match(expected_counts, actual_counts), + "receipt_template_not_final_receipt": receipt_template.get("production_apply_executed") is False + and receipt_template.get("valid_production_receipt") is False, + "session_plan_not_executed": session_plan.get("production_apply_executed") is False, + } + ready = all(checks.values()) + receipt = {} + if ready: + receipt = { + "actual_after_apply_counts": actual_counts, + "apply_output_paths": paths["apply_output_paths"], + "cleanup_readback": _read_cleanup_log(paths["cleanup_log_path"], repo_root=repo_root), + "direct_claim_score_path": paths["direct_claim_score_path"], + "explicit_authorization_record": { + "authorized": True, + "authorized_by": auth_verification.get("operator_identity"), + "deployed_sha": auth_verification.get("deployed_sha"), + "authorization_text": auth_verification.get("expected_authorization_text"), + }, + "expected_after_apply_counts": expected_counts, + "git_commit_sha": str(auth_verification.get("deployed_sha") or ""), + "known_residual_risks": list(receipt_template["receipt_template"].get("known_residual_risks", [])), + "operator_identity": str(auth_verification.get("operator_identity") or ""), + "postflight_output_paths": paths["postflight_output_paths"], + "preflight_output_paths": paths["preflight_output_paths"], + "rollback_packet_paths": paths["rollback_packet_paths"], + "service_readback": _read_service_log(paths["service_log_path"], repo_root=repo_root), + "telegram_or_handler_regression_paths": paths["telegram_or_handler_regression_paths"], + } + status = "ready_to_emit_receipt" if ready else "not_ready_missing_or_unverified_session_evidence" + return { + "generated_at_utc": datetime.now(timezone.utc).isoformat(), + "mode": "receipt_assembly_offline", + "status": status, + "receipt_ready": ready, + "production_apply_executed": ready, + "receipt_out": str(receipt_out), + "checks": checks, + "missing_paths_by_group": missing_by_group, + "expected_after_apply_counts": expected_counts, + "actual_after_apply_counts": actual_counts, + "assembled_receipt": receipt, + "claim_ceiling": ( + "This assembler only builds a receipt from retained post-apply artifacts. It does not run SQL, does not " + "mutate production, and does not prove canonical rows changed unless receipt_ready=true and the output " + "receipt validates." + ), + } + + +def write_json(path: Path, data: dict[str, Any]) -> None: + path.parent.mkdir(parents=True, exist_ok=True) + path.write_text(json.dumps(data, indent=2, sort_keys=True) + "\n", encoding="utf-8") + + +def write_markdown(path: Path, data: dict[str, Any]) -> None: + lines = [ + "# Working Leo Production Apply Receipt Assembly", + "", + f"Generated UTC: `{data['generated_at_utc']}`", + f"Mode: `{data['mode']}`", + f"Status: `{data['status']}`", + f"Receipt ready: `{data['receipt_ready']}`", + f"Production apply executed according to assembled evidence: `{data['production_apply_executed']}`", + f"Receipt output: `{data['receipt_out']}`", + "", + "## Checks", + "", + ] + for key, value in sorted(data["checks"].items()): + lines.append(f"- `{key}`: `{value}`") + lines.extend(["", "## Missing Paths By Group", ""]) + for group, paths in sorted(data["missing_paths_by_group"].items()): + lines.append(f"- `{group}`: `{len(paths)}` missing") + for item in paths[:10]: + lines.append(f" - `{item}`") + if len(paths) > 10: + lines.append(f" - ... {len(paths) - 10} more") + lines.extend(["", "## Claim Ceiling", "", data["claim_ceiling"], ""]) + path.parent.mkdir(parents=True, exist_ok=True) + path.write_text("\n".join(lines), encoding="utf-8") + + +def parse_args(argv: list[str] | None = None) -> argparse.Namespace: + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument("--runbook", type=Path, default=DEFAULT_RUNBOOK) + parser.add_argument("--session-plan", type=Path, default=DEFAULT_SESSION_PLAN) + parser.add_argument("--receipt-template", type=Path, default=DEFAULT_RECEIPT_TEMPLATE) + parser.add_argument("--auth-verification", type=Path, default=DEFAULT_AUTH_VERIFICATION) + parser.add_argument("--actual-counts", type=Path, default=DEFAULT_ACTUAL_COUNTS) + parser.add_argument("--out", type=Path, default=DEFAULT_OUT) + parser.add_argument("--markdown-out", type=Path, default=DEFAULT_MARKDOWN_OUT) + parser.add_argument("--receipt-out", type=Path, default=DEFAULT_RECEIPT_OUT) + parser.add_argument("--emit-receipt", action="store_true") + return parser.parse_args(argv) + + +def main(argv: list[str] | None = None) -> int: + args = parse_args(argv) + data = build_assembly( + runbook_path=args.runbook, + session_plan_path=args.session_plan, + receipt_template_path=args.receipt_template, + auth_verification_path=args.auth_verification, + actual_counts_path=args.actual_counts, + receipt_out=args.receipt_out, + ) + write_json(args.out, data) + write_markdown(args.markdown_out, data) + if args.emit_receipt and data["receipt_ready"]: + write_json(args.receipt_out, data["assembled_receipt"]) + print( + json.dumps( + { + "out": str(args.out), + "markdown_out": str(args.markdown_out), + "receipt_ready": data["receipt_ready"], + "status": data["status"], + }, + indent=2, + sort_keys=True, + ) + ) + return 0 if data["receipt_ready"] else 2 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/tests/test_assemble_working_leo_production_apply_receipt.py b/tests/test_assemble_working_leo_production_apply_receipt.py new file mode 100644 index 0000000..28f1aac --- /dev/null +++ b/tests/test_assemble_working_leo_production_apply_receipt.py @@ -0,0 +1,123 @@ +"""Tests for scripts/assemble_working_leo_production_apply_receipt.py.""" + +from __future__ import annotations + +import json +import sys +from pathlib import Path + +REPO_ROOT = Path(__file__).resolve().parents[1] +sys.path.insert(0, str(REPO_ROOT / "scripts")) + +import assemble_working_leo_production_apply_receipt as assembler # noqa: E402 +import validate_working_leo_production_receipt as validator # noqa: E402 + + +def write_json(path: Path, data: dict) -> None: + path.parent.mkdir(parents=True, exist_ok=True) + path.write_text(json.dumps(data, indent=2, sort_keys=True) + "\n", encoding="utf-8") + + +def test_current_assembly_refuses_without_authorization_or_session_logs(): + result = assembler.build_assembly() + + assert result["status"] == "not_ready_missing_or_unverified_session_evidence" + assert result["receipt_ready"] is False + assert result["production_apply_executed"] is False + assert result["checks"]["authorization_verified"] is False + assert result["checks"]["all_session_artifacts_exist"] is False + assert result["assembled_receipt"] == {} + assert "does not run SQL" in result["claim_ceiling"] + + +def test_assembly_emits_validator_ready_receipt_from_fixture(tmp_path: Path): + expected_counts = {"claims": 1, "sources": 2} + runbook = { + "expected_after_apply_counts": expected_counts, + "production_apply_receipt_required_fields": [ + "explicit_authorization_record", + "operator_identity", + "git_commit_sha", + "preflight_output_paths", + "apply_output_paths", + "postflight_output_paths", + "expected_after_apply_counts", + "actual_after_apply_counts", + "telegram_or_handler_regression_paths", + "direct_claim_score_path", + "service_readback", + "cleanup_readback", + "rollback_packet_paths", + "known_residual_risks", + ], + } + session_plan = { + "production_apply_executed": False, + "receipt_field_sources_after_execution": { + "preflight_output_paths": ["logs/preflight.log"], + "apply_output_paths": ["logs/apply.log"], + "postflight_output_paths": ["logs/postflight.log"], + "telegram_or_handler_regression_paths": ["logs/handler.log"], + "service_readback": "logs/service.log", + "cleanup_readback": "logs/cleanup.log", + "rollback_packet_paths": ["logs/rollback.sql"], + }, + } + template = { + "production_apply_executed": False, + "valid_production_receipt": False, + "receipt_template": { + "direct_claim_score_path": "logs/direct-score.md", + "known_residual_risks": ["GCP parity remains separate"], + }, + } + auth = { + "safe_to_enter_apply_window": True, + "production_apply_executed": False, + "operator_identity": "operator@example.com", + "deployed_sha": "db0c538", + "expected_authorization_text": "authorized", + } + for relative in ( + "logs/preflight.log", + "logs/apply.log", + "logs/postflight.log", + "logs/handler.log", + "logs/rollback.sql", + ): + (tmp_path / relative).parent.mkdir(parents=True, exist_ok=True) + (tmp_path / relative).write_text("ok\n", encoding="utf-8") + (tmp_path / "logs/direct-score.md").write_text( + "Overall pass for scored coverage: `True`\nPrompts scored: `6/6`\n", + encoding="utf-8", + ) + (tmp_path / "logs/service.log").write_text( + "ActiveState=active\nSubState=running\nMainPID=1908033\nNRestarts=0\n", + encoding="utf-8", + ) + (tmp_path / "logs/cleanup.log").write_text("", encoding="utf-8") + write_json(tmp_path / "runbook.json", runbook) + write_json(tmp_path / "session.json", session_plan) + write_json(tmp_path / "template.json", template) + write_json(tmp_path / "auth.json", auth) + write_json(tmp_path / "counts.json", expected_counts) + + result = assembler.build_assembly( + runbook_path=tmp_path / "runbook.json", + session_plan_path=tmp_path / "session.json", + receipt_template_path=tmp_path / "template.json", + auth_verification_path=tmp_path / "auth.json", + actual_counts_path=tmp_path / "counts.json", + receipt_out=tmp_path / "receipt.json", + repo_root=tmp_path, + ) + write_json(tmp_path / "receipt.json", result["assembled_receipt"]) + validation = validator.validate_receipt( + tmp_path / "receipt.json", + tmp_path / "runbook.json", + repo_root=tmp_path, + ) + + assert result["receipt_ready"] is True + assert result["checks"]["actual_counts_match_expected"] is True + assert validation["valid"] is True