Merge remote-tracking branch 'origin/main' into codex/leo-gcp-runtime-security-20260715
This commit is contained in:
commit
8490a0d8c8
55 changed files with 17291 additions and 970 deletions
212
docs/leo-reproducible-identity.md
Normal file
212
docs/leo-reproducible-identity.md
Normal file
|
|
@ -0,0 +1,212 @@
|
|||
# Reproducible Leo identity
|
||||
|
||||
## Definition of Working
|
||||
|
||||
- **Working target:** generate one pinned Leo identity manifest, compile a
|
||||
disposable profile, answer the fixed identity query in a fresh process,
|
||||
restart in a second process, and reject any drift before an answer.
|
||||
- **Operator path:** run
|
||||
`python -m scripts.run_leo_identity_reconstruction_canary` with the committed
|
||||
identity fixtures from a clean checkout.
|
||||
- **Done means:** the T2 receipt reports two distinct stopped processes with the
|
||||
same manifest, identity inputs, query, answer hash, and output provenance;
|
||||
the second process starts from a newly compiled empty profile; the drift
|
||||
attempt exits before answering; every process group and temporary profile is
|
||||
removed.
|
||||
- **Not done:** a hand-edited `SOUL.md`, a manifest self-hash, unit tests without
|
||||
process restart, or prior VPS restart evidence that did not reconstruct from
|
||||
this manifest.
|
||||
- **Required tier:** `T2_runtime`. T3 VPS restart/readback is a post-merge
|
||||
graduation target.
|
||||
|
||||
## Identity input inventory
|
||||
|
||||
`GatewayRunner` and the surrounding Hermes profile can change an answer through
|
||||
the following surfaces. The manifest either pins each surface or explicitly
|
||||
keeps it outside identity authority.
|
||||
|
||||
| Surface | Binding | Authority |
|
||||
| --- | --- | --- |
|
||||
| Model provider, route, limits, and reasoning settings | secret-free semantic config hash | runtime input; the actual model remains a per-turn receipt |
|
||||
| Hosted model weights | provider-managed, explicitly not locally hashable | never claimed as a local hash |
|
||||
| Hermes and Teleo code | clean Git commits plus executable source-tree hashes | runtime input |
|
||||
| Python ABI and imported runtime packages | exact implementation/version and curated package versions | runtime input |
|
||||
| Skills, plugins, and database tools | content hashes | runtime input |
|
||||
| Gateway/tool permissions | strict allowlisted config hash plus exact no-send/read-only policy | runtime input; this local compiler does not claim an authorizer readback |
|
||||
| Static constitutional rules | committed source path, byte hash, and semantic hash | static authority |
|
||||
| Database snapshot version | database/user/system identity plus content, row, structure, and capture-provenance hashes; only WAL position is excluded | T2 pins a noncanonical fixture; it cannot grant canonical authority |
|
||||
| Database-derived identity rows | typed table/row/kind/rank/evidence bindings plus source mode | synthetic fixtures are explicitly noncanonical; T3 requires independently verified database-exporter output |
|
||||
| `SOUL.md` and `identity.json` | deterministic compiled-view hashes | generated views, never authorities |
|
||||
| Sessions, state, and memory | excluded from the identity input hash and labeled temporary | continuity only; never evidence |
|
||||
|
||||
The disposable profile is compiled from a strict non-secret configuration
|
||||
allowlist; unrecognized transport/credential fields are not copied. Credential
|
||||
values are omitted rather than hashed. Rotating a bot token changes the broad
|
||||
operational behavior observation but does not change Leo's identity.
|
||||
Changing a non-secret permission, model setting, skill, code file, database
|
||||
fingerprint, constitutional rule, database identity row, or compiled view does
|
||||
change a pinned input and fails closed.
|
||||
|
||||
### Current `GatewayRunner` consumption map
|
||||
|
||||
The T2 compiler contract was checked against the current live runtime source.
|
||||
This inventory defines what the post-merge T3 receipt must observe rather than
|
||||
silently assuming that a profile file is the whole prompt:
|
||||
|
||||
- Startup resolves `-p leoclean` to `HERMES_HOME`, then loads profile and project
|
||||
environment files before `config.yaml`; environment expansion, legacy
|
||||
`gateway.json`, and defaults can change the effective configuration. The T2
|
||||
compiler therefore enforces an exact top-level profile allowlist (including
|
||||
rejection of dangling symlinks) rather than relying on a filename denylist.
|
||||
- Routing consumes the requested default model, the top-level
|
||||
`smart_model_routing` switch, provider endpoints/defaults, auth pool choice,
|
||||
reasoning settings, token/turn limits, and fallbacks. The pinned top-level
|
||||
routing switch must be a boolean; arbitrary nested routing data is rejected.
|
||||
Credentials are runtime capability, not identity, and their values are never
|
||||
retained.
|
||||
- Prompt construction consumes generated `SOUL.md`, the gateway/agent system
|
||||
message, persistent `MEMORY.md`/`USER.md`, compiled skills, project-context
|
||||
files, current time/timezone, and the effective model/provider. T2 requires
|
||||
memory and project context absent; T3 records the effective system-prompt and
|
||||
compiled-skills-prompt hashes.
|
||||
- Plugin discovery can include profile plugins, optional project plugins, and
|
||||
installed entry points. The live database-context hook can inject a
|
||||
query-bound contract before the model and can reject or replace the reply
|
||||
afterward, so T3 retains plugin registry, contract, retrieval, and delivered
|
||||
response hashes.
|
||||
- Effective tools come from platform toolsets and the runtime registry, not a
|
||||
descriptive fixture field. T3 must read back exact tool schemas, prove the
|
||||
send tool absent, and keep terminal restricted to the clone-bound read-only
|
||||
wrapper.
|
||||
- Authorization consumes chat/user allowlists and pairing-store state. T2 starts
|
||||
with pairing absent; T3 records the fixed synthetic source and the actual
|
||||
authorization decision without exposing IDs or tokens.
|
||||
- Session keys consume platform/chat/user/thread/topic fields. Auto-skill,
|
||||
reply/media/file context, persisted transcripts, and a reused system prompt
|
||||
can all change a turn. Verification therefore happens before every child
|
||||
starts, and T3 binds session key, persisted session ID, message-context
|
||||
absence, and prompt hashes.
|
||||
|
||||
The committed T2 database/identity inputs are synthetic fixtures and the
|
||||
compiled view labels them `synthetic_noncanonical_fixture`; they do not stand
|
||||
in for approved production rows. This T2 schema never grants canonical
|
||||
authority from caller-supplied or merely self-hashed JSON. T3 must use output
|
||||
that is independently verified by the database-owning same-transaction exporter
|
||||
and bound to the database fingerprint, database user, system identifier, and
|
||||
row digest.
|
||||
|
||||
Every pinned source tree and profile component is structurally revalidated:
|
||||
the verifier recomputes its file count, total bytes, sorted unique paths, and
|
||||
canonical content hash, and rejects missing files, unreadable entries, or
|
||||
symlinks. Rehashing forged structural metadata cannot make it authoritative.
|
||||
|
||||
The current live Hermes checkout is not clean, so its Git SHA alone is not a
|
||||
reproducible source bundle. This T2 receipt intentionally uses the committed
|
||||
clean local runtime and the committed database/identity snapshot fixture. It
|
||||
does not claim to reconstruct the current dirty VPS runtime. T3 must run only
|
||||
after the merged identity code is deployed and must bind the deployed clean
|
||||
content (or a content-addressed dirty-source bundle if the live checkout has not
|
||||
yet been repaired).
|
||||
|
||||
## Commands
|
||||
|
||||
The complete canary is the preferred operator command:
|
||||
|
||||
```bash
|
||||
python -m scripts.run_leo_identity_reconstruction_canary \
|
||||
--profile-template fixtures/working-leo/leo-identity-v1/profile-template \
|
||||
--hermes-root fixtures/working-leo/leo-identity-v1/hermes-runtime \
|
||||
--deployment-root . \
|
||||
--source-root . \
|
||||
--database-fingerprint fixtures/working-leo/leo-identity-v1/leo-database-fingerprint-v1.json \
|
||||
--constitution fixtures/working-leo/leo-identity-v1/leo-constitution-v1.json \
|
||||
--database-identity fixtures/working-leo/leo-identity-v1/leo-database-identity-v1.json \
|
||||
--output docs/reports/leo-working-state-20260709/leo-reproducible-identity-t2-current.json
|
||||
```
|
||||
|
||||
The negative lifecycle is separately runnable. It proves drift is caught before
|
||||
the second process starts:
|
||||
|
||||
```bash
|
||||
python -m scripts.run_leo_identity_reconstruction_canary \
|
||||
--profile-template fixtures/working-leo/leo-identity-v1/profile-template \
|
||||
--hermes-root fixtures/working-leo/leo-identity-v1/hermes-runtime \
|
||||
--deployment-root . \
|
||||
--source-root . \
|
||||
--database-fingerprint fixtures/working-leo/leo-identity-v1/leo-database-fingerprint-v1.json \
|
||||
--constitution fixtures/working-leo/leo-identity-v1/leo-constitution-v1.json \
|
||||
--database-identity fixtures/working-leo/leo-identity-v1/leo-database-identity-v1.json \
|
||||
--inject-drift-before-restart \
|
||||
--output /tmp/leo-identity-drift-rejection.json
|
||||
```
|
||||
|
||||
For inspection, the lifecycle can be decomposed into explicit manifest and
|
||||
compile commands:
|
||||
|
||||
```bash
|
||||
python -m scripts.leo_behavior_manifest \
|
||||
--profile fixtures/working-leo/leo-identity-v1/profile-template \
|
||||
--hermes-root fixtures/working-leo/leo-identity-v1/hermes-runtime \
|
||||
--deployment-root . \
|
||||
--output /tmp/leo-behavior.json
|
||||
|
||||
python -m scripts.leo_identity_manifest generate \
|
||||
--behavior-manifest /tmp/leo-behavior.json \
|
||||
--database-fingerprint fixtures/working-leo/leo-identity-v1/leo-database-fingerprint-v1.json \
|
||||
--constitution fixtures/working-leo/leo-identity-v1/leo-constitution-v1.json \
|
||||
--database-identity fixtures/working-leo/leo-identity-v1/leo-database-identity-v1.json \
|
||||
--source-root . \
|
||||
--output /tmp/leo-identity-manifest.json
|
||||
|
||||
python -m scripts.leo_identity_profile compile \
|
||||
--manifest /tmp/leo-identity-manifest.json \
|
||||
--source-root . \
|
||||
--profile-template fixtures/working-leo/leo-identity-v1/profile-template \
|
||||
--profile /tmp/leo-disposable-profile \
|
||||
--hermes-root fixtures/working-leo/leo-identity-v1/hermes-runtime \
|
||||
--deployment-root .
|
||||
```
|
||||
|
||||
All commands require a clean Git worktree because a commit plus an unretained
|
||||
dirty source tree is not reproducible.
|
||||
|
||||
Child processes execute the real interpreter and temporary-profile paths only
|
||||
in process-local memory. Retained receipts persist a repo-relative
|
||||
`logical_command`, the stable `<python>` and `<temporary-profile>` placeholders,
|
||||
and an explicit `profile_role`; they never serialize the checkout, interpreter,
|
||||
or temporary directory path.
|
||||
|
||||
## State inventory and transitions
|
||||
|
||||
| State | Meaning | Next valid transition |
|
||||
| --- | --- | --- |
|
||||
| `inputs_unverified` | source paths exist but are not yet bound | validate clean Git, runtime, DB, rules, rows, and permissions |
|
||||
| `manifest_pinned` | every material identity input has a stable hash | compile deterministic views |
|
||||
| `profile_compiled` | static profile copied and generated views match the manifest | verify immediately before start |
|
||||
| `runtime_verified` | runtime/code/view hashes match and session state is non-authoritative | answer fixed query |
|
||||
| `stopped_cleanly` | child and process group are absent | compile a new empty profile from the manifest |
|
||||
| `restart_reproduced` | child from the newly compiled profile has the same identity/query/provenance inputs | retain receipt and clean every profile |
|
||||
| `drift_detected` | any input or generated view differs | fail closed; no answer and no next start |
|
||||
|
||||
The irreversible boundary is not a database or production mutation: this T2
|
||||
canary is a local compiler/process runtime, no-send, database-read-only, and
|
||||
disposable. The successful-restart receipt reaches `T2_runtime`; the standalone
|
||||
pre-restart drift receipt is a passing negative component but reports
|
||||
`T1_model` and `goal_tier_satisfied=false`. Neither proves the live VPS
|
||||
`GatewayRunner`, Telegram delivery, hosted-model behavior, production database
|
||||
state, or T3 restart recovery.
|
||||
|
||||
Here `T2_runtime` uses the required Capability Tier Proof vocabulary: local
|
||||
runtime behavior with restart. It does not imply Hermes/GatewayRunner or a
|
||||
hosted model; those exclusions are explicit in the receipt's `runtime_variant`,
|
||||
`tier_basis`, and `claim_ceiling`.
|
||||
|
||||
## T3 graduation
|
||||
|
||||
After merge and rollback proof, extend the schema with independent verification
|
||||
of the database-owning same-transaction exporter, generate the manifest from
|
||||
that live read-only canonical capture and deployed clean commits, compile a
|
||||
disposable VPS profile, invoke the real no-send `GatewayRunner`, terminate that
|
||||
child, open a new child from the same manifest, and retain model-call, DB-read,
|
||||
service, cleanup, and drift-negative readbacks. Do not replace the production
|
||||
profile during that graduation.
|
||||
|
|
@ -0,0 +1,332 @@
|
|||
{
|
||||
"actual_hosted_model_call_performed": false,
|
||||
"behavior_observation_before_compile": {
|
||||
"behavior_sha256": "693a5d542e3d817c1c77c8aa3180f14d5f98ec1e71f5e4313685b4da70b489aa",
|
||||
"identity_runtime_sha256": "5c54248a5d1f00b35912d47d8b3045b8cfbed16ae9b86409b549ab7042f51159",
|
||||
"source_commit": "b238fd6fc2636ed3582e14900774014c52732698"
|
||||
},
|
||||
"claim_ceiling": "Local first-process and pre-restart drift-refusal component only; no successful restart proof, GatewayRunner, hosted model, production database, VPS, or T3 claim.",
|
||||
"cleanup": {
|
||||
"no_profile_retained": true,
|
||||
"temporary_root_removed": true
|
||||
},
|
||||
"compile": {
|
||||
"compiled_view_sha256": {
|
||||
"SOUL.md": "83d27dba6e1b160085388a5dc84da565abf5736351b1af3f220d13b35aac244a",
|
||||
"identity.json": "40419152862e7d9bca631c53eaa2201052cf61eafe6d304c8a302f8ea97d6fb6"
|
||||
},
|
||||
"generated_views_are_authority": false,
|
||||
"identity_inputs_sha256": "c101c488a9f623b4cef841ddb561c0f289a74df54aadfdfe9b28c4b7643fec2e",
|
||||
"manifest_sha256": "22e66cf39b2c5aac3b4043f37aa0773b4861fec616a435e8b5e0ff8c86586bef",
|
||||
"nonauthoritative_inputs_omitted": {
|
||||
".cursorrules": true,
|
||||
".hermes.md": true,
|
||||
".skills_prompt_snapshot.json": true,
|
||||
"AGENTS.md": true,
|
||||
"CLAUDE.md": true,
|
||||
"HERMES.md": true,
|
||||
"MEMORY.md": true,
|
||||
"USER.md": true,
|
||||
"memories": true,
|
||||
"platforms/pairing": true
|
||||
},
|
||||
"profile_static_entries": [
|
||||
"config.yaml",
|
||||
"skills",
|
||||
"plugins",
|
||||
"bin"
|
||||
],
|
||||
"runtime_identity_sha256": "5c54248a5d1f00b35912d47d8b3045b8cfbed16ae9b86409b549ab7042f51159",
|
||||
"schema": "livingip.leoIdentityCompileReceipt.v1",
|
||||
"session_directories_started_empty": true,
|
||||
"status": "pass"
|
||||
},
|
||||
"compiled_profile_before_query": {
|
||||
"behavior_sha256": "a62b26015a7c9506f0296404be150608a816a2d545f471f7960bd27324d6849c",
|
||||
"identity_runtime_sha256": "5c54248a5d1f00b35912d47d8b3045b8cfbed16ae9b86409b549ab7042f51159"
|
||||
},
|
||||
"current_tier": "T1_model",
|
||||
"drift_target": "compiled SOUL.md generated view",
|
||||
"errors": [],
|
||||
"first_start": {
|
||||
"actual_argv_persisted": false,
|
||||
"command_serialization": "logical_redacted_v1",
|
||||
"launcher_pid": 80040,
|
||||
"logical_command": [
|
||||
"<python>",
|
||||
"-m",
|
||||
"scripts.leo_identity_profile",
|
||||
"query",
|
||||
"--profile",
|
||||
"<temporary-profile>",
|
||||
"--source-root",
|
||||
".",
|
||||
"--hermes-root",
|
||||
"fixtures/working-leo/leo-identity-v1/hermes-runtime",
|
||||
"--deployment-root",
|
||||
".",
|
||||
"--query",
|
||||
"What defines Leo's identity, and what is temporary?"
|
||||
],
|
||||
"orphan_cleanup_required": false,
|
||||
"process_group_absent_after_wait": true,
|
||||
"profile_role": "first_start",
|
||||
"returncode": 0,
|
||||
"stderr_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
|
||||
"stdout": {
|
||||
"answer": "Leo is defined by 3 pinned static constitutional rules and 5 active database-derived identity rows from a synthetic noncanonical fixture at fingerprint 1111111111111111111111111111111111111111111111111111111111111111. SOUL.md is a generated view; runtime/session memory is temporary, noncanonical, and cannot be evidence.",
|
||||
"answer_sha256": "e0a21e1fc5357a2f358b4e96c52e971f3addee2468e44748d898adfd62dafa25",
|
||||
"authorization": {
|
||||
"authorization_decision_observed": false,
|
||||
"claim": "local_policy_binding_not_an_authorizer_readback",
|
||||
"declared_runtime_policy": {
|
||||
"allowed_tools": [
|
||||
"identity_readback"
|
||||
],
|
||||
"database_write_enabled": false,
|
||||
"network_send_enabled": false
|
||||
}
|
||||
},
|
||||
"identity_inputs_sha256": "c101c488a9f623b4cef841ddb561c0f289a74df54aadfdfe9b28c4b7643fec2e",
|
||||
"manifest_sha256": "22e66cf39b2c5aac3b4043f37aa0773b4861fec616a435e8b5e0ff8c86586bef",
|
||||
"output_provenance": {
|
||||
"actual_model_call_performed": false,
|
||||
"compiled_identity_sha256": "40419152862e7d9bca631c53eaa2201052cf61eafe6d304c8a302f8ea97d6fb6",
|
||||
"compiled_soul_sha256": "83d27dba6e1b160085388a5dc84da565abf5736351b1af3f220d13b35aac244a",
|
||||
"database_authority": "synthetic_noncanonical_fixture",
|
||||
"database_canonical_authority_granted": false,
|
||||
"database_fingerprint_sha256": "1111111111111111111111111111111111111111111111111111111111111111",
|
||||
"database_identity_sha256": "70aaa7287cc41b52a3c902cf2e1b90fa4d84a5ee0a61e10c642f556fcc9304c3",
|
||||
"runtime_identity_sha256": "5c54248a5d1f00b35912d47d8b3045b8cfbed16ae9b86409b549ab7042f51159",
|
||||
"static_constitution_sha256": "b576d5cee08530a95e0b196a3296f4743b70d94bcadffaa36544dd6bf1387f8a"
|
||||
},
|
||||
"process_id": 80040,
|
||||
"query": "What defines Leo's identity, and what is temporary?",
|
||||
"query_sha256": "13704c2c9ae999e3f9b3f1c9c5572d062cd7fe49903c2317fa85aaa39490af66",
|
||||
"runtime_instance_id": "493f274a5f0340a2aa675f13b8e5b4af",
|
||||
"schema": "livingip.leoIdentityQueryReceipt.v1",
|
||||
"session": {
|
||||
"classification": "temporary_noncanonical",
|
||||
"included_in_output_provenance": false,
|
||||
"may_be_used_as_evidence": false,
|
||||
"record_sha256": "56b6a2ea25657a87dc90dc19f49bece0ac62241f5814732ed80ef4f34d426d84"
|
||||
},
|
||||
"started_at_utc": "2026-07-15T02:46:34.316819+00:00",
|
||||
"status": "pass"
|
||||
},
|
||||
"terminated_with": null,
|
||||
"timed_out": false
|
||||
},
|
||||
"fixed_query": "What defines Leo's identity, and what is temporary?",
|
||||
"fixed_query_sha256": "13704c2c9ae999e3f9b3f1c9c5572d062cd7fe49903c2317fa85aaa39490af66",
|
||||
"gates": {
|
||||
"drift_detected_before_restart": true,
|
||||
"drift_process_had_no_orphan_cleanup": true,
|
||||
"drift_process_stopped": true,
|
||||
"drift_returned_no_answer": true,
|
||||
"first_process_stopped": true,
|
||||
"first_start_passed": true,
|
||||
"second_start_not_attempted": true
|
||||
},
|
||||
"generated_at_utc": "2026-07-15T02:46:31.831631+00:00",
|
||||
"goal_tier_satisfied": false,
|
||||
"manifest": {
|
||||
"compiled_views": {
|
||||
"SOUL.md": {
|
||||
"generated_from_identity_inputs_sha256": "c101c488a9f623b4cef841ddb561c0f289a74df54aadfdfe9b28c4b7643fec2e",
|
||||
"role": "generated_view_not_authority",
|
||||
"sha256": "83d27dba6e1b160085388a5dc84da565abf5736351b1af3f220d13b35aac244a"
|
||||
},
|
||||
"identity.json": {
|
||||
"generated_from_identity_inputs_sha256": "c101c488a9f623b4cef841ddb561c0f289a74df54aadfdfe9b28c4b7643fec2e",
|
||||
"role": "generated_view_not_authority",
|
||||
"sha256": "40419152862e7d9bca631c53eaa2201052cf61eafe6d304c8a302f8ea97d6fb6"
|
||||
}
|
||||
},
|
||||
"identity_inputs": {
|
||||
"canonical_database": {
|
||||
"authority": "synthetic_noncanonical_fixture",
|
||||
"canonical_authority_granted": false,
|
||||
"database": "leo_identity_fixture",
|
||||
"database_user": "leo_identity_reader",
|
||||
"fingerprint_sha256": "1111111111111111111111111111111111111111111111111111111111111111",
|
||||
"source": {
|
||||
"record_count": 7,
|
||||
"repo_path": "fixtures/working-leo/leo-identity-v1/leo-database-fingerprint-v1.json",
|
||||
"semantic_sha256": "c5bbf346613270a5e3b17f604f69306ed42f545d4f227d784ec0dcb3d675dcb2"
|
||||
},
|
||||
"structure_sha256": "3333333333333333333333333333333333333333333333333333333333333333",
|
||||
"system_identifier": "7649789040005668902",
|
||||
"table_count": 7,
|
||||
"table_rows_sha256": "2222222222222222222222222222222222222222222222222222222222222222",
|
||||
"total_rows": 7
|
||||
},
|
||||
"gatewayrunner_execution_contract": {
|
||||
"fixed_message_context": {
|
||||
"auto_skill": null,
|
||||
"media_or_file_context": null,
|
||||
"reply_context": null
|
||||
},
|
||||
"profile_surfaces": [
|
||||
"config.yaml",
|
||||
"generated SOUL.md",
|
||||
"skills",
|
||||
"plugins",
|
||||
"bin tools"
|
||||
],
|
||||
"required_absent_or_empty": {
|
||||
"generated_skill_prompt_cache": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945",
|
||||
"pairing_store": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945",
|
||||
"persistent_memory": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945",
|
||||
"prior_sessions_at_first_start": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945",
|
||||
"project_context": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945"
|
||||
},
|
||||
"required_t3_turn_receipt_fields": [
|
||||
"runner_class",
|
||||
"authorization_decision",
|
||||
"effective_system_prompt_sha256",
|
||||
"compiled_skills_prompt_sha256",
|
||||
"tool_registry_schema_sha256",
|
||||
"plugin_registry_sha256",
|
||||
"selected_model",
|
||||
"selected_provider",
|
||||
"api_mode",
|
||||
"base_url_host",
|
||||
"database_retrieval_receipt",
|
||||
"session_key_sha256",
|
||||
"persisted_session_id_sha256"
|
||||
]
|
||||
},
|
||||
"identity_name": "Leo",
|
||||
"identity_sources": {
|
||||
"database_derived_identity": {
|
||||
"authority": "synthetic_noncanonical_fixture",
|
||||
"content_sha256": "9de2dfa37529b23ba277348f3d910e967551e490a9b4d2be637bf45bb2aa7dde",
|
||||
"database_fingerprint_sha256": "1111111111111111111111111111111111111111111111111111111111111111",
|
||||
"provenance": {
|
||||
"authority": "synthetic_noncanonical_fixture",
|
||||
"canonical_authority_granted": false,
|
||||
"export_receipt_sha256": null,
|
||||
"mode": "synthetic_noncanonical_fixture",
|
||||
"same_transaction_as_fingerprint": false
|
||||
},
|
||||
"record_count": 5,
|
||||
"repo_path": "fixtures/working-leo/leo-identity-v1/leo-database-identity-v1.json",
|
||||
"semantic_sha256": "70aaa7287cc41b52a3c902cf2e1b90fa4d84a5ee0a61e10c642f556fcc9304c3"
|
||||
},
|
||||
"static_constitution": {
|
||||
"authority": "pinned_static_source",
|
||||
"content_sha256": "b5477e778a2be0abba783390dac2e04ed199b8ce5679fc324270f808d46543f1",
|
||||
"record_count": 3,
|
||||
"repo_path": "fixtures/working-leo/leo-identity-v1/leo-constitution-v1.json",
|
||||
"semantic_sha256": "b576d5cee08530a95e0b196a3296f4743b70d94bcadffaa36544dd6bf1387f8a"
|
||||
}
|
||||
},
|
||||
"model": {
|
||||
"actual_model_required_in_turn_receipt": true,
|
||||
"default_model": "leo-identity-readback-v1",
|
||||
"gateway_smart_model_routing": null,
|
||||
"hosted_weights": "external_provider_managed_not_locally_hashable",
|
||||
"model_section_sha256": "90b3943ace9ff83b1711002fda8dc9736448e8d3c1c58a17ac90608f4ce58756",
|
||||
"provider": "fixture-local",
|
||||
"smart_routing": false,
|
||||
"smart_routing_model": null
|
||||
},
|
||||
"permissions": {
|
||||
"authorization_decision_required_in_runtime_receipt": true,
|
||||
"gateway_permissions_sha256": "eac17ada1d02b5413183587d12fc265538479de00709ed8c275e9045cd720290",
|
||||
"identity_config_sha256": "e6df9b65bab148ea8502555bbc260df66b4785e7dd527cfd15d2f0a48c2e8b3e",
|
||||
"runtime_policy": {
|
||||
"allowed_tools": [
|
||||
"identity_readback"
|
||||
],
|
||||
"database_write_enabled": false,
|
||||
"network_send_enabled": false
|
||||
},
|
||||
"tool_permissions_sha256": "9bb2cec2f65d43efb597a72bdced44076c25aac292f2fccbc4c448b6e7fd3e16"
|
||||
},
|
||||
"runtime": {
|
||||
"hermes_git_head": "b238fd6fc2636ed3582e14900774014c52732698",
|
||||
"hermes_source_sha256": "dcf8109051e0b69cafe2e8dd328ff501211b62ea19725416c3781bbdd594d028",
|
||||
"identity_runtime_sha256": "5c54248a5d1f00b35912d47d8b3045b8cfbed16ae9b86409b549ab7042f51159",
|
||||
"python": {
|
||||
"abi_tag": "cpython-311",
|
||||
"implementation": "CPython",
|
||||
"python_version": "3.11.15",
|
||||
"runtime_distributions": {
|
||||
"PyYAML": "6.0.3"
|
||||
},
|
||||
"runtime_distributions_sha256": "57a91bb880a01800903c1604b6eec1419514864ebd6a0644121920da15a8f165"
|
||||
},
|
||||
"teleo_git_head": "b238fd6fc2636ed3582e14900774014c52732698",
|
||||
"teleo_source_sha256": "2bd2e659eafb0ac0823f7f51c4296b2eb500b6f74469b3ac5f5287a5d4810aea"
|
||||
},
|
||||
"session_boundary": {
|
||||
"classification": "temporary_noncanonical",
|
||||
"included_in_identity_inputs": false,
|
||||
"may_be_used_as_evidence": false,
|
||||
"restart_policy": "fresh_process_with_session_state_outside_identity_authority"
|
||||
},
|
||||
"skills": {
|
||||
"content_sha256": "d3f449ddcd7c88238dc88c6233cf2130875f51bd2e0911b2ce477b7c602ae90f",
|
||||
"file_count": 1
|
||||
},
|
||||
"source_commit": "b238fd6fc2636ed3582e14900774014c52732698"
|
||||
},
|
||||
"identity_inputs_sha256": "c101c488a9f623b4cef841ddb561c0f289a74df54aadfdfe9b28c4b7643fec2e",
|
||||
"manifest_sha256": "22e66cf39b2c5aac3b4043f37aa0773b4861fec616a435e8b5e0ff8c86586bef",
|
||||
"schema": "livingip.leoIdentityManifest.v1"
|
||||
},
|
||||
"mode": "drift_before_restart",
|
||||
"pre_restart_drift": {
|
||||
"actual_argv_persisted": false,
|
||||
"command_serialization": "logical_redacted_v1",
|
||||
"launcher_pid": 80246,
|
||||
"logical_command": [
|
||||
"<python>",
|
||||
"-m",
|
||||
"scripts.leo_identity_profile",
|
||||
"query",
|
||||
"--profile",
|
||||
"<temporary-profile>",
|
||||
"--source-root",
|
||||
".",
|
||||
"--hermes-root",
|
||||
"fixtures/working-leo/leo-identity-v1/hermes-runtime",
|
||||
"--deployment-root",
|
||||
".",
|
||||
"--query",
|
||||
"What defines Leo's identity, and what is temporary?"
|
||||
],
|
||||
"orphan_cleanup_required": false,
|
||||
"process_group_absent_after_wait": true,
|
||||
"profile_role": "pre_restart_drift",
|
||||
"returncode": 3,
|
||||
"stderr_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
|
||||
"stdout": {
|
||||
"error": "identity_drift",
|
||||
"message": "compiled view drift detected: SOUL.md",
|
||||
"status": "error"
|
||||
},
|
||||
"terminated_with": null,
|
||||
"timed_out": false
|
||||
},
|
||||
"production_database_contacted": false,
|
||||
"production_profile_replaced": false,
|
||||
"receipt_sha256": "50278cc740d0427316f73a78abad840b3e3b128a516f464001d42e632e19c2a8",
|
||||
"required_tier": "T2_runtime",
|
||||
"runtime_component_proven": "first_local_process_plus_pre_restart_drift_refusal",
|
||||
"runtime_variant": "local_deterministic_identity_compiler_readback",
|
||||
"schema": "livingip.leoIdentityReconstructionReceipt.v1",
|
||||
"second_start_attempted": false,
|
||||
"session_boundary_readback": {
|
||||
"full_behavior_changed_after_session": true,
|
||||
"identity_runtime_unchanged_after_session": true,
|
||||
"session_classification": "temporary_noncanonical",
|
||||
"session_file_count": 1,
|
||||
"session_used_as_output_provenance": false
|
||||
},
|
||||
"status": "pass",
|
||||
"telegram_message_sent": false,
|
||||
"tier_basis": "This negative component does not complete the required restart path, so it remains below T2_runtime."
|
||||
}
|
||||
|
|
@ -0,0 +1,478 @@
|
|||
{
|
||||
"actual_hosted_model_call_performed": false,
|
||||
"behavior_observation_before_compile": {
|
||||
"behavior_sha256": "693a5d542e3d817c1c77c8aa3180f14d5f98ec1e71f5e4313685b4da70b489aa",
|
||||
"identity_runtime_sha256": "5c54248a5d1f00b35912d47d8b3045b8cfbed16ae9b86409b549ab7042f51159",
|
||||
"source_commit": "b238fd6fc2636ed3582e14900774014c52732698"
|
||||
},
|
||||
"claim_ceiling": "Local disposable identity compilation, fresh-profile reconstruction, and cold-process restart only; not a live GatewayRunner, hosted-model, Telegram, production database, VPS restart, or T3 proof.",
|
||||
"cleanup": {
|
||||
"no_profile_retained": true,
|
||||
"temporary_root_removed": true
|
||||
},
|
||||
"compile": {
|
||||
"compiled_view_sha256": {
|
||||
"SOUL.md": "83d27dba6e1b160085388a5dc84da565abf5736351b1af3f220d13b35aac244a",
|
||||
"identity.json": "40419152862e7d9bca631c53eaa2201052cf61eafe6d304c8a302f8ea97d6fb6"
|
||||
},
|
||||
"generated_views_are_authority": false,
|
||||
"identity_inputs_sha256": "c101c488a9f623b4cef841ddb561c0f289a74df54aadfdfe9b28c4b7643fec2e",
|
||||
"manifest_sha256": "22e66cf39b2c5aac3b4043f37aa0773b4861fec616a435e8b5e0ff8c86586bef",
|
||||
"nonauthoritative_inputs_omitted": {
|
||||
".cursorrules": true,
|
||||
".hermes.md": true,
|
||||
".skills_prompt_snapshot.json": true,
|
||||
"AGENTS.md": true,
|
||||
"CLAUDE.md": true,
|
||||
"HERMES.md": true,
|
||||
"MEMORY.md": true,
|
||||
"USER.md": true,
|
||||
"memories": true,
|
||||
"platforms/pairing": true
|
||||
},
|
||||
"profile_static_entries": [
|
||||
"config.yaml",
|
||||
"skills",
|
||||
"plugins",
|
||||
"bin"
|
||||
],
|
||||
"runtime_identity_sha256": "5c54248a5d1f00b35912d47d8b3045b8cfbed16ae9b86409b549ab7042f51159",
|
||||
"schema": "livingip.leoIdentityCompileReceipt.v1",
|
||||
"session_directories_started_empty": true,
|
||||
"status": "pass"
|
||||
},
|
||||
"compiled_profile_before_query": {
|
||||
"behavior_sha256": "a62b26015a7c9506f0296404be150608a816a2d545f471f7960bd27324d6849c",
|
||||
"identity_runtime_sha256": "5c54248a5d1f00b35912d47d8b3045b8cfbed16ae9b86409b549ab7042f51159"
|
||||
},
|
||||
"current_tier": "T2_runtime",
|
||||
"drift_compile": {
|
||||
"compiled_view_sha256": {
|
||||
"SOUL.md": "83d27dba6e1b160085388a5dc84da565abf5736351b1af3f220d13b35aac244a",
|
||||
"identity.json": "40419152862e7d9bca631c53eaa2201052cf61eafe6d304c8a302f8ea97d6fb6"
|
||||
},
|
||||
"generated_views_are_authority": false,
|
||||
"identity_inputs_sha256": "c101c488a9f623b4cef841ddb561c0f289a74df54aadfdfe9b28c4b7643fec2e",
|
||||
"manifest_sha256": "22e66cf39b2c5aac3b4043f37aa0773b4861fec616a435e8b5e0ff8c86586bef",
|
||||
"nonauthoritative_inputs_omitted": {
|
||||
".cursorrules": true,
|
||||
".hermes.md": true,
|
||||
".skills_prompt_snapshot.json": true,
|
||||
"AGENTS.md": true,
|
||||
"CLAUDE.md": true,
|
||||
"HERMES.md": true,
|
||||
"MEMORY.md": true,
|
||||
"USER.md": true,
|
||||
"memories": true,
|
||||
"platforms/pairing": true
|
||||
},
|
||||
"profile_static_entries": [
|
||||
"config.yaml",
|
||||
"skills",
|
||||
"plugins",
|
||||
"bin"
|
||||
],
|
||||
"runtime_identity_sha256": "5c54248a5d1f00b35912d47d8b3045b8cfbed16ae9b86409b549ab7042f51159",
|
||||
"schema": "livingip.leoIdentityCompileReceipt.v1",
|
||||
"session_directories_started_empty": true,
|
||||
"status": "pass"
|
||||
},
|
||||
"drift_negative": {
|
||||
"actual_argv_persisted": false,
|
||||
"answer_returned": false,
|
||||
"command_serialization": "logical_redacted_v1",
|
||||
"fail_closed": true,
|
||||
"launcher_pid": 80851,
|
||||
"logical_command": [
|
||||
"<python>",
|
||||
"-m",
|
||||
"scripts.leo_identity_profile",
|
||||
"query",
|
||||
"--profile",
|
||||
"<temporary-profile>",
|
||||
"--source-root",
|
||||
".",
|
||||
"--hermes-root",
|
||||
"fixtures/working-leo/leo-identity-v1/hermes-runtime",
|
||||
"--deployment-root",
|
||||
".",
|
||||
"--query",
|
||||
"What defines Leo's identity, and what is temporary?"
|
||||
],
|
||||
"orphan_cleanup_required": false,
|
||||
"process_group_absent_after_wait": true,
|
||||
"profile_role": "drift_negative",
|
||||
"returncode": 3,
|
||||
"stderr_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
|
||||
"stdout": {
|
||||
"error": "identity_drift",
|
||||
"message": "compiled view drift detected: SOUL.md",
|
||||
"status": "error"
|
||||
},
|
||||
"terminated_with": null,
|
||||
"timed_out": false
|
||||
},
|
||||
"drift_target": "compiled SOUL.md generated view",
|
||||
"errors": [],
|
||||
"first_start": {
|
||||
"actual_argv_persisted": false,
|
||||
"command_serialization": "logical_redacted_v1",
|
||||
"launcher_pid": 80054,
|
||||
"logical_command": [
|
||||
"<python>",
|
||||
"-m",
|
||||
"scripts.leo_identity_profile",
|
||||
"query",
|
||||
"--profile",
|
||||
"<temporary-profile>",
|
||||
"--source-root",
|
||||
".",
|
||||
"--hermes-root",
|
||||
"fixtures/working-leo/leo-identity-v1/hermes-runtime",
|
||||
"--deployment-root",
|
||||
".",
|
||||
"--query",
|
||||
"What defines Leo's identity, and what is temporary?"
|
||||
],
|
||||
"orphan_cleanup_required": false,
|
||||
"process_group_absent_after_wait": true,
|
||||
"profile_role": "first_start",
|
||||
"returncode": 0,
|
||||
"stderr_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
|
||||
"stdout": {
|
||||
"answer": "Leo is defined by 3 pinned static constitutional rules and 5 active database-derived identity rows from a synthetic noncanonical fixture at fingerprint 1111111111111111111111111111111111111111111111111111111111111111. SOUL.md is a generated view; runtime/session memory is temporary, noncanonical, and cannot be evidence.",
|
||||
"answer_sha256": "e0a21e1fc5357a2f358b4e96c52e971f3addee2468e44748d898adfd62dafa25",
|
||||
"authorization": {
|
||||
"authorization_decision_observed": false,
|
||||
"claim": "local_policy_binding_not_an_authorizer_readback",
|
||||
"declared_runtime_policy": {
|
||||
"allowed_tools": [
|
||||
"identity_readback"
|
||||
],
|
||||
"database_write_enabled": false,
|
||||
"network_send_enabled": false
|
||||
}
|
||||
},
|
||||
"identity_inputs_sha256": "c101c488a9f623b4cef841ddb561c0f289a74df54aadfdfe9b28c4b7643fec2e",
|
||||
"manifest_sha256": "22e66cf39b2c5aac3b4043f37aa0773b4861fec616a435e8b5e0ff8c86586bef",
|
||||
"output_provenance": {
|
||||
"actual_model_call_performed": false,
|
||||
"compiled_identity_sha256": "40419152862e7d9bca631c53eaa2201052cf61eafe6d304c8a302f8ea97d6fb6",
|
||||
"compiled_soul_sha256": "83d27dba6e1b160085388a5dc84da565abf5736351b1af3f220d13b35aac244a",
|
||||
"database_authority": "synthetic_noncanonical_fixture",
|
||||
"database_canonical_authority_granted": false,
|
||||
"database_fingerprint_sha256": "1111111111111111111111111111111111111111111111111111111111111111",
|
||||
"database_identity_sha256": "70aaa7287cc41b52a3c902cf2e1b90fa4d84a5ee0a61e10c642f556fcc9304c3",
|
||||
"runtime_identity_sha256": "5c54248a5d1f00b35912d47d8b3045b8cfbed16ae9b86409b549ab7042f51159",
|
||||
"static_constitution_sha256": "b576d5cee08530a95e0b196a3296f4743b70d94bcadffaa36544dd6bf1387f8a"
|
||||
},
|
||||
"process_id": 80054,
|
||||
"query": "What defines Leo's identity, and what is temporary?",
|
||||
"query_sha256": "13704c2c9ae999e3f9b3f1c9c5572d062cd7fe49903c2317fa85aaa39490af66",
|
||||
"runtime_instance_id": "4bbcaeeeb5654b69adabed33b91cf3e4",
|
||||
"schema": "livingip.leoIdentityQueryReceipt.v1",
|
||||
"session": {
|
||||
"classification": "temporary_noncanonical",
|
||||
"included_in_output_provenance": false,
|
||||
"may_be_used_as_evidence": false,
|
||||
"record_sha256": "56b6a2ea25657a87dc90dc19f49bece0ac62241f5814732ed80ef4f34d426d84"
|
||||
},
|
||||
"started_at_utc": "2026-07-15T02:46:34.391880+00:00",
|
||||
"status": "pass"
|
||||
},
|
||||
"terminated_with": null,
|
||||
"timed_out": false
|
||||
},
|
||||
"fixed_query": "What defines Leo's identity, and what is temporary?",
|
||||
"fixed_query_sha256": "13704c2c9ae999e3f9b3f1c9c5572d062cd7fe49903c2317fa85aaa39490af66",
|
||||
"gates": {
|
||||
"answer_and_provenance_explainable": true,
|
||||
"drift_failed_closed": true,
|
||||
"drift_process_had_no_orphan_cleanup": true,
|
||||
"drift_process_stopped": true,
|
||||
"drift_profile_started_without_sessions": true,
|
||||
"first_process_stopped": true,
|
||||
"first_start_passed": true,
|
||||
"identity_inputs_reproduced": true,
|
||||
"manifest_generated": true,
|
||||
"manifest_reproduced": true,
|
||||
"pre_restart_verification_passed": true,
|
||||
"query_reproduced": true,
|
||||
"restart_passed": true,
|
||||
"restart_process_is_distinct": true,
|
||||
"restart_process_stopped": true,
|
||||
"restart_profile_recompiled_from_manifest": true,
|
||||
"restart_profile_started_without_sessions": true,
|
||||
"session_excluded_from_identity": true,
|
||||
"views_compiled_and_bound": true
|
||||
},
|
||||
"generated_at_utc": "2026-07-15T02:46:31.346851+00:00",
|
||||
"goal_tier_satisfied": true,
|
||||
"manifest": {
|
||||
"compiled_views": {
|
||||
"SOUL.md": {
|
||||
"generated_from_identity_inputs_sha256": "c101c488a9f623b4cef841ddb561c0f289a74df54aadfdfe9b28c4b7643fec2e",
|
||||
"role": "generated_view_not_authority",
|
||||
"sha256": "83d27dba6e1b160085388a5dc84da565abf5736351b1af3f220d13b35aac244a"
|
||||
},
|
||||
"identity.json": {
|
||||
"generated_from_identity_inputs_sha256": "c101c488a9f623b4cef841ddb561c0f289a74df54aadfdfe9b28c4b7643fec2e",
|
||||
"role": "generated_view_not_authority",
|
||||
"sha256": "40419152862e7d9bca631c53eaa2201052cf61eafe6d304c8a302f8ea97d6fb6"
|
||||
}
|
||||
},
|
||||
"identity_inputs": {
|
||||
"canonical_database": {
|
||||
"authority": "synthetic_noncanonical_fixture",
|
||||
"canonical_authority_granted": false,
|
||||
"database": "leo_identity_fixture",
|
||||
"database_user": "leo_identity_reader",
|
||||
"fingerprint_sha256": "1111111111111111111111111111111111111111111111111111111111111111",
|
||||
"source": {
|
||||
"record_count": 7,
|
||||
"repo_path": "fixtures/working-leo/leo-identity-v1/leo-database-fingerprint-v1.json",
|
||||
"semantic_sha256": "c5bbf346613270a5e3b17f604f69306ed42f545d4f227d784ec0dcb3d675dcb2"
|
||||
},
|
||||
"structure_sha256": "3333333333333333333333333333333333333333333333333333333333333333",
|
||||
"system_identifier": "7649789040005668902",
|
||||
"table_count": 7,
|
||||
"table_rows_sha256": "2222222222222222222222222222222222222222222222222222222222222222",
|
||||
"total_rows": 7
|
||||
},
|
||||
"gatewayrunner_execution_contract": {
|
||||
"fixed_message_context": {
|
||||
"auto_skill": null,
|
||||
"media_or_file_context": null,
|
||||
"reply_context": null
|
||||
},
|
||||
"profile_surfaces": [
|
||||
"config.yaml",
|
||||
"generated SOUL.md",
|
||||
"skills",
|
||||
"plugins",
|
||||
"bin tools"
|
||||
],
|
||||
"required_absent_or_empty": {
|
||||
"generated_skill_prompt_cache": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945",
|
||||
"pairing_store": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945",
|
||||
"persistent_memory": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945",
|
||||
"prior_sessions_at_first_start": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945",
|
||||
"project_context": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945"
|
||||
},
|
||||
"required_t3_turn_receipt_fields": [
|
||||
"runner_class",
|
||||
"authorization_decision",
|
||||
"effective_system_prompt_sha256",
|
||||
"compiled_skills_prompt_sha256",
|
||||
"tool_registry_schema_sha256",
|
||||
"plugin_registry_sha256",
|
||||
"selected_model",
|
||||
"selected_provider",
|
||||
"api_mode",
|
||||
"base_url_host",
|
||||
"database_retrieval_receipt",
|
||||
"session_key_sha256",
|
||||
"persisted_session_id_sha256"
|
||||
]
|
||||
},
|
||||
"identity_name": "Leo",
|
||||
"identity_sources": {
|
||||
"database_derived_identity": {
|
||||
"authority": "synthetic_noncanonical_fixture",
|
||||
"content_sha256": "9de2dfa37529b23ba277348f3d910e967551e490a9b4d2be637bf45bb2aa7dde",
|
||||
"database_fingerprint_sha256": "1111111111111111111111111111111111111111111111111111111111111111",
|
||||
"provenance": {
|
||||
"authority": "synthetic_noncanonical_fixture",
|
||||
"canonical_authority_granted": false,
|
||||
"export_receipt_sha256": null,
|
||||
"mode": "synthetic_noncanonical_fixture",
|
||||
"same_transaction_as_fingerprint": false
|
||||
},
|
||||
"record_count": 5,
|
||||
"repo_path": "fixtures/working-leo/leo-identity-v1/leo-database-identity-v1.json",
|
||||
"semantic_sha256": "70aaa7287cc41b52a3c902cf2e1b90fa4d84a5ee0a61e10c642f556fcc9304c3"
|
||||
},
|
||||
"static_constitution": {
|
||||
"authority": "pinned_static_source",
|
||||
"content_sha256": "b5477e778a2be0abba783390dac2e04ed199b8ce5679fc324270f808d46543f1",
|
||||
"record_count": 3,
|
||||
"repo_path": "fixtures/working-leo/leo-identity-v1/leo-constitution-v1.json",
|
||||
"semantic_sha256": "b576d5cee08530a95e0b196a3296f4743b70d94bcadffaa36544dd6bf1387f8a"
|
||||
}
|
||||
},
|
||||
"model": {
|
||||
"actual_model_required_in_turn_receipt": true,
|
||||
"default_model": "leo-identity-readback-v1",
|
||||
"gateway_smart_model_routing": null,
|
||||
"hosted_weights": "external_provider_managed_not_locally_hashable",
|
||||
"model_section_sha256": "90b3943ace9ff83b1711002fda8dc9736448e8d3c1c58a17ac90608f4ce58756",
|
||||
"provider": "fixture-local",
|
||||
"smart_routing": false,
|
||||
"smart_routing_model": null
|
||||
},
|
||||
"permissions": {
|
||||
"authorization_decision_required_in_runtime_receipt": true,
|
||||
"gateway_permissions_sha256": "eac17ada1d02b5413183587d12fc265538479de00709ed8c275e9045cd720290",
|
||||
"identity_config_sha256": "e6df9b65bab148ea8502555bbc260df66b4785e7dd527cfd15d2f0a48c2e8b3e",
|
||||
"runtime_policy": {
|
||||
"allowed_tools": [
|
||||
"identity_readback"
|
||||
],
|
||||
"database_write_enabled": false,
|
||||
"network_send_enabled": false
|
||||
},
|
||||
"tool_permissions_sha256": "9bb2cec2f65d43efb597a72bdced44076c25aac292f2fccbc4c448b6e7fd3e16"
|
||||
},
|
||||
"runtime": {
|
||||
"hermes_git_head": "b238fd6fc2636ed3582e14900774014c52732698",
|
||||
"hermes_source_sha256": "dcf8109051e0b69cafe2e8dd328ff501211b62ea19725416c3781bbdd594d028",
|
||||
"identity_runtime_sha256": "5c54248a5d1f00b35912d47d8b3045b8cfbed16ae9b86409b549ab7042f51159",
|
||||
"python": {
|
||||
"abi_tag": "cpython-311",
|
||||
"implementation": "CPython",
|
||||
"python_version": "3.11.15",
|
||||
"runtime_distributions": {
|
||||
"PyYAML": "6.0.3"
|
||||
},
|
||||
"runtime_distributions_sha256": "57a91bb880a01800903c1604b6eec1419514864ebd6a0644121920da15a8f165"
|
||||
},
|
||||
"teleo_git_head": "b238fd6fc2636ed3582e14900774014c52732698",
|
||||
"teleo_source_sha256": "2bd2e659eafb0ac0823f7f51c4296b2eb500b6f74469b3ac5f5287a5d4810aea"
|
||||
},
|
||||
"session_boundary": {
|
||||
"classification": "temporary_noncanonical",
|
||||
"included_in_identity_inputs": false,
|
||||
"may_be_used_as_evidence": false,
|
||||
"restart_policy": "fresh_process_with_session_state_outside_identity_authority"
|
||||
},
|
||||
"skills": {
|
||||
"content_sha256": "d3f449ddcd7c88238dc88c6233cf2130875f51bd2e0911b2ce477b7c602ae90f",
|
||||
"file_count": 1
|
||||
},
|
||||
"source_commit": "b238fd6fc2636ed3582e14900774014c52732698"
|
||||
},
|
||||
"identity_inputs_sha256": "c101c488a9f623b4cef841ddb561c0f289a74df54aadfdfe9b28c4b7643fec2e",
|
||||
"manifest_sha256": "22e66cf39b2c5aac3b4043f37aa0773b4861fec616a435e8b5e0ff8c86586bef",
|
||||
"schema": "livingip.leoIdentityManifest.v1"
|
||||
},
|
||||
"mode": "successful_restart_plus_drift_negative",
|
||||
"pre_restart_verification": "pass",
|
||||
"production_database_contacted": false,
|
||||
"production_profile_replaced": false,
|
||||
"receipt_sha256": "685641533be36b78e382dfd690bdc588bc95045379b44dd885d1d1d0ee57b507",
|
||||
"required_tier": "T2_runtime",
|
||||
"restart": {
|
||||
"actual_argv_persisted": false,
|
||||
"command_serialization": "logical_redacted_v1",
|
||||
"launcher_pid": 80642,
|
||||
"logical_command": [
|
||||
"<python>",
|
||||
"-m",
|
||||
"scripts.leo_identity_profile",
|
||||
"query",
|
||||
"--profile",
|
||||
"<temporary-profile>",
|
||||
"--source-root",
|
||||
".",
|
||||
"--hermes-root",
|
||||
"fixtures/working-leo/leo-identity-v1/hermes-runtime",
|
||||
"--deployment-root",
|
||||
".",
|
||||
"--query",
|
||||
"What defines Leo's identity, and what is temporary?"
|
||||
],
|
||||
"orphan_cleanup_required": false,
|
||||
"process_group_absent_after_wait": true,
|
||||
"profile_role": "restart",
|
||||
"returncode": 0,
|
||||
"stderr_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
|
||||
"stdout": {
|
||||
"answer": "Leo is defined by 3 pinned static constitutional rules and 5 active database-derived identity rows from a synthetic noncanonical fixture at fingerprint 1111111111111111111111111111111111111111111111111111111111111111. SOUL.md is a generated view; runtime/session memory is temporary, noncanonical, and cannot be evidence.",
|
||||
"answer_sha256": "e0a21e1fc5357a2f358b4e96c52e971f3addee2468e44748d898adfd62dafa25",
|
||||
"authorization": {
|
||||
"authorization_decision_observed": false,
|
||||
"claim": "local_policy_binding_not_an_authorizer_readback",
|
||||
"declared_runtime_policy": {
|
||||
"allowed_tools": [
|
||||
"identity_readback"
|
||||
],
|
||||
"database_write_enabled": false,
|
||||
"network_send_enabled": false
|
||||
}
|
||||
},
|
||||
"identity_inputs_sha256": "c101c488a9f623b4cef841ddb561c0f289a74df54aadfdfe9b28c4b7643fec2e",
|
||||
"manifest_sha256": "22e66cf39b2c5aac3b4043f37aa0773b4861fec616a435e8b5e0ff8c86586bef",
|
||||
"output_provenance": {
|
||||
"actual_model_call_performed": false,
|
||||
"compiled_identity_sha256": "40419152862e7d9bca631c53eaa2201052cf61eafe6d304c8a302f8ea97d6fb6",
|
||||
"compiled_soul_sha256": "83d27dba6e1b160085388a5dc84da565abf5736351b1af3f220d13b35aac244a",
|
||||
"database_authority": "synthetic_noncanonical_fixture",
|
||||
"database_canonical_authority_granted": false,
|
||||
"database_fingerprint_sha256": "1111111111111111111111111111111111111111111111111111111111111111",
|
||||
"database_identity_sha256": "70aaa7287cc41b52a3c902cf2e1b90fa4d84a5ee0a61e10c642f556fcc9304c3",
|
||||
"runtime_identity_sha256": "5c54248a5d1f00b35912d47d8b3045b8cfbed16ae9b86409b549ab7042f51159",
|
||||
"static_constitution_sha256": "b576d5cee08530a95e0b196a3296f4743b70d94bcadffaa36544dd6bf1387f8a"
|
||||
},
|
||||
"process_id": 80642,
|
||||
"query": "What defines Leo's identity, and what is temporary?",
|
||||
"query_sha256": "13704c2c9ae999e3f9b3f1c9c5572d062cd7fe49903c2317fa85aaa39490af66",
|
||||
"runtime_instance_id": "109445cde86f4ac3b266930462fb62c3",
|
||||
"schema": "livingip.leoIdentityQueryReceipt.v1",
|
||||
"session": {
|
||||
"classification": "temporary_noncanonical",
|
||||
"included_in_output_provenance": false,
|
||||
"may_be_used_as_evidence": false,
|
||||
"record_sha256": "56b6a2ea25657a87dc90dc19f49bece0ac62241f5814732ed80ef4f34d426d84"
|
||||
},
|
||||
"started_at_utc": "2026-07-15T02:46:37.036778+00:00",
|
||||
"status": "pass"
|
||||
},
|
||||
"terminated_with": null,
|
||||
"timed_out": false
|
||||
},
|
||||
"restart_compile": {
|
||||
"compiled_view_sha256": {
|
||||
"SOUL.md": "83d27dba6e1b160085388a5dc84da565abf5736351b1af3f220d13b35aac244a",
|
||||
"identity.json": "40419152862e7d9bca631c53eaa2201052cf61eafe6d304c8a302f8ea97d6fb6"
|
||||
},
|
||||
"generated_views_are_authority": false,
|
||||
"identity_inputs_sha256": "c101c488a9f623b4cef841ddb561c0f289a74df54aadfdfe9b28c4b7643fec2e",
|
||||
"manifest_sha256": "22e66cf39b2c5aac3b4043f37aa0773b4861fec616a435e8b5e0ff8c86586bef",
|
||||
"nonauthoritative_inputs_omitted": {
|
||||
".cursorrules": true,
|
||||
".hermes.md": true,
|
||||
".skills_prompt_snapshot.json": true,
|
||||
"AGENTS.md": true,
|
||||
"CLAUDE.md": true,
|
||||
"HERMES.md": true,
|
||||
"MEMORY.md": true,
|
||||
"USER.md": true,
|
||||
"memories": true,
|
||||
"platforms/pairing": true
|
||||
},
|
||||
"profile_static_entries": [
|
||||
"config.yaml",
|
||||
"skills",
|
||||
"plugins",
|
||||
"bin"
|
||||
],
|
||||
"runtime_identity_sha256": "5c54248a5d1f00b35912d47d8b3045b8cfbed16ae9b86409b549ab7042f51159",
|
||||
"schema": "livingip.leoIdentityCompileReceipt.v1",
|
||||
"session_directories_started_empty": true,
|
||||
"status": "pass"
|
||||
},
|
||||
"runtime_component_proven": "fresh_profile_recompile_plus_distinct_process_restart",
|
||||
"runtime_variant": "local_deterministic_identity_compiler_readback",
|
||||
"schema": "livingip.leoIdentityReconstructionReceipt.v1",
|
||||
"second_start_attempted": true,
|
||||
"session_boundary_readback": {
|
||||
"full_behavior_changed_after_session": true,
|
||||
"identity_runtime_unchanged_after_session": true,
|
||||
"session_classification": "temporary_noncanonical",
|
||||
"session_file_count": 1,
|
||||
"session_used_as_output_provenance": false
|
||||
},
|
||||
"status": "pass",
|
||||
"telegram_message_sent": false,
|
||||
"tier_basis": "Capability Tier Proof defines T2_runtime as local API/runtime behavior with restart where relevant; this is compiler-process runtime proof and explicitly excludes GatewayRunner and hosted-model proof."
|
||||
}
|
||||
|
|
@ -0,0 +1,141 @@
|
|||
begin;
|
||||
set local standard_conforming_strings = on;
|
||||
set local lock_timeout = '5s';
|
||||
select pg_advisory_xact_lock(hashtextextended('proposal-rollback:' || E'edaf2c90-af15-5a2f-b6b9-fe08ab9ae81b', 0));
|
||||
do $rollback$
|
||||
declare
|
||||
affected integer;
|
||||
approval_now jsonb;
|
||||
downstream_dependency_count integer;
|
||||
begin
|
||||
perform 1 from kb_stage.kb_proposals
|
||||
where id = E'edaf2c90-af15-5a2f-b6b9-fe08ab9ae81b'::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'edaf2c90-af15-5a2f-b6b9-fe08ab9ae81b'::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":"b4d0a944-8f11-5516-80ca-bc680f0059ad","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":"a9dd972a-b867-56f7-b3c9-3913dd9a0abe","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":"b4d0a944-8f11-5516-80ca-bc680f0059ad","to_claim":"a9dd972a-b867-56f7-b3c9-3913dd9a0abe","weight":0.75}],"evidence":[{"claim_id":"b4d0a944-8f11-5516-80ca-bc680f0059ad","created_by":null,"role":"grounds","source_id":"3953271f-7df5-5674-99b0-980b1b3534e6","weight":0.9},{"claim_id":"a9dd972a-b867-56f7-b3c9-3913dd9a0abe","created_by":null,"role":"illustrates","source_id":"3d31345d-a4f7-52a7-af4a-0034f99a8123","weight":0.8}],"reasoning_tools":[{"agent_id":null,"category":"verification","description":"Verify approved proposal to canonical graph lifecycle in a disposable clone.","id":"a32a7252-d39f-5ee9-873a-a82b56a6bb08","name":"Canonical row proof canary"}],"sources":[{"created_by":null,"excerpt":"Disposable clone lifecycle canary source A.","hash":"approve-claim-canary-e315c2518c-a","id":"3953271f-7df5-5674-99b0-980b1b3534e6","source_type":"observation","storage_path":null,"url":null},{"created_by":null,"excerpt":"Disposable clone lifecycle canary source B.","hash":"approve-claim-canary-e315c2518c-b","id":"3d31345d-a4f7-52a7-af4a-0034f99a8123","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'99999999-9999-9999-9999-999999999999'::uuid
|
||||
and reviewed_at is not distinct from E'2026-07-15 03:59:09.091704+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 03:59:12.452878+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'edaf2c90-af15-5a2f-b6b9-fe08ab9ae81b'::uuid;
|
||||
if approval_now is distinct from E'{"payload":{"apply_payload":{"agent_id":null,"claims":[{"confidence":0.9,"created_by":null,"id":"b4d0a944-8f11-5516-80ca-bc680f0059ad","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":"a9dd972a-b867-56f7-b3c9-3913dd9a0abe","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":"b4d0a944-8f11-5516-80ca-bc680f0059ad","to_claim":"a9dd972a-b867-56f7-b3c9-3913dd9a0abe","weight":0.75}],"evidence":[{"claim_id":"b4d0a944-8f11-5516-80ca-bc680f0059ad","created_by":null,"role":"grounds","source_id":"3953271f-7df5-5674-99b0-980b1b3534e6","weight":0.9},{"claim_id":"a9dd972a-b867-56f7-b3c9-3913dd9a0abe","created_by":null,"role":"illustrates","source_id":"3d31345d-a4f7-52a7-af4a-0034f99a8123","weight":0.8}],"reasoning_tools":[{"agent_id":null,"category":"verification","description":"Verify approved proposal to canonical graph lifecycle in a disposable clone.","id":"a32a7252-d39f-5ee9-873a-a82b56a6bb08","name":"Canonical row proof canary"}],"sources":[{"created_by":null,"excerpt":"Disposable clone lifecycle canary source A.","hash":"approve-claim-canary-e315c2518c-a","id":"3953271f-7df5-5674-99b0-980b1b3534e6","source_type":"observation","storage_path":null,"url":null},{"created_by":null,"excerpt":"Disposable clone lifecycle canary source B.","hash":"approve-claim-canary-e315c2518c-b","id":"3d31345d-a4f7-52a7-af4a-0034f99a8123","source_type":"observation","storage_path":null,"url":null}]}},"proposal_id":"edaf2c90-af15-5a2f-b6b9-fe08ab9ae81b","proposal_type":"approve_claim","review_note":"Reviewed exact strict payload inside the disposable clone.","reviewed_at":"2026-07-15 03:59:09.091704+00","reviewed_by_agent_id":"99999999-9999-9999-9999-999999999999","reviewed_by_db_role":"kb_review","reviewed_by_handle":"m3ta"}'::jsonb then
|
||||
raise exception 'proposal rollback: immutable approval snapshot drifted';
|
||||
end if;
|
||||
select count(*) into downstream_dependency_count
|
||||
from (
|
||||
select ce.claim_id
|
||||
from public.claim_evidence ce
|
||||
where (ce.claim_id = any(array[E'a9dd972a-b867-56f7-b3c9-3913dd9a0abe'::uuid, E'b4d0a944-8f11-5516-80ca-bc680f0059ad'::uuid]::uuid[]) or ce.source_id = any(array[E'3953271f-7df5-5674-99b0-980b1b3534e6'::uuid, E'3d31345d-a4f7-52a7-af4a-0034f99a8123'::uuid]::uuid[]))
|
||||
and not (((ce.claim_id = E'a9dd972a-b867-56f7-b3c9-3913dd9a0abe'::uuid and ce.source_id = E'3d31345d-a4f7-52a7-af4a-0034f99a8123'::uuid and ce.role = E'illustrates'::evidence_role) or (ce.claim_id = E'b4d0a944-8f11-5516-80ca-bc680f0059ad'::uuid and ce.source_id = E'3953271f-7df5-5674-99b0-980b1b3534e6'::uuid and ce.role = E'grounds'::evidence_role)))
|
||||
union all
|
||||
select edge.id
|
||||
from public.claim_edges edge
|
||||
where (edge.from_claim = any(array[E'a9dd972a-b867-56f7-b3c9-3913dd9a0abe'::uuid, E'b4d0a944-8f11-5516-80ca-bc680f0059ad'::uuid]::uuid[]) or edge.to_claim = any(array[E'a9dd972a-b867-56f7-b3c9-3913dd9a0abe'::uuid, E'b4d0a944-8f11-5516-80ca-bc680f0059ad'::uuid]::uuid[]))
|
||||
and edge.id <> all(array[E'cd799806-18e8-5e8c-959c-5f9c267654a7'::uuid]::uuid[])
|
||||
union all
|
||||
select claim.id
|
||||
from public.claims claim
|
||||
where claim.superseded_by = any(array[E'a9dd972a-b867-56f7-b3c9-3913dd9a0abe'::uuid, E'b4d0a944-8f11-5516-80ca-bc680f0059ad'::uuid]::uuid[])
|
||||
and claim.id <> all(array[E'a9dd972a-b867-56f7-b3c9-3913dd9a0abe'::uuid, E'b4d0a944-8f11-5516-80ca-bc680f0059ad'::uuid]::uuid[])
|
||||
) external_dependencies;
|
||||
if downstream_dependency_count <> 0 then
|
||||
raise exception 'proposal rollback: % downstream dependenc(ies) exist; rollback quarantined', downstream_dependency_count;
|
||||
end if;
|
||||
if (select count(*) from public.claim_evidence t
|
||||
where ((t.claim_id = E'a9dd972a-b867-56f7-b3c9-3913dd9a0abe'::uuid and t.source_id = E'3d31345d-a4f7-52a7-af4a-0034f99a8123'::uuid and t.role = E'illustrates'::evidence_role)) and to_jsonb(t) = E'{"claim_id":"a9dd972a-b867-56f7-b3c9-3913dd9a0abe","created_at":"2026-07-15T03:59:12.43629+00:00","created_by":null,"role":"illustrates","source_id":"3d31345d-a4f7-52a7-af4a-0034f99a8123","weight":0.8}'::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.claim_id = E'b4d0a944-8f11-5516-80ca-bc680f0059ad'::uuid and t.source_id = E'3953271f-7df5-5674-99b0-980b1b3534e6'::uuid and t.role = E'grounds'::evidence_role)) and to_jsonb(t) = E'{"claim_id":"b4d0a944-8f11-5516-80ca-bc680f0059ad","created_at":"2026-07-15T03:59:12.43629+00:00","created_by":null,"role":"grounds","source_id":"3953271f-7df5-5674-99b0-980b1b3534e6","weight":0.9}'::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'cd799806-18e8-5e8c-959c-5f9c267654a7'::uuid and to_jsonb(t) = E'{"created_at":"2026-07-15T03:59:12.43629+00:00","created_by":null,"edge_type":"supports","from_claim":"b4d0a944-8f11-5516-80ca-bc680f0059ad","id":"cd799806-18e8-5e8c-959c-5f9c267654a7","to_claim":"a9dd972a-b867-56f7-b3c9-3913dd9a0abe","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'a32a7252-d39f-5ee9-873a-a82b56a6bb08'::uuid and to_jsonb(t) = E'{"agent_id":null,"category":"verification","created_at":"2026-07-15T03:59:12.43629+00:00","description":"Verify approved proposal to canonical graph lifecycle in a disposable clone.","id":"a32a7252-d39f-5ee9-873a-a82b56a6bb08","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'3953271f-7df5-5674-99b0-980b1b3534e6'::uuid and to_jsonb(t) = E'{"captured_at":null,"created_at":"2026-07-15T03:59:12.43629+00:00","created_by":null,"excerpt":"Disposable clone lifecycle canary source A.","hash":"approve-claim-canary-e315c2518c-a","id":"3953271f-7df5-5674-99b0-980b1b3534e6","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'3d31345d-a4f7-52a7-af4a-0034f99a8123'::uuid and to_jsonb(t) = E'{"captured_at":null,"created_at":"2026-07-15T03:59:12.43629+00:00","created_by":null,"excerpt":"Disposable clone lifecycle canary source B.","hash":"approve-claim-canary-e315c2518c-b","id":"3d31345d-a4f7-52a7-af4a-0034f99a8123","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'a9dd972a-b867-56f7-b3c9-3913dd9a0abe'::uuid and to_jsonb(t) = E'{"confidence":0.85,"created_at":"2026-07-15T03:59:12.43629+00:00","created_by":null,"id":"a9dd972a-b867-56f7-b3c9-3913dd9a0abe","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-15T03:59:12.43629+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'b4d0a944-8f11-5516-80ca-bc680f0059ad'::uuid and to_jsonb(t) = E'{"confidence":0.9,"created_at":"2026-07-15T03:59:12.43629+00:00","created_by":null,"id":"b4d0a944-8f11-5516-80ca-bc680f0059ad","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-15T03:59:12.43629+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 target where ((target.claim_id = E'a9dd972a-b867-56f7-b3c9-3913dd9a0abe'::uuid and target.source_id = E'3d31345d-a4f7-52a7-af4a-0034f99a8123'::uuid and target.role = E'illustrates'::evidence_role) or (target.claim_id = E'b4d0a944-8f11-5516-80ca-bc680f0059ad'::uuid and target.source_id = E'3953271f-7df5-5674-99b0-980b1b3534e6'::uuid and target.role = E'grounds'::evidence_role));
|
||||
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'cd799806-18e8-5e8c-959c-5f9c267654a7'::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'a32a7252-d39f-5ee9-873a-a82b56a6bb08'::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'3953271f-7df5-5674-99b0-980b1b3534e6'::uuid, E'3d31345d-a4f7-52a7-af4a-0034f99a8123'::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'a9dd972a-b867-56f7-b3c9-3913dd9a0abe'::uuid, E'b4d0a944-8f11-5516-80ca-bc680f0059ad'::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 = 'canceled',
|
||||
applied_by_handle = null,
|
||||
applied_by_agent_id = null,
|
||||
applied_at = null,
|
||||
updated_at = now()
|
||||
where id = E'edaf2c90-af15-5a2f-b6b9-fe08ab9ae81b'::uuid
|
||||
and status = 'applied'
|
||||
and payload = E'{"apply_payload":{"agent_id":null,"claims":[{"confidence":0.9,"created_by":null,"id":"b4d0a944-8f11-5516-80ca-bc680f0059ad","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":"a9dd972a-b867-56f7-b3c9-3913dd9a0abe","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":"b4d0a944-8f11-5516-80ca-bc680f0059ad","to_claim":"a9dd972a-b867-56f7-b3c9-3913dd9a0abe","weight":0.75}],"evidence":[{"claim_id":"b4d0a944-8f11-5516-80ca-bc680f0059ad","created_by":null,"role":"grounds","source_id":"3953271f-7df5-5674-99b0-980b1b3534e6","weight":0.9},{"claim_id":"a9dd972a-b867-56f7-b3c9-3913dd9a0abe","created_by":null,"role":"illustrates","source_id":"3d31345d-a4f7-52a7-af4a-0034f99a8123","weight":0.8}],"reasoning_tools":[{"agent_id":null,"category":"verification","description":"Verify approved proposal to canonical graph lifecycle in a disposable clone.","id":"a32a7252-d39f-5ee9-873a-a82b56a6bb08","name":"Canonical row proof canary"}],"sources":[{"created_by":null,"excerpt":"Disposable clone lifecycle canary source A.","hash":"approve-claim-canary-e315c2518c-a","id":"3953271f-7df5-5674-99b0-980b1b3534e6","source_type":"observation","storage_path":null,"url":null},{"created_by":null,"excerpt":"Disposable clone lifecycle canary source B.","hash":"approve-claim-canary-e315c2518c-b","id":"3d31345d-a4f7-52a7-af4a-0034f99a8123","source_type":"observation","storage_path":null,"url":null}]}}'::jsonb
|
||||
and applied_at is not distinct from E'2026-07-15 03:59:12.452878+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;
|
||||
File diff suppressed because it is too large
Load diff
|
|
@ -0,0 +1,219 @@
|
|||
{
|
||||
"applied_row_keys": {
|
||||
"claim_edges": [
|
||||
"cd799806-18e8-5e8c-959c-5f9c267654a7"
|
||||
],
|
||||
"claim_evidence": [
|
||||
"a9dd972a-b867-56f7-b3c9-3913dd9a0abe|3d31345d-a4f7-52a7-af4a-0034f99a8123|illustrates",
|
||||
"b4d0a944-8f11-5516-80ca-bc680f0059ad|3953271f-7df5-5674-99b0-980b1b3534e6|grounds"
|
||||
],
|
||||
"claims": [
|
||||
"a9dd972a-b867-56f7-b3c9-3913dd9a0abe",
|
||||
"b4d0a944-8f11-5516-80ca-bc680f0059ad"
|
||||
],
|
||||
"reasoning_tools": [
|
||||
"a32a7252-d39f-5ee9-873a-a82b56a6bb08"
|
||||
],
|
||||
"sources": [
|
||||
"3953271f-7df5-5674-99b0-980b1b3534e6",
|
||||
"3d31345d-a4f7-52a7-af4a-0034f99a8123"
|
||||
]
|
||||
},
|
||||
"applied_row_sha256": {
|
||||
"claim_edges": [
|
||||
"aae7ed87c66cf58136f2b0027ae1cddc9092cd64bfc8e617cd7746b2306274c5"
|
||||
],
|
||||
"claim_evidence": [
|
||||
"388f3363173efda00f0688fab77fe0ce2baf62035220b843be1adea1f1c70f7f",
|
||||
"55838cb722f7158cbdbdc3b79212e764f9fa6014771985aec3c1c7856967db07"
|
||||
],
|
||||
"claims": [
|
||||
"75fe4543c9c3194612b1cf98b074ff7e361da17c9bcd59f9b6f085c2c0861277",
|
||||
"5914923936817eff6d7e5c824c94c18ae6392b7a6e80c87ace2e547865b173eb"
|
||||
],
|
||||
"reasoning_tools": [
|
||||
"990dacb7b77cec117d9ee4a7630625a8782d06dfd549340b3269b8332c170576"
|
||||
],
|
||||
"sources": [
|
||||
"585edbec2f98ec127041cdd662506a1494ea402f7e25ac0082dbda98197bf130",
|
||||
"a8d2eead7cb3e563869978570173e2af753dfe131d4b7cfcf6dd419ffbb427e5"
|
||||
]
|
||||
},
|
||||
"apply_payload_sha256": "e033bd4e742dfa0dad7d26e2f2b1f18eb71996541cdbc575bb2d4504c045e36f",
|
||||
"apply_receipt_sha256": "ac99a2a315cc8e6e214e0f2f69d1a23413da9cfd8629c202b61a678ffda6d7ca",
|
||||
"apply_sql_sha256": "b52cd47182dc0f542a394147201bb3a125518f8a4bc1a7fc44f2b0caa39c4a1b",
|
||||
"approval_snapshot_sha256": "1f9d0a58ad236908da931c7489fe14ee855d0f13c4d72eb5b218370e116e2096",
|
||||
"artifact": "proposal_apply_lifecycle_receipt",
|
||||
"checks": {
|
||||
"apply_receipt_replay_ready": true,
|
||||
"apply_rows_have_exact_ids": true,
|
||||
"fresh_owned_preflight_consumed_by_apply": true,
|
||||
"fresh_owned_targets": true,
|
||||
"immutable_approval_unchanged": true,
|
||||
"rollback_counts_restored": true,
|
||||
"rollback_ledger_quarantined_from_worker": 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_owned_apply_sql_sha256": "b52cd47182dc0f542a394147201bb3a125518f8a4bc1a7fc44f2b0caa39c4a1b",
|
||||
"fresh_preflight_artifact_sha256": "2312c91d82ee378d4a53136b8e307900c97d0611d9f12098e799cb6de5d30077",
|
||||
"fresh_preflight_sha256": "90facb2ca62feb1d3c7a242e84427ab402cf57148eaba40ec700f3cc4896d20f",
|
||||
"generated_at_utc": "2026-07-15T03:59:15.412413+00:00",
|
||||
"lifecycle_receipt_sha256": "4254f363b0c6115ecf07856c6e6a9879b43840e688aa73211cb9eff893b36c06",
|
||||
"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": "edaf2c90-af15-5a2f-b6b9-fe08ab9ae81b",
|
||||
"payload": {
|
||||
"apply_payload": {
|
||||
"agent_id": null,
|
||||
"claims": [
|
||||
{
|
||||
"confidence": 0.9,
|
||||
"created_by": null,
|
||||
"id": "b4d0a944-8f11-5516-80ca-bc680f0059ad",
|
||||
"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": "a9dd972a-b867-56f7-b3c9-3913dd9a0abe",
|
||||
"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": "b4d0a944-8f11-5516-80ca-bc680f0059ad",
|
||||
"to_claim": "a9dd972a-b867-56f7-b3c9-3913dd9a0abe",
|
||||
"weight": 0.75
|
||||
}
|
||||
],
|
||||
"evidence": [
|
||||
{
|
||||
"claim_id": "b4d0a944-8f11-5516-80ca-bc680f0059ad",
|
||||
"created_by": null,
|
||||
"role": "grounds",
|
||||
"source_id": "3953271f-7df5-5674-99b0-980b1b3534e6",
|
||||
"weight": 0.9
|
||||
},
|
||||
{
|
||||
"claim_id": "a9dd972a-b867-56f7-b3c9-3913dd9a0abe",
|
||||
"created_by": null,
|
||||
"role": "illustrates",
|
||||
"source_id": "3d31345d-a4f7-52a7-af4a-0034f99a8123",
|
||||
"weight": 0.8
|
||||
}
|
||||
],
|
||||
"reasoning_tools": [
|
||||
{
|
||||
"agent_id": null,
|
||||
"category": "verification",
|
||||
"description": "Verify approved proposal to canonical graph lifecycle in a disposable clone.",
|
||||
"id": "a32a7252-d39f-5ee9-873a-a82b56a6bb08",
|
||||
"name": "Canonical row proof canary"
|
||||
}
|
||||
],
|
||||
"sources": [
|
||||
{
|
||||
"created_by": null,
|
||||
"excerpt": "Disposable clone lifecycle canary source A.",
|
||||
"hash": "approve-claim-canary-e315c2518c-a",
|
||||
"id": "3953271f-7df5-5674-99b0-980b1b3534e6",
|
||||
"source_type": "observation",
|
||||
"storage_path": null,
|
||||
"url": null
|
||||
},
|
||||
{
|
||||
"created_by": null,
|
||||
"excerpt": "Disposable clone lifecycle canary source B.",
|
||||
"hash": "approve-claim-canary-e315c2518c-b",
|
||||
"id": "3d31345d-a4f7-52a7-af4a-0034f99a8123",
|
||||
"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 03:59:09.091704+00",
|
||||
"reviewed_by_agent_id": "99999999-9999-9999-9999-999999999999",
|
||||
"reviewed_by_handle": "m3ta",
|
||||
"status": "approved"
|
||||
},
|
||||
"proposal_payload_sha256": "cf2676db5a64142d07a7b46f02f1ba38bfa8cca69d03484bbcaa5eeb7002af71",
|
||||
"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": "edaf2c90-af15-5a2f-b6b9-fe08ab9ae81b",
|
||||
"proposal_type": "approve_claim",
|
||||
"review_note": "Reviewed exact strict payload inside the disposable clone.",
|
||||
"reviewed_at": "2026-07-15 03:59:09.091704+00",
|
||||
"reviewed_by_agent_id": "99999999-9999-9999-9999-999999999999",
|
||||
"reviewed_by_handle": "m3ta",
|
||||
"status": "canceled"
|
||||
},
|
||||
"rollback_sql_sha256": "50758dab3f998289a879cedb4a3f4535814e70c7f4dde417812092b9fe194901",
|
||||
"schema": "livingip.proposalApplyRollback.v2",
|
||||
"target_rows_after": {
|
||||
"claim_edges": [],
|
||||
"claim_evidence": [],
|
||||
"claims": [],
|
||||
"reasoning_tools": [],
|
||||
"sources": []
|
||||
}
|
||||
},
|
||||
"schema": "livingip.proposalApplyLifecycleReceipt.v2",
|
||||
"strongest_claim_allowed": "deterministic disposable-clone apply and compensating rollback"
|
||||
}
|
||||
|
|
@ -0,0 +1,260 @@
|
|||
{
|
||||
"artifact": "proposal_apply_production_authorization_packet",
|
||||
"authorization_record_required": {
|
||||
"authorization_text": "<EXACT_TEXT_FROM_VERIFIER>",
|
||||
"authorized": true,
|
||||
"binding_sha256": "6f1984f3a69ad049d4bbcc408ed2542dc5f081806ec9baa9a35c8959e5dab62a",
|
||||
"expires_at_utc": "<UTC>",
|
||||
"operator_identity": "<OPERATOR_IDENTITY>",
|
||||
"production_rollback_sql_sha256": "<EXACT_PRODUCTION_ROLLBACK_SHA256>",
|
||||
"received_at_utc": "<UTC>",
|
||||
"rollback_authorized": true
|
||||
},
|
||||
"authorization_text_template": "I authorize one production DB apply for proposal 9b2b5fa4-0e0d-5db0-aa4d-6fd102889946 with payload SHA-256 6fba5e8e105a28dfaf5733ff7c9f85a20d31d653add0bc4a0f81e4b08de803af to Docker container teleo-pg, database teleo, system identifier 7649789040005668902, binding SHA-256 6f1984f3a69ad049d4bbcc408ed2542dc5f081806ec9baa9a35c8959e5dab62a. I also authorize conditional production rollback SHA-256 <PRODUCTION_ROLLBACK_SQL_SHA256> only if the bound postflight fails and no downstream dependency exists. Do not send Telegram, mutate another proposal, expose Cloud SQL, or promote GCP. Operator <OPERATOR_IDENTITY>; received <UTC>; expires <UTC>.",
|
||||
"binding": {
|
||||
"approval_gate": {
|
||||
"apply_role_present": true,
|
||||
"approve_function_present": false,
|
||||
"assert_function_present": false,
|
||||
"finish_function_present": false,
|
||||
"immutable_approval_table_present": false,
|
||||
"review_role_present": false
|
||||
},
|
||||
"approval_gate_dependency": {
|
||||
"path": "scripts/kb_apply_prereqs.sql",
|
||||
"requires_separate_production_authorization": true,
|
||||
"sha256": "bdf8c5da05eed10665b05ad1e331e3c9c8d72464c59889a3cf8f34ab23822faa"
|
||||
},
|
||||
"candidate_readback": {
|
||||
"matching_candidate": null,
|
||||
"matching_candidate_count": 0
|
||||
},
|
||||
"destination": {
|
||||
"container": "teleo-pg",
|
||||
"database": "teleo",
|
||||
"server_version_num": "160014",
|
||||
"system_identifier": "7649789040005668902"
|
||||
},
|
||||
"destination_readback": {
|
||||
"observed_at_utc": "2026-07-15T02:07:27.133665+00:00",
|
||||
"read_only_transaction": true
|
||||
},
|
||||
"engine": {
|
||||
"apply_engine_path": "scripts/apply_proposal.py",
|
||||
"apply_engine_sha256": "ca2c0a0c1031393c95a26102d57339654d2363f4c51cdf39aabb9071d0ca6c26",
|
||||
"apply_sql_sha256": "1a7d65870e415ee8891b6dd84732a29bcee00412c10862d3d1db4b191a8ade38",
|
||||
"repo_git_sha": "bd3c17628c6cf7da734be01149bbf1cc77a6d71b",
|
||||
"runtime_manifest": {
|
||||
"scripts/apply_proposal.py": "ca2c0a0c1031393c95a26102d57339654d2363f4c51cdf39aabb9071d0ca6c26",
|
||||
"scripts/kb_apply_prereqs.sql": "bdf8c5da05eed10665b05ad1e331e3c9c8d72464c59889a3cf8f34ab23822faa",
|
||||
"scripts/kb_apply_replay_receipt.py": "4ead132fc32a69baaecfe7b638cba8ba6d54d8508d0b7e6a922dc8065805c97f",
|
||||
"scripts/proposal_apply_lifecycle.py": "a643b83b55c9e76f545ebafb9582d6d07ff432600c1b66004cc7440d7ac1963b"
|
||||
}
|
||||
},
|
||||
"expected_rows": {
|
||||
"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"
|
||||
]
|
||||
},
|
||||
"row_sha256": {
|
||||
"claim_edges": [
|
||||
"60d14cbc45d424fa1eb62db6478f185bf2c2d86559e57ffa77474e8d0b3c527c"
|
||||
],
|
||||
"claim_evidence": [
|
||||
"e97de162c0730da69b357e1350f0da7e5843c4e67d498c12d731a0f04a8868d7",
|
||||
"3054718195abe3f78e08cfcacd59902d41eb91c7153c6c63f9bcb3bc7c6902ac"
|
||||
],
|
||||
"claims": [
|
||||
"e593b9cf7b0bc9267f3e48d8173129b84b09c028f290f1abc97ccb73940b31dc",
|
||||
"24280b5159cbbf75e00eb24ae50ab69994397a583f347a241a5e262cf0c03179"
|
||||
],
|
||||
"reasoning_tools": [
|
||||
"257924b236c3c27289b9ae2314687be0e96779415fc6ff87faada22893b757ba"
|
||||
],
|
||||
"sources": [
|
||||
"d7a690c2b18701db5b48e8189b1621c8025c1ed75889a4d0a3a4c9761c03dc3b",
|
||||
"bee048794799006bd00bf4bb02ae57998e670f5bcdfb140dff871dcb042d0198"
|
||||
]
|
||||
}
|
||||
},
|
||||
"production_preconditions": {
|
||||
"approval_gate_ready": false,
|
||||
"destination_readback_observed_at_utc": "2026-07-15T02:07:27.133665+00:00",
|
||||
"destination_readback_was_read_only": true,
|
||||
"exact_production_rollback_packet_ready": false,
|
||||
"matching_candidate_count": 0,
|
||||
"production_apply_authorization_present": false,
|
||||
"production_apply_executed": false,
|
||||
"strict_proposal_present_and_approved": false
|
||||
},
|
||||
"production_rollback": {
|
||||
"artifact_schema": null,
|
||||
"artifact_sha256": null,
|
||||
"bound_for_action_time_authorization": false,
|
||||
"conditional_rollback_requires_explicit_authorization": true,
|
||||
"rollback_sql_sha256": null,
|
||||
"scope": "exact_production_destination_postapply_receipt",
|
||||
"status": "not_generated"
|
||||
},
|
||||
"proposal": {
|
||||
"apply_payload_sha256": "c89bc03ce7714f325293329a0bf95eaba0a56c596ef021d731b48dab0447c684",
|
||||
"approval_snapshot_sha256": "310b54030e26ed43d7226f2e803610586e80d21ff064c67e11ea21e93ef40bd9",
|
||||
"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_payload_sha256": "6fba5e8e105a28dfaf5733ff7c9f85a20d31d653add0bc4a0f81e4b08de803af",
|
||||
"proposal_type": "approve_claim",
|
||||
"required_applied_at": null,
|
||||
"required_status": "approved",
|
||||
"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"
|
||||
},
|
||||
"rollback": {
|
||||
"conditional_rollback_requires_explicit_authorization": true,
|
||||
"lifecycle_receipt_sha256": "8e74cf1f5c372633f9b6f15363ff759ba6ce9bf42df51288bb9be70ddabe49b3",
|
||||
"production_executable": false,
|
||||
"rollback_sql_sha256": "ef2464a6802426509333861cf0768ca64184901ab7bd2030529e7356a35d9cb3",
|
||||
"scope": "disposable_clone_rehearsal"
|
||||
}
|
||||
},
|
||||
"binding_sha256": "6f1984f3a69ad049d4bbcc408ed2542dc5f081806ec9baa9a35c8959e5dab62a",
|
||||
"claim_ceiling": "T2 clone lifecycle plus T3 destination readback; no production apply authorization or execution",
|
||||
"current_tier": "T3_live_readonly",
|
||||
"generated_at_utc": "2026-07-15T02:08:10.775963+00:00",
|
||||
"next_exact_action": "deploy and independently verify the immutable approval gate before selecting a production proposal",
|
||||
"production_apply_authorization_present": false,
|
||||
"production_apply_executed": false,
|
||||
"production_preconditions": {
|
||||
"approval_gate_ready": false,
|
||||
"destination_readback_observed_at_utc": "2026-07-15T02:07:27.133665+00:00",
|
||||
"destination_readback_was_read_only": true,
|
||||
"exact_production_rollback_packet_ready": false,
|
||||
"matching_candidate_count": 0,
|
||||
"production_apply_authorization_present": false,
|
||||
"production_apply_executed": false,
|
||||
"strict_proposal_present_and_approved": false
|
||||
},
|
||||
"production_rollback_requirement": {
|
||||
"clone_rehearsal_is_not_production_rollback": true,
|
||||
"clone_rehearsal_rollback_sql_sha256": "ef2464a6802426509333861cf0768ca64184901ab7bd2030529e7356a35d9cb3",
|
||||
"production_rollback_artifact_schema": null,
|
||||
"production_rollback_artifact_sha256": null,
|
||||
"production_rollback_sql_sha256": null,
|
||||
"required_before_apply_window": true,
|
||||
"required_binding": "an exact production rollback SQL SHA-256 in both the action-time record and authorization text",
|
||||
"status": "not_generated"
|
||||
},
|
||||
"required_tier": "T6_authorized_production",
|
||||
"safe_to_enter_apply_window": false,
|
||||
"schema": "livingip.proposalApplyAuthorizationPacket.v1",
|
||||
"scope_exclusions": {
|
||||
"approval_gate_deployment_authorized": false,
|
||||
"cloud_sql_exposure_authorized": false,
|
||||
"gcp_promotion_authorized": false,
|
||||
"telegram_send_authorized": false
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,62 @@
|
|||
# Proposal Apply Production Authorization Packet
|
||||
|
||||
Generated UTC: `2026-07-15T02:08:10.775963+00:00`
|
||||
Required tier: `T6_authorized_production`
|
||||
Current tier: `T3_live_readonly`
|
||||
Safe to enter apply window: `False`
|
||||
Production apply authorized: `False`
|
||||
Production apply executed: `False`
|
||||
|
||||
## Exact Binding
|
||||
|
||||
- Proposal: `9b2b5fa4-0e0d-5db0-aa4d-6fd102889946` (`approve_claim`)
|
||||
- Proposal payload SHA-256: `6fba5e8e105a28dfaf5733ff7c9f85a20d31d653add0bc4a0f81e4b08de803af`
|
||||
- Apply payload SHA-256: `c89bc03ce7714f325293329a0bf95eaba0a56c596ef021d731b48dab0447c684`
|
||||
- Immutable approval SHA-256: `310b54030e26ed43d7226f2e803610586e80d21ff064c67e11ea21e93ef40bd9`
|
||||
- Destination: `teleo-pg/teleo`
|
||||
- Destination system identifier: `7649789040005668902`
|
||||
- Apply engine SHA-256: `ca2c0a0c1031393c95a26102d57339654d2363f4c51cdf39aabb9071d0ca6c26`
|
||||
- Apply engine path: `scripts/apply_proposal.py`
|
||||
- Apply SQL SHA-256: `1a7d65870e415ee8891b6dd84732a29bcee00412c10862d3d1db4b191a8ade38`
|
||||
- Clone rehearsal rollback SQL SHA-256: `ef2464a6802426509333861cf0768ca64184901ab7bd2030529e7356a35d9cb3`
|
||||
- Production rollback status: `not_generated`
|
||||
- Production rollback SQL SHA-256: `None`
|
||||
- Approval gate prerequisite SHA-256: `bdf8c5da05eed10665b05ad1e331e3c9c8d72464c59889a3cf8f34ab23822faa`
|
||||
- Approval gate prerequisite path: `scripts/kb_apply_prereqs.sql`
|
||||
- Binding SHA-256: `6f1984f3a69ad049d4bbcc408ed2542dc5f081806ec9baa9a35c8959e5dab62a`
|
||||
|
||||
## Production Preconditions
|
||||
|
||||
- `approval_gate_ready`: `False`
|
||||
- `destination_readback_observed_at_utc`: `2026-07-15T02:07:27.133665+00:00`
|
||||
- `destination_readback_was_read_only`: `True`
|
||||
- `exact_production_rollback_packet_ready`: `False`
|
||||
- `matching_candidate_count`: `0`
|
||||
- `production_apply_authorization_present`: `False`
|
||||
- `production_apply_executed`: `False`
|
||||
- `strict_proposal_present_and_approved`: `False`
|
||||
|
||||
## Approval Gate Readback
|
||||
|
||||
- `apply_role_present`: `True`
|
||||
- `approve_function_present`: `False`
|
||||
- `assert_function_present`: `False`
|
||||
- `finish_function_present`: `False`
|
||||
- `immutable_approval_table_present`: `False`
|
||||
- `review_role_present`: `False`
|
||||
|
||||
## Exact Action-Time Authorization Text
|
||||
|
||||
This text is not actionable until every production precondition above is true.
|
||||
|
||||
I authorize one production DB apply for proposal 9b2b5fa4-0e0d-5db0-aa4d-6fd102889946 with payload SHA-256 6fba5e8e105a28dfaf5733ff7c9f85a20d31d653add0bc4a0f81e4b08de803af to Docker container teleo-pg, database teleo, system identifier 7649789040005668902, binding SHA-256 6f1984f3a69ad049d4bbcc408ed2542dc5f081806ec9baa9a35c8959e5dab62a. I also authorize conditional production rollback SHA-256 <PRODUCTION_ROLLBACK_SQL_SHA256> only if the bound postflight fails and no downstream dependency exists. Do not send Telegram, mutate another proposal, expose Cloud SQL, or promote GCP. Operator <OPERATOR_IDENTITY>; received <UTC>; expires <UTC>.
|
||||
|
||||
## Current Gate
|
||||
|
||||
deploy and independently verify the immutable approval gate before selecting a production proposal
|
||||
|
||||
The production approval-gate deployment is explicitly outside this apply packet and requires separate authorization.
|
||||
|
||||
## Claim Ceiling
|
||||
|
||||
T2 clone lifecycle plus T3 destination readback; no production apply authorization or execution
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
{
|
||||
"artifact": "proposal_apply_production_target_readback",
|
||||
"schema": "livingip.proposalApplyProductionTargetReadback.v1",
|
||||
"observed_at_utc": "2026-07-15T02:07:27.133665+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."
|
||||
}
|
||||
|
|
@ -0,0 +1,272 @@
|
|||
{
|
||||
"authorization_gate_status": "ready_to_request_exact_authorization",
|
||||
"browser_provenance_contract": {
|
||||
"capture_channel": "codex_chrome_extension",
|
||||
"requires_browser_session_tab_and_capture_identifiers": true,
|
||||
"requires_chrome_backend_tool_receipts": true,
|
||||
"requires_codex_rollout_log_outside_evidence_root": true,
|
||||
"requires_codex_user_message_authorization_receipt": true,
|
||||
"requires_hashes_for_every_screenshot_and_accessibility_artifact": true,
|
||||
"requires_preflight_challenge_nonce": true,
|
||||
"requires_provenance_sha256_in_final_chrome_tool_receipt": true,
|
||||
"requires_telegram_web_origin_and_chat_identity": true,
|
||||
"schema": "livingip.authenticatedChromeTelegramCaptureProvenance.v1"
|
||||
},
|
||||
"checks": {
|
||||
"authenticated_chrome_is_only_send_transport": true,
|
||||
"canonical_manifest_path_and_sha_bound": true,
|
||||
"database_session_and_role_fail_closed_read_only": true,
|
||||
"exact_prompts_imported_from_handler_verifier": true,
|
||||
"exact_three_turn_sequence": true,
|
||||
"first_prompt_supplies_no_row_id": true,
|
||||
"handler_checks_all_pass": true,
|
||||
"handler_outcomes_all_pass": true,
|
||||
"handler_prompt_ids_exact": true,
|
||||
"handler_proved_no_telegram_post": true,
|
||||
"handler_proved_read_only_tool_traces": true,
|
||||
"handler_proved_unchanged_fingerprint": true,
|
||||
"handler_receipt_passed": true,
|
||||
"handler_receipt_schema_supported": true,
|
||||
"handler_safety_gate_passed": true,
|
||||
"handler_tier_remains_below_telegram_visible": true,
|
||||
"independent_browser_provenance_required": true,
|
||||
"packet_does_not_mutate_database": true,
|
||||
"packet_does_not_send": true
|
||||
},
|
||||
"claim_ceiling": {
|
||||
"current_tier": "T0_spec_plus_prior_T2_handler_evidence",
|
||||
"not_proven": [
|
||||
"Telegram-visible delivery of these three messages",
|
||||
"Telegram-visible replies from Leo",
|
||||
"post-send canonical fingerprint equality"
|
||||
],
|
||||
"proven": "The exact three-turn Chrome send packet is bound to a passing no-send handler receipt.",
|
||||
"required_tier": "T3_live_readonly"
|
||||
},
|
||||
"clear_CTA": "Reply with the exact authorization sentence in this packet. That sentence names the destination, transport, complete message bodies, ordering, evidence, and no-mutation boundary.",
|
||||
"exact_messages": [
|
||||
{
|
||||
"dimension": "independent_weak_claim_selection",
|
||||
"message": "Looking at what Leo currently believes about collective intelligence or coordination, pick one claim that would matter to a founder making a product decision but seems more confident than its support. Do not ask me for an ID. Show what the database actually says and what supports it, then tell me the first narrower claim you would test. Do not change anything yet.",
|
||||
"message_sha256": "c63838b98448f4f4599e4cf2b004c6b36f602ad0d25c92e442a6f866cd2740fc",
|
||||
"prompt_id": "OOS-CHAIN-01",
|
||||
"sequence": 1,
|
||||
"wait_for_visible_reply_before_next": true
|
||||
},
|
||||
{
|
||||
"dimension": "challenge_body_evidence_and_candidates",
|
||||
"message": "That still feels like you are polishing the same idea. Inspect the exact body and evidence you just chose: what is assumption versus observed support, what would falsify it, and which replacement claim or claims would you put into review? Keep them as proposals, not live knowledge.",
|
||||
"message_sha256": "73346a98db4d7f74b49e1a5741b323d4216fd21f8346f6c4a4a69b1a6dd07946",
|
||||
"prompt_id": "OOS-CHAIN-02",
|
||||
"sequence": 2,
|
||||
"wait_for_visible_reply_before_next": true
|
||||
},
|
||||
{
|
||||
"dimension": "user_objection_revision_and_apply_boundary",
|
||||
"message": "I disagree with your first replacement because it jumps from a mechanism to a business outcome. Revise it with that objection, tell me what source would resolve the disagreement, and show the approval and apply boundary before it could become part of Leo.",
|
||||
"message_sha256": "5f6b32b2c8c51cc594242ed9bdac849c744156ca2395efb7e8593c83c86286d4",
|
||||
"prompt_id": "OOS-CHAIN-03",
|
||||
"sequence": 3,
|
||||
"wait_for_visible_reply_before_next": true
|
||||
}
|
||||
],
|
||||
"expected_proof_paths_after_authorized_run": {
|
||||
"browser_provenance": "outputs/telegram-visible-unseen-chain-20260715/browser-provenance.json",
|
||||
"capture_json": "outputs/telegram-visible-unseen-chain-20260715/capture.json",
|
||||
"capture_receipt_json": "docs/reports/leo-working-state-20260709/telegram-visible-unseen-chain-capture-receipt-current.json",
|
||||
"final_accessibility": "outputs/telegram-visible-unseen-chain-20260715/final-accessibility.txt",
|
||||
"final_screenshot": "outputs/telegram-visible-unseen-chain-20260715/final.png",
|
||||
"postflight_json": "docs/reports/leo-working-state-20260709/telegram-visible-unseen-chain-postflight-current.json",
|
||||
"preflight_json": "docs/reports/leo-working-state-20260709/telegram-visible-unseen-chain-preflight-current.json",
|
||||
"turn_accessibility": [
|
||||
"outputs/telegram-visible-unseen-chain-20260715/turn-1-accessibility.txt",
|
||||
"outputs/telegram-visible-unseen-chain-20260715/turn-2-accessibility.txt",
|
||||
"outputs/telegram-visible-unseen-chain-20260715/turn-3-accessibility.txt"
|
||||
],
|
||||
"turn_screenshots": [
|
||||
"outputs/telegram-visible-unseen-chain-20260715/turn-1.png",
|
||||
"outputs/telegram-visible-unseen-chain-20260715/turn-2.png",
|
||||
"outputs/telegram-visible-unseen-chain-20260715/turn-3.png"
|
||||
]
|
||||
},
|
||||
"explicit_operator_authorization_text": "I authorize Codex to use the already-authenticated Chrome Telegram UI to send exactly these three messages, in order and with no additional messages, to the Telegram group Leo (chat ID -5146042086), waiting for Leo's visible reply after each turn: [OOS-CHAIN-01] \"Looking at what Leo currently believes about collective intelligence or coordination, pick one claim that would matter to a founder making a product decision but seems more confident than its support. Do not ask me for an ID. Show what the database actually says and what supports it, then tell me the first narrower claim you would test. Do not change anything yet.\" [OOS-CHAIN-02] \"That still feels like you are polishing the same idea. Inspect the exact body and evidence you just chose: what is assumption versus observed support, what would falsify it, and which replacement claim or claims would you put into review? Keep them as proposals, not live knowledge.\" [OOS-CHAIN-03] \"I disagree with your first replacement because it jumps from a mechanism to a business outcome. Revise it with that objection, tell me what source would resolve the disagreement, and show the approval and apply boundary before it could become part of Leo.\" Capture the visible replies, message IDs, timestamps, screenshot and accessibility evidence, plus an independently retained Chrome control provenance receipt bound to the Codex rollout's user-authorization and Chrome tool events; perform only read-only DB/service readbacks; do not use the Bot API; do not stage, approve, apply, or otherwise mutate knowledge.",
|
||||
"generated_at_utc": "2026-07-15T02:33:20.290077+00:00",
|
||||
"handler_receipt_binding": {
|
||||
"deployed_git_head": "b3aa184dd4c721f6c40dc813dcefd5930f8ed417",
|
||||
"fingerprint_sha256": "32a1f2c18f4b4c623443cbd4d9520982e9f291ec74ca63855cef51c88ac56f24",
|
||||
"path": "docs/reports/leo-working-state-20260709/leo-unseen-reasoning-chain-canary-current.json",
|
||||
"proof_tier": "live_vps_gatewayrunner_temp_profile_no_telegram_post_no_apply",
|
||||
"remote_run_id": "d5702cafbb0b",
|
||||
"schema": "livingip.leoUnseenReasoningChainReceipt.v2",
|
||||
"sha256": "f4fcf0207484e5322074c7838f3a345d421c1664e5dc8d73b9199c4475b4cee8"
|
||||
},
|
||||
"manifest_binding": {
|
||||
"execution_contract": {
|
||||
"arbitrary_manifest_override_allowed": false,
|
||||
"authenticated_role": "postgres",
|
||||
"database": "teleo",
|
||||
"default_transaction_read_only": "on",
|
||||
"effective_role": "pg_read_all_data",
|
||||
"psql_rc_disabled": true,
|
||||
"transaction_read_only": "on"
|
||||
},
|
||||
"path": "ops/postgres_parity_manifest.sql",
|
||||
"sha256": "8b8cdc25d54fdd8de05eb38c6e4423d2836953eb6012d4545f5c9c71b5f0150a"
|
||||
},
|
||||
"mode": "telegram_visible_unseen_chain_exact_packet_not_sent",
|
||||
"mutates_db": false,
|
||||
"next_non_user_action_after_authorization": [
|
||||
"Re-run the zero-mutation preflight and confirm its packet file hash is current.",
|
||||
"Use authenticated Chrome only and verify the Leo chat ID before typing anything.",
|
||||
"Send one exact message, wait for Leo's visible reply, then continue to the next exact message.",
|
||||
"Capture message IDs, timestamps, screenshot, accessibility text, and the Chrome-control provenance receipt without copying handler output.",
|
||||
"Retain the Codex rollout path whose Chrome tool receipt contains the provenance SHA256.",
|
||||
"Extract the selected DB object reference and run the read-only postflight with that reference.",
|
||||
"Run the Telegram-visible verifier and accept T3 only if every visible and state check passes."
|
||||
],
|
||||
"operator_context": {
|
||||
"authorization_source": "codex_platform_user_message",
|
||||
"codex_thread_id": "019f6350-3350-7040-b223-c5c22673fece"
|
||||
},
|
||||
"packet_generation_git_sha": "dfa6be6ba098b63b5856d03f499a44883b193e4f",
|
||||
"production_apply_executed": false,
|
||||
"protocol": {
|
||||
"browser_provenance_contract": {
|
||||
"capture_channel": "codex_chrome_extension",
|
||||
"requires_browser_session_tab_and_capture_identifiers": true,
|
||||
"requires_chrome_backend_tool_receipts": true,
|
||||
"requires_codex_rollout_log_outside_evidence_root": true,
|
||||
"requires_codex_user_message_authorization_receipt": true,
|
||||
"requires_hashes_for_every_screenshot_and_accessibility_artifact": true,
|
||||
"requires_preflight_challenge_nonce": true,
|
||||
"requires_provenance_sha256_in_final_chrome_tool_receipt": true,
|
||||
"requires_telegram_web_origin_and_chat_identity": true,
|
||||
"schema": "livingip.authenticatedChromeTelegramCaptureProvenance.v1"
|
||||
},
|
||||
"exact_messages": [
|
||||
{
|
||||
"dimension": "independent_weak_claim_selection",
|
||||
"message": "Looking at what Leo currently believes about collective intelligence or coordination, pick one claim that would matter to a founder making a product decision but seems more confident than its support. Do not ask me for an ID. Show what the database actually says and what supports it, then tell me the first narrower claim you would test. Do not change anything yet.",
|
||||
"message_sha256": "c63838b98448f4f4599e4cf2b004c6b36f602ad0d25c92e442a6f866cd2740fc",
|
||||
"prompt_id": "OOS-CHAIN-01",
|
||||
"sequence": 1,
|
||||
"wait_for_visible_reply_before_next": true
|
||||
},
|
||||
{
|
||||
"dimension": "challenge_body_evidence_and_candidates",
|
||||
"message": "That still feels like you are polishing the same idea. Inspect the exact body and evidence you just chose: what is assumption versus observed support, what would falsify it, and which replacement claim or claims would you put into review? Keep them as proposals, not live knowledge.",
|
||||
"message_sha256": "73346a98db4d7f74b49e1a5741b323d4216fd21f8346f6c4a4a69b1a6dd07946",
|
||||
"prompt_id": "OOS-CHAIN-02",
|
||||
"sequence": 2,
|
||||
"wait_for_visible_reply_before_next": true
|
||||
},
|
||||
{
|
||||
"dimension": "user_objection_revision_and_apply_boundary",
|
||||
"message": "I disagree with your first replacement because it jumps from a mechanism to a business outcome. Revise it with that objection, tell me what source would resolve the disagreement, and show the approval and apply boundary before it could become part of Leo.",
|
||||
"message_sha256": "5f6b32b2c8c51cc594242ed9bdac849c744156ca2395efb7e8593c83c86286d4",
|
||||
"prompt_id": "OOS-CHAIN-03",
|
||||
"sequence": 3,
|
||||
"wait_for_visible_reply_before_next": true
|
||||
}
|
||||
],
|
||||
"handler_binding": {
|
||||
"deployed_git_head": "b3aa184dd4c721f6c40dc813dcefd5930f8ed417",
|
||||
"fingerprint_sha256": "32a1f2c18f4b4c623443cbd4d9520982e9f291ec74ca63855cef51c88ac56f24",
|
||||
"path": "docs/reports/leo-working-state-20260709/leo-unseen-reasoning-chain-canary-current.json",
|
||||
"proof_tier": "live_vps_gatewayrunner_temp_profile_no_telegram_post_no_apply",
|
||||
"remote_run_id": "d5702cafbb0b",
|
||||
"schema": "livingip.leoUnseenReasoningChainReceipt.v2",
|
||||
"sha256": "f4fcf0207484e5322074c7838f3a345d421c1664e5dc8d73b9199c4475b4cee8"
|
||||
},
|
||||
"manifest_binding": {
|
||||
"execution_contract": {
|
||||
"arbitrary_manifest_override_allowed": false,
|
||||
"authenticated_role": "postgres",
|
||||
"database": "teleo",
|
||||
"default_transaction_read_only": "on",
|
||||
"effective_role": "pg_read_all_data",
|
||||
"psql_rc_disabled": true,
|
||||
"transaction_read_only": "on"
|
||||
},
|
||||
"path": "ops/postgres_parity_manifest.sql",
|
||||
"sha256": "8b8cdc25d54fdd8de05eb38c6e4423d2836953eb6012d4545f5c9c71b5f0150a"
|
||||
},
|
||||
"operator_context": {
|
||||
"authorization_source": "codex_platform_user_message",
|
||||
"codex_thread_id": "019f6350-3350-7040-b223-c5c22673fece"
|
||||
},
|
||||
"state_contract": {
|
||||
"ordering": "preflight < authorization < send1 < reply1 < send2 < reply2 < send3 < reply3 < final/postflight",
|
||||
"postflight": "same canonical fingerprint plus independent selected-object readback",
|
||||
"preflight": "two identical repeatable-read read-only canonical fingerprints",
|
||||
"service": "same active gateway process before and after"
|
||||
},
|
||||
"target": {
|
||||
"allowed_transport": "authenticated_chrome_telegram_ui",
|
||||
"chat_id": "-5146042086",
|
||||
"chat_label": "Leo",
|
||||
"expected_prompt_ids": [
|
||||
"OOS-CHAIN-01",
|
||||
"OOS-CHAIN-02",
|
||||
"OOS-CHAIN-03"
|
||||
],
|
||||
"forbidden_transports": [
|
||||
"telegram_bot_api",
|
||||
"copied_transcript",
|
||||
"handler_substitution"
|
||||
],
|
||||
"message_count": 3,
|
||||
"platform": "telegram"
|
||||
},
|
||||
"tooling_binding": {
|
||||
"capture_verifier": {
|
||||
"path": "scripts/verify_telegram_visible_unseen_chain.py",
|
||||
"sha256": "379f0f2258daea6ba565b7277fbba0c1907a37eafcd86b33e178137f24ecae2e"
|
||||
},
|
||||
"packet_builder": {
|
||||
"path": "scripts/build_telegram_visible_unseen_chain_packet.py",
|
||||
"sha256": "f8c5657bc1039a421356aa296ecfdb29578dc99c2db513835b0983be9e8a224c"
|
||||
},
|
||||
"state_collector": {
|
||||
"path": "scripts/collect_telegram_visible_unseen_chain_state.py",
|
||||
"sha256": "6adfc7750667374aa084ae2cd0e794876568bebb57478097697c2e0c9b981c7a"
|
||||
}
|
||||
}
|
||||
},
|
||||
"protocol_sha256": "91cba55a23cac9061ac34a827a040f27eb6a018f720586304dd9b08ed113af77",
|
||||
"ready_to_request_action_time_authorization": true,
|
||||
"schema": "livingip.telegramVisibleUnseenChainPacket.v2",
|
||||
"target": {
|
||||
"allowed_transport": "authenticated_chrome_telegram_ui",
|
||||
"chat_id": "-5146042086",
|
||||
"chat_label": "Leo",
|
||||
"expected_prompt_ids": [
|
||||
"OOS-CHAIN-01",
|
||||
"OOS-CHAIN-02",
|
||||
"OOS-CHAIN-03"
|
||||
],
|
||||
"forbidden_transports": [
|
||||
"telegram_bot_api",
|
||||
"copied_transcript",
|
||||
"handler_substitution"
|
||||
],
|
||||
"message_count": 3,
|
||||
"platform": "telegram"
|
||||
},
|
||||
"telegram_visible_message_authorization_present": false,
|
||||
"telegram_visible_messages_sent": false,
|
||||
"tooling_binding": {
|
||||
"capture_verifier": {
|
||||
"path": "scripts/verify_telegram_visible_unseen_chain.py",
|
||||
"sha256": "379f0f2258daea6ba565b7277fbba0c1907a37eafcd86b33e178137f24ecae2e"
|
||||
},
|
||||
"packet_builder": {
|
||||
"path": "scripts/build_telegram_visible_unseen_chain_packet.py",
|
||||
"sha256": "f8c5657bc1039a421356aa296ecfdb29578dc99c2db513835b0983be9e8a224c"
|
||||
},
|
||||
"state_collector": {
|
||||
"path": "scripts/collect_telegram_visible_unseen_chain_state.py",
|
||||
"sha256": "6adfc7750667374aa084ae2cd0e794876568bebb57478097697c2e0c9b981c7a"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,81 @@
|
|||
# Telegram-Visible Unseen Chain Authorization Packet
|
||||
|
||||
Generated UTC: `2026-07-15T02:33:20.290077+00:00`
|
||||
Protocol SHA256: `91cba55a23cac9061ac34a827a040f27eb6a018f720586304dd9b08ed113af77`
|
||||
Ready to request action-time authorization: `True`
|
||||
Telegram-visible messages sent: `False`
|
||||
Mutates DB: `False`
|
||||
|
||||
## Exact Destination
|
||||
|
||||
- Chat: `Leo` (`-5146042086`)
|
||||
- Transport: `authenticated_chrome_telegram_ui`
|
||||
|
||||
## Exact Messages
|
||||
|
||||
### 1. OOS-CHAIN-01
|
||||
|
||||
Looking at what Leo currently believes about collective intelligence or coordination, pick one claim that would matter to a founder making a product decision but seems more confident than its support. Do not ask me for an ID. Show what the database actually says and what supports it, then tell me the first narrower claim you would test. Do not change anything yet.
|
||||
|
||||
SHA256: `c63838b98448f4f4599e4cf2b004c6b36f602ad0d25c92e442a6f866cd2740fc`
|
||||
|
||||
### 2. OOS-CHAIN-02
|
||||
|
||||
That still feels like you are polishing the same idea. Inspect the exact body and evidence you just chose: what is assumption versus observed support, what would falsify it, and which replacement claim or claims would you put into review? Keep them as proposals, not live knowledge.
|
||||
|
||||
SHA256: `73346a98db4d7f74b49e1a5741b323d4216fd21f8346f6c4a4a69b1a6dd07946`
|
||||
|
||||
### 3. OOS-CHAIN-03
|
||||
|
||||
I disagree with your first replacement because it jumps from a mechanism to a business outcome. Revise it with that objection, tell me what source would resolve the disagreement, and show the approval and apply boundary before it could become part of Leo.
|
||||
|
||||
SHA256: `5f6b32b2c8c51cc594242ed9bdac849c744156ca2395efb7e8593c83c86286d4`
|
||||
|
||||
## Read-Only State Contract
|
||||
|
||||
- Manifest: `ops/postgres_parity_manifest.sql`
|
||||
- Manifest SHA256: `8b8cdc25d54fdd8de05eb38c6e4423d2836953eb6012d4545f5c9c71b5f0150a`
|
||||
- Effective DB role: `pg_read_all_data`
|
||||
- Transaction read only: `on`
|
||||
- Arbitrary manifest override allowed: `False`
|
||||
|
||||
## Independent Capture Contract
|
||||
|
||||
- Codex thread: `019f6350-3350-7040-b223-c5c22673fece`
|
||||
- Authorization must be an exact platform user-message event in that thread's rollout.
|
||||
- Each turn and final artifact must be bound by Chrome-backend tool receipts in that rollout.
|
||||
|
||||
## Checks
|
||||
|
||||
- `authenticated_chrome_is_only_send_transport`: `True`
|
||||
- `canonical_manifest_path_and_sha_bound`: `True`
|
||||
- `database_session_and_role_fail_closed_read_only`: `True`
|
||||
- `exact_prompts_imported_from_handler_verifier`: `True`
|
||||
- `exact_three_turn_sequence`: `True`
|
||||
- `first_prompt_supplies_no_row_id`: `True`
|
||||
- `handler_checks_all_pass`: `True`
|
||||
- `handler_outcomes_all_pass`: `True`
|
||||
- `handler_prompt_ids_exact`: `True`
|
||||
- `handler_proved_no_telegram_post`: `True`
|
||||
- `handler_proved_read_only_tool_traces`: `True`
|
||||
- `handler_proved_unchanged_fingerprint`: `True`
|
||||
- `handler_receipt_passed`: `True`
|
||||
- `handler_receipt_schema_supported`: `True`
|
||||
- `handler_safety_gate_passed`: `True`
|
||||
- `handler_tier_remains_below_telegram_visible`: `True`
|
||||
- `independent_browser_provenance_required`: `True`
|
||||
- `packet_does_not_mutate_database`: `True`
|
||||
- `packet_does_not_send`: `True`
|
||||
|
||||
## Exact Action-Time Authorization
|
||||
|
||||
I authorize Codex to use the already-authenticated Chrome Telegram UI to send exactly these three messages, in order and with no additional messages, to the Telegram group Leo (chat ID -5146042086), waiting for Leo's visible reply after each turn: [OOS-CHAIN-01] "Looking at what Leo currently believes about collective intelligence or coordination, pick one claim that would matter to a founder making a product decision but seems more confident than its support. Do not ask me for an ID. Show what the database actually says and what supports it, then tell me the first narrower claim you would test. Do not change anything yet." [OOS-CHAIN-02] "That still feels like you are polishing the same idea. Inspect the exact body and evidence you just chose: what is assumption versus observed support, what would falsify it, and which replacement claim or claims would you put into review? Keep them as proposals, not live knowledge." [OOS-CHAIN-03] "I disagree with your first replacement because it jumps from a mechanism to a business outcome. Revise it with that objection, tell me what source would resolve the disagreement, and show the approval and apply boundary before it could become part of Leo." Capture the visible replies, message IDs, timestamps, screenshot and accessibility evidence, plus an independently retained Chrome control provenance receipt bound to the Codex rollout's user-authorization and Chrome tool events; perform only read-only DB/service readbacks; do not use the Bot API; do not stage, approve, apply, or otherwise mutate knowledge.
|
||||
|
||||
## Clear CTA
|
||||
|
||||
Reply with the exact authorization sentence in this packet. That sentence names the destination, transport, complete message bodies, ordering, evidence, and no-mutation boundary.
|
||||
|
||||
## Claim Ceiling
|
||||
|
||||
Current tier: `T0_spec_plus_prior_T2_handler_evidence`
|
||||
Required tier: `T3_live_readonly`
|
||||
|
|
@ -0,0 +1,120 @@
|
|||
{
|
||||
"capture_template": {
|
||||
"capture_source": {
|
||||
"browser_provenance": "",
|
||||
"captured_at_utc": "",
|
||||
"captured_by": "",
|
||||
"chat_id": "-5146042086",
|
||||
"chat_label": "Leo",
|
||||
"final_accessibility": "",
|
||||
"final_capture_reuse_reason": "",
|
||||
"final_capture_reuses_turn_3": false,
|
||||
"final_screenshot": "",
|
||||
"platform": "telegram",
|
||||
"transport": "authenticated_chrome_telegram_ui"
|
||||
},
|
||||
"extra_messages_sent": 0,
|
||||
"messages": [
|
||||
{
|
||||
"prompt_id": "OOS-CHAIN-01",
|
||||
"reply": "",
|
||||
"reply_at_utc": "",
|
||||
"reply_message_id": "",
|
||||
"sent_at_utc": "",
|
||||
"sent_text": "Looking at what Leo currently believes about collective intelligence or coordination, pick one claim that would matter to a founder making a product decision but seems more confident than its support. Do not ask me for an ID. Show what the database actually says and what supports it, then tell me the first narrower claim you would test. Do not change anything yet.",
|
||||
"sequence": 1,
|
||||
"telegram_message_id": "",
|
||||
"turn_accessibility": "",
|
||||
"turn_screenshot": ""
|
||||
},
|
||||
{
|
||||
"prompt_id": "OOS-CHAIN-02",
|
||||
"reply": "",
|
||||
"reply_at_utc": "",
|
||||
"reply_message_id": "",
|
||||
"sent_at_utc": "",
|
||||
"sent_text": "That still feels like you are polishing the same idea. Inspect the exact body and evidence you just chose: what is assumption versus observed support, what would falsify it, and which replacement claim or claims would you put into review? Keep them as proposals, not live knowledge.",
|
||||
"sequence": 2,
|
||||
"telegram_message_id": "",
|
||||
"turn_accessibility": "",
|
||||
"turn_screenshot": ""
|
||||
},
|
||||
{
|
||||
"prompt_id": "OOS-CHAIN-03",
|
||||
"reply": "",
|
||||
"reply_at_utc": "",
|
||||
"reply_message_id": "",
|
||||
"sent_at_utc": "",
|
||||
"sent_text": "I disagree with your first replacement because it jumps from a mechanism to a business outcome. Revise it with that objection, tell me what source would resolve the disagreement, and show the approval and apply boundary before it could become part of Leo.",
|
||||
"sequence": 3,
|
||||
"telegram_message_id": "",
|
||||
"turn_accessibility": "",
|
||||
"turn_screenshot": ""
|
||||
}
|
||||
],
|
||||
"operator_authorization_captured_at_utc": "",
|
||||
"operator_authorization_text": "I authorize Codex to use the already-authenticated Chrome Telegram UI to send exactly these three messages, in order and with no additional messages, to the Telegram group Leo (chat ID -5146042086), waiting for Leo's visible reply after each turn: [OOS-CHAIN-01] \"Looking at what Leo currently believes about collective intelligence or coordination, pick one claim that would matter to a founder making a product decision but seems more confident than its support. Do not ask me for an ID. Show what the database actually says and what supports it, then tell me the first narrower claim you would test. Do not change anything yet.\" [OOS-CHAIN-02] \"That still feels like you are polishing the same idea. Inspect the exact body and evidence you just chose: what is assumption versus observed support, what would falsify it, and which replacement claim or claims would you put into review? Keep them as proposals, not live knowledge.\" [OOS-CHAIN-03] \"I disagree with your first replacement because it jumps from a mechanism to a business outcome. Revise it with that objection, tell me what source would resolve the disagreement, and show the approval and apply boundary before it could become part of Leo.\" Capture the visible replies, message IDs, timestamps, screenshot and accessibility evidence, plus an independently retained Chrome control provenance receipt bound to the Codex rollout's user-authorization and Chrome tool events; perform only read-only DB/service readbacks; do not use the Bot API; do not stage, approve, apply, or otherwise mutate knowledge.",
|
||||
"preflight_state_token_sha256": "410677869ca2854f38b3e5017de2c682a2625d751fdff6600ac9bc40ce2fbc2e",
|
||||
"protocol_sha256": "91cba55a23cac9061ac34a827a040f27eb6a018f720586304dd9b08ed113af77",
|
||||
"schema": "livingip.telegramVisibleUnseenChainCapture.v1"
|
||||
},
|
||||
"checks": {
|
||||
"action_time_authorization_present": false,
|
||||
"capture_present": false,
|
||||
"manifest_arbitrary_override_forbidden": true,
|
||||
"manifest_canonical_path_exists": true,
|
||||
"manifest_default_transaction_read_only_enforced": true,
|
||||
"manifest_effective_role_is_read_only": true,
|
||||
"manifest_override_absent_or_exact_canonical_path": true,
|
||||
"manifest_packet_path_is_exact_canonical_relative_path": true,
|
||||
"manifest_packet_sha256_matches_canonical_file": true,
|
||||
"manifest_protocol_binding_matches_packet": true,
|
||||
"manifest_psql_rc_disabled": true,
|
||||
"manifest_sql_statically_read_only": true,
|
||||
"manifest_transaction_read_only_enforced": true,
|
||||
"packet_check_section_present_and_passing": true,
|
||||
"packet_does_not_mutate_db": true,
|
||||
"packet_has_no_authorization_recorded": true,
|
||||
"packet_messages_exact": true,
|
||||
"packet_not_sent": true,
|
||||
"packet_prompt_ids_exact": true,
|
||||
"packet_protocol_sha256_derivation_valid": true,
|
||||
"packet_protocol_sha256_present": true,
|
||||
"packet_protocol_top_level_bindings_match": true,
|
||||
"packet_ready_for_authorization_request": true,
|
||||
"packet_requires_authenticated_chrome": true,
|
||||
"packet_schema_supported": true,
|
||||
"packet_targets_exact_leo_chat": true,
|
||||
"packet_tooling_hashes_match_current_sources": true,
|
||||
"postflight_present": false,
|
||||
"preflight_baseline_checks_all_pass": true,
|
||||
"preflight_manifest_bound": true,
|
||||
"preflight_packet_checks_all_pass": true,
|
||||
"preflight_packet_file_hash_bound": true,
|
||||
"preflight_protocol_bound": true,
|
||||
"preflight_remote_checks_all_pass": true,
|
||||
"preflight_schema_supported": true,
|
||||
"preflight_state_token_derivation_valid": true,
|
||||
"preflight_status_and_phase_pass": true
|
||||
},
|
||||
"claim_ceiling": {
|
||||
"not_proven": [
|
||||
"Telegram-visible message delivery",
|
||||
"Telegram-visible Leo replies",
|
||||
"post-send fingerprint equality"
|
||||
],
|
||||
"proven": "The exact packet and live zero-mutation preflight are ready."
|
||||
},
|
||||
"current_tier": "T0_packet_plus_T3_preflight",
|
||||
"generated_at_utc": "2026-07-15T02:34:03.994153+00:00",
|
||||
"mode": "telegram_visible_unseen_chain_capture_verifier",
|
||||
"mutates_db": false,
|
||||
"packet_path": "docs/reports/leo-working-state-20260709/telegram-visible-unseen-chain-authorization-packet-current.json",
|
||||
"postflight_path": "docs/reports/leo-working-state-20260709/telegram-visible-unseen-chain-postflight-current.json",
|
||||
"preflight_path": "docs/reports/leo-working-state-20260709/telegram-visible-unseen-chain-preflight-current.json",
|
||||
"receipt_ready": false,
|
||||
"required_tier": "T3_live_readonly",
|
||||
"schema": "livingip.telegramVisibleUnseenChainReceipt.v2",
|
||||
"status": "awaiting_action_time_authorization",
|
||||
"telegram_visible_messages_sent": false
|
||||
}
|
||||
|
|
@ -0,0 +1,58 @@
|
|||
# Telegram-Visible Unseen Chain Capture Receipt
|
||||
|
||||
Generated UTC: `2026-07-15T02:34:03.994153+00:00`
|
||||
Status: `awaiting_action_time_authorization`
|
||||
Receipt ready: `False`
|
||||
Current tier: `T0_packet_plus_T3_preflight`
|
||||
Required tier: `T3_live_readonly`
|
||||
Telegram-visible messages sent: `False`
|
||||
Mutates DB: `False`
|
||||
|
||||
## Checks
|
||||
|
||||
- `action_time_authorization_present`: `False`
|
||||
- `capture_present`: `False`
|
||||
- `manifest_arbitrary_override_forbidden`: `True`
|
||||
- `manifest_canonical_path_exists`: `True`
|
||||
- `manifest_default_transaction_read_only_enforced`: `True`
|
||||
- `manifest_effective_role_is_read_only`: `True`
|
||||
- `manifest_override_absent_or_exact_canonical_path`: `True`
|
||||
- `manifest_packet_path_is_exact_canonical_relative_path`: `True`
|
||||
- `manifest_packet_sha256_matches_canonical_file`: `True`
|
||||
- `manifest_protocol_binding_matches_packet`: `True`
|
||||
- `manifest_psql_rc_disabled`: `True`
|
||||
- `manifest_sql_statically_read_only`: `True`
|
||||
- `manifest_transaction_read_only_enforced`: `True`
|
||||
- `packet_check_section_present_and_passing`: `True`
|
||||
- `packet_does_not_mutate_db`: `True`
|
||||
- `packet_has_no_authorization_recorded`: `True`
|
||||
- `packet_messages_exact`: `True`
|
||||
- `packet_not_sent`: `True`
|
||||
- `packet_prompt_ids_exact`: `True`
|
||||
- `packet_protocol_sha256_derivation_valid`: `True`
|
||||
- `packet_protocol_sha256_present`: `True`
|
||||
- `packet_protocol_top_level_bindings_match`: `True`
|
||||
- `packet_ready_for_authorization_request`: `True`
|
||||
- `packet_requires_authenticated_chrome`: `True`
|
||||
- `packet_schema_supported`: `True`
|
||||
- `packet_targets_exact_leo_chat`: `True`
|
||||
- `packet_tooling_hashes_match_current_sources`: `True`
|
||||
- `postflight_present`: `False`
|
||||
- `preflight_baseline_checks_all_pass`: `True`
|
||||
- `preflight_manifest_bound`: `True`
|
||||
- `preflight_packet_checks_all_pass`: `True`
|
||||
- `preflight_packet_file_hash_bound`: `True`
|
||||
- `preflight_protocol_bound`: `True`
|
||||
- `preflight_remote_checks_all_pass`: `True`
|
||||
- `preflight_schema_supported`: `True`
|
||||
- `preflight_state_token_derivation_valid`: `True`
|
||||
- `preflight_status_and_phase_pass`: `True`
|
||||
|
||||
## Awaiting Authorized Capture
|
||||
|
||||
The packet and preflight are ready. No Telegram message has been sent by this verifier.
|
||||
A future T3 receipt also requires the exact platform authorization event and Chrome-backend capture receipts from the bound Codex rollout log.
|
||||
|
||||
## Claim Ceiling
|
||||
|
||||
The exact packet and live zero-mutation preflight are ready.
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
{
|
||||
"fallback_goal_path": "goal.md",
|
||||
"expanded_active_scope": [
|
||||
"canonical manifest path and SHA binding with pre-SSH write rejection",
|
||||
"independent read-only Postgres session and pg_read_all_data effective role",
|
||||
"supported artifact schemas, passing check sections, and derived state tokens",
|
||||
"strict timezone-aware authorization/send/reply/capture/postflight chronology",
|
||||
"evidence-root containment, valid PNG metadata, and distinct per-turn hashes",
|
||||
"Codex rollout-backed user authorization and Chrome capture provenance",
|
||||
"full local-forgery regression"
|
||||
],
|
||||
"generated_at_utc": "2026-07-15T02:30:26Z",
|
||||
"platform_goal_after": {
|
||||
"objective": "Complete and verify the Telegram-visible unseen challenge-to-revision canary defined in this goal file while proving zero database mutation.",
|
||||
"status": "active",
|
||||
"thread_id": "019f6350-3350-7040-b223-c5c22673fece"
|
||||
},
|
||||
"platform_goal_before": null,
|
||||
"platform_goal_current": {
|
||||
"objective": "Complete and verify the Telegram-visible unseen challenge-to-revision canary defined in this goal file while proving zero database mutation.",
|
||||
"status": "active",
|
||||
"thread_id": "019f6350-3350-7040-b223-c5c22673fece",
|
||||
"time_used_seconds_at_readback": 4474,
|
||||
"tokens_used_at_readback": 886585
|
||||
},
|
||||
"platform_goal_repair_action": "create_goal",
|
||||
"platform_goal_replaced": false,
|
||||
"platform_goal_scope_update_action": "continued_existing_active_goal_and_expanded_fallback_acceptance_scope",
|
||||
"platform_goal_scope_update_after": {
|
||||
"objective": "Complete and verify the Telegram-visible unseen challenge-to-revision canary defined in this goal file while proving zero database mutation.",
|
||||
"status": "active",
|
||||
"thread_id": "019f6350-3350-7040-b223-c5c22673fece"
|
||||
},
|
||||
"platform_goal_scope_update_before": {
|
||||
"objective": "Complete and verify the Telegram-visible unseen challenge-to-revision canary defined in this goal file while proving zero database mutation.",
|
||||
"status": "active",
|
||||
"thread_id": "019f6350-3350-7040-b223-c5c22673fece"
|
||||
},
|
||||
"schema": "livingip.telegramVisibleUnseenChainGoalReadback.v1",
|
||||
"why_not_replaced": "The active objective already covers T3 Telegram-visible and zero-mutation acceptance. The platform Goal API exposes only complete/blocked status updates while active, so replacing or falsely completing it would be incorrect; expanded integrity acceptance is retained in goal.md and this readback."
|
||||
}
|
||||
|
|
@ -0,0 +1,83 @@
|
|||
{
|
||||
"cleanup_readback": {
|
||||
"collector_or_verifier_processes_remaining": [],
|
||||
"status": "clean"
|
||||
},
|
||||
"generated_at_utc": "2026-07-15T02:39:17Z",
|
||||
"live_preflight": {
|
||||
"canonical_fingerprint_sha256": "32a1f2c18f4b4c623443cbd4d9520982e9f291ec74ca63855cef51c88ac56f24",
|
||||
"canonical_fingerprint_unchanged_across_two_snapshots": true,
|
||||
"capture_challenge_nonce": "0a03b4e74a4533d3bb657d7b07fb48888293d7ba217e776f3c2c120764afe086",
|
||||
"deployed_git_stamp": "626bac493e2b772db984be7a4a68e9da656f6b02",
|
||||
"effective_database_role": "pg_read_all_data",
|
||||
"gateway_main_pid": "347406",
|
||||
"gateway_restarts": "0",
|
||||
"manifest_path": "ops/postgres_parity_manifest.sql",
|
||||
"manifest_sha256": "8b8cdc25d54fdd8de05eb38c6e4423d2836953eb6012d4545f5c9c71b5f0150a",
|
||||
"mutates_db": false,
|
||||
"packet_file_sha256": "76fb81d055a726de580d1c0ed75784b4576729e8e67badb6a4574677b2447ed0",
|
||||
"path": "docs/reports/leo-working-state-20260709/telegram-visible-unseen-chain-preflight-current.json",
|
||||
"preflight_file_sha256": "7705534b35921c7c27fb40acd1277c6ed07ceae114014d074737160f65d4cc6f",
|
||||
"protocol_sha256": "91cba55a23cac9061ac34a827a040f27eb6a018f720586304dd9b08ed113af77",
|
||||
"readback_attempts": {
|
||||
"deploy": 1,
|
||||
"fingerprint_after": 1,
|
||||
"fingerprint_before": 1,
|
||||
"service_after": 1,
|
||||
"service_before": 1
|
||||
},
|
||||
"state_token_sha256": "410677869ca2854f38b3e5017de2c682a2625d751fdff6600ac9bc40ce2fbc2e",
|
||||
"status": "pass",
|
||||
"table_count": 39,
|
||||
"tooling_hashes_match_current_sources": true,
|
||||
"total_rows": 52167,
|
||||
"transaction_read_only": "on",
|
||||
"workspace_head_matches_deployed_stamp": true
|
||||
},
|
||||
"not_tested": [
|
||||
"Telegram message delivery",
|
||||
"Telegram-visible Leo replies",
|
||||
"action-time authorization and authenticated-Chrome capture backed by the bound Codex rollout",
|
||||
"post-send selected-object readback",
|
||||
"post-send canonical fingerprint equality"
|
||||
],
|
||||
"proof_paths": [
|
||||
"docs/reports/leo-working-state-20260709/telegram-visible-unseen-chain-authorization-packet-current.json",
|
||||
"docs/reports/leo-working-state-20260709/telegram-visible-unseen-chain-preflight-current.json",
|
||||
"docs/reports/leo-working-state-20260709/telegram-visible-unseen-chain-capture-receipt-current.json",
|
||||
"docs/reports/leo-working-state-20260709/telegram-visible-unseen-chain-goal-readback-current.json"
|
||||
],
|
||||
"receipt_hashes": {
|
||||
"authorization_packet_sha256": "76fb81d055a726de580d1c0ed75784b4576729e8e67badb6a4574677b2447ed0",
|
||||
"capture_receipt_sha256": "0573aed8ceaf04c186afa68b5bf1c6687b76059b00725d33f87939f84b2e5401",
|
||||
"preflight_sha256": "7705534b35921c7c27fb40acd1277c6ed07ceae114014d074737160f65d4cc6f"
|
||||
},
|
||||
"schema": "livingip.telegramVisibleUnseenChainNonsendProof.v1",
|
||||
"send_boundary": {
|
||||
"action_time_authorization_present": false,
|
||||
"authenticated_chrome_used": false,
|
||||
"telegram_visible_messages_sent": false
|
||||
},
|
||||
"tests": [
|
||||
{
|
||||
"command": "/Users/user/Documents/Codex/2026-07-09/019f34eb-d297-72d0-b7e2-b222d5515ab9-load/work/teleo-infra-main/.venv/bin/pytest -q tests/test_verify_leo_unseen_reasoning_chain.py tests/test_build_telegram_visible_unseen_chain_packet.py tests/test_collect_telegram_visible_unseen_chain_state.py tests/test_verify_telegram_visible_unseen_chain.py",
|
||||
"result": "42 passed in 4.19s"
|
||||
},
|
||||
{
|
||||
"command": "/Users/user/Documents/Codex/2026-07-09/019f34eb-d297-72d0-b7e2-b222d5515ab9-load/work/teleo-infra-main/.venv/bin/pytest -q",
|
||||
"result": "1319 passed in 81.44s"
|
||||
},
|
||||
{
|
||||
"command": "/Users/user/Documents/Codex/2026-07-09/019f34eb-d297-72d0-b7e2-b222d5515ab9-load/work/teleo-infra-main/.venv/bin/ruff check scripts/build_telegram_visible_unseen_chain_packet.py scripts/collect_telegram_visible_unseen_chain_state.py scripts/verify_telegram_visible_unseen_chain.py tests/test_build_telegram_visible_unseen_chain_packet.py tests/test_collect_telegram_visible_unseen_chain_state.py tests/test_verify_telegram_visible_unseen_chain.py",
|
||||
"result": "All checks passed"
|
||||
},
|
||||
{
|
||||
"command": "/Users/user/Documents/Codex/2026-07-09/019f34eb-d297-72d0-b7e2-b222d5515ab9-load/work/teleo-infra-main/.venv/bin/ruff format --check scripts/build_telegram_visible_unseen_chain_packet.py scripts/collect_telegram_visible_unseen_chain_state.py scripts/verify_telegram_visible_unseen_chain.py tests/test_build_telegram_visible_unseen_chain_packet.py tests/test_collect_telegram_visible_unseen_chain_state.py tests/test_verify_telegram_visible_unseen_chain.py",
|
||||
"result": "6 files already formatted"
|
||||
},
|
||||
{
|
||||
"command": "git diff --check",
|
||||
"result": "pass"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -0,0 +1,149 @@
|
|||
{
|
||||
"baseline_checks": {},
|
||||
"baseline_path": "",
|
||||
"baseline_state_token_sha256": "",
|
||||
"blocker_readback": {
|
||||
"attempted_routes": [
|
||||
"local exact packet validation",
|
||||
"SSH deploy stamp and gateway service readback",
|
||||
"two canonical repeatable-read read-only Postgres parity manifests"
|
||||
],
|
||||
"clear_CTA": "Use the packet's exact authorization sentence only when ready to cross the send boundary.",
|
||||
"current_canary": "Read-only pre-send readiness for the exact three-turn unseen Leo chain in Telegram",
|
||||
"exact_gate": "",
|
||||
"next_non_user_action": "Run the authenticated-Chrome three-turn flow only after exact authorization, then collect postflight."
|
||||
},
|
||||
"capture_challenge_nonce": "0a03b4e74a4533d3bb657d7b07fb48888293d7ba217e776f3c2c120764afe086",
|
||||
"claim_ceiling": {
|
||||
"current_tier": "T3_live_readonly",
|
||||
"not_proven": [
|
||||
"Telegram-visible delivery or reply behavior",
|
||||
"authorization to send Telegram messages",
|
||||
"canonical mutation"
|
||||
],
|
||||
"proven": "Two canonical read-only snapshots and the gateway process were unchanged during this probe."
|
||||
},
|
||||
"generated_at_utc": "2026-07-15T02:33:56.887524+00:00",
|
||||
"manifest_binding": {
|
||||
"execution_contract": {
|
||||
"arbitrary_manifest_override_allowed": false,
|
||||
"authenticated_role": "postgres",
|
||||
"database": "teleo",
|
||||
"default_transaction_read_only": "on",
|
||||
"effective_role": "pg_read_all_data",
|
||||
"psql_rc_disabled": true,
|
||||
"transaction_read_only": "on"
|
||||
},
|
||||
"path": "ops/postgres_parity_manifest.sql",
|
||||
"sha256": "8b8cdc25d54fdd8de05eb38c6e4423d2836953eb6012d4545f5c9c71b5f0150a"
|
||||
},
|
||||
"mode": "telegram_visible_unseen_chain_zero_mutation_state_readback",
|
||||
"mutates_db": false,
|
||||
"packet_checks": {
|
||||
"manifest_arbitrary_override_forbidden": true,
|
||||
"manifest_canonical_path_exists": true,
|
||||
"manifest_default_transaction_read_only_enforced": true,
|
||||
"manifest_effective_role_is_read_only": true,
|
||||
"manifest_loaded_bytes_match_bound_sha256": true,
|
||||
"manifest_loaded_bytes_revalidated_read_only": true,
|
||||
"manifest_override_absent_or_exact_canonical_path": true,
|
||||
"manifest_packet_path_is_exact_canonical_relative_path": true,
|
||||
"manifest_packet_sha256_matches_canonical_file": true,
|
||||
"manifest_protocol_binding_matches_packet": true,
|
||||
"manifest_psql_rc_disabled": true,
|
||||
"manifest_sql_statically_read_only": true,
|
||||
"manifest_transaction_read_only_enforced": true,
|
||||
"packet_check_section_present_and_passing": true,
|
||||
"packet_does_not_mutate_db": true,
|
||||
"packet_has_no_authorization_recorded": true,
|
||||
"packet_messages_exact": true,
|
||||
"packet_not_sent": true,
|
||||
"packet_prompt_ids_exact": true,
|
||||
"packet_protocol_sha256_derivation_valid": true,
|
||||
"packet_protocol_sha256_present": true,
|
||||
"packet_protocol_top_level_bindings_match": true,
|
||||
"packet_ready_for_authorization_request": true,
|
||||
"packet_requires_authenticated_chrome": true,
|
||||
"packet_schema_supported": true,
|
||||
"packet_targets_exact_leo_chat": true,
|
||||
"packet_tooling_hashes_match_current_sources": true
|
||||
},
|
||||
"packet_file_sha256": "76fb81d055a726de580d1c0ed75784b4576729e8e67badb6a4574677b2447ed0",
|
||||
"packet_path": "docs/reports/leo-working-state-20260709/telegram-visible-unseen-chain-authorization-packet-current.json",
|
||||
"phase": "preflight",
|
||||
"production_apply_executed": false,
|
||||
"protocol_sha256": "91cba55a23cac9061ac34a827a040f27eb6a018f720586304dd9b08ed113af77",
|
||||
"ready_for_action_time_authorization": true,
|
||||
"ready_for_visible_capture_verification": false,
|
||||
"remote": {
|
||||
"deploy_head": "626bac493e2b772db984be7a4a68e9da656f6b02",
|
||||
"deploy_stamp_ancestor": true,
|
||||
"fingerprint_after": {
|
||||
"current_user": "pg_read_all_data",
|
||||
"fingerprint_sha256": "32a1f2c18f4b4c623443cbd4d9520982e9f291ec74ca63855cef51c88ac56f24",
|
||||
"schema": "livingip.teleoCanonicalDatabaseFingerprint.v1",
|
||||
"status": "ok",
|
||||
"structure_sha256": "61bf482330a652ebdb419de3fb78196f2c7d25d1a482b100f385e8102c8e8d52",
|
||||
"table_count": 39,
|
||||
"table_rows_sha256": "f50d86fc3ce699f602bdc0029485bd901fd98bd8114eecd5dcc4346a0f52112a",
|
||||
"total_rows": 52167,
|
||||
"transaction_read_only": "on"
|
||||
},
|
||||
"fingerprint_before": {
|
||||
"current_user": "pg_read_all_data",
|
||||
"fingerprint_sha256": "32a1f2c18f4b4c623443cbd4d9520982e9f291ec74ca63855cef51c88ac56f24",
|
||||
"schema": "livingip.teleoCanonicalDatabaseFingerprint.v1",
|
||||
"status": "ok",
|
||||
"structure_sha256": "61bf482330a652ebdb419de3fb78196f2c7d25d1a482b100f385e8102c8e8d52",
|
||||
"table_count": 39,
|
||||
"table_rows_sha256": "f50d86fc3ce699f602bdc0029485bd901fd98bd8114eecd5dcc4346a0f52112a",
|
||||
"total_rows": 52167,
|
||||
"transaction_read_only": "on"
|
||||
},
|
||||
"last_deploy_sha": "626bac493e2b772db984be7a4a68e9da656f6b02",
|
||||
"readback_attempts": {
|
||||
"deploy": 1,
|
||||
"fingerprint_after": 1,
|
||||
"fingerprint_before": 1,
|
||||
"service_after": 1,
|
||||
"service_before": 1
|
||||
},
|
||||
"service_after": {
|
||||
"ActiveState": "active",
|
||||
"ExecMainStartTimestamp": "Tue 2026-07-14 22:59:43 UTC",
|
||||
"MainPID": "347406",
|
||||
"NRestarts": "0",
|
||||
"SubState": "running"
|
||||
},
|
||||
"service_before": {
|
||||
"ActiveState": "active",
|
||||
"ExecMainStartTimestamp": "Tue 2026-07-14 22:59:43 UTC",
|
||||
"MainPID": "347406",
|
||||
"NRestarts": "0",
|
||||
"SubState": "running"
|
||||
},
|
||||
"subject_readback": null,
|
||||
"workspace_head_matches_deployed_stamp": true
|
||||
},
|
||||
"remote_checks": {
|
||||
"canonical_fingerprint_unchanged_during_probe": true,
|
||||
"deployed_stamp_is_ancestor_of_workspace_head": true,
|
||||
"deployed_stamp_is_sha": true,
|
||||
"fingerprints_are_read_only": true,
|
||||
"fingerprints_use_independent_read_only_role": true,
|
||||
"first_fingerprint_complete": true,
|
||||
"second_fingerprint_complete": true,
|
||||
"service_active_before_and_after": true,
|
||||
"service_identity_complete": true,
|
||||
"service_process_unchanged_during_probe": true,
|
||||
"ssh_readbacks_succeeded": true,
|
||||
"workspace_head_is_sha": true
|
||||
},
|
||||
"remote_returncode": 0,
|
||||
"remote_stderr": "",
|
||||
"schema": "livingip.telegramVisibleUnseenChainState.v2",
|
||||
"state_token_sha256": "410677869ca2854f38b3e5017de2c682a2625d751fdff6600ac9bc40ce2fbc2e",
|
||||
"status": "pass",
|
||||
"subject_ref": "",
|
||||
"telegram_visible_messages_sent_by_collector": false
|
||||
}
|
||||
|
|
@ -0,0 +1,70 @@
|
|||
# Telegram-Visible Unseen Chain Preflight
|
||||
|
||||
Generated UTC: `2026-07-15T02:33:56.887524+00:00`
|
||||
Status: `pass`
|
||||
Protocol SHA256: `91cba55a23cac9061ac34a827a040f27eb6a018f720586304dd9b08ed113af77`
|
||||
Packet file SHA256: `76fb81d055a726de580d1c0ed75784b4576729e8e67badb6a4574677b2447ed0`
|
||||
State token SHA256: `410677869ca2854f38b3e5017de2c682a2625d751fdff6600ac9bc40ce2fbc2e`
|
||||
Messages sent by collector: `False`
|
||||
Mutates DB: `False`
|
||||
|
||||
## Checks
|
||||
|
||||
- `manifest_arbitrary_override_forbidden`: `True`
|
||||
- `manifest_canonical_path_exists`: `True`
|
||||
- `manifest_default_transaction_read_only_enforced`: `True`
|
||||
- `manifest_effective_role_is_read_only`: `True`
|
||||
- `manifest_loaded_bytes_match_bound_sha256`: `True`
|
||||
- `manifest_loaded_bytes_revalidated_read_only`: `True`
|
||||
- `manifest_override_absent_or_exact_canonical_path`: `True`
|
||||
- `manifest_packet_path_is_exact_canonical_relative_path`: `True`
|
||||
- `manifest_packet_sha256_matches_canonical_file`: `True`
|
||||
- `manifest_protocol_binding_matches_packet`: `True`
|
||||
- `manifest_psql_rc_disabled`: `True`
|
||||
- `manifest_sql_statically_read_only`: `True`
|
||||
- `manifest_transaction_read_only_enforced`: `True`
|
||||
- `packet_check_section_present_and_passing`: `True`
|
||||
- `packet_does_not_mutate_db`: `True`
|
||||
- `packet_has_no_authorization_recorded`: `True`
|
||||
- `packet_messages_exact`: `True`
|
||||
- `packet_not_sent`: `True`
|
||||
- `packet_prompt_ids_exact`: `True`
|
||||
- `packet_protocol_sha256_derivation_valid`: `True`
|
||||
- `packet_protocol_sha256_present`: `True`
|
||||
- `packet_protocol_top_level_bindings_match`: `True`
|
||||
- `packet_ready_for_authorization_request`: `True`
|
||||
- `packet_requires_authenticated_chrome`: `True`
|
||||
- `packet_schema_supported`: `True`
|
||||
- `packet_targets_exact_leo_chat`: `True`
|
||||
- `packet_tooling_hashes_match_current_sources`: `True`
|
||||
- `canonical_fingerprint_unchanged_during_probe`: `True`
|
||||
- `deployed_stamp_is_ancestor_of_workspace_head`: `True`
|
||||
- `deployed_stamp_is_sha`: `True`
|
||||
- `fingerprints_are_read_only`: `True`
|
||||
- `fingerprints_use_independent_read_only_role`: `True`
|
||||
- `first_fingerprint_complete`: `True`
|
||||
- `second_fingerprint_complete`: `True`
|
||||
- `service_active_before_and_after`: `True`
|
||||
- `service_identity_complete`: `True`
|
||||
- `service_process_unchanged_during_probe`: `True`
|
||||
- `ssh_readbacks_succeeded`: `True`
|
||||
- `workspace_head_is_sha`: `True`
|
||||
|
||||
## Live Readback
|
||||
|
||||
- Deploy head: `626bac493e2b772db984be7a4a68e9da656f6b02`
|
||||
- Deploy stamp: `626bac493e2b772db984be7a4a68e9da656f6b02`
|
||||
- Gateway MainPID: `347406`
|
||||
- Gateway NRestarts: `0`
|
||||
- Manifest: `ops/postgres_parity_manifest.sql`
|
||||
- Manifest SHA256: `8b8cdc25d54fdd8de05eb38c6e4423d2836953eb6012d4545f5c9c71b5f0150a`
|
||||
- Effective DB role: `pg_read_all_data`
|
||||
- Transaction read only: `on`
|
||||
- Canonical fingerprint: `32a1f2c18f4b4c623443cbd4d9520982e9f291ec74ca63855cef51c88ac56f24`
|
||||
- Canonical tables: `39`
|
||||
- Canonical rows: `52167`
|
||||
- Selected object ref: ``
|
||||
|
||||
## Claim Ceiling
|
||||
|
||||
Two canonical read-only snapshots and the gateway process were unchanged during this probe.
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
"""Pinned fixture prompt boundary."""
|
||||
|
||||
GENERATED_SOUL_IS_AUTHORITY = False
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
"""Pinned fixture process boundary; the canary uses the real profile verifier."""
|
||||
|
||||
SESSION_STATE_IS_IDENTITY = False
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
"""Pinned fixture tool configuration."""
|
||||
|
||||
ALLOWED_TOOLS = ("identity_readback",)
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
"""Pinned fixture entrypoint for the disposable identity runtime."""
|
||||
|
||||
RUNTIME_NAME = "leo-identity-readback-v1"
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
"""Pinned fixture registry for the no-send identity readback tool."""
|
||||
|
||||
REGISTERED_TOOLS = ("identity_readback",)
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
{
|
||||
"identity_name": "Leo",
|
||||
"rules": [
|
||||
{
|
||||
"id": "canonical-evidence",
|
||||
"text": "Treat canonical database rows and their bound evidence as durable knowledge; never promote session memory to evidence."
|
||||
},
|
||||
{
|
||||
"id": "review-before-apply",
|
||||
"text": "Proposals may be prepared, but review and guarded apply remain separate authorized actions."
|
||||
},
|
||||
{
|
||||
"id": "truthful-proof-tier",
|
||||
"text": "State exactly what was observed, separate inference from proof, and fail closed when required provenance drifts."
|
||||
}
|
||||
],
|
||||
"schema": "livingip.leoConstitutionSource.v1"
|
||||
}
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
{
|
||||
"environment": "disposable_fixture",
|
||||
"fingerprint_sha256": "1111111111111111111111111111111111111111111111111111111111111111",
|
||||
"read_consistency": {
|
||||
"after": {
|
||||
"database": "leo_identity_fixture",
|
||||
"database_user": "leo_identity_reader",
|
||||
"system_identifier": "7649789040005668902",
|
||||
"wal_lsn": "0/16B6C50"
|
||||
},
|
||||
"before": {
|
||||
"database": "leo_identity_fixture",
|
||||
"database_user": "leo_identity_reader",
|
||||
"system_identifier": "7649789040005668902",
|
||||
"wal_lsn": "0/16B6C50"
|
||||
},
|
||||
"status": "stable_wal_marker"
|
||||
},
|
||||
"schema": "livingip.teleoCanonicalDatabaseFingerprint.v1",
|
||||
"status": "ok",
|
||||
"structure_sha256": "3333333333333333333333333333333333333333333333333333333333333333",
|
||||
"table_count": 7,
|
||||
"table_rows_sha256": "2222222222222222222222222222222222222222222222222222222222222222",
|
||||
"total_rows": 7
|
||||
}
|
||||
|
|
@ -0,0 +1,58 @@
|
|||
{
|
||||
"database_fingerprint_sha256": "1111111111111111111111111111111111111111111111111111111111111111",
|
||||
"identity_name": "Leo",
|
||||
"source_provenance": {
|
||||
"canonical_authority_granted": false,
|
||||
"export_receipt_sha256": null,
|
||||
"mode": "synthetic_noncanonical_fixture",
|
||||
"same_transaction_as_fingerprint": false
|
||||
},
|
||||
"records": [
|
||||
{
|
||||
"evidence_sha256": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
|
||||
"kind": "persona",
|
||||
"rank": 0,
|
||||
"row_id": "11111111-1111-4111-8111-111111111111",
|
||||
"status": "active",
|
||||
"table": "public.personas",
|
||||
"text": "Leo is the evidence-bound reasoning interface for the Teleo collective."
|
||||
},
|
||||
{
|
||||
"evidence_sha256": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
|
||||
"kind": "strategy",
|
||||
"rank": 0,
|
||||
"row_id": "22222222-2222-4222-8222-222222222222",
|
||||
"status": "active",
|
||||
"table": "public.strategies",
|
||||
"text": "Prefer source-grounded synthesis that exposes uncertainty and review boundaries."
|
||||
},
|
||||
{
|
||||
"evidence_sha256": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc",
|
||||
"kind": "belief",
|
||||
"rank": 0,
|
||||
"row_id": "33333333-3333-4333-8333-333333333333",
|
||||
"status": "active",
|
||||
"table": "public.beliefs",
|
||||
"text": "A plausible answer without provenance is weaker than a bounded answer with an exact receipt."
|
||||
},
|
||||
{
|
||||
"evidence_sha256": "dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd",
|
||||
"kind": "shared_root",
|
||||
"rank": 0,
|
||||
"row_id": "44444444-4444-4444-8444-444444444444",
|
||||
"status": "active",
|
||||
"table": "public.shared_root",
|
||||
"text": "Collective intelligence must remain inspectable, reversible, and accountable to evidence."
|
||||
},
|
||||
{
|
||||
"evidence_sha256": "eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee",
|
||||
"kind": "strategy_node",
|
||||
"rank": 1,
|
||||
"row_id": "55555555-5555-4555-8555-555555555555",
|
||||
"status": "active",
|
||||
"table": "public.strategy_nodes",
|
||||
"text": "Compile identity from exact canonical inputs and reject drift before runtime startup."
|
||||
}
|
||||
],
|
||||
"schema": "livingip.leoDatabaseIdentitySource.v1"
|
||||
}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
#!/usr/bin/env python3
|
||||
"""Fixture marker for the no-send identity readback tool."""
|
||||
|
||||
ACCESS_MODE = "read_only"
|
||||
NETWORK_SEND_ENABLED = False
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
model:
|
||||
provider: fixture-local
|
||||
default: leo-identity-readback-v1
|
||||
smart_routing: false
|
||||
max_tokens: 512
|
||||
agent:
|
||||
reasoning_effort: deterministic
|
||||
memory:
|
||||
enabled: false
|
||||
search: disabled
|
||||
gateway:
|
||||
execution_mode: local_no_send
|
||||
telegram:
|
||||
posting_enabled: false
|
||||
bot_token: fixture-value-is-never-emitted-or-identity-hashed
|
||||
tools:
|
||||
allowed:
|
||||
- identity_readback
|
||||
write_enabled: false
|
||||
identity_runtime:
|
||||
network_send_enabled: false
|
||||
database_write_enabled: false
|
||||
allowed_tools:
|
||||
- identity_readback
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
"""Fixture marker for the pinned identity-boundary middleware."""
|
||||
|
||||
IDENTITY_VIEW_IS_AUTHORITY = False
|
||||
SESSION_MEMORY_IS_EVIDENCE = False
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
name: identity-boundary
|
||||
version: 1
|
||||
description: Reject startup when a compiled identity view drifts.
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
---
|
||||
name: identity-readback
|
||||
description: Explain the pinned Leo identity and its noncanonical session boundary.
|
||||
---
|
||||
|
||||
Read only the compiled identity view and its manifest receipt. Never treat a
|
||||
session transcript, generated SOUL file, or unverified runtime memory as a
|
||||
canonical source.
|
||||
|
|
@ -14,6 +14,7 @@ dependencies = [
|
|||
|
||||
[project.optional-dependencies]
|
||||
dev = [
|
||||
"hypothesis>=6,<7",
|
||||
"pytest>=8",
|
||||
"pytest-asyncio>=0.23",
|
||||
"ruff>=0.3",
|
||||
|
|
|
|||
|
|
@ -111,8 +111,17 @@ CLAIM_TYPES = {"empirical", "structural", "normative", "meta", "concept"}
|
|||
SOURCE_TYPES = {"paper", "article", "transcript", "observation", "dataset", "post", "dm", "other"}
|
||||
EVIDENCE_ROLES = {"grounds", "illustrates", "contradicts"}
|
||||
EDGE_TYPES = {
|
||||
"supports", "challenges", "requires", "relates", "contradicts",
|
||||
"supersedes", "derives_from", "cites", "causes", "constrains", "accelerates",
|
||||
"supports",
|
||||
"challenges",
|
||||
"requires",
|
||||
"relates",
|
||||
"contradicts",
|
||||
"supersedes",
|
||||
"derives_from",
|
||||
"cites",
|
||||
"causes",
|
||||
"constrains",
|
||||
"accelerates",
|
||||
}
|
||||
|
||||
MAX_BUNDLE_ROWS = {
|
||||
|
|
@ -143,6 +152,21 @@ def _jsonb(value: Any) -> str:
|
|||
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:
|
||||
if not values:
|
||||
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}")
|
||||
|
||||
|
||||
def _validate_approval_meta(
|
||||
approval: dict[str, Any], proposal_type: str, apply_payload: dict[str, Any]
|
||||
) -> None:
|
||||
def _validate_approval_meta(approval: dict[str, Any], proposal_type: str, apply_payload: dict[str, Any]) -> None:
|
||||
if not isinstance(approval, dict):
|
||||
raise ValueError("approved proposal metadata is required")
|
||||
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:
|
||||
return f"""select kb_stage.assert_approved_proposal(
|
||||
{sql_literal(proposal_id)}::uuid,
|
||||
{sql_literal(approval['proposal_type'])},
|
||||
{_jsonb(approval['payload'])},
|
||||
{sql_literal(approval['reviewed_by_handle'])},
|
||||
{sql_literal(approval.get('reviewed_by_agent_id'))}::uuid,
|
||||
{sql_literal(approval['reviewed_at'])}::timestamptz,
|
||||
{sql_literal(approval['review_note'])}
|
||||
{sql_literal(approval["proposal_type"])},
|
||||
{_jsonb(approval["payload"])},
|
||||
{sql_literal(approval["reviewed_by_handle"])},
|
||||
{sql_literal(approval.get("reviewed_by_agent_id"))}::uuid,
|
||||
{sql_literal(approval["reviewed_at"])}::timestamptz,
|
||||
{sql_literal(approval["review_note"])}
|
||||
);"""
|
||||
|
||||
|
||||
|
|
@ -245,12 +267,12 @@ end
|
|||
$verify$;"""
|
||||
finish_sql = f"""select kb_stage.finish_approved_proposal(
|
||||
{sql_literal(proposal_id)}::uuid,
|
||||
{sql_literal(approval['proposal_type'])},
|
||||
{_jsonb(approval['payload'])},
|
||||
{sql_literal(approval['reviewed_by_handle'])},
|
||||
{sql_literal(approval.get('reviewed_by_agent_id'))}::uuid,
|
||||
{sql_literal(approval['reviewed_at'])}::timestamptz,
|
||||
{sql_literal(approval['review_note'])},
|
||||
{sql_literal(approval["proposal_type"])},
|
||||
{_jsonb(approval["payload"])},
|
||||
{sql_literal(approval["reviewed_by_handle"])},
|
||||
{sql_literal(approval.get("reviewed_by_agent_id"))}::uuid,
|
||||
{sql_literal(approval["reviewed_at"])}::timestamptz,
|
||||
{sql_literal(approval["review_note"])},
|
||||
{sql_literal(applied_by)}
|
||||
);"""
|
||||
return checks_sql + "\n" + finish_sql
|
||||
|
|
@ -301,9 +323,9 @@ update public.strategies
|
|||
insert into public.strategies
|
||||
(agent_id, diagnosis, guiding_policy, proximate_objectives, version, active)
|
||||
select {sql_literal(agent_id)}::uuid,
|
||||
{sql_literal(strategy['diagnosis'])},
|
||||
{sql_literal(strategy['guiding_policy'])},
|
||||
{_jsonb(strategy['proximate_objectives'])},
|
||||
{sql_literal(strategy["diagnosis"])},
|
||||
{sql_literal(strategy["guiding_policy"])},
|
||||
{_jsonb(strategy["proximate_objectives"])},
|
||||
coalesce(max(version), 0) + 1,
|
||||
true
|
||||
from public.strategies
|
||||
|
|
@ -325,9 +347,7 @@ values
|
|||
raise exception 'apply_proposal: expected exactly one active strategy for agent %', {sql_literal(agent_id)};
|
||||
end if;"""
|
||||
|
||||
ledger = _ledger_and_verify(
|
||||
proposal_id, applied_by or SERVICE_AGENT_HANDLE, checks, approval
|
||||
)
|
||||
ledger = _ledger_and_verify(proposal_id, applied_by or SERVICE_AGENT_HANDLE, checks, 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],
|
||||
) -> str:
|
||||
_validate_approval_meta(approval, "add_edge", apply_payload)
|
||||
f = apply_payload.get("from_claim")
|
||||
t = apply_payload.get("to_claim")
|
||||
_reject_unknown(apply_payload, {"from_claim", "to_claim", "edge_type", "weight"}, "add_edge apply_payload")
|
||||
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")
|
||||
w = apply_payload.get("weight")
|
||||
if not (f and t and et):
|
||||
raise ValueError("add_edge apply_payload requires 'from_claim', 'to_claim', 'edge_type'")
|
||||
if et not in EDGE_TYPES:
|
||||
raise ValueError(f"add_edge.edge_type must be one of {sorted(EDGE_TYPES)}")
|
||||
w = _weight(apply_payload.get("weight"), "add_edge.weight")
|
||||
if f == t:
|
||||
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}"
|
||||
canonical = f"""
|
||||
|
|
@ -354,8 +376,8 @@ def build_add_edge_sql(
|
|||
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 into public.claim_edges (from_claim, to_claim, edge_type, weight)
|
||||
select {sql_literal(f)}::uuid, {sql_literal(t)}::uuid,
|
||||
insert into public.claim_edges (id, from_claim, to_claim, edge_type, weight)
|
||||
select {sql_literal(row_id)}::uuid, {sql_literal(f)}::uuid, {sql_literal(t)}::uuid,
|
||||
{sql_literal(et)}::edge_type, {sql_literal(w)}
|
||||
where not exists (
|
||||
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);
|
||||
""".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
|
||||
and to_claim = {sql_literal(t)}::uuid
|
||||
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';
|
||||
end if;"""
|
||||
|
||||
ledger = _ledger_and_verify(
|
||||
proposal_id, applied_by or SERVICE_AGENT_HANDLE, checks, approval
|
||||
)
|
||||
ledger = _ledger_and_verify(proposal_id, applied_by or SERVICE_AGENT_HANDLE, checks, 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],
|
||||
) -> str:
|
||||
_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 []
|
||||
if not evidence:
|
||||
raise ValueError("attach_evidence apply_payload requires non-empty 'evidence'")
|
||||
|
|
@ -399,17 +428,17 @@ def build_attach_evidence_sql(
|
|||
statements = []
|
||||
checks = []
|
||||
for i, ev in enumerate(evidence):
|
||||
claim_id = ev.get("claim_id")
|
||||
source_id = ev.get("source_id")
|
||||
role = ev.get("role") or "grounds"
|
||||
weight = ev.get("weight")
|
||||
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."
|
||||
_reject_unknown(
|
||||
ev,
|
||||
{"claim_id", "source_id", "role", "weight"},
|
||||
f"attach_evidence.evidence[{i}]",
|
||||
)
|
||||
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")
|
||||
statements.append(
|
||||
f"""insert into public.claim_evidence (claim_id, source_id, role, weight)
|
||||
select {sql_literal(claim_id)}::uuid, {sql_literal(source_id)}::uuid,
|
||||
|
|
@ -417,7 +446,14 @@ select {sql_literal(claim_id)}::uuid, {sql_literal(source_id)}::uuid,
|
|||
on conflict (claim_id, source_id, role) do nothing;"""
|
||||
)
|
||||
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
|
||||
and source_id = {sql_literal(source_id)}::uuid
|
||||
and role = {sql_literal(role)}::evidence_role
|
||||
|
|
@ -434,9 +470,7 @@ on conflict (claim_id, source_id, role) do nothing;"""
|
|||
)
|
||||
|
||||
canonical = "\n".join(statements)
|
||||
ledger = _ledger_and_verify(
|
||||
proposal_id, applied_by or SERVICE_AGENT_HANDLE, "\n".join(checks), approval
|
||||
)
|
||||
ledger = _ledger_and_verify(proposal_id, applied_by or SERVICE_AGENT_HANDLE, "\n".join(checks), approval)
|
||||
return _wrap_txn(canonical, ledger, _approval_guard_sql(proposal_id, approval))
|
||||
|
||||
|
||||
|
|
@ -445,6 +479,9 @@ def build_approve_claim_sql(
|
|||
proposal_id: str,
|
||||
applied_by: str | None,
|
||||
approval: dict[str, Any],
|
||||
*,
|
||||
fresh_owned: bool = False,
|
||||
fresh_preflight_sha256: str | None = None,
|
||||
) -> str:
|
||||
"""Build one conflict-safe transaction for a reviewed canonical graph bundle."""
|
||||
_validate_approval_meta(approval, "approve_claim", apply_payload)
|
||||
|
|
@ -509,12 +546,8 @@ def build_approve_claim_sql(
|
|||
"status": status,
|
||||
"confidence": _weight(row.get("confidence"), f"{path}.confidence"),
|
||||
"tags": tags,
|
||||
"created_by": _uuid(
|
||||
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
|
||||
),
|
||||
"created_by": _uuid(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),
|
||||
}
|
||||
)
|
||||
|
||||
|
|
@ -543,9 +576,7 @@ def build_approve_claim_sql(
|
|||
"storage_path": row.get("storage_path"),
|
||||
"excerpt": row.get("excerpt"),
|
||||
"hash": source_hash,
|
||||
"created_by": _uuid(
|
||||
row.get("created_by", agent_id), f"{path}.created_by", nullable=True
|
||||
),
|
||||
"created_by": _uuid(row.get("created_by", agent_id), f"{path}.created_by", nullable=True),
|
||||
}
|
||||
)
|
||||
|
||||
|
|
@ -566,9 +597,7 @@ def build_approve_claim_sql(
|
|||
"source_id": _uuid(row.get("source_id"), f"{path}.source_id"),
|
||||
"role": role,
|
||||
"weight": _weight(row.get("weight"), f"{path}.weight"),
|
||||
"created_by": _uuid(
|
||||
row.get("created_by", agent_id), f"{path}.created_by", nullable=True
|
||||
),
|
||||
"created_by": _uuid(row.get("created_by", agent_id), f"{path}.created_by", nullable=True),
|
||||
}
|
||||
)
|
||||
|
||||
|
|
@ -589,13 +618,12 @@ def build_approve_claim_sql(
|
|||
raise ValueError(f"{path} cannot be a self-edge")
|
||||
edges.append(
|
||||
{
|
||||
"id": deterministic_row_uuid(proposal_id, "claim_edge", from_claim, to_claim, edge_type),
|
||||
"from_claim": from_claim,
|
||||
"to_claim": to_claim,
|
||||
"edge_type": edge_type,
|
||||
"weight": _weight(row.get("weight"), f"{path}.weight"),
|
||||
"created_by": _uuid(
|
||||
row.get("created_by", agent_id), f"{path}.created_by", nullable=True
|
||||
),
|
||||
"created_by": _uuid(row.get("created_by", agent_id), f"{path}.created_by", nullable=True),
|
||||
}
|
||||
)
|
||||
|
||||
|
|
@ -639,169 +667,212 @@ def build_approve_claim_sql(
|
|||
)
|
||||
_dedupe([row["id"] for row in reasoning_tools], "approve_claim.reasoning_tools ids")
|
||||
|
||||
if fresh_owned:
|
||||
if (
|
||||
not isinstance(fresh_preflight_sha256, str)
|
||||
or len(fresh_preflight_sha256) != 64
|
||||
or any(character not in "0123456789abcdef" for character in fresh_preflight_sha256)
|
||||
):
|
||||
raise ValueError("fresh-owned approve_claim requires an exact preflight SHA-256")
|
||||
elif fresh_preflight_sha256 is not None:
|
||||
raise ValueError("fresh preflight SHA-256 is only valid for fresh-owned approve_claim")
|
||||
|
||||
statements: list[str] = []
|
||||
checks: list[str] = []
|
||||
|
||||
if fresh_owned:
|
||||
statements.extend(
|
||||
[
|
||||
f"-- fresh-owned preflight SHA-256: {fresh_preflight_sha256}",
|
||||
(
|
||||
"select pg_advisory_xact_lock(hashtextextended("
|
||||
f"'proposal-fresh-apply:' || {sql_literal(proposal_id)}, 0));"
|
||||
),
|
||||
]
|
||||
)
|
||||
|
||||
if sources:
|
||||
collision_checks = []
|
||||
for row in sources:
|
||||
collision_checks.append(
|
||||
f""" if exists (select 1 from public.sources
|
||||
where hash = {sql_literal(row['hash'])}
|
||||
and id <> {sql_literal(row['id'])}::uuid) then
|
||||
raise exception 'approve_claim: source hash collision for source %', {sql_literal(row['id'])};
|
||||
where hash = {sql_literal(row["hash"])}
|
||||
and id <> {sql_literal(row["id"])}::uuid) then
|
||||
raise exception 'approve_claim: source hash collision for source %', {sql_literal(row["id"])};
|
||||
end if;"""
|
||||
)
|
||||
statements.append(
|
||||
"do $source_conflicts$\nbegin\n"
|
||||
+ "\n".join(collision_checks)
|
||||
+ "\nend\n$source_conflicts$;"
|
||||
)
|
||||
statements.append("do $source_conflicts$\nbegin\n" + "\n".join(collision_checks) + "\nend\n$source_conflicts$;")
|
||||
|
||||
for row in claims:
|
||||
tags = _text_array(row["tags"])
|
||||
conflict_clause = ";" if fresh_owned else "\non conflict (id) do nothing;"
|
||||
statements.append(
|
||||
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'])},
|
||||
{sql_literal(row['status'])}, {sql_literal(row['confidence'])}, {tags},
|
||||
{sql_literal(row['created_by'])}::uuid, {sql_literal(row['superseded_by'])}::uuid
|
||||
on conflict (id) do nothing;"""
|
||||
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["created_by"])}::uuid, {sql_literal(row["superseded_by"])}::uuid{conflict_clause}"""
|
||||
)
|
||||
checks.append(
|
||||
f""" if not exists (select 1 from public.claims
|
||||
where id = {sql_literal(row['id'])}::uuid
|
||||
and type = {sql_literal(row['type'])}
|
||||
and text = {sql_literal(row['text'])}
|
||||
and status = {sql_literal(row['status'])}
|
||||
and confidence is not distinct from {sql_literal(row['confidence'])}
|
||||
where id = {sql_literal(row["id"])}::uuid
|
||||
and type = {sql_literal(row["type"])}
|
||||
and text = {sql_literal(row["text"])}
|
||||
and status = {sql_literal(row["status"])}
|
||||
and confidence is not distinct from {sql_literal(row["confidence"])}
|
||||
and tags is not distinct from {tags}
|
||||
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
|
||||
raise exception 'approve_claim: claim row does not match strict apply payload: %', {sql_literal(row['id'])};
|
||||
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
|
||||
raise exception 'approve_claim: claim row does not match strict apply payload: %', {sql_literal(row["id"])};
|
||||
end if;"""
|
||||
)
|
||||
|
||||
for row in sources:
|
||||
conflict_clause = ";" if fresh_owned else "\non conflict do nothing;"
|
||||
statements.append(
|
||||
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'])},
|
||||
{sql_literal(row['storage_path'])}, {sql_literal(row['excerpt'])}, {sql_literal(row['hash'])},
|
||||
{sql_literal(row['created_by'])}::uuid
|
||||
on conflict do nothing;"""
|
||||
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["created_by"])}::uuid{conflict_clause}"""
|
||||
)
|
||||
checks.append(
|
||||
f""" if exists (select 1 from public.sources
|
||||
where hash = {sql_literal(row['hash'])}
|
||||
and id <> {sql_literal(row['id'])}::uuid) then
|
||||
raise exception 'approve_claim: source hash collision for source %', {sql_literal(row['id'])};
|
||||
where hash = {sql_literal(row["hash"])}
|
||||
and id <> {sql_literal(row["id"])}::uuid) then
|
||||
raise exception 'approve_claim: source hash collision for source %', {sql_literal(row["id"])};
|
||||
end if;
|
||||
if not exists (select 1 from public.sources
|
||||
where id = {sql_literal(row['id'])}::uuid
|
||||
and source_type = {sql_literal(row['source_type'])}
|
||||
and url is not distinct from {sql_literal(row['url'])}
|
||||
and storage_path is not distinct from {sql_literal(row['storage_path'])}
|
||||
and excerpt is not distinct from {sql_literal(row['excerpt'])}
|
||||
and hash = {sql_literal(row['hash'])}
|
||||
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'])};
|
||||
where id = {sql_literal(row["id"])}::uuid
|
||||
and source_type = {sql_literal(row["source_type"])}
|
||||
and url is not distinct from {sql_literal(row["url"])}
|
||||
and storage_path is not distinct from {sql_literal(row["storage_path"])}
|
||||
and excerpt is not distinct from {sql_literal(row["excerpt"])}
|
||||
and hash = {sql_literal(row["hash"])}
|
||||
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"])};
|
||||
end if;"""
|
||||
)
|
||||
|
||||
for row in reasoning_tools:
|
||||
conflict_clause = ";" if fresh_owned else "\non conflict (id) do nothing;"
|
||||
statements.append(
|
||||
f"""insert into public.reasoning_tools (id, agent_id, name, description, category)
|
||||
select {sql_literal(row['id'])}::uuid, {sql_literal(row['agent_id'])}::uuid,
|
||||
{sql_literal(row['name'])}, {sql_literal(row['description'])}, {sql_literal(row['category'])}
|
||||
on conflict (id) do nothing;"""
|
||||
select {sql_literal(row["id"])}::uuid, {sql_literal(row["agent_id"])}::uuid,
|
||||
{sql_literal(row["name"])}, {sql_literal(row["description"])}, {sql_literal(row["category"])}{conflict_clause}"""
|
||||
)
|
||||
checks.append(
|
||||
f""" if not exists (select 1 from public.reasoning_tools
|
||||
where id = {sql_literal(row['id'])}::uuid
|
||||
and agent_id is not distinct from {sql_literal(row['agent_id'])}::uuid
|
||||
and name = {sql_literal(row['name'])}
|
||||
and description = {sql_literal(row['description'])}
|
||||
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'])};
|
||||
where id = {sql_literal(row["id"])}::uuid
|
||||
and agent_id is not distinct from {sql_literal(row["agent_id"])}::uuid
|
||||
and name = {sql_literal(row["name"])}
|
||||
and description = {sql_literal(row["description"])}
|
||||
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"])};
|
||||
end if;"""
|
||||
)
|
||||
|
||||
for row in evidence:
|
||||
conflict_clause = ";" if fresh_owned else "\non conflict (claim_id, source_id, role) do nothing;"
|
||||
statements.append(
|
||||
f"""insert into public.claim_evidence (claim_id, source_id, role, weight, created_by)
|
||||
select {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['created_by'])}::uuid
|
||||
on conflict (claim_id, source_id, role) do nothing;"""
|
||||
select {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["created_by"])}::uuid{conflict_clause}"""
|
||||
)
|
||||
checks.append(
|
||||
f""" 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
|
||||
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(row["claim_id"])}::uuid
|
||||
and source_id = {sql_literal(row["source_id"])}::uuid
|
||||
and role = {sql_literal(row["role"])}::evidence_role) <> 1 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';
|
||||
end if;
|
||||
if not 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 not distinct from {sql_literal(row['weight'])}
|
||||
and created_by is not distinct from {sql_literal(row['created_by'])}::uuid) then
|
||||
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 not distinct from {sql_literal(row["weight"])}
|
||||
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';
|
||||
end if;"""
|
||||
)
|
||||
|
||||
for row in edges:
|
||||
edge_lock_key = (
|
||||
f"claim_edge:{row['from_claim']}:{row['to_claim']}:{row['edge_type']}"
|
||||
edge_lock_key = f"claim_edge:{row['from_claim']}:{row['to_claim']}:{row['edge_type']}"
|
||||
edge_insert_guard = (
|
||||
";"
|
||||
if fresh_owned
|
||||
else f"""\n where not 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);"""
|
||||
)
|
||||
statements.append(
|
||||
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)
|
||||
select {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['created_by'])}::uuid
|
||||
where not 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);"""
|
||||
insert into public.claim_edges (id, from_claim, to_claim, edge_type, weight, created_by)
|
||||
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["created_by"])}::uuid{edge_insert_guard}"""
|
||||
)
|
||||
checks.append(
|
||||
f""" 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
|
||||
f""" -- Accept a legacy receipt id only when exactly one semantic row matches.
|
||||
if (select count(*) 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) <> 1 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';
|
||||
end if;
|
||||
if not 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 not distinct from {sql_literal(row['weight'])}
|
||||
and created_by is not distinct from {sql_literal(row['created_by'])}::uuid) then
|
||||
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 not distinct from {sql_literal(row["weight"])}
|
||||
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';
|
||||
end if;"""
|
||||
)
|
||||
|
||||
canonical = "\n\n".join(statements)
|
||||
ledger = _ledger_and_verify(
|
||||
proposal_id, applied_by or SERVICE_AGENT_HANDLE, "\n".join(checks), approval
|
||||
ledger = _ledger_and_verify(proposal_id, applied_by or SERVICE_AGENT_HANDLE, "\n".join(checks), approval)
|
||||
return _wrap_txn(
|
||||
canonical,
|
||||
ledger,
|
||||
_approval_guard_sql(proposal_id, approval),
|
||||
serializable=fresh_owned,
|
||||
)
|
||||
return _wrap_txn(canonical, ledger, _approval_guard_sql(proposal_id, approval))
|
||||
|
||||
|
||||
def _wrap_txn(canonical_sql: str, ledger_sql: str, approval_guard_sql: str) -> str:
|
||||
def _wrap_txn(
|
||||
canonical_sql: str,
|
||||
ledger_sql: str,
|
||||
approval_guard_sql: str,
|
||||
*,
|
||||
serializable: bool = False,
|
||||
) -> str:
|
||||
return (
|
||||
"begin;\n"
|
||||
"set local standard_conforming_strings = on;\n"
|
||||
f"{approval_guard_sql}\n"
|
||||
f"{canonical_sql}\n"
|
||||
f"{ledger_sql}\n"
|
||||
"commit;\n"
|
||||
+ ("set transaction isolation level serializable;\n" if serializable else "")
|
||||
+ "set local standard_conforming_strings = on;\n"
|
||||
+ f"{approval_guard_sql}\n"
|
||||
+ f"{canonical_sql}\n"
|
||||
+ f"{ledger_sql}\n"
|
||||
+ "commit;\n"
|
||||
)
|
||||
|
||||
|
||||
|
|
@ -813,7 +884,13 @@ BUILDERS = {
|
|||
}
|
||||
|
||||
|
||||
def build_apply_sql(proposal: dict[str, Any], applied_by: str | None) -> str:
|
||||
def build_apply_sql(
|
||||
proposal: dict[str, Any],
|
||||
applied_by: str | None,
|
||||
*,
|
||||
fresh_owned: bool = False,
|
||||
fresh_preflight_sha256: str | None = None,
|
||||
) -> str:
|
||||
ptype = proposal["proposal_type"]
|
||||
if ptype not in BUILDERS:
|
||||
raise ValueError(f"apply_proposal cannot apply proposal_type {ptype!r}")
|
||||
|
|
@ -824,6 +901,17 @@ def build_apply_sql(proposal: dict[str, Any], applied_by: str | None) -> str:
|
|||
"proposal payload has no 'apply_payload' strict contract. "
|
||||
"Run the normalizer to produce apply_payload before applying."
|
||||
)
|
||||
if fresh_owned and ptype != "approve_claim":
|
||||
raise ValueError("fresh-owned apply is supported only for approve_claim")
|
||||
if ptype == "approve_claim":
|
||||
return build_approve_claim_sql(
|
||||
apply_payload,
|
||||
proposal["id"],
|
||||
applied_by or SERVICE_AGENT_HANDLE,
|
||||
proposal,
|
||||
fresh_owned=fresh_owned,
|
||||
fresh_preflight_sha256=fresh_preflight_sha256,
|
||||
)
|
||||
return BUILDERS[ptype](
|
||||
apply_payload,
|
||||
proposal["id"],
|
||||
|
|
@ -837,9 +925,7 @@ def assert_applyable(proposal: dict[str, Any]) -> None:
|
|||
if status == "applied":
|
||||
raise SystemExit(f"proposal {proposal['id']} is already applied (idempotent no-op)")
|
||||
if status != "approved":
|
||||
raise SystemExit(
|
||||
f"proposal {proposal['id']} has status {status!r}; only 'approved' proposals apply"
|
||||
)
|
||||
raise SystemExit(f"proposal {proposal['id']} has status {status!r}; only 'approved' proposals apply")
|
||||
|
||||
|
||||
def assert_receiptable(proposal: dict[str, Any]) -> None:
|
||||
|
|
@ -877,23 +963,36 @@ def run_psql(
|
|||
) -> str:
|
||||
docker_binary = shutil.which("docker") or "docker"
|
||||
command = [
|
||||
docker_binary, "exec", "-e", "PGPASSWORD", "-i", args.container,
|
||||
"psql", "-U", args.role, "-h", args.host, "-d", args.db,
|
||||
"-v", "ON_ERROR_STOP=1", "-At", "-q",
|
||||
docker_binary,
|
||||
"exec",
|
||||
"-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(
|
||||
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"},
|
||||
check=False,
|
||||
)
|
||||
if result.returncode != 0:
|
||||
if redact_output_on_error:
|
||||
raise SystemExit(
|
||||
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}); private postflight output redacted")
|
||||
raise SystemExit(f"psql failed ({result.returncode})\nSTDOUT:\n{result.stdout}\nSTDERR:\n{result.stderr}")
|
||||
return result.stdout
|
||||
|
||||
|
||||
|
|
@ -940,7 +1039,7 @@ def capture_replay_receipt(
|
|||
raise RuntimeError("postflight query did not return a JSON object")
|
||||
apply_sql_source = "exact_executed_sql"
|
||||
if apply_sql is None:
|
||||
apply_sql = build_apply_sql(proposal, proposal.get("applied_by_handle"))
|
||||
apply_sql = build_apply_sql_for_args(proposal, args, proposal.get("applied_by_handle"))
|
||||
apply_sql_source = "reconstructed_current_engine"
|
||||
receipt = replay_receipt.build_replay_receipt(
|
||||
proposal,
|
||||
|
|
@ -972,6 +1071,14 @@ def parse_args(argv: list[str]) -> argparse.Namespace:
|
|||
p.add_argument("--db", default=DEFAULT_DB)
|
||||
p.add_argument("--host", default=DEFAULT_HOST)
|
||||
p.add_argument("--role", default=DEFAULT_ROLE)
|
||||
p.add_argument(
|
||||
"--fresh-preflight",
|
||||
type=Path,
|
||||
help=(
|
||||
"exact proposal_apply_fresh_preflight JSON; makes approve_claim use strict fresh-owned inserts "
|
||||
"bound to the timestamped preflight"
|
||||
),
|
||||
)
|
||||
p.add_argument(
|
||||
"--receipt-only",
|
||||
action="store_true",
|
||||
|
|
@ -980,8 +1087,7 @@ def parse_args(argv: list[str]) -> argparse.Namespace:
|
|||
p.add_argument(
|
||||
"--receipt-dir",
|
||||
default=None,
|
||||
help="private receipt directory (default: KB_APPLY_RECEIPT_DIR or "
|
||||
f"{replay_receipt.DEFAULT_RECEIPT_DIR})",
|
||||
help=f"private receipt directory (default: KB_APPLY_RECEIPT_DIR or {replay_receipt.DEFAULT_RECEIPT_DIR})",
|
||||
)
|
||||
p.add_argument(
|
||||
"--receipt-out",
|
||||
|
|
@ -994,6 +1100,28 @@ def parse_args(argv: list[str]) -> argparse.Namespace:
|
|||
return args
|
||||
|
||||
|
||||
def build_apply_sql_for_args(
|
||||
proposal: dict[str, Any],
|
||||
args: argparse.Namespace,
|
||||
applied_by: str | None,
|
||||
) -> str:
|
||||
fresh_preflight_path = getattr(args, "fresh_preflight", None)
|
||||
if fresh_preflight_path is None:
|
||||
return build_apply_sql(proposal, applied_by)
|
||||
if not fresh_preflight_path.is_file():
|
||||
raise SystemExit(f"fresh preflight file not found: {fresh_preflight_path}")
|
||||
try:
|
||||
preflight = json.loads(fresh_preflight_path.read_text(encoding="utf-8"))
|
||||
except (OSError, json.JSONDecodeError) as exc:
|
||||
raise SystemExit(f"fresh preflight is unreadable: {fresh_preflight_path}") from exc
|
||||
import proposal_apply_lifecycle as lifecycle
|
||||
|
||||
try:
|
||||
return lifecycle.build_fresh_owned_apply_sql(proposal, preflight, applied_by)
|
||||
except ValueError as exc:
|
||||
raise SystemExit(f"fresh preflight refused: {exc}") from exc
|
||||
|
||||
|
||||
def main(argv: list[str] | None = None) -> int:
|
||||
args = parse_args(sys.argv[1:] if argv is None else argv)
|
||||
|
||||
|
|
@ -1020,13 +1148,13 @@ def main(argv: list[str] | None = None) -> int:
|
|||
password = load_password(args.secrets_file)
|
||||
proposal = load_proposal(args, password)
|
||||
assert_applyable(proposal)
|
||||
print(build_apply_sql(proposal, args.applied_by))
|
||||
print(build_apply_sql_for_args(proposal, args, args.applied_by))
|
||||
return 0
|
||||
|
||||
password = load_password(args.secrets_file)
|
||||
proposal = load_proposal(args, password)
|
||||
assert_applyable(proposal)
|
||||
sql = build_apply_sql(proposal, args.applied_by)
|
||||
sql = build_apply_sql_for_args(proposal, args, args.applied_by)
|
||||
run_psql(args, sql, password)
|
||||
applied_proposal = load_proposal(args, password)
|
||||
try:
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@ from __future__ import annotations
|
|||
import argparse
|
||||
import json
|
||||
import os
|
||||
import stat
|
||||
import subprocess
|
||||
import sys
|
||||
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.
|
||||
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) #
|
||||
|
|
@ -160,14 +168,69 @@ def partition_candidates(
|
|||
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 #
|
||||
# --------------------------------------------------------------------------- #
|
||||
def _psql_args(args: argparse.Namespace) -> argparse.Namespace:
|
||||
"""Namespace shaped for ap.run_psql (reuses the kb_apply connection path)."""
|
||||
return argparse.Namespace(
|
||||
container=args.container, db=args.db, host=args.host, role=args.role
|
||||
)
|
||||
return argparse.Namespace(container=args.container, db=args.db, host=args.host, role=args.role)
|
||||
|
||||
|
||||
def fetch_candidates(
|
||||
|
|
@ -181,19 +244,72 @@ def fetch_candidates(
|
|||
|
||||
|
||||
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 = [
|
||||
sys.executable, str(args.apply_script), proposal_id,
|
||||
"--applied-by", args.applied_by,
|
||||
"--secrets-file", args.secrets_file,
|
||||
"--container", args.container, "--db", args.db,
|
||||
"--host", args.host, "--role", args.role,
|
||||
sys.executable,
|
||||
str(args.apply_script),
|
||||
proposal_id,
|
||||
"--applied-by",
|
||||
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)
|
||||
if result.returncode != 0:
|
||||
raise RuntimeError(
|
||||
f"apply failed for {proposal_id}: {result.stdout.strip()} {result.stderr.strip()}"
|
||||
committed = result.returncode == 0 or has_exact_postcommit_receipt_failure(
|
||||
result.stderr,
|
||||
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:
|
||||
|
|
@ -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)"
|
||||
result = subprocess.run(cmd, text=True, capture_output=True, check=False)
|
||||
if result.returncode != 0:
|
||||
raise RuntimeError(
|
||||
f"render failed for agent {agent_id}: {result.stdout.strip()} {result.stderr.strip()}"
|
||||
)
|
||||
raise RuntimeError(f"render failed for agent {agent_id}: {result.stdout.strip()} {result.stderr.strip()}")
|
||||
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:
|
||||
password = ap.load_password(args.secrets_file)
|
||||
failure_counts = load_failure_state(args.failure_state_file)
|
||||
exhausted_ids = tuple(
|
||||
proposal_id
|
||||
for proposal_id, count in failure_counts.items()
|
||||
if count >= args.max_attempts
|
||||
)
|
||||
exhausted_ids = tuple(proposal_id for proposal_id, count in failure_counts.items() if count >= args.max_attempts)
|
||||
candidates = fetch_candidates(args, password, exhausted_ids)
|
||||
|
||||
for proposal_id in exhausted_ids:
|
||||
|
|
@ -263,6 +373,15 @@ def run(args: argparse.Namespace) -> int:
|
|||
print(f"applied {pid} ({ptype})")
|
||||
if ptype in RENDER_TYPES:
|
||||
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:
|
||||
failures += 1
|
||||
# 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
|
||||
# retrying forever. Surface loudly for the operator.
|
||||
failure_counts[pid] = failure_counts.get(pid, 0) + 1
|
||||
print(f"ERROR applying {pid} ({ptype}) [attempt {failure_counts[pid]}/"
|
||||
f"{args.max_attempts}]: {exc}", file=sys.stderr)
|
||||
print(
|
||||
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)
|
||||
return 1 if failures else 0
|
||||
|
||||
|
||||
def parse_args(argv: list[str]) -> argparse.Namespace:
|
||||
p = argparse.ArgumentParser(
|
||||
description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter
|
||||
)
|
||||
p = argparse.ArgumentParser(description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter)
|
||||
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.",
|
||||
)
|
||||
p.add_argument("--limit", type=int, default=20, help="max candidates fetched per tick")
|
||||
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 "
|
||||
"one-at-a-time and observably, not a whole-queue drain)",
|
||||
)
|
||||
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 "
|
||||
"poison pill and skipped (needs a human fix, not endless retries)",
|
||||
)
|
||||
p.add_argument(
|
||||
"--failure-state-file",
|
||||
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 "
|
||||
"the poison-pill ceiling actually bites)",
|
||||
help="persisted per-proposal failure counts (survives oneshot ticks so the poison-pill ceiling actually bites)",
|
||||
)
|
||||
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)",
|
||||
)
|
||||
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)",
|
||||
)
|
||||
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}'. "
|
||||
"Empty (default) skips render until the SOUL renderer is deployed.",
|
||||
)
|
||||
|
|
|
|||
406
scripts/build_telegram_visible_unseen_chain_packet.py
Normal file
406
scripts/build_telegram_visible_unseen_chain_packet.py
Normal file
|
|
@ -0,0 +1,406 @@
|
|||
#!/usr/bin/env python3
|
||||
"""Build the exact no-send packet for Leo's unseen Telegram reasoning chain."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import hashlib
|
||||
import json
|
||||
import subprocess
|
||||
from datetime import datetime, timezone
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
|
||||
try:
|
||||
import verify_leo_unseen_reasoning_chain as unseen
|
||||
except ImportError: # pragma: no cover - imported as scripts.* in tests
|
||||
from scripts import verify_leo_unseen_reasoning_chain as unseen
|
||||
|
||||
SCHEMA = "livingip.telegramVisibleUnseenChainPacket.v2"
|
||||
REPO_ROOT = Path(__file__).resolve().parents[1]
|
||||
REPORT_DIR = Path("docs/reports/leo-working-state-20260709")
|
||||
DEFAULT_HANDLER_RECEIPT = REPORT_DIR / "leo-unseen-reasoning-chain-canary-current.json"
|
||||
DEFAULT_OUT = REPORT_DIR / "telegram-visible-unseen-chain-authorization-packet-current.json"
|
||||
DEFAULT_MARKDOWN_OUT = REPORT_DIR / "telegram-visible-unseen-chain-authorization-packet-current.md"
|
||||
DEFAULT_CAPTURE_RECEIPT = REPORT_DIR / "telegram-visible-unseen-chain-capture-receipt-current.json"
|
||||
DEFAULT_PREFLIGHT = REPORT_DIR / "telegram-visible-unseen-chain-preflight-current.json"
|
||||
DEFAULT_POSTFLIGHT = REPORT_DIR / "telegram-visible-unseen-chain-postflight-current.json"
|
||||
DEFAULT_CHAT_ID = "-5146042086"
|
||||
DEFAULT_CHAT_LABEL = "Leo"
|
||||
DEFAULT_PROOF_DIR = "outputs/telegram-visible-unseen-chain-20260715"
|
||||
DEFAULT_MANIFEST_SQL = Path("ops/postgres_parity_manifest.sql")
|
||||
READ_ONLY_DB_ROLE = "pg_read_all_data"
|
||||
DEFAULT_CODEX_THREAD_ID = "019f6350-3350-7040-b223-c5c22673fece"
|
||||
TOOLING_PATHS = {
|
||||
"packet_builder": Path("scripts/build_telegram_visible_unseen_chain_packet.py"),
|
||||
"state_collector": Path("scripts/collect_telegram_visible_unseen_chain_state.py"),
|
||||
"capture_verifier": Path("scripts/verify_telegram_visible_unseen_chain.py"),
|
||||
}
|
||||
|
||||
|
||||
def _load_json(path: Path) -> dict[str, Any]:
|
||||
return json.loads(path.read_text(encoding="utf-8"))
|
||||
|
||||
|
||||
def _sha256_bytes(value: bytes) -> str:
|
||||
return hashlib.sha256(value).hexdigest()
|
||||
|
||||
|
||||
def _sha256_file(path: Path) -> str:
|
||||
return _sha256_bytes(path.read_bytes())
|
||||
|
||||
|
||||
def _canonical_sha256(value: Any) -> str:
|
||||
encoded = json.dumps(value, sort_keys=True, separators=(",", ":")).encode("utf-8")
|
||||
return _sha256_bytes(encoded)
|
||||
|
||||
|
||||
def current_git_sha(repo_root: Path = Path(".")) -> str:
|
||||
proc = subprocess.run(
|
||||
["git", "rev-parse", "HEAD"],
|
||||
cwd=repo_root,
|
||||
text=True,
|
||||
capture_output=True,
|
||||
check=False,
|
||||
)
|
||||
return proc.stdout.strip() if proc.returncode == 0 else ""
|
||||
|
||||
|
||||
def exact_messages() -> list[dict[str, Any]]:
|
||||
messages = []
|
||||
for sequence, prompt in enumerate(unseen.PROMPTS, start=1):
|
||||
message = str(prompt["message"])
|
||||
messages.append(
|
||||
{
|
||||
"sequence": sequence,
|
||||
"prompt_id": prompt["id"],
|
||||
"dimension": prompt["dimension"],
|
||||
"message": message,
|
||||
"message_sha256": _sha256_bytes(message.encode("utf-8")),
|
||||
"wait_for_visible_reply_before_next": True,
|
||||
}
|
||||
)
|
||||
return messages
|
||||
|
||||
|
||||
def tooling_binding(repo_root: Path = REPO_ROOT) -> dict[str, dict[str, Any]]:
|
||||
return {name: {"path": str(path), "sha256": _sha256_file(repo_root / path)} for name, path in TOOLING_PATHS.items()}
|
||||
|
||||
|
||||
def manifest_binding(repo_root: Path = REPO_ROOT) -> dict[str, Any]:
|
||||
return {
|
||||
"path": str(DEFAULT_MANIFEST_SQL),
|
||||
"sha256": _sha256_file(repo_root / DEFAULT_MANIFEST_SQL),
|
||||
"execution_contract": {
|
||||
"database": "teleo",
|
||||
"authenticated_role": "postgres",
|
||||
"effective_role": READ_ONLY_DB_ROLE,
|
||||
"default_transaction_read_only": "on",
|
||||
"transaction_read_only": "on",
|
||||
"psql_rc_disabled": True,
|
||||
"arbitrary_manifest_override_allowed": False,
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
def _handler_checks(receipt: dict[str, Any]) -> dict[str, bool]:
|
||||
safety = receipt.get("safety_gate") if isinstance(receipt.get("safety_gate"), dict) else {}
|
||||
safety_checks = safety.get("checks") if isinstance(safety.get("checks"), dict) else {}
|
||||
database = receipt.get("database") if isinstance(receipt.get("database"), dict) else {}
|
||||
prompt_ids = [str(item["id"]) for item in unseen.PROMPTS]
|
||||
return {
|
||||
"handler_receipt_passed": receipt.get("status") == "pass",
|
||||
"handler_receipt_schema_supported": receipt.get("schema") == unseen.SCHEMA,
|
||||
"handler_prompt_ids_exact": receipt.get("prompt_ids") == prompt_ids,
|
||||
"handler_outcomes_all_pass": bool(receipt.get("outcomes"))
|
||||
and all(value is True for value in receipt.get("outcomes", {}).values()),
|
||||
"handler_checks_all_pass": bool(receipt.get("checks"))
|
||||
and all(value is True for value in receipt.get("checks", {}).values()),
|
||||
"handler_safety_gate_passed": safety.get("status") == "pass",
|
||||
"handler_proved_no_telegram_post": safety_checks.get("no_telegram_post") is True,
|
||||
"handler_proved_read_only_tool_traces": safety_checks.get("all_tool_traces_read_only_and_bound") is True,
|
||||
"handler_proved_unchanged_fingerprint": database.get("fingerprint_unchanged") is True
|
||||
and isinstance(database.get("fingerprint_sha256"), str)
|
||||
and len(database["fingerprint_sha256"]) == 64,
|
||||
"handler_tier_remains_below_telegram_visible": "Telegram-visible message delivery"
|
||||
in (receipt.get("claim_ceiling") or {}).get("not_proven", []),
|
||||
}
|
||||
|
||||
|
||||
def _authorization_text(*, chat_label: str, chat_id: str, messages: list[dict[str, Any]]) -> str:
|
||||
quoted = " ".join(f"[{item['prompt_id']}] {json.dumps(item['message'], ensure_ascii=True)}" for item in messages)
|
||||
return (
|
||||
"I authorize Codex to use the already-authenticated Chrome Telegram UI to send exactly these three "
|
||||
f"messages, in order and with no additional messages, to the Telegram group {chat_label} (chat ID "
|
||||
f"{chat_id}), waiting for Leo's visible reply after each turn: {quoted} Capture the visible replies, "
|
||||
"message IDs, timestamps, screenshot and accessibility evidence, plus an independently retained Chrome "
|
||||
"control provenance receipt bound to the Codex rollout's user-authorization and Chrome tool events; "
|
||||
"perform only read-only DB/service "
|
||||
"readbacks; do not use the Bot API; do not stage, approve, apply, or otherwise mutate knowledge."
|
||||
)
|
||||
|
||||
|
||||
def build_packet(
|
||||
*,
|
||||
handler_receipt_path: Path = DEFAULT_HANDLER_RECEIPT,
|
||||
chat_id: str = DEFAULT_CHAT_ID,
|
||||
chat_label: str = DEFAULT_CHAT_LABEL,
|
||||
proof_dir: str = DEFAULT_PROOF_DIR,
|
||||
codex_thread_id: str = DEFAULT_CODEX_THREAD_ID,
|
||||
git_sha: str | None = None,
|
||||
) -> dict[str, Any]:
|
||||
handler_receipt = _load_json(handler_receipt_path)
|
||||
messages = exact_messages()
|
||||
handler_checks = _handler_checks(handler_receipt)
|
||||
target = {
|
||||
"platform": "telegram",
|
||||
"chat_label": chat_label,
|
||||
"chat_id": chat_id,
|
||||
"allowed_transport": "authenticated_chrome_telegram_ui",
|
||||
"forbidden_transports": ["telegram_bot_api", "copied_transcript", "handler_substitution"],
|
||||
"message_count": len(messages),
|
||||
"expected_prompt_ids": [item["prompt_id"] for item in messages],
|
||||
}
|
||||
handler_binding = {
|
||||
"path": str(handler_receipt_path),
|
||||
"sha256": _sha256_file(handler_receipt_path),
|
||||
"schema": handler_receipt.get("schema"),
|
||||
"proof_tier": handler_receipt.get("proof_tier"),
|
||||
"remote_run_id": handler_receipt.get("remote_run_id"),
|
||||
"deployed_git_head": handler_receipt.get("deployed_git_head"),
|
||||
"fingerprint_sha256": (handler_receipt.get("database") or {}).get("fingerprint_sha256"),
|
||||
}
|
||||
tooling = tooling_binding()
|
||||
manifest = manifest_binding()
|
||||
browser_provenance_contract = {
|
||||
"schema": "livingip.authenticatedChromeTelegramCaptureProvenance.v1",
|
||||
"capture_channel": "codex_chrome_extension",
|
||||
"requires_preflight_challenge_nonce": True,
|
||||
"requires_codex_rollout_log_outside_evidence_root": True,
|
||||
"requires_chrome_backend_tool_receipts": True,
|
||||
"requires_provenance_sha256_in_final_chrome_tool_receipt": True,
|
||||
"requires_codex_user_message_authorization_receipt": True,
|
||||
"requires_browser_session_tab_and_capture_identifiers": True,
|
||||
"requires_telegram_web_origin_and_chat_identity": True,
|
||||
"requires_hashes_for_every_screenshot_and_accessibility_artifact": True,
|
||||
}
|
||||
protocol = {
|
||||
"target": target,
|
||||
"exact_messages": messages,
|
||||
"handler_binding": handler_binding,
|
||||
"tooling_binding": tooling,
|
||||
"manifest_binding": manifest,
|
||||
"browser_provenance_contract": browser_provenance_contract,
|
||||
"operator_context": {
|
||||
"codex_thread_id": codex_thread_id,
|
||||
"authorization_source": "codex_platform_user_message",
|
||||
},
|
||||
"state_contract": {
|
||||
"preflight": "two identical repeatable-read read-only canonical fingerprints",
|
||||
"postflight": "same canonical fingerprint plus independent selected-object readback",
|
||||
"service": "same active gateway process before and after",
|
||||
"ordering": "preflight < authorization < send1 < reply1 < send2 < reply2 < send3 < reply3 < final/postflight",
|
||||
},
|
||||
}
|
||||
protocol_sha256 = _canonical_sha256(protocol)
|
||||
checks = {
|
||||
**handler_checks,
|
||||
"exact_three_turn_sequence": len(messages) == 3 and [item["sequence"] for item in messages] == [1, 2, 3],
|
||||
"exact_prompts_imported_from_handler_verifier": [item["message"] for item in messages]
|
||||
== [item["message"] for item in unseen.PROMPTS],
|
||||
"first_prompt_supplies_no_row_id": unseen.UUID_RE.search(messages[0]["message"]) is None,
|
||||
"authenticated_chrome_is_only_send_transport": target["allowed_transport"]
|
||||
== "authenticated_chrome_telegram_ui",
|
||||
"canonical_manifest_path_and_sha_bound": manifest == manifest_binding(),
|
||||
"database_session_and_role_fail_closed_read_only": manifest["execution_contract"]["effective_role"]
|
||||
== READ_ONLY_DB_ROLE
|
||||
and manifest["execution_contract"]["default_transaction_read_only"] == "on"
|
||||
and manifest["execution_contract"]["transaction_read_only"] == "on"
|
||||
and manifest["execution_contract"]["arbitrary_manifest_override_allowed"] is False,
|
||||
"independent_browser_provenance_required": browser_provenance_contract[
|
||||
"requires_codex_rollout_log_outside_evidence_root"
|
||||
]
|
||||
is True,
|
||||
"packet_does_not_send": True,
|
||||
"packet_does_not_mutate_database": True,
|
||||
}
|
||||
ready = all(checks.values())
|
||||
authorization_text = _authorization_text(chat_label=chat_label, chat_id=chat_id, messages=messages)
|
||||
proof_paths = {
|
||||
"preflight_json": str(DEFAULT_PREFLIGHT),
|
||||
"postflight_json": str(DEFAULT_POSTFLIGHT),
|
||||
"capture_receipt_json": str(DEFAULT_CAPTURE_RECEIPT),
|
||||
"capture_json": f"{proof_dir}/capture.json",
|
||||
"turn_screenshots": [f"{proof_dir}/turn-{index}.png" for index in range(1, 4)],
|
||||
"turn_accessibility": [f"{proof_dir}/turn-{index}-accessibility.txt" for index in range(1, 4)],
|
||||
"final_screenshot": f"{proof_dir}/final.png",
|
||||
"final_accessibility": f"{proof_dir}/final-accessibility.txt",
|
||||
"browser_provenance": f"{proof_dir}/browser-provenance.json",
|
||||
}
|
||||
return {
|
||||
"schema": SCHEMA,
|
||||
"generated_at_utc": datetime.now(timezone.utc).isoformat(),
|
||||
"mode": "telegram_visible_unseen_chain_exact_packet_not_sent",
|
||||
"packet_generation_git_sha": git_sha if git_sha is not None else current_git_sha(),
|
||||
"protocol_sha256": protocol_sha256,
|
||||
"protocol": protocol,
|
||||
"ready_to_request_action_time_authorization": ready,
|
||||
"authorization_gate_status": "ready_to_request_exact_authorization" if ready else "not_ready",
|
||||
"telegram_visible_messages_sent": False,
|
||||
"telegram_visible_message_authorization_present": False,
|
||||
"production_apply_executed": False,
|
||||
"mutates_db": False,
|
||||
"target": target,
|
||||
"exact_messages": messages,
|
||||
"handler_receipt_binding": handler_binding,
|
||||
"tooling_binding": tooling,
|
||||
"manifest_binding": manifest,
|
||||
"browser_provenance_contract": browser_provenance_contract,
|
||||
"operator_context": protocol["operator_context"],
|
||||
"checks": checks,
|
||||
"expected_proof_paths_after_authorized_run": proof_paths,
|
||||
"explicit_operator_authorization_text": authorization_text,
|
||||
"clear_CTA": (
|
||||
"Reply with the exact authorization sentence in this packet. That sentence names the destination, "
|
||||
"transport, complete message bodies, ordering, evidence, and no-mutation boundary."
|
||||
),
|
||||
"next_non_user_action_after_authorization": [
|
||||
"Re-run the zero-mutation preflight and confirm its packet file hash is current.",
|
||||
"Use authenticated Chrome only and verify the Leo chat ID before typing anything.",
|
||||
"Send one exact message, wait for Leo's visible reply, then continue to the next exact message.",
|
||||
"Capture message IDs, timestamps, screenshot, accessibility text, and the Chrome-control provenance receipt without copying handler output.",
|
||||
"Retain the Codex rollout path whose Chrome tool receipt contains the provenance SHA256.",
|
||||
"Extract the selected DB object reference and run the read-only postflight with that reference.",
|
||||
"Run the Telegram-visible verifier and accept T3 only if every visible and state check passes.",
|
||||
],
|
||||
"claim_ceiling": {
|
||||
"current_tier": "T0_spec_plus_prior_T2_handler_evidence",
|
||||
"required_tier": "T3_live_readonly",
|
||||
"proven": "The exact three-turn Chrome send packet is bound to a passing no-send handler receipt.",
|
||||
"not_proven": [
|
||||
"Telegram-visible delivery of these three messages",
|
||||
"Telegram-visible replies from Leo",
|
||||
"post-send canonical fingerprint equality",
|
||||
],
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
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:
|
||||
target = data["target"]
|
||||
lines = [
|
||||
"# Telegram-Visible Unseen Chain Authorization Packet",
|
||||
"",
|
||||
f"Generated UTC: `{data['generated_at_utc']}`",
|
||||
f"Protocol SHA256: `{data['protocol_sha256']}`",
|
||||
f"Ready to request action-time authorization: `{data['ready_to_request_action_time_authorization']}`",
|
||||
f"Telegram-visible messages sent: `{data['telegram_visible_messages_sent']}`",
|
||||
f"Mutates DB: `{data['mutates_db']}`",
|
||||
"",
|
||||
"## Exact Destination",
|
||||
"",
|
||||
f"- Chat: `{target['chat_label']}` (`{target['chat_id']}`)",
|
||||
f"- Transport: `{target['allowed_transport']}`",
|
||||
"",
|
||||
"## Exact Messages",
|
||||
"",
|
||||
]
|
||||
for item in data["exact_messages"]:
|
||||
lines.extend(
|
||||
[
|
||||
f"### {item['sequence']}. {item['prompt_id']}",
|
||||
"",
|
||||
item["message"],
|
||||
"",
|
||||
f"SHA256: `{item['message_sha256']}`",
|
||||
"",
|
||||
]
|
||||
)
|
||||
manifest = data["manifest_binding"]
|
||||
execution = manifest["execution_contract"]
|
||||
lines.extend(
|
||||
[
|
||||
"## Read-Only State Contract",
|
||||
"",
|
||||
f"- Manifest: `{manifest['path']}`",
|
||||
f"- Manifest SHA256: `{manifest['sha256']}`",
|
||||
f"- Effective DB role: `{execution['effective_role']}`",
|
||||
f"- Transaction read only: `{execution['transaction_read_only']}`",
|
||||
f"- Arbitrary manifest override allowed: `{execution['arbitrary_manifest_override_allowed']}`",
|
||||
"",
|
||||
"## Independent Capture Contract",
|
||||
"",
|
||||
f"- Codex thread: `{data['operator_context']['codex_thread_id']}`",
|
||||
"- Authorization must be an exact platform user-message event in that thread's rollout.",
|
||||
"- Each turn and final artifact must be bound by Chrome-backend tool receipts in that rollout.",
|
||||
"",
|
||||
"## Checks",
|
||||
"",
|
||||
]
|
||||
)
|
||||
lines.extend(f"- `{key}`: `{value}`" for key, value in sorted(data["checks"].items()))
|
||||
lines.extend(
|
||||
[
|
||||
"",
|
||||
"## Exact Action-Time Authorization",
|
||||
"",
|
||||
data["explicit_operator_authorization_text"],
|
||||
"",
|
||||
"## Clear CTA",
|
||||
"",
|
||||
data["clear_CTA"],
|
||||
"",
|
||||
"## Claim Ceiling",
|
||||
"",
|
||||
f"Current tier: `{data['claim_ceiling']['current_tier']}`",
|
||||
f"Required tier: `{data['claim_ceiling']['required_tier']}`",
|
||||
"",
|
||||
]
|
||||
)
|
||||
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("--handler-receipt", type=Path, default=DEFAULT_HANDLER_RECEIPT)
|
||||
parser.add_argument("--chat-id", default=DEFAULT_CHAT_ID)
|
||||
parser.add_argument("--chat-label", default=DEFAULT_CHAT_LABEL)
|
||||
parser.add_argument("--proof-dir", default=DEFAULT_PROOF_DIR)
|
||||
parser.add_argument("--out", type=Path, default=DEFAULT_OUT)
|
||||
parser.add_argument("--markdown-out", type=Path, default=DEFAULT_MARKDOWN_OUT)
|
||||
return parser.parse_args(argv)
|
||||
|
||||
|
||||
def main(argv: list[str] | None = None) -> int:
|
||||
args = parse_args(argv)
|
||||
data = build_packet(
|
||||
handler_receipt_path=args.handler_receipt,
|
||||
chat_id=args.chat_id,
|
||||
chat_label=args.chat_label,
|
||||
proof_dir=args.proof_dir,
|
||||
)
|
||||
write_json(args.out, data)
|
||||
write_markdown(args.markdown_out, data)
|
||||
print(
|
||||
json.dumps(
|
||||
{
|
||||
"out": str(args.out),
|
||||
"markdown_out": str(args.markdown_out),
|
||||
"ready_to_request_action_time_authorization": data["ready_to_request_action_time_authorization"],
|
||||
"telegram_visible_messages_sent": False,
|
||||
},
|
||||
indent=2,
|
||||
sort_keys=True,
|
||||
)
|
||||
)
|
||||
return 0 if data["ready_to_request_action_time_authorization"] else 2
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
788
scripts/collect_telegram_visible_unseen_chain_state.py
Normal file
788
scripts/collect_telegram_visible_unseen_chain_state.py
Normal file
|
|
@ -0,0 +1,788 @@
|
|||
#!/usr/bin/env python3
|
||||
"""Collect fail-closed read-only state for the unseen Telegram chain."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import hashlib
|
||||
import json
|
||||
import re
|
||||
import secrets
|
||||
import shlex
|
||||
import subprocess
|
||||
from collections.abc import Callable
|
||||
from dataclasses import dataclass
|
||||
from datetime import datetime, timezone
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
|
||||
try:
|
||||
import build_telegram_visible_unseen_chain_packet as packet_builder
|
||||
import verify_leo_unseen_reasoning_chain as unseen
|
||||
except ImportError: # pragma: no cover - imported as scripts.* in tests
|
||||
from scripts import build_telegram_visible_unseen_chain_packet as packet_builder
|
||||
from scripts import verify_leo_unseen_reasoning_chain as unseen
|
||||
|
||||
SCHEMA = "livingip.telegramVisibleUnseenChainState.v2"
|
||||
REPO_ROOT = Path(__file__).resolve().parents[1]
|
||||
REPORT_DIR = Path("docs/reports/leo-working-state-20260709")
|
||||
DEFAULT_PACKET = packet_builder.DEFAULT_OUT
|
||||
DEFAULT_PREFLIGHT_OUT = REPORT_DIR / "telegram-visible-unseen-chain-preflight-current.json"
|
||||
DEFAULT_PREFLIGHT_MARKDOWN_OUT = REPORT_DIR / "telegram-visible-unseen-chain-preflight-current.md"
|
||||
DEFAULT_POSTFLIGHT_OUT = REPORT_DIR / "telegram-visible-unseen-chain-postflight-current.json"
|
||||
DEFAULT_POSTFLIGHT_MARKDOWN_OUT = REPORT_DIR / "telegram-visible-unseen-chain-postflight-current.md"
|
||||
DEFAULT_SSH_TARGET = "root@77.42.65.182"
|
||||
DEFAULT_SSH_KEY = Path.home() / ".ssh/livingip_hetzner_20260604_ed25519"
|
||||
DEFAULT_MANIFEST_SQL = packet_builder.DEFAULT_MANIFEST_SQL
|
||||
REMOTE_REPO = "/opt/teleo-eval/workspaces/deploy-infra"
|
||||
SUBJECT_REF_RE = re.compile(
|
||||
r"^(?:[0-9a-f]{8}|[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12})$",
|
||||
re.IGNORECASE,
|
||||
)
|
||||
SHA40_RE = re.compile(r"^[0-9a-f]{40}$")
|
||||
SHA64_RE = re.compile(r"^[0-9a-f]{64}$")
|
||||
FORBIDDEN_MANIFEST_SQL_RE = re.compile(
|
||||
r"\b(?:insert|update|delete|merge|create|alter|drop|truncate|grant|revoke|copy|call|do|vacuum|"
|
||||
r"refresh|reindex|cluster|commit|prepare|execute)\b|"
|
||||
r"\\(?:!|i|ir|include|include_relative|copy)\b|"
|
||||
r"\bset\s+(?:session\s+authorization|role)\b|"
|
||||
r"\breset\s+(?:session\s+authorization|role)\b|"
|
||||
r"\b(?:default_)?transaction_read_only\s*=\s*(?:off|false|0)\b|"
|
||||
r"\btransaction\s+read\s+write\b",
|
||||
re.IGNORECASE,
|
||||
)
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class CommandResult:
|
||||
returncode: int
|
||||
stdout: str
|
||||
stderr: str
|
||||
|
||||
|
||||
Runner = Callable[[list[str], str, int], CommandResult]
|
||||
|
||||
|
||||
def subprocess_runner(command: list[str], input_text: str, timeout: int) -> CommandResult:
|
||||
try:
|
||||
proc = subprocess.run(
|
||||
command,
|
||||
input=input_text,
|
||||
text=True,
|
||||
capture_output=True,
|
||||
timeout=timeout,
|
||||
check=False,
|
||||
)
|
||||
except subprocess.TimeoutExpired as exc:
|
||||
return CommandResult(124, str(exc.stdout or ""), f"command timed out after {timeout}s")
|
||||
return CommandResult(proc.returncode, proc.stdout, proc.stderr)
|
||||
|
||||
|
||||
def _load_json(path: Path) -> dict[str, Any]:
|
||||
return json.loads(path.read_text(encoding="utf-8"))
|
||||
|
||||
|
||||
def _canonical_sha256(value: Any) -> str:
|
||||
encoded = json.dumps(value, sort_keys=True, separators=(",", ":")).encode("utf-8")
|
||||
return hashlib.sha256(encoded).hexdigest()
|
||||
|
||||
|
||||
def _sha256_file(path: Path) -> str:
|
||||
return hashlib.sha256(path.read_bytes()).hexdigest()
|
||||
|
||||
|
||||
def canonical_manifest_path() -> Path:
|
||||
return (REPO_ROOT / DEFAULT_MANIFEST_SQL).resolve()
|
||||
|
||||
|
||||
def _manifest_sql_is_statically_read_only(sql: str) -> bool:
|
||||
normalized = re.sub(r"\s+", " ", sql).strip().casefold()
|
||||
return (
|
||||
normalized.startswith(r"\set on_error_stop on")
|
||||
and "begin transaction isolation level repeatable read read only;" in normalized
|
||||
and normalized.endswith("rollback;")
|
||||
and FORBIDDEN_MANIFEST_SQL_RE.search(sql) is None
|
||||
)
|
||||
|
||||
|
||||
def manifest_checks(packet: dict[str, Any], requested_path: Path | None = None) -> dict[str, bool]:
|
||||
canonical_path = canonical_manifest_path()
|
||||
binding = packet.get("manifest_binding") if isinstance(packet.get("manifest_binding"), dict) else {}
|
||||
protocol = packet.get("protocol") if isinstance(packet.get("protocol"), dict) else {}
|
||||
execution = binding.get("execution_contract") if isinstance(binding.get("execution_contract"), dict) else {}
|
||||
try:
|
||||
sql = canonical_path.read_text(encoding="utf-8")
|
||||
actual_sha256 = _sha256_file(canonical_path)
|
||||
except OSError:
|
||||
sql = ""
|
||||
actual_sha256 = ""
|
||||
override_path = requested_path.resolve() if requested_path is not None else canonical_path
|
||||
return {
|
||||
"manifest_canonical_path_exists": canonical_path.is_file(),
|
||||
"manifest_override_absent_or_exact_canonical_path": override_path == canonical_path,
|
||||
"manifest_packet_path_is_exact_canonical_relative_path": binding.get("path") == str(DEFAULT_MANIFEST_SQL),
|
||||
"manifest_packet_sha256_matches_canonical_file": bool(actual_sha256) and binding.get("sha256") == actual_sha256,
|
||||
"manifest_protocol_binding_matches_packet": protocol.get("manifest_binding") == binding,
|
||||
"manifest_sql_statically_read_only": bool(sql) and _manifest_sql_is_statically_read_only(sql),
|
||||
"manifest_effective_role_is_read_only": execution.get("effective_role") == packet_builder.READ_ONLY_DB_ROLE,
|
||||
"manifest_default_transaction_read_only_enforced": execution.get("default_transaction_read_only") == "on",
|
||||
"manifest_transaction_read_only_enforced": execution.get("transaction_read_only") == "on",
|
||||
"manifest_psql_rc_disabled": execution.get("psql_rc_disabled") is True,
|
||||
"manifest_arbitrary_override_forbidden": execution.get("arbitrary_manifest_override_allowed") is False,
|
||||
}
|
||||
|
||||
|
||||
def parse_key_value_lines(text: str) -> dict[str, str]:
|
||||
values: dict[str, str] = {}
|
||||
for line in text.splitlines():
|
||||
if "=" not in line:
|
||||
continue
|
||||
key, value = line.split("=", 1)
|
||||
values[key] = value.strip()
|
||||
return values
|
||||
|
||||
|
||||
def parse_manifest_output(raw: str) -> dict[str, Any]:
|
||||
rows = []
|
||||
try:
|
||||
for line in raw.splitlines():
|
||||
candidate = line.strip()
|
||||
if not candidate or candidate in {"BEGIN", "SET", "ROLLBACK"}:
|
||||
continue
|
||||
value = json.loads(candidate)
|
||||
if isinstance(value, dict):
|
||||
rows.append(value)
|
||||
except (TypeError, json.JSONDecodeError) as exc:
|
||||
return {"status": "error", "error": f"manifest_parse_error:{type(exc).__name__}"}
|
||||
|
||||
tables = {
|
||||
f"{row['schema']}.{row['table']}": {
|
||||
"row_count": int(row["row_count"]),
|
||||
"rowset_md5": row["rowset_md5"],
|
||||
}
|
||||
for row in rows
|
||||
if row.get("kind") == "table"
|
||||
}
|
||||
singleton_kinds = {
|
||||
"schemas",
|
||||
"extensions",
|
||||
"application_roles",
|
||||
"columns",
|
||||
"constraints",
|
||||
"indexes",
|
||||
"sequences",
|
||||
"views",
|
||||
"functions",
|
||||
"triggers",
|
||||
"types",
|
||||
"policies",
|
||||
}
|
||||
singleton = {str(row["kind"]): row.get("items", []) for row in rows if row.get("kind") in singleton_kinds}
|
||||
identity_rows = [row for row in rows if row.get("kind") == "identity"]
|
||||
if len(identity_rows) != 1 or not tables or singleton_kinds - set(singleton):
|
||||
return {"status": "error", "error": "canonical_database_fingerprint_manifest_incomplete"}
|
||||
identity = identity_rows[0]
|
||||
stable = {
|
||||
"identity": {
|
||||
key: identity.get(key)
|
||||
for key in (
|
||||
"database",
|
||||
"server_version_num",
|
||||
"server_encoding",
|
||||
"database_collation",
|
||||
"database_ctype",
|
||||
"transaction_read_only",
|
||||
)
|
||||
},
|
||||
"singleton_sha256": {key: _canonical_sha256(value) for key, value in sorted(singleton.items())},
|
||||
"tables": tables,
|
||||
}
|
||||
return {
|
||||
"schema": "livingip.teleoCanonicalDatabaseFingerprint.v1",
|
||||
"status": "ok",
|
||||
"fingerprint_sha256": _canonical_sha256(stable),
|
||||
"table_count": len(tables),
|
||||
"total_rows": sum(item["row_count"] for item in tables.values()),
|
||||
"table_rows_sha256": _canonical_sha256(tables),
|
||||
"structure_sha256": _canonical_sha256(stable["singleton_sha256"]),
|
||||
"transaction_read_only": identity.get("transaction_read_only"),
|
||||
"current_user": identity.get("current_user"),
|
||||
}
|
||||
|
||||
|
||||
def packet_checks(packet: dict[str, Any], *, requested_manifest_path: Path | None = None) -> dict[str, bool]:
|
||||
target = packet.get("target") if isinstance(packet.get("target"), dict) else {}
|
||||
protocol = packet.get("protocol") if isinstance(packet.get("protocol"), dict) else {}
|
||||
packet_check_section = packet.get("checks") if isinstance(packet.get("checks"), dict) else {}
|
||||
exact = packet_builder.exact_messages()
|
||||
expected_tooling = packet_builder.tooling_binding()
|
||||
checks = {
|
||||
"packet_schema_supported": packet.get("schema") == packet_builder.SCHEMA,
|
||||
"packet_check_section_present_and_passing": bool(packet_check_section)
|
||||
and all(value is True for value in packet_check_section.values()),
|
||||
"packet_ready_for_authorization_request": packet.get("ready_to_request_action_time_authorization") is True,
|
||||
"packet_not_sent": packet.get("telegram_visible_messages_sent") is False,
|
||||
"packet_has_no_authorization_recorded": packet.get("telegram_visible_message_authorization_present") is False,
|
||||
"packet_does_not_mutate_db": packet.get("mutates_db") is False,
|
||||
"packet_targets_exact_leo_chat": target.get("chat_label") == packet_builder.DEFAULT_CHAT_LABEL
|
||||
and target.get("chat_id") == packet_builder.DEFAULT_CHAT_ID,
|
||||
"packet_requires_authenticated_chrome": target.get("allowed_transport") == "authenticated_chrome_telegram_ui",
|
||||
"packet_prompt_ids_exact": target.get("expected_prompt_ids") == [item["id"] for item in unseen.PROMPTS],
|
||||
"packet_messages_exact": [item.get("message") for item in packet.get("exact_messages", [])]
|
||||
== [item["message"] for item in exact],
|
||||
"packet_protocol_sha256_present": bool(SHA64_RE.fullmatch(str(packet.get("protocol_sha256") or ""))),
|
||||
"packet_protocol_sha256_derivation_valid": bool(protocol)
|
||||
and packet.get("protocol_sha256") == _canonical_sha256(protocol),
|
||||
"packet_protocol_top_level_bindings_match": protocol.get("target") == packet.get("target")
|
||||
and protocol.get("exact_messages") == packet.get("exact_messages")
|
||||
and protocol.get("handler_binding") == packet.get("handler_receipt_binding")
|
||||
and protocol.get("tooling_binding") == packet.get("tooling_binding")
|
||||
and protocol.get("browser_provenance_contract") == packet.get("browser_provenance_contract")
|
||||
and protocol.get("operator_context") == packet.get("operator_context"),
|
||||
"packet_tooling_hashes_match_current_sources": packet.get("tooling_binding") == expected_tooling,
|
||||
}
|
||||
checks.update(manifest_checks(packet, requested_path=requested_manifest_path))
|
||||
return checks
|
||||
|
||||
|
||||
def ssh_command(args: argparse.Namespace, remote_command: str) -> list[str]:
|
||||
return [
|
||||
"ssh",
|
||||
"-i",
|
||||
str(args.ssh_key),
|
||||
"-o",
|
||||
"BatchMode=yes",
|
||||
"-o",
|
||||
"StrictHostKeyChecking=accept-new",
|
||||
"-o",
|
||||
f"ConnectTimeout={args.connect_timeout}",
|
||||
args.ssh_target,
|
||||
remote_command,
|
||||
]
|
||||
|
||||
|
||||
def deploy_readback_command() -> str:
|
||||
repo = shlex.quote(REMOTE_REPO)
|
||||
return (
|
||||
f"cd {repo} && "
|
||||
"deploy_head=$(git rev-parse HEAD) && "
|
||||
"last_deploy_sha=$(cat /opt/teleo-eval/.last-deploy-sha) && "
|
||||
'printf \'deploy_head=%s\\nlast_deploy_sha=%s\\n\' "$deploy_head" "$last_deploy_sha" && '
|
||||
'if git merge-base --is-ancestor "$last_deploy_sha" "$deploy_head"; then '
|
||||
"printf 'deploy_stamp_ancestor=true\\n'; else printf 'deploy_stamp_ancestor=false\\n'; fi"
|
||||
)
|
||||
|
||||
|
||||
def service_readback_command() -> str:
|
||||
return (
|
||||
"systemctl show leoclean-gateway.service "
|
||||
"-p ActiveState -p SubState -p MainPID -p NRestarts -p ExecMainStartTimestamp --no-pager"
|
||||
)
|
||||
|
||||
|
||||
def fingerprint_readback_command() -> str:
|
||||
pgoptions = shlex.quote(
|
||||
"PGOPTIONS=-c default_transaction_read_only=on -c transaction_read_only=on "
|
||||
f"-c role={packet_builder.READ_ONLY_DB_ROLE}"
|
||||
)
|
||||
return f"docker exec -e {pgoptions} -i teleo-pg psql -X -U postgres -d teleo -At -q -v ON_ERROR_STOP=1"
|
||||
|
||||
|
||||
def subject_readback_sql(subject_ref: str) -> str:
|
||||
if not SUBJECT_REF_RE.fullmatch(subject_ref):
|
||||
raise ValueError("subject_ref must be an eight-hex prefix or UUID")
|
||||
prefix = subject_ref.casefold()
|
||||
return f"""
|
||||
\\set ON_ERROR_STOP on
|
||||
begin transaction isolation level repeatable read read only;
|
||||
select jsonb_build_object(
|
||||
'subject_ref', '{prefix}',
|
||||
'matches', coalesce(jsonb_agg(item order by item->>'table', item->'row'->>'id'), '[]'::jsonb)
|
||||
)::text
|
||||
from (
|
||||
select jsonb_build_object(
|
||||
'table', 'public.claims',
|
||||
'row', to_jsonb(claim_row),
|
||||
'evidence_count', (select count(*) from public.claim_evidence evidence where evidence.claim_id = claim_row.id)
|
||||
) as item
|
||||
from public.claims claim_row
|
||||
where lower(claim_row.id::text) like '{prefix}%'
|
||||
union all
|
||||
select jsonb_build_object(
|
||||
'table', 'public.beliefs',
|
||||
'row', to_jsonb(belief_row),
|
||||
'evidence_count', null
|
||||
) as item
|
||||
from public.beliefs belief_row
|
||||
where lower(belief_row.id::text) like '{prefix}%'
|
||||
) matched;
|
||||
rollback;
|
||||
""".strip()
|
||||
|
||||
|
||||
def _parse_single_json_line(raw: str) -> dict[str, Any] | None:
|
||||
for line in raw.splitlines():
|
||||
candidate = line.strip()
|
||||
if not candidate or candidate in {"BEGIN", "SET", "ROLLBACK"}:
|
||||
continue
|
||||
try:
|
||||
value = json.loads(candidate)
|
||||
except json.JSONDecodeError:
|
||||
continue
|
||||
if isinstance(value, dict):
|
||||
return value
|
||||
return None
|
||||
|
||||
|
||||
def collect_remote(
|
||||
args: argparse.Namespace,
|
||||
runner: Runner,
|
||||
*,
|
||||
manifest_sql: str,
|
||||
) -> tuple[dict[str, Any], int, str]:
|
||||
calls: list[tuple[str, list[str], str, int]] = [
|
||||
("deploy", ssh_command(args, deploy_readback_command()), "", args.timeout),
|
||||
("service_before", ssh_command(args, service_readback_command()), "", args.timeout),
|
||||
(
|
||||
"fingerprint_before",
|
||||
ssh_command(args, fingerprint_readback_command()),
|
||||
manifest_sql,
|
||||
args.fingerprint_timeout,
|
||||
),
|
||||
(
|
||||
"fingerprint_after",
|
||||
ssh_command(args, fingerprint_readback_command()),
|
||||
manifest_sql,
|
||||
args.fingerprint_timeout,
|
||||
),
|
||||
("service_after", ssh_command(args, service_readback_command()), "", args.timeout),
|
||||
]
|
||||
if args.subject_ref:
|
||||
calls.append(
|
||||
(
|
||||
"subject",
|
||||
ssh_command(args, fingerprint_readback_command()),
|
||||
subject_readback_sql(args.subject_ref),
|
||||
args.timeout,
|
||||
)
|
||||
)
|
||||
results: dict[str, CommandResult] = {}
|
||||
attempts: dict[str, int] = {}
|
||||
for name, command, input_text, timeout in calls:
|
||||
result = CommandResult(1, "", "not attempted")
|
||||
for attempt in range(1, max(1, args.ssh_attempts) + 1):
|
||||
result = runner(command, input_text, timeout)
|
||||
attempts[name] = attempt
|
||||
if result.returncode == 0:
|
||||
break
|
||||
results[name] = result
|
||||
deploy_values = parse_key_value_lines(results["deploy"].stdout)
|
||||
service_before = parse_key_value_lines(results["service_before"].stdout)
|
||||
service_after = parse_key_value_lines(results["service_after"].stdout)
|
||||
fingerprint_before = parse_manifest_output(results["fingerprint_before"].stdout)
|
||||
fingerprint_after = parse_manifest_output(results["fingerprint_after"].stdout)
|
||||
subject = _parse_single_json_line(results["subject"].stdout) if "subject" in results else None
|
||||
returncode = next((result.returncode for result in results.values() if result.returncode != 0), 0)
|
||||
stderr = "\n".join(f"{name}: {result.stderr.strip()}" for name, result in results.items() if result.stderr.strip())
|
||||
return (
|
||||
{
|
||||
"deploy_head": deploy_values.get("deploy_head", ""),
|
||||
"last_deploy_sha": deploy_values.get("last_deploy_sha", ""),
|
||||
"deploy_stamp_ancestor": deploy_values.get("deploy_stamp_ancestor") == "true",
|
||||
"workspace_head_matches_deployed_stamp": deploy_values.get("deploy_head")
|
||||
== deploy_values.get("last_deploy_sha"),
|
||||
"service_before": service_before,
|
||||
"service_after": service_after,
|
||||
"fingerprint_before": fingerprint_before,
|
||||
"fingerprint_after": fingerprint_after,
|
||||
"subject_readback": subject,
|
||||
"readback_attempts": attempts,
|
||||
},
|
||||
returncode,
|
||||
stderr,
|
||||
)
|
||||
|
||||
|
||||
def _service_active(state: dict[str, Any]) -> bool:
|
||||
return state.get("ActiveState") == "active" and state.get("SubState") == "running"
|
||||
|
||||
|
||||
def _service_identity(state: dict[str, Any]) -> dict[str, Any]:
|
||||
return {key: state.get(key) for key in ("MainPID", "NRestarts", "ExecMainStartTimestamp")}
|
||||
|
||||
|
||||
def _remote_checks(
|
||||
remote: dict[str, Any],
|
||||
*,
|
||||
returncode: int,
|
||||
subject_required: bool,
|
||||
expected_subject_ref: str | None,
|
||||
) -> dict[str, bool]:
|
||||
before = remote.get("fingerprint_before") or {}
|
||||
after = remote.get("fingerprint_after") or {}
|
||||
service_before = remote.get("service_before") or {}
|
||||
service_after = remote.get("service_after") or {}
|
||||
subject = remote.get("subject_readback") or {}
|
||||
matches = subject.get("matches") if isinstance(subject, dict) else None
|
||||
checks = {
|
||||
"ssh_readbacks_succeeded": returncode == 0,
|
||||
"workspace_head_is_sha": bool(SHA40_RE.fullmatch(str(remote.get("deploy_head") or ""))),
|
||||
"deployed_stamp_is_sha": bool(SHA40_RE.fullmatch(str(remote.get("last_deploy_sha") or ""))),
|
||||
"deployed_stamp_is_ancestor_of_workspace_head": remote.get("deploy_stamp_ancestor") is True,
|
||||
"service_active_before_and_after": _service_active(service_before) and _service_active(service_after),
|
||||
"service_identity_complete": all(
|
||||
value
|
||||
for value in (
|
||||
service_before.get("MainPID"),
|
||||
service_before.get("NRestarts"),
|
||||
service_before.get("ExecMainStartTimestamp"),
|
||||
service_after.get("MainPID"),
|
||||
service_after.get("NRestarts"),
|
||||
service_after.get("ExecMainStartTimestamp"),
|
||||
)
|
||||
),
|
||||
"service_process_unchanged_during_probe": _service_identity(service_before) == _service_identity(service_after),
|
||||
"first_fingerprint_complete": before.get("status") == "ok" and int(before.get("table_count") or 0) > 0,
|
||||
"second_fingerprint_complete": after.get("status") == "ok" and int(after.get("table_count") or 0) > 0,
|
||||
"fingerprints_are_read_only": before.get("transaction_read_only") == "on"
|
||||
and after.get("transaction_read_only") == "on",
|
||||
"fingerprints_use_independent_read_only_role": before.get("current_user") == packet_builder.READ_ONLY_DB_ROLE
|
||||
and after.get("current_user") == packet_builder.READ_ONLY_DB_ROLE,
|
||||
"canonical_fingerprint_unchanged_during_probe": bool(before.get("fingerprint_sha256"))
|
||||
and before.get("fingerprint_sha256") == after.get("fingerprint_sha256"),
|
||||
}
|
||||
if subject_required:
|
||||
checks.update(
|
||||
{
|
||||
"subject_readback_present": isinstance(subject, dict),
|
||||
"subject_reference_matches_request": subject.get("subject_ref")
|
||||
== str(expected_subject_ref or "").casefold(),
|
||||
"subject_resolved_to_exactly_one_db_object": isinstance(matches, list) and len(matches) == 1,
|
||||
}
|
||||
)
|
||||
return checks
|
||||
|
||||
|
||||
def derive_state_token(artifact: dict[str, Any]) -> str:
|
||||
return _canonical_sha256(
|
||||
{
|
||||
"schema": artifact.get("schema"),
|
||||
"generated_at_utc": artifact.get("generated_at_utc"),
|
||||
"phase": artifact.get("phase"),
|
||||
"packet_file_sha256": artifact.get("packet_file_sha256"),
|
||||
"protocol_sha256": artifact.get("protocol_sha256"),
|
||||
"manifest_binding": artifact.get("manifest_binding"),
|
||||
"capture_challenge_nonce": artifact.get("capture_challenge_nonce"),
|
||||
"baseline_state_token_sha256": artifact.get("baseline_state_token_sha256"),
|
||||
"subject_ref": artifact.get("subject_ref"),
|
||||
"packet_checks": artifact.get("packet_checks"),
|
||||
"remote_checks": artifact.get("remote_checks"),
|
||||
"baseline_checks": artifact.get("baseline_checks"),
|
||||
"remote": {
|
||||
"deploy_head": (artifact.get("remote") or {}).get("deploy_head"),
|
||||
"last_deploy_sha": (artifact.get("remote") or {}).get("last_deploy_sha"),
|
||||
"service_after": _service_identity((artifact.get("remote") or {}).get("service_after") or {}),
|
||||
"fingerprint_after": (artifact.get("remote") or {}).get("fingerprint_after"),
|
||||
"subject_readback": (artifact.get("remote") or {}).get("subject_readback"),
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
def state_token_is_valid(artifact: dict[str, Any]) -> bool:
|
||||
token = artifact.get("state_token_sha256")
|
||||
return bool(SHA64_RE.fullmatch(str(token or ""))) and token == derive_state_token(artifact)
|
||||
|
||||
|
||||
def _empty_remote() -> dict[str, Any]:
|
||||
return {
|
||||
"deploy_head": "",
|
||||
"last_deploy_sha": "",
|
||||
"deploy_stamp_ancestor": False,
|
||||
"workspace_head_matches_deployed_stamp": False,
|
||||
"service_before": {},
|
||||
"service_after": {},
|
||||
"fingerprint_before": {},
|
||||
"fingerprint_after": {},
|
||||
"subject_readback": None,
|
||||
"readback_attempts": {},
|
||||
}
|
||||
|
||||
|
||||
def collect_state(args: argparse.Namespace, *, runner: Runner = subprocess_runner) -> dict[str, Any]:
|
||||
packet = _load_json(args.packet)
|
||||
requested_manifest_path = getattr(args, "manifest_sql", None)
|
||||
local_packet_checks = packet_checks(packet, requested_manifest_path=requested_manifest_path)
|
||||
manifest_sql = ""
|
||||
if all(local_packet_checks.values()):
|
||||
try:
|
||||
manifest_sql = canonical_manifest_path().read_text(encoding="utf-8")
|
||||
except OSError:
|
||||
manifest_sql = ""
|
||||
loaded_sha256 = hashlib.sha256(manifest_sql.encode("utf-8")).hexdigest()
|
||||
local_packet_checks.update(
|
||||
{
|
||||
"manifest_loaded_bytes_match_bound_sha256": loaded_sha256
|
||||
== (packet.get("manifest_binding") or {}).get("sha256"),
|
||||
"manifest_loaded_bytes_revalidated_read_only": _manifest_sql_is_statically_read_only(manifest_sql),
|
||||
}
|
||||
)
|
||||
if all(local_packet_checks.values()):
|
||||
remote, remote_returncode, remote_stderr = collect_remote(
|
||||
args,
|
||||
runner,
|
||||
manifest_sql=manifest_sql,
|
||||
)
|
||||
else:
|
||||
remote = _empty_remote()
|
||||
remote_returncode = 1
|
||||
remote_stderr = "local fail-closed validation rejected execution before SSH"
|
||||
remote_checks = _remote_checks(
|
||||
remote,
|
||||
returncode=remote_returncode,
|
||||
subject_required=args.phase == "postflight",
|
||||
expected_subject_ref=args.subject_ref,
|
||||
)
|
||||
baseline = _load_json(args.baseline) if args.baseline else None
|
||||
baseline_checks: dict[str, bool] = {}
|
||||
if args.phase == "postflight":
|
||||
baseline_packet_checks = baseline.get("packet_checks") if isinstance(baseline, dict) else {}
|
||||
baseline_remote_checks = baseline.get("remote_checks") if isinstance(baseline, dict) else {}
|
||||
baseline_nonce = str((baseline or {}).get("capture_challenge_nonce") or "")
|
||||
baseline_checks = {
|
||||
"baseline_supplied": baseline is not None,
|
||||
"baseline_schema_supported": bool(baseline and baseline.get("schema") == SCHEMA),
|
||||
"baseline_is_passing_preflight": bool(
|
||||
baseline and baseline.get("phase") == "preflight" and baseline.get("status") == "pass"
|
||||
),
|
||||
"baseline_check_sections_all_pass": bool(baseline_packet_checks)
|
||||
and all(value is True for value in baseline_packet_checks.values())
|
||||
and bool(baseline_remote_checks)
|
||||
and all(value is True for value in baseline_remote_checks.values()),
|
||||
"baseline_state_token_derivation_valid": bool(baseline and state_token_is_valid(baseline)),
|
||||
"baseline_capture_challenge_nonce_valid": bool(SHA64_RE.fullmatch(baseline_nonce)),
|
||||
"baseline_protocol_matches_packet": bool(
|
||||
baseline and baseline.get("protocol_sha256") == packet.get("protocol_sha256")
|
||||
),
|
||||
"baseline_packet_file_matches": bool(
|
||||
baseline and baseline.get("packet_file_sha256") == _sha256_file(args.packet)
|
||||
),
|
||||
"baseline_manifest_binding_matches_packet": bool(
|
||||
baseline and baseline.get("manifest_binding") == packet.get("manifest_binding")
|
||||
),
|
||||
"canonical_fingerprint_matches_preflight": bool(
|
||||
baseline
|
||||
and (baseline.get("remote") or {}).get("fingerprint_after", {}).get("fingerprint_sha256")
|
||||
== remote.get("fingerprint_after", {}).get("fingerprint_sha256")
|
||||
),
|
||||
"gateway_process_matches_preflight": bool(
|
||||
baseline
|
||||
and _service_identity((baseline.get("remote") or {}).get("service_after") or {})
|
||||
== _service_identity(remote.get("service_after") or {})
|
||||
),
|
||||
}
|
||||
status = (
|
||||
"pass"
|
||||
if all(local_packet_checks.values()) and all(remote_checks.values()) and all(baseline_checks.values())
|
||||
else "fail"
|
||||
)
|
||||
packet_file_sha256 = _sha256_file(args.packet)
|
||||
generated_at_utc = datetime.now(timezone.utc).isoformat()
|
||||
capture_challenge_nonce = (
|
||||
secrets.token_hex(32)
|
||||
if args.phase == "preflight"
|
||||
else str((baseline or {}).get("capture_challenge_nonce") or "")
|
||||
)
|
||||
baseline_state_token_sha256 = (
|
||||
str((baseline or {}).get("state_token_sha256") or "") if args.phase == "postflight" else ""
|
||||
)
|
||||
exact_gate = ""
|
||||
if status != "pass":
|
||||
failed = [
|
||||
key
|
||||
for checks in (local_packet_checks, remote_checks, baseline_checks)
|
||||
for key, value in checks.items()
|
||||
if value is not True
|
||||
]
|
||||
exact_gate = "; ".join(part for part in (remote_stderr.strip(), ", ".join(failed)) if part)
|
||||
current_canary = (
|
||||
"Read-only pre-send readiness for the exact three-turn unseen Leo chain in Telegram"
|
||||
if args.phase == "preflight"
|
||||
else "Read-only post-send DB grounding and unchanged-state proof for the exact Telegram chain"
|
||||
)
|
||||
artifact = {
|
||||
"schema": SCHEMA,
|
||||
"generated_at_utc": generated_at_utc,
|
||||
"mode": "telegram_visible_unseen_chain_zero_mutation_state_readback",
|
||||
"phase": args.phase,
|
||||
"status": status,
|
||||
"ready_for_action_time_authorization": args.phase == "preflight" and status == "pass",
|
||||
"ready_for_visible_capture_verification": args.phase == "postflight" and status == "pass",
|
||||
"telegram_visible_messages_sent_by_collector": False,
|
||||
"production_apply_executed": False,
|
||||
"mutates_db": False,
|
||||
"packet_path": str(args.packet),
|
||||
"packet_file_sha256": packet_file_sha256,
|
||||
"protocol_sha256": packet.get("protocol_sha256"),
|
||||
"manifest_binding": packet.get("manifest_binding"),
|
||||
"capture_challenge_nonce": capture_challenge_nonce,
|
||||
"baseline_state_token_sha256": baseline_state_token_sha256,
|
||||
"baseline_path": str(args.baseline) if args.baseline else "",
|
||||
"subject_ref": args.subject_ref or "",
|
||||
"packet_checks": local_packet_checks,
|
||||
"remote_checks": remote_checks,
|
||||
"baseline_checks": baseline_checks,
|
||||
"remote": remote,
|
||||
"remote_returncode": remote_returncode,
|
||||
"remote_stderr": remote_stderr,
|
||||
"blocker_readback": {
|
||||
"current_canary": current_canary,
|
||||
"attempted_routes": [
|
||||
"local exact packet validation",
|
||||
*(
|
||||
[
|
||||
"SSH deploy stamp and gateway service readback",
|
||||
"two canonical repeatable-read read-only Postgres parity manifests",
|
||||
*(["independent selected-object DB readback"] if args.subject_ref else []),
|
||||
]
|
||||
if remote.get("readback_attempts")
|
||||
else []
|
||||
),
|
||||
],
|
||||
"exact_gate": exact_gate,
|
||||
"clear_CTA": (
|
||||
"No user action is needed; repair the named readback check and rerun this collector."
|
||||
if exact_gate
|
||||
else "Use the packet's exact authorization sentence only when ready to cross the send boundary."
|
||||
),
|
||||
"next_non_user_action": (
|
||||
"Run the authenticated-Chrome three-turn flow only after exact authorization, then collect postflight."
|
||||
if args.phase == "preflight" and status == "pass"
|
||||
else "Repair the failed preflight check and rerun before requesting authorization."
|
||||
if args.phase == "preflight"
|
||||
else "Run the visible capture verifier against this postflight and the retained Chrome evidence."
|
||||
),
|
||||
},
|
||||
"claim_ceiling": {
|
||||
"current_tier": "T3_live_readonly" if status == "pass" else "T0_failed_preflight",
|
||||
"proven": (
|
||||
"Two canonical read-only snapshots and the gateway process were unchanged during this probe."
|
||||
if status == "pass"
|
||||
else "No live readiness claim; one or more fail-closed checks did not pass."
|
||||
),
|
||||
"not_proven": [
|
||||
"Telegram-visible delivery or reply behavior",
|
||||
"authorization to send Telegram messages",
|
||||
"canonical mutation",
|
||||
],
|
||||
},
|
||||
}
|
||||
artifact["state_token_sha256"] = derive_state_token(artifact)
|
||||
return artifact
|
||||
|
||||
|
||||
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:
|
||||
remote = data.get("remote") or {}
|
||||
service = remote.get("service_after") or {}
|
||||
fingerprint = remote.get("fingerprint_after") or {}
|
||||
lines = [
|
||||
f"# Telegram-Visible Unseen Chain {data['phase'].title()}",
|
||||
"",
|
||||
f"Generated UTC: `{data['generated_at_utc']}`",
|
||||
f"Status: `{data['status']}`",
|
||||
f"Protocol SHA256: `{data['protocol_sha256']}`",
|
||||
f"Packet file SHA256: `{data['packet_file_sha256']}`",
|
||||
f"State token SHA256: `{data['state_token_sha256']}`",
|
||||
f"Messages sent by collector: `{data['telegram_visible_messages_sent_by_collector']}`",
|
||||
f"Mutates DB: `{data['mutates_db']}`",
|
||||
"",
|
||||
"## Checks",
|
||||
"",
|
||||
]
|
||||
for section in ("packet_checks", "remote_checks", "baseline_checks"):
|
||||
for key, value in sorted(data.get(section, {}).items()):
|
||||
lines.append(f"- `{key}`: `{value}`")
|
||||
lines.extend(
|
||||
[
|
||||
"",
|
||||
"## Live Readback",
|
||||
"",
|
||||
f"- Deploy head: `{remote.get('deploy_head', '')}`",
|
||||
f"- Deploy stamp: `{remote.get('last_deploy_sha', '')}`",
|
||||
f"- Gateway MainPID: `{service.get('MainPID', '')}`",
|
||||
f"- Gateway NRestarts: `{service.get('NRestarts', '')}`",
|
||||
f"- Manifest: `{(data.get('manifest_binding') or {}).get('path', '')}`",
|
||||
f"- Manifest SHA256: `{(data.get('manifest_binding') or {}).get('sha256', '')}`",
|
||||
f"- Effective DB role: `{fingerprint.get('current_user', '')}`",
|
||||
f"- Transaction read only: `{fingerprint.get('transaction_read_only', '')}`",
|
||||
f"- Canonical fingerprint: `{fingerprint.get('fingerprint_sha256', '')}`",
|
||||
f"- Canonical tables: `{fingerprint.get('table_count', '')}`",
|
||||
f"- Canonical rows: `{fingerprint.get('total_rows', '')}`",
|
||||
f"- Selected object ref: `{data.get('subject_ref', '')}`",
|
||||
"",
|
||||
"## Claim Ceiling",
|
||||
"",
|
||||
data["claim_ceiling"]["proven"],
|
||||
"",
|
||||
]
|
||||
)
|
||||
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("--phase", choices=("preflight", "postflight"), default="preflight")
|
||||
parser.add_argument("--packet", type=Path, default=DEFAULT_PACKET)
|
||||
parser.add_argument("--baseline", type=Path)
|
||||
parser.add_argument("--subject-ref")
|
||||
parser.add_argument("--ssh-target", default=DEFAULT_SSH_TARGET)
|
||||
parser.add_argument("--ssh-key", type=Path, default=DEFAULT_SSH_KEY)
|
||||
parser.add_argument("--connect-timeout", type=int, default=10)
|
||||
parser.add_argument("--timeout", type=int, default=60)
|
||||
parser.add_argument("--fingerprint-timeout", type=int, default=240)
|
||||
parser.add_argument("--ssh-attempts", type=int, default=3)
|
||||
parser.add_argument("--out", type=Path)
|
||||
parser.add_argument("--markdown-out", type=Path)
|
||||
args = parser.parse_args(argv)
|
||||
if args.phase == "postflight" and (not args.baseline or not args.subject_ref):
|
||||
parser.error("postflight requires --baseline and --subject-ref")
|
||||
if args.subject_ref and not SUBJECT_REF_RE.fullmatch(args.subject_ref):
|
||||
parser.error("--subject-ref must be an eight-hex prefix or UUID")
|
||||
if args.out is None:
|
||||
args.out = DEFAULT_PREFLIGHT_OUT if args.phase == "preflight" else DEFAULT_POSTFLIGHT_OUT
|
||||
if args.markdown_out is None:
|
||||
args.markdown_out = (
|
||||
DEFAULT_PREFLIGHT_MARKDOWN_OUT if args.phase == "preflight" else DEFAULT_POSTFLIGHT_MARKDOWN_OUT
|
||||
)
|
||||
return args
|
||||
|
||||
|
||||
def main(argv: list[str] | None = None) -> int:
|
||||
args = parse_args(argv)
|
||||
data = collect_state(args)
|
||||
write_json(args.out, data)
|
||||
write_markdown(args.markdown_out, data)
|
||||
print(
|
||||
json.dumps(
|
||||
{
|
||||
"out": str(args.out),
|
||||
"markdown_out": str(args.markdown_out),
|
||||
"phase": args.phase,
|
||||
"status": data["status"],
|
||||
"mutates_db": False,
|
||||
},
|
||||
indent=2,
|
||||
sort_keys=True,
|
||||
)
|
||||
)
|
||||
return 0 if data["status"] == "pass" else 2
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
230
scripts/finalize_approve_claim_isolated_canary.py
Normal file
230
scripts/finalize_approve_claim_isolated_canary.py
Normal 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())
|
||||
|
|
@ -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(
|
||||
proposal_id: str,
|
||||
*,
|
||||
|
|
|
|||
|
|
@ -11,9 +11,13 @@ from __future__ import annotations
|
|||
|
||||
import argparse
|
||||
import hashlib
|
||||
import importlib.metadata
|
||||
import json
|
||||
import os
|
||||
import platform
|
||||
import re
|
||||
import subprocess
|
||||
import sys
|
||||
from datetime import datetime, timezone
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
|
|
@ -24,6 +28,54 @@ SCHEMA = "livingip.leoBehaviorManifest.v1"
|
|||
DEFAULT_PROFILE = Path("/home/teleo/.hermes/profiles/leoclean")
|
||||
DEFAULT_HERMES_ROOT = Path("/home/teleo/.hermes/hermes-agent")
|
||||
DEFAULT_DEPLOYMENT_ROOT = Path("/opt/teleo-eval/workspaces/deploy-infra")
|
||||
STATIC_RUNTIME_COMPONENTS = (
|
||||
"profile_config",
|
||||
"procedural_skills",
|
||||
"runtime_middleware",
|
||||
"database_tools",
|
||||
)
|
||||
IDENTITY_RUNTIME_COMPONENTS = (
|
||||
"procedural_skills",
|
||||
"runtime_middleware",
|
||||
"database_tools",
|
||||
)
|
||||
STABLE_MANIFEST_FIELDS = (
|
||||
"schema",
|
||||
"model_runtime",
|
||||
"hermes_runtime",
|
||||
"teleo_infrastructure_runtime",
|
||||
"components",
|
||||
"python_runtime",
|
||||
"canonical_database",
|
||||
)
|
||||
SECRET_KEYS = frozenset(
|
||||
{
|
||||
"access_key",
|
||||
"access_token",
|
||||
"api_key",
|
||||
"authorization",
|
||||
"bot_token",
|
||||
"client_secret",
|
||||
"credential",
|
||||
"credentials",
|
||||
"password",
|
||||
"private_key",
|
||||
"refresh_token",
|
||||
"secret",
|
||||
"token",
|
||||
}
|
||||
)
|
||||
SECRET_KEY_SUFFIXES = (
|
||||
"api_key",
|
||||
"access_key",
|
||||
"private_key",
|
||||
"password",
|
||||
"secret",
|
||||
"token",
|
||||
"credential",
|
||||
)
|
||||
RUNTIME_DISTRIBUTIONS = ("PyYAML",)
|
||||
SAFE_CONFIG_SCALAR = re.compile(r"^[A-Za-z0-9._:/-]+$")
|
||||
|
||||
|
||||
def sha256_bytes(value: bytes) -> str:
|
||||
|
|
@ -50,7 +102,9 @@ def _safe_relative(path: Path, root: Path) -> str:
|
|||
return str(path)
|
||||
|
||||
|
||||
def _resolved_node_fingerprint(path: Path, seen_directories: frozenset[tuple[int, int]] = frozenset()) -> dict[str, Any]:
|
||||
def _resolved_node_fingerprint(
|
||||
path: Path, seen_directories: frozenset[tuple[int, int]] = frozenset()
|
||||
) -> dict[str, Any]:
|
||||
"""Hash a symlink target, following nested links while stopping directory cycles."""
|
||||
|
||||
try:
|
||||
|
|
@ -141,21 +195,139 @@ def _nested(config: dict[str, Any], *path: str) -> Any:
|
|||
return value
|
||||
|
||||
|
||||
def secret_free_config(value: Any) -> Any:
|
||||
"""Return a semantic config projection with secret-bearing fields omitted."""
|
||||
|
||||
if isinstance(value, dict):
|
||||
return {
|
||||
str(key): secret_free_config(item)
|
||||
for key, item in sorted(value.items(), key=lambda pair: str(pair[0]))
|
||||
if not _is_secret_key(str(key))
|
||||
}
|
||||
if isinstance(value, list):
|
||||
return [secret_free_config(item) for item in value]
|
||||
return value
|
||||
|
||||
|
||||
def _validate_identity_config_value(value: Any, *, path: str) -> None:
|
||||
if value is None or isinstance(value, (bool, int)):
|
||||
return
|
||||
if isinstance(value, str):
|
||||
if not SAFE_CONFIG_SCALAR.fullmatch(value) or "://" in value or "@" in value:
|
||||
raise ValueError(f"unsafe identity config scalar: {path}")
|
||||
return
|
||||
if isinstance(value, list):
|
||||
for index, item in enumerate(value):
|
||||
_validate_identity_config_value(item, path=f"{path}[{index}]")
|
||||
return
|
||||
if isinstance(value, dict):
|
||||
for key, item in value.items():
|
||||
if _is_secret_key(str(key)):
|
||||
raise ValueError(f"secret-bearing identity config key: {path}.{key}")
|
||||
_validate_identity_config_value(item, path=f"{path}.{key}")
|
||||
return
|
||||
raise ValueError(f"unsupported identity config value: {path}")
|
||||
|
||||
|
||||
def identity_config_projection(raw: dict[str, Any]) -> dict[str, Any]:
|
||||
"""Build the only configuration surface copied into a disposable identity profile."""
|
||||
|
||||
section_fields = {
|
||||
"model": ("provider", "default", "smart_routing", "smart_routing_model", "max_tokens"),
|
||||
"agent": ("reasoning_effort",),
|
||||
"memory": ("enabled", "search"),
|
||||
"tools": ("allowed", "write_enabled"),
|
||||
"identity_runtime": ("network_send_enabled", "database_write_enabled", "allowed_tools"),
|
||||
}
|
||||
projection: dict[str, Any] = {}
|
||||
for section, fields in section_fields.items():
|
||||
source = raw.get(section)
|
||||
if source is None:
|
||||
continue
|
||||
if not isinstance(source, dict):
|
||||
raise ValueError(f"identity config section must be a mapping: {section}")
|
||||
selected = {field: source[field] for field in fields if field in source}
|
||||
_validate_identity_config_value(selected, path=section)
|
||||
projection[section] = selected
|
||||
|
||||
gateway = raw.get("gateway")
|
||||
if gateway is not None:
|
||||
if not isinstance(gateway, dict):
|
||||
raise ValueError("identity config section must be a mapping: gateway")
|
||||
selected_gateway = {key: gateway[key] for key in ("execution_mode",) if key in gateway}
|
||||
telegram = gateway.get("telegram")
|
||||
if telegram is not None:
|
||||
if not isinstance(telegram, dict):
|
||||
raise ValueError("identity config section must be a mapping: gateway.telegram")
|
||||
selected_telegram = {key: telegram[key] for key in ("posting_enabled",) if key in telegram}
|
||||
if selected_telegram:
|
||||
selected_gateway["telegram"] = selected_telegram
|
||||
_validate_identity_config_value(selected_gateway, path="gateway")
|
||||
projection["gateway"] = selected_gateway
|
||||
|
||||
if "smart_model_routing" in raw:
|
||||
routing = raw["smart_model_routing"]
|
||||
if not isinstance(routing, bool):
|
||||
raise ValueError("smart_model_routing must be boolean")
|
||||
projection["smart_model_routing"] = routing
|
||||
return projection
|
||||
|
||||
|
||||
def _is_secret_key(key: str) -> bool:
|
||||
snake_case = re.sub(r"(?<=[a-z0-9])(?=[A-Z])", "_", key)
|
||||
normalized = re.sub(r"[^a-z0-9]+", "_", snake_case.casefold()).strip("_")
|
||||
return normalized in SECRET_KEYS or any(normalized.endswith(f"_{suffix}") for suffix in SECRET_KEY_SUFFIXES)
|
||||
|
||||
|
||||
def python_runtime_manifest() -> dict[str, Any]:
|
||||
distributions: dict[str, str | None] = {}
|
||||
for name in RUNTIME_DISTRIBUTIONS:
|
||||
try:
|
||||
distributions[name] = importlib.metadata.version(name)
|
||||
except importlib.metadata.PackageNotFoundError:
|
||||
distributions[name] = None
|
||||
return {
|
||||
"implementation": platform.python_implementation(),
|
||||
"python_version": platform.python_version(),
|
||||
"abi_tag": sys.implementation.cache_tag,
|
||||
"runtime_distributions": distributions,
|
||||
"runtime_distributions_sha256": canonical_sha256(distributions),
|
||||
}
|
||||
|
||||
|
||||
def safe_model_config(config_path: Path) -> dict[str, Any]:
|
||||
try:
|
||||
raw = yaml.safe_load(config_path.read_text(encoding="utf-8")) or {}
|
||||
except (OSError, TypeError, yaml.YAMLError) as exc:
|
||||
return {"status": "unavailable", "error": type(exc).__name__}
|
||||
if not isinstance(raw, dict):
|
||||
return {"status": "unavailable", "error": "ConfigNotMapping"}
|
||||
semantic = secret_free_config(raw)
|
||||
try:
|
||||
identity_config = identity_config_projection(raw)
|
||||
except ValueError:
|
||||
return {"status": "unavailable", "error": "UnsafeIdentityConfig"}
|
||||
model_semantic = identity_config.get("model") or {}
|
||||
return {
|
||||
"status": "observed",
|
||||
"provider": _nested(raw, "model", "provider"),
|
||||
"default_model": _nested(raw, "model", "default"),
|
||||
"smart_routing": _nested(raw, "model", "smart_routing"),
|
||||
"smart_routing_model": _nested(raw, "model", "smart_routing_model"),
|
||||
"max_tokens": _nested(raw, "model", "max_tokens"),
|
||||
"reasoning_effort": _nested(raw, "agent", "reasoning_effort"),
|
||||
"memory_enabled": _nested(raw, "memory", "enabled"),
|
||||
"memory_search": _nested(raw, "memory", "search"),
|
||||
"config_sha256": file_sha256(config_path),
|
||||
"semantic_config_sha256": canonical_sha256(semantic),
|
||||
"identity_config_sha256": canonical_sha256(identity_config),
|
||||
"model_section_sha256": canonical_sha256(model_semantic),
|
||||
"gateway_permissions_sha256": canonical_sha256(identity_config.get("gateway")),
|
||||
"tool_permissions_sha256": canonical_sha256(identity_config.get("tools")),
|
||||
"memory_section_sha256": canonical_sha256(identity_config.get("memory")),
|
||||
"agent_runtime_sha256": canonical_sha256(identity_config.get("agent")),
|
||||
"identity_runtime_policy": identity_config.get("identity_runtime"),
|
||||
"provider": _nested(identity_config, "model", "provider"),
|
||||
"default_model": _nested(identity_config, "model", "default"),
|
||||
"smart_routing": _nested(identity_config, "model", "smart_routing"),
|
||||
"smart_routing_model": _nested(identity_config, "model", "smart_routing_model"),
|
||||
"gateway_smart_model_routing": identity_config.get("smart_model_routing"),
|
||||
"max_tokens": _nested(identity_config, "model", "max_tokens"),
|
||||
"reasoning_effort": _nested(identity_config, "agent", "reasoning_effort"),
|
||||
"memory_enabled": _nested(identity_config, "memory", "enabled"),
|
||||
"memory_search": _nested(identity_config, "memory", "search"),
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -196,7 +368,13 @@ def git_state(repo: Path) -> dict[str, Any]:
|
|||
}
|
||||
|
||||
|
||||
def source_code_manifest(profile: Path, paths: tuple[Path, ...]) -> dict[str, Any]:
|
||||
def source_code_manifest(
|
||||
profile: Path,
|
||||
paths: tuple[Path, ...],
|
||||
*,
|
||||
source_root: Path | None = None,
|
||||
namespace: str = "source",
|
||||
) -> dict[str, Any]:
|
||||
"""Hash executable source while excluding generated caches and environments."""
|
||||
|
||||
allowed_suffixes = {
|
||||
|
|
@ -216,12 +394,21 @@ def source_code_manifest(profile: Path, paths: tuple[Path, ...]) -> dict[str, An
|
|||
excluded_parts = {".git", ".pytest_cache", "__pycache__", "node_modules", "venv", ".venv"}
|
||||
files: list[dict[str, Any]] = []
|
||||
missing: list[str] = []
|
||||
symlinks: list[str] = []
|
||||
source_root = (source_root or profile).resolve()
|
||||
|
||||
def source_label(path: Path) -> str:
|
||||
return f"{namespace}:{_safe_relative(path, source_root)}"
|
||||
|
||||
for requested in paths:
|
||||
if not requested.exists() and not requested.is_symlink():
|
||||
missing.append(_safe_relative(requested, profile))
|
||||
missing.append(source_label(requested))
|
||||
continue
|
||||
candidates = [requested] if requested.is_file() else sorted(requested.rglob("*"))
|
||||
for path in candidates:
|
||||
if path.is_symlink():
|
||||
symlinks.append(source_label(path))
|
||||
continue
|
||||
if not path.is_file() or excluded_parts & set(path.parts):
|
||||
continue
|
||||
stat = path.stat()
|
||||
|
|
@ -229,14 +416,14 @@ def source_code_manifest(profile: Path, paths: tuple[Path, ...]) -> dict[str, An
|
|||
continue
|
||||
files.append(
|
||||
{
|
||||
"path": _safe_relative(path, profile),
|
||||
"path": source_label(path),
|
||||
"bytes": stat.st_size,
|
||||
"mode": oct(stat.st_mode & 0o777),
|
||||
"sha256": file_sha256(path),
|
||||
}
|
||||
)
|
||||
files.sort(key=lambda item: item["path"])
|
||||
stable = {"files": files, "missing": sorted(missing)}
|
||||
stable = {"files": files, "missing": sorted(missing), "symlinks": sorted(symlinks)}
|
||||
return {
|
||||
**stable,
|
||||
"file_count": len(files),
|
||||
|
|
@ -261,6 +448,72 @@ def component(
|
|||
}
|
||||
|
||||
|
||||
def stable_manifest_payload(manifest: dict[str, Any]) -> dict[str, Any]:
|
||||
"""Return the canonical, path-independent behavior payload."""
|
||||
|
||||
return {field: manifest.get(field) for field in STABLE_MANIFEST_FIELDS}
|
||||
|
||||
|
||||
def static_runtime_payload(manifest: dict[str, Any]) -> dict[str, Any]:
|
||||
"""Return the exact payload committed by ``static_runtime_sha256``."""
|
||||
|
||||
components = manifest.get("components") or {}
|
||||
return {
|
||||
"schema": manifest.get("schema"),
|
||||
"model_runtime": manifest.get("model_runtime"),
|
||||
"hermes_runtime": manifest.get("hermes_runtime"),
|
||||
"teleo_infrastructure_runtime": manifest.get("teleo_infrastructure_runtime"),
|
||||
"components": {name: components.get(name) for name in STATIC_RUNTIME_COMPONENTS},
|
||||
"python_runtime": manifest.get("python_runtime"),
|
||||
"canonical_database": manifest.get("canonical_database"),
|
||||
}
|
||||
|
||||
|
||||
def identity_runtime_payload(manifest: dict[str, Any]) -> dict[str, Any]:
|
||||
"""Return the exact payload committed by ``identity_runtime_sha256``."""
|
||||
|
||||
model = manifest.get("model_runtime") or {}
|
||||
components = manifest.get("components") or {}
|
||||
teleo = manifest.get("teleo_infrastructure_runtime") or {}
|
||||
identity_model_runtime = {
|
||||
key: model.get(key)
|
||||
for key in (
|
||||
"status",
|
||||
"identity_config_sha256",
|
||||
"model_section_sha256",
|
||||
"gateway_permissions_sha256",
|
||||
"tool_permissions_sha256",
|
||||
"memory_section_sha256",
|
||||
"agent_runtime_sha256",
|
||||
"identity_runtime_policy",
|
||||
"provider",
|
||||
"default_model",
|
||||
"smart_routing",
|
||||
"smart_routing_model",
|
||||
"gateway_smart_model_routing",
|
||||
"max_tokens",
|
||||
"reasoning_effort",
|
||||
"memory_enabled",
|
||||
"memory_search",
|
||||
"base_model_weights",
|
||||
"actual_per_turn_model_must_be_recorded_by_the_call_receipt",
|
||||
)
|
||||
}
|
||||
return {
|
||||
"schema": manifest.get("schema"),
|
||||
"model_runtime": identity_model_runtime,
|
||||
"hermes_runtime": manifest.get("hermes_runtime"),
|
||||
"teleo_infrastructure_runtime": {
|
||||
"git_head": teleo.get("git_head"),
|
||||
"git_state": teleo.get("git_state"),
|
||||
"source_tree": teleo.get("identity_source_tree"),
|
||||
},
|
||||
"components": {name: components.get(name) for name in IDENTITY_RUNTIME_COMPONENTS},
|
||||
"python_runtime": manifest.get("python_runtime"),
|
||||
"canonical_database": manifest.get("canonical_database"),
|
||||
}
|
||||
|
||||
|
||||
def build_manifest(
|
||||
profile: Path = DEFAULT_PROFILE,
|
||||
hermes_root: Path = DEFAULT_HERMES_ROOT,
|
||||
|
|
@ -270,6 +523,12 @@ def build_manifest(
|
|||
hermes_root = hermes_root.resolve()
|
||||
deployment_root = deployment_root.resolve()
|
||||
config = safe_model_config(profile / "config.yaml")
|
||||
identity_runtime_sources = (
|
||||
deployment_root / "scripts" / "leo_behavior_manifest.py",
|
||||
deployment_root / "scripts" / "leo_identity_manifest.py",
|
||||
deployment_root / "scripts" / "leo_identity_profile.py",
|
||||
deployment_root / "scripts" / "run_leo_identity_reconstruction_canary.py",
|
||||
)
|
||||
components = {
|
||||
"profile_config": component(
|
||||
profile,
|
||||
|
|
@ -294,10 +553,10 @@ def build_manifest(
|
|||
),
|
||||
"runtime_middleware": component(
|
||||
profile,
|
||||
role="Pre-LLM context injection and post-LLM validation or response replacement.",
|
||||
role="Profile plugins for pre-LLM context injection and post-LLM validation or response replacement.",
|
||||
mutability="deployment_static",
|
||||
replayability="fully_hashable",
|
||||
paths=(profile / "plugins", hermes_root / "run_agent.py"),
|
||||
paths=(profile / "plugins",),
|
||||
),
|
||||
"database_tools": component(
|
||||
profile,
|
||||
|
|
@ -353,14 +612,28 @@ def build_manifest(
|
|||
hermes_root / "hermes_cli",
|
||||
hermes_root / "tools",
|
||||
),
|
||||
source_root=hermes_root,
|
||||
namespace="hermes",
|
||||
),
|
||||
},
|
||||
"teleo_infrastructure_runtime": {
|
||||
"git_head": git_head(deployment_root),
|
||||
"git_state": git_state(deployment_root),
|
||||
"source_tree": source_code_manifest(profile, (deployment_root,)),
|
||||
"source_tree": source_code_manifest(
|
||||
profile,
|
||||
(deployment_root,),
|
||||
source_root=deployment_root,
|
||||
namespace="teleo",
|
||||
),
|
||||
"identity_source_tree": source_code_manifest(
|
||||
profile,
|
||||
identity_runtime_sources,
|
||||
source_root=deployment_root,
|
||||
namespace="teleo-identity",
|
||||
),
|
||||
},
|
||||
"components": components,
|
||||
"python_runtime": python_runtime_manifest(),
|
||||
"canonical_database": {
|
||||
"included": False,
|
||||
"reason": "Fingerprint through a read-only Postgres manifest in the database-owning harness.",
|
||||
|
|
@ -372,7 +645,9 @@ def build_manifest(
|
|||
"profile_root": str(profile),
|
||||
"hermes_root": str(hermes_root),
|
||||
"deployment_root": str(deployment_root),
|
||||
"behavior_sha256": canonical_sha256(stable),
|
||||
"static_runtime_sha256": canonical_sha256(static_runtime_payload(stable)),
|
||||
"identity_runtime_sha256": canonical_sha256(identity_runtime_payload(stable)),
|
||||
"behavior_sha256": canonical_sha256(stable_manifest_payload(stable)),
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
878
scripts/leo_identity_manifest.py
Normal file
878
scripts/leo_identity_manifest.py
Normal file
|
|
@ -0,0 +1,878 @@
|
|||
#!/usr/bin/env python3
|
||||
"""Build and verify Leo's pinned, reproducible identity manifest."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import re
|
||||
import sys
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
|
||||
if __package__ in {None, ""}:
|
||||
sys.path.insert(0, str(Path(__file__).resolve().parents[1]))
|
||||
|
||||
from scripts import leo_behavior_manifest as behavior
|
||||
|
||||
SCHEMA = "livingip.leoIdentityManifest.v1"
|
||||
CONSTITUTION_SCHEMA = "livingip.leoConstitutionSource.v1"
|
||||
DATABASE_IDENTITY_SCHEMA = "livingip.leoDatabaseIdentitySource.v1"
|
||||
STRUCTURED_VIEW_SCHEMA = "livingip.leoCompiledIdentityView.v1"
|
||||
DATABASE_FINGERPRINT_SCHEMA = "livingip.teleoCanonicalDatabaseFingerprint.v1"
|
||||
SYNTHETIC_DATABASE_MODE = "synthetic_noncanonical_fixture"
|
||||
CANONICAL_DATABASE_MODE = "canonical_database_same_transaction_export"
|
||||
HEX_64 = re.compile(r"^[0-9a-f]{64}$")
|
||||
HEX_40 = re.compile(r"^[0-9a-f]{40}$")
|
||||
IDENTITY_TABLES = frozenset(
|
||||
{
|
||||
"public.personas",
|
||||
"public.strategies",
|
||||
"public.beliefs",
|
||||
"public.shared_root",
|
||||
"public.strategy_nodes",
|
||||
"public.strategy_node_anchors",
|
||||
"public.claims",
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
def expected_runtime_policy() -> dict[str, Any]:
|
||||
return {
|
||||
"network_send_enabled": False,
|
||||
"database_write_enabled": False,
|
||||
"allowed_tools": ["identity_readback"],
|
||||
}
|
||||
|
||||
|
||||
def expected_session_boundary() -> dict[str, Any]:
|
||||
return {
|
||||
"classification": "temporary_noncanonical",
|
||||
"included_in_identity_inputs": False,
|
||||
"may_be_used_as_evidence": False,
|
||||
"restart_policy": "fresh_process_with_session_state_outside_identity_authority",
|
||||
}
|
||||
|
||||
|
||||
def expected_gatewayrunner_contract() -> dict[str, Any]:
|
||||
return {
|
||||
"profile_surfaces": ["config.yaml", "generated SOUL.md", "skills", "plugins", "bin tools"],
|
||||
"required_absent_or_empty": {
|
||||
"persistent_memory": behavior.canonical_sha256([]),
|
||||
"pairing_store": behavior.canonical_sha256([]),
|
||||
"project_context": behavior.canonical_sha256([]),
|
||||
"generated_skill_prompt_cache": behavior.canonical_sha256([]),
|
||||
"prior_sessions_at_first_start": behavior.canonical_sha256([]),
|
||||
},
|
||||
"fixed_message_context": {
|
||||
"auto_skill": None,
|
||||
"reply_context": None,
|
||||
"media_or_file_context": None,
|
||||
},
|
||||
"required_t3_turn_receipt_fields": [
|
||||
"runner_class",
|
||||
"authorization_decision",
|
||||
"effective_system_prompt_sha256",
|
||||
"compiled_skills_prompt_sha256",
|
||||
"tool_registry_schema_sha256",
|
||||
"plugin_registry_sha256",
|
||||
"selected_model",
|
||||
"selected_provider",
|
||||
"api_mode",
|
||||
"base_url_host",
|
||||
"database_retrieval_receipt",
|
||||
"session_key_sha256",
|
||||
"persisted_session_id_sha256",
|
||||
],
|
||||
}
|
||||
|
||||
|
||||
class IdentityManifestError(ValueError):
|
||||
"""An identity input is incomplete, inconsistent, or drifted."""
|
||||
|
||||
|
||||
def _require(condition: bool, message: str) -> None:
|
||||
if not condition:
|
||||
raise IdentityManifestError(message)
|
||||
|
||||
|
||||
def _is_sha256(value: Any) -> bool:
|
||||
return isinstance(value, str) and bool(HEX_64.fullmatch(value))
|
||||
|
||||
|
||||
def load_json(path: Path, label: str) -> dict[str, Any]:
|
||||
try:
|
||||
value = json.loads(path.read_text(encoding="utf-8"))
|
||||
except (OSError, json.JSONDecodeError) as exc:
|
||||
raise IdentityManifestError(f"cannot read {label}: {type(exc).__name__}") from exc
|
||||
if not isinstance(value, dict):
|
||||
raise IdentityManifestError(f"{label} must be a JSON object")
|
||||
return value
|
||||
|
||||
|
||||
def canonical_rules(value: dict[str, Any]) -> list[dict[str, str]]:
|
||||
_require(value.get("schema") == CONSTITUTION_SCHEMA, "unsupported constitution schema")
|
||||
_require(value.get("identity_name") == "Leo", "constitution identity_name must be Leo")
|
||||
raw_rules = value.get("rules")
|
||||
_require(isinstance(raw_rules, list) and bool(raw_rules), "constitution rules must be non-empty")
|
||||
rules: list[dict[str, str]] = []
|
||||
for raw in raw_rules:
|
||||
_require(isinstance(raw, dict), "each constitutional rule must be an object")
|
||||
rule_id = str(raw.get("id") or "").strip()
|
||||
text = str(raw.get("text") or "").strip()
|
||||
_require(bool(rule_id and text), "each constitutional rule needs id and text")
|
||||
rules.append({"id": rule_id, "text": text})
|
||||
_require(len({item["id"] for item in rules}) == len(rules), "constitutional rule ids must be unique")
|
||||
return sorted(rules, key=lambda item: item["id"])
|
||||
|
||||
|
||||
def canonical_database_records(value: dict[str, Any], *, fingerprint_sha256: str) -> list[dict[str, str | int]]:
|
||||
_require(value.get("schema") == DATABASE_IDENTITY_SCHEMA, "unsupported database identity schema")
|
||||
_require(value.get("identity_name") == "Leo", "database identity_name must be Leo")
|
||||
_require(
|
||||
value.get("database_fingerprint_sha256") == fingerprint_sha256,
|
||||
"database identity export is not bound to the supplied database fingerprint",
|
||||
)
|
||||
raw_records = value.get("records")
|
||||
_require(isinstance(raw_records, list) and bool(raw_records), "database identity records must be non-empty")
|
||||
records: list[dict[str, str | int]] = []
|
||||
for raw in raw_records:
|
||||
_require(isinstance(raw, dict), "each database identity record must be an object")
|
||||
rank = raw.get("rank", 0)
|
||||
record: dict[str, str | int] = {
|
||||
"table": str(raw.get("table") or "").strip(),
|
||||
"row_id": str(raw.get("row_id") or "").strip(),
|
||||
"kind": str(raw.get("kind") or "").strip(),
|
||||
"rank": rank if isinstance(rank, int) and not isinstance(rank, bool) else -1,
|
||||
"text": str(raw.get("text") or "").strip(),
|
||||
"status": str(raw.get("status") or "").strip(),
|
||||
"evidence_sha256": str(raw.get("evidence_sha256") or "").strip(),
|
||||
}
|
||||
_require(record["table"] in IDENTITY_TABLES, "database identity table is outside the allowlist")
|
||||
_require(bool(record["row_id"] and record["kind"] and record["text"]), "database record fields are incomplete")
|
||||
_require(isinstance(record["rank"], int) and record["rank"] >= 0, "database record rank is invalid")
|
||||
_require(record["status"] == "active", "database identity records must be active selected rows")
|
||||
_require(_is_sha256(record["evidence_sha256"]), "database record evidence_sha256 is invalid")
|
||||
records.append(record)
|
||||
keys = {(item["table"], item["row_id"]) for item in records}
|
||||
_require(len(keys) == len(records), "database identity row bindings must be unique")
|
||||
return sorted(records, key=lambda item: (str(item["table"]), int(item["rank"]), str(item["row_id"])))
|
||||
|
||||
|
||||
def database_fingerprint_semantic(value: dict[str, Any]) -> dict[str, Any]:
|
||||
"""Bind immutable capture provenance while excluding only the volatile WAL position."""
|
||||
|
||||
result = {key: value[key] for key in sorted(value) if key != "read_consistency"}
|
||||
consistency = value["read_consistency"]
|
||||
result["read_consistency"] = {
|
||||
"status": consistency["status"],
|
||||
"before": {key: item for key, item in consistency["before"].items() if key != "wal_lsn"},
|
||||
"after": {key: item for key, item in consistency["after"].items() if key != "wal_lsn"},
|
||||
}
|
||||
return result
|
||||
|
||||
|
||||
def database_identity_provenance(
|
||||
value: dict[str, Any],
|
||||
*,
|
||||
fingerprint: dict[str, Any],
|
||||
) -> dict[str, Any]:
|
||||
raw = value.get("source_provenance")
|
||||
_require(isinstance(raw, dict), "database identity source provenance is missing")
|
||||
mode = raw.get("mode")
|
||||
if mode == SYNTHETIC_DATABASE_MODE:
|
||||
_require(
|
||||
raw
|
||||
== {
|
||||
"mode": SYNTHETIC_DATABASE_MODE,
|
||||
"canonical_authority_granted": False,
|
||||
"same_transaction_as_fingerprint": False,
|
||||
"export_receipt_sha256": None,
|
||||
},
|
||||
"synthetic database provenance contract is invalid",
|
||||
)
|
||||
_require(
|
||||
fingerprint.get("environment") == "disposable_fixture",
|
||||
"synthetic rows require a fixture fingerprint",
|
||||
)
|
||||
_require("export_receipt" not in value, "synthetic database identity must not claim an export receipt")
|
||||
return {**raw, "authority": "synthetic_noncanonical_fixture"}
|
||||
|
||||
if mode == CANONICAL_DATABASE_MODE:
|
||||
raise IdentityManifestError(
|
||||
"canonical authority requires independently verified output from the database-owning same-transaction "
|
||||
"exporter; caller-supplied T2 JSON cannot grant it"
|
||||
)
|
||||
raise IdentityManifestError("unsupported database identity provenance mode")
|
||||
|
||||
|
||||
def validate_database_fingerprint(value: dict[str, Any]) -> None:
|
||||
_require(value.get("schema") == DATABASE_FINGERPRINT_SCHEMA, "unsupported database fingerprint schema")
|
||||
_require(value.get("status") == "ok", "database fingerprint status must be ok")
|
||||
for field in ("fingerprint_sha256", "table_rows_sha256", "structure_sha256"):
|
||||
_require(_is_sha256(value.get(field)), f"database fingerprint {field} is invalid")
|
||||
_require(isinstance(value.get("table_count"), int) and value["table_count"] > 0, "table_count must be positive")
|
||||
_require(isinstance(value.get("total_rows"), int) and value["total_rows"] >= 0, "total_rows is invalid")
|
||||
consistency = value.get("read_consistency")
|
||||
_require(isinstance(consistency, dict), "database read_consistency is missing")
|
||||
before = consistency.get("before")
|
||||
after = consistency.get("after")
|
||||
_require(consistency.get("status") == "stable_wal_marker", "database fingerprint was not read consistently")
|
||||
_require(isinstance(before, dict) and before == after and bool(before), "database read markers differ")
|
||||
for field in ("database", "database_user", "system_identifier", "wal_lsn"):
|
||||
_require(bool(before.get(field)), f"database read marker {field} is missing")
|
||||
|
||||
|
||||
def validate_content_manifest(value: Any, *, label: str) -> None:
|
||||
"""Recompute the structural metadata of a replayable content manifest."""
|
||||
|
||||
_require(isinstance(value, dict), f"{label} is invalid")
|
||||
_require(
|
||||
set(value) == {"files", "missing", "symlinks", "file_count", "total_bytes", "sha256"},
|
||||
f"{label} fields are invalid",
|
||||
)
|
||||
files = value.get("files")
|
||||
missing = value.get("missing")
|
||||
symlinks = value.get("symlinks")
|
||||
_require(isinstance(files, list) and bool(files), f"{label} is empty")
|
||||
_require(missing == [], f"{label} has missing inputs")
|
||||
_require(symlinks == [], f"{label} contains unsupported symlinks")
|
||||
|
||||
paths: list[str] = []
|
||||
total_bytes = 0
|
||||
for item in files:
|
||||
_require(isinstance(item, dict), f"{label} contains unreadable inputs")
|
||||
_require(set(item) == {"path", "bytes", "mode", "sha256"}, f"{label} contains unreadable inputs")
|
||||
path = item.get("path")
|
||||
size = item.get("bytes")
|
||||
mode = item.get("mode")
|
||||
_require(isinstance(path, str) and bool(path), f"{label} contains an invalid path")
|
||||
_require(isinstance(size, int) and not isinstance(size, bool) and size >= 0, f"{label} byte size is invalid")
|
||||
_require(isinstance(mode, str) and bool(re.fullmatch(r"0o[0-7]{3}", mode)), f"{label} mode is invalid")
|
||||
_require(_is_sha256(item.get("sha256")), f"{label} contains unreadable inputs")
|
||||
paths.append(path)
|
||||
total_bytes += size
|
||||
|
||||
_require(paths == sorted(paths) and len(paths) == len(set(paths)), f"{label} paths are not unique and sorted")
|
||||
_require(value.get("file_count") == len(files), f"{label} file count is invalid")
|
||||
_require(value.get("total_bytes") == total_bytes, f"{label} total bytes is invalid")
|
||||
stable = {"files": files, "missing": missing, "symlinks": symlinks}
|
||||
_require(behavior.canonical_sha256(stable) == value.get("sha256"), f"{label} content hash is invalid")
|
||||
|
||||
|
||||
def validate_behavior_manifest(value: dict[str, Any]) -> None:
|
||||
_require(value.get("schema") == behavior.SCHEMA, "unsupported behavior manifest schema")
|
||||
for field in ("behavior_sha256", "static_runtime_sha256", "identity_runtime_sha256"):
|
||||
_require(_is_sha256(value.get(field)), f"behavior manifest {field} is invalid")
|
||||
_require(
|
||||
behavior.canonical_sha256(behavior.identity_runtime_payload(value)) == value["identity_runtime_sha256"],
|
||||
"behavior identity runtime hash drift detected",
|
||||
)
|
||||
_require(
|
||||
behavior.canonical_sha256(behavior.static_runtime_payload(value)) == value["static_runtime_sha256"],
|
||||
"behavior static runtime hash drift detected",
|
||||
)
|
||||
_require(
|
||||
behavior.canonical_sha256(behavior.stable_manifest_payload(value)) == value["behavior_sha256"],
|
||||
"behavior manifest stable payload hash drift detected",
|
||||
)
|
||||
model = value.get("model_runtime")
|
||||
_require(isinstance(model, dict) and model.get("status") == "observed", "model runtime was not observed")
|
||||
_require(bool(model.get("provider") and model.get("default_model")), "provider and default model must be pinned")
|
||||
for field in (
|
||||
"semantic_config_sha256",
|
||||
"identity_config_sha256",
|
||||
"model_section_sha256",
|
||||
"gateway_permissions_sha256",
|
||||
"tool_permissions_sha256",
|
||||
"memory_section_sha256",
|
||||
"agent_runtime_sha256",
|
||||
):
|
||||
_require(_is_sha256(model.get(field)), f"model runtime {field} is invalid")
|
||||
_require(
|
||||
model.get("base_model_weights") == "external_provider_managed_not_locally_hashable",
|
||||
"hosted model weight boundary is missing",
|
||||
)
|
||||
_require(
|
||||
model.get("actual_per_turn_model_must_be_recorded_by_the_call_receipt") is True, "model receipt gate missing"
|
||||
)
|
||||
policy = model.get("identity_runtime_policy")
|
||||
_require(policy == expected_runtime_policy(), "identity runtime policy must be the exact local readback policy")
|
||||
for field in ("hermes_runtime", "teleo_infrastructure_runtime"):
|
||||
runtime = value.get(field)
|
||||
_require(isinstance(runtime, dict), f"{field} is missing")
|
||||
_require(bool(HEX_40.fullmatch(str(runtime.get("git_head") or ""))), f"{field} git_head is invalid")
|
||||
git_state = runtime.get("git_state")
|
||||
_require(
|
||||
isinstance(git_state, dict) and git_state.get("worktree_clean") is True,
|
||||
f"{field} is not reconstructible from clean Git",
|
||||
)
|
||||
tree = runtime.get("identity_source_tree" if field == "teleo_infrastructure_runtime" else "source_tree")
|
||||
validate_content_manifest(tree, label=f"{field} source tree")
|
||||
components = value.get("components")
|
||||
_require(isinstance(components, dict), "behavior components are missing")
|
||||
for name in behavior.IDENTITY_RUNTIME_COMPONENTS:
|
||||
content = (components.get(name) or {}).get("content")
|
||||
validate_content_manifest(content, label=f"component {name}")
|
||||
python_runtime = value.get("python_runtime")
|
||||
_require(isinstance(python_runtime, dict), "Python runtime binding is missing")
|
||||
_require(
|
||||
bool(python_runtime.get("implementation") and python_runtime.get("python_version")),
|
||||
"Python runtime is incomplete",
|
||||
)
|
||||
_require(_is_sha256(python_runtime.get("runtime_distributions_sha256")), "runtime package binding is invalid")
|
||||
_require(
|
||||
all(python_runtime.get("runtime_distributions", {}).values()), "a required runtime distribution is missing"
|
||||
)
|
||||
|
||||
|
||||
def _repo_path(path: Path, source_root: Path) -> str:
|
||||
try:
|
||||
return path.resolve(strict=True).relative_to(source_root.resolve(strict=True)).as_posix()
|
||||
except (OSError, ValueError) as exc:
|
||||
raise IdentityManifestError(f"identity source is outside the pinned source root: {path}") from exc
|
||||
|
||||
|
||||
def source_binding(
|
||||
path: Path,
|
||||
*,
|
||||
source_root: Path,
|
||||
semantic_value: Any,
|
||||
count: int,
|
||||
pin_content: bool = True,
|
||||
) -> dict[str, Any]:
|
||||
result = {
|
||||
"repo_path": _repo_path(path, source_root),
|
||||
"semantic_sha256": behavior.canonical_sha256(semantic_value),
|
||||
"record_count": count,
|
||||
}
|
||||
if pin_content:
|
||||
result["content_sha256"] = behavior.file_sha256(path)
|
||||
return result
|
||||
|
||||
|
||||
def render_identity_views(
|
||||
*,
|
||||
identity_inputs_sha256: str,
|
||||
database_fingerprint_sha256: str,
|
||||
database_provenance: dict[str, Any],
|
||||
rules: list[dict[str, str]],
|
||||
records: list[dict[str, str | int]],
|
||||
) -> dict[str, str]:
|
||||
soul = [
|
||||
"<!-- GENERATED FILE: edit the pinned sources, never this view. -->",
|
||||
"# Leo",
|
||||
"",
|
||||
f"Identity inputs: `{identity_inputs_sha256}`",
|
||||
"",
|
||||
"## Static constitutional rules",
|
||||
"",
|
||||
"These rules are static constitutional inputs, not database claims.",
|
||||
"",
|
||||
]
|
||||
soul.extend(f"- **{item['id']}**: {item['text']}" for item in rules)
|
||||
database_description = (
|
||||
"canonical database capture"
|
||||
if database_provenance["canonical_authority_granted"]
|
||||
else "synthetic noncanonical fixture"
|
||||
)
|
||||
soul.extend(
|
||||
[
|
||||
"",
|
||||
"## Database-derived identity",
|
||||
"",
|
||||
f"Generated from {database_description} fingerprint `{database_fingerprint_sha256}`.",
|
||||
"",
|
||||
]
|
||||
)
|
||||
soul.extend(
|
||||
f"- `{item['table']}/{item['row_id']}` [{item['kind']}, rank {item['rank']}]: {item['text']} "
|
||||
f"(evidence `{item['evidence_sha256']}`)"
|
||||
for item in records
|
||||
)
|
||||
soul.extend(
|
||||
[
|
||||
"",
|
||||
"## Authority and session boundary",
|
||||
"",
|
||||
"- This `SOUL.md` is a generated view and is never an authority by itself.",
|
||||
"- Generated database identity is authoritative only when its same-transaction export receipt grants canonical authority.",
|
||||
"- Runtime/session memory is temporary, noncanonical, and cannot serve as evidence.",
|
||||
"- Hosted model weights are provider-managed and must be attributed by each turn receipt.",
|
||||
"",
|
||||
]
|
||||
)
|
||||
structured = {
|
||||
"schema": STRUCTURED_VIEW_SCHEMA,
|
||||
"identity_name": "Leo",
|
||||
"identity_inputs_sha256": identity_inputs_sha256,
|
||||
"static_constitution": {"authority": "pinned_static_source", "rules": rules},
|
||||
"database_identity": {
|
||||
"authority": database_provenance["authority"],
|
||||
"canonical_authority_granted": database_provenance["canonical_authority_granted"],
|
||||
"source_mode": database_provenance["mode"],
|
||||
"database_fingerprint_sha256": database_fingerprint_sha256,
|
||||
"records": records,
|
||||
},
|
||||
"session_boundary": {
|
||||
"authority": "none",
|
||||
"classification": "temporary_noncanonical",
|
||||
"may_be_used_as_evidence": False,
|
||||
},
|
||||
}
|
||||
return {
|
||||
"SOUL.md": "\n".join(soul),
|
||||
"identity.json": json.dumps(structured, indent=2, sort_keys=True) + "\n",
|
||||
}
|
||||
|
||||
|
||||
def build_identity_manifest(
|
||||
*,
|
||||
behavior_manifest: dict[str, Any],
|
||||
database_fingerprint_path: Path,
|
||||
constitution_path: Path,
|
||||
database_identity_path: Path,
|
||||
source_root: Path,
|
||||
source_commit: str | None = None,
|
||||
) -> dict[str, Any]:
|
||||
validate_behavior_manifest(behavior_manifest)
|
||||
database_fingerprint = load_json(database_fingerprint_path, "database fingerprint")
|
||||
validate_database_fingerprint(database_fingerprint)
|
||||
constitution = load_json(constitution_path, "constitution source")
|
||||
database_identity = load_json(database_identity_path, "database identity source")
|
||||
rules = canonical_rules(constitution)
|
||||
records = canonical_database_records(
|
||||
database_identity, fingerprint_sha256=database_fingerprint["fingerprint_sha256"]
|
||||
)
|
||||
database_provenance = database_identity_provenance(
|
||||
database_identity,
|
||||
fingerprint=database_fingerprint,
|
||||
)
|
||||
runtime_commit = behavior_manifest["teleo_infrastructure_runtime"]["git_head"]
|
||||
source_commit = source_commit or runtime_commit
|
||||
_require(bool(HEX_40.fullmatch(str(source_commit))), "source commit is invalid")
|
||||
_require(source_commit == runtime_commit, "source commit does not match the behavior manifest")
|
||||
|
||||
model = behavior_manifest["model_runtime"]
|
||||
components = behavior_manifest["components"]
|
||||
marker = database_fingerprint["read_consistency"]["before"]
|
||||
core = {
|
||||
"identity_name": "Leo",
|
||||
"source_commit": source_commit,
|
||||
"runtime": {
|
||||
"identity_runtime_sha256": behavior_manifest["identity_runtime_sha256"],
|
||||
"hermes_git_head": behavior_manifest["hermes_runtime"]["git_head"],
|
||||
"hermes_source_sha256": behavior_manifest["hermes_runtime"]["source_tree"]["sha256"],
|
||||
"teleo_git_head": runtime_commit,
|
||||
"teleo_source_sha256": behavior_manifest["teleo_infrastructure_runtime"]["identity_source_tree"]["sha256"],
|
||||
"python": behavior_manifest["python_runtime"],
|
||||
},
|
||||
"model": {
|
||||
"provider": model["provider"],
|
||||
"default_model": model["default_model"],
|
||||
"smart_routing": model.get("smart_routing"),
|
||||
"smart_routing_model": model.get("smart_routing_model"),
|
||||
"gateway_smart_model_routing": model.get("gateway_smart_model_routing"),
|
||||
"model_section_sha256": model["model_section_sha256"],
|
||||
"hosted_weights": "external_provider_managed_not_locally_hashable",
|
||||
"actual_model_required_in_turn_receipt": True,
|
||||
},
|
||||
"skills": {
|
||||
"content_sha256": components["procedural_skills"]["content"]["sha256"],
|
||||
"file_count": components["procedural_skills"]["content"]["file_count"],
|
||||
},
|
||||
"permissions": {
|
||||
"identity_config_sha256": model["identity_config_sha256"],
|
||||
"gateway_permissions_sha256": model["gateway_permissions_sha256"],
|
||||
"tool_permissions_sha256": model["tool_permissions_sha256"],
|
||||
"runtime_policy": model["identity_runtime_policy"],
|
||||
"authorization_decision_required_in_runtime_receipt": True,
|
||||
},
|
||||
"canonical_database": {
|
||||
"database": marker["database"],
|
||||
"database_user": marker["database_user"],
|
||||
"system_identifier": marker["system_identifier"],
|
||||
"authority": database_provenance["authority"],
|
||||
"canonical_authority_granted": database_provenance["canonical_authority_granted"],
|
||||
**{
|
||||
key: database_fingerprint[key]
|
||||
for key in ("fingerprint_sha256", "table_rows_sha256", "structure_sha256", "table_count", "total_rows")
|
||||
},
|
||||
"source": source_binding(
|
||||
database_fingerprint_path,
|
||||
source_root=source_root,
|
||||
semantic_value=database_fingerprint_semantic(database_fingerprint),
|
||||
count=database_fingerprint["table_count"],
|
||||
pin_content=False,
|
||||
),
|
||||
},
|
||||
"identity_sources": {
|
||||
"static_constitution": {
|
||||
"authority": "pinned_static_source",
|
||||
**source_binding(constitution_path, source_root=source_root, semantic_value=rules, count=len(rules)),
|
||||
},
|
||||
"database_derived_identity": {
|
||||
"authority": database_provenance["authority"],
|
||||
"provenance": database_provenance,
|
||||
"database_fingerprint_sha256": database_fingerprint["fingerprint_sha256"],
|
||||
**source_binding(
|
||||
database_identity_path,
|
||||
source_root=source_root,
|
||||
semantic_value={"provenance": database_provenance, "records": records},
|
||||
count=len(records),
|
||||
),
|
||||
},
|
||||
},
|
||||
"session_boundary": expected_session_boundary(),
|
||||
"gatewayrunner_execution_contract": expected_gatewayrunner_contract(),
|
||||
}
|
||||
identity_inputs_sha256 = behavior.canonical_sha256(core)
|
||||
views = render_identity_views(
|
||||
identity_inputs_sha256=identity_inputs_sha256,
|
||||
database_fingerprint_sha256=database_fingerprint["fingerprint_sha256"],
|
||||
database_provenance=database_provenance,
|
||||
rules=rules,
|
||||
records=records,
|
||||
)
|
||||
stable = {
|
||||
"schema": SCHEMA,
|
||||
"identity_inputs": core,
|
||||
"identity_inputs_sha256": identity_inputs_sha256,
|
||||
"compiled_views": {
|
||||
name: {
|
||||
"role": "generated_view_not_authority",
|
||||
"sha256": behavior.sha256_bytes(content.encode("utf-8")),
|
||||
"generated_from_identity_inputs_sha256": identity_inputs_sha256,
|
||||
}
|
||||
for name, content in sorted(views.items())
|
||||
},
|
||||
}
|
||||
return {**stable, "manifest_sha256": behavior.canonical_sha256(stable)}
|
||||
|
||||
|
||||
def validate_identity_manifest(value: dict[str, Any]) -> None:
|
||||
_require(value.get("schema") == SCHEMA, "unsupported identity manifest schema")
|
||||
expected = value.get("manifest_sha256")
|
||||
_require(_is_sha256(expected), "identity manifest sha256 is invalid")
|
||||
stable = {key: item for key, item in value.items() if key != "manifest_sha256"}
|
||||
_require(behavior.canonical_sha256(stable) == expected, "identity manifest hash drift detected")
|
||||
core = value.get("identity_inputs")
|
||||
_require(isinstance(core, dict), "identity inputs are missing")
|
||||
_require(
|
||||
set(core)
|
||||
== {
|
||||
"identity_name",
|
||||
"source_commit",
|
||||
"runtime",
|
||||
"model",
|
||||
"skills",
|
||||
"permissions",
|
||||
"canonical_database",
|
||||
"identity_sources",
|
||||
"session_boundary",
|
||||
"gatewayrunner_execution_contract",
|
||||
},
|
||||
"identity input contract fields are invalid",
|
||||
)
|
||||
identity_hash = value.get("identity_inputs_sha256")
|
||||
_require(_is_sha256(identity_hash), "identity input hash is invalid")
|
||||
_require(behavior.canonical_sha256(core) == identity_hash, "identity input hash drift detected")
|
||||
_require(core.get("identity_name") == "Leo", "identity name must be Leo")
|
||||
|
||||
runtime = core.get("runtime")
|
||||
_require(isinstance(runtime, dict), "runtime binding is missing")
|
||||
_require(
|
||||
set(runtime)
|
||||
== {
|
||||
"identity_runtime_sha256",
|
||||
"hermes_git_head",
|
||||
"hermes_source_sha256",
|
||||
"teleo_git_head",
|
||||
"teleo_source_sha256",
|
||||
"python",
|
||||
},
|
||||
"runtime binding fields are invalid",
|
||||
)
|
||||
_require(_is_sha256(runtime.get("identity_runtime_sha256")), "identity runtime binding is invalid")
|
||||
for field in ("hermes_git_head", "teleo_git_head"):
|
||||
_require(bool(HEX_40.fullmatch(str(runtime.get(field) or ""))), f"runtime {field} is invalid")
|
||||
for field in ("hermes_source_sha256", "teleo_source_sha256"):
|
||||
_require(_is_sha256(runtime.get(field)), f"runtime {field} is invalid")
|
||||
_require(core.get("source_commit") == runtime["teleo_git_head"], "source commit is not bound to Teleo Git")
|
||||
python_runtime = runtime.get("python")
|
||||
_require(isinstance(python_runtime, dict), "Python runtime binding is missing")
|
||||
_require(
|
||||
bool(python_runtime.get("implementation") and python_runtime.get("python_version")),
|
||||
"Python runtime binding is incomplete",
|
||||
)
|
||||
_require(_is_sha256(python_runtime.get("runtime_distributions_sha256")), "Python distribution binding is invalid")
|
||||
|
||||
model = core.get("model")
|
||||
_require(isinstance(model, dict), "model binding is missing")
|
||||
_require(
|
||||
set(model)
|
||||
== {
|
||||
"provider",
|
||||
"default_model",
|
||||
"smart_routing",
|
||||
"smart_routing_model",
|
||||
"gateway_smart_model_routing",
|
||||
"model_section_sha256",
|
||||
"hosted_weights",
|
||||
"actual_model_required_in_turn_receipt",
|
||||
},
|
||||
"model binding fields are invalid",
|
||||
)
|
||||
_require(bool(model.get("provider") and model.get("default_model")), "model provider and default must be pinned")
|
||||
_require(_is_sha256(model.get("model_section_sha256")), "model section binding is invalid")
|
||||
_require(
|
||||
model.get("hosted_weights") == "external_provider_managed_not_locally_hashable",
|
||||
"hosted model boundary is invalid",
|
||||
)
|
||||
_require(model.get("actual_model_required_in_turn_receipt") is True, "per-turn model receipt gate is invalid")
|
||||
|
||||
skills = core.get("skills")
|
||||
_require(isinstance(skills, dict) and set(skills) == {"content_sha256", "file_count"}, "skills binding is invalid")
|
||||
_require(_is_sha256(skills.get("content_sha256")), "skills content hash is invalid")
|
||||
_require(
|
||||
isinstance(skills.get("file_count"), int)
|
||||
and not isinstance(skills.get("file_count"), bool)
|
||||
and skills["file_count"] > 0,
|
||||
"skills file count is invalid",
|
||||
)
|
||||
|
||||
permissions = core.get("permissions")
|
||||
_require(isinstance(permissions, dict), "permission binding is missing")
|
||||
_require(
|
||||
set(permissions)
|
||||
== {
|
||||
"identity_config_sha256",
|
||||
"gateway_permissions_sha256",
|
||||
"tool_permissions_sha256",
|
||||
"runtime_policy",
|
||||
"authorization_decision_required_in_runtime_receipt",
|
||||
},
|
||||
"permission binding fields are invalid",
|
||||
)
|
||||
for field in ("identity_config_sha256", "gateway_permissions_sha256", "tool_permissions_sha256"):
|
||||
_require(_is_sha256(permissions.get(field)), f"permission binding {field} is invalid")
|
||||
_require(
|
||||
permissions.get("runtime_policy") == expected_runtime_policy(),
|
||||
"identity runtime policy must be the exact local readback policy",
|
||||
)
|
||||
_require(
|
||||
permissions.get("authorization_decision_required_in_runtime_receipt") is True,
|
||||
"runtime authorization receipt gate is invalid",
|
||||
)
|
||||
|
||||
database = core.get("canonical_database")
|
||||
_require(isinstance(database, dict), "canonical database binding is missing")
|
||||
for field in ("fingerprint_sha256", "table_rows_sha256", "structure_sha256"):
|
||||
_require(_is_sha256(database.get(field)), f"canonical database {field} is invalid")
|
||||
_require(
|
||||
bool(database.get("database") and database.get("database_user") and database.get("system_identifier")),
|
||||
"canonical database identity is incomplete",
|
||||
)
|
||||
allowed_authorities = {"synthetic_noncanonical_fixture": False}
|
||||
_require(database.get("authority") in allowed_authorities, "database authority is invalid")
|
||||
_require(
|
||||
database.get("canonical_authority_granted") is allowed_authorities[database["authority"]],
|
||||
"database canonical authority grant is invalid",
|
||||
)
|
||||
_require(
|
||||
isinstance(database.get("table_count"), int)
|
||||
and not isinstance(database.get("table_count"), bool)
|
||||
and database["table_count"] > 0,
|
||||
"canonical database table_count is invalid",
|
||||
)
|
||||
_require(
|
||||
isinstance(database.get("total_rows"), int)
|
||||
and not isinstance(database.get("total_rows"), bool)
|
||||
and database["total_rows"] >= 0,
|
||||
"canonical database total_rows is invalid",
|
||||
)
|
||||
|
||||
def validate_source_binding(binding: Any, *, label: str, content_required: bool) -> None:
|
||||
_require(isinstance(binding, dict), f"{label} source binding is missing")
|
||||
repo_path = binding.get("repo_path")
|
||||
_require(
|
||||
isinstance(repo_path, str)
|
||||
and bool(repo_path)
|
||||
and not Path(repo_path).is_absolute()
|
||||
and ".." not in Path(repo_path).parts,
|
||||
f"{label} source path is invalid",
|
||||
)
|
||||
_require(_is_sha256(binding.get("semantic_sha256")), f"{label} semantic binding is invalid")
|
||||
_require(
|
||||
isinstance(binding.get("record_count"), int)
|
||||
and not isinstance(binding.get("record_count"), bool)
|
||||
and binding["record_count"] > 0,
|
||||
f"{label} record count is invalid",
|
||||
)
|
||||
if content_required:
|
||||
_require(_is_sha256(binding.get("content_sha256")), f"{label} content binding is invalid")
|
||||
else:
|
||||
_require("content_sha256" not in binding, f"{label} content binding must exclude volatile capture markers")
|
||||
|
||||
validate_source_binding(database.get("source"), label="database fingerprint", content_required=False)
|
||||
sources = core.get("identity_sources")
|
||||
_require(
|
||||
isinstance(sources, dict) and set(sources) == {"static_constitution", "database_derived_identity"},
|
||||
"identity source bindings are invalid",
|
||||
)
|
||||
constitution = sources["static_constitution"]
|
||||
derived = sources["database_derived_identity"]
|
||||
_require(isinstance(constitution, dict), "constitution source binding is invalid")
|
||||
_require(isinstance(derived, dict), "database identity source binding is invalid")
|
||||
_require(constitution.get("authority") == "pinned_static_source", "constitution authority is invalid")
|
||||
_require(derived.get("authority") == database["authority"], "database identity authority is invalid")
|
||||
provenance = derived.get("provenance")
|
||||
_require(isinstance(provenance, dict), "database identity provenance is missing")
|
||||
_require(provenance.get("authority") == database["authority"], "database identity provenance authority is invalid")
|
||||
_require(
|
||||
provenance.get("canonical_authority_granted") is database["canonical_authority_granted"],
|
||||
"database identity provenance grant is invalid",
|
||||
)
|
||||
_require(provenance.get("mode") == SYNTHETIC_DATABASE_MODE, "synthetic database provenance mode is invalid")
|
||||
_require(
|
||||
provenance.get("same_transaction_as_fingerprint") is False,
|
||||
"synthetic fixture transaction claim is invalid",
|
||||
)
|
||||
_require(provenance.get("export_receipt_sha256") is None, "synthetic fixture must not claim an export receipt")
|
||||
_require(
|
||||
derived.get("database_fingerprint_sha256") == database["fingerprint_sha256"],
|
||||
"database identity source is misbound",
|
||||
)
|
||||
validate_source_binding(constitution, label="constitution", content_required=True)
|
||||
validate_source_binding(derived, label="database identity", content_required=True)
|
||||
_require(core.get("session_boundary") == expected_session_boundary(), "session authority boundary is invalid")
|
||||
_require(
|
||||
core.get("gatewayrunner_execution_contract") == expected_gatewayrunner_contract(),
|
||||
"GatewayRunner execution contract is invalid",
|
||||
)
|
||||
|
||||
views = value.get("compiled_views")
|
||||
_require(isinstance(views, dict) and set(views) == {"SOUL.md", "identity.json"}, "compiled views are incomplete")
|
||||
for name, view in views.items():
|
||||
_require(isinstance(view, dict) and _is_sha256(view.get("sha256")), f"compiled view {name} is invalid")
|
||||
_require(
|
||||
set(view) == {"role", "sha256", "generated_from_identity_inputs_sha256"},
|
||||
f"compiled view {name} fields are invalid",
|
||||
)
|
||||
_require(view.get("role") == "generated_view_not_authority", f"compiled view {name} authority is invalid")
|
||||
_require(
|
||||
view.get("generated_from_identity_inputs_sha256") == identity_hash, f"compiled view {name} is misbound"
|
||||
)
|
||||
|
||||
|
||||
def verify_bound_sources(value: dict[str, Any], source_root: Path) -> dict[str, str]:
|
||||
validate_identity_manifest(value)
|
||||
core = value["identity_inputs"]
|
||||
bindings = {
|
||||
"database fingerprint": core["canonical_database"]["source"],
|
||||
"constitution source": core["identity_sources"]["static_constitution"],
|
||||
"database identity source": core["identity_sources"]["database_derived_identity"],
|
||||
}
|
||||
paths = {label: source_root / binding["repo_path"] for label, binding in bindings.items()}
|
||||
for label, binding in bindings.items():
|
||||
path = paths[label]
|
||||
_require(path.is_file(), f"bound {label} is missing")
|
||||
if binding.get("content_sha256"):
|
||||
_require(behavior.file_sha256(path) == binding["content_sha256"], f"bound {label} content drift detected")
|
||||
fingerprint = load_json(paths["database fingerprint"], "database fingerprint")
|
||||
validate_database_fingerprint(fingerprint)
|
||||
_require(
|
||||
behavior.canonical_sha256(database_fingerprint_semantic(fingerprint))
|
||||
== bindings["database fingerprint"]["semantic_sha256"],
|
||||
"database fingerprint semantic drift detected",
|
||||
)
|
||||
marker = fingerprint["read_consistency"]["before"]
|
||||
for field in ("database", "database_user", "system_identifier"):
|
||||
_require(marker[field] == core["canonical_database"][field], f"canonical database {field} drift detected")
|
||||
rules = canonical_rules(load_json(paths["constitution source"], "constitution source"))
|
||||
database_identity = load_json(paths["database identity source"], "database identity source")
|
||||
records = canonical_database_records(
|
||||
database_identity,
|
||||
fingerprint_sha256=fingerprint["fingerprint_sha256"],
|
||||
)
|
||||
database_provenance = database_identity_provenance(
|
||||
database_identity,
|
||||
fingerprint=fingerprint,
|
||||
)
|
||||
_require(
|
||||
behavior.canonical_sha256(rules) == bindings["constitution source"]["semantic_sha256"],
|
||||
"constitution semantic drift detected",
|
||||
)
|
||||
_require(
|
||||
behavior.canonical_sha256({"provenance": database_provenance, "records": records})
|
||||
== bindings["database identity source"]["semantic_sha256"],
|
||||
"database identity semantic drift detected",
|
||||
)
|
||||
_require(
|
||||
database_provenance == core["identity_sources"]["database_derived_identity"]["provenance"],
|
||||
"database identity provenance drift detected",
|
||||
)
|
||||
_require(
|
||||
fingerprint["fingerprint_sha256"] == core["canonical_database"]["fingerprint_sha256"],
|
||||
"canonical database fingerprint drift detected",
|
||||
)
|
||||
views = render_identity_views(
|
||||
identity_inputs_sha256=value["identity_inputs_sha256"],
|
||||
database_fingerprint_sha256=fingerprint["fingerprint_sha256"],
|
||||
database_provenance=database_provenance,
|
||||
rules=rules,
|
||||
records=records,
|
||||
)
|
||||
for name, content in views.items():
|
||||
_require(
|
||||
behavior.sha256_bytes(content.encode("utf-8")) == value["compiled_views"][name]["sha256"],
|
||||
f"compiled view contract drift detected for {name}",
|
||||
)
|
||||
return views
|
||||
|
||||
|
||||
def write_json(path: Path, value: dict[str, Any]) -> None:
|
||||
path.parent.mkdir(parents=True, exist_ok=True)
|
||||
path.write_text(json.dumps(value, indent=2, sort_keys=True) + "\n", encoding="utf-8")
|
||||
|
||||
|
||||
def main() -> int:
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
subparsers = parser.add_subparsers(dest="command", required=True)
|
||||
generate = subparsers.add_parser("generate")
|
||||
generate.add_argument("--behavior-manifest", type=Path, required=True)
|
||||
generate.add_argument("--database-fingerprint", type=Path, required=True)
|
||||
generate.add_argument("--constitution", type=Path, required=True)
|
||||
generate.add_argument("--database-identity", type=Path, required=True)
|
||||
generate.add_argument("--source-root", type=Path, required=True)
|
||||
generate.add_argument("--source-commit")
|
||||
generate.add_argument("--output", type=Path, required=True)
|
||||
verify = subparsers.add_parser("verify")
|
||||
verify.add_argument("--manifest", type=Path, required=True)
|
||||
verify.add_argument("--source-root", type=Path)
|
||||
args = parser.parse_args()
|
||||
try:
|
||||
if args.command == "generate":
|
||||
manifest = build_identity_manifest(
|
||||
behavior_manifest=load_json(args.behavior_manifest, "behavior manifest"),
|
||||
database_fingerprint_path=args.database_fingerprint,
|
||||
constitution_path=args.constitution,
|
||||
database_identity_path=args.database_identity,
|
||||
source_root=args.source_root,
|
||||
source_commit=args.source_commit,
|
||||
)
|
||||
write_json(args.output, manifest)
|
||||
else:
|
||||
manifest = load_json(args.manifest, "identity manifest")
|
||||
validate_identity_manifest(manifest)
|
||||
if args.source_root:
|
||||
verify_bound_sources(manifest, args.source_root)
|
||||
print(json.dumps({"status": "ok", "manifest_sha256": manifest["manifest_sha256"]}))
|
||||
return 0
|
||||
except IdentityManifestError as exc:
|
||||
print(json.dumps({"status": "error", "error": "identity_manifest_invalid", "message": str(exc)}))
|
||||
return 2
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
495
scripts/leo_identity_profile.py
Normal file
495
scripts/leo_identity_profile.py
Normal file
|
|
@ -0,0 +1,495 @@
|
|||
#!/usr/bin/env python3
|
||||
"""Compile, verify, and query a disposable Leo identity profile."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import os
|
||||
import shutil
|
||||
import sys
|
||||
import uuid
|
||||
from datetime import UTC, datetime
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
|
||||
import yaml
|
||||
|
||||
if __package__ in {None, ""}:
|
||||
sys.path.insert(0, str(Path(__file__).resolve().parents[1]))
|
||||
|
||||
from scripts import leo_behavior_manifest as behavior
|
||||
from scripts import leo_identity_manifest as identity
|
||||
|
||||
LOCK_SCHEMA = "livingip.leoIdentityProfileLock.v1"
|
||||
COMPILE_RECEIPT_SCHEMA = "livingip.leoIdentityCompileReceipt.v1"
|
||||
QUERY_RECEIPT_SCHEMA = "livingip.leoIdentityQueryReceipt.v1"
|
||||
SESSION_RECORD_SCHEMA = "livingip.leoTemporarySessionRecord.v1"
|
||||
FIXED_QUERY = "What defines Leo's identity, and what is temporary?"
|
||||
STATIC_PROFILE_ENTRIES = ("config.yaml", "skills", "plugins", "bin")
|
||||
COMPILED_PROFILE_ENTRIES = frozenset(
|
||||
{
|
||||
"config.yaml",
|
||||
"skills",
|
||||
"plugins",
|
||||
"bin",
|
||||
"SOUL.md",
|
||||
"identity.json",
|
||||
"identity-manifest.json",
|
||||
"identity-lock.json",
|
||||
"compile-receipt.json",
|
||||
"sessions",
|
||||
"state",
|
||||
}
|
||||
)
|
||||
OMITTED_NONAUTHORITATIVE_ENTRIES = (
|
||||
"memories",
|
||||
"MEMORY.md",
|
||||
"USER.md",
|
||||
"platforms/pairing",
|
||||
".skills_prompt_snapshot.json",
|
||||
".hermes.md",
|
||||
"HERMES.md",
|
||||
"AGENTS.md",
|
||||
"CLAUDE.md",
|
||||
".cursorrules",
|
||||
)
|
||||
|
||||
|
||||
class IdentityProfileError(identity.IdentityManifestError):
|
||||
"""A compiled profile cannot be trusted or started."""
|
||||
|
||||
|
||||
def _require(condition: bool, message: str) -> None:
|
||||
if not condition:
|
||||
raise IdentityProfileError(message)
|
||||
|
||||
|
||||
def _copy_static_profile(template: Path, target: Path) -> list[str]:
|
||||
_require(template.is_dir(), "profile template is missing")
|
||||
_require(not target.exists(), "compiled profile target already exists")
|
||||
target.mkdir(parents=True, mode=0o700)
|
||||
copied: list[str] = []
|
||||
for name in STATIC_PROFILE_ENTRIES:
|
||||
source = template / name
|
||||
if not source.exists():
|
||||
continue
|
||||
destination = target / name
|
||||
_require(not source.is_symlink(), f"unsafe symlinked static profile entry: {name}")
|
||||
if source.is_dir():
|
||||
_require(
|
||||
not any(path.is_symlink() for path in source.rglob("*")),
|
||||
f"unsafe symlink inside static profile entry: {name}",
|
||||
)
|
||||
shutil.copytree(source, destination, symlinks=False)
|
||||
elif source.is_file() and not source.is_symlink():
|
||||
if name == "config.yaml":
|
||||
try:
|
||||
raw_config = yaml.safe_load(source.read_text(encoding="utf-8")) or {}
|
||||
except (OSError, TypeError, yaml.YAMLError) as exc:
|
||||
raise IdentityProfileError(f"cannot sanitize profile config: {type(exc).__name__}") from exc
|
||||
_require(isinstance(raw_config, dict), "profile config must be a mapping")
|
||||
destination.write_text(
|
||||
yaml.safe_dump(behavior.identity_config_projection(raw_config), sort_keys=False),
|
||||
encoding="utf-8",
|
||||
)
|
||||
destination.chmod(0o600)
|
||||
else:
|
||||
shutil.copy2(source, destination)
|
||||
else:
|
||||
raise IdentityProfileError(f"unsafe static profile entry: {name}")
|
||||
copied.append(name)
|
||||
_require("config.yaml" in copied, "profile template config.yaml is missing")
|
||||
return copied
|
||||
|
||||
|
||||
def _behavior(profile: Path, hermes_root: Path, deployment_root: Path) -> dict[str, Any]:
|
||||
return behavior.build_manifest(profile, hermes_root, deployment_root)
|
||||
|
||||
|
||||
def _verify_runtime_binding(
|
||||
manifest: dict[str, Any],
|
||||
*,
|
||||
profile: Path,
|
||||
hermes_root: Path,
|
||||
deployment_root: Path,
|
||||
) -> dict[str, Any]:
|
||||
observed = _behavior(profile, hermes_root, deployment_root)
|
||||
identity.validate_behavior_manifest(observed)
|
||||
expected = manifest["identity_inputs"]["runtime"]
|
||||
_require(
|
||||
observed["identity_runtime_sha256"] == expected["identity_runtime_sha256"], "identity runtime drift detected"
|
||||
)
|
||||
_require(observed["hermes_runtime"]["git_head"] == expected["hermes_git_head"], "Hermes Git drift detected")
|
||||
_require(
|
||||
observed["hermes_runtime"]["source_tree"]["sha256"] == expected["hermes_source_sha256"],
|
||||
"Hermes source drift detected",
|
||||
)
|
||||
_require(
|
||||
observed["teleo_infrastructure_runtime"]["git_head"] == expected["teleo_git_head"],
|
||||
"Teleo Git drift detected",
|
||||
)
|
||||
_require(
|
||||
observed["teleo_infrastructure_runtime"]["identity_source_tree"]["sha256"] == expected["teleo_source_sha256"],
|
||||
"Teleo identity source drift detected",
|
||||
)
|
||||
_require(observed["python_runtime"] == expected["python"], "Python runtime drift detected")
|
||||
_require(
|
||||
manifest["identity_inputs"]["source_commit"] == observed["teleo_infrastructure_runtime"]["git_head"],
|
||||
"source commit drift detected",
|
||||
)
|
||||
|
||||
expected_model = manifest["identity_inputs"]["model"]
|
||||
observed_model = observed["model_runtime"]
|
||||
model_bindings = {
|
||||
"provider": observed_model.get("provider"),
|
||||
"default_model": observed_model.get("default_model"),
|
||||
"smart_routing": observed_model.get("smart_routing"),
|
||||
"smart_routing_model": observed_model.get("smart_routing_model"),
|
||||
"gateway_smart_model_routing": observed_model.get("gateway_smart_model_routing"),
|
||||
"model_section_sha256": observed_model.get("model_section_sha256"),
|
||||
"hosted_weights": observed_model.get("base_model_weights"),
|
||||
"actual_model_required_in_turn_receipt": observed_model.get(
|
||||
"actual_per_turn_model_must_be_recorded_by_the_call_receipt"
|
||||
),
|
||||
}
|
||||
for field, observed_value in model_bindings.items():
|
||||
_require(expected_model.get(field) == observed_value, f"model runtime binding drift detected: {field}")
|
||||
|
||||
expected_permissions = manifest["identity_inputs"]["permissions"]
|
||||
permission_bindings = {
|
||||
"identity_config_sha256": observed_model.get("identity_config_sha256"),
|
||||
"gateway_permissions_sha256": observed_model.get("gateway_permissions_sha256"),
|
||||
"tool_permissions_sha256": observed_model.get("tool_permissions_sha256"),
|
||||
"runtime_policy": observed_model.get("identity_runtime_policy"),
|
||||
"authorization_decision_required_in_runtime_receipt": True,
|
||||
}
|
||||
for field, observed_value in permission_bindings.items():
|
||||
_require(
|
||||
expected_permissions.get(field) == observed_value, f"permission runtime binding drift detected: {field}"
|
||||
)
|
||||
|
||||
observed_skills = observed["components"]["procedural_skills"]["content"]
|
||||
expected_skills = manifest["identity_inputs"]["skills"]
|
||||
_require(expected_skills["content_sha256"] == observed_skills["sha256"], "skills runtime binding drift detected")
|
||||
_require(expected_skills["file_count"] == observed_skills["file_count"], "skills file count drift detected")
|
||||
return observed
|
||||
|
||||
|
||||
def _view_file_sha256(profile: Path, name: str) -> str:
|
||||
path = profile / name
|
||||
_require(path.is_file() and not path.is_symlink(), f"compiled view is missing or unsafe: {name}")
|
||||
return behavior.file_sha256(path)
|
||||
|
||||
|
||||
def _verify_nonauthoritative_surfaces(
|
||||
profile: Path,
|
||||
*,
|
||||
require_empty_sessions: bool,
|
||||
require_compile_receipt: bool,
|
||||
) -> dict[str, Any]:
|
||||
omitted = {
|
||||
name: not (profile / name).exists() and not (profile / name).is_symlink()
|
||||
for name in OMITTED_NONAUTHORITATIVE_ENTRIES
|
||||
}
|
||||
_require(all(omitted.values()), "profile contains a forbidden nonauthoritative input surface")
|
||||
expected_entries = set(COMPILED_PROFILE_ENTRIES)
|
||||
if not require_compile_receipt:
|
||||
expected_entries.remove("compile-receipt.json")
|
||||
profile_entries = list(profile.iterdir())
|
||||
actual_entries = {path.name for path in profile_entries}
|
||||
_require(actual_entries == expected_entries, "compiled profile entry set is not exact")
|
||||
_require(not any(path.is_symlink() for path in profile_entries), "compiled profile entries must not be symlinks")
|
||||
if require_compile_receipt:
|
||||
compile_receipt = identity.load_json(profile / "compile-receipt.json", "identity compile receipt")
|
||||
_require(compile_receipt.get("schema") == COMPILE_RECEIPT_SCHEMA, "identity compile receipt schema is invalid")
|
||||
_require(compile_receipt.get("status") == "pass", "identity compile receipt status is invalid")
|
||||
state = profile / "state"
|
||||
sessions = profile / "sessions"
|
||||
for path, label in ((state, "state"), (sessions, "sessions")):
|
||||
_require(path.is_dir() and not path.is_symlink(), f"profile {label} directory is missing or unsafe")
|
||||
_require(not any(state.iterdir()), "profile state directory must remain empty")
|
||||
session_files = list(sessions.iterdir())
|
||||
if require_empty_sessions:
|
||||
_require(not session_files, "profile sessions must start empty")
|
||||
for path in session_files:
|
||||
_require(path.is_file() and not path.is_symlink() and path.suffix == ".json", "unsafe session entry detected")
|
||||
record = identity.load_json(path, "temporary session record")
|
||||
_require(
|
||||
set(record)
|
||||
== {
|
||||
"schema",
|
||||
"authority",
|
||||
"classification",
|
||||
"query_sha256",
|
||||
"answer_sha256",
|
||||
"may_be_used_as_evidence",
|
||||
},
|
||||
"temporary session record fields are invalid",
|
||||
)
|
||||
_require(record.get("schema") == SESSION_RECORD_SCHEMA, "temporary session record schema is invalid")
|
||||
_require(record.get("authority") == "none", "temporary session authority is invalid")
|
||||
_require(record.get("classification") == "temporary_noncanonical", "temporary session class is invalid")
|
||||
_require(record.get("may_be_used_as_evidence") is False, "temporary session cannot be evidence")
|
||||
_require(identity._is_sha256(record.get("query_sha256")), "temporary session query hash is invalid")
|
||||
_require(identity._is_sha256(record.get("answer_sha256")), "temporary session answer hash is invalid")
|
||||
return {
|
||||
"nonauthoritative_inputs_omitted": omitted,
|
||||
"session_file_count": len(session_files),
|
||||
"state_empty": True,
|
||||
}
|
||||
|
||||
|
||||
def compile_profile(
|
||||
manifest: dict[str, Any],
|
||||
*,
|
||||
source_root: Path,
|
||||
profile_template: Path,
|
||||
profile: Path,
|
||||
hermes_root: Path,
|
||||
deployment_root: Path,
|
||||
) -> dict[str, Any]:
|
||||
views = identity.verify_bound_sources(manifest, source_root)
|
||||
template_behavior = _behavior(profile_template, hermes_root, deployment_root)
|
||||
identity.validate_behavior_manifest(template_behavior)
|
||||
_require(
|
||||
template_behavior["identity_runtime_sha256"]
|
||||
== manifest["identity_inputs"]["runtime"]["identity_runtime_sha256"],
|
||||
"profile template does not match the pinned identity runtime",
|
||||
)
|
||||
copied = _copy_static_profile(profile_template, profile)
|
||||
try:
|
||||
for name, content in views.items():
|
||||
path = profile / name
|
||||
path.write_text(content, encoding="utf-8")
|
||||
path.chmod(0o600)
|
||||
identity.write_json(profile / "identity-manifest.json", manifest)
|
||||
(profile / "identity-manifest.json").chmod(0o600)
|
||||
for directory in (profile / "sessions", profile / "state"):
|
||||
directory.mkdir(mode=0o700)
|
||||
lock = {
|
||||
"schema": LOCK_SCHEMA,
|
||||
"manifest_sha256": manifest["manifest_sha256"],
|
||||
"identity_inputs_sha256": manifest["identity_inputs_sha256"],
|
||||
"compiled_views": {name: {"sha256": _view_file_sha256(profile, name)} for name in sorted(views)},
|
||||
"session_boundary": manifest["identity_inputs"]["session_boundary"],
|
||||
}
|
||||
identity.write_json(profile / "identity-lock.json", lock)
|
||||
(profile / "identity-lock.json").chmod(0o600)
|
||||
observed = _verify_runtime_binding(
|
||||
manifest,
|
||||
profile=profile,
|
||||
hermes_root=hermes_root,
|
||||
deployment_root=deployment_root,
|
||||
)
|
||||
for name, expected in manifest["compiled_views"].items():
|
||||
_require(_view_file_sha256(profile, name) == expected["sha256"], f"compiled {name} hash mismatch")
|
||||
soul_files = observed["components"]["runtime_identity"]["content"]["files"]
|
||||
soul = next((item for item in soul_files if item.get("path") == "SOUL.md"), None)
|
||||
_require(
|
||||
isinstance(soul, dict) and soul.get("sha256") == manifest["compiled_views"]["SOUL.md"]["sha256"],
|
||||
"SOUL runtime binding failed",
|
||||
)
|
||||
surface_readback = _verify_nonauthoritative_surfaces(
|
||||
profile,
|
||||
require_empty_sessions=True,
|
||||
require_compile_receipt=False,
|
||||
)
|
||||
receipt = {
|
||||
"schema": COMPILE_RECEIPT_SCHEMA,
|
||||
"status": "pass",
|
||||
"manifest_sha256": manifest["manifest_sha256"],
|
||||
"identity_inputs_sha256": manifest["identity_inputs_sha256"],
|
||||
"profile_static_entries": copied,
|
||||
"compiled_view_sha256": {
|
||||
name: manifest["compiled_views"][name]["sha256"] for name in sorted(manifest["compiled_views"])
|
||||
},
|
||||
"runtime_identity_sha256": observed["identity_runtime_sha256"],
|
||||
"session_directories_started_empty": all(
|
||||
not any((profile / name).iterdir()) for name in ("sessions", "state")
|
||||
),
|
||||
"nonauthoritative_inputs_omitted": surface_readback["nonauthoritative_inputs_omitted"],
|
||||
"generated_views_are_authority": False,
|
||||
}
|
||||
identity.write_json(profile / "compile-receipt.json", receipt)
|
||||
return receipt
|
||||
except BaseException:
|
||||
shutil.rmtree(profile, ignore_errors=True)
|
||||
raise
|
||||
|
||||
|
||||
def verify_profile(
|
||||
profile: Path,
|
||||
*,
|
||||
source_root: Path,
|
||||
hermes_root: Path,
|
||||
deployment_root: Path,
|
||||
) -> tuple[dict[str, Any], dict[str, str], dict[str, Any]]:
|
||||
manifest = identity.load_json(profile / "identity-manifest.json", "compiled identity manifest")
|
||||
views = identity.verify_bound_sources(manifest, source_root)
|
||||
lock = identity.load_json(profile / "identity-lock.json", "identity profile lock")
|
||||
_verify_nonauthoritative_surfaces(
|
||||
profile,
|
||||
require_empty_sessions=False,
|
||||
require_compile_receipt=True,
|
||||
)
|
||||
_require(lock.get("schema") == LOCK_SCHEMA, "identity profile lock schema is invalid")
|
||||
_require(
|
||||
lock.get("manifest_sha256") == manifest["manifest_sha256"], "identity profile lock manifest drift detected"
|
||||
)
|
||||
_require(
|
||||
lock.get("identity_inputs_sha256") == manifest["identity_inputs_sha256"],
|
||||
"identity profile lock input drift detected",
|
||||
)
|
||||
compile_receipt = identity.load_json(profile / "compile-receipt.json", "identity compile receipt")
|
||||
_require(
|
||||
compile_receipt.get("manifest_sha256") == manifest["manifest_sha256"],
|
||||
"identity compile receipt manifest drift detected",
|
||||
)
|
||||
_require(
|
||||
compile_receipt.get("identity_inputs_sha256") == manifest["identity_inputs_sha256"],
|
||||
"identity compile receipt input drift detected",
|
||||
)
|
||||
for name, expected_content in views.items():
|
||||
expected_hash = behavior.sha256_bytes(expected_content.encode("utf-8"))
|
||||
_require(expected_hash == manifest["compiled_views"][name]["sha256"], f"manifest view drift detected: {name}")
|
||||
_require(_view_file_sha256(profile, name) == expected_hash, f"compiled view drift detected: {name}")
|
||||
_require(
|
||||
(lock.get("compiled_views") or {}).get(name, {}).get("sha256") == expected_hash,
|
||||
f"profile lock view drift detected: {name}",
|
||||
)
|
||||
observed = _verify_runtime_binding(
|
||||
manifest,
|
||||
profile=profile,
|
||||
hermes_root=hermes_root,
|
||||
deployment_root=deployment_root,
|
||||
)
|
||||
return manifest, views, observed
|
||||
|
||||
|
||||
def query_profile(
|
||||
profile: Path,
|
||||
*,
|
||||
query: str,
|
||||
source_root: Path,
|
||||
hermes_root: Path,
|
||||
deployment_root: Path,
|
||||
) -> dict[str, Any]:
|
||||
_require(query == FIXED_QUERY, "only the pinned identity readback query is allowed")
|
||||
manifest, _views, observed = verify_profile(
|
||||
profile,
|
||||
source_root=source_root,
|
||||
hermes_root=hermes_root,
|
||||
deployment_root=deployment_root,
|
||||
)
|
||||
structured = identity.load_json(profile / "identity.json", "compiled structured identity view")
|
||||
rule_count = len(structured["static_constitution"]["rules"])
|
||||
record_count = len(structured["database_identity"]["records"])
|
||||
fingerprint = structured["database_identity"]["database_fingerprint_sha256"]
|
||||
canonical_authority = structured["database_identity"]["canonical_authority_granted"]
|
||||
database_description = "canonical database" if canonical_authority else "synthetic noncanonical fixture"
|
||||
answer = (
|
||||
f"Leo is defined by {rule_count} pinned static constitutional rules and {record_count} active "
|
||||
f"database-derived identity rows from a {database_description} at fingerprint {fingerprint}. "
|
||||
"SOUL.md is a generated view; "
|
||||
"runtime/session memory is temporary, noncanonical, and cannot be evidence."
|
||||
)
|
||||
query_sha256 = behavior.sha256_bytes(query.encode("utf-8"))
|
||||
answer_sha256 = behavior.sha256_bytes(answer.encode("utf-8"))
|
||||
instance_id = uuid.uuid4().hex
|
||||
session_record = {
|
||||
"schema": SESSION_RECORD_SCHEMA,
|
||||
"authority": "none",
|
||||
"classification": "temporary_noncanonical",
|
||||
"query_sha256": query_sha256,
|
||||
"answer_sha256": answer_sha256,
|
||||
"may_be_used_as_evidence": False,
|
||||
}
|
||||
session_path = profile / "sessions" / f"{instance_id}.json"
|
||||
identity.write_json(session_path, session_record)
|
||||
receipt = {
|
||||
"schema": QUERY_RECEIPT_SCHEMA,
|
||||
"status": "pass",
|
||||
"started_at_utc": datetime.now(UTC).isoformat(),
|
||||
"process_id": os.getpid(),
|
||||
"runtime_instance_id": instance_id,
|
||||
"query": query,
|
||||
"query_sha256": query_sha256,
|
||||
"answer": answer,
|
||||
"answer_sha256": answer_sha256,
|
||||
"manifest_sha256": manifest["manifest_sha256"],
|
||||
"identity_inputs_sha256": manifest["identity_inputs_sha256"],
|
||||
"output_provenance": {
|
||||
"static_constitution_sha256": manifest["identity_inputs"]["identity_sources"]["static_constitution"][
|
||||
"semantic_sha256"
|
||||
],
|
||||
"database_identity_sha256": manifest["identity_inputs"]["identity_sources"]["database_derived_identity"][
|
||||
"semantic_sha256"
|
||||
],
|
||||
"database_fingerprint_sha256": fingerprint,
|
||||
"database_authority": structured["database_identity"]["authority"],
|
||||
"database_canonical_authority_granted": canonical_authority,
|
||||
"compiled_identity_sha256": manifest["compiled_views"]["identity.json"]["sha256"],
|
||||
"compiled_soul_sha256": manifest["compiled_views"]["SOUL.md"]["sha256"],
|
||||
"runtime_identity_sha256": observed["identity_runtime_sha256"],
|
||||
"actual_model_call_performed": False,
|
||||
},
|
||||
"authorization": {
|
||||
"declared_runtime_policy": manifest["identity_inputs"]["permissions"]["runtime_policy"],
|
||||
"authorization_decision_observed": False,
|
||||
"claim": "local_policy_binding_not_an_authorizer_readback",
|
||||
},
|
||||
"session": {
|
||||
"record_sha256": behavior.file_sha256(session_path),
|
||||
"classification": "temporary_noncanonical",
|
||||
"included_in_output_provenance": False,
|
||||
"may_be_used_as_evidence": False,
|
||||
},
|
||||
}
|
||||
return receipt
|
||||
|
||||
|
||||
def main() -> int:
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
subparsers = parser.add_subparsers(dest="command", required=True)
|
||||
compile_command = subparsers.add_parser("compile")
|
||||
compile_command.add_argument("--manifest", type=Path, required=True)
|
||||
compile_command.add_argument("--source-root", type=Path, required=True)
|
||||
compile_command.add_argument("--profile-template", type=Path, required=True)
|
||||
compile_command.add_argument("--profile", type=Path, required=True)
|
||||
compile_command.add_argument("--hermes-root", type=Path, required=True)
|
||||
compile_command.add_argument("--deployment-root", type=Path, required=True)
|
||||
query_command = subparsers.add_parser("query")
|
||||
query_command.add_argument("--profile", type=Path, required=True)
|
||||
query_command.add_argument("--query", default=FIXED_QUERY)
|
||||
query_command.add_argument("--source-root", type=Path, required=True)
|
||||
query_command.add_argument("--hermes-root", type=Path, required=True)
|
||||
query_command.add_argument("--deployment-root", type=Path, required=True)
|
||||
args = parser.parse_args()
|
||||
try:
|
||||
if args.command == "compile":
|
||||
result = compile_profile(
|
||||
identity.load_json(args.manifest, "identity manifest"),
|
||||
source_root=args.source_root,
|
||||
profile_template=args.profile_template,
|
||||
profile=args.profile,
|
||||
hermes_root=args.hermes_root,
|
||||
deployment_root=args.deployment_root,
|
||||
)
|
||||
else:
|
||||
result = query_profile(
|
||||
args.profile,
|
||||
query=args.query,
|
||||
source_root=args.source_root,
|
||||
hermes_root=args.hermes_root,
|
||||
deployment_root=args.deployment_root,
|
||||
)
|
||||
print(json.dumps(result, sort_keys=True))
|
||||
return 0
|
||||
except identity.IdentityManifestError as exc:
|
||||
print(json.dumps({"status": "error", "error": "identity_drift", "message": str(exc)}))
|
||||
return 3
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
1821
scripts/proposal_apply_lifecycle.py
Normal file
1821
scripts/proposal_apply_lifecycle.py
Normal file
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
|
@ -9,6 +9,8 @@ image="${POSTGRES_CANARY_IMAGE:-postgres:16}"
|
|||
source_tier="${SOURCE_TIER:-live-readonly}"
|
||||
normalization_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
|
||||
case "$1" in
|
||||
|
|
@ -20,6 +22,14 @@ while [[ $# -gt 0 ]]; do
|
|||
output="$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="$2"
|
||||
shift 2
|
||||
|
|
@ -99,11 +109,19 @@ service_state() {
|
|||
}
|
||||
|
||||
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)"
|
||||
service_before="$(service_state)"
|
||||
|
||||
docker run -d --name "$container" \
|
||||
--network none \
|
||||
--label livingip.canary=proposal-apply-lifecycle \
|
||||
--label "livingip.canary.instance=${container}" \
|
||||
--tmpfs /var/lib/postgresql/data:rw,nosuid,size=512m \
|
||||
-e POSTGRES_PASSWORD="isolated-postgres-${RANDOM}-${RANDOM}" \
|
||||
-e POSTGRES_DB=teleo \
|
||||
|
|
@ -127,6 +145,12 @@ if [[ "$ready_streak" -lt 2 ]]; then
|
|||
fi
|
||||
container_network_mode="$(docker inspect -f '{{.HostConfig.NetworkMode}}' "$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" \
|
||||
--schema-only --no-owner --no-privileges >"$workdir/schema.sql"
|
||||
|
|
@ -165,6 +189,13 @@ normalization_args=()
|
|||
if [[ -n "$normalization_json" ]]; then
|
||||
normalization_args=(--normalization-json "$normalization_json")
|
||||
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
|
||||
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" \
|
||||
--secrets-file "$workdir/kb-apply.env" \
|
||||
"${normalization_args[@]}" \
|
||||
"${artifact_args[@]}" \
|
||||
--output "$output" \
|
||||
>"$workdir/stdout.json" 2>"$workdir/stderr.log"
|
||||
canary_rc=$?
|
||||
|
|
@ -192,6 +224,20 @@ container_name_readback="$(
|
|||
docker container ls -a --filter "name=^/${container}$" --format '{{.Names}}' 2>&1
|
||||
)"
|
||||
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
|
||||
outer_workdir_lexists=true
|
||||
else
|
||||
|
|
@ -214,6 +260,9 @@ OUTER_CONTAINER_REMOVE_RC="$outer_container_remove_rc" \
|
|||
OUTER_WORKDIR_REMOVE_RC="$outer_workdir_remove_rc" \
|
||||
CONTAINER_NAME_READBACK="$container_name_readback" \
|
||||
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" \
|
||||
CANARY_RC="$canary_rc" \
|
||||
SOURCE_TIER="$source_tier" \
|
||||
|
|
@ -221,219 +270,6 @@ SOURCE_NETWORK_MODE="$source_network_mode" \
|
|||
SOURCE_CANARY_LABEL="$source_canary_label" \
|
||||
CANARY_NETWORK_MODE="$container_network_mode" \
|
||||
CANARY_MOUNTS_JSON="$container_mounts_json" \
|
||||
python3 - "$output" <<'PY'
|
||||
import hashlib
|
||||
import json
|
||||
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
|
||||
CANARY_LABEL="$container_canary_label" \
|
||||
CANARY_INSTANCE_LABEL="$container_instance_label" \
|
||||
python3 "$repo_root/scripts/finalize_approve_claim_isolated_canary.py" "$output"
|
||||
|
|
|
|||
517
scripts/run_leo_identity_reconstruction_canary.py
Normal file
517
scripts/run_leo_identity_reconstruction_canary.py
Normal file
|
|
@ -0,0 +1,517 @@
|
|||
#!/usr/bin/env python3
|
||||
"""Prove manifest-driven Leo identity reconstruction across a cold restart."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import os
|
||||
import shutil
|
||||
import signal
|
||||
import subprocess
|
||||
import sys
|
||||
import tempfile
|
||||
import time
|
||||
from datetime import UTC, datetime
|
||||
from pathlib import Path, PurePosixPath, PureWindowsPath
|
||||
from typing import Any
|
||||
|
||||
if __package__ in {None, ""}:
|
||||
sys.path.insert(0, str(Path(__file__).resolve().parents[1]))
|
||||
|
||||
from scripts import leo_behavior_manifest as behavior
|
||||
from scripts import leo_identity_manifest as identity
|
||||
from scripts import leo_identity_profile as profile_runtime
|
||||
|
||||
SCHEMA = "livingip.leoIdentityReconstructionReceipt.v1"
|
||||
PRIVATE_PATH_PREFIXES = tuple("/" + value for value in ("Users/", "private/tmp/", "var/folders/"))
|
||||
|
||||
|
||||
class CanaryError(RuntimeError):
|
||||
"""The disposable identity runtime did not satisfy its T2 contract."""
|
||||
|
||||
|
||||
def _require(condition: bool, message: str) -> None:
|
||||
if not condition:
|
||||
raise CanaryError(message)
|
||||
|
||||
|
||||
def _receipt_strings(value: object) -> list[str]:
|
||||
if isinstance(value, dict):
|
||||
keys = [key for key in value if isinstance(key, str)]
|
||||
return keys + [text for item in value.values() for text in _receipt_strings(item)]
|
||||
if isinstance(value, list):
|
||||
return [text for item in value for text in _receipt_strings(item)]
|
||||
return [value] if isinstance(value, str) else []
|
||||
|
||||
|
||||
def _validate_portable_receipt(value: object) -> None:
|
||||
for text in _receipt_strings(value):
|
||||
if (
|
||||
any(prefix in text for prefix in PRIVATE_PATH_PREFIXES)
|
||||
or PurePosixPath(text).is_absolute()
|
||||
or PureWindowsPath(text).is_absolute()
|
||||
):
|
||||
raise CanaryError("receipt contains a private or absolute filesystem path")
|
||||
|
||||
|
||||
def _process_group_absent(process_group: int) -> bool:
|
||||
try:
|
||||
os.killpg(process_group, 0)
|
||||
except ProcessLookupError:
|
||||
return True
|
||||
except PermissionError:
|
||||
return False
|
||||
return False
|
||||
|
||||
|
||||
def _wait_for_process_group_absence(process_group: int, timeout_seconds: float = 5) -> bool:
|
||||
deadline = time.monotonic() + timeout_seconds
|
||||
while time.monotonic() < deadline:
|
||||
if _process_group_absent(process_group):
|
||||
return True
|
||||
time.sleep(0.02)
|
||||
return _process_group_absent(process_group)
|
||||
|
||||
|
||||
def _signal_process_group(process_group: int, signal_number: signal.Signals) -> bool:
|
||||
try:
|
||||
os.killpg(process_group, signal_number)
|
||||
return True
|
||||
except (ProcessLookupError, PermissionError):
|
||||
return False
|
||||
|
||||
|
||||
def _cleanup_remaining_process_group(process_group: int) -> str | None:
|
||||
if not _signal_process_group(process_group, signal.SIGTERM):
|
||||
return None
|
||||
if _wait_for_process_group_absence(process_group, timeout_seconds=1):
|
||||
return "SIGTERM"
|
||||
if not _signal_process_group(process_group, signal.SIGKILL):
|
||||
return "SIGTERM"
|
||||
return "SIGKILL"
|
||||
|
||||
|
||||
def _logical_repo_path(path: Path, *, deployment_root: Path, placeholder: str) -> str:
|
||||
"""Return a stable repo-relative path or a non-identifying placeholder."""
|
||||
|
||||
try:
|
||||
relative = path.resolve().relative_to(deployment_root.resolve())
|
||||
except (OSError, ValueError):
|
||||
return placeholder
|
||||
value = relative.as_posix()
|
||||
return value if value != "." else "."
|
||||
|
||||
|
||||
def _logical_query_command(
|
||||
*,
|
||||
deployment_root: Path,
|
||||
source_root: Path,
|
||||
hermes_root: Path,
|
||||
) -> list[str]:
|
||||
return [
|
||||
"<python>",
|
||||
"-m",
|
||||
"scripts.leo_identity_profile",
|
||||
"query",
|
||||
"--profile",
|
||||
"<temporary-profile>",
|
||||
"--source-root",
|
||||
_logical_repo_path(source_root, deployment_root=deployment_root, placeholder="<source-root>"),
|
||||
"--hermes-root",
|
||||
_logical_repo_path(hermes_root, deployment_root=deployment_root, placeholder="<hermes-root>"),
|
||||
"--deployment-root",
|
||||
".",
|
||||
"--query",
|
||||
profile_runtime.FIXED_QUERY,
|
||||
]
|
||||
|
||||
|
||||
def _run_query_child(
|
||||
*,
|
||||
deployment_root: Path,
|
||||
profile: Path,
|
||||
source_root: Path,
|
||||
hermes_root: Path,
|
||||
profile_role: str,
|
||||
timeout_seconds: float = 60,
|
||||
) -> dict[str, Any]:
|
||||
deployment_root = deployment_root.resolve()
|
||||
profile = profile.resolve()
|
||||
source_root = source_root.resolve()
|
||||
hermes_root = hermes_root.resolve()
|
||||
actual_argv = [
|
||||
sys.executable,
|
||||
"-m",
|
||||
"scripts.leo_identity_profile",
|
||||
"query",
|
||||
"--profile",
|
||||
str(profile),
|
||||
"--source-root",
|
||||
str(source_root),
|
||||
"--hermes-root",
|
||||
str(hermes_root),
|
||||
"--deployment-root",
|
||||
str(deployment_root),
|
||||
"--query",
|
||||
profile_runtime.FIXED_QUERY,
|
||||
]
|
||||
process = subprocess.Popen(
|
||||
actual_argv,
|
||||
cwd=deployment_root,
|
||||
env={**os.environ, "PYTHONDONTWRITEBYTECODE": "1"},
|
||||
text=True,
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE,
|
||||
start_new_session=True,
|
||||
)
|
||||
timed_out = False
|
||||
terminated_with: str | None = None
|
||||
stdout = ""
|
||||
stderr = ""
|
||||
process_group_absent_after_wait = False
|
||||
orphan_cleanup_required = False
|
||||
try:
|
||||
try:
|
||||
stdout, stderr = process.communicate(timeout=timeout_seconds)
|
||||
except subprocess.TimeoutExpired:
|
||||
timed_out = True
|
||||
if _signal_process_group(process.pid, signal.SIGTERM):
|
||||
terminated_with = "SIGTERM"
|
||||
try:
|
||||
stdout, stderr = process.communicate(timeout=5)
|
||||
except subprocess.TimeoutExpired:
|
||||
if _signal_process_group(process.pid, signal.SIGKILL):
|
||||
terminated_with = "SIGKILL"
|
||||
stdout, stderr = process.communicate(timeout=5)
|
||||
finally:
|
||||
if process.poll() is None:
|
||||
if _signal_process_group(process.pid, signal.SIGTERM):
|
||||
terminated_with = terminated_with or "SIGTERM"
|
||||
try:
|
||||
process.communicate(timeout=5)
|
||||
except subprocess.TimeoutExpired:
|
||||
if _signal_process_group(process.pid, signal.SIGKILL):
|
||||
terminated_with = "SIGKILL"
|
||||
process.communicate(timeout=5)
|
||||
orphan_cleanup_required = not _process_group_absent(process.pid)
|
||||
if orphan_cleanup_required:
|
||||
terminated_with = _cleanup_remaining_process_group(process.pid) or terminated_with
|
||||
process_group_absent_after_wait = _wait_for_process_group_absence(process.pid)
|
||||
try:
|
||||
payload = json.loads(stdout.strip().splitlines()[-1]) if stdout.strip() else {}
|
||||
except json.JSONDecodeError as exc:
|
||||
raise CanaryError("identity child returned invalid JSON") from exc
|
||||
return {
|
||||
"logical_command": _logical_query_command(
|
||||
deployment_root=deployment_root,
|
||||
source_root=source_root,
|
||||
hermes_root=hermes_root,
|
||||
),
|
||||
"command_serialization": "logical_redacted_v1",
|
||||
"profile_role": profile_role,
|
||||
"actual_argv_persisted": False,
|
||||
"launcher_pid": process.pid,
|
||||
"returncode": process.returncode,
|
||||
"timed_out": timed_out,
|
||||
"terminated_with": terminated_with,
|
||||
"orphan_cleanup_required": orphan_cleanup_required,
|
||||
"stdout": payload,
|
||||
"stderr_sha256": behavior.sha256_bytes(stderr.encode("utf-8")),
|
||||
"process_group_absent_after_wait": process_group_absent_after_wait,
|
||||
}
|
||||
|
||||
|
||||
def _query_passed(child: dict[str, Any]) -> bool:
|
||||
payload = child.get("stdout") or {}
|
||||
return bool(
|
||||
child.get("returncode") == 0
|
||||
and child.get("timed_out") is False
|
||||
and child.get("orphan_cleanup_required") is False
|
||||
and child.get("process_group_absent_after_wait") is True
|
||||
and payload.get("schema") == profile_runtime.QUERY_RECEIPT_SCHEMA
|
||||
and payload.get("status") == "pass"
|
||||
)
|
||||
|
||||
|
||||
def _drift_attempt(
|
||||
*,
|
||||
deployment_root: Path,
|
||||
source_root: Path,
|
||||
hermes_root: Path,
|
||||
drift_profile: Path,
|
||||
) -> dict[str, Any]:
|
||||
with (drift_profile / "SOUL.md").open("a", encoding="utf-8") as handle:
|
||||
handle.write("\nInjected drift must fail closed.\n")
|
||||
child = _run_query_child(
|
||||
deployment_root=deployment_root,
|
||||
profile=drift_profile,
|
||||
source_root=source_root,
|
||||
hermes_root=hermes_root,
|
||||
profile_role="drift_negative",
|
||||
)
|
||||
child["fail_closed"] = bool(
|
||||
child["returncode"] == 3
|
||||
and child["timed_out"] is False
|
||||
and child["orphan_cleanup_required"] is False
|
||||
and child["process_group_absent_after_wait"] is True
|
||||
and (child.get("stdout") or {}).get("error") == "identity_drift"
|
||||
and "compiled view drift detected" in str((child.get("stdout") or {}).get("message"))
|
||||
)
|
||||
child["answer_returned"] = bool((child.get("stdout") or {}).get("answer"))
|
||||
return child
|
||||
|
||||
|
||||
def run_canary(args: argparse.Namespace) -> tuple[dict[str, Any], int]:
|
||||
output = args.output.resolve()
|
||||
temporary_root = Path(tempfile.mkdtemp(prefix="leo-identity-reconstruction-"))
|
||||
report: dict[str, Any] = {
|
||||
"schema": SCHEMA,
|
||||
"generated_at_utc": datetime.now(UTC).isoformat(),
|
||||
"required_tier": "T2_runtime",
|
||||
"mode": "drift_before_restart"
|
||||
if args.inject_drift_before_restart
|
||||
else "successful_restart_plus_drift_negative",
|
||||
"fixed_query": profile_runtime.FIXED_QUERY,
|
||||
"fixed_query_sha256": behavior.sha256_bytes(profile_runtime.FIXED_QUERY.encode("utf-8")),
|
||||
"production_profile_replaced": False,
|
||||
"production_database_contacted": False,
|
||||
"telegram_message_sent": False,
|
||||
"actual_hosted_model_call_performed": False,
|
||||
"errors": [],
|
||||
}
|
||||
exit_code = 1
|
||||
try:
|
||||
behavior_manifest = behavior.build_manifest(args.profile_template, args.hermes_root, args.deployment_root)
|
||||
identity.validate_behavior_manifest(behavior_manifest)
|
||||
manifest = identity.build_identity_manifest(
|
||||
behavior_manifest=behavior_manifest,
|
||||
database_fingerprint_path=args.database_fingerprint,
|
||||
constitution_path=args.constitution,
|
||||
database_identity_path=args.database_identity,
|
||||
source_root=args.source_root,
|
||||
)
|
||||
report["manifest"] = manifest
|
||||
report["behavior_observation_before_compile"] = {
|
||||
"behavior_sha256": behavior_manifest["behavior_sha256"],
|
||||
"identity_runtime_sha256": behavior_manifest["identity_runtime_sha256"],
|
||||
"source_commit": behavior_manifest["teleo_infrastructure_runtime"]["git_head"],
|
||||
}
|
||||
compiled_profile = temporary_root / "first-profile"
|
||||
report["compile"] = profile_runtime.compile_profile(
|
||||
manifest,
|
||||
source_root=args.source_root,
|
||||
profile_template=args.profile_template,
|
||||
profile=compiled_profile,
|
||||
hermes_root=args.hermes_root,
|
||||
deployment_root=args.deployment_root,
|
||||
)
|
||||
compiled_behavior_before_query = behavior.build_manifest(
|
||||
compiled_profile, args.hermes_root, args.deployment_root
|
||||
)
|
||||
report["compiled_profile_before_query"] = {
|
||||
"behavior_sha256": compiled_behavior_before_query["behavior_sha256"],
|
||||
"identity_runtime_sha256": compiled_behavior_before_query["identity_runtime_sha256"],
|
||||
}
|
||||
first = _run_query_child(
|
||||
deployment_root=args.deployment_root,
|
||||
profile=compiled_profile,
|
||||
source_root=args.source_root,
|
||||
hermes_root=args.hermes_root,
|
||||
profile_role="first_start",
|
||||
)
|
||||
report["first_start"] = first
|
||||
_require(_query_passed(first), "first disposable identity process did not answer successfully")
|
||||
after_first = behavior.build_manifest(compiled_profile, args.hermes_root, args.deployment_root)
|
||||
report["session_boundary_readback"] = {
|
||||
"full_behavior_changed_after_session": after_first["behavior_sha256"]
|
||||
!= compiled_behavior_before_query["behavior_sha256"],
|
||||
"identity_runtime_unchanged_after_session": after_first["identity_runtime_sha256"]
|
||||
== compiled_behavior_before_query["identity_runtime_sha256"],
|
||||
"session_file_count": len(list((compiled_profile / "sessions").glob("*.json"))),
|
||||
"session_classification": "temporary_noncanonical",
|
||||
"session_used_as_output_provenance": False,
|
||||
}
|
||||
if args.inject_drift_before_restart:
|
||||
with (compiled_profile / "SOUL.md").open("a", encoding="utf-8") as handle:
|
||||
handle.write("\nInjected pre-restart drift.\n")
|
||||
rejected = _run_query_child(
|
||||
deployment_root=args.deployment_root,
|
||||
profile=compiled_profile,
|
||||
source_root=args.source_root,
|
||||
hermes_root=args.hermes_root,
|
||||
profile_role="pre_restart_drift",
|
||||
)
|
||||
report["pre_restart_drift"] = rejected
|
||||
report["drift_target"] = "compiled SOUL.md generated view"
|
||||
report["second_start_attempted"] = False
|
||||
report["gates"] = {
|
||||
"first_start_passed": True,
|
||||
"first_process_stopped": first["process_group_absent_after_wait"],
|
||||
"drift_detected_before_restart": rejected["returncode"] == 3
|
||||
and (rejected.get("stdout") or {}).get("error") == "identity_drift",
|
||||
"drift_returned_no_answer": not bool((rejected.get("stdout") or {}).get("answer")),
|
||||
"drift_process_stopped": rejected["process_group_absent_after_wait"],
|
||||
"drift_process_had_no_orphan_cleanup": rejected["orphan_cleanup_required"] is False,
|
||||
"second_start_not_attempted": True,
|
||||
}
|
||||
report["status"] = "pass" if all(report["gates"].values()) else "fail"
|
||||
else:
|
||||
profile_runtime.verify_profile(
|
||||
compiled_profile,
|
||||
source_root=args.source_root,
|
||||
hermes_root=args.hermes_root,
|
||||
deployment_root=args.deployment_root,
|
||||
)
|
||||
report["pre_restart_verification"] = "pass"
|
||||
report["second_start_attempted"] = True
|
||||
restarted_profile = temporary_root / "restart-profile"
|
||||
report["restart_compile"] = profile_runtime.compile_profile(
|
||||
manifest,
|
||||
source_root=args.source_root,
|
||||
profile_template=args.profile_template,
|
||||
profile=restarted_profile,
|
||||
hermes_root=args.hermes_root,
|
||||
deployment_root=args.deployment_root,
|
||||
)
|
||||
profile_runtime.verify_profile(
|
||||
restarted_profile,
|
||||
source_root=args.source_root,
|
||||
hermes_root=args.hermes_root,
|
||||
deployment_root=args.deployment_root,
|
||||
)
|
||||
second = _run_query_child(
|
||||
deployment_root=args.deployment_root,
|
||||
profile=restarted_profile,
|
||||
source_root=args.source_root,
|
||||
hermes_root=args.hermes_root,
|
||||
profile_role="restart",
|
||||
)
|
||||
report["restart"] = second
|
||||
_require(_query_passed(second), "restarted disposable identity process did not answer successfully")
|
||||
first_payload = first["stdout"]
|
||||
second_payload = second["stdout"]
|
||||
drift_profile = temporary_root / "drift-profile"
|
||||
report["drift_compile"] = profile_runtime.compile_profile(
|
||||
manifest,
|
||||
source_root=args.source_root,
|
||||
profile_template=args.profile_template,
|
||||
profile=drift_profile,
|
||||
hermes_root=args.hermes_root,
|
||||
deployment_root=args.deployment_root,
|
||||
)
|
||||
drift = _drift_attempt(
|
||||
deployment_root=args.deployment_root,
|
||||
source_root=args.source_root,
|
||||
hermes_root=args.hermes_root,
|
||||
drift_profile=drift_profile,
|
||||
)
|
||||
report["drift_negative"] = drift
|
||||
report["drift_target"] = "compiled SOUL.md generated view"
|
||||
report["gates"] = {
|
||||
"manifest_generated": identity._is_sha256(manifest["manifest_sha256"]),
|
||||
"views_compiled_and_bound": report["compile"]["status"] == "pass",
|
||||
"first_start_passed": True,
|
||||
"first_process_stopped": first["process_group_absent_after_wait"],
|
||||
"pre_restart_verification_passed": True,
|
||||
"restart_profile_recompiled_from_manifest": report["restart_compile"]["status"] == "pass",
|
||||
"restart_profile_started_without_sessions": report["restart_compile"][
|
||||
"session_directories_started_empty"
|
||||
],
|
||||
"restart_passed": True,
|
||||
"restart_process_is_distinct": first_payload["process_id"] != second_payload["process_id"]
|
||||
and first_payload["runtime_instance_id"] != second_payload["runtime_instance_id"],
|
||||
"identity_inputs_reproduced": first_payload["identity_inputs_sha256"]
|
||||
== second_payload["identity_inputs_sha256"],
|
||||
"manifest_reproduced": first_payload["manifest_sha256"] == second_payload["manifest_sha256"],
|
||||
"query_reproduced": first_payload["query_sha256"] == second_payload["query_sha256"],
|
||||
"answer_and_provenance_explainable": first_payload["answer_sha256"] == second_payload["answer_sha256"]
|
||||
and first_payload["output_provenance"] == second_payload["output_provenance"],
|
||||
"session_excluded_from_identity": report["session_boundary_readback"][
|
||||
"identity_runtime_unchanged_after_session"
|
||||
],
|
||||
"drift_failed_closed": drift["fail_closed"] and not drift["answer_returned"],
|
||||
"drift_profile_started_without_sessions": report["drift_compile"]["session_directories_started_empty"],
|
||||
"drift_process_stopped": drift["process_group_absent_after_wait"],
|
||||
"drift_process_had_no_orphan_cleanup": drift["orphan_cleanup_required"] is False,
|
||||
"restart_process_stopped": second["process_group_absent_after_wait"],
|
||||
}
|
||||
report["status"] = "pass" if all(report["gates"].values()) else "fail"
|
||||
if report["status"] == "pass":
|
||||
exit_code = 0
|
||||
except (CanaryError, identity.IdentityManifestError, OSError, subprocess.SubprocessError) as exc:
|
||||
report["status"] = "fail"
|
||||
report["errors"].append(
|
||||
{
|
||||
"type": type(exc).__name__,
|
||||
"message": "details_redacted",
|
||||
"detail_sha256": behavior.sha256_bytes(str(exc).encode("utf-8")),
|
||||
}
|
||||
)
|
||||
finally:
|
||||
shutil.rmtree(temporary_root, ignore_errors=True)
|
||||
report["cleanup"] = {
|
||||
"temporary_root_removed": not temporary_root.exists(),
|
||||
"no_profile_retained": not temporary_root.exists(),
|
||||
}
|
||||
if not all(report["cleanup"].values()):
|
||||
report["status"] = "fail"
|
||||
exit_code = 1
|
||||
positive_restart_passed = report.get("status") == "pass" and not args.inject_drift_before_restart
|
||||
report["current_tier"] = "T2_runtime" if positive_restart_passed else "T1_model"
|
||||
report["goal_tier_satisfied"] = positive_restart_passed
|
||||
report["runtime_component_proven"] = (
|
||||
"fresh_profile_recompile_plus_distinct_process_restart"
|
||||
if positive_restart_passed
|
||||
else "first_local_process_plus_pre_restart_drift_refusal"
|
||||
)
|
||||
report["runtime_variant"] = "local_deterministic_identity_compiler_readback"
|
||||
report["tier_basis"] = (
|
||||
"Capability Tier Proof defines T2_runtime as local API/runtime behavior with restart where relevant; "
|
||||
"this is compiler-process runtime proof and explicitly excludes GatewayRunner and hosted-model proof."
|
||||
if positive_restart_passed
|
||||
else "This negative component does not complete the required restart path, so it remains below T2_runtime."
|
||||
)
|
||||
report["claim_ceiling"] = (
|
||||
"Local disposable identity compilation, fresh-profile reconstruction, and cold-process restart only; "
|
||||
"not a live GatewayRunner, hosted-model, Telegram, production database, VPS restart, or T3 proof."
|
||||
if positive_restart_passed
|
||||
else "Local first-process and pre-restart drift-refusal component only; no successful restart proof, "
|
||||
"GatewayRunner, hosted model, production database, VPS, or T3 claim."
|
||||
)
|
||||
_validate_portable_receipt(report)
|
||||
stable = {key: value for key, value in report.items() if key != "receipt_sha256"}
|
||||
report["receipt_sha256"] = behavior.canonical_sha256(stable)
|
||||
identity.write_json(output, report)
|
||||
return report, exit_code
|
||||
|
||||
|
||||
def main() -> int:
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument("--profile-template", type=Path, required=True)
|
||||
parser.add_argument("--hermes-root", type=Path, required=True)
|
||||
parser.add_argument("--deployment-root", type=Path, required=True)
|
||||
parser.add_argument("--source-root", type=Path, required=True)
|
||||
parser.add_argument("--database-fingerprint", type=Path, required=True)
|
||||
parser.add_argument("--constitution", type=Path, required=True)
|
||||
parser.add_argument("--database-identity", type=Path, required=True)
|
||||
parser.add_argument("--output", type=Path, required=True)
|
||||
parser.add_argument("--inject-drift-before-restart", action="store_true")
|
||||
args = parser.parse_args()
|
||||
report, exit_code = run_canary(args)
|
||||
print(
|
||||
json.dumps(
|
||||
{
|
||||
"status": report.get("status"),
|
||||
"current_tier": report.get("current_tier"),
|
||||
"receipt_sha256": report.get("receipt_sha256"),
|
||||
"output": str(args.output),
|
||||
},
|
||||
sort_keys=True,
|
||||
)
|
||||
)
|
||||
return exit_code
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
1200
scripts/verify_telegram_visible_unseen_chain.py
Normal file
1200
scripts/verify_telegram_visible_unseen_chain.py
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -30,6 +30,10 @@ sys.path.insert(0, str(REPO_ROOT / "scripts"))
|
|||
|
||||
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):
|
||||
return {
|
||||
|
|
@ -112,7 +116,7 @@ def test_revise_strategy_rejects_bad_node_type():
|
|||
|
||||
# --- add_edge ------------------------------------------------------------- #
|
||||
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))
|
||||
assert "insert into public.claim_edges" 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():
|
||||
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))
|
||||
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 sql.startswith("begin;")
|
||||
assert sql.rstrip().endswith("commit;")
|
||||
assert sql.index("raise exception 'apply_proposal: claim_edge row") < sql.index(
|
||||
"kb_stage.finish_approved_proposal"
|
||||
)
|
||||
assert sql.index("raise exception 'apply_proposal: claim_edge row") < sql.index("kb_stage.finish_approved_proposal")
|
||||
|
||||
|
||||
def test_add_edge_rejects_self_loop():
|
||||
|
|
@ -144,22 +146,18 @@ def test_add_edge_rejects_self_loop():
|
|||
|
||||
# --- attach_evidence ------------------------------------------------------ #
|
||||
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))
|
||||
assert "insert into public.claim_evidence" in sql
|
||||
assert "public.claim_evidence (id," not in sql
|
||||
assert "public.claim_evidence (claim_id, source_id, role, weight)" in sql
|
||||
assert "::evidence_role" in sql
|
||||
assert "not exists" in sql
|
||||
|
||||
|
||||
def test_attach_evidence_semantic_row_accepts_match_and_rejects_weight_mismatch():
|
||||
payload = {
|
||||
"evidence": [
|
||||
{"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)
|
||||
)
|
||||
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))
|
||||
verify = sql[sql.index("do $verify$") : sql.index("kb_stage.finish_approved_proposal")]
|
||||
|
||||
assert "weight is not distinct from 0.78" in verify
|
||||
|
|
@ -167,9 +165,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 sql.startswith("begin;")
|
||||
assert sql.rstrip().endswith("commit;")
|
||||
assert sql.index("raise exception 'apply_proposal: evidence row") < sql.index(
|
||||
"kb_stage.finish_approved_proposal"
|
||||
)
|
||||
assert sql.index("raise exception 'apply_proposal: evidence row") < sql.index("kb_stage.finish_approved_proposal")
|
||||
|
||||
|
||||
def test_attach_evidence_requires_source_id():
|
||||
|
|
@ -231,9 +227,7 @@ def _approve_claim_bundle():
|
|||
{"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},
|
||||
],
|
||||
"edges": [
|
||||
{"from_claim": claim_a, "to_claim": claim_b, "edge_type": "supports", "weight": 0.7}
|
||||
],
|
||||
"edges": [{"from_claim": claim_a, "to_claim": claim_b, "edge_type": "supports", "weight": 0.7}],
|
||||
"reasoning_tools": [
|
||||
{
|
||||
"id": "eeeeeeee-eeee-4eee-8eee-eeeeeeeeeeee",
|
||||
|
|
@ -259,6 +253,8 @@ def test_approve_claim_bundle_sql_is_atomic_and_row_verified():
|
|||
assert "insert into public.claims" in sql
|
||||
assert "insert into public.sources" in sql
|
||||
assert "insert into public.claim_evidence" in sql
|
||||
assert "public.claim_evidence (id," not in sql
|
||||
assert "public.claim_evidence (claim_id, source_id, role, weight, created_by)" in sql
|
||||
assert "insert into public.claim_edges" in sql
|
||||
assert "insert into public.reasoning_tools" in sql
|
||||
assert "source hash collision" in sql
|
||||
|
|
@ -291,9 +287,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 sql.startswith("begin;")
|
||||
assert sql.rstrip().endswith("commit;")
|
||||
assert sql.index("raise exception 'approve_claim: evidence row") < sql.index(
|
||||
"kb_stage.finish_approved_proposal"
|
||||
)
|
||||
assert sql.index("raise exception 'approve_claim: evidence row") < sql.index("kb_stage.finish_approved_proposal")
|
||||
|
||||
|
||||
def test_approve_claim_bundle_rejects_duplicate_source_hashes():
|
||||
|
|
@ -388,6 +382,34 @@ def test_apply_sql_locks_and_binds_approval_before_canonical_write():
|
|||
assert "Reviewed exact strict payload." in sql
|
||||
|
||||
|
||||
def test_fresh_owned_apply_uses_strict_inserts_and_binds_preflight_hash():
|
||||
payload = _approve_claim_bundle()
|
||||
proposal = {
|
||||
"id": "99999999-9999-4999-8999-999999999999",
|
||||
"proposal_type": "approve_claim",
|
||||
"status": "approved",
|
||||
"payload": {"apply_payload": payload},
|
||||
"reviewed_by_handle": "m3ta",
|
||||
"reviewed_by_agent_id": None,
|
||||
"reviewed_at": "2026-07-10T00:00:00+00:00",
|
||||
"review_note": "Reviewed exact strict payload.",
|
||||
}
|
||||
preflight_sha256 = "a" * 64
|
||||
|
||||
sql = ap.build_apply_sql(
|
||||
proposal,
|
||||
"kb-apply",
|
||||
fresh_owned=True,
|
||||
fresh_preflight_sha256=preflight_sha256,
|
||||
)
|
||||
|
||||
assert preflight_sha256 in sql
|
||||
assert "set transaction isolation level serializable" in sql.lower()
|
||||
assert "on conflict" not in sql.lower()
|
||||
assert "where not exists" not in sql.lower()
|
||||
assert sql.index("set transaction isolation level serializable") < sql.index("kb_stage.assert_approved_proposal")
|
||||
|
||||
|
||||
def test_build_apply_sql_requires_review_provenance():
|
||||
proposal = {
|
||||
"id": "99999999-9999-4999-8999-999999999999",
|
||||
|
|
@ -445,7 +467,7 @@ def test_assert_applyable_allows_approved():
|
|||
|
||||
# --- ledger flip: concurrency guard + FK stamp --------------------------- #
|
||||
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))
|
||||
assert "kb_stage.assert_approved_proposal" in sql
|
||||
assert "kb_stage.finish_approved_proposal" in sql
|
||||
|
|
@ -459,7 +481,7 @@ def test_ledger_transition_uses_payload_bound_security_functions():
|
|||
|
||||
|
||||
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))
|
||||
# Hard resolve into a variable + NOT-NULL assert, never a silent inline
|
||||
# subselect that would stamp NULL on an unresolved handle.
|
||||
|
|
@ -468,7 +490,7 @@ def test_ledger_flip_stamps_agent_fk():
|
|||
|
||||
|
||||
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 = {
|
||||
"id": "pid",
|
||||
"proposal_type": "add_edge",
|
||||
|
|
|
|||
|
|
@ -6,7 +6,10 @@ standalone (`python3 tests/test_apply_worker.py`).
|
|||
"""
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import stat
|
||||
import sys
|
||||
import tempfile
|
||||
from pathlib import Path
|
||||
|
||||
try:
|
||||
|
|
@ -40,19 +43,33 @@ sys.path.insert(0, str(REPO_ROOT / "scripts"))
|
|||
import apply_worker as w # noqa: E402
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def restore_apply_worker_dependencies():
|
||||
def _dependency_restore():
|
||||
original_load_password = w.ap.load_password
|
||||
original_load_failure_state = w.load_failure_state
|
||||
original_fetch_candidates = w.fetch_candidates
|
||||
original_apply_one = w.apply_one
|
||||
original_render_one = w.render_one
|
||||
original_subprocess_run = w.subprocess.run
|
||||
yield
|
||||
w.ap.load_password = original_load_password
|
||||
w.load_failure_state = original_load_failure_state
|
||||
w.fetch_candidates = original_fetch_candidates
|
||||
w.apply_one = original_apply_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 ------------------------------------------------------ #
|
||||
|
|
@ -116,22 +133,283 @@ def test_render_command_expands_agent_id():
|
|||
# --- enablement gate ------------------------------------------------------ #
|
||||
def _args(**over):
|
||||
base = dict(
|
||||
enable=False, limit=20, max_per_tick=1, max_attempts=3,
|
||||
failure_state_file=None, applied_by="kb-apply",
|
||||
apply_script="apply_proposal.py", render_cmd="",
|
||||
secrets_file="x", container="teleo-pg", db="teleo",
|
||||
host="127.0.0.1", role="kb_apply",
|
||||
enable=False,
|
||||
limit=20,
|
||||
max_per_tick=1,
|
||||
max_attempts=3,
|
||||
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)
|
||||
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):
|
||||
calls = []
|
||||
w.ap.load_password = lambda _f: "pw"
|
||||
w.fetch_candidates = lambda a, p, excluded: [
|
||||
{"id": "p1", "proposal_type": "revise_strategy", "agent_id": "ag"}
|
||||
]
|
||||
w.fetch_candidates = lambda a, p, excluded: [{"id": "p1", "proposal_type": "revise_strategy", "agent_id": "ag"}]
|
||||
w.apply_one = lambda a, pid: calls.append(pid)
|
||||
|
||||
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():
|
||||
applied, rendered = [], []
|
||||
w.ap.load_password = lambda _f: "pw"
|
||||
w.fetch_candidates = lambda a, p, excluded: [
|
||||
{"id": "p1", "proposal_type": "revise_strategy", "agent_id": "ag"}
|
||||
]
|
||||
w.fetch_candidates = lambda a, p, excluded: [{"id": "p1", "proposal_type": "revise_strategy", "agent_id": "ag"}]
|
||||
w.apply_one = lambda a, pid: applied.append(pid)
|
||||
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():
|
||||
applied, rendered = [], []
|
||||
w.ap.load_password = lambda _f: "pw"
|
||||
w.fetch_candidates = lambda a, p, excluded: [
|
||||
{"id": "e1", "proposal_type": "add_edge", "agent_id": None}
|
||||
]
|
||||
w.fetch_candidates = lambda a, p, excluded: [{"id": "e1", "proposal_type": "add_edge", "agent_id": None}]
|
||||
w.apply_one = lambda a, pid: applied.append(pid)
|
||||
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():
|
||||
applied, rendered = [], []
|
||||
w.ap.load_password = lambda _f: "pw"
|
||||
w.fetch_candidates = lambda a, p, excluded: [
|
||||
{"id": "c1", "proposal_type": "approve_claim", "agent_id": "ag"}
|
||||
]
|
||||
w.fetch_candidates = lambda a, p, excluded: [{"id": "c1", "proposal_type": "approve_claim", "agent_id": "ag"}]
|
||||
w.apply_one = lambda a, pid: applied.append(pid)
|
||||
w.render_one = lambda a, agent_id: rendered.append(agent_id) or "ok"
|
||||
|
||||
|
|
@ -263,7 +535,7 @@ if __name__ == "__main__":
|
|||
failures = 0
|
||||
for name, fn in sorted(globals().items()):
|
||||
if name.startswith("test_") and callable(fn):
|
||||
restore = restore_apply_worker_dependencies()
|
||||
restore = _dependency_restore()
|
||||
next(restore)
|
||||
try:
|
||||
fn()
|
||||
|
|
|
|||
73
tests/test_build_telegram_visible_unseen_chain_packet.py
Normal file
73
tests/test_build_telegram_visible_unseen_chain_packet.py
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
from pathlib import Path
|
||||
|
||||
from scripts import build_telegram_visible_unseen_chain_packet as packet
|
||||
|
||||
|
||||
def test_packet_binds_handler_receipt_and_preserves_exact_messages() -> None:
|
||||
data = packet.build_packet(git_sha="a" * 40)
|
||||
|
||||
assert data["schema"] == packet.SCHEMA
|
||||
assert data["ready_to_request_action_time_authorization"] is True
|
||||
assert data["telegram_visible_messages_sent"] is False
|
||||
assert data["telegram_visible_message_authorization_present"] is False
|
||||
assert data["mutates_db"] is False
|
||||
assert data["target"]["chat_label"] == "Leo"
|
||||
assert data["target"]["chat_id"] == "-5146042086"
|
||||
assert data["target"]["allowed_transport"] == "authenticated_chrome_telegram_ui"
|
||||
assert [item["message"] for item in data["exact_messages"]] == [item["message"] for item in packet.unseen.PROMPTS]
|
||||
assert [item["sequence"] for item in data["exact_messages"]] == [1, 2, 3]
|
||||
assert all(len(item["message_sha256"]) == 64 for item in data["exact_messages"])
|
||||
assert data["handler_receipt_binding"]["sha256"] == packet._sha256_file(packet.DEFAULT_HANDLER_RECEIPT)
|
||||
assert data["tooling_binding"] == packet.tooling_binding()
|
||||
assert data["manifest_binding"] == packet.manifest_binding()
|
||||
assert data["manifest_binding"]["path"] == "ops/postgres_parity_manifest.sql"
|
||||
assert data["manifest_binding"]["execution_contract"]["effective_role"] == "pg_read_all_data"
|
||||
assert data["manifest_binding"]["execution_contract"]["transaction_read_only"] == "on"
|
||||
assert data["protocol"]["manifest_binding"] == data["manifest_binding"]
|
||||
assert data["operator_context"]["codex_thread_id"] == packet.DEFAULT_CODEX_THREAD_ID
|
||||
assert data["protocol"]["operator_context"] == data["operator_context"]
|
||||
assert packet._canonical_sha256(data["protocol"]) == data["protocol_sha256"]
|
||||
assert all(data["checks"].values())
|
||||
|
||||
|
||||
def test_action_time_authorization_contains_destination_transport_and_full_messages() -> None:
|
||||
data = packet.build_packet(git_sha="a" * 40)
|
||||
authorization = data["explicit_operator_authorization_text"]
|
||||
|
||||
assert "Telegram group Leo (chat ID -5146042086)" in authorization
|
||||
assert "already-authenticated Chrome Telegram UI" in authorization
|
||||
assert "do not use the Bot API" in authorization
|
||||
assert "Codex rollout's user-authorization and Chrome tool events" in authorization
|
||||
assert "no additional messages" in authorization
|
||||
for item in data["exact_messages"]:
|
||||
assert item["prompt_id"] in authorization
|
||||
assert json.dumps(item["message"], ensure_ascii=True) in authorization
|
||||
|
||||
|
||||
def test_packet_fails_closed_when_handler_receipt_no_longer_passes(tmp_path: Path) -> None:
|
||||
receipt = json.loads(packet.DEFAULT_HANDLER_RECEIPT.read_text(encoding="utf-8"))
|
||||
receipt["status"] = "fail"
|
||||
receipt_path = tmp_path / "handler.json"
|
||||
receipt_path.write_text(json.dumps(receipt), encoding="utf-8")
|
||||
|
||||
data = packet.build_packet(handler_receipt_path=receipt_path, git_sha="a" * 40)
|
||||
|
||||
assert data["ready_to_request_action_time_authorization"] is False
|
||||
assert data["authorization_gate_status"] == "not_ready"
|
||||
assert data["checks"]["handler_receipt_passed"] is False
|
||||
|
||||
|
||||
def test_markdown_retains_exact_cta_and_no_send_ceiling(tmp_path: Path) -> None:
|
||||
data = packet.build_packet(git_sha="a" * 40)
|
||||
out = tmp_path / "packet.md"
|
||||
|
||||
packet.write_markdown(out, data)
|
||||
|
||||
text = out.read_text(encoding="utf-8")
|
||||
assert "Telegram-Visible Unseen Chain Authorization Packet" in text
|
||||
assert "Telegram-visible messages sent: `False`" in text
|
||||
assert "Exact Action-Time Authorization" in text
|
||||
assert data["exact_messages"][2]["message"] in text
|
||||
320
tests/test_collect_telegram_visible_unseen_chain_state.py
Normal file
320
tests/test_collect_telegram_visible_unseen_chain_state.py
Normal file
|
|
@ -0,0 +1,320 @@
|
|||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import copy
|
||||
import json
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
|
||||
from scripts import build_telegram_visible_unseen_chain_packet as packet_builder
|
||||
from scripts import collect_telegram_visible_unseen_chain_state as state
|
||||
|
||||
|
||||
def manifest_output(*, row_count: int = 7) -> str:
|
||||
rows = [
|
||||
{
|
||||
"kind": "identity",
|
||||
"database": "teleo",
|
||||
"current_user": packet_builder.READ_ONLY_DB_ROLE,
|
||||
"server_version_num": 160014,
|
||||
"server_encoding": "UTF8",
|
||||
"database_collation": "C.UTF-8",
|
||||
"database_ctype": "C.UTF-8",
|
||||
"transaction_read_only": "on",
|
||||
}
|
||||
]
|
||||
for kind in (
|
||||
"schemas",
|
||||
"extensions",
|
||||
"application_roles",
|
||||
"columns",
|
||||
"constraints",
|
||||
"indexes",
|
||||
"sequences",
|
||||
"views",
|
||||
"functions",
|
||||
"triggers",
|
||||
"types",
|
||||
"policies",
|
||||
):
|
||||
rows.append({"kind": kind, "items": []})
|
||||
rows.append(
|
||||
{
|
||||
"kind": "table",
|
||||
"schema": "public",
|
||||
"table": "claims",
|
||||
"row_count": row_count,
|
||||
"rowset_md5": "f" * 32,
|
||||
}
|
||||
)
|
||||
return "BEGIN\nSET\n" + "\n".join(json.dumps(item) for item in rows) + "\nROLLBACK\n"
|
||||
|
||||
|
||||
def write_packet(tmp_path: Path) -> Path:
|
||||
out = tmp_path / "packet.json"
|
||||
packet_builder.write_json(
|
||||
out,
|
||||
packet_builder.build_packet(
|
||||
handler_receipt_path=packet_builder.DEFAULT_HANDLER_RECEIPT.resolve(),
|
||||
git_sha="a" * 40,
|
||||
),
|
||||
)
|
||||
return out
|
||||
|
||||
|
||||
def args_for(packet: Path, tmp_path: Path, *, phase: str = "preflight") -> argparse.Namespace:
|
||||
return argparse.Namespace(
|
||||
phase=phase,
|
||||
packet=packet,
|
||||
baseline=None,
|
||||
subject_ref=None,
|
||||
manifest_sql=Path("ops/postgres_parity_manifest.sql"),
|
||||
ssh_target="root@example.invalid",
|
||||
ssh_key=tmp_path / "key",
|
||||
connect_timeout=1,
|
||||
timeout=5,
|
||||
fingerprint_timeout=5,
|
||||
ssh_attempts=3,
|
||||
out=tmp_path / f"{phase}.json",
|
||||
markdown_out=tmp_path / f"{phase}.md",
|
||||
)
|
||||
|
||||
|
||||
class GoodRunner:
|
||||
def __init__(self) -> None:
|
||||
self.service_calls = 0
|
||||
|
||||
def __call__(self, command: list[str], input_text: str, _timeout: int) -> state.CommandResult:
|
||||
remote_command = command[-1]
|
||||
if "git rev-parse HEAD" in remote_command:
|
||||
sha = "b" * 40
|
||||
return state.CommandResult(
|
||||
0,
|
||||
f"deploy_head={sha}\nlast_deploy_sha={sha}\ndeploy_stamp_ancestor=true\n",
|
||||
"",
|
||||
)
|
||||
if "systemctl show" in remote_command:
|
||||
self.service_calls += 1
|
||||
return state.CommandResult(
|
||||
0,
|
||||
"\n".join(
|
||||
[
|
||||
"ActiveState=active",
|
||||
"SubState=running",
|
||||
"MainPID=123",
|
||||
"NRestarts=0",
|
||||
"ExecMainStartTimestamp=Wed 2026-07-15 00:00:00 UTC",
|
||||
]
|
||||
),
|
||||
"",
|
||||
)
|
||||
if "'subject_ref'" in input_text:
|
||||
assert "default_transaction_read_only=on" in remote_command
|
||||
assert "-c transaction_read_only=on" in remote_command
|
||||
assert f"role={packet_builder.READ_ONLY_DB_ROLE}" in remote_command
|
||||
assert "psql -X" in remote_command
|
||||
payload = {
|
||||
"subject_ref": "c0000000",
|
||||
"matches": [
|
||||
{
|
||||
"table": "public.beliefs",
|
||||
"row": {"id": "c0000000-0000-4000-8000-000000000001"},
|
||||
"evidence_count": None,
|
||||
}
|
||||
],
|
||||
}
|
||||
return state.CommandResult(0, f"BEGIN\n{json.dumps(payload)}\nROLLBACK\n", "")
|
||||
if "postgres_parity_manifest" not in remote_command and input_text.startswith("\\set ON_ERROR_STOP"):
|
||||
assert "default_transaction_read_only=on" in remote_command
|
||||
assert "-c transaction_read_only=on" in remote_command
|
||||
assert f"role={packet_builder.READ_ONLY_DB_ROLE}" in remote_command
|
||||
assert "psql -X" in remote_command
|
||||
return state.CommandResult(0, manifest_output(), "")
|
||||
raise AssertionError(f"unexpected command: {command} / input={input_text[:80]}")
|
||||
|
||||
|
||||
def test_preflight_passes_with_two_identical_read_only_fingerprints(tmp_path: Path) -> None:
|
||||
args = args_for(write_packet(tmp_path), tmp_path)
|
||||
|
||||
result = state.collect_state(args, runner=GoodRunner())
|
||||
|
||||
assert result["status"] == "pass"
|
||||
assert result["ready_for_action_time_authorization"] is True
|
||||
assert result["telegram_visible_messages_sent_by_collector"] is False
|
||||
assert result["mutates_db"] is False
|
||||
assert all(result["packet_checks"].values())
|
||||
assert all(result["remote_checks"].values())
|
||||
assert len(result["state_token_sha256"]) == 64
|
||||
|
||||
|
||||
def test_preflight_fails_when_second_fingerprint_drifts(tmp_path: Path) -> None:
|
||||
args = args_for(write_packet(tmp_path), tmp_path)
|
||||
fingerprint_calls = 0
|
||||
good = GoodRunner()
|
||||
|
||||
def drift_runner(command: list[str], input_text: str, timeout: int) -> state.CommandResult:
|
||||
nonlocal fingerprint_calls
|
||||
if input_text.startswith("\\set ON_ERROR_STOP") and "'subject_ref'" not in input_text:
|
||||
fingerprint_calls += 1
|
||||
return state.CommandResult(0, manifest_output(row_count=7 + fingerprint_calls - 1), "")
|
||||
return good(command, input_text, timeout)
|
||||
|
||||
result = state.collect_state(args, runner=drift_runner)
|
||||
|
||||
assert result["status"] == "fail"
|
||||
assert result["remote_checks"]["canonical_fingerprint_unchanged_during_probe"] is False
|
||||
|
||||
|
||||
def test_preflight_accepts_newer_workspace_head_when_deployed_stamp_is_ancestor(tmp_path: Path) -> None:
|
||||
args = args_for(write_packet(tmp_path), tmp_path)
|
||||
|
||||
class AheadRunner(GoodRunner):
|
||||
def __call__(self, command: list[str], input_text: str, timeout: int) -> state.CommandResult:
|
||||
if "git rev-parse HEAD" in command[-1]:
|
||||
return state.CommandResult(
|
||||
0,
|
||||
f"deploy_head={'c' * 40}\nlast_deploy_sha={'b' * 40}\ndeploy_stamp_ancestor=true\n",
|
||||
"",
|
||||
)
|
||||
return super().__call__(command, input_text, timeout)
|
||||
|
||||
result = state.collect_state(args, runner=AheadRunner())
|
||||
|
||||
assert result["status"] == "pass"
|
||||
assert result["remote"]["workspace_head_matches_deployed_stamp"] is False
|
||||
assert result["remote_checks"]["deployed_stamp_is_ancestor_of_workspace_head"] is True
|
||||
|
||||
|
||||
def test_preflight_retries_transient_ssh_failure(tmp_path: Path) -> None:
|
||||
args = args_for(write_packet(tmp_path), tmp_path)
|
||||
good = GoodRunner()
|
||||
deploy_attempts = 0
|
||||
|
||||
def transient_runner(command: list[str], input_text: str, timeout: int) -> state.CommandResult:
|
||||
nonlocal deploy_attempts
|
||||
if "git rev-parse HEAD" in command[-1]:
|
||||
deploy_attempts += 1
|
||||
if deploy_attempts == 1:
|
||||
return state.CommandResult(255, "", "Connection timed out during banner exchange")
|
||||
return good(command, input_text, timeout)
|
||||
|
||||
result = state.collect_state(args, runner=transient_runner)
|
||||
|
||||
assert result["status"] == "pass"
|
||||
assert result["remote"]["readback_attempts"]["deploy"] == 2
|
||||
|
||||
|
||||
def test_preflight_rejects_packet_bound_to_different_tooling_source(tmp_path: Path) -> None:
|
||||
packet_path = write_packet(tmp_path)
|
||||
packet = json.loads(packet_path.read_text(encoding="utf-8"))
|
||||
packet["tooling_binding"]["capture_verifier"]["sha256"] = "0" * 64
|
||||
packet_path.write_text(json.dumps(packet), encoding="utf-8")
|
||||
|
||||
result = state.collect_state(args_for(packet_path, tmp_path), runner=GoodRunner())
|
||||
|
||||
assert result["status"] == "fail"
|
||||
assert result["packet_checks"]["packet_tooling_hashes_match_current_sources"] is False
|
||||
|
||||
|
||||
def test_postflight_binds_baseline_fingerprint_service_and_subject(tmp_path: Path) -> None:
|
||||
packet = write_packet(tmp_path)
|
||||
pre_args = args_for(packet, tmp_path)
|
||||
preflight = state.collect_state(pre_args, runner=GoodRunner())
|
||||
baseline = tmp_path / "preflight.json"
|
||||
state.write_json(baseline, preflight)
|
||||
post_args = args_for(packet, tmp_path, phase="postflight")
|
||||
post_args.baseline = baseline
|
||||
post_args.subject_ref = "c0000000"
|
||||
|
||||
postflight = state.collect_state(post_args, runner=GoodRunner())
|
||||
|
||||
assert postflight["status"] == "pass"
|
||||
assert postflight["ready_for_visible_capture_verification"] is True
|
||||
assert all(postflight["baseline_checks"].values())
|
||||
assert postflight["remote_checks"]["subject_resolved_to_exactly_one_db_object"] is True
|
||||
|
||||
|
||||
def test_postflight_rejects_baseline_fingerprint_mismatch(tmp_path: Path) -> None:
|
||||
packet = write_packet(tmp_path)
|
||||
pre_args = args_for(packet, tmp_path)
|
||||
preflight = state.collect_state(pre_args, runner=GoodRunner())
|
||||
preflight = copy.deepcopy(preflight)
|
||||
preflight["remote"]["fingerprint_after"]["fingerprint_sha256"] = "0" * 64
|
||||
baseline = tmp_path / "preflight.json"
|
||||
state.write_json(baseline, preflight)
|
||||
post_args = args_for(packet, tmp_path, phase="postflight")
|
||||
post_args.baseline = baseline
|
||||
post_args.subject_ref = "c0000000"
|
||||
|
||||
postflight = state.collect_state(post_args, runner=GoodRunner())
|
||||
|
||||
assert postflight["status"] == "fail"
|
||||
assert postflight["baseline_checks"]["canonical_fingerprint_matches_preflight"] is False
|
||||
|
||||
|
||||
def test_subject_sql_rejects_untrusted_input() -> None:
|
||||
try:
|
||||
state.subject_readback_sql("c0000000'; delete from public.claims; --")
|
||||
except ValueError as exc:
|
||||
assert "subject_ref" in str(exc)
|
||||
else:
|
||||
raise AssertionError("unsafe subject ref was accepted")
|
||||
|
||||
|
||||
class NoSshRunner:
|
||||
def __init__(self) -> None:
|
||||
self.calls = 0
|
||||
|
||||
def __call__(self, _command: list[str], _input_text: str, _timeout: int) -> state.CommandResult:
|
||||
self.calls += 1
|
||||
raise AssertionError("SSH runner must not be called after local fail-closed rejection")
|
||||
|
||||
|
||||
def test_write_capable_manifest_override_is_rejected_before_ssh(tmp_path: Path) -> None:
|
||||
packet = write_packet(tmp_path)
|
||||
malicious = tmp_path / "write.sql"
|
||||
malicious.write_text(
|
||||
"\\set ON_ERROR_STOP on\nbegin;\nupdate public.claims set status = 'live';\ncommit;\n",
|
||||
encoding="utf-8",
|
||||
)
|
||||
args = args_for(packet, tmp_path)
|
||||
args.manifest_sql = malicious
|
||||
runner = NoSshRunner()
|
||||
|
||||
result = state.collect_state(args, runner=runner)
|
||||
|
||||
assert result["status"] == "fail"
|
||||
assert result["packet_checks"]["manifest_override_absent_or_exact_canonical_path"] is False
|
||||
assert result["remote"]["readback_attempts"] == {}
|
||||
assert runner.calls == 0
|
||||
assert state._manifest_sql_is_statically_read_only(malicious.read_text(encoding="utf-8")) is False
|
||||
|
||||
|
||||
def test_manifest_hash_mismatch_is_rejected_before_ssh(tmp_path: Path) -> None:
|
||||
packet_path = write_packet(tmp_path)
|
||||
packet = json.loads(packet_path.read_text(encoding="utf-8"))
|
||||
packet["manifest_binding"]["sha256"] = "0" * 64
|
||||
packet_path.write_text(json.dumps(packet), encoding="utf-8")
|
||||
runner = NoSshRunner()
|
||||
|
||||
result = state.collect_state(args_for(packet_path, tmp_path), runner=runner)
|
||||
|
||||
assert result["status"] == "fail"
|
||||
assert result["packet_checks"]["manifest_packet_sha256_matches_canonical_file"] is False
|
||||
assert result["remote"]["readback_attempts"] == {}
|
||||
assert runner.calls == 0
|
||||
|
||||
|
||||
def test_cli_removes_arbitrary_manifest_override() -> None:
|
||||
with pytest.raises(SystemExit):
|
||||
state.parse_args(["--manifest-sql", "write.sql"])
|
||||
|
||||
|
||||
def test_fingerprint_command_enforces_read_only_session_role_and_disables_psql_rc() -> None:
|
||||
command = state.fingerprint_readback_command()
|
||||
|
||||
assert "default_transaction_read_only=on" in command
|
||||
assert "-c transaction_read_only=on" in command
|
||||
assert f"role={packet_builder.READ_ONLY_DB_ROLE}" in command
|
||||
assert "psql -X" in command
|
||||
|
|
@ -4,6 +4,8 @@ import json
|
|||
import subprocess
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
|
||||
from scripts import leo_behavior_manifest as manifest
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
|
|
@ -58,6 +60,11 @@ gateway:
|
|||
assert '{"private":"conversation"}' not in encoded
|
||||
|
||||
|
||||
def test_identity_config_rejects_nonboolean_smart_model_routing() -> None:
|
||||
with pytest.raises(ValueError, match="smart_model_routing must be boolean"):
|
||||
manifest.identity_config_projection({"smart_model_routing": {"route": "untrusted"}})
|
||||
|
||||
|
||||
def test_behavior_manifest_changes_when_a_behavior_layer_changes(tmp_path: Path) -> None:
|
||||
profile = tmp_path / "profile"
|
||||
hermes = tmp_path / "hermes"
|
||||
|
|
@ -156,3 +163,64 @@ def test_git_state_marks_untracked_files_dirty(tmp_path: Path) -> None:
|
|||
|
||||
assert state["worktree_clean"] is False
|
||||
assert len(str(state["status_sha256"])) == 64
|
||||
|
||||
|
||||
def test_identity_runtime_omits_secret_values_but_pins_semantic_model_settings(tmp_path: Path) -> None:
|
||||
profile = tmp_path / "profile"
|
||||
hermes = tmp_path / "hermes"
|
||||
deployment = tmp_path / "deployment"
|
||||
config = """model:
|
||||
provider: fixture
|
||||
default: identity-v1
|
||||
max_tokens: 512
|
||||
gateway:
|
||||
telegram:
|
||||
bot_token: token-a
|
||||
botToken: camel-token-a
|
||||
provider:
|
||||
apiKey: camel-api-key-a
|
||||
transport:
|
||||
endpoint: https://fixture-user:fixture-password-a@example.invalid/v1
|
||||
headers: ['Authorization: Bearer fixture-header-a']
|
||||
tools:
|
||||
allowed: [identity_readback]
|
||||
identity_runtime:
|
||||
network_send_enabled: false
|
||||
database_write_enabled: false
|
||||
allowed_tools: [identity_readback]
|
||||
"""
|
||||
_write(profile / "config.yaml", config)
|
||||
_write(profile / "skills" / "identity" / "SKILL.md", "identity\n")
|
||||
_write(profile / "plugins" / "identity" / "__init__.py", "BOUNDARY = True\n")
|
||||
_write(profile / "bin" / "identity.py", "READ_ONLY = True\n")
|
||||
_write(hermes / "run_agent.py", "runtime\n")
|
||||
_write(hermes / "agent" / "prompt_builder.py", "prompts\n")
|
||||
for name in (
|
||||
"leo_behavior_manifest.py",
|
||||
"leo_identity_manifest.py",
|
||||
"leo_identity_profile.py",
|
||||
"run_leo_identity_reconstruction_canary.py",
|
||||
):
|
||||
_write(deployment / "scripts" / name, f"# {name}\n")
|
||||
|
||||
before = manifest.build_manifest(profile, hermes, deployment)
|
||||
_write(
|
||||
profile / "config.yaml",
|
||||
config.replace("token-a", "token-b")
|
||||
.replace("camel-api-key-a", "camel-api-key-b")
|
||||
.replace("fixture-password-a", "fixture-password-b")
|
||||
.replace("fixture-header-a", "fixture-header-b"),
|
||||
)
|
||||
secret_rotated = manifest.build_manifest(profile, hermes, deployment)
|
||||
_write(profile / "config.yaml", config.replace("max_tokens: 512", "max_tokens: 1024"))
|
||||
model_changed = manifest.build_manifest(profile, hermes, deployment)
|
||||
|
||||
assert before["behavior_sha256"] != secret_rotated["behavior_sha256"]
|
||||
assert before["identity_runtime_sha256"] == secret_rotated["identity_runtime_sha256"]
|
||||
assert before["identity_runtime_sha256"] != model_changed["identity_runtime_sha256"]
|
||||
encoded = json.dumps(before)
|
||||
assert "token-a" not in encoded
|
||||
assert "camel-token-a" not in encoded
|
||||
assert "camel-api-key-a" not in encoded
|
||||
assert "fixture-password-a" not in encoded
|
||||
assert "fixture-header-a" not in encoded
|
||||
|
|
|
|||
794
tests/test_leo_identity_manifest.py
Normal file
794
tests/test_leo_identity_manifest.py
Normal file
|
|
@ -0,0 +1,794 @@
|
|||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import copy
|
||||
import json
|
||||
import os
|
||||
import subprocess
|
||||
import time
|
||||
from pathlib import Path, PureWindowsPath
|
||||
|
||||
import pytest
|
||||
|
||||
from scripts import leo_behavior_manifest as behavior
|
||||
from scripts import leo_identity_manifest as identity
|
||||
from scripts import leo_identity_profile as profile_runtime
|
||||
from scripts import run_leo_identity_reconstruction_canary as canary
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
COMMITTED_RECEIPTS = (
|
||||
ROOT / "docs/reports/leo-working-state-20260709/leo-reproducible-identity-t2-current.json",
|
||||
ROOT / "docs/reports/leo-working-state-20260709/leo-reproducible-identity-drift-negative-current.json",
|
||||
)
|
||||
|
||||
|
||||
def _write(path: Path, value: str) -> None:
|
||||
path.parent.mkdir(parents=True, exist_ok=True)
|
||||
path.write_text(value, encoding="utf-8")
|
||||
|
||||
|
||||
def _write_json(path: Path, value: dict) -> None:
|
||||
_write(path, json.dumps(value, indent=2, sort_keys=True) + "\n")
|
||||
|
||||
|
||||
def _assert_path_portable_receipt(value: object) -> None:
|
||||
canary._validate_portable_receipt(value)
|
||||
|
||||
|
||||
def _assert_logical_child_execution(child: dict, *, profile_role: str) -> None:
|
||||
logical_command = child["logical_command"]
|
||||
assert "command" not in child
|
||||
assert child["profile_role"] == profile_role
|
||||
assert child["command_serialization"] == "logical_redacted_v1"
|
||||
assert child["actual_argv_persisted"] is False
|
||||
assert logical_command[0] == "<python>"
|
||||
assert logical_command[logical_command.index("--profile") + 1] == "<temporary-profile>"
|
||||
_assert_path_portable_receipt(child)
|
||||
|
||||
|
||||
def _fixture(tmp_path: Path) -> dict[str, Path | dict]:
|
||||
repo = tmp_path / "repo"
|
||||
profile = repo / "profile-template"
|
||||
hermes = repo / "hermes-runtime"
|
||||
compiled = tmp_path / "compiled-profile"
|
||||
_write(
|
||||
profile / "config.yaml",
|
||||
"""model:
|
||||
provider: fixture-local
|
||||
default: identity-v1
|
||||
max_tokens: 512
|
||||
memory:
|
||||
enabled: false
|
||||
gateway:
|
||||
execution_mode: local_no_send
|
||||
telegram:
|
||||
bot_token: never-emit-this-fixture-value
|
||||
transport:
|
||||
endpoint: https://fixture-user:fixture-password@example.invalid/v1
|
||||
headers: ['Authorization: Bearer fixture-secret']
|
||||
tools:
|
||||
allowed: [identity_readback]
|
||||
write_enabled: false
|
||||
identity_runtime:
|
||||
network_send_enabled: false
|
||||
database_write_enabled: false
|
||||
allowed_tools: [identity_readback]
|
||||
""",
|
||||
)
|
||||
_write(profile / "skills" / "identity" / "SKILL.md", "# identity readback\n")
|
||||
_write(profile / "plugins" / "identity" / "__init__.py", "BOUNDARY = True\n")
|
||||
_write(profile / "bin" / "identity_readback.py", "READ_ONLY = True\n")
|
||||
_write(hermes / "run_agent.py", "RUNTIME = 'identity-v1'\n")
|
||||
_write(hermes / "agent" / "prompt_builder.py", "SOUL_IS_GENERATED = True\n")
|
||||
_write(hermes / "gateway" / "run.py", "SESSION_IS_IDENTITY = False\n")
|
||||
_write(hermes / "hermes_cli" / "tools_config.py", "TOOLS = ('identity_readback',)\n")
|
||||
_write(hermes / "tools" / "registry.py", "READ_ONLY = True\n")
|
||||
for name in (
|
||||
"leo_behavior_manifest.py",
|
||||
"leo_identity_manifest.py",
|
||||
"leo_identity_profile.py",
|
||||
"run_leo_identity_reconstruction_canary.py",
|
||||
):
|
||||
_write(repo / "scripts" / name, (ROOT / "scripts" / name).read_text(encoding="utf-8"))
|
||||
|
||||
fingerprint_path = repo / "fixtures" / "database-fingerprint.json"
|
||||
constitution_path = repo / "fixtures" / "constitution.json"
|
||||
database_identity_path = repo / "fixtures" / "database-identity.json"
|
||||
fingerprint = {
|
||||
"schema": identity.DATABASE_FINGERPRINT_SCHEMA,
|
||||
"status": "ok",
|
||||
"environment": "disposable_fixture",
|
||||
"fingerprint_sha256": "1" * 64,
|
||||
"table_rows_sha256": "2" * 64,
|
||||
"structure_sha256": "3" * 64,
|
||||
"table_count": 2,
|
||||
"total_rows": 2,
|
||||
"read_consistency": {
|
||||
"status": "stable_wal_marker",
|
||||
"before": {
|
||||
"database": "fixture",
|
||||
"database_user": "reader",
|
||||
"system_identifier": "12345",
|
||||
"wal_lsn": "0/1",
|
||||
},
|
||||
"after": {
|
||||
"database": "fixture",
|
||||
"database_user": "reader",
|
||||
"system_identifier": "12345",
|
||||
"wal_lsn": "0/1",
|
||||
},
|
||||
},
|
||||
}
|
||||
constitution = {
|
||||
"schema": identity.CONSTITUTION_SCHEMA,
|
||||
"identity_name": "Leo",
|
||||
"rules": [
|
||||
{"id": "evidence", "text": "Never use temporary session memory as canonical evidence."},
|
||||
{"id": "truth", "text": "Fail closed when a pinned identity input drifts."},
|
||||
],
|
||||
}
|
||||
database_identity = {
|
||||
"schema": identity.DATABASE_IDENTITY_SCHEMA,
|
||||
"identity_name": "Leo",
|
||||
"database_fingerprint_sha256": "1" * 64,
|
||||
"source_provenance": {
|
||||
"mode": identity.SYNTHETIC_DATABASE_MODE,
|
||||
"canonical_authority_granted": False,
|
||||
"same_transaction_as_fingerprint": False,
|
||||
"export_receipt_sha256": None,
|
||||
},
|
||||
"records": [
|
||||
{
|
||||
"table": "public.personas",
|
||||
"row_id": "persona-1",
|
||||
"kind": "persona",
|
||||
"rank": 0,
|
||||
"text": "Leo is an evidence-bound reasoning interface.",
|
||||
"status": "active",
|
||||
"evidence_sha256": "a" * 64,
|
||||
},
|
||||
{
|
||||
"table": "public.beliefs",
|
||||
"row_id": "belief-1",
|
||||
"kind": "belief",
|
||||
"rank": 0,
|
||||
"text": "Exact provenance is stronger than plausible recollection.",
|
||||
"status": "active",
|
||||
"evidence_sha256": "b" * 64,
|
||||
},
|
||||
],
|
||||
}
|
||||
_write_json(fingerprint_path, fingerprint)
|
||||
_write_json(constitution_path, constitution)
|
||||
_write_json(database_identity_path, database_identity)
|
||||
|
||||
subprocess.run(["git", "init", "-q", str(repo)], check=True)
|
||||
subprocess.run(["git", "-C", str(repo), "config", "user.email", "test@example.com"], check=True)
|
||||
subprocess.run(["git", "-C", str(repo), "config", "user.name", "Test"], check=True)
|
||||
subprocess.run(["git", "-C", str(repo), "add", "."], check=True)
|
||||
subprocess.run(
|
||||
["git", "-C", str(repo), "commit", "-qm", "fixture"],
|
||||
check=True,
|
||||
env={
|
||||
**dict(__import__("os").environ),
|
||||
"GIT_AUTHOR_DATE": "2026-01-01T00:00:00Z",
|
||||
"GIT_COMMITTER_DATE": "2026-01-01T00:00:00Z",
|
||||
},
|
||||
)
|
||||
behavior_manifest = behavior.build_manifest(profile, hermes, repo)
|
||||
manifest = identity.build_identity_manifest(
|
||||
behavior_manifest=behavior_manifest,
|
||||
database_fingerprint_path=fingerprint_path,
|
||||
constitution_path=constitution_path,
|
||||
database_identity_path=database_identity_path,
|
||||
source_root=repo,
|
||||
)
|
||||
return {
|
||||
"repo": repo,
|
||||
"profile": profile,
|
||||
"hermes": hermes,
|
||||
"compiled": compiled,
|
||||
"fingerprint": fingerprint_path,
|
||||
"constitution": constitution_path,
|
||||
"database_identity": database_identity_path,
|
||||
"behavior": behavior_manifest,
|
||||
"manifest": manifest,
|
||||
}
|
||||
|
||||
|
||||
def _fully_rehash_manifest(fixture: dict[str, Path | dict], manifest: dict) -> None:
|
||||
identity_hash = behavior.canonical_sha256(manifest["identity_inputs"])
|
||||
manifest["identity_inputs_sha256"] = identity_hash
|
||||
fingerprint = identity.load_json(fixture["fingerprint"], "database fingerprint")
|
||||
rules = identity.canonical_rules(identity.load_json(fixture["constitution"], "constitution"))
|
||||
records = identity.canonical_database_records(
|
||||
identity.load_json(fixture["database_identity"], "database identity"),
|
||||
fingerprint_sha256=fingerprint["fingerprint_sha256"],
|
||||
)
|
||||
database_provenance = identity.database_identity_provenance(
|
||||
identity.load_json(fixture["database_identity"], "database identity"),
|
||||
fingerprint=fingerprint,
|
||||
)
|
||||
rendered = identity.render_identity_views(
|
||||
identity_inputs_sha256=identity_hash,
|
||||
database_fingerprint_sha256=fingerprint["fingerprint_sha256"],
|
||||
database_provenance=database_provenance,
|
||||
rules=rules,
|
||||
records=records,
|
||||
)
|
||||
for name, content in rendered.items():
|
||||
manifest["compiled_views"][name]["sha256"] = behavior.sha256_bytes(content.encode("utf-8"))
|
||||
manifest["compiled_views"][name]["generated_from_identity_inputs_sha256"] = identity_hash
|
||||
stable = {key: value for key, value in manifest.items() if key != "manifest_sha256"}
|
||||
manifest["manifest_sha256"] = behavior.canonical_sha256(stable)
|
||||
|
||||
|
||||
def _rehash_behavior_manifest(manifest: dict) -> None:
|
||||
manifest["identity_runtime_sha256"] = behavior.canonical_sha256(behavior.identity_runtime_payload(manifest))
|
||||
manifest["static_runtime_sha256"] = behavior.canonical_sha256(behavior.static_runtime_payload(manifest))
|
||||
manifest["behavior_sha256"] = behavior.canonical_sha256(behavior.stable_manifest_payload(manifest))
|
||||
|
||||
|
||||
def _canary_args(fixture: dict[str, Path | dict], output: Path, *, inject_drift: bool = False) -> argparse.Namespace:
|
||||
return argparse.Namespace(
|
||||
profile_template=fixture["profile"],
|
||||
hermes_root=fixture["hermes"],
|
||||
deployment_root=fixture["repo"],
|
||||
source_root=fixture["repo"],
|
||||
database_fingerprint=fixture["fingerprint"],
|
||||
constitution=fixture["constitution"],
|
||||
database_identity=fixture["database_identity"],
|
||||
output=output,
|
||||
inject_drift_before_restart=inject_drift,
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"private_path",
|
||||
[
|
||||
"/" + "Users/operator/checkout/profile",
|
||||
"/" + "private/tmp/lane/.venv/bin/python",
|
||||
"/" + "var/folders/cache/temporary-profile",
|
||||
"/" + "tmp/temporary-profile",
|
||||
"/" + "opt/checkout/interpreter",
|
||||
"/" + "workspace/checkout/temporary-profile",
|
||||
str(PureWindowsPath("C:/operator/checkout/temporary-profile")),
|
||||
"\\\\" + "server\\share\\checkout\\temporary-profile",
|
||||
],
|
||||
)
|
||||
def test_receipt_path_guard_recursively_rejects_private_and_absolute_paths(private_path: str) -> None:
|
||||
with pytest.raises(canary.CanaryError, match="private or absolute filesystem path"):
|
||||
_assert_path_portable_receipt({"outer": [{"logical_command": ["<python>", private_path]}]})
|
||||
|
||||
|
||||
def test_receipt_path_guard_rejects_an_absolute_path_in_a_nested_key() -> None:
|
||||
private_key = "/" + "tmp/checkout/temporary-profile"
|
||||
with pytest.raises(canary.CanaryError, match="private or absolute filesystem path"):
|
||||
_assert_path_portable_receipt({"outer": [{private_key: "<temporary-profile>"}]})
|
||||
|
||||
|
||||
def test_logical_command_uses_placeholders_for_paths_outside_the_deployment_root(tmp_path: Path) -> None:
|
||||
logical_command = canary._logical_query_command(
|
||||
deployment_root=tmp_path / "checkout",
|
||||
source_root=tmp_path / "outside-source",
|
||||
hermes_root=tmp_path / "outside-hermes",
|
||||
)
|
||||
|
||||
assert logical_command[logical_command.index("--source-root") + 1] == "<source-root>"
|
||||
assert logical_command[logical_command.index("--hermes-root") + 1] == "<hermes-root>"
|
||||
_assert_path_portable_receipt(logical_command)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("receipt_path", COMMITTED_RECEIPTS, ids=lambda path: path.name)
|
||||
def test_committed_identity_receipts_are_path_portable_and_self_hashed(receipt_path: Path) -> None:
|
||||
receipt = json.loads(receipt_path.read_text(encoding="utf-8"))
|
||||
_assert_path_portable_receipt(receipt)
|
||||
stable = {key: value for key, value in receipt.items() if key != "receipt_sha256"}
|
||||
assert behavior.canonical_sha256(stable) == receipt["receipt_sha256"]
|
||||
|
||||
|
||||
def test_manifest_compiles_generated_views_and_reproduces_identity_across_queries(tmp_path: Path) -> None:
|
||||
fixture = _fixture(tmp_path)
|
||||
manifest = fixture["manifest"]
|
||||
assert isinstance(manifest, dict)
|
||||
rebuilt = identity.build_identity_manifest(
|
||||
behavior_manifest=fixture["behavior"],
|
||||
database_fingerprint_path=fixture["fingerprint"],
|
||||
constitution_path=fixture["constitution"],
|
||||
database_identity_path=fixture["database_identity"],
|
||||
source_root=fixture["repo"],
|
||||
)
|
||||
assert rebuilt == manifest
|
||||
|
||||
compile_receipt = profile_runtime.compile_profile(
|
||||
manifest,
|
||||
source_root=fixture["repo"],
|
||||
profile_template=fixture["profile"],
|
||||
profile=fixture["compiled"],
|
||||
hermes_root=fixture["hermes"],
|
||||
deployment_root=fixture["repo"],
|
||||
)
|
||||
first = profile_runtime.query_profile(
|
||||
fixture["compiled"],
|
||||
query=profile_runtime.FIXED_QUERY,
|
||||
source_root=fixture["repo"],
|
||||
hermes_root=fixture["hermes"],
|
||||
deployment_root=fixture["repo"],
|
||||
)
|
||||
second = profile_runtime.query_profile(
|
||||
fixture["compiled"],
|
||||
query=profile_runtime.FIXED_QUERY,
|
||||
source_root=fixture["repo"],
|
||||
hermes_root=fixture["hermes"],
|
||||
deployment_root=fixture["repo"],
|
||||
)
|
||||
|
||||
assert compile_receipt["status"] == "pass"
|
||||
assert "never-emit-this-fixture-value" not in (fixture["compiled"] / "config.yaml").read_text(encoding="utf-8")
|
||||
assert "fixture-password" not in (fixture["compiled"] / "config.yaml").read_text(encoding="utf-8")
|
||||
assert "fixture-secret" not in (fixture["compiled"] / "config.yaml").read_text(encoding="utf-8")
|
||||
assert (fixture["compiled"] / "SOUL.md").read_text(encoding="utf-8").startswith("<!-- GENERATED FILE")
|
||||
assert first["manifest_sha256"] == second["manifest_sha256"]
|
||||
assert first["identity_inputs_sha256"] == second["identity_inputs_sha256"]
|
||||
assert first["answer_sha256"] == second["answer_sha256"]
|
||||
assert first["output_provenance"] == second["output_provenance"]
|
||||
assert first["runtime_instance_id"] != second["runtime_instance_id"]
|
||||
assert first["session"]["included_in_output_provenance"] is False
|
||||
assert first["output_provenance"]["database_canonical_authority_granted"] is False
|
||||
assert first["authorization"]["authorization_decision_observed"] is False
|
||||
assert "synthetic noncanonical fixture" in first["answer"]
|
||||
assert len(list((fixture["compiled"] / "sessions").glob("*.json"))) == 2
|
||||
|
||||
|
||||
def test_profile_and_bound_source_drift_fail_closed(tmp_path: Path) -> None:
|
||||
fixture = _fixture(tmp_path)
|
||||
profile_runtime.compile_profile(
|
||||
fixture["manifest"],
|
||||
source_root=fixture["repo"],
|
||||
profile_template=fixture["profile"],
|
||||
profile=fixture["compiled"],
|
||||
hermes_root=fixture["hermes"],
|
||||
deployment_root=fixture["repo"],
|
||||
)
|
||||
with (fixture["compiled"] / "SOUL.md").open("a", encoding="utf-8") as handle:
|
||||
handle.write("drift\n")
|
||||
with pytest.raises(identity.IdentityManifestError, match="compiled view drift detected"):
|
||||
profile_runtime.query_profile(
|
||||
fixture["compiled"],
|
||||
query=profile_runtime.FIXED_QUERY,
|
||||
source_root=fixture["repo"],
|
||||
hermes_root=fixture["hermes"],
|
||||
deployment_root=fixture["repo"],
|
||||
)
|
||||
|
||||
_write(fixture["constitution"], fixture["constitution"].read_text(encoding="utf-8") + "\n")
|
||||
with pytest.raises(identity.IdentityManifestError, match="constitution source content drift"):
|
||||
identity.verify_bound_sources(fixture["manifest"], fixture["repo"])
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("relative_path", "content", "message"),
|
||||
[
|
||||
("memories/USER.md", "untrusted memory\n", "forbidden nonauthoritative"),
|
||||
("MEMORY.md", "untrusted top-level memory\n", "forbidden nonauthoritative"),
|
||||
("USER.md", "untrusted top-level user memory\n", "forbidden nonauthoritative"),
|
||||
("platforms/pairing/telegram.json", "{}\n", "forbidden nonauthoritative"),
|
||||
(".env", "LEO_SECRET=untrusted\n", "profile entry set is not exact"),
|
||||
("gateway.json", "{}\n", "profile entry set is not exact"),
|
||||
("unexpected.txt", "untrusted input\n", "profile entry set is not exact"),
|
||||
("sessions/injected.txt", "untrusted session\n", "unsafe session entry"),
|
||||
("state/injected.json", "{}\n", "state directory must remain empty"),
|
||||
],
|
||||
)
|
||||
def test_profile_rechecks_nonauthoritative_surfaces_before_every_query(
|
||||
tmp_path: Path, relative_path: str, content: str, message: str
|
||||
) -> None:
|
||||
fixture = _fixture(tmp_path)
|
||||
profile_runtime.compile_profile(
|
||||
fixture["manifest"],
|
||||
source_root=fixture["repo"],
|
||||
profile_template=fixture["profile"],
|
||||
profile=fixture["compiled"],
|
||||
hermes_root=fixture["hermes"],
|
||||
deployment_root=fixture["repo"],
|
||||
)
|
||||
_write(fixture["compiled"] / relative_path, content)
|
||||
|
||||
with pytest.raises(profile_runtime.IdentityProfileError, match=message):
|
||||
profile_runtime.query_profile(
|
||||
fixture["compiled"],
|
||||
query=profile_runtime.FIXED_QUERY,
|
||||
source_root=fixture["repo"],
|
||||
hermes_root=fixture["hermes"],
|
||||
deployment_root=fixture["repo"],
|
||||
)
|
||||
|
||||
|
||||
def test_manifest_rejects_rehashed_core_tampering(tmp_path: Path) -> None:
|
||||
fixture = _fixture(tmp_path)
|
||||
tampered = copy.deepcopy(fixture["manifest"])
|
||||
tampered["identity_inputs"]["session_boundary"]["may_be_used_as_evidence"] = True
|
||||
stable = {key: value for key, value in tampered.items() if key != "manifest_sha256"}
|
||||
tampered["manifest_sha256"] = behavior.canonical_sha256(stable)
|
||||
|
||||
with pytest.raises(identity.IdentityManifestError, match="identity input hash drift"):
|
||||
identity.validate_identity_manifest(tampered)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("path", "value", "message"),
|
||||
[
|
||||
(("permissions", "runtime_policy", "network_send_enabled"), True, "exact local readback policy"),
|
||||
(("session_boundary", "may_be_used_as_evidence"), True, "session authority boundary"),
|
||||
],
|
||||
)
|
||||
def test_manifest_rejects_fully_rehashed_safety_invariant_tampering(
|
||||
tmp_path: Path, path: tuple[str, ...], value: object, message: str
|
||||
) -> None:
|
||||
fixture = _fixture(tmp_path)
|
||||
tampered = copy.deepcopy(fixture["manifest"])
|
||||
target = tampered["identity_inputs"]
|
||||
for key in path[:-1]:
|
||||
target = target[key]
|
||||
target[path[-1]] = value
|
||||
_fully_rehash_manifest(fixture, tampered)
|
||||
|
||||
with pytest.raises(identity.IdentityManifestError, match=message):
|
||||
identity.verify_bound_sources(tampered, fixture["repo"])
|
||||
|
||||
|
||||
def test_behavior_manifest_rejects_unhashed_model_claim_tampering(tmp_path: Path) -> None:
|
||||
fixture = _fixture(tmp_path)
|
||||
tampered_behavior = copy.deepcopy(fixture["behavior"])
|
||||
tampered_behavior["model_runtime"]["default_model"] = "tampered-unobserved-model"
|
||||
|
||||
with pytest.raises(identity.IdentityManifestError, match="behavior identity runtime hash drift"):
|
||||
identity.build_identity_manifest(
|
||||
behavior_manifest=tampered_behavior,
|
||||
database_fingerprint_path=fixture["fingerprint"],
|
||||
constitution_path=fixture["constitution"],
|
||||
database_identity_path=fixture["database_identity"],
|
||||
source_root=fixture["repo"],
|
||||
)
|
||||
|
||||
|
||||
def test_profile_rejects_a_dangling_extra_symlink(tmp_path: Path) -> None:
|
||||
fixture = _fixture(tmp_path)
|
||||
profile_runtime.compile_profile(
|
||||
fixture["manifest"],
|
||||
source_root=fixture["repo"],
|
||||
profile_template=fixture["profile"],
|
||||
profile=fixture["compiled"],
|
||||
hermes_root=fixture["hermes"],
|
||||
deployment_root=fixture["repo"],
|
||||
)
|
||||
(fixture["compiled"] / ".env").symlink_to(tmp_path / "missing-env")
|
||||
|
||||
with pytest.raises(profile_runtime.IdentityProfileError, match="profile entry set is not exact"):
|
||||
profile_runtime.query_profile(
|
||||
fixture["compiled"],
|
||||
query=profile_runtime.FIXED_QUERY,
|
||||
source_root=fixture["repo"],
|
||||
hermes_root=fixture["hermes"],
|
||||
deployment_root=fixture["repo"],
|
||||
)
|
||||
|
||||
|
||||
def test_profile_rejects_a_symlink_in_an_allowed_entry(tmp_path: Path) -> None:
|
||||
fixture = _fixture(tmp_path)
|
||||
profile_runtime.compile_profile(
|
||||
fixture["manifest"],
|
||||
source_root=fixture["repo"],
|
||||
profile_template=fixture["profile"],
|
||||
profile=fixture["compiled"],
|
||||
hermes_root=fixture["hermes"],
|
||||
deployment_root=fixture["repo"],
|
||||
)
|
||||
external_config = tmp_path / "external-config.yaml"
|
||||
external_config.write_bytes((fixture["compiled"] / "config.yaml").read_bytes())
|
||||
(fixture["compiled"] / "config.yaml").unlink()
|
||||
(fixture["compiled"] / "config.yaml").symlink_to(external_config)
|
||||
|
||||
with pytest.raises(profile_runtime.IdentityProfileError, match="profile entries must not be symlinks"):
|
||||
profile_runtime.query_profile(
|
||||
fixture["compiled"],
|
||||
query=profile_runtime.FIXED_QUERY,
|
||||
source_root=fixture["repo"],
|
||||
hermes_root=fixture["hermes"],
|
||||
deployment_root=fixture["repo"],
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("mutation", "message"),
|
||||
[
|
||||
("unreadable_file", "unreadable inputs"),
|
||||
("symlink", "unsupported symlinks"),
|
||||
("forged_structure", "is empty"),
|
||||
],
|
||||
)
|
||||
def test_behavior_manifest_rejects_unreplayable_identity_components(
|
||||
tmp_path: Path, mutation: str, message: str
|
||||
) -> None:
|
||||
fixture = _fixture(tmp_path)
|
||||
tampered_behavior = copy.deepcopy(fixture["behavior"])
|
||||
content = tampered_behavior["components"]["procedural_skills"]["content"]
|
||||
if mutation == "unreadable_file":
|
||||
content["files"][0].pop("sha256")
|
||||
content["files"][0]["status"] = "unavailable"
|
||||
elif mutation == "symlink":
|
||||
content["symlinks"].append(
|
||||
{
|
||||
"path": "skills/identity/link",
|
||||
"target": "/outside/checkout",
|
||||
"target_fingerprint": {"kind": "unavailable", "error": "FileNotFoundError"},
|
||||
}
|
||||
)
|
||||
else:
|
||||
content["files"] = []
|
||||
content["sha256"] = behavior.canonical_sha256({key: content[key] for key in ("files", "missing", "symlinks")})
|
||||
_rehash_behavior_manifest(tampered_behavior)
|
||||
|
||||
with pytest.raises(identity.IdentityManifestError, match=message):
|
||||
identity.validate_behavior_manifest(tampered_behavior)
|
||||
|
||||
|
||||
def test_fully_rehashed_model_claim_must_match_observed_runtime(tmp_path: Path) -> None:
|
||||
fixture = _fixture(tmp_path)
|
||||
tampered = copy.deepcopy(fixture["manifest"])
|
||||
tampered["identity_inputs"]["model"]["default_model"] = "tampered-unobserved-model"
|
||||
_fully_rehash_manifest(fixture, tampered)
|
||||
identity.validate_identity_manifest(tampered)
|
||||
|
||||
with pytest.raises(
|
||||
profile_runtime.IdentityProfileError, match="model runtime binding drift detected: default_model"
|
||||
):
|
||||
profile_runtime.compile_profile(
|
||||
tampered,
|
||||
source_root=fixture["repo"],
|
||||
profile_template=fixture["profile"],
|
||||
profile=fixture["compiled"],
|
||||
hermes_root=fixture["hermes"],
|
||||
deployment_root=fixture["repo"],
|
||||
)
|
||||
assert not fixture["compiled"].exists()
|
||||
|
||||
|
||||
def test_restart_canary_uses_distinct_processes_and_cleans_up(tmp_path: Path) -> None:
|
||||
fixture = _fixture(tmp_path)
|
||||
output = tmp_path / "restart-receipt.json"
|
||||
report, exit_code = canary.run_canary(_canary_args(fixture, output))
|
||||
|
||||
assert exit_code == 0
|
||||
assert report["status"] == "pass"
|
||||
assert report["gates"]["restart_process_is_distinct"] is True
|
||||
assert report["gates"]["restart_profile_recompiled_from_manifest"] is True
|
||||
assert report["restart_compile"]["session_directories_started_empty"] is True
|
||||
assert report["drift_compile"]["session_directories_started_empty"] is True
|
||||
_assert_logical_child_execution(report["first_start"], profile_role="first_start")
|
||||
_assert_logical_child_execution(report["restart"], profile_role="restart")
|
||||
_assert_logical_child_execution(report["drift_negative"], profile_role="drift_negative")
|
||||
_assert_path_portable_receipt(report)
|
||||
assert report["first_start"]["launcher_pid"] != report["restart"]["launcher_pid"]
|
||||
assert report["first_start"]["process_group_absent_after_wait"] is True
|
||||
assert report["restart"]["process_group_absent_after_wait"] is True
|
||||
assert report["drift_negative"]["fail_closed"] is True
|
||||
assert report["drift_negative"]["process_group_absent_after_wait"] is True
|
||||
assert report["goal_tier_satisfied"] is True
|
||||
assert report["current_tier"] == "T2_runtime"
|
||||
assert report["cleanup"]["temporary_root_removed"] is True
|
||||
assert behavior.git_state(fixture["repo"])["worktree_clean"] is True
|
||||
assert json.loads(output.read_text(encoding="utf-8")) == report
|
||||
|
||||
|
||||
def test_restart_canary_rejects_drift_before_second_start(tmp_path: Path) -> None:
|
||||
fixture = _fixture(tmp_path)
|
||||
output = tmp_path / "drift-receipt.json"
|
||||
report, exit_code = canary.run_canary(_canary_args(fixture, output, inject_drift=True))
|
||||
|
||||
assert exit_code == 0
|
||||
assert report["status"] == "pass"
|
||||
assert report["gates"]["drift_detected_before_restart"] is True
|
||||
assert report["second_start_attempted"] is False
|
||||
assert "restart" not in report
|
||||
_assert_logical_child_execution(report["first_start"], profile_role="first_start")
|
||||
_assert_logical_child_execution(report["pre_restart_drift"], profile_role="pre_restart_drift")
|
||||
_assert_path_portable_receipt(report)
|
||||
assert report["pre_restart_drift"]["process_group_absent_after_wait"] is True
|
||||
assert all(report["gates"].values())
|
||||
assert report["goal_tier_satisfied"] is False
|
||||
assert report["current_tier"] == "T1_model"
|
||||
assert report["cleanup"]["temporary_root_removed"] is True
|
||||
assert json.loads(output.read_text(encoding="utf-8")) == report
|
||||
|
||||
|
||||
def test_query_child_timeout_terminates_process_group(tmp_path: Path) -> None:
|
||||
fixture = _fixture(tmp_path)
|
||||
marker = tmp_path / "descendant.pid"
|
||||
sleeping_module = f"""import subprocess
|
||||
import sys
|
||||
import time
|
||||
from pathlib import Path
|
||||
|
||||
child = subprocess.Popen([sys.executable, '-c', 'import time; time.sleep(60)'])
|
||||
Path({str(marker)!r}).write_text(str(child.pid), encoding='utf-8')
|
||||
time.sleep(60)
|
||||
"""
|
||||
_write(fixture["repo"] / "scripts" / "leo_identity_profile.py", sleeping_module)
|
||||
|
||||
result = canary._run_query_child(
|
||||
deployment_root=fixture["repo"],
|
||||
profile=fixture["compiled"],
|
||||
source_root=fixture["repo"],
|
||||
hermes_root=fixture["hermes"],
|
||||
profile_role="timeout_test",
|
||||
timeout_seconds=0.5,
|
||||
)
|
||||
|
||||
assert result["timed_out"] is True
|
||||
assert result["terminated_with"] in {"SIGTERM", "SIGKILL"}
|
||||
assert result["returncode"] != 0
|
||||
assert result["process_group_absent_after_wait"] is True
|
||||
descendant_pid = int(marker.read_text(encoding="utf-8"))
|
||||
deadline = time.monotonic() + 5
|
||||
while time.monotonic() < deadline:
|
||||
try:
|
||||
os.kill(descendant_pid, 0)
|
||||
except ProcessLookupError:
|
||||
break
|
||||
time.sleep(0.02)
|
||||
with pytest.raises(ProcessLookupError):
|
||||
os.kill(descendant_pid, 0)
|
||||
|
||||
|
||||
def test_query_child_cleans_and_rejects_orphan_from_completed_launcher(tmp_path: Path) -> None:
|
||||
fixture = _fixture(tmp_path)
|
||||
marker = tmp_path / "completed-descendant.pid"
|
||||
query_payload = {"schema": profile_runtime.QUERY_RECEIPT_SCHEMA, "status": "pass"}
|
||||
leaking_module = f"""import json
|
||||
import subprocess
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
child = subprocess.Popen(
|
||||
[sys.executable, '-c', 'import time; time.sleep(60)'],
|
||||
stdin=subprocess.DEVNULL,
|
||||
stdout=subprocess.DEVNULL,
|
||||
stderr=subprocess.DEVNULL,
|
||||
)
|
||||
Path({str(marker)!r}).write_text(str(child.pid), encoding='utf-8')
|
||||
print(json.dumps({query_payload!r}))
|
||||
"""
|
||||
_write(fixture["repo"] / "scripts" / "leo_identity_profile.py", leaking_module)
|
||||
|
||||
result = canary._run_query_child(
|
||||
deployment_root=fixture["repo"],
|
||||
profile=fixture["compiled"],
|
||||
source_root=fixture["repo"],
|
||||
hermes_root=fixture["hermes"],
|
||||
profile_role="orphan_cleanup_test",
|
||||
timeout_seconds=5,
|
||||
)
|
||||
|
||||
assert result["returncode"] == 0
|
||||
assert result["orphan_cleanup_required"] is True
|
||||
assert result["terminated_with"] in {"SIGTERM", "SIGKILL"}
|
||||
assert result["process_group_absent_after_wait"] is True
|
||||
assert canary._query_passed(result) is False
|
||||
|
||||
|
||||
def test_wal_capture_marker_is_not_an_identity_input(tmp_path: Path) -> None:
|
||||
fixture = _fixture(tmp_path)
|
||||
original = fixture["manifest"]
|
||||
fingerprint = json.loads(fixture["fingerprint"].read_text(encoding="utf-8"))
|
||||
fingerprint["read_consistency"]["before"]["wal_lsn"] = "0/2"
|
||||
fingerprint["read_consistency"]["after"]["wal_lsn"] = "0/2"
|
||||
_write_json(fixture["fingerprint"], fingerprint)
|
||||
rebuilt = identity.build_identity_manifest(
|
||||
behavior_manifest=fixture["behavior"],
|
||||
database_fingerprint_path=fixture["fingerprint"],
|
||||
constitution_path=fixture["constitution"],
|
||||
database_identity_path=fixture["database_identity"],
|
||||
source_root=fixture["repo"],
|
||||
)
|
||||
|
||||
assert rebuilt["identity_inputs_sha256"] == original["identity_inputs_sha256"]
|
||||
assert rebuilt["manifest_sha256"] == original["manifest_sha256"]
|
||||
|
||||
|
||||
def test_database_identity_and_system_markers_are_identity_inputs(tmp_path: Path) -> None:
|
||||
fixture = _fixture(tmp_path)
|
||||
original = fixture["manifest"]
|
||||
fingerprint = json.loads(fixture["fingerprint"].read_text(encoding="utf-8"))
|
||||
for marker in (fingerprint["read_consistency"]["before"], fingerprint["read_consistency"]["after"]):
|
||||
marker["database"] = "different_database"
|
||||
marker["database_user"] = "different_reader"
|
||||
marker["system_identifier"] = "99999"
|
||||
_write_json(fixture["fingerprint"], fingerprint)
|
||||
rebuilt = identity.build_identity_manifest(
|
||||
behavior_manifest=fixture["behavior"],
|
||||
database_fingerprint_path=fixture["fingerprint"],
|
||||
constitution_path=fixture["constitution"],
|
||||
database_identity_path=fixture["database_identity"],
|
||||
source_root=fixture["repo"],
|
||||
)
|
||||
|
||||
assert rebuilt["identity_inputs_sha256"] != original["identity_inputs_sha256"]
|
||||
with pytest.raises(identity.IdentityManifestError, match="database fingerprint semantic drift"):
|
||||
identity.verify_bound_sources(original, fixture["repo"])
|
||||
|
||||
|
||||
def test_synthetic_database_rows_cannot_claim_canonical_authority(tmp_path: Path) -> None:
|
||||
fixture = _fixture(tmp_path)
|
||||
database_identity = json.loads(fixture["database_identity"].read_text(encoding="utf-8"))
|
||||
database_identity["source_provenance"] = {
|
||||
"mode": identity.CANONICAL_DATABASE_MODE,
|
||||
"canonical_authority_granted": True,
|
||||
"same_transaction_as_fingerprint": True,
|
||||
"export_receipt_sha256": "f" * 64,
|
||||
}
|
||||
_write_json(fixture["database_identity"], database_identity)
|
||||
|
||||
with pytest.raises(identity.IdentityManifestError, match="independently verified output"):
|
||||
identity.build_identity_manifest(
|
||||
behavior_manifest=fixture["behavior"],
|
||||
database_fingerprint_path=fixture["fingerprint"],
|
||||
constitution_path=fixture["constitution"],
|
||||
database_identity_path=fixture["database_identity"],
|
||||
source_root=fixture["repo"],
|
||||
)
|
||||
|
||||
|
||||
def test_self_hashed_database_export_receipt_cannot_grant_canonical_authority(tmp_path: Path) -> None:
|
||||
fixture = _fixture(tmp_path)
|
||||
fingerprint = json.loads(fixture["fingerprint"].read_text(encoding="utf-8"))
|
||||
fingerprint["environment"] = "canonical_readonly_capture"
|
||||
_write_json(fixture["fingerprint"], fingerprint)
|
||||
database_identity = json.loads(fixture["database_identity"].read_text(encoding="utf-8"))
|
||||
records = identity.canonical_database_records(
|
||||
database_identity,
|
||||
fingerprint_sha256=fingerprint["fingerprint_sha256"],
|
||||
)
|
||||
marker = fingerprint["read_consistency"]["before"]
|
||||
receipt_stable = {
|
||||
"schema": "livingip.untrustedCallerSuppliedExportReceipt.v1",
|
||||
"read_only": True,
|
||||
"same_transaction_as_fingerprint": True,
|
||||
"transaction_isolation": "repeatable_read_read_only",
|
||||
"database": marker["database"],
|
||||
"database_user": marker["database_user"],
|
||||
"system_identifier": marker["system_identifier"],
|
||||
"database_fingerprint_sha256": fingerprint["fingerprint_sha256"],
|
||||
"records_sha256": behavior.canonical_sha256(records),
|
||||
}
|
||||
receipt_hash = behavior.canonical_sha256(receipt_stable)
|
||||
database_identity["source_provenance"] = {
|
||||
"mode": identity.CANONICAL_DATABASE_MODE,
|
||||
"canonical_authority_granted": True,
|
||||
"same_transaction_as_fingerprint": True,
|
||||
"export_receipt_sha256": receipt_hash,
|
||||
}
|
||||
database_identity["export_receipt"] = {**receipt_stable, "receipt_sha256": receipt_hash}
|
||||
_write_json(fixture["database_identity"], database_identity)
|
||||
|
||||
with pytest.raises(identity.IdentityManifestError, match="independently verified output"):
|
||||
identity.build_identity_manifest(
|
||||
behavior_manifest=fixture["behavior"],
|
||||
database_fingerprint_path=fixture["fingerprint"],
|
||||
constitution_path=fixture["constitution"],
|
||||
database_identity_path=fixture["database_identity"],
|
||||
source_root=fixture["repo"],
|
||||
)
|
||||
|
||||
|
||||
def test_same_clean_commit_reproduces_identity_from_different_checkout_paths(tmp_path: Path) -> None:
|
||||
first = _fixture(tmp_path / "checkout-a")
|
||||
second = _fixture(tmp_path / "checkout-b")
|
||||
|
||||
assert (
|
||||
first["behavior"]["teleo_infrastructure_runtime"]["git_head"]
|
||||
== second["behavior"]["teleo_infrastructure_runtime"]["git_head"]
|
||||
)
|
||||
assert first["behavior"]["identity_runtime_sha256"] == second["behavior"]["identity_runtime_sha256"]
|
||||
assert first["manifest"]["identity_inputs_sha256"] == second["manifest"]["identity_inputs_sha256"]
|
||||
assert first["manifest"]["manifest_sha256"] == second["manifest"]["manifest_sha256"]
|
||||
1010
tests/test_proposal_apply_lifecycle.py
Normal file
1010
tests/test_proposal_apply_lifecycle.py
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -13,6 +13,11 @@ sys.path.insert(0, str(ROOT / "scripts"))
|
|||
import run_approve_claim_clone_canary as canary # noqa: E402
|
||||
|
||||
|
||||
def test_unrelated_fingerprint_orders_legacy_claim_evidence_by_composite_key() -> None:
|
||||
assert canary.CLAIM_EVIDENCE_FINGERPRINT_ORDER == ("ce.claim_id::text, ce.source_id::text, ce.role::text")
|
||||
assert "ce.id" not in canary.CLAIM_EVIDENCE_FINGERPRINT_ORDER
|
||||
|
||||
|
||||
def _passing_result(expected_rows: dict, expected_deltas: dict) -> dict:
|
||||
proposal_id = "aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa"
|
||||
return {
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@
|
|||
|
||||
from __future__ import annotations
|
||||
|
||||
import hashlib
|
||||
import json
|
||||
import subprocess
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
|
@ -11,8 +13,10 @@ import pytest
|
|||
ROOT = Path(__file__).resolve().parents[1]
|
||||
sys.path.insert(0, str(ROOT / "scripts"))
|
||||
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 finalize_approve_claim_isolated_canary as finalizer # 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(
|
||||
canary.shutil,
|
||||
"which",
|
||||
lambda executable: "/opt/homebrew/bin/docker"
|
||||
if executable == "docker"
|
||||
else None,
|
||||
lambda executable: "/opt/homebrew/bin/docker" if executable == "docker" else None,
|
||||
)
|
||||
|
||||
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(
|
||||
apply.shutil,
|
||||
"which",
|
||||
lambda executable: "/opt/homebrew/bin/docker"
|
||||
if executable == "docker"
|
||||
else None,
|
||||
lambda executable: "/opt/homebrew/bin/docker" if executable == "docker" else None,
|
||||
)
|
||||
|
||||
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:
|
||||
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 "--network none" 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_MOUNTS_JSON="$container_mounts_json"' in text
|
||||
assert 'data["checks"]["outer_source_tier_enforced"]' in text
|
||||
assert 'data["checks"]["outer_container_network_disabled"]' in text
|
||||
assert 'data["checks"]["outer_container_has_no_docker_volumes"]' in text
|
||||
assert 'checks["outer_source_tier_enforced"]' in text
|
||||
assert 'checks["outer_container_network_disabled"]' in text
|
||||
assert 'checks["outer_container_has_no_docker_volumes"]' 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
|
||||
|
|
|
|||
766
tests/test_verify_telegram_visible_unseen_chain.py
Normal file
766
tests/test_verify_telegram_visible_unseen_chain.py
Normal file
|
|
@ -0,0 +1,766 @@
|
|||
from __future__ import annotations
|
||||
|
||||
import copy
|
||||
import hashlib
|
||||
import json
|
||||
import struct
|
||||
import zlib
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
|
||||
from scripts import build_telegram_visible_unseen_chain_packet as packet_builder
|
||||
from scripts import collect_telegram_visible_unseen_chain_state as state_collector
|
||||
from scripts import verify_telegram_visible_unseen_chain as verifier
|
||||
|
||||
SUBJECT_ID = "c0000000-0000-4000-8000-000000000001"
|
||||
CHALLENGE_NONCE = "a" * 64
|
||||
TURN_CAPTURE_CALL_IDS = ["call_chrome_turn_1", "call_chrome_turn_2", "call_chrome_turn_3"]
|
||||
FINAL_CAPTURE_CALL_ID = "call_chrome_final"
|
||||
|
||||
|
||||
def packet_and_path(tmp_path: Path) -> tuple[dict, Path]:
|
||||
packet = packet_builder.build_packet(
|
||||
handler_receipt_path=packet_builder.DEFAULT_HANDLER_RECEIPT.resolve(),
|
||||
git_sha="a" * 40,
|
||||
)
|
||||
path = tmp_path / "packet.json"
|
||||
packet_builder.write_json(path, packet)
|
||||
return packet, path
|
||||
|
||||
|
||||
def _finish_state_token(value: dict) -> dict:
|
||||
value["state_token_sha256"] = state_collector.derive_state_token(value)
|
||||
return value
|
||||
|
||||
|
||||
def preflight(packet: dict, packet_path: Path) -> dict:
|
||||
return _finish_state_token(
|
||||
{
|
||||
"schema": state_collector.SCHEMA,
|
||||
"generated_at_utc": "2026-07-14T23:59:00+00:00",
|
||||
"phase": "preflight",
|
||||
"status": "pass",
|
||||
"protocol_sha256": packet["protocol_sha256"],
|
||||
"packet_file_sha256": verifier._sha256_file(packet_path),
|
||||
"manifest_binding": packet["manifest_binding"],
|
||||
"capture_challenge_nonce": CHALLENGE_NONCE,
|
||||
"baseline_state_token_sha256": "",
|
||||
"subject_ref": "",
|
||||
"packet_checks": {"fixture_packet_checks_pass": True},
|
||||
"remote_checks": {"fixture_remote_checks_pass": True},
|
||||
"baseline_checks": {},
|
||||
"remote": {
|
||||
"deploy_head": "d" * 40,
|
||||
"last_deploy_sha": "d" * 40,
|
||||
"fingerprint_after": {"fingerprint_sha256": "f" * 64},
|
||||
"service_after": {
|
||||
"MainPID": "123",
|
||||
"NRestarts": "0",
|
||||
"ExecMainStartTimestamp": "Wed 2026-07-15 00:00:00 UTC",
|
||||
},
|
||||
"subject_readback": None,
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
def postflight(packet: dict, packet_path: Path, before: dict) -> dict:
|
||||
return _finish_state_token(
|
||||
{
|
||||
"schema": state_collector.SCHEMA,
|
||||
"generated_at_utc": "2026-07-15T00:04:00Z",
|
||||
"phase": "postflight",
|
||||
"status": "pass",
|
||||
"protocol_sha256": packet["protocol_sha256"],
|
||||
"packet_file_sha256": verifier._sha256_file(packet_path),
|
||||
"manifest_binding": packet["manifest_binding"],
|
||||
"capture_challenge_nonce": CHALLENGE_NONCE,
|
||||
"baseline_state_token_sha256": before["state_token_sha256"],
|
||||
"subject_ref": "c0000000",
|
||||
"packet_checks": {"fixture_packet_checks_pass": True},
|
||||
"remote_checks": {"fixture_remote_checks_pass": True},
|
||||
"baseline_checks": {"fixture_baseline_checks_pass": True},
|
||||
"remote": {
|
||||
"deploy_head": "d" * 40,
|
||||
"last_deploy_sha": "d" * 40,
|
||||
"fingerprint_after": {"fingerprint_sha256": "f" * 64},
|
||||
"service_after": {
|
||||
"MainPID": "123",
|
||||
"NRestarts": "0",
|
||||
"ExecMainStartTimestamp": "Wed 2026-07-15 00:00:00 UTC",
|
||||
},
|
||||
"subject_readback": {
|
||||
"subject_ref": "c0000000",
|
||||
"matches": [
|
||||
{
|
||||
"table": "public.beliefs",
|
||||
"row": {"id": SUBJECT_ID, "statement": "Coordination is the bottleneck."},
|
||||
}
|
||||
],
|
||||
},
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
def write_png(path: Path, rgba: tuple[int, int, int, int]) -> None:
|
||||
width = verifier.MIN_SCREENSHOT_WIDTH
|
||||
height = verifier.MIN_SCREENSHOT_HEIGHT
|
||||
scanline = b"\x00" + bytes(rgba) * width
|
||||
pixels = scanline * height
|
||||
|
||||
def chunk(kind: bytes, payload: bytes) -> bytes:
|
||||
return (
|
||||
struct.pack(">I", len(payload))
|
||||
+ kind
|
||||
+ payload
|
||||
+ struct.pack(">I", zlib.crc32(kind + payload) & 0xFFFFFFFF)
|
||||
)
|
||||
|
||||
ihdr = struct.pack(">IIBBBBB", width, height, 8, 6, 0, 0, 0)
|
||||
path.write_bytes(
|
||||
b"\x89PNG\r\n\x1a\n" + chunk(b"IHDR", ihdr) + chunk(b"IDAT", zlib.compress(pixels)) + chunk(b"IEND", b"")
|
||||
)
|
||||
|
||||
|
||||
def _artifact_hashes(capture: dict) -> dict:
|
||||
source = capture["capture_source"]
|
||||
return {
|
||||
"final_screenshot": verifier._sha256_file(Path(source["final_screenshot"])),
|
||||
"final_accessibility": verifier._sha256_file(Path(source["final_accessibility"])),
|
||||
"turn_screenshots": [verifier._sha256_file(Path(item["turn_screenshot"])) for item in capture["messages"]],
|
||||
"turn_accessibility": [verifier._sha256_file(Path(item["turn_accessibility"])) for item in capture["messages"]],
|
||||
}
|
||||
|
||||
|
||||
def authorization_event(packet: dict, capture: dict) -> dict:
|
||||
return {
|
||||
"timestamp": capture["operator_authorization_captured_at_utc"],
|
||||
"type": "response_item",
|
||||
"payload": {
|
||||
"type": "message",
|
||||
"role": "user",
|
||||
"content": [{"type": "input_text", "text": capture["operator_authorization_text"]}],
|
||||
"internal_chat_message_metadata_passthrough": {"turn_id": "user-message-20260715-authorization"},
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
def write_browser_provenance(packet: dict, capture: dict, path: Path) -> str:
|
||||
source = capture["capture_source"]
|
||||
auth_event = authorization_event(packet, capture)
|
||||
auth_event_sha256 = hashlib.sha256(
|
||||
json.dumps(auth_event, sort_keys=True, separators=(",", ":")).encode("utf-8")
|
||||
).hexdigest()
|
||||
final_call_id = TURN_CAPTURE_CALL_IDS[2] if source["final_capture_reuses_turn_3"] else FINAL_CAPTURE_CALL_ID
|
||||
provenance = {
|
||||
"schema": verifier.BROWSER_PROVENANCE_SCHEMA,
|
||||
"status": "pass",
|
||||
"capture_channel": "codex_chrome_extension",
|
||||
"capture_challenge_nonce": CHALLENGE_NONCE,
|
||||
"protocol_sha256": packet["protocol_sha256"],
|
||||
"turn_capture_call_ids": TURN_CAPTURE_CALL_IDS,
|
||||
"final_capture_call_id": final_call_id,
|
||||
"browser": {
|
||||
"browser_type": "extension",
|
||||
"browser_id": "chrome-backend-20260715",
|
||||
"session_id": "chrome-session-20260715",
|
||||
"tab_id": "telegram-tab-20260715",
|
||||
"provider_capture_id": "chrome-capture-20260715",
|
||||
"page_url": "https://web.telegram.org/k/#-5146042086",
|
||||
"page_title": "Leo - Telegram",
|
||||
"captured_at_utc": source["captured_at_utc"],
|
||||
},
|
||||
"authorization": {
|
||||
"source": "codex_platform_user_message",
|
||||
"thread_id": packet["operator_context"]["codex_thread_id"],
|
||||
"user_message_id": "user-message-20260715-authorization",
|
||||
"source_receipt_id": auth_event_sha256,
|
||||
"text_sha256": hashlib.sha256(capture["operator_authorization_text"].encode("utf-8")).hexdigest(),
|
||||
"captured_at_utc": capture["operator_authorization_captured_at_utc"],
|
||||
},
|
||||
"telegram": {
|
||||
"chat_label": "Leo",
|
||||
"chat_id": "-5146042086",
|
||||
"message_ids": [item["telegram_message_id"] for item in capture["messages"]],
|
||||
"reply_ids": [item["reply_message_id"] for item in capture["messages"]],
|
||||
},
|
||||
"artifacts": _artifact_hashes(capture),
|
||||
"checks": {
|
||||
"authenticated_chrome_extension_session": True,
|
||||
"telegram_web_origin_observed": True,
|
||||
"chat_identity_observed_in_browser": True,
|
||||
"message_ids_observed_in_browser": True,
|
||||
"accessibility_captured_from_browser": True,
|
||||
"screenshots_captured_from_browser": True,
|
||||
"authorization_read_from_codex_user_message": True,
|
||||
},
|
||||
}
|
||||
path.write_text(json.dumps(provenance, indent=2, sort_keys=True) + "\n", encoding="utf-8")
|
||||
return verifier._sha256_file(path)
|
||||
|
||||
|
||||
def write_codex_rollout(packet: dict, capture: dict, tmp_path: Path, provenance_sha256: str) -> Path:
|
||||
provenance_path = Path(capture["capture_source"]["browser_provenance"])
|
||||
provenance = json.loads(provenance_path.read_text(encoding="utf-8"))
|
||||
browser = provenance["browser"]
|
||||
artifacts = provenance["artifacts"]
|
||||
thread_id = packet["operator_context"]["codex_thread_id"]
|
||||
sessions_root = tmp_path.parent / f"{tmp_path.name}-codex-sessions"
|
||||
rollout_dir = sessions_root / "2026" / "07" / "15"
|
||||
rollout_dir.mkdir(parents=True, exist_ok=True)
|
||||
rollout_path = rollout_dir / f"rollout-2026-07-15T00-00-00-{thread_id}.jsonl"
|
||||
events = [
|
||||
{
|
||||
"timestamp": "2026-07-14T23:58:00Z",
|
||||
"type": "session_meta",
|
||||
"payload": {"id": thread_id},
|
||||
},
|
||||
authorization_event(packet, capture),
|
||||
]
|
||||
|
||||
def chrome_event(call_id: str, timestamp: str, values: list[str]) -> dict:
|
||||
return {
|
||||
"timestamp": timestamp,
|
||||
"type": "event_msg",
|
||||
"payload": {
|
||||
"type": "mcp_tool_call_end",
|
||||
"call_id": call_id,
|
||||
"invocation": {
|
||||
"server": "node_repl",
|
||||
"tool": "js",
|
||||
"arguments": {
|
||||
"code": (
|
||||
"await tab.screenshot({fullPage:false}); "
|
||||
"await tab.playwright.domSnapshot(); await tab.url(); await tab.title();"
|
||||
)
|
||||
},
|
||||
},
|
||||
"result": {
|
||||
"Ok": {
|
||||
"content": [{"type": "text", "text": json.dumps(values)}],
|
||||
"isError": False,
|
||||
"_meta": {
|
||||
"codex/toolSurface": {
|
||||
"backend": "chrome",
|
||||
"browserId": browser["browser_id"],
|
||||
"kind": "browserUse",
|
||||
"openTabIds": [browser["tab_id"]],
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
turn_timestamps = ["2026-07-15T00:01:30Z", "2026-07-15T00:02:30Z", "2026-07-15T00:03:30Z"]
|
||||
for index, (call_id, timestamp, message) in enumerate(
|
||||
zip(TURN_CAPTURE_CALL_IDS, turn_timestamps, capture["messages"], strict=True)
|
||||
):
|
||||
values = [
|
||||
artifacts["turn_screenshots"][index],
|
||||
artifacts["turn_accessibility"][index],
|
||||
message["telegram_message_id"],
|
||||
message["reply_message_id"],
|
||||
browser["page_url"],
|
||||
browser["page_title"],
|
||||
packet["target"]["chat_id"],
|
||||
]
|
||||
if provenance["final_capture_call_id"] == call_id:
|
||||
values.extend(
|
||||
[
|
||||
artifacts["final_screenshot"],
|
||||
artifacts["final_accessibility"],
|
||||
provenance_sha256,
|
||||
*[item["telegram_message_id"] for item in capture["messages"]],
|
||||
*[item["reply_message_id"] for item in capture["messages"]],
|
||||
]
|
||||
)
|
||||
timestamp = capture["capture_source"]["captured_at_utc"]
|
||||
events.append(chrome_event(call_id, timestamp, values))
|
||||
if provenance["final_capture_call_id"] == FINAL_CAPTURE_CALL_ID:
|
||||
events.append(
|
||||
chrome_event(
|
||||
FINAL_CAPTURE_CALL_ID,
|
||||
capture["capture_source"]["captured_at_utc"],
|
||||
[
|
||||
artifacts["final_screenshot"],
|
||||
artifacts["final_accessibility"],
|
||||
provenance_sha256,
|
||||
*[item["telegram_message_id"] for item in capture["messages"]],
|
||||
*[item["reply_message_id"] for item in capture["messages"]],
|
||||
],
|
||||
)
|
||||
)
|
||||
rollout_path.write_text(
|
||||
"".join(json.dumps(event, sort_keys=True) + "\n" for event in events),
|
||||
encoding="utf-8",
|
||||
)
|
||||
return rollout_path
|
||||
|
||||
|
||||
def refresh_provenance_and_rollout(packet: dict, capture: dict, tmp_path: Path) -> Path:
|
||||
provenance_path = Path(capture["capture_source"]["browser_provenance"])
|
||||
provenance_sha256 = write_browser_provenance(packet, capture, provenance_path)
|
||||
return write_codex_rollout(packet, capture, tmp_path, provenance_sha256)
|
||||
|
||||
|
||||
def good_capture(packet: dict, tmp_path: Path) -> tuple[dict, Path]:
|
||||
screenshot = tmp_path / "final.png"
|
||||
accessibility = tmp_path / "final.txt"
|
||||
write_png(screenshot, (10, 20, 30, 255))
|
||||
accessibility.write_text("telegram final accessibility proof", encoding="utf-8")
|
||||
replies = [
|
||||
(
|
||||
"The database public.beliefs object c0000000 is an axiom with confidence 0.85. What supports it in "
|
||||
"the DB: nothing supports it; there are zero evidence rows and no external primary source."
|
||||
),
|
||||
(
|
||||
"Claim c0000000 is still the coordination bottleneck belief. Assumption versus observed support: the "
|
||||
"priority leap is assumed and the evidence is absent. Falsifier: a contrary case. Proposal A and "
|
||||
"Proposal B are staged only for review; nothing applied and neither is live knowledge."
|
||||
),
|
||||
(
|
||||
"Revised proposal: separate the mechanism from the business outcome. What would resolve the "
|
||||
"disagreement: a randomized study and its primary source dataset. Keep it pending_review for human "
|
||||
"review; approved is not apply and applied_at remains null. This is not an apply."
|
||||
),
|
||||
]
|
||||
colors = [(40, 50, 60, 255), (70, 80, 90, 255), (100, 110, 120, 255)]
|
||||
messages = []
|
||||
for item, reply, color in zip(packet["exact_messages"], replies, colors, strict=True):
|
||||
sequence = item["sequence"]
|
||||
turn_screenshot = tmp_path / f"turn-{sequence}.png"
|
||||
turn_accessibility = tmp_path / f"turn-{sequence}.txt"
|
||||
write_png(turn_screenshot, color)
|
||||
turn_accessibility.write_text(
|
||||
f"Telegram message: {item['message']}\nLeo reply: {reply}\n",
|
||||
encoding="utf-8",
|
||||
)
|
||||
messages.append(
|
||||
{
|
||||
"sequence": sequence,
|
||||
"prompt_id": item["prompt_id"],
|
||||
"sent_text": item["message"],
|
||||
"reply": reply,
|
||||
"sent_at_utc": f"2026-07-15T00:0{sequence}:00Z",
|
||||
"reply_at_utc": f"2026-07-15T00:0{sequence}:20Z",
|
||||
"telegram_message_id": f"sent-{sequence}",
|
||||
"reply_message_id": f"reply-{sequence}",
|
||||
"turn_screenshot": str(turn_screenshot),
|
||||
"turn_accessibility": str(turn_accessibility),
|
||||
}
|
||||
)
|
||||
provenance_path = tmp_path / "browser-provenance.json"
|
||||
capture = {
|
||||
"schema": verifier.CAPTURE_SCHEMA,
|
||||
"protocol_sha256": packet["protocol_sha256"],
|
||||
"preflight_state_token_sha256": "",
|
||||
"operator_authorization_text": packet["explicit_operator_authorization_text"],
|
||||
"operator_authorization_captured_at_utc": "2026-07-15T00:00:00Z",
|
||||
"extra_messages_sent": 0,
|
||||
"capture_source": {
|
||||
"platform": "telegram",
|
||||
"transport": "authenticated_chrome_telegram_ui",
|
||||
"chat_label": "Leo",
|
||||
"chat_id": "-5146042086",
|
||||
"captured_at_utc": "2026-07-15T00:03:40Z",
|
||||
"captured_by": "codex_chrome_extension",
|
||||
"final_screenshot": str(screenshot),
|
||||
"final_accessibility": str(accessibility),
|
||||
"browser_provenance": str(provenance_path),
|
||||
"final_capture_reuses_turn_3": False,
|
||||
"final_capture_reuse_reason": "",
|
||||
},
|
||||
"messages": messages,
|
||||
}
|
||||
rollout_path = refresh_provenance_and_rollout(packet, capture, tmp_path)
|
||||
return capture, rollout_path
|
||||
|
||||
|
||||
def verified_fixture(tmp_path: Path) -> tuple[dict, Path, dict, dict, dict, Path]:
|
||||
packet, packet_path = packet_and_path(tmp_path)
|
||||
before = preflight(packet, packet_path)
|
||||
after = postflight(packet, packet_path, before)
|
||||
capture, rollout = good_capture(packet, tmp_path)
|
||||
capture["preflight_state_token_sha256"] = before["state_token_sha256"]
|
||||
return packet, packet_path, before, after, capture, rollout
|
||||
|
||||
|
||||
def run_verifier(
|
||||
packet: dict,
|
||||
packet_path: Path,
|
||||
before: dict,
|
||||
after: dict,
|
||||
capture: dict,
|
||||
rollout_log: Path | None,
|
||||
tmp_path: Path,
|
||||
) -> dict:
|
||||
return verifier.verify_capture(
|
||||
packet,
|
||||
before,
|
||||
capture,
|
||||
after,
|
||||
packet_path=packet_path,
|
||||
evidence_root=tmp_path,
|
||||
codex_rollout_log=rollout_log,
|
||||
codex_sessions_root=(
|
||||
rollout_log.parents[3] if rollout_log is not None else tmp_path.parent / f"{tmp_path.name}-codex-sessions"
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
def test_no_capture_returns_awaiting_authorization_template(tmp_path: Path) -> None:
|
||||
packet, packet_path = packet_and_path(tmp_path)
|
||||
before = preflight(packet, packet_path)
|
||||
|
||||
receipt = verifier.verify_capture(
|
||||
packet,
|
||||
before,
|
||||
None,
|
||||
None,
|
||||
packet_path=packet_path,
|
||||
evidence_root=tmp_path,
|
||||
)
|
||||
|
||||
assert receipt["status"] == "awaiting_action_time_authorization"
|
||||
assert receipt["preparation_ready"] is True
|
||||
assert receipt["receipt_ready"] is False
|
||||
assert receipt["current_tier"] == verifier.PREPARATION_TIER
|
||||
assert receipt["telegram_visible_messages_sent"] is False
|
||||
assert receipt["live_receipt_boundary"]["accepted_by_this_api"] is False
|
||||
assert receipt["live_receipt_boundary"]["verified"] is False
|
||||
assert receipt["capture_template"]["schema"] == verifier.CAPTURE_SCHEMA
|
||||
assert receipt["capture_template"]["messages"][0]["prompt_id"] == "OOS-CHAIN-01"
|
||||
|
||||
|
||||
def test_public_verifier_keeps_fully_well_formed_all_local_forgery_preparation_only(
|
||||
tmp_path: Path,
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
) -> None:
|
||||
_packet, packet_path, before, after, capture, rollout = verified_fixture(tmp_path)
|
||||
preflight_path = tmp_path / "preflight.json"
|
||||
capture_path = tmp_path / "capture.json"
|
||||
postflight_path = tmp_path / "postflight.json"
|
||||
out_path = tmp_path / "receipt.json"
|
||||
markdown_path = tmp_path / "receipt.md"
|
||||
verifier.write_json(preflight_path, before)
|
||||
verifier.write_json(capture_path, capture)
|
||||
verifier.write_json(postflight_path, after)
|
||||
monkeypatch.setattr(verifier, "DEFAULT_CODEX_SESSIONS_ROOT", rollout.parents[3])
|
||||
|
||||
exit_code = verifier.main(
|
||||
[
|
||||
"--packet",
|
||||
str(packet_path),
|
||||
"--preflight",
|
||||
str(preflight_path),
|
||||
"--capture-json",
|
||||
str(capture_path),
|
||||
"--postflight",
|
||||
str(postflight_path),
|
||||
"--evidence-root",
|
||||
str(tmp_path),
|
||||
"--codex-rollout-log",
|
||||
str(rollout),
|
||||
"--out",
|
||||
str(out_path),
|
||||
"--markdown-out",
|
||||
str(markdown_path),
|
||||
]
|
||||
)
|
||||
receipt = json.loads(out_path.read_text(encoding="utf-8"))
|
||||
|
||||
assert exit_code == 0
|
||||
assert receipt["status"] == verifier.PREPARATION_STATUS
|
||||
assert receipt["verification_scope"] == "caller_writable_preparation_structure"
|
||||
assert receipt["preparation_ready"] is True
|
||||
assert receipt["receipt_ready"] is False
|
||||
assert receipt["current_tier"] == verifier.PREPARATION_TIER
|
||||
assert receipt["telegram_visible_messages_sent"] is False
|
||||
assert receipt["live_receipt_boundary"] == {
|
||||
"accepted_by_this_api": False,
|
||||
"authority": "independently_authenticated_platform_browser_receipt",
|
||||
"local_inputs_are": "caller_writable_preparation_evidence",
|
||||
"required": True,
|
||||
"verified": False,
|
||||
}
|
||||
assert all(receipt["checks"].values())
|
||||
assert all(receipt["preparation_outcomes"].values())
|
||||
assert receipt["selected_subject"]["row_id"] == SUBJECT_ID
|
||||
assert "T3_live_readonly" not in receipt["current_tier"]
|
||||
assert "caller-writable preparation evidence only" in markdown_path.read_text(encoding="utf-8")
|
||||
|
||||
|
||||
def test_self_declared_browser_provenance_without_codex_rollout_cannot_pass_t3(
|
||||
tmp_path: Path,
|
||||
) -> None:
|
||||
packet, packet_path, before, after, capture, _rollout = verified_fixture(tmp_path)
|
||||
|
||||
receipt = run_verifier(packet, packet_path, before, after, capture, None, tmp_path)
|
||||
|
||||
assert receipt["status"] == "fail"
|
||||
assert receipt["telegram_visible_messages_sent"] is False
|
||||
assert receipt["checks"]["codex_rollout_log_has_expected_local_sessions_shape"] is False
|
||||
assert receipt["checks"]["codex_rollout_capture_events_are_chrome_backend"] is False
|
||||
|
||||
|
||||
def test_non_chrome_rollout_capture_events_are_rejected(tmp_path: Path) -> None:
|
||||
packet, packet_path, before, after, capture, rollout = verified_fixture(tmp_path)
|
||||
events = [json.loads(line) for line in rollout.read_text(encoding="utf-8").splitlines()]
|
||||
for event in events:
|
||||
payload = event.get("payload") or {}
|
||||
if payload.get("type") == "mcp_tool_call_end":
|
||||
payload["result"]["Ok"]["_meta"]["codex/toolSurface"]["backend"] = "computerUse"
|
||||
rollout.write_text(
|
||||
"".join(json.dumps(event, sort_keys=True) + "\n" for event in events),
|
||||
encoding="utf-8",
|
||||
)
|
||||
|
||||
receipt = run_verifier(packet, packet_path, before, after, capture, rollout, tmp_path)
|
||||
|
||||
assert receipt["status"] == "fail"
|
||||
assert receipt["checks"]["codex_rollout_capture_events_are_chrome_backend"] is False
|
||||
|
||||
|
||||
def test_bot_api_capture_is_rejected(tmp_path: Path) -> None:
|
||||
packet, packet_path, before, after, capture, rollout = verified_fixture(tmp_path)
|
||||
capture["capture_source"]["transport"] = "telegram_bot_api"
|
||||
|
||||
receipt = run_verifier(packet, packet_path, before, after, capture, rollout, tmp_path)
|
||||
|
||||
assert receipt["status"] == "fail"
|
||||
assert receipt["checks"]["authenticated_chrome_transport_declared"] is False
|
||||
assert receipt["checks"]["bot_api_not_substituted"] is False
|
||||
|
||||
|
||||
def test_postflight_fingerprint_drift_is_rejected(tmp_path: Path) -> None:
|
||||
packet, packet_path, before, after, capture, rollout = verified_fixture(tmp_path)
|
||||
after["remote"]["fingerprint_after"]["fingerprint_sha256"] = "0" * 64
|
||||
|
||||
receipt = run_verifier(packet, packet_path, before, after, capture, rollout, tmp_path)
|
||||
|
||||
assert receipt["status"] == "fail"
|
||||
assert receipt["checks"]["postflight_state_token_derivation_valid"] is False
|
||||
assert receipt["checks"]["canonical_fingerprint_unchanged_from_preflight"] is False
|
||||
|
||||
|
||||
def test_message_text_drift_is_rejected(tmp_path: Path) -> None:
|
||||
packet, packet_path, before, after, capture, rollout = verified_fixture(tmp_path)
|
||||
capture["messages"][1]["sent_text"] += " extra"
|
||||
|
||||
receipt = run_verifier(packet, packet_path, before, after, capture, rollout, tmp_path)
|
||||
|
||||
assert receipt["status"] == "fail"
|
||||
assert receipt["checks"]["sent_text_exact"] is False
|
||||
|
||||
|
||||
def test_sent_and_reply_message_id_reuse_is_rejected(tmp_path: Path) -> None:
|
||||
packet, packet_path, before, after, capture, _rollout = verified_fixture(tmp_path)
|
||||
capture["messages"][0]["reply_message_id"] = capture["messages"][0]["telegram_message_id"]
|
||||
rollout = refresh_provenance_and_rollout(packet, capture, tmp_path)
|
||||
|
||||
receipt = run_verifier(packet, packet_path, before, after, capture, rollout, tmp_path)
|
||||
|
||||
assert receipt["status"] == "fail"
|
||||
assert receipt["checks"]["message_and_reply_ids_present_unique"] is False
|
||||
|
||||
|
||||
def test_copied_reply_not_present_in_accessibility_is_rejected(tmp_path: Path) -> None:
|
||||
packet, packet_path, before, after, capture, rollout = verified_fixture(tmp_path)
|
||||
capture["messages"][0]["reply"] += " copied-only suffix"
|
||||
|
||||
receipt = run_verifier(packet, packet_path, before, after, capture, rollout, tmp_path)
|
||||
|
||||
assert receipt["status"] == "fail"
|
||||
assert receipt["checks"]["turn_accessibility_binds_exact_messages_and_replies"] is False
|
||||
|
||||
|
||||
def test_all_prompts_sent_before_replies_is_rejected(tmp_path: Path) -> None:
|
||||
packet, packet_path, before, after, capture, rollout = verified_fixture(tmp_path)
|
||||
capture["messages"][0]["reply_at_utc"] = "2026-07-15T00:02:30Z"
|
||||
|
||||
receipt = run_verifier(packet, packet_path, before, after, capture, rollout, tmp_path)
|
||||
|
||||
assert receipt["status"] == "fail"
|
||||
assert receipt["checks"]["strict_send_reply_turn_order"] is False
|
||||
|
||||
|
||||
def test_after_the_fact_authorization_is_rejected(tmp_path: Path) -> None:
|
||||
packet, packet_path, before, after, capture, _rollout = verified_fixture(tmp_path)
|
||||
capture["operator_authorization_captured_at_utc"] = "2026-07-15T00:01:10Z"
|
||||
rollout = refresh_provenance_and_rollout(packet, capture, tmp_path)
|
||||
|
||||
receipt = run_verifier(packet, packet_path, before, after, capture, rollout, tmp_path)
|
||||
|
||||
assert receipt["status"] == "fail"
|
||||
assert receipt["checks"]["captured_authorization_before_first_send"] is False
|
||||
|
||||
|
||||
@pytest.mark.parametrize("timestamp", ["2026-07-15T00:01:00", "not-a-timestamp"])
|
||||
def test_naive_or_malformed_timestamps_are_rejected(tmp_path: Path, timestamp: str) -> None:
|
||||
packet, packet_path, before, after, capture, rollout = verified_fixture(tmp_path)
|
||||
capture["messages"][0]["sent_at_utc"] = timestamp
|
||||
|
||||
receipt = run_verifier(packet, packet_path, before, after, capture, rollout, tmp_path)
|
||||
|
||||
assert receipt["status"] == "fail"
|
||||
assert receipt["checks"]["timestamps_valid_and_timezone_aware"] is False
|
||||
|
||||
|
||||
def test_reused_per_turn_evidence_is_rejected(tmp_path: Path) -> None:
|
||||
packet, packet_path, before, after, capture, _rollout = verified_fixture(tmp_path)
|
||||
capture["messages"][1]["turn_screenshot"] = capture["messages"][0]["turn_screenshot"]
|
||||
capture["messages"][1]["turn_accessibility"] = capture["messages"][0]["turn_accessibility"]
|
||||
rollout = refresh_provenance_and_rollout(packet, capture, tmp_path)
|
||||
|
||||
receipt = run_verifier(packet, packet_path, before, after, capture, rollout, tmp_path)
|
||||
|
||||
assert receipt["status"] == "fail"
|
||||
assert receipt["checks"]["per_turn_screenshot_hashes_distinct_nonempty"] is False
|
||||
assert receipt["checks"]["per_turn_accessibility_hashes_distinct_nonempty"] is False
|
||||
|
||||
|
||||
def test_final_capture_may_reuse_turn_three_when_documented(tmp_path: Path) -> None:
|
||||
packet, packet_path, before, after, capture, _rollout = verified_fixture(tmp_path)
|
||||
capture["capture_source"]["final_screenshot"] = capture["messages"][2]["turn_screenshot"]
|
||||
capture["capture_source"]["final_accessibility"] = capture["messages"][2]["turn_accessibility"]
|
||||
capture["capture_source"]["final_capture_reuses_turn_3"] = True
|
||||
capture["capture_source"]["final_capture_reuse_reason"] = (
|
||||
"The final Chrome capture is the retained third-turn response state."
|
||||
)
|
||||
rollout = refresh_provenance_and_rollout(packet, capture, tmp_path)
|
||||
|
||||
receipt = run_verifier(packet, packet_path, before, after, capture, rollout, tmp_path)
|
||||
|
||||
assert receipt["status"] == verifier.PREPARATION_STATUS
|
||||
assert receipt["preparation_ready"] is True
|
||||
assert receipt["receipt_ready"] is False
|
||||
assert receipt["telegram_visible_messages_sent"] is False
|
||||
assert receipt["checks"]["final_capture_reuse_policy_satisfied"] is True
|
||||
|
||||
|
||||
def test_undocumented_final_turn_three_reuse_is_rejected(tmp_path: Path) -> None:
|
||||
packet, packet_path, before, after, capture, _rollout = verified_fixture(tmp_path)
|
||||
capture["capture_source"]["final_screenshot"] = capture["messages"][2]["turn_screenshot"]
|
||||
rollout = refresh_provenance_and_rollout(packet, capture, tmp_path)
|
||||
|
||||
receipt = run_verifier(packet, packet_path, before, after, capture, rollout, tmp_path)
|
||||
|
||||
assert receipt["status"] == "fail"
|
||||
assert receipt["checks"]["final_capture_reuse_policy_satisfied"] is False
|
||||
|
||||
|
||||
def test_evidence_path_escape_is_rejected(tmp_path: Path) -> None:
|
||||
packet, packet_path, before, after, capture, rollout = verified_fixture(tmp_path)
|
||||
outside = tmp_path.parent / "outside-turn.png"
|
||||
write_png(outside, (1, 2, 3, 255))
|
||||
capture["messages"][0]["turn_screenshot"] = str(outside)
|
||||
|
||||
receipt = run_verifier(packet, packet_path, before, after, capture, rollout, tmp_path)
|
||||
|
||||
assert receipt["status"] == "fail"
|
||||
assert receipt["checks"]["all_evidence_paths_contained_in_root"] is False
|
||||
|
||||
|
||||
def test_non_png_screenshot_is_rejected(tmp_path: Path) -> None:
|
||||
packet, packet_path, before, after, capture, _rollout = verified_fixture(tmp_path)
|
||||
Path(capture["messages"][0]["turn_screenshot"]).write_bytes(b"not a png")
|
||||
rollout = refresh_provenance_and_rollout(packet, capture, tmp_path)
|
||||
|
||||
receipt = run_verifier(packet, packet_path, before, after, capture, rollout, tmp_path)
|
||||
|
||||
assert receipt["status"] == "fail"
|
||||
assert receipt["checks"]["screenshots_are_valid_png_with_metadata"] is False
|
||||
|
||||
|
||||
def test_malformed_local_bundle_without_supported_state_or_rollout_structure_fails(
|
||||
tmp_path: Path,
|
||||
) -> None:
|
||||
packet, packet_path = packet_and_path(tmp_path)
|
||||
before = {
|
||||
"phase": "preflight",
|
||||
"status": "pass",
|
||||
"generated_at_utc": "2026-07-14T23:59:00Z",
|
||||
"protocol_sha256": packet["protocol_sha256"],
|
||||
"packet_file_sha256": verifier._sha256_file(packet_path),
|
||||
"state_token_sha256": "1" * 64,
|
||||
"remote": {"fingerprint_after": {"fingerprint_sha256": "f" * 64}, "service_after": {}},
|
||||
}
|
||||
after = {
|
||||
"phase": "postflight",
|
||||
"status": "pass",
|
||||
"generated_at_utc": "2026-07-15T00:04:00Z",
|
||||
"protocol_sha256": packet["protocol_sha256"],
|
||||
"state_token_sha256": "2" * 64,
|
||||
"subject_ref": "c0000000",
|
||||
"remote": {
|
||||
"fingerprint_after": {"fingerprint_sha256": "f" * 64},
|
||||
"service_after": {},
|
||||
"subject_readback": {"subject_ref": "c0000000", "matches": []},
|
||||
},
|
||||
}
|
||||
fake_png = tmp_path / "fake.png"
|
||||
fake_text = tmp_path / "fake.txt"
|
||||
fake_png.write_bytes(b"arbitrary non-PNG bytes")
|
||||
fake_text.write_text("copied prompts and replies", encoding="utf-8")
|
||||
capture = {
|
||||
"protocol_sha256": packet["protocol_sha256"],
|
||||
"preflight_state_token_sha256": "1" * 64,
|
||||
"operator_authorization_text": packet["explicit_operator_authorization_text"],
|
||||
"operator_authorization_captured_at_utc": "2026-07-15T00:00:00Z",
|
||||
"extra_messages_sent": 0,
|
||||
"capture_source": {
|
||||
"platform": "telegram",
|
||||
"transport": "authenticated_chrome_telegram_ui",
|
||||
"chat_label": "Leo",
|
||||
"chat_id": "-5146042086",
|
||||
"captured_at_utc": "2026-07-15T00:03:40Z",
|
||||
"captured_by": "fabricated",
|
||||
"final_screenshot": str(fake_png),
|
||||
"final_accessibility": str(fake_text),
|
||||
"browser_provenance": "",
|
||||
"final_capture_reuses_turn_3": False,
|
||||
"final_capture_reuse_reason": "",
|
||||
},
|
||||
"messages": [
|
||||
{
|
||||
"sequence": item["sequence"],
|
||||
"prompt_id": item["prompt_id"],
|
||||
"sent_text": item["message"],
|
||||
"reply": f"fabricated reply {item['sequence']}",
|
||||
"sent_at_utc": f"2026-07-15T00:0{item['sequence']}:00Z",
|
||||
"reply_at_utc": f"2026-07-15T00:0{item['sequence']}:20Z",
|
||||
"telegram_message_id": f"sent-{item['sequence']}",
|
||||
"reply_message_id": f"reply-{item['sequence']}",
|
||||
"turn_screenshot": str(fake_png),
|
||||
"turn_accessibility": str(fake_text),
|
||||
}
|
||||
for item in packet["exact_messages"]
|
||||
],
|
||||
}
|
||||
|
||||
receipt = run_verifier(packet, packet_path, before, after, capture, None, tmp_path)
|
||||
|
||||
assert receipt["status"] == "fail"
|
||||
assert receipt["current_tier"] != "T3_live_readonly"
|
||||
assert receipt["telegram_visible_messages_sent"] is False
|
||||
assert receipt["checks"]["capture_schema_supported"] is False
|
||||
assert receipt["checks"]["preflight_schema_supported"] is False
|
||||
assert receipt["checks"]["preflight_state_token_derivation_valid"] is False
|
||||
assert receipt["checks"]["codex_rollout_log_has_expected_local_sessions_shape"] is False
|
||||
assert receipt["checks"]["codex_rollout_has_exact_single_authorization_event"] is False
|
||||
assert receipt["checks"]["screenshots_are_valid_png_with_metadata"] is False
|
||||
assert receipt["checks"]["per_turn_screenshot_hashes_distinct_nonempty"] is False
|
||||
|
||||
|
||||
def test_state_token_tampering_is_rejected(tmp_path: Path) -> None:
|
||||
packet, packet_path, before, after, capture, rollout = verified_fixture(tmp_path)
|
||||
before = copy.deepcopy(before)
|
||||
before["generated_at_utc"] = "2026-07-14T23:58:00Z"
|
||||
|
||||
receipt = run_verifier(packet, packet_path, before, after, capture, rollout, tmp_path)
|
||||
|
||||
assert receipt["status"] == "fail"
|
||||
assert receipt["checks"]["preflight_state_token_derivation_valid"] is False
|
||||
Loading…
Reference in a new issue