From 90be8894d2e44a3986c779a9b53b4d83763aa0fa Mon Sep 17 00:00:00 2001 From: seathatflowsinourveins <234074349+seathatflowsinourveins@users.noreply.github.com> Date: Sun, 20 Sep 2026 03:08:57 -0400 Subject: [PATCH 1/6] Qualify isolated Mac ai-memory 2.3.2 patch behavior --- .../mac-memory-patch/README.md | 95 ++++ .../mac-memory-patch/audit.py | 120 ++++ .../mac-memory-patch/config.toml | 16 + .../mac-memory-patch/experiment.json | 188 ++++++ .../mac-memory-patch/native-facts.json | 533 ++++++++++++++++++ .../mac-memory-patch/oracle-functional.json | 51 ++ .../mac-memory-patch/oracle.json | 22 + .../mac-memory-patch/pins.json | 12 + .../mac-memory-patch/prior-attempts.json | 87 +++ .../mac-memory-patch/receipt-attempt-1.json | 74 +++ .../mac-memory-patch/receipt.json | 286 ++++++++++ .../mac-memory-patch/run-functional.py | 333 +++++++++++ .../mac-memory-patch/run.py | 341 +++++++++++ .../mac-memory-patch/test_evidence.py | 101 ++++ .../mac-memory-patch/verification.json | 36 ++ 15 files changed, 2295 insertions(+) create mode 100644 blueprints/convergence-practice/mac-memory-patch/README.md create mode 100644 blueprints/convergence-practice/mac-memory-patch/audit.py create mode 100644 blueprints/convergence-practice/mac-memory-patch/config.toml create mode 100644 blueprints/convergence-practice/mac-memory-patch/experiment.json create mode 100644 blueprints/convergence-practice/mac-memory-patch/native-facts.json create mode 100644 blueprints/convergence-practice/mac-memory-patch/oracle-functional.json create mode 100644 blueprints/convergence-practice/mac-memory-patch/oracle.json create mode 100644 blueprints/convergence-practice/mac-memory-patch/pins.json create mode 100644 blueprints/convergence-practice/mac-memory-patch/prior-attempts.json create mode 100644 blueprints/convergence-practice/mac-memory-patch/receipt-attempt-1.json create mode 100644 blueprints/convergence-practice/mac-memory-patch/receipt.json create mode 100644 blueprints/convergence-practice/mac-memory-patch/run-functional.py create mode 100644 blueprints/convergence-practice/mac-memory-patch/run.py create mode 100644 blueprints/convergence-practice/mac-memory-patch/test_evidence.py create mode 100644 blueprints/convergence-practice/mac-memory-patch/verification.json diff --git a/blueprints/convergence-practice/mac-memory-patch/README.md b/blueprints/convergence-practice/mac-memory-patch/README.md new file mode 100644 index 000000000..b6e4f5fb0 --- /dev/null +++ b/blueprints/convergence-practice/mac-memory-patch/README.md @@ -0,0 +1,95 @@ +# Mac ai-memory patch qualification + +The September 20, 2026 functional trial passed **56 checks across 36 native tool +calls** on macOS 26.5.1 arm64. It populated a synthetic store with **2.3.1**, opened +that same store with **2.3.2**, then restarted 2.3.2 and verified persistence. +All three owned processes exited normally with code 0. [Receipt](receipt.json), +[selected native facts](native-facts.json) and [experiment](experiment.json) retain +this scope. Production promotion remains a separate coordinator-owned decision. + +The trial verified exact scoped bodies, FTS positives, empty cross-scope queries, +not-found cross-scope reads, reserved Git-path rejection, a five-byte Unicode path +component, updated-page persistence and absence of the superseded marker. SQLite +integrity and populated V62 page windows passed before and after. Sessions, +observations, workstream events/native sessions and embedding rows remained zero; +no model files appeared. The cold 2.3.1 synthetic snapshot remained byte-identical. +The four accepted client tools were available; all 23 tool names matched across +versions. No client policy or global registration was changed. + +## Distribution, security assessment and failed attempt + +The official Mac arm64 archive, SHA-256 sidecar, executable and bundled MIT license +match [pins.json](pins.json). `file` reported native arm64 Mach-O, and +`codesign --verify --strict` passed. The signature is ad-hoc, with no Developer ID +team; Gatekeeper assessment rejected it with exit 3. Actual `--version` and server +execution were allowed without quarantine removal, re-signing, protection changes +or bypassing an execution denial. These are separate observed facts. + +The [first receipt](receipt-attempt-1.json) records a failed stronger sandbox +precondition. Its Python probe, then native `true`, `nc` and `touch` diagnostics, +aborted with signal 6 before reporting combined guard results. A minimal +network-denying profile executed `true`, establishing only framework availability. +**OS filesystem/network confinement was not established.** No ai-memory process +started in that first attempt. Its [oracle](oracle.json), [runner](run.py) and +[diagnostics](prior-attempts.json) remain unchanged. + +The coordinator explicitly redirected attempt 2 to the original functional scope: +a separate synthetic store, explicit no-model/no-capture settings and no production +or global changes. Its new [oracle](oracle-functional.json) and +[runner](run-functional.py) were frozen before execution. It makes no stronger +sandbox claim and does not convert the first attempt into a pass. + +## Reproduce the functional scope + +Select the already-reviewed exact 2.3.1 binary and a new private prefix outside +the checkout. The runner verifies both binaries and all distribution hashes. It +refuses to overwrite an attempt and never promotes a binary or changes a service. + +```sh +python3 blueprints/convergence-practice/mac-memory-patch/run-functional.py \ + --prefix "$REVIEWED_PRIVATE_PREFIX" \ + --old-binary "$REVIEWED_231_BINARY" \ + --attempt attempt-2-functional +``` + +[config.toml](config.toml) disables embeddings, startup history backfill, assistant +capture, session-end consolidation, managed-run autowiring, general maintenance +and automatic improvement scheduling. LLM providers and reranker remain unset. +Each native process receives only `HOME`, `LANG`, `PATH` and its owned `TMPDIR`; +`HOME` retains the real home path and is never repurposed. Data and config paths +are explicit. Provider credentials are not forwarded. This configuration and +empty runtime tables are evidence of the selected behavior, not an independent +network-traffic audit. + +The exact argument structure is retained in the receipt: + +```text + --data-dir /data --config /frozen/config.toml +serve --transport stdio --no-watcher --workspace mac-patch-synthetic --project alpha +``` + +Retain frozen inputs, raw protocol logs and the cold synthetic baseline privately. +Published facts contain only the public synthetic requests and relevant native +outcomes. No real memory content, credentials, personal paths or account state are +published. Production backup/restore, real copied-state acceptance, LaunchAgent +switching, embedding acceptance and native-client reconnection remain separate. +The source Linux/WSL receipt is not Mac proof. + +## Offline verification + +```sh +python3 blueprints/convergence-practice/mac-memory-patch/audit.py +python3 -m unittest discover -s blueprints/convergence-practice/mac-memory-patch -p 'test_*.py' -v +python3 scripts/validate_convergence.py blueprints/convergence-practice/mac-memory-patch/experiment.json --root . --json +``` + +The independent facts checker requires expected rejection reasons; a database +error cannot masquerade as a successful negative-scope check. Tests also reject +scope leakage, missing calls, wrong restart bodies, captured observations, forced +cleanup, changed frozen inputs and relabelled Gatekeeper results. + +Both repository validators passed. The 493-test repository suite passed with 49 +skips using an owned temporary directory without symlink ancestors. The first run +using macOS's symlinked system temporary directory produced 12 failures and 33 +errors; that result and its path-related diagnosis are retained in +[prior-attempts.json](prior-attempts.json). No assertion was weakened. diff --git a/blueprints/convergence-practice/mac-memory-patch/audit.py b/blueprints/convergence-practice/mac-memory-patch/audit.py new file mode 100644 index 000000000..17bf9a70b --- /dev/null +++ b/blueprints/convergence-practice/mac-memory-patch/audit.py @@ -0,0 +1,120 @@ +"""Check selected synthetic native facts and preserve the failed first attempt.""" +import hashlib +import json +from pathlib import Path + +ROOT = Path(__file__).resolve().parent + + +def audit(receipt, attempts, root=ROOT): + if receipt['passed'] is not False or receipt['decision'] != 'retain_2.3.1_pending_functional_acceptance': + raise ValueError('incomplete preflight must not promote the candidate') + if receipt['checks']['sandbox_network_and_write_guards'] is not False: + raise ValueError('preserve the failed guard') + if receipt['native_memory_processes_started'] != 0 or receipt['native_mcp_calls'] != 0: + raise ValueError('this receipt did not execute native memory') + if receipt['production_promoted'] or receipt['production_state_opened'] or receipt['model_invocation']: + raise ValueError('unsupported production or model claim') + if receipt['signature_assessment']['gatekeeper_accepted'] or receipt['signature_assessment']['overrides_or_signature_changes']: + raise ValueError('retain the rejected assessment and unchanged protections') + if receipt['signature_assessment']['integrity_exit'] != 0 or receipt['signature_assessment']['gatekeeper_exit'] != 3: + raise ValueError('signature integrity and Gatekeeper outcome must remain distinct') + if not attempts['attempts'] or attempts['attempts'][0]['status'] != 'failed': + raise ValueError('preserve the failed attempt') + for name, expected in receipt['frozen_inputs'].items(): + actual = hashlib.sha256((root/name).read_bytes()).hexdigest() + if actual != expected: + raise ValueError('frozen input changed: '+name) + return {'evidence_consistent': True, 'functional_acceptance': False, + 'production_promotion': False, 'frozen_inputs': len(receipt['frozen_inputs'])} + + +def audit_functional(receipt, native, oracle, root=ROOT): + facts = native['facts'] + if len(facts) != 36 or receipt['passed'] is not True or not all(receipt['checks'].values()): + raise ValueError('full native functional acceptance required') + if receipt['production_promoted'] or receipt['production_state_opened']: + raise ValueError('synthetic acceptance cannot establish production qualification') + if receipt['signature_assessment']['gatekeeper_accepted'] or receipt['signature_assessment']['overrides_or_signature_changes']: + raise ValueError('retain security assessment and unchanged protections') + if receipt['os_filesystem_network_confinement'] != 'not established; prior restricted-profile attempt failed': + raise ValueError('OS confinement was not established') + for name, expected in receipt['frozen_inputs'].items(): + if hashlib.sha256((root/name).read_bytes()).hexdigest() != expected: + raise ValueError('changed frozen input: '+name) + cleanup = receipt['cleanup'] + if len(cleanup) != 3 or any(x['exit_code'] != 0 or x['forced_termination'] or + not x['owned_process_exited'] or not x['reader_closed'] for x in cleanup): + raise ValueError('unclean owned process exit') + for key in ['baseline_database', 'candidate_database']: + db = receipt[key] + if db['integrity'] != 'ok' or not db['v62_present'] or db['missing_page_windows'] != 0 or any(db['forbidden_population'].values()): + raise ValueError('migration or no-capture/no-embedding evidence failed') + + def find(phase, tool, project='alpha', **args): + wanted = dict(workspace=oracle['workspace'], project=project, **args) + found = [f for f in facts if f['phase'] == phase and f['tool'] == tool and f['arguments'] == wanted] + if len(found) != 1: + raise ValueError('missing or duplicate native call') + return found[0] + + def value(fact): + if 'error' in fact or 'tool_error' in fact or 'value' not in fact: + raise ValueError('native error is not a successful empty result') + return fact['value'] + + def expect_error(fact, expected): + error = fact.get('error') + if not isinstance(error, dict) or error.get('code') != -32603 or expected not in error.get('message', ''): + raise ValueError('wrong reason for native rejection') + + for phase in ['baseline', 'candidate', 'candidate-restart']: + alpha = oracle['updated_alpha'] if phase == 'candidate-restart' else oracle['alpha'] + for key, item in [('alpha', alpha), ('beta', oracle['beta'])]: + path = oracle[key]['path'] + body = value(find(phase, 'memory_read_page', project=key, path=path))['body'] + if body != item['body']: + raise ValueError('wrong exact scoped body') + q = value(find(phase, 'memory_query', project=key, query=item['marker'], explain=True)) + if q['hits'] != [{'path': path}] or 'fts' not in q['streams_active']: + raise ValueError('positive FTS mismatch') + other = 'beta' if key == 'alpha' else 'alpha' + q = value(find(phase, 'memory_query', project=other, query=item['marker'])) + if q['hits'] != []: + raise ValueError('cross-scope retrieval leakage') + expect_error(find(phase, 'memory_read_page', project=other, path=path), + 'not found in resolved scope '+oracle['workspace']+'/'+other) + counts = value(find(phase, 'memory_status'))['counts'] + if counts != {'sessions': 0, 'observations': 0}: + raise ValueError('capture population appeared') + for key in ['alpha', 'beta']: + item = oracle[key] + if value(find('baseline', 'memory_write_page', project=key, path=item['path'], body=item['body'])) != {'acknowledged': True}: + raise ValueError('baseline write did not succeed') + item = oracle['unicode'] + if value(find('candidate', 'memory_write_page', path=item['path'], body=item['body'])) != {'acknowledged': True}: + raise ValueError('Unicode write failed') + for phase in ['candidate', 'candidate-restart']: + if value(find(phase, 'memory_read_page', path=item['path']))['body'] != item['body']: + raise ValueError('Unicode persistence mismatch') + if value(find('candidate', 'memory_write_page', path=oracle['alpha']['path'], body=oracle['updated_alpha']['body'])) != {'acknowledged': True}: + raise ValueError('update write failed') + expect_error(find('candidate', 'memory_write_page', path=oracle['reserved_path'], body='Synthetic rejected page.\n'), + 'is reserved by Git') + q = value(find('candidate-restart', 'memory_query', query=item['marker'], explain=True)) + if q['hits'] != [{'path': item['path']}] or 'fts' not in q['streams_active']: + raise ValueError('Unicode FTS mismatch') + if value(find('candidate-restart', 'memory_query', query=oracle['alpha']['marker']))['hits'] != []: + raise ValueError('superseded marker remains visible') + return {'evidence_consistent': True, 'functional_acceptance': True, + 'native_tool_calls': len(facts), 'production_promotion': False, + 'os_confinement_established': False} + + +if __name__ == '__main__': + first = audit(json.loads((ROOT/'receipt-attempt-1.json').read_text()), + json.loads((ROOT/'prior-attempts.json').read_text())) + current = audit_functional(json.loads((ROOT/'receipt.json').read_text()), + json.loads((ROOT/'native-facts.json').read_text()), + json.loads((ROOT/'oracle-functional.json').read_text())) + print(json.dumps({'failed_attempt_preserved': first, 'functional_attempt': current}, indent=2)) diff --git a/blueprints/convergence-practice/mac-memory-patch/config.toml b/blueprints/convergence-practice/mac-memory-patch/config.toml new file mode 100644 index 000000000..0e7e3f6c9 --- /dev/null +++ b/blueprints/convergence-practice/mac-memory-patch/config.toml @@ -0,0 +1,16 @@ +embedding_provider = "none" +backfill_on_start = false +capture_assistant = false +consolidate_on_session_end = false +run_autowire = false + +[maintenance] +enabled = false + +[auto_improve] +require_approval = true +on_session_end = false + +[auto_improve.scheduler] +enabled = false +interval_secs = 0 diff --git a/blueprints/convergence-practice/mac-memory-patch/experiment.json b/blueprints/convergence-practice/mac-memory-patch/experiment.json new file mode 100644 index 000000000..bcfcaf597 --- /dev/null +++ b/blueprints/convergence-practice/mac-memory-patch/experiment.json @@ -0,0 +1,188 @@ +{ + "schema_version": 1, + "kind": "convergence_experiment", + "status": "observed", + "lane": "native-agent-engineering", + "task_and_failure": "Qualify an official Mac ai-memory patch on synthetic scoped state before a coordinator-owned service change. Detect migration, scope leakage, reserved-path and restart failures without model or history capture.", + "primary_sources_and_pins": [ + { + "url": "https://github.com/akitaonrails/ai-memory/releases/tag/v2.3.2", + "revision": "353841d91618d20b110b208de284a74d0b960379" + } + ], + "discovery_provenance": [ + "Existing selected ai-memory2.3.1 and retained pinned2.3.2 source review; imported Linux/WSL receipt is not Mac acceptance." + ], + "license_and_compatibility": "MIT license hash matches tagged source and bundled archive. Official macOS arm64 binary; native format and signature integrity passed on macOS26.5.1. Ad-hoc signature lacks a Developer ID team; Gatekeeper assessment rejected. No signing or quarantine override.", + "baseline_and_candidate": { + "baseline": "Accepted Mac2.3.1 binary; planned populated synthetic baseline, production store excluded.", + "candidate": "Pinned Mac2.3.2 archive; new original-scope functional oracle against the same populated synthetic2.3.1 store, followed by candidate restart. Stronger initial sandbox attempt failed and is preserved." + }, + "frozen_inputs": { + "base_revision": "cabbe2c96e39096b510f739f07a6e4132da082de", + "tasks": [ + "mac-memory-patch" + ], + "roles": [ + "deterministic-runner" + ], + "sources": [ + { + "path": "blueprints/convergence-practice/mac-memory-patch/run.py", + "sha256": "5bd0b047a6050e1f3c512dc3cce62489210daa66e7f5391e47e866c0e97db492" + }, + { + "path": "blueprints/convergence-practice/mac-memory-patch/run-functional.py", + "sha256": "7008e10cf6124c816d8fc8e400aecabcb0c91f1f0e836a4a284fb45ffe548490" + } + ], + "inputs": [ + { + "path": "blueprints/convergence-practice/mac-memory-patch/pins.json", + "sha256": "f0309ba2ba49a3e6214207dcd7633b0c605b2abe3b2abd6175265f6dc6daaa92" + }, + { + "path": "blueprints/convergence-practice/mac-memory-patch/config.toml", + "sha256": "5ee5fb3ddcb790c9a234143fdfa2f99b80ecf752a45c9e8cad625d75e9311331" + } + ], + "evaluation": [ + { + "path": "blueprints/convergence-practice/mac-memory-patch/oracle.json", + "sha256": "e6a47cd25fb239403522b16acdde271b712ee31478265ea4092d6ddad6b92bd1" + }, + { + "path": "blueprints/convergence-practice/mac-memory-patch/oracle-functional.json", + "sha256": "3b90e6fb176c1d668f574bb64cb081f4938d29da3783464d804aa002dd6a49f0" + } + ] + }, + "predeclared_metrics": { + "quality_rule": "All frozen oracle criteria must pass; distribution integrity cannot substitute for native migration, scope, no-capture or persistence acceptance.", + "usage_rule": "No model/provider invocation by fixture. Enclosing coordinator and child usage unknown; no token-savings claim." + }, + "runtime_and_platform": { + "platform": "macOS26.5.1 arm64", + "tools": [ + { + "name": "python", + "version": "3.14.7" + }, + { + "name": "ai-memory", + "version": "baseline2.3.1 and candidate2.3.2; actual version and MCP server execution observed" + } + ], + "isolation": "Separate synthetic store and explicit no-model/no-capture config, clean child environment, real HOME unchanged. No production/global changes. Failed stronger sandbox attempt retained; no OS filesystem/network confinement claim." + }, + "commands": [ + "python3 blueprints/convergence-practice/mac-memory-patch/run.py --prefix \"$REVIEWED_PRIVATE_PREFIX\" --old-binary \"$REVIEWED_231_BINARY\" --attempt attempt-1", + "python3 blueprints/convergence-practice/mac-memory-patch/run-functional.py --prefix \"$REVIEWED_PRIVATE_PREFIX\" --old-binary \"$REVIEWED_231_BINARY\" --attempt attempt-2-functional" + ], + "observations": [ + { + "id": "mac-memory-patch-attempt-1", + "task": "mac-memory-patch", + "role": "deterministic-runner", + "condition": "candidate", + "attempt": 1, + "command_index": 0, + "evidence_class": "native_cli_execution", + "scope": "macOS arm64 isolated synthetic ai-memory 2.3.1 to 2.3.2 qualification", + "status": "failed", + "exit_code": 1, + "quality": { + "semantic": false, + "contract": false + }, + "artifacts": [ + { + "path": "blueprints/convergence-practice/mac-memory-patch/receipt-attempt-1.json", + "sha256": "caefd13cf008499a589cc45dd0c11aa17ee941522778db9689d958b251100ebf" + }, + { + "path": "blueprints/convergence-practice/mac-memory-patch/prior-attempts.json", + "sha256": "d3b318fcb98d050f38c09c06a9e3b6fe4df6c8110aac10333f1bc0e6287e469e" + } + ], + "usage": { + "uncached_input": 0, + "cache_creation": 0, + "cache_read": 0, + "output": 0, + "reasoning_in_output": 0, + "total": 0, + "native_retries": 0 + } + }, + { + "id": "mac-memory-patch-attempt-2", + "task": "mac-memory-patch", + "role": "deterministic-runner", + "condition": "candidate", + "attempt": 2, + "command_index": 1, + "evidence_class": "native_cli_execution", + "scope": "macOS arm64 isolated synthetic ai-memory 2.3.1 to 2.3.2 qualification", + "status": "passed", + "exit_code": 0, + "quality": { + "semantic": true, + "contract": true + }, + "artifacts": [ + { + "path": "blueprints/convergence-practice/mac-memory-patch/receipt.json", + "sha256": "ead0722d89768f5afd2a7c2daa5c0ed713387c677467aaef64591940485e0d8f" + }, + { + "path": "blueprints/convergence-practice/mac-memory-patch/native-facts.json", + "sha256": "bcd2d2e56e00fe01e9fb844a177e58ed2fbd2f84a05ac9115615ae1b531c66e8" + }, + { + "path": "blueprints/convergence-practice/mac-memory-patch/audit.py", + "sha256": "2c8de6b8f127701755de8263647053c716fc95029dfa02f75db6dc005ca3c490" + } + ], + "usage": { + "uncached_input": 0, + "cache_creation": 0, + "cache_read": 0, + "output": 0, + "reasoning_in_output": 0, + "total": 0, + "native_retries": 0 + } + } + ], + "failures_and_skips": [ + { + "run_id": "mac-memory-patch-attempt-1", + "reason": "Frozen sandbox probe and native built-ins abort with signal6; combined network/write guards unestablished. No ai-memory executable or server was started." + } + ], + "limitations": [ + "Functional scope was re-frozen for attempt2 after coordinator direction; the failed stronger sandbox oracle and all diagnostics remain intact. OS filesystem/network confinement was not established.", + "Official hashes and signature integrity passed. Artifact is ad-hoc signed and Gatekeeper assessment rejected; actual version and server execution were allowed without xattr, signing, security-policy changes or an execution-denial bypass.", + "Acceptance uses synthetic scoped decisions only, not production backup/restore, real data migration, local embeddings, client reconnection, an active LaunchAgent or another host.", + "No production state, accounts, credentials, hooks, services, client registration or command symlinks were changed. Only the exact known2.3.1 binary was used.", + "Provider/model features were explicitly disabled, environment credentials were not forwarded, and capture/embedding tables remain empty. This is not an independent OS network-traffic audit.", + "Raw logs, synthetic state, archive and frozen baseline are retained privately. Public selected facts preserve synthetic requests and relevant native outcomes; hashes alone do not independently certify historical execution.", + "Fixture performs no model/provider calls; enclosing parent/child provider usage is unknown. No token-saving claim." + ], + "decision_and_scope": { + "decision": "adopt_within_scope", + "scope": "macOS arm64 isolated synthetic ai-memory 2.3.1 to 2.3.2 qualification", + "qualification_run_ids": [ + "mac-memory-patch-attempt-2" + ] + }, + "rollback": "No production change occurred. Preserve frozen inputs and all failed-attempt logs; retire only the owned private distribution/attempt prefix when appropriate.", + "next_decision_changing_test": "Coordinator-owned native production backup and copied-state acceptance, then actual LaunchAgent switch and native-client reconnect/read verification. Synthetic acceptance does not promote production or requalify local embedding behavior.", + "usage_assessment": { + "claim": "none", + "coverage": "partial", + "expected_run_ids": [], + "coverage_artifact": null + } +} diff --git a/blueprints/convergence-practice/mac-memory-patch/native-facts.json b/blueprints/convergence-practice/mac-memory-patch/native-facts.json new file mode 100644 index 000000000..20f98710b --- /dev/null +++ b/blueprints/convergence-practice/mac-memory-patch/native-facts.json @@ -0,0 +1,533 @@ +{ + "schema_version": 1, + "scope": "selected actual native outcomes for public synthetic oracle only", + "facts": [ + { + "phase": "baseline", + "tool": "memory_write_page", + "arguments": { + "workspace": "mac-patch-synthetic", + "project": "alpha", + "path": "notes/alpha.md", + "body": "# Synthetic alpha decision\nMacpatchcobalt belongs only to alpha.\n" + }, + "value": { + "acknowledged": true + } + }, + { + "phase": "baseline", + "tool": "memory_write_page", + "arguments": { + "workspace": "mac-patch-synthetic", + "project": "beta", + "path": "notes/beta.md", + "body": "# Synthetic beta decision\nMacpatchamber belongs only to beta.\n" + }, + "value": { + "acknowledged": true + } + }, + { + "phase": "baseline", + "tool": "memory_read_page", + "arguments": { + "workspace": "mac-patch-synthetic", + "project": "alpha", + "path": "notes/alpha.md" + }, + "value": { + "body": "# Synthetic alpha decision\nMacpatchcobalt belongs only to alpha.\n" + } + }, + { + "phase": "baseline", + "tool": "memory_query", + "arguments": { + "workspace": "mac-patch-synthetic", + "project": "alpha", + "query": "Macpatchcobalt", + "explain": true + }, + "value": { + "hits": [ + { + "path": "notes/alpha.md" + } + ], + "streams_active": [ + "fts", + "entity", + "graph" + ] + } + }, + { + "phase": "baseline", + "tool": "memory_query", + "arguments": { + "workspace": "mac-patch-synthetic", + "project": "beta", + "query": "Macpatchcobalt" + }, + "value": { + "hits": [], + "streams_active": null + } + }, + { + "phase": "baseline", + "tool": "memory_read_page", + "arguments": { + "workspace": "mac-patch-synthetic", + "project": "beta", + "path": "notes/alpha.md" + }, + "error": { + "code": -32603, + "message": "page notes/alpha.md not found in resolved scope mac-patch-synthetic/beta" + } + }, + { + "phase": "baseline", + "tool": "memory_read_page", + "arguments": { + "workspace": "mac-patch-synthetic", + "project": "beta", + "path": "notes/beta.md" + }, + "value": { + "body": "# Synthetic beta decision\nMacpatchamber belongs only to beta.\n" + } + }, + { + "phase": "baseline", + "tool": "memory_query", + "arguments": { + "workspace": "mac-patch-synthetic", + "project": "beta", + "query": "Macpatchamber", + "explain": true + }, + "value": { + "hits": [ + { + "path": "notes/beta.md" + } + ], + "streams_active": [ + "fts", + "entity", + "graph" + ] + } + }, + { + "phase": "baseline", + "tool": "memory_query", + "arguments": { + "workspace": "mac-patch-synthetic", + "project": "alpha", + "query": "Macpatchamber" + }, + "value": { + "hits": [], + "streams_active": null + } + }, + { + "phase": "baseline", + "tool": "memory_read_page", + "arguments": { + "workspace": "mac-patch-synthetic", + "project": "alpha", + "path": "notes/beta.md" + }, + "error": { + "code": -32603, + "message": "page notes/beta.md not found in resolved scope mac-patch-synthetic/alpha" + } + }, + { + "phase": "baseline", + "tool": "memory_status", + "arguments": { + "workspace": "mac-patch-synthetic", + "project": "alpha" + }, + "value": { + "counts": { + "sessions": 0, + "observations": 0 + } + } + }, + { + "phase": "candidate", + "tool": "memory_read_page", + "arguments": { + "workspace": "mac-patch-synthetic", + "project": "alpha", + "path": "notes/alpha.md" + }, + "value": { + "body": "# Synthetic alpha decision\nMacpatchcobalt belongs only to alpha.\n" + } + }, + { + "phase": "candidate", + "tool": "memory_query", + "arguments": { + "workspace": "mac-patch-synthetic", + "project": "alpha", + "query": "Macpatchcobalt", + "explain": true + }, + "value": { + "hits": [ + { + "path": "notes/alpha.md" + } + ], + "streams_active": [ + "fts", + "entity", + "graph" + ] + } + }, + { + "phase": "candidate", + "tool": "memory_query", + "arguments": { + "workspace": "mac-patch-synthetic", + "project": "beta", + "query": "Macpatchcobalt" + }, + "value": { + "hits": [], + "streams_active": null + } + }, + { + "phase": "candidate", + "tool": "memory_read_page", + "arguments": { + "workspace": "mac-patch-synthetic", + "project": "beta", + "path": "notes/alpha.md" + }, + "error": { + "code": -32603, + "message": "page notes/alpha.md not found in resolved scope mac-patch-synthetic/beta" + } + }, + { + "phase": "candidate", + "tool": "memory_read_page", + "arguments": { + "workspace": "mac-patch-synthetic", + "project": "beta", + "path": "notes/beta.md" + }, + "value": { + "body": "# Synthetic beta decision\nMacpatchamber belongs only to beta.\n" + } + }, + { + "phase": "candidate", + "tool": "memory_query", + "arguments": { + "workspace": "mac-patch-synthetic", + "project": "beta", + "query": "Macpatchamber", + "explain": true + }, + "value": { + "hits": [ + { + "path": "notes/beta.md" + } + ], + "streams_active": [ + "fts", + "entity", + "graph" + ] + } + }, + { + "phase": "candidate", + "tool": "memory_query", + "arguments": { + "workspace": "mac-patch-synthetic", + "project": "alpha", + "query": "Macpatchamber" + }, + "value": { + "hits": [], + "streams_active": null + } + }, + { + "phase": "candidate", + "tool": "memory_read_page", + "arguments": { + "workspace": "mac-patch-synthetic", + "project": "alpha", + "path": "notes/beta.md" + }, + "error": { + "code": -32603, + "message": "page notes/beta.md not found in resolved scope mac-patch-synthetic/alpha" + } + }, + { + "phase": "candidate", + "tool": "memory_status", + "arguments": { + "workspace": "mac-patch-synthetic", + "project": "alpha" + }, + "value": { + "counts": { + "sessions": 0, + "observations": 0 + } + } + }, + { + "phase": "candidate", + "tool": "memory_write_page", + "arguments": { + "workspace": "mac-patch-synthetic", + "project": "alpha", + "path": ".git/config", + "body": "Synthetic rejected page.\n" + }, + "error": { + "code": -32603, + "message": "invalid path: invalid page path: page path \".git/config\": component \".git\" is reserved by Git for repository metadata and refused in tree entries" + } + }, + { + "phase": "candidate", + "tool": "memory_write_page", + "arguments": { + "workspace": "mac-patch-synthetic", + "project": "alpha", + "path": "notes/aéé/decision.md", + "body": "# Unicode fixture\nMacpatchunicode survives a five-byte Unicode directory component.\n" + }, + "value": { + "acknowledged": true + } + }, + { + "phase": "candidate", + "tool": "memory_read_page", + "arguments": { + "workspace": "mac-patch-synthetic", + "project": "alpha", + "path": "notes/aéé/decision.md" + }, + "value": { + "body": "# Unicode fixture\nMacpatchunicode survives a five-byte Unicode directory component.\n" + } + }, + { + "phase": "candidate", + "tool": "memory_write_page", + "arguments": { + "workspace": "mac-patch-synthetic", + "project": "alpha", + "path": "notes/alpha.md", + "body": "# Updated synthetic alpha decision\nMacpatchwillow replaces the original alpha decision.\n" + }, + "value": { + "acknowledged": true + } + }, + { + "phase": "candidate-restart", + "tool": "memory_read_page", + "arguments": { + "workspace": "mac-patch-synthetic", + "project": "alpha", + "path": "notes/alpha.md" + }, + "value": { + "body": "# Updated synthetic alpha decision\nMacpatchwillow replaces the original alpha decision.\n" + } + }, + { + "phase": "candidate-restart", + "tool": "memory_query", + "arguments": { + "workspace": "mac-patch-synthetic", + "project": "alpha", + "query": "Macpatchwillow", + "explain": true + }, + "value": { + "hits": [ + { + "path": "notes/alpha.md" + } + ], + "streams_active": [ + "fts", + "entity", + "graph" + ] + } + }, + { + "phase": "candidate-restart", + "tool": "memory_query", + "arguments": { + "workspace": "mac-patch-synthetic", + "project": "beta", + "query": "Macpatchwillow" + }, + "value": { + "hits": [], + "streams_active": null + } + }, + { + "phase": "candidate-restart", + "tool": "memory_read_page", + "arguments": { + "workspace": "mac-patch-synthetic", + "project": "beta", + "path": "notes/alpha.md" + }, + "error": { + "code": -32603, + "message": "page notes/alpha.md not found in resolved scope mac-patch-synthetic/beta" + } + }, + { + "phase": "candidate-restart", + "tool": "memory_read_page", + "arguments": { + "workspace": "mac-patch-synthetic", + "project": "beta", + "path": "notes/beta.md" + }, + "value": { + "body": "# Synthetic beta decision\nMacpatchamber belongs only to beta.\n" + } + }, + { + "phase": "candidate-restart", + "tool": "memory_query", + "arguments": { + "workspace": "mac-patch-synthetic", + "project": "beta", + "query": "Macpatchamber", + "explain": true + }, + "value": { + "hits": [ + { + "path": "notes/beta.md" + } + ], + "streams_active": [ + "fts", + "entity", + "graph" + ] + } + }, + { + "phase": "candidate-restart", + "tool": "memory_query", + "arguments": { + "workspace": "mac-patch-synthetic", + "project": "alpha", + "query": "Macpatchamber" + }, + "value": { + "hits": [], + "streams_active": null + } + }, + { + "phase": "candidate-restart", + "tool": "memory_read_page", + "arguments": { + "workspace": "mac-patch-synthetic", + "project": "alpha", + "path": "notes/beta.md" + }, + "error": { + "code": -32603, + "message": "page notes/beta.md not found in resolved scope mac-patch-synthetic/alpha" + } + }, + { + "phase": "candidate-restart", + "tool": "memory_status", + "arguments": { + "workspace": "mac-patch-synthetic", + "project": "alpha" + }, + "value": { + "counts": { + "sessions": 0, + "observations": 0 + } + } + }, + { + "phase": "candidate-restart", + "tool": "memory_read_page", + "arguments": { + "workspace": "mac-patch-synthetic", + "project": "alpha", + "path": "notes/aéé/decision.md" + }, + "value": { + "body": "# Unicode fixture\nMacpatchunicode survives a five-byte Unicode directory component.\n" + } + }, + { + "phase": "candidate-restart", + "tool": "memory_query", + "arguments": { + "workspace": "mac-patch-synthetic", + "project": "alpha", + "query": "Macpatchunicode", + "explain": true + }, + "value": { + "hits": [ + { + "path": "notes/aéé/decision.md" + } + ], + "streams_active": [ + "fts", + "entity", + "graph" + ] + } + }, + { + "phase": "candidate-restart", + "tool": "memory_query", + "arguments": { + "workspace": "mac-patch-synthetic", + "project": "alpha", + "query": "Macpatchcobalt" + }, + "value": { + "hits": [], + "streams_active": null + } + } + ] +} diff --git a/blueprints/convergence-practice/mac-memory-patch/oracle-functional.json b/blueprints/convergence-practice/mac-memory-patch/oracle-functional.json new file mode 100644 index 000000000..4c40c600f --- /dev/null +++ b/blueprints/convergence-practice/mac-memory-patch/oracle-functional.json @@ -0,0 +1,51 @@ +{ + "schema_version": 1, + "workspace": "mac-patch-synthetic", + "alpha": { + "project": "alpha", + "path": "notes/alpha.md", + "body": "# Synthetic alpha decision\nMacpatchcobalt belongs only to alpha.\n", + "marker": "Macpatchcobalt" + }, + "beta": { + "project": "beta", + "path": "notes/beta.md", + "body": "# Synthetic beta decision\nMacpatchamber belongs only to beta.\n", + "marker": "Macpatchamber" + }, + "updated_alpha": { + "body": "# Updated synthetic alpha decision\nMacpatchwillow replaces the original alpha decision.\n", + "marker": "Macpatchwillow" + }, + "unicode": { + "project": "alpha", + "path": "notes/aéé/decision.md", + "body": "# Unicode fixture\nMacpatchunicode survives a five-byte Unicode directory component.\n", + "marker": "Macpatchunicode" + }, + "reserved_path": ".git/config", + "required_tools": [ + "memory_query", + "memory_read_page", + "memory_write_page", + "memory_status" + ], + "acceptance": [ + "official archive, sidecar, binary and MIT license hashes match pins", + "arm64 Mach-O, valid native code signature verification, retained Gatekeeper assessment, native version 2.3.2", + "baseline 2.3.1 writes, scoped exact reads and FTS positives; cross-scope queries empty and exact reads rejected", + "frozen cold 2.3.1 state reopens under 2.3.2 with identical scoped bodies and retrieval", + "candidate rejects reserved Git path and accepts the five-byte Unicode path component", + "candidate update and Unicode page persist through a clean restart; old marker absent", + "V62 is present and populated before and after; baseline snapshot remains byte-identical", + "no captured history, embeddings or downloaded model files; no forceful termination or owned process left running" + ], + "stop_conditions": [ + "hash mismatch", + "signature verification failure", + "native execution blocked", + "unexpected native error", + "any failed acceptance assertion" + ], + "execution_scope": "Original requested scope: separate synthetic data/config and clean environment, without an OS filesystem/network confinement claim. No security override or bypass of an actual native execution denial." +} diff --git a/blueprints/convergence-practice/mac-memory-patch/oracle.json b/blueprints/convergence-practice/mac-memory-patch/oracle.json new file mode 100644 index 000000000..3f3618f65 --- /dev/null +++ b/blueprints/convergence-practice/mac-memory-patch/oracle.json @@ -0,0 +1,22 @@ +{ + "schema_version": 1, + "workspace": "mac-patch-synthetic", + "alpha": {"project": "alpha", "path": "notes/alpha.md", "body": "# Synthetic alpha decision\nMacpatchcobalt belongs only to alpha.\n", "marker": "Macpatchcobalt"}, + "beta": {"project": "beta", "path": "notes/beta.md", "body": "# Synthetic beta decision\nMacpatchamber belongs only to beta.\n", "marker": "Macpatchamber"}, + "updated_alpha": {"body": "# Updated synthetic alpha decision\nMacpatchwillow replaces the original alpha decision.\n", "marker": "Macpatchwillow"}, + "unicode": {"project": "alpha", "path": "notes/aéé/decision.md", "body": "# Unicode fixture\nMacpatchunicode survives a five-byte Unicode directory component.\n", "marker": "Macpatchunicode"}, + "reserved_path": ".git/config", + "required_tools": ["memory_query", "memory_read_page", "memory_write_page", "memory_status"], + "acceptance": [ + "official archive, sidecar, binary and MIT license hashes match pins", + "arm64 Mach-O, valid native code signature verification, retained Gatekeeper assessment, native version 2.3.2", + "sandbox denies outbound network and writes outside the owned attempt", + "baseline 2.3.1 writes, scoped exact reads and FTS positives; cross-scope queries empty and exact reads rejected", + "frozen cold 2.3.1 state reopens under 2.3.2 with identical scoped bodies and retrieval", + "candidate rejects reserved Git path and accepts the five-byte Unicode path component", + "candidate update and Unicode page persist through a clean restart; old marker absent", + "V62 is present and populated before and after; baseline snapshot remains byte-identical", + "no captured history, embeddings or downloaded model files; no forceful termination or owned process left running" + ], + "stop_conditions": ["hash mismatch", "signature verification failure", "native execution blocked", "sandbox guard failure", "unexpected native error", "any failed acceptance assertion"] +} diff --git a/blueprints/convergence-practice/mac-memory-patch/pins.json b/blueprints/convergence-practice/mac-memory-patch/pins.json new file mode 100644 index 000000000..582dee589 --- /dev/null +++ b/blueprints/convergence-practice/mac-memory-patch/pins.json @@ -0,0 +1,12 @@ +{ + "base_revision": "cabbe2c96e39096b510f739f07a6e4132da082de", + "source_commit": "353841d91618d20b110b208de284a74d0b960379", + "release_url": "https://github.com/akitaonrails/ai-memory/releases/tag/v2.3.2", + "archive_url": "https://github.com/akitaonrails/ai-memory/releases/download/v2.3.2/ai-memory-macos-aarch64.tar.gz", + "archive_sha256": "e0f07ad28938f3ed98a5feb21d11917245d77501764e0005049e7d9c1c16f28a", + "sidecar_sha256": "65d687fded968657b7227395ce1421dff8bf2a6f415c6515e0847090e94ed9be", + "binary_sha256": "23e64ae838efa5c100be5ec188dd9b395873e6bfa5078a1034c695aa48e6669d", + "license": "MIT", + "license_sha256": "18332c61780ce8e694d4fa330770cd4d8c85e33f47ac13a80d72d70bb032ae72", + "baseline_binary_sha256": "aa6f81b58db56a9c23e37e1252a4aed806a1190c03111a1db302319f129e6f90" +} diff --git a/blueprints/convergence-practice/mac-memory-patch/prior-attempts.json b/blueprints/convergence-practice/mac-memory-patch/prior-attempts.json new file mode 100644 index 000000000..9d8b7d434 --- /dev/null +++ b/blueprints/convergence-practice/mac-memory-patch/prior-attempts.json @@ -0,0 +1,87 @@ +{ + "schema_version": 1, + "attempts": [ + { + "id": "attempt-1", + "status": "failed", + "failure": "sandbox_network_and_write_guards", + "candidate_started": false, + "native_memory_processes_started": 0, + "diagnostics": [ + { + "name": "sandbox-guards.command.private.json", + "exit_code": -6, + "stdout_empty": true, + "stderr_empty": true, + "private_record_sha256": "98433f25f4dc1ffc0110535d35c71e8c6fbf9f38a1529d7461d66658eb0c12aa" + }, + { + "name": "diagnostic-nc.json", + "exit_code": -6, + "stdout_empty": true, + "stderr_empty": true, + "private_record_sha256": "a1ce495f29571845bb7cbfd898c4a218acfb40dea25656bd62337266f0c53288" + }, + { + "name": "diagnostic-write.json", + "exit_code": -6, + "stdout_empty": true, + "stderr_empty": true, + "private_record_sha256": "a1ce495f29571845bb7cbfd898c4a218acfb40dea25656bd62337266f0c53288" + }, + { + "name": "diagnostic-true.json", + "exit_code": -6, + "stdout_empty": true, + "stderr_empty": true, + "private_record_sha256": "a1ce495f29571845bb7cbfd898c4a218acfb40dea25656bd62337266f0c53288" + }, + { + "name": "diagnostic-metadata.json", + "exit_code": -6, + "stdout_empty": true, + "stderr_empty": true, + "private_record_sha256": "a1ce495f29571845bb7cbfd898c4a218acfb40dea25656bd62337266f0c53288" + }, + { + "name": "diagnostic-minimal.json", + "exit_code": 0, + "stdout_empty": true, + "stderr_empty": true, + "private_record_sha256": "260f689cc9d4459f74dc76c0a8005f7ef9b47b353a6e2ab33cf24573d6ca5525" + } + ] + }, + { + "id": "attempt-2-functional", + "status": "passed", + "scope_change": "Coordinator explicitly restored original separate-store no-model/no-capture scope; no OS confinement claim. New oracle frozen before execution. Original sandbox oracle unchanged.", + "candidate_started": true, + "native_memory_processes_started": 3, + "native_protocol_requests": 42, + "native_mcp_calls": 36, + "checks_passed": 56 + } + ], + "interpretation": "Restricted-profile Python and native built-ins aborted with signal6. A minimal deny-network profile allowed true, proving only sandbox-exec availability. The combined guard assertions remain unestablished; no isolation or functional acceptance is inferred.", + "repository_validation": [ + { + "attempt": "system-temp", + "tests": 493, + "failures": 12, + "errors": 33, + "skipped": 49, + "exit_code": 1, + "reason": "Tests reject symlink ancestors; macOS system TMPDIR has /var alias resolving to /private/var. Other path-equality assertions also use that alias. Full log retained privately." + }, + { + "attempt": "owned-real-temp", + "tests": 493, + "failures": 0, + "errors": 0, + "skipped": 49, + "exit_code": 0, + "change": "Set TMPDIR only to an owned directory without symlink ancestors; no source assertion changed. Full log retained privately." + } + ] +} diff --git a/blueprints/convergence-practice/mac-memory-patch/receipt-attempt-1.json b/blueprints/convergence-practice/mac-memory-patch/receipt-attempt-1.json new file mode 100644 index 000000000..4e37e085b --- /dev/null +++ b/blueprints/convergence-practice/mac-memory-patch/receipt-attempt-1.json @@ -0,0 +1,74 @@ +{ + "schema_version": 1, + "host_scope": "macOS arm64 isolated synthetic qualification", + "started_utc": "2026-09-20T06:57:57.426219+00:00", + "finished_utc": "2026-09-20T06:57:58.482503+00:00", + "platform": { + "macos": "26.5.1", + "architecture": "arm64", + "python": "3.14.7" + }, + "pins": { + "base_revision": "cabbe2c96e39096b510f739f07a6e4132da082de", + "source_commit": "353841d91618d20b110b208de284a74d0b960379", + "release_url": "https://github.com/akitaonrails/ai-memory/releases/tag/v2.3.2", + "archive_url": "https://github.com/akitaonrails/ai-memory/releases/download/v2.3.2/ai-memory-macos-aarch64.tar.gz", + "archive_sha256": "e0f07ad28938f3ed98a5feb21d11917245d77501764e0005049e7d9c1c16f28a", + "sidecar_sha256": "65d687fded968657b7227395ce1421dff8bf2a6f415c6515e0847090e94ed9be", + "binary_sha256": "23e64ae838efa5c100be5ec188dd9b395873e6bfa5078a1034c695aa48e6669d", + "license": "MIT", + "license_sha256": "18332c61780ce8e694d4fa330770cd4d8c85e33f47ac13a80d72d70bb032ae72", + "baseline_binary_sha256": "aa6f81b58db56a9c23e37e1252a4aed806a1190c03111a1db302319f129e6f90" + }, + "frozen_inputs": { + "config.toml": "5ee5fb3ddcb790c9a234143fdfa2f99b80ecf752a45c9e8cad625d75e9311331", + "oracle.json": "e6a47cd25fb239403522b16acdde271b712ee31478265ea4092d6ddad6b92bd1", + "pins.json": "f0309ba2ba49a3e6214207dcd7633b0c605b2abe3b2abd6175265f6dc6daaa92", + "run.py": "5bd0b047a6050e1f3c512dc3cce62489210daa66e7f5391e47e866c0e97db492" + }, + "checks": { + "baseline_binary_hash": true, + "archive_sha256": true, + "sidecar_sha256": true, + "archive_hash": true, + "sidecar_hash": true, + "sidecar_names_exact_archive": true, + "candidate_binary_hash": true, + "bundled_mit_license_hash": true, + "native_arm64_format": true, + "native_signature_integrity": true, + "sandbox_network_and_write_guards": false + }, + "cleanup": [], + "production_promoted": false, + "production_state_opened": false, + "model_invocation": false, + "enclosing_agent_usage": null, + "signature_assessment": { + "integrity_exit": 0, + "ad_hoc": true, + "gatekeeper_exit": 3, + "gatekeeper_accepted": false, + "overrides_or_signature_changes": false, + "gatekeeper_summary": "rejected; raw assessment retained privately" + }, + "passed": false, + "failure": { + "type": "AssertionError", + "message": "sandbox_network_and_write_guards" + }, + "id": "mac-ai-memory-232-preflight-20260920", + "evidence_class": "native_distribution_preflight", + "native_memory_processes_started": 0, + "native_mcp_calls": 0, + "decision": "retain_2.3.1_pending_functional_acceptance", + "functional_checks": "not run: frozen sandbox precondition not established", + "limitations": [ + "Checksum integrity shares the upstream release trust channel; no independent signed-release attestation was verified.", + "Native code-signature integrity passed; the artifact is ad-hoc signed, without a Developer ID team, and Gatekeeper assessment rejected it. No xattr removal, re-signing or protection override was used.", + "No ai-memory candidate execution, migration, scoped retrieval, no-capture runtime or restart acceptance occurred.", + "An additional sandbox condition introduced by this recipe failed before native memory startup. This does not establish a defect in ai-memory or claim that the original narrower synthetic task is impossible.", + "Private raw commands, assessment output and diagnostic stderr remain outside the checkout. No production memory, credentials, accounts or services were accessed by this execution.", + "No model run or token-savings claim; enclosing parent and child provider usage remains unknown." + ] +} diff --git a/blueprints/convergence-practice/mac-memory-patch/receipt.json b/blueprints/convergence-practice/mac-memory-patch/receipt.json new file mode 100644 index 000000000..578a19318 --- /dev/null +++ b/blueprints/convergence-practice/mac-memory-patch/receipt.json @@ -0,0 +1,286 @@ +{ + "schema_version": 1, + "host_scope": "macOS arm64 isolated synthetic qualification", + "started_utc": "2026-09-20T07:04:00.220545+00:00", + "platform": { + "macos": "26.5.1", + "architecture": "arm64", + "python": "3.14.7" + }, + "pins": { + "base_revision": "cabbe2c96e39096b510f739f07a6e4132da082de", + "source_commit": "353841d91618d20b110b208de284a74d0b960379", + "release_url": "https://github.com/akitaonrails/ai-memory/releases/tag/v2.3.2", + "archive_url": "https://github.com/akitaonrails/ai-memory/releases/download/v2.3.2/ai-memory-macos-aarch64.tar.gz", + "archive_sha256": "e0f07ad28938f3ed98a5feb21d11917245d77501764e0005049e7d9c1c16f28a", + "sidecar_sha256": "65d687fded968657b7227395ce1421dff8bf2a6f415c6515e0847090e94ed9be", + "binary_sha256": "23e64ae838efa5c100be5ec188dd9b395873e6bfa5078a1034c695aa48e6669d", + "license": "MIT", + "license_sha256": "18332c61780ce8e694d4fa330770cd4d8c85e33f47ac13a80d72d70bb032ae72", + "baseline_binary_sha256": "aa6f81b58db56a9c23e37e1252a4aed806a1190c03111a1db302319f129e6f90" + }, + "frozen_inputs": { + "config.toml": "5ee5fb3ddcb790c9a234143fdfa2f99b80ecf752a45c9e8cad625d75e9311331", + "oracle-functional.json": "3b90e6fb176c1d668f574bb64cb081f4938d29da3783464d804aa002dd6a49f0", + "pins.json": "f0309ba2ba49a3e6214207dcd7633b0c605b2abe3b2abd6175265f6dc6daaa92", + "run-functional.py": "7008e10cf6124c816d8fc8e400aecabcb0c91f1f0e836a4a284fb45ffe548490" + }, + "checks": { + "baseline_binary_hash": true, + "archive_hash": true, + "sidecar_hash": true, + "sidecar_names_exact_archive": true, + "candidate_binary_hash": true, + "bundled_mit_license_hash": true, + "native_arm64_format": true, + "native_signature_integrity": true, + "baseline_native_version": true, + "candidate_native_version": true, + "baseline_server_version": true, + "baseline_four_tools_available": true, + "baseline_alpha_body": true, + "baseline_alpha_fts": true, + "baseline_alpha_negative_query": true, + "baseline_alpha_negative_read": true, + "baseline_beta_body": true, + "baseline_beta_fts": true, + "baseline_beta_negative_query": true, + "baseline_beta_negative_read": true, + "baseline_no_capture_status": true, + "baseline_integrity_and_v62": true, + "candidate_server_version": true, + "candidate_four_tools_available": true, + "candidate_alpha_body": true, + "candidate_alpha_fts": true, + "candidate_alpha_negative_query": true, + "candidate_alpha_negative_read": true, + "candidate_beta_body": true, + "candidate_beta_fts": true, + "candidate_beta_negative_query": true, + "candidate_beta_negative_read": true, + "candidate_no_capture_status": true, + "candidate_git_reserved_path_rejected": true, + "candidate_unicode_exact_read": true, + "candidate-restart_server_version": true, + "candidate-restart_four_tools_available": true, + "candidate-restart_alpha_body": true, + "candidate-restart_alpha_fts": true, + "candidate-restart_alpha_negative_query": true, + "candidate-restart_alpha_negative_read": true, + "candidate-restart_beta_body": true, + "candidate-restart_beta_fts": true, + "candidate-restart_beta_negative_query": true, + "candidate-restart_beta_negative_read": true, + "candidate-restart_no_capture_status": true, + "restart_unicode_exact_body": true, + "restart_unicode_fts": true, + "superseded_marker_absent": true, + "candidate_integrity_and_v62": true, + "no_capture_or_embedding_rows": true, + "no_model_files": true, + "baseline_snapshot_unchanged": true, + "frozen_inputs_unchanged": true, + "binary_hashes_unchanged": true, + "all_owned_processes_cleanly_exited": true + }, + "cleanup": [ + { + "phase": "baseline", + "exit_code": 0, + "forced_termination": false, + "reader_closed": true, + "owned_process_exited": true, + "protocol_requests": 13 + }, + { + "phase": "candidate", + "exit_code": 0, + "forced_termination": false, + "reader_closed": true, + "owned_process_exited": true, + "protocol_requests": 15 + }, + { + "phase": "candidate-restart", + "exit_code": 0, + "forced_termination": false, + "reader_closed": true, + "owned_process_exited": true, + "protocol_requests": 14 + } + ], + "production_promoted": false, + "production_state_opened": false, + "model_invocation": false, + "enclosing_agent_usage": null, + "signature_assessment": { + "integrity_exit": 0, + "ad_hoc": true, + "gatekeeper_exit": 3, + "gatekeeper_accepted": false, + "overrides_or_signature_changes": false, + "gatekeeper_summary": "rejected; raw assessment retained privately" + }, + "os_filesystem_network_confinement": "not established; prior restricted-profile attempt failed", + "environment_keys": [ + "HOME", + "LANG", + "PATH", + "TMPDIR" + ], + "native_arguments_template": [ + "", + "--data-dir", + "/data", + "--config", + "/frozen/config.toml", + "serve", + "--transport", + "stdio", + "--no-watcher", + "--workspace", + "mac-patch-synthetic", + "--project", + "alpha" + ], + "versions": { + "baseline": "ai-memory 2.3.1", + "candidate": "ai-memory 2.3.2" + }, + "tool_names_by_phase": { + "baseline": [ + "memory_auto_improve", + "memory_briefing", + "memory_consolidate", + "memory_delete_page", + "memory_explore", + "memory_feedback", + "memory_forget_sweep", + "memory_handoff_accept", + "memory_handoff_begin", + "memory_handoff_cancel", + "memory_handoff_list", + "memory_install_self_routing", + "memory_lint", + "memory_message_cancel", + "memory_message_list", + "memory_message_pop", + "memory_message_send", + "memory_query", + "memory_read_page", + "memory_read_session_observations", + "memory_recent", + "memory_status", + "memory_write_page" + ], + "candidate": [ + "memory_auto_improve", + "memory_briefing", + "memory_consolidate", + "memory_delete_page", + "memory_explore", + "memory_feedback", + "memory_forget_sweep", + "memory_handoff_accept", + "memory_handoff_begin", + "memory_handoff_cancel", + "memory_handoff_list", + "memory_install_self_routing", + "memory_lint", + "memory_message_cancel", + "memory_message_list", + "memory_message_pop", + "memory_message_send", + "memory_query", + "memory_read_page", + "memory_read_session_observations", + "memory_recent", + "memory_status", + "memory_write_page" + ], + "candidate-restart": [ + "memory_auto_improve", + "memory_briefing", + "memory_consolidate", + "memory_delete_page", + "memory_explore", + "memory_feedback", + "memory_forget_sweep", + "memory_handoff_accept", + "memory_handoff_begin", + "memory_handoff_cancel", + "memory_handoff_list", + "memory_install_self_routing", + "memory_lint", + "memory_message_cancel", + "memory_message_list", + "memory_message_pop", + "memory_message_send", + "memory_query", + "memory_read_page", + "memory_read_session_observations", + "memory_recent", + "memory_status", + "memory_write_page" + ] + }, + "baseline_database": { + "integrity": "ok", + "forbidden_population": { + "sessions": 0, + "observations": 0, + "workstream_events": 0, + "workstream_native_sessions": 0, + "page_embeddings": 0 + }, + "v62_present": true, + "missing_page_windows": 0, + "page_versions": 2 + }, + "candidate_database": { + "integrity": "ok", + "forbidden_population": { + "sessions": 0, + "observations": 0, + "workstream_events": 0, + "workstream_native_sessions": 0, + "page_embeddings": 0 + }, + "v62_present": true, + "missing_page_windows": 0, + "page_versions": 4 + }, + "passed": true, + "finished_utc": "2026-09-20T07:04:01.047342+00:00", + "private_log_hashes": { + "baseline-store-hashes.private.json": "7487de79d0274deed693cfabced6064d845994a8485eadeb604c7539a3dae8c4", + "baseline-version.command.private.json": "11c226b8b0cf93c3630e85fb62b9b027287017fed38f89a1003520ad67ad1f52", + "baseline.protocol.json": "48eb6c0f329e2da829d5f0939a356419f81294f93b9192e2d7e0c683c0e544a6", + "baseline.stdout.jsonl": "583ad4cabe51ce800efaf61a0b01a5da30d0c326d6b3a35a04927a1d349f3733", + "candidate-restart.protocol.json": "8ad4f731dff2ad6b2c027e06a379c559feaa39d44615c089ceadbe5f554d30bf", + "candidate-restart.stdout.jsonl": "3210cb74e394d5390f793698fb05dc8e226f5f38b7f9a41f85e5718f6edf6cb7", + "candidate-version.command.private.json": "1957d1cb6d8379c83ac2d13655025843a157e429d3cd42323a0da4f83815a446", + "candidate.protocol.json": "e04801760c0a5d7c7702029d31215473aa05ebf0ae38505a16efb1dd451f62e4", + "candidate.stdout.jsonl": "a4f4b2e90de30863abcbe50f3dd94c32daea775b9d348cfb93ab818a9bec08b0", + "cleanup.json": "c6ccfd123281805f853cfba7c3fea99bf6f618a290437fe86c410e04710c625a", + "codesign-display.command.private.json": "e98e042c3161d28e099f4b030ffaa9e8622352c4d1d0a0253bc1450d4680635f", + "codesign-verify.command.private.json": "526538173af8fd7caa4706a67d2fe80f9ea51fb72e9c86c40ff1520c5b69a1b7", + "file.command.private.json": "348d9f1100bbec571ceaf8bdfd6aeb6543a8892db8d1823c11a80c68f3deb6d5", + "gatekeeper.command.private.json": "3ffa2d6c4a5405d8f7c299a1f731f5c477b0277240d055f7109d54d491a155ca" + }, + "id": "mac-ai-memory-232-functional-20260920", + "evidence_class": "native_cli_e2e", + "native_memory_processes_started": 3, + "native_mcp_calls": 36, + "native_protocol_requests": 42, + "decision": "qualified_within_isolated_synthetic_scope", + "limitations": [ + "Functional scope was re-frozen for attempt2 after coordinator direction; the failed stronger sandbox oracle and all diagnostics remain intact. OS filesystem/network confinement was not established.", + "Official hashes and signature integrity passed. Artifact is ad-hoc signed and Gatekeeper assessment rejected; actual version and server execution were allowed without xattr, signing, security-policy changes or an execution-denial bypass.", + "Acceptance uses synthetic scoped decisions only, not production backup/restore, real data migration, local embeddings, client reconnection, an active LaunchAgent or another host.", + "No production state, accounts, credentials, hooks, services, client registration or command symlinks were changed. Only the exact known2.3.1 binary was used.", + "Provider/model features were explicitly disabled, environment credentials were not forwarded, and capture/embedding tables remain empty. This is not an independent OS network-traffic audit.", + "Raw logs, synthetic state, archive and frozen baseline are retained privately. Public selected facts preserve synthetic requests and relevant native outcomes; hashes alone do not independently certify historical execution.", + "Fixture performs no model/provider calls; enclosing parent/child provider usage is unknown. No token-saving claim." + ] +} diff --git a/blueprints/convergence-practice/mac-memory-patch/run-functional.py b/blueprints/convergence-practice/mac-memory-patch/run-functional.py new file mode 100644 index 000000000..196e27c9d --- /dev/null +++ b/blueprints/convergence-practice/mac-memory-patch/run-functional.py @@ -0,0 +1,333 @@ +#!/usr/bin/env python3 +"""Original-scope synthetic Mac patch trial; no OS confinement claim or promotion.""" +import argparse +import datetime +import hashlib +import json +import os +from pathlib import Path +import platform +import queue +import shutil +import sqlite3 +import subprocess +import tarfile +import threading +import time +import urllib.request + +HERE = Path(__file__).resolve().parent + + +def sha(path): + with Path(path).open('rb') as stream: + return hashlib.file_digest(stream, 'sha256').hexdigest() + + +def save(path, value): + Path(path).write_text(json.dumps(value, indent=2, ensure_ascii=False) + '\n') + + +def tree_hashes(root): + return {str(p.relative_to(root)): sha(p) for p in sorted(root.rglob('*')) if p.is_file()} + + +def payload(response): + if 'error' in response or response.get('result', {}).get('isError'): + raise ValueError('native failure is not an empty successful response') + content = response['result']['content'] + if len(content) != 1 or content[0]['type'] != 'text': + raise ValueError('unexpected native content shape') + value = json.loads(content[0]['text']) + if not isinstance(value, dict): + raise ValueError('expected native object') + return value + + +def rejected(response): + return isinstance(response.get('error'), dict) or response.get('result', {}).get('isError') is True + + +class MCP: + def __init__(self, argv, cwd, env, root, name, cleanup): + self.root, self.name, self.records = root, name, [] + self.cleanup = cleanup + self.err = (root / (name + '.stderr')).open('w') + self.raw = (root / (name + '.stdout.jsonl')).open('w') + self.proc = subprocess.Popen(argv, cwd=cwd, env=env, stdin=subprocess.PIPE, + stdout=subprocess.PIPE, stderr=self.err, text=True) + self.replies = queue.Queue() + self.thread = threading.Thread(target=self.read, daemon=True) + self.thread.start() + + def read(self): + try: + for line in self.proc.stdout: + self.raw.write(line) + self.raw.flush() + self.replies.put(json.loads(line)) + except Exception as exc: + self.replies.put(exc) + finally: + self.replies.put(EOFError('native stdio closed')) + + def request(self, method, params): + identity = len(self.records) + 1 + req = {'jsonrpc': '2.0', 'id': identity, 'method': method, 'params': params} + self.proc.stdin.write(json.dumps(req) + '\n') + self.proc.stdin.flush() + deadline = time.monotonic() + 20 + while True: + response = self.replies.get(timeout=max(.001, deadline-time.monotonic())) + if isinstance(response, Exception): + raise response + if response.get('id') == identity: + self.records.append({'request': req, 'response': response}) + save(self.root / (self.name + '.protocol.json'), self.records) + return response + if time.monotonic() >= deadline: + raise TimeoutError('native response deadline') + + def initialize(self): + response = self.request('initialize', {'protocolVersion': '2025-03-26', + 'capabilities': {}, 'clientInfo': {'name': 'mac-memory-patch-synthetic', 'version': '1'}}) + if 'error' in response: + raise ValueError('initialization rejected') + self.proc.stdin.write(json.dumps({'jsonrpc': '2.0', 'method': 'notifications/initialized'}) + '\n') + self.proc.stdin.flush() + return response['result'] + + def call(self, name, **args): + return self.request('tools/call', {'name': name, 'arguments': args}) + + def close(self): + forced = False + try: + self.proc.stdin.close() + self.proc.wait(timeout=10) + except (subprocess.TimeoutExpired, BrokenPipeError): + forced = True + self.proc.terminate() + try: + self.proc.wait(timeout=5) + except subprocess.TimeoutExpired: + self.proc.kill() + self.proc.wait(timeout=5) + self.thread.join(timeout=2) + self.err.close() + self.raw.close() + self.proc.stdout.close() + result = {'phase': self.name, 'exit_code': self.proc.returncode, + 'forced_termination': forced, 'reader_closed': not self.thread.is_alive(), + 'owned_process_exited': self.proc.poll() is not None, + 'protocol_requests': len(self.records)} + self.cleanup.append(result) + save(self.root / 'cleanup.json', self.cleanup) + + +def database_state(data): + with sqlite3.connect((data / 'db/memory.sqlite').as_uri() + '?mode=ro', uri=True) as db: + tables = {r[0] for r in db.execute("SELECT name FROM sqlite_master WHERE type='table'")} + required = ['sessions', 'observations', 'workstream_events', 'workstream_native_sessions', 'page_embeddings'] + if not set(required).issubset(tables): + raise ValueError('missing no-capture/no-embedding tables') + return {'integrity': db.execute('PRAGMA integrity_check').fetchone()[0], + 'forbidden_population': {t: db.execute('SELECT count(*) FROM '+t).fetchone()[0] for t in required}, + 'v62_present': db.execute('SELECT count(*) FROM refinery_schema_history WHERE version=62').fetchone()[0] == 1, + 'missing_page_windows': db.execute('SELECT count(*) FROM pages WHERE valid_from IS NULL').fetchone()[0], + 'page_versions': db.execute('SELECT count(*) FROM pages').fetchone()[0]} + + +def main(): + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument('--prefix', type=Path, required=True) + parser.add_argument('--old-binary', type=Path, required=True) + parser.add_argument('--attempt', required=True) + args = parser.parse_args() + os.umask(0o077) + prefix = args.prefix.expanduser().resolve() + old = args.old_binary.expanduser().resolve(strict=True) + if platform.system() != 'Darwin' or platform.machine() != 'arm64': + raise ValueError('this recipe requires native Apple Silicon macOS') + if not args.attempt.replace('-', '').isalnum() or prefix == Path.home() or prefix.is_relative_to(HERE): + raise ValueError('choose a named new attempt and a private prefix outside the checkout') + prefix.mkdir(parents=True, exist_ok=True, mode=0o700) + attempt = prefix / args.attempt + attempt.mkdir(mode=0o700) + (attempt / 'tmp').mkdir() + pins = json.loads((HERE / 'pins.json').read_text()) + oracle = json.loads((HERE / 'oracle-functional.json').read_text()) + frozen = attempt / 'frozen' + frozen.mkdir() + for filename in ['run-functional.py', 'pins.json', 'oracle-functional.json', 'config.toml']: + shutil.copyfile(HERE / filename, frozen / filename) + frozen_hashes = tree_hashes(frozen) + checks, cleanup = {}, [] + result = {'schema_version': 1, 'host_scope': 'macOS arm64 isolated synthetic qualification', + 'started_utc': datetime.datetime.now(datetime.timezone.utc).isoformat(), + 'platform': {'macos': platform.mac_ver()[0], 'architecture': platform.machine(), + 'python': platform.python_version()}, + 'pins': pins, 'frozen_inputs': frozen_hashes, 'checks': checks, + 'cleanup': cleanup, 'production_promoted': False, 'production_state_opened': False, + 'model_invocation': False, 'enclosing_agent_usage': None} + + def check(name, value): + checks[name] = bool(value) + save(attempt / 'receipt.json', result) + if not value: + raise AssertionError(name) + + def command(name, argv, env=None): + cp = subprocess.run(argv, cwd=attempt, env=env, capture_output=True, text=True, timeout=30) + save(attempt / (name+'.command.private.json'), {'argv': list(map(str, argv)), + 'exit_code': cp.returncode, 'stdout': cp.stdout, 'stderr': cp.stderr}) + return cp + + try: + check('baseline_binary_hash', sha(old) == pins['baseline_binary_sha256']) + installation = prefix / 'distribution-2.3.2' + if not installation.exists(): + installation.mkdir() + for suffix, key in [('', 'archive_sha256'), ('.sha256', 'sidecar_sha256')]: + url = pins['archive_url'] + suffix + path = installation / ('ai-memory-macos-aarch64.tar.gz'+suffix) + with urllib.request.urlopen(url, timeout=30) as response, path.open('xb') as target: + shutil.copyfileobj(response, target) + check(key, sha(path) == pins[key]) + archive = installation / 'ai-memory-macos-aarch64.tar.gz' + with tarfile.open(archive, 'r:gz') as tar: + members = tar.getmembers() + if any(Path(m.name).is_absolute() or '..' in Path(m.name).parts or + m.issym() or m.islnk() or not (m.isfile() or m.isdir()) for m in members): + raise ValueError('unsafe release archive') + tar.extractall(installation / 'unpacked', members=members, filter='data') + check('archive_hash', sha(installation / 'ai-memory-macos-aarch64.tar.gz') == pins['archive_sha256']) + sidecar = installation / 'ai-memory-macos-aarch64.tar.gz.sha256' + check('sidecar_hash', sha(sidecar) == pins['sidecar_sha256']) + check('sidecar_names_exact_archive', sidecar.read_text().split() == [pins['archive_sha256'], 'ai-memory-macos-aarch64.tar.gz']) + new = installation / 'unpacked/ai-memory' + check('candidate_binary_hash', sha(new) == pins['binary_sha256']) + check('bundled_mit_license_hash', sha(installation / 'unpacked/LICENSE') == pins['license_sha256']) + cp = command('file', ['/usr/bin/file', str(new)]) + check('native_arm64_format', cp.returncode == 0 and 'Mach-O 64-bit executable arm64' in cp.stdout) + cp = command('codesign-verify', ['/usr/bin/codesign', '--verify', '--strict', '--verbose=2', str(new)]) + check('native_signature_integrity', cp.returncode == 0) + detail = command('codesign-display', ['/usr/bin/codesign', '-dv', '--verbose=4', str(new)]) + gatekeeper = command('gatekeeper', ['/usr/sbin/spctl', '--assess', '--type', 'execute', '--verbose=4', str(new)]) + result['signature_assessment'] = {'integrity_exit': cp.returncode, + 'ad_hoc': 'Signature=adhoc' in detail.stderr, + 'gatekeeper_exit': gatekeeper.returncode, + 'gatekeeper_accepted': gatekeeper.returncode == 0, + 'overrides_or_signature_changes': False, + 'gatekeeper_summary': 'rejected: no usable signature' if 'no usable signature' in gatekeeper.stderr else + ('accepted' if gatekeeper.returncode == 0 else 'rejected; raw assessment retained privately')} + env = {'PATH': '/usr/bin:/bin:/usr/sbin:/sbin', 'HOME': str(Path.home()), + 'LANG': 'en_US.UTF-8', 'TMPDIR': str(attempt / 'tmp')} + sandbox = [] + result['os_filesystem_network_confinement'] = 'not established; prior restricted-profile attempt failed' + result['environment_keys'] = sorted(env) + result['native_arguments_template'] = ['', '--data-dir', '/data', '--config', '/frozen/config.toml', 'serve', '--transport', 'stdio', '--no-watcher', '--workspace', oracle['workspace'], '--project', 'alpha'] + versions = {} + for name, binary, expected in [('baseline', old, '2.3.1'), ('candidate', new, '2.3.2')]: + cp = command(name+'-version', sandbox+[str(binary), '--version'], env) + versions[name] = cp.stdout.strip() + check(name+'_native_version', cp.returncode == 0 and versions[name] == 'ai-memory '+expected) + result['versions'] = versions + config = frozen / 'config.toml' + data = attempt / 'data' + workspace = oracle['workspace'] + + def start(name, binary): + m = MCP(sandbox + [str(binary), '--data-dir', str(data), '--config', str(config), + 'serve', '--transport', 'stdio', '--no-watcher', '--workspace', workspace, + '--project', 'alpha'], attempt, env, attempt, name, cleanup) + return m + + def initialize(m, version): + info = m.initialize() + check(m.name+'_server_version', info['serverInfo']['version'] == version) + listed = m.request('tools/list', {}) + names = sorted(t['name'] for t in listed['result']['tools']) + result.setdefault('tool_names_by_phase', {})[m.name] = names + check(m.name+'_four_tools_available', set(oracle['required_tools']).issubset(names)) + + def call(m, tool, project='alpha', **arguments): + return m.call(tool, workspace=workspace, project=project, **arguments) + + def verify_scopes(m, alpha_body, alpha_marker): + for key, body, marker in [('alpha', alpha_body, alpha_marker), ('beta', oracle['beta']['body'], oracle['beta']['marker'])]: + item = oracle[key] + read = payload(call(m, 'memory_read_page', project=key, path=item['path'])) + check(m.name+'_'+key+'_body', read['body'] == body) + query = payload(call(m, 'memory_query', project=key, query=marker, explain=True)) + check(m.name+'_'+key+'_fts', [h['path'] for h in query['hits']] == [item['path']] and 'fts' in query['streams_active']) + other = 'beta' if key == 'alpha' else 'alpha' + query = payload(call(m, 'memory_query', project=other, query=marker)) + check(m.name+'_'+key+'_negative_query', query['hits'] == []) + negative = call(m, 'memory_read_page', project=other, path=item['path']) + check(m.name+'_'+key+'_negative_read', rejected(negative)) + status = payload(call(m, 'memory_status')) + check(m.name+'_no_capture_status', status['counts']['sessions'] == 0 and status['counts']['observations'] == 0) + + m = start('baseline', old) + try: + initialize(m, '2.3.1') + for key in ['alpha', 'beta']: + item = oracle[key] + payload(call(m, 'memory_write_page', project=key, path=item['path'], body=item['body'])) + verify_scopes(m, oracle['alpha']['body'], oracle['alpha']['marker']) + finally: + m.close() + baseline_state = database_state(data) + result['baseline_database'] = baseline_state + check('baseline_integrity_and_v62', baseline_state['integrity'] == 'ok' and baseline_state['v62_present'] and baseline_state['missing_page_windows'] == 0) + baseline = attempt / 'frozen-baseline-store' + shutil.copytree(data, baseline) + baseline_hashes = tree_hashes(baseline) + save(attempt / 'baseline-store-hashes.private.json', baseline_hashes) + m = start('candidate', new) + try: + initialize(m, '2.3.2') + verify_scopes(m, oracle['alpha']['body'], oracle['alpha']['marker']) + negative = call(m, 'memory_write_page', path=oracle['reserved_path'], body='Synthetic rejected page.\n') + check('candidate_git_reserved_path_rejected', rejected(negative)) + item = oracle['unicode'] + payload(call(m, 'memory_write_page', path=item['path'], body=item['body'])) + check('candidate_unicode_exact_read', payload(call(m, 'memory_read_page', path=item['path']))['body'] == item['body']) + payload(call(m, 'memory_write_page', path=oracle['alpha']['path'], body=oracle['updated_alpha']['body'])) + finally: + m.close() + m = start('candidate-restart', new) + try: + initialize(m, '2.3.2') + verify_scopes(m, oracle['updated_alpha']['body'], oracle['updated_alpha']['marker']) + item = oracle['unicode'] + check('restart_unicode_exact_body', payload(call(m, 'memory_read_page', path=item['path']))['body'] == item['body']) + q = payload(call(m, 'memory_query', query=item['marker'], explain=True)) + check('restart_unicode_fts', [h['path'] for h in q['hits']] == [item['path']] and 'fts' in q['streams_active']) + check('superseded_marker_absent', payload(call(m, 'memory_query', query=oracle['alpha']['marker']))['hits'] == []) + finally: + m.close() + state = database_state(data) + result['candidate_database'] = state + check('candidate_integrity_and_v62', state['integrity'] == 'ok' and state['v62_present'] and state['missing_page_windows'] == 0) + check('no_capture_or_embedding_rows', all(n == 0 for n in state['forbidden_population'].values())) + check('no_model_files', not (data/'models').exists() or not any(p.is_file() for p in (data/'models').rglob('*'))) + check('baseline_snapshot_unchanged', baseline_hashes == tree_hashes(baseline)) + check('frozen_inputs_unchanged', frozen_hashes == tree_hashes(frozen)) + check('binary_hashes_unchanged', sha(old) == pins['baseline_binary_sha256'] and sha(new) == pins['binary_sha256']) + check('all_owned_processes_cleanly_exited', len(cleanup) == 3 and all(x['exit_code'] == 0 and not x['forced_termination'] and x['owned_process_exited'] and x['reader_closed'] for x in cleanup)) + result['passed'] = True + except Exception as exc: + result.update(passed=False, failure={'type': type(exc).__name__, 'message': str(exc)}) + raise + finally: + result['finished_utc'] = datetime.datetime.now(datetime.timezone.utc).isoformat() + result['private_log_hashes'] = {p.name: sha(p) for p in sorted(attempt.glob('*.json*')) if p.name != 'receipt.json'} + save(attempt/'receipt.json', result) + print(json.dumps({'passed': result.get('passed', False), 'checks': len(checks), + 'failed_checks': [k for k,v in checks.items() if not v], 'cleanup': cleanup})) + + +if __name__ == '__main__': + main() diff --git a/blueprints/convergence-practice/mac-memory-patch/run.py b/blueprints/convergence-practice/mac-memory-patch/run.py new file mode 100644 index 000000000..3343958b0 --- /dev/null +++ b/blueprints/convergence-practice/mac-memory-patch/run.py @@ -0,0 +1,341 @@ +#!/usr/bin/env python3 +"""Mac-only, synthetic ai-memory 2.3.1 -> 2.3.2 qualification; no promotion.""" +import argparse +import datetime +import hashlib +import json +import os +from pathlib import Path +import platform +import queue +import shutil +import sqlite3 +import subprocess +import tarfile +import threading +import time +import urllib.request + +HERE = Path(__file__).resolve().parent + + +def sha(path): + with Path(path).open('rb') as stream: + return hashlib.file_digest(stream, 'sha256').hexdigest() + + +def save(path, value): + Path(path).write_text(json.dumps(value, indent=2, ensure_ascii=False) + '\n') + + +def tree_hashes(root): + return {str(p.relative_to(root)): sha(p) for p in sorted(root.rglob('*')) if p.is_file()} + + +def payload(response): + if 'error' in response or response.get('result', {}).get('isError'): + raise ValueError('native failure is not an empty successful response') + content = response['result']['content'] + if len(content) != 1 or content[0]['type'] != 'text': + raise ValueError('unexpected native content shape') + value = json.loads(content[0]['text']) + if not isinstance(value, dict): + raise ValueError('expected native object') + return value + + +def rejected(response): + return isinstance(response.get('error'), dict) or response.get('result', {}).get('isError') is True + + +class MCP: + def __init__(self, argv, cwd, env, root, name, cleanup): + self.root, self.name, self.records = root, name, [] + self.cleanup = cleanup + self.err = (root / (name + '.stderr')).open('w') + self.raw = (root / (name + '.stdout.jsonl')).open('w') + self.proc = subprocess.Popen(argv, cwd=cwd, env=env, stdin=subprocess.PIPE, + stdout=subprocess.PIPE, stderr=self.err, text=True) + self.replies = queue.Queue() + self.thread = threading.Thread(target=self.read, daemon=True) + self.thread.start() + + def read(self): + try: + for line in self.proc.stdout: + self.raw.write(line) + self.raw.flush() + self.replies.put(json.loads(line)) + except Exception as exc: + self.replies.put(exc) + finally: + self.replies.put(EOFError('native stdio closed')) + + def request(self, method, params): + identity = len(self.records) + 1 + req = {'jsonrpc': '2.0', 'id': identity, 'method': method, 'params': params} + self.proc.stdin.write(json.dumps(req) + '\n') + self.proc.stdin.flush() + deadline = time.monotonic() + 20 + while True: + response = self.replies.get(timeout=max(.001, deadline-time.monotonic())) + if isinstance(response, Exception): + raise response + if response.get('id') == identity: + self.records.append({'request': req, 'response': response}) + save(self.root / (self.name + '.protocol.json'), self.records) + return response + if time.monotonic() >= deadline: + raise TimeoutError('native response deadline') + + def initialize(self): + response = self.request('initialize', {'protocolVersion': '2025-03-26', + 'capabilities': {}, 'clientInfo': {'name': 'mac-memory-patch-synthetic', 'version': '1'}}) + if 'error' in response: + raise ValueError('initialization rejected') + self.proc.stdin.write(json.dumps({'jsonrpc': '2.0', 'method': 'notifications/initialized'}) + '\n') + self.proc.stdin.flush() + return response['result'] + + def call(self, name, **args): + return self.request('tools/call', {'name': name, 'arguments': args}) + + def close(self): + forced = False + try: + self.proc.stdin.close() + self.proc.wait(timeout=10) + except (subprocess.TimeoutExpired, BrokenPipeError): + forced = True + self.proc.terminate() + try: + self.proc.wait(timeout=5) + except subprocess.TimeoutExpired: + self.proc.kill() + self.proc.wait(timeout=5) + self.thread.join(timeout=2) + self.err.close() + self.raw.close() + self.proc.stdout.close() + result = {'phase': self.name, 'exit_code': self.proc.returncode, + 'forced_termination': forced, 'reader_closed': not self.thread.is_alive(), + 'owned_process_exited': self.proc.poll() is not None, + 'protocol_requests': len(self.records)} + self.cleanup.append(result) + save(self.root / 'cleanup.json', self.cleanup) + + +def database_state(data): + with sqlite3.connect((data / 'db/memory.sqlite').as_uri() + '?mode=ro', uri=True) as db: + tables = {r[0] for r in db.execute("SELECT name FROM sqlite_master WHERE type='table'")} + required = ['sessions', 'observations', 'workstream_events', 'workstream_native_sessions', 'page_embeddings'] + if not set(required).issubset(tables): + raise ValueError('missing no-capture/no-embedding tables') + return {'integrity': db.execute('PRAGMA integrity_check').fetchone()[0], + 'forbidden_population': {t: db.execute('SELECT count(*) FROM '+t).fetchone()[0] for t in required}, + 'v62_present': db.execute('SELECT count(*) FROM refinery_schema_history WHERE version=62').fetchone()[0] == 1, + 'missing_page_windows': db.execute('SELECT count(*) FROM pages WHERE valid_from IS NULL').fetchone()[0], + 'page_versions': db.execute('SELECT count(*) FROM pages').fetchone()[0]} + + +def main(): + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument('--prefix', type=Path, required=True) + parser.add_argument('--old-binary', type=Path, required=True) + parser.add_argument('--attempt', required=True) + args = parser.parse_args() + os.umask(0o077) + prefix = args.prefix.expanduser().resolve() + old = args.old_binary.expanduser().resolve(strict=True) + if platform.system() != 'Darwin' or platform.machine() != 'arm64': + raise ValueError('this recipe requires native Apple Silicon macOS') + if not args.attempt.replace('-', '').isalnum() or prefix == Path.home() or prefix.is_relative_to(HERE): + raise ValueError('choose a named new attempt and a private prefix outside the checkout') + prefix.mkdir(parents=True, exist_ok=True, mode=0o700) + attempt = prefix / args.attempt + attempt.mkdir(mode=0o700) + (attempt / 'tmp').mkdir() + pins = json.loads((HERE / 'pins.json').read_text()) + oracle = json.loads((HERE / 'oracle.json').read_text()) + frozen = attempt / 'frozen' + frozen.mkdir() + for filename in ['run.py', 'pins.json', 'oracle.json', 'config.toml']: + shutil.copyfile(HERE / filename, frozen / filename) + frozen_hashes = tree_hashes(frozen) + checks, cleanup = {}, [] + result = {'schema_version': 1, 'host_scope': 'macOS arm64 isolated synthetic qualification', + 'started_utc': datetime.datetime.now(datetime.timezone.utc).isoformat(), + 'platform': {'macos': platform.mac_ver()[0], 'architecture': platform.machine(), + 'python': platform.python_version()}, + 'pins': pins, 'frozen_inputs': frozen_hashes, 'checks': checks, + 'cleanup': cleanup, 'production_promoted': False, 'production_state_opened': False, + 'model_invocation': False, 'enclosing_agent_usage': None} + + def check(name, value): + checks[name] = bool(value) + save(attempt / 'receipt.json', result) + if not value: + raise AssertionError(name) + + def command(name, argv, env=None): + cp = subprocess.run(argv, cwd=attempt, env=env, capture_output=True, text=True, timeout=30) + save(attempt / (name+'.command.private.json'), {'argv': list(map(str, argv)), + 'exit_code': cp.returncode, 'stdout': cp.stdout, 'stderr': cp.stderr}) + return cp + + try: + check('baseline_binary_hash', sha(old) == pins['baseline_binary_sha256']) + installation = prefix / 'distribution-2.3.2' + if not installation.exists(): + installation.mkdir() + for suffix, key in [('', 'archive_sha256'), ('.sha256', 'sidecar_sha256')]: + url = pins['archive_url'] + suffix + path = installation / ('ai-memory-macos-aarch64.tar.gz'+suffix) + with urllib.request.urlopen(url, timeout=30) as response, path.open('xb') as target: + shutil.copyfileobj(response, target) + check(key, sha(path) == pins[key]) + archive = installation / 'ai-memory-macos-aarch64.tar.gz' + with tarfile.open(archive, 'r:gz') as tar: + members = tar.getmembers() + if any(Path(m.name).is_absolute() or '..' in Path(m.name).parts or + m.issym() or m.islnk() or not (m.isfile() or m.isdir()) for m in members): + raise ValueError('unsafe release archive') + tar.extractall(installation / 'unpacked', members=members, filter='data') + check('archive_hash', sha(installation / 'ai-memory-macos-aarch64.tar.gz') == pins['archive_sha256']) + sidecar = installation / 'ai-memory-macos-aarch64.tar.gz.sha256' + check('sidecar_hash', sha(sidecar) == pins['sidecar_sha256']) + check('sidecar_names_exact_archive', sidecar.read_text().split() == [pins['archive_sha256'], 'ai-memory-macos-aarch64.tar.gz']) + new = installation / 'unpacked/ai-memory' + check('candidate_binary_hash', sha(new) == pins['binary_sha256']) + check('bundled_mit_license_hash', sha(installation / 'unpacked/LICENSE') == pins['license_sha256']) + cp = command('file', ['/usr/bin/file', str(new)]) + check('native_arm64_format', cp.returncode == 0 and 'Mach-O 64-bit executable arm64' in cp.stdout) + cp = command('codesign-verify', ['/usr/bin/codesign', '--verify', '--strict', '--verbose=2', str(new)]) + check('native_signature_integrity', cp.returncode == 0) + detail = command('codesign-display', ['/usr/bin/codesign', '-dv', '--verbose=4', str(new)]) + gatekeeper = command('gatekeeper', ['/usr/sbin/spctl', '--assess', '--type', 'execute', '--verbose=4', str(new)]) + result['signature_assessment'] = {'integrity_exit': cp.returncode, + 'ad_hoc': 'Signature=adhoc' in detail.stderr, + 'gatekeeper_exit': gatekeeper.returncode, + 'gatekeeper_accepted': gatekeeper.returncode == 0, + 'overrides_or_signature_changes': False, + 'gatekeeper_summary': 'rejected: no usable signature' if 'no usable signature' in gatekeeper.stderr else + ('accepted' if gatekeeper.returncode == 0 else 'rejected; raw assessment retained privately')} + env = {'PATH': '/usr/bin:/bin:/usr/sbin:/sbin', 'HOME': str(Path.home()), + 'LANG': 'en_US.UTF-8', 'TMPDIR': str(attempt / 'tmp')} + profile = attempt / 'sandbox.sb' + profile.write_text('(version 1)\n(deny default)\n(allow process*)\n(allow sysctl-read)\n' + '(allow mach-lookup)\n(allow file-read* ' + + ' '.join('(subpath '+json.dumps(p)+')' for p in ['/System', '/usr', '/Library', '/private/etc', '/dev', '/private/var/db', str(prefix), str(old.parent)]) + + ')\n(allow file-write* (subpath '+json.dumps(str(attempt))+'))\n') + sandbox = ['/usr/bin/sandbox-exec', '-f', str(profile)] + probe = ('import errno,pathlib,socket; s=socket.socket(); ' + '\ntry: s.connect(("127.0.0.1",9))\nexcept OSError as e: assert e.errno==errno.EPERM\nelse: raise AssertionError("network allowed")\n' + 'try: pathlib.Path('+repr(str(prefix/'escape-probe'))+').write_text("guard failure")\n' + 'except OSError as e: assert e.errno==errno.EPERM\nelse: raise AssertionError("outside write allowed")\nprint("guards passed")') + cp = command('sandbox-guards', sandbox+['/usr/bin/python3', '-c', probe], env) + check('sandbox_network_and_write_guards', cp.returncode == 0 and cp.stdout.strip() == 'guards passed') + versions = {} + for name, binary, expected in [('baseline', old, '2.3.1'), ('candidate', new, '2.3.2')]: + cp = command(name+'-version', sandbox+[str(binary), '--version'], env) + versions[name] = cp.stdout.strip() + check(name+'_native_version', cp.returncode == 0 and versions[name] == 'ai-memory '+expected) + result['versions'] = versions + config = frozen / 'config.toml' + data = attempt / 'data' + workspace = oracle['workspace'] + + def start(name, binary): + m = MCP(sandbox + [str(binary), '--data-dir', str(data), '--config', str(config), + 'serve', '--transport', 'stdio', '--no-watcher', '--workspace', workspace, + '--project', 'alpha'], attempt, env, attempt, name, cleanup) + return m + + def initialize(m, version): + info = m.initialize() + check(m.name+'_server_version', info['serverInfo']['version'] == version) + listed = m.request('tools/list', {}) + names = sorted(t['name'] for t in listed['result']['tools']) + result.setdefault('tool_names_by_phase', {})[m.name] = names + check(m.name+'_four_tools_available', set(oracle['required_tools']).issubset(names)) + + def call(m, tool, project='alpha', **arguments): + return m.call(tool, workspace=workspace, project=project, **arguments) + + def verify_scopes(m, alpha_body, alpha_marker): + for key, body, marker in [('alpha', alpha_body, alpha_marker), ('beta', oracle['beta']['body'], oracle['beta']['marker'])]: + item = oracle[key] + read = payload(call(m, 'memory_read_page', project=key, path=item['path'])) + check(m.name+'_'+key+'_body', read['body'] == body) + query = payload(call(m, 'memory_query', project=key, query=marker, explain=True)) + check(m.name+'_'+key+'_fts', [h['path'] for h in query['hits']] == [item['path']] and 'fts' in query['streams_active']) + other = 'beta' if key == 'alpha' else 'alpha' + query = payload(call(m, 'memory_query', project=other, query=marker)) + check(m.name+'_'+key+'_negative_query', query['hits'] == []) + negative = call(m, 'memory_read_page', project=other, path=item['path']) + check(m.name+'_'+key+'_negative_read', rejected(negative)) + status = payload(call(m, 'memory_status')) + check(m.name+'_no_capture_status', status['counts']['sessions'] == 0 and status['counts']['observations'] == 0) + + m = start('baseline', old) + try: + initialize(m, '2.3.1') + for key in ['alpha', 'beta']: + item = oracle[key] + payload(call(m, 'memory_write_page', project=key, path=item['path'], body=item['body'])) + verify_scopes(m, oracle['alpha']['body'], oracle['alpha']['marker']) + finally: + m.close() + baseline_state = database_state(data) + result['baseline_database'] = baseline_state + check('baseline_integrity_and_v62', baseline_state['integrity'] == 'ok' and baseline_state['v62_present'] and baseline_state['missing_page_windows'] == 0) + baseline = attempt / 'frozen-baseline-store' + shutil.copytree(data, baseline) + baseline_hashes = tree_hashes(baseline) + save(attempt / 'baseline-store-hashes.private.json', baseline_hashes) + m = start('candidate', new) + try: + initialize(m, '2.3.2') + verify_scopes(m, oracle['alpha']['body'], oracle['alpha']['marker']) + negative = call(m, 'memory_write_page', path=oracle['reserved_path'], body='Synthetic rejected page.\n') + check('candidate_git_reserved_path_rejected', rejected(negative)) + item = oracle['unicode'] + payload(call(m, 'memory_write_page', path=item['path'], body=item['body'])) + check('candidate_unicode_exact_read', payload(call(m, 'memory_read_page', path=item['path']))['body'] == item['body']) + payload(call(m, 'memory_write_page', path=oracle['alpha']['path'], body=oracle['updated_alpha']['body'])) + finally: + m.close() + m = start('candidate-restart', new) + try: + initialize(m, '2.3.2') + verify_scopes(m, oracle['updated_alpha']['body'], oracle['updated_alpha']['marker']) + item = oracle['unicode'] + check('restart_unicode_exact_body', payload(call(m, 'memory_read_page', path=item['path']))['body'] == item['body']) + q = payload(call(m, 'memory_query', query=item['marker'], explain=True)) + check('restart_unicode_fts', [h['path'] for h in q['hits']] == [item['path']] and 'fts' in q['streams_active']) + check('superseded_marker_absent', payload(call(m, 'memory_query', query=oracle['alpha']['marker']))['hits'] == []) + finally: + m.close() + state = database_state(data) + result['candidate_database'] = state + check('candidate_integrity_and_v62', state['integrity'] == 'ok' and state['v62_present'] and state['missing_page_windows'] == 0) + check('no_capture_or_embedding_rows', all(n == 0 for n in state['forbidden_population'].values())) + check('no_model_files', not (data/'models').exists() or not any(p.is_file() for p in (data/'models').rglob('*'))) + check('baseline_snapshot_unchanged', baseline_hashes == tree_hashes(baseline)) + check('frozen_inputs_unchanged', frozen_hashes == tree_hashes(frozen)) + check('binary_hashes_unchanged', sha(old) == pins['baseline_binary_sha256'] and sha(new) == pins['binary_sha256']) + check('all_owned_processes_cleanly_exited', len(cleanup) == 3 and all(x['exit_code'] == 0 and not x['forced_termination'] and x['owned_process_exited'] and x['reader_closed'] for x in cleanup)) + result['passed'] = True + except Exception as exc: + result.update(passed=False, failure={'type': type(exc).__name__, 'message': str(exc)}) + raise + finally: + result['finished_utc'] = datetime.datetime.now(datetime.timezone.utc).isoformat() + result['private_log_hashes'] = {p.name: sha(p) for p in sorted(attempt.glob('*.json*')) if p.name != 'receipt.json'} + save(attempt/'receipt.json', result) + print(json.dumps({'passed': result.get('passed', False), 'checks': len(checks), + 'failed_checks': [k for k,v in checks.items() if not v], 'cleanup': cleanup})) + + +if __name__ == '__main__': + main() diff --git a/blueprints/convergence-practice/mac-memory-patch/test_evidence.py b/blueprints/convergence-practice/mac-memory-patch/test_evidence.py new file mode 100644 index 000000000..56f29b583 --- /dev/null +++ b/blueprints/convergence-practice/mac-memory-patch/test_evidence.py @@ -0,0 +1,101 @@ +import copy +import importlib.util +import json +from pathlib import Path +import tempfile +import unittest + +ROOT = Path(__file__).resolve().parent +spec = importlib.util.spec_from_file_location('mac_patch_audit', ROOT/'audit.py') +module = importlib.util.module_from_spec(spec) +spec.loader.exec_module(module) + + +class EvidenceTests(unittest.TestCase): + def setUp(self): + self.receipt = json.loads((ROOT/'receipt-attempt-1.json').read_text()) + self.attempts = json.loads((ROOT/'prior-attempts.json').read_text()) + + def test_retained_incomplete_attempt(self): + result = module.audit(self.receipt, self.attempts) + self.assertTrue(result['evidence_consistent']) + self.assertFalse(result['functional_acceptance']) + + def test_no_promotion_from_distribution_checks(self): + self.receipt['passed'] = True + with self.assertRaises(ValueError): + module.audit(self.receipt, self.attempts) + + def test_guard_failure_cannot_be_erased(self): + self.receipt['checks']['sandbox_network_and_write_guards'] = True + with self.assertRaises(ValueError): + module.audit(self.receipt, self.attempts) + + def test_gatekeeper_assessment_cannot_be_relabelled(self): + self.receipt['signature_assessment']['gatekeeper_accepted'] = True + with self.assertRaises(ValueError): + module.audit(self.receipt, self.attempts) + + def test_failed_attempt_cannot_be_dropped(self): + self.attempts['attempts'] = [] + with self.assertRaises(ValueError): + module.audit(self.receipt, self.attempts) + + def test_changed_frozen_oracle_rejected(self): + with tempfile.TemporaryDirectory() as folder: + root = Path(folder) + for name in self.receipt['frozen_inputs']: + (root/name).write_bytes((ROOT/name).read_bytes()) + (root/'oracle.json').write_text('{}') + with self.assertRaises(ValueError): + module.audit(self.receipt, self.attempts, root) + + +class FunctionalFactsTests(unittest.TestCase): + def setUp(self): + self.receipt = json.loads((ROOT/'receipt.json').read_text()) + self.native = json.loads((ROOT/'native-facts.json').read_text()) + self.oracle = json.loads((ROOT/'oracle-functional.json').read_text()) + + def check(self): + return module.audit_functional(self.receipt, self.native, self.oracle) + + def test_selected_native_facts_satisfy_oracle(self): + self.assertTrue(self.check()['functional_acceptance']) + + def test_cross_scope_leakage_fails(self): + fact = next(f for f in self.native['facts'] if f['tool'] == 'memory_query' and f.get('value', {}).get('hits') == []) + fact['value']['hits'] = [{'path': 'notes/alpha.md'}] + with self.assertRaises(ValueError): + self.check() + + def test_unrelated_failure_cannot_count_as_negative_read(self): + fact = next(f for f in self.native['facts'] if 'error' in f) + fact['error']['message'] = 'database unavailable' + with self.assertRaises(ValueError): + self.check() + + def test_missing_native_call_fails(self): + self.native['facts'].pop() + with self.assertRaises(ValueError): + self.check() + + def test_wrong_restart_body_fails(self): + fact = next(f for f in self.native['facts'] if f['phase'] == 'candidate-restart' and f['tool'] == 'memory_read_page' and 'value' in f) + fact['value']['body'] = self.oracle['alpha']['body'] + with self.assertRaises(ValueError): + self.check() + + def test_forced_cleanup_not_accepted(self): + self.receipt['cleanup'][0]['forced_termination'] = True + with self.assertRaises(ValueError): + self.check() + + def test_capture_population_fails(self): + self.receipt['candidate_database']['forbidden_population']['observations'] = 1 + with self.assertRaises(ValueError): + self.check() + + +if __name__ == '__main__': + unittest.main() diff --git a/blueprints/convergence-practice/mac-memory-patch/verification.json b/blueprints/convergence-practice/mac-memory-patch/verification.json new file mode 100644 index 000000000..ec7726922 --- /dev/null +++ b/blueprints/convergence-practice/mac-memory-patch/verification.json @@ -0,0 +1,36 @@ +{ + "schema_version": 1, + "commands": [ + { + "command": "python3 blueprints/convergence-practice/mac-memory-patch/audit.py", + "exit_code": 0, + "meaning": "Selected native facts satisfy functional oracle; initial failure preserved; no production/OS confinement claim." + }, + { + "command": "python3 -m unittest discover -s blueprints/convergence-practice/mac-memory-patch -p 'test_*.py' -v", + "exit_code": 0, + "tests": 13, + "skipped": 0 + }, + { + "command": "python3 scripts/validate.py", + "exit_code": 0, + "components": 64, + "hashed_files": 723, + "profiles": 4, + "receipts": 73 + }, + { + "command": "python3 scripts/validate_catalogs.py", + "exit_code": 0 + }, + { + "command": "TMPDIR=\"$OWNED_REAL_TEMP\" python3 -m unittest discover -s tests -v", + "exit_code": 0, + "tests": 493, + "skipped": 49, + "prior_failure_retained_in": "prior-attempts.json" + } + ], + "limit": "Offline consistency and regression checks do not rerun native memory, establish production acceptance or measure enclosing agent usage." +} From 4215eea6b3631a8a352036f57b25581ca2256564 Mon Sep 17 00:00:00 2001 From: seathatflowsinourveins <234074349+seathatflowsinourveins@users.noreply.github.com> Date: Sun, 20 Sep 2026 03:17:33 -0400 Subject: [PATCH 2/6] Qualify frozen run-ledger application on isolated WSL runtime --- .../wsl-application/README.md | 166 +++++++++++ .../wsl-application/freeze.json | 49 ++++ .../wsl-application/playwright.config.ts | 22 ++ .../wsl-application/receipt.json | 269 ++++++++++++++++++ .../wsl-application/sources.json | 55 ++++ .../wsl-application/ubuntu-packages.json | 112 ++++++++ 6 files changed, 673 insertions(+) create mode 100644 blueprints/convergence-practice/wsl-application/README.md create mode 100644 blueprints/convergence-practice/wsl-application/freeze.json create mode 100644 blueprints/convergence-practice/wsl-application/playwright.config.ts create mode 100644 blueprints/convergence-practice/wsl-application/receipt.json create mode 100644 blueprints/convergence-practice/wsl-application/sources.json create mode 100644 blueprints/convergence-practice/wsl-application/ubuntu-packages.json diff --git a/blueprints/convergence-practice/wsl-application/README.md b/blueprints/convergence-practice/wsl-application/README.md new file mode 100644 index 000000000..2a8fb9369 --- /dev/null +++ b/blueprints/convergence-practice/wsl-application/README.md @@ -0,0 +1,166 @@ +# Native WSL run-ledger qualification + +This lane runs the existing [typed application](../application-delivery/README.md) +on Ubuntu 24.04 x86-64 under WSL2, from public source +`cabbe2c96e39096b510f739f07a6e4132da082de`. It retains the original API and browser +assertions, application pins and lockfiles. [freeze.json](freeze.json) records +those exact inputs; [receipt.json](receipt.json) records native results and failed +attempts. Historical Mac results are separate evidence. + +The native WSL run passed all 12 API/database guards, the production build, +schema/type checks, the unchanged browser create/update workflow, separate +empty-database migration reversal, and exact record/history persistence across +PostgreSQL and application restarts. All owned servers and browsers were stopped. + +The existing Node 24.21.0, uv 0.12.17 and Python 3.13.15 are reused. The project's +`>=3.13,<3.15` requirement and universal `uv.lock` support that Python. pnpm +12.4.2 is installed only in the qualification prefix. Linux Chrome for Testing +153.0.8010.52 is an explicit platform adaptation: Google's official metadata does +not list the Mac receipt's installed Chrome 153.0.8010.53 as a Linux CfT artifact. +The Playwright 1.63.0 test and its assertions remain unchanged. + +## Isolated prerequisites + +Choose a new task-owned prefix outside canonical projects; do not reuse an +existing database or installation. Set `QUAL_PREFIX` to that absolute path, +`QUAL_APP` to its `source/blueprints/convergence-practice/application-delivery`, +and `QUAL_RECIPE` to this published recipe directory. Clone the public repository +into `source` and detach at the revision above. Check ports 15432, 18080 and 18081 +before starting anything. Stop if occupied; never stop another task's process. +Copy this lane's `playwright.config.ts` into the sibling `wsl-application` directory +of the pinned clone, leaving `application-delivery` unchanged. + +The host already provided GCC 13.3.0, GNU Make 4.3, Perl, curl, tar, unzip, shasum, +`dpkg-deb`, the Ubuntu archive keyring, glibc 2.39 and SQLite 3.45.1. The missing +native tools/libraries were supplied by the seven exact packages in +[ubuntu-packages.json](ubuntu-packages.json). Its dependency constraints match +those existing libraries. Verify each signed Ubuntu `InRelease` with `gpgv`, each +uncompressed `Packages` hash/size against that release, and each downloaded `.deb` +SHA-256 against its package entry. Extract payloads using only: + +```sh +dpkg-deb -x "$VERIFIED_DEB" "$QUAL_PREFIX/tools/sysroot" +``` + +This executes no maintainer scripts and changes no system package database. +Retain package copyright files. `sources.json` records the upstream pnpm metadata, +Linux native artifact integrity, Chrome artifact identity and PostgreSQL publisher +checksum. The measured pnpm installation verified both npm metadata and archive +integrity, extracted `@pnpm/exe.linux-x64@12.4.2`, and linked its `pnpm` executable +only into `tools/bin`. pnpm 12's package is a native wrapper; the old +`package/bin/pnpm.cjs` path does not exist. No lifecycle script was executed. +Extract the exact verified Chrome archive into `tools/chrome-linux64`. + +Use process-local variables in the qualification shell: + +```sh +export PATH="$QUAL_PREFIX/tools/bin:$QUAL_PREFIX/tools/sysroot/usr/bin:$PATH" +export M4="$QUAL_PREFIX/tools/sysroot/usr/bin/m4" +export BISON_PKGDATADIR="$QUAL_PREFIX/tools/sysroot/usr/share/bison" +export LD_LIBRARY_PATH="$QUAL_PREFIX/tools/sysroot/usr/lib/x86_64-linux-gnu" +export ALSA_CONFIG_PATH="$QUAL_PREFIX/tools/sysroot/usr/share/alsa/alsa.conf" +export UV_PYTHON="$(command -v python3.13)" +export UV_PYTHON_DOWNLOADS=never +export UV_CACHE_DIR="$QUAL_APP/.runtime/uv-cache" +export XDG_CACHE_HOME="$QUAL_PREFIX/cache" +export NEXT_TELEMETRY_DISABLED=1 +export WSL_CHROME_EXECUTABLE="$QUAL_PREFIX/tools/chrome-linux64/chrome" +cd "$QUAL_APP" +make setup +``` + +The Chrome launch keeps Playwright's isolated temporary context and loopback +application lifecycle. GPU acceleration is disabled. No personal browser, +credential store, model, provider or account is used. + +## PostgreSQL clean build + +The original nested `make postgres-install` has a clean-build defect: the +recursive `$(MAKE)` reaches PostgreSQL with `MAKELEVEL=1`. In PostgreSQL 18.6, +`src/Makefile.global.in` lines 393–401 creates generated headers only at +`MAKELEVEL=0`. A fresh build therefore fails on missing `utils/errcodes.h`. +The original file and its historical hashes are preserved. Run the supported +upstream build directly from the shell after source configuration: + +```sh +test ! -e .runtime/postgresql/18.6 +mkdir -p .runtime/postgresql-source .runtime/postgresql-build +curl --fail --location --proto '=https' --tlsv1.2 \ + https://ftp.postgresql.org/pub/source/v18.6/postgresql-18.6.tar.bz2 \ + --output .runtime/postgresql-source/postgresql-18.6.tar.bz2 +printf '%s %s\n' \ + 555610c24d53e4316da5b7d3fc25c279d96856d5e0e23ee308c328c5fa881d9f \ + .runtime/postgresql-source/postgresql-18.6.tar.bz2 | shasum -a 256 -c - +tar -xjf .runtime/postgresql-source/postgresql-18.6.tar.bz2 \ + -C .runtime/postgresql-source +(cd .runtime/postgresql-build && \ + ../postgresql-source/postgresql-18.6/configure \ + --prefix="$QUAL_APP/.runtime/postgresql/18.6" \ + --without-icu --without-readline --without-zlib) +# These are shell-level commands, not recursive Makefile recipes. +taskset -c 0-3 make -C .runtime/postgresql-build -j 4 +taskset -c 0-3 make -C .runtime/postgresql-build install +cp .runtime/postgresql-source/postgresql-18.6/COPYRIGHT \ + .runtime/postgresql/18.6/COPYRIGHT +make postgres-init postgres-start postgres-databases +make migrate migrate-test +make migrate migrate-test +``` + +Use up to four allowed CPU IDs if the host's affinity differs. Installation and +initialization must refuse existing destinations. The local source configuration +has no ICU, readline, zlib or TLS, uses UTF-8/C locale and local synthetic trust +authentication, and listens only on loopback with no Unix socket. It qualifies +this fixture, not a production database service. + +## Native verification and restart + +Run the original verify actions, selecting only the task-owned Linux browser: + +```sh +pnpm peers check +uv run --frozen python verify_schema.py +pnpm typecheck +taskset -c 0-3 pnpm build +make test +taskset -c 0-3 pnpm exec playwright test \ + --config ../wsl-application/playwright.config.ts +``` + +The browser config imports the original config, retaining its test directory, +headless Chromium mode, zero retries, one worker, timeout, isolated server start, +`reuseExistingServer: false` and graceful process cleanup. It changes the Linux +executable path and disables GPU acceleration. All original assertions still run. +The JSON browser report is written under this alternate config directory's +`.runtime/browser-results.json`. + +For schema reversal, create a separate empty synthetic database using the owned +`createdb`, set `DATABASE_URL` only for each Alembic invocation, and exercise +`upgrade head` → `downgrade base` → `upgrade head`. Inspect table names after each +step, then drop only this explicitly created reversal database. This proves +schema reversal, not recovery of deleted data. + +For persistence, retain the browser-created row's full API JSON and database row +plus both history events. Stop the owned API/Next and PostgreSQL, start the same +database and application, and compare the exact retained values, including ID, +timestamps, revision, status and events. Reopen the retained row in a fresh +headless browser and assert its passed status and two recorded changes. Keep raw +row identifiers and machine paths in private evidence. + +The frozen supervisor's exclusive bind preflight can reject a recently stopped +API port while TCP is in `TIME-WAIT`, despite no remaining listener. This occurred +on WSL. Wait for normal TCP expiry and retry the same supervisor; do not terminate +unowned processes or change the acceptance assertions to bypass it. + +## Cleanup and limits + +Stop the owned application supervisor, let it reap API/Next process groups, and +run `make postgres-stop`. Verify the three ports are free and no owned browser or +application processes remain. Retain selected synthetic data and full logs, +including failures, outside public receipts. To roll back, first stop those owned +processes, preserve needed evidence, then remove only the newly created task +prefix after review. Reverting this recipe alone does not delete database state. + +This acceptance has no authentication, external ingestion, deployment, production +load, backup/independent-host restore, model execution or trading claim. Whole-task +model usage is unknown; no token-saving claim is made. diff --git a/blueprints/convergence-practice/wsl-application/freeze.json b/blueprints/convergence-practice/wsl-application/freeze.json new file mode 100644 index 000000000..59927c83c --- /dev/null +++ b/blueprints/convergence-practice/wsl-application/freeze.json @@ -0,0 +1,49 @@ +{ + "schema_version": 1, + "source_revision": "cabbe2c96e39096b510f739f07a6e4132da082de", + "source_repository": "https://github.com/seathatflowsinourveins/native-agent-stack", + "application": "blueprints/convergence-practice/application-delivery", + "oracle_unchanged": true, + "files": [ + { + "path": "acceptance-plan.json", + "sha256": "a8ac3edea74e51294f8359a201d94cc963348dbc24ddd2faecf2e04a3ec9e29e" + }, + { + "path": "backend/test_api.py", + "sha256": "404cef6a7ba380a331ee15dc7a9414756d84f12456f67c34982d5d8968ea813e" + }, + { + "path": "browser/ledger.spec.ts", + "sha256": "1cd010bae5b7612023652a064e7a85a53b52dbe39ef46e97b8587439a0b064a6" + }, + { + "path": "freeze.json", + "sha256": "333198ba238dd35bea47882dea9e15fcadf1ab5b8609ed2bfa93aa21a1911720" + }, + { + "path": "Makefile", + "sha256": "dbab0b62a259b26a86a8e174b2ab17ba7ce28ac5d19f8412fb41c016f75bc011" + }, + { + "path": "project-contract.json", + "sha256": "977bef87b2ff759c19b238e937553b307efa837d163ea19e8a72799f98af567a" + }, + { + "path": "uv.lock", + "sha256": "552d8834e745d7c91daa15e47c5f6d0cd9063db18c98790d2f1af05038f7417d" + }, + { + "path": "pnpm-lock.yaml", + "sha256": "73ba78a623c6448e5e67a3f488f2e50f20b3b4b4c2da12cd29077f25f6a57c2b" + }, + { + "path": "openapi.json", + "sha256": "83346419cc47a151fad15bac80ddf67f013986f4c674b6ff9c2f82af71656a6c" + }, + { + "path": "app/api.generated.ts", + "sha256": "dabe8af2f2ce36b03e51921df4fa574092b4e9aadf6306c046bc53d2c4db03da" + } + ] +} diff --git a/blueprints/convergence-practice/wsl-application/playwright.config.ts b/blueprints/convergence-practice/wsl-application/playwright.config.ts new file mode 100644 index 000000000..9a80a7d54 --- /dev/null +++ b/blueprints/convergence-practice/wsl-application/playwright.config.ts @@ -0,0 +1,22 @@ +import path from 'node:path'; +import base from '../application-delivery/playwright.config'; + +// Keep the frozen browser oracle and server lifecycle. Only select the isolated +// Linux browser executable; never attach to an existing personal browser. +const executablePath = process.env.WSL_CHROME_EXECUTABLE; +if (!executablePath || !path.isAbsolute(executablePath)) { + throw new Error('WSL_CHROME_EXECUTABLE must name the absolute task-owned Chrome executable'); +} + +export default { + ...base, + testDir: path.resolve(__dirname, '../application-delivery/browser'), + webServer: { + ...base.webServer, + cwd: path.resolve(__dirname, '../application-delivery'), + }, + use: { + ...base.use, + launchOptions: { executablePath, args: ['--disable-gpu'] }, + }, +}; diff --git a/blueprints/convergence-practice/wsl-application/receipt.json b/blueprints/convergence-practice/wsl-application/receipt.json new file mode 100644 index 000000000..93fd03a4c --- /dev/null +++ b/blueprints/convergence-practice/wsl-application/receipt.json @@ -0,0 +1,269 @@ +{ + "schema_version": 1, + "kind": "native_cli_e2e", + "status": "passed_with_explicit_platform_adaptations", + "completed_at_utc": "2026-09-20T07:14:00.254217+00:00", + "host_role": "velanext", + "platform": { + "os": "Ubuntu 24.04.5 LTS", + "architecture": "x86_64", + "kernel": "6.18.33.2-microsoft-standard-WSL2", + "qualification_scope": "New isolated prefix on existing WSL host; no canonical project or system package changes." + }, + "source_revision": "cabbe2c96e39096b510f739f07a6e4132da082de", + "source_repository": "https://github.com/seathatflowsinourveins/native-agent-stack", + "frozen_inputs": "freeze.json", + "frozen_inputs_unchanged": true, + "runtimes": { + "node": "24.21.0", + "pnpm": "12.4.2", + "python": "3.13.15", + "uv": "0.12.17", + "postgresql": "18.6", + "next": "16.3.5", + "react": "19.3.0", + "fastapi": "0.141.1", + "playwright": "1.63.0", + "chrome_for_testing": "153.0.8010.52" + }, + "acceptance": [ + { + "check": "Locked dependency restore", + "command": "make setup", + "exit": 0, + "python": "Frozen uv.lock, no builds, no Python downloads", + "javascript": "Frozen pnpm-lock.yaml, ignore-scripts, isolated store" + }, + { + "check": "Native PostgreSQL source build/install", + "commands": [ + "taskset -c 0-3 make -C .runtime/postgresql-build -j 4", + "taskset -c 0-3 make -C .runtime/postgresql-build install" + ], + "exit": 0, + "archive_publisher_sha256_matched": true, + "actual_server_version": "18.6", + "source_changed": false + }, + { + "check": "Empty application/test database migrations and idempotent repeat", + "commands": [ + "make postgres-init postgres-start postgres-databases", + "make migrate migrate-test", + "make migrate migrate-test" + ], + "exit": 0 + }, + { + "check": "Separate empty-database upgrade/downgrade/re-upgrade", + "commands": [ + "createdb ", + "DATABASE_URL= uv run --frozen alembic upgrade head", + "DATABASE_URL= uv run --frozen alembic downgrade base", + "DATABASE_URL= uv run --frozen alembic upgrade head", + "dropdb " + ], + "all_command_exits": 0, + "empty_tables": [], + "upgraded_tables": [ + "alembic_version", + "run_events", + "runs" + ], + "downgraded_tables": [ + "alembic_version" + ], + "reupgraded_tables": [ + "alembic_version", + "run_events", + "runs" + ], + "original_application_databases_unchanged": true, + "temporary_database_removed": true + }, + { + "check": "Dependency peer compatibility", + "command": "pnpm peers check", + "exit": 0 + }, + { + "check": "OpenAPI and generated TypeScript drift", + "command": "uv run --frozen python verify_schema.py", + "exit": 0 + }, + { + "check": "Type checking", + "command": "pnpm typecheck", + "exit": 0 + }, + { + "check": "Production Next build", + "command": "NEXT_TELEMETRY_DISABLED=1 taskset -c 0-3 pnpm build", + "exit": 0 + }, + { + "check": "Frozen API/database guards", + "command": "make test", + "exit": 0, + "passed": 12, + "failed": 0, + "skipped": 0, + "warnings": 1, + "warning": "Existing Starlette TestClient AnyIO BlockingPortal alias deprecation." + }, + { + "check": "Frozen real browser create/update/reload", + "command": "taskset -c 0-3 pnpm exec playwright test --config ../wsl-application/playwright.config.ts", + "exit": 0, + "passed": 1, + "failed": 0, + "skipped": 0, + "retries": 0, + "workers": 1, + "headless": true, + "browser_assertions_changed": false, + "page_errors": 0 + }, + { + "check": "Native application/database restart and exact persistence", + "exit": 0, + "api_exact_equal": true, + "database_rows_and_history_exact_equal": true, + "record_count": 1, + "event_count": 2, + "postgres_restart": true, + "api_next_restart": true, + "fresh_browser_reopened_row": true, + "database_before_sha256": "2102521d349981af655720ef1e27d262e93ca2208e8ba557ed38819e8a94eb97", + "database_after_sha256": "2102521d349981af655720ef1e27d262e93ca2208e8ba557ed38819e8a94eb97", + "response_payload": { + "before_sha256": "c5cd616bf94018dd86f5f2a2b8b5b26a6d60472057d58ac52cbb2ca5aa5d8fcd", + "after_sha256": "c5cd616bf94018dd86f5f2a2b8b5b26a6d60472057d58ac52cbb2ca5aa5d8fcd" + } + }, + { + "check": "Fresh browser reopens retained record after restart", + "exit": 0, + "passed": 1, + "status": "passed", + "revision": 2, + "history_count": 2, + "page_errors": 0 + }, + { + "check": "External Make boundary correction fixture", + "command": "env MAKELEVEL=0 $(MAKE) -f Child", + "exit": 0, + "external_project_makelevel": 0, + "internal_recursive_makelevel": 1 + } + ], + "retained_failures": [ + { + "stage": "Initial setup", + "exit": 2, + "cause": "Task-local pnpm symlink assumed obsolete package/bin/pnpm.cjs; make exited127 for pnpm. Frozen Python restore had succeeded.", + "resolution": "Verified pnpm12.4.2 wrapper/native metadata, extracted exact @pnpm/exe.linux-x64 artifact, then reran setup successfully." + }, + { + "stage": "Initial native PostgreSQL configuration", + "exit": 2, + "cause": "configure: error: bison not found", + "resolution": "Exact authenticated Ubuntu M4/Bison/Flex payloads extracted only into task sysroot." + }, + { + "stage": "Recursive PostgreSQL make", + "exit": 2, + "cause": "Missing utils/errcodes.h because original wrapper invoked external project at MAKELEVEL1; upstream header generation requires0.", + "resolution": "Unmodified upstream standalone make build/install succeeded; original application Makefile retained byte-for-byte." + }, + { + "stage": "Mac browser version metadata lookup", + "exit": 1, + "http_status": 404, + "cause": "No official Chrome for Testing153.0.8010.53 metadata.", + "resolution": "Explicit verified Linux153.0.8010.52 adaptation; no claim of identical Mac/Linux browser artifact." + }, + { + "stage": "Immediate application restart", + "exit": 1, + "cause": "Original serve.py bind preflight rejected local18081 TIME-WAIT despite no listener or owned process.", + "resolution": "Waited for normal native TCP expiry, resumed using exact retained before snapshots, verified full equality and fresh browser read." + }, + { + "stage": "Initial cleanup bind probe", + "exit": 1, + "cause": "Same TIME-WAIT bind restriction.", + "resolution": "Final cleanup separately verified no listeners via socket connection probes/ss and no owned browser/application/database processes." + }, + { + "stage": "Browser evidence copy", + "exit": 1, + "cause": "Reporter output followed alternate config directory instead of original app directory.", + "resolution": "Located and retained exact sibling wsl-application/.runtime/browser-results.json; test result unaffected." + } + ], + "command_exit_records": { + "01-setup": 2, + "02-setup": 0, + "03-postgres-install": 2, + "04-peers": 0, + "05-schema": 0, + "06-typecheck": 0, + "07-build": 0, + "08-postgres-install": 2, + "09-postgres-build": 0, + "10-postgres-install": 0, + "11-postgres-init": 0, + "12-postgres-start": 0, + "13-postgres-databases": 0, + "14-migrations": 0, + "15-migrations-repeat": 0, + "16-api-tests": 0, + "17-browser": 0, + "18-migration-createdb": 0, + "18-migration-downgrade": 0, + "18-migration-dropdb": 0, + "18-migration-reupgrade": 0, + "18-migration-upgrade": 0, + "19-postgres-start": 0, + "19-postgres-stop": 0, + "20-postgres-stop-final": 0, + "22-makelevel-boundary": 0, + "23-browser-after-restart": 0, + "23-postgres-resume": 0, + "23-supervisor-stop": 0, + "24-postgres-stop-final": 0 + }, + "cleanup": { + "ports_not_listening": [ + 15432, + 18080, + 18081 + ], + "owned_servers_or_browsers_remaining": 0, + "temporary_reversal_database_removed": true, + "retained": "Synthetic ledger databases, task-only runtimes/artifacts, complete build/test/server logs and exact before/after rows in private qualification prefix.", + "system_packages_installed": false, + "package_maintainer_scripts_executed": false, + "global_path_or_loader_changed": false, + "shared_services_changed": false, + "native_client_accounts_or_models_used": false + }, + "private_evidence": { + "files_indexed": 107, + "indexed_bytes": 7534904, + "index_sha256": "0e980c0b9d96959127201c105b645ccd5773c5fed8e2955c23925773f3ab784a", + "location": "Task-owned qualification prefix; native paths and raw identifiers intentionally omitted.", + "full_failed_attempts_retained": true + }, + "rollback": "Stop only owned API/Next/browser/PostgreSQL processes; preserve needed synthetic data/evidence; remove only the newly created qualification prefix after review. No canonical project or system package rollback is required.", + "limits": [ + "Native single-host WSL application acceptance, not source-only replay.", + "No production database hardening, authentication, external ingestion, hosted deployment, load test, backup or independent-host restore.", + "The original wrapper needs its separately recorded clean-build correction; this receipt uses supported standalone upstream make.", + "Immediate restart can wait for TCP TIME-WAIT because the frozen supervisor uses exclusive bind preflight.", + "No provider/model, GPU workload, broker or trading execution.", + "Whole-task model usage unknown; no token-saving claim." + ] +} diff --git a/blueprints/convergence-practice/wsl-application/sources.json b/blueprints/convergence-practice/wsl-application/sources.json new file mode 100644 index 000000000..7e5a689bb --- /dev/null +++ b/blueprints/convergence-practice/wsl-application/sources.json @@ -0,0 +1,55 @@ +{ + "schema_version": 1, + "checked_at_utc": "2026-09-20", + "application_sources": "../application-delivery/sources.json", + "application_source_revision": "cabbe2c96e39096b510f739f07a6e4132da082de", + "postgresql": { + "version": "18.6", + "archive_url": "https://ftp.postgresql.org/pub/source/v18.6/postgresql-18.6.tar.bz2", + "checksum_url": "https://ftp.postgresql.org/pub/source/v18.6/postgresql-18.6.tar.bz2.sha256", + "sha256": "555610c24d53e4316da5b7d3fc25c279d96856d5e0e23ee308c328c5fa881d9f", + "license": "PostgreSQL License", + "requirements_url": "https://www.postgresql.org/docs/18/install-requirements.html", + "build_url": "https://www.postgresql.org/docs/18/install-make.html", + "configure_flags": [ + "--prefix=/.runtime/postgresql/18.6", + "--without-icu", + "--without-readline", + "--without-zlib" + ], + "build_prerequisites": "Flex, Bison, Perl, C compiler and GNU Make; isolated exact Ubuntu packages supply missing Flex/Bison/M4.", + "binary_sha256": "246347864bd2e689b95bd3576f2408b9ff3657c98dcb4c08d918be089b1d5043", + "copyright_sha256": "3d6af92ff8a4c2cdf69afb1cf44edea727922f5cd0cf8b5f72b11cdecac8fdfd", + "makefile_global_in_sha256": "312247524128b0f0697b7b655f3b86a866f67c0602cb7f5ae78d91615a7eeb65", + "compiler": "gcc (Ubuntu 13.3.0-6ubuntu2~24.04.1) 13.3.0", + "make": "GNU Make 4.3" + }, + "pnpm": { + "version": "12.4.2", + "license": "MIT", + "wrapper_metadata_url": "https://registry.npmjs.org/pnpm/12.4.2", + "wrapper_metadata_sha256": "3385f22c75eaf4edff515ef577b19f4f2acabbaa7139ec43cc178e1843f24221", + "native_metadata_url": "https://registry.npmjs.org/@pnpm%2fexe.linux-x64/12.4.2", + "native_metadata_sha256": "72739420a4aa160b82df2eb7fac9a0b56b2ab46705e6df2488dfd61128af0ade", + "native_archive_sha256": "545b89d5c6026ac33d4c28bd3c6cc38cc050d571b35a4e69f13aad4a441af142", + "native_integrity": "sha512-/pbt0UVTa8NMDhzOWLQRfZ6G9ROKXlJPZtx845BqyWfc7hCrWXhTLBd70yO2y8+E+IWN3oHM1s/JsIQNGk1yvg==", + "installation": "Verified wrapper source selects @pnpm/exe.linux-x64 on glibc; extracted exact native artifact and linked only task tools/bin/pnpm. No lifecycle scripts executed." + }, + "chrome": { + "version": "153.0.8010.52", + "revision": "1681091", + "url": "https://storage.googleapis.com/chrome-for-testing-public/153.0.8010.52/linux64/chrome-linux64.zip", + "archive_sha256": "e66f66d4802a46d4a022667e668aa950e277cadbfbed4b3777915b47413a0ef9", + "metadata_url": "https://googlechromelabs.github.io/chrome-for-testing/known-good-versions-with-downloads.json", + "metadata_sha256": "bbab04c7ff546c2e78cf53847416086d3505161351a69c0dd48d2e0694aa0d44", + "license": "Google Chrome Terms of Service; Chromium and other third-party licenses in chrome://credits. ABOUT retained with archive.", + "license_url": "https://www.google.com/chrome/terms/", + "publisher_sha256_available": false, + "hash_scope": "Observed downloaded archive identity; version and URL verified against official Google Chrome for Testing metadata.", + "platform_adaptation": "Linux153.0.8010.52; Mac installed Chrome153.0.8010.53 is retained in the original receipt and is not claimed to be the same artifact.", + "binary_sha256": "328fbee82d8e58b05a755b2343abfd192d92ca7066353cb357fad389bc7e3989", + "about_sha256": "34d078ce3003087a8374e7c6156fda374769b8047d6ddaf419d66414aa48edfb" + }, + "ubuntu_packages": "ubuntu-packages.json", + "python_compatibility": "Existing Python3.13.15 satisfies the unmodified project >=3.13,<3.15 constraint and its frozen universal uv.lock." +} diff --git a/blueprints/convergence-practice/wsl-application/ubuntu-packages.json b/blueprints/convergence-practice/wsl-application/ubuntu-packages.json new file mode 100644 index 000000000..9272e52fc --- /dev/null +++ b/blueprints/convergence-practice/wsl-application/ubuntu-packages.json @@ -0,0 +1,112 @@ +{ + "authentication": [ + { + "suite": "noble", + "signature_exit": 0, + "inrelease_sha256": "cdb2f31d809f589719a53c6ad15f255b27569c4059542ada282aaa21b8e164b0", + "packages_sha256": "8f6f71ae839c8cba390a7643fcbbdacddb0bc7d12c1583a2dd80a1f8443a30e5", + "packages_size": 7165069 + }, + { + "suite": "noble-updates", + "signature_exit": 0, + "inrelease_sha256": "aeaf85abd41363b42bf9951020685e0f28971d0626afd28f210919a2b8f89810", + "packages_sha256": "06e10331f528fffa71c2bd4a47548cdefeb1c8b040c160c6dd8645e183fd7e76", + "packages_size": 6874409 + } + ], + "packages": [ + { + "name": "flex", + "version": "2.6.4-8.2build1", + "architecture": "amd64", + "suite": "noble", + "url": "https://archive.ubuntu.com/ubuntu/pool/main/f/flex/flex_2.6.4-8.2build1_amd64.deb", + "sha256": "c5604f55827b50e3f568b4731b7799f86b147454c867be02bc141d9d8ce561ff", + "depends": "libc6 (>= 2.38), m4", + "copyright_path": "usr/share/doc/flex/copyright", + "copyright_sha256": "908e7be25f1d5848fc378b76bdbaed59f3d1e19ae61fdeb9d1ad12640bf0e078", + "license_summary": "FLEX (BSD-style); bundled files also GPL/LGPL/FSFAP; see retained copyright" + }, + { + "name": "libnspr4", + "version": "2:4.35-1.1build1", + "architecture": "amd64", + "suite": "noble", + "url": "https://archive.ubuntu.com/ubuntu/pool/main/n/nspr/libnspr4_4.35-1.1build1_amd64.deb", + "sha256": "e579e72d091f6c7a13f5a756c31065b15aae5b81840d61b069355aa2283c07b4", + "depends": "libc6 (>= 2.38)", + "copyright_path": "usr/share/doc/libnspr4/copyright", + "copyright_sha256": "3c4fcc131809b2b6993513bfe4cf6f1ede391ec84f1d5ceca78fb75537b22452", + "license_summary": "MPL-2.0" + }, + { + "name": "m4", + "version": "1.4.19-4build1", + "architecture": "amd64", + "suite": "noble", + "url": "https://archive.ubuntu.com/ubuntu/pool/main/m/m4/m4_1.4.19-4build1_amd64.deb", + "sha256": "30ea715845a1863abd55d11e47ab91513130bf347852d4cdeae69e9d98fa795c", + "depends": "libc6 (>= 2.38)", + "copyright_path": "usr/share/doc/m4/copyright", + "copyright_sha256": "9438e0cbd4cf2121d2a9b61f42b1aaf765788dc3454983c55f2107cfe504f11c", + "license_summary": "GPL-3.0-or-later; manual GFDL-1.3-or-later" + }, + { + "name": "bison", + "version": "2:3.8.2+dfsg-1ubuntu0.24.04.1", + "architecture": "amd64", + "suite": "noble-updates", + "url": "https://archive.ubuntu.com/ubuntu/pool/main/b/bison/bison_3.8.2+dfsg-1ubuntu0.24.04.1_amd64.deb", + "sha256": "9d75084d1293f68f3c1a2ee677dea5baa4e010bac2d4c455d8e23177e97aa353", + "depends": "m4, libc6 (>= 2.38)", + "copyright_path": "usr/share/doc/bison/copyright", + "copyright_sha256": "0870e455b94b9043e84948624d3368d9a45d10674ae4398762b99bb2c328dffd", + "license_summary": "GPL-3.0-or-later; Debian packaging GPL-2.0-or-later" + }, + { + "name": "libasound2-data", + "version": "1.2.11-1ubuntu0.3", + "architecture": "all", + "suite": "noble-updates", + "url": "https://archive.ubuntu.com/ubuntu/pool/main/a/alsa-lib/libasound2-data_1.2.11-1ubuntu0.3_all.deb", + "sha256": "0c26896193480d9dbb055e85e8ddfb9c9f34cf19afee340987cd6311e2886fc1", + "depends": null, + "copyright_path": "usr/share/doc/libasound2-data/copyright", + "copyright_sha256": "9b356b4fae53b5d5e7668e048f085d68a5039de7b6afbf465f50e81513334062", + "license_summary": "LGPL-2.1-or-later (copyright file spells LPGL)" + }, + { + "name": "libasound2t64", + "version": "1.2.11-1ubuntu0.3", + "architecture": "amd64", + "suite": "noble-updates", + "url": "https://archive.ubuntu.com/ubuntu/pool/main/a/alsa-lib/libasound2t64_1.2.11-1ubuntu0.3_amd64.deb", + "sha256": "5d17bfb5683eb99f1be951fe48e1be5bf3c52391913b6b74a8aecf9b4f5e779f", + "depends": "libasound2-data (>= 1.2.11-1ubuntu0.3), libc6 (>= 2.38)", + "copyright_path": "usr/share/doc/libasound2t64/copyright", + "copyright_sha256": "9b356b4fae53b5d5e7668e048f085d68a5039de7b6afbf465f50e81513334062", + "license_summary": "LGPL-2.1-or-later (copyright file spells LPGL)" + }, + { + "name": "libnss3", + "version": "2:3.98-1ubuntu0.2", + "architecture": "amd64", + "suite": "noble-updates", + "url": "https://archive.ubuntu.com/ubuntu/pool/main/n/nss/libnss3_3.98-1ubuntu0.2_amd64.deb", + "sha256": "4254f11d782dfb970e78113519a59d440112ed43c4b56f709da0aef81da8651a", + "depends": "libc6 (>= 2.34), libnspr4 (>= 2:4.34), libsqlite3-0 (>= 3.5.9)", + "copyright_path": "usr/share/doc/libnss3/copyright", + "copyright_sha256": "3f450f9453233852b3a469a36a897cc68fb87be3e8b3a5ba64f63a7904528408", + "license_summary": "MPL-2.0 with Zlib, BSD-3 and public-domain files" + } + ], + "scope": "Exact official Ubuntu 24.04 package payloads extracted into a task-owned sysroot; no package installation, maintainer scripts, services or system database mutation.", + "authentication_method": "Existing native Ubuntu archive keyring verified each signed InRelease with gpgv; uncompressed Packages SHA256/size matched signed Release, then each HTTPS .deb matched its Packages SHA256.", + "existing_runtime_dependencies": { + "libc6": "2.39-0ubuntu8.9", + "libsqlite3-0": "3.45.1-1ubuntu2.7", + "libgcc-s1": "14.2.0-4ubuntu2~24.04.1", + "libstdc++6": "14.2.0-4ubuntu2~24.04.1" + } +} From 2e223aee5ba50771e04f166749b42b1632d8fa12 Mon Sep 17 00:00:00 2001 From: seathatflowsinourveins <234074349+seathatflowsinourveins@users.noreply.github.com> Date: Sun, 20 Sep 2026 03:19:16 -0400 Subject: [PATCH 3/6] Fix PostgreSQL make boundary and loopback restart probe --- .../application-delivery/Makefile | 4 +- .../application-delivery/README.md | 25 ++++ .../history/Makefile.cabbe2c | 59 +++++++++ .../history/recipe-revisions.json | 67 ++++++++++ .../history/serve.cabbe2c.py | 54 ++++++++ .../application-delivery/serve.py | 12 +- .../application-delivery/test_portability.py | 119 ++++++++++++++++++ 7 files changed, 335 insertions(+), 5 deletions(-) create mode 100644 blueprints/convergence-practice/application-delivery/history/Makefile.cabbe2c create mode 100644 blueprints/convergence-practice/application-delivery/history/recipe-revisions.json create mode 100644 blueprints/convergence-practice/application-delivery/history/serve.cabbe2c.py create mode 100644 blueprints/convergence-practice/application-delivery/test_portability.py diff --git a/blueprints/convergence-practice/application-delivery/Makefile b/blueprints/convergence-practice/application-delivery/Makefile index 318df54a6..80e81ae9c 100644 --- a/blueprints/convergence-practice/application-delivery/Makefile +++ b/blueprints/convergence-practice/application-delivery/Makefile @@ -39,8 +39,8 @@ postgres-install: printf '%s %s\n' 555610c24d53e4316da5b7d3fc25c279d96856d5e0e23ee308c328c5fa881d9f .runtime/postgresql-source/postgresql-18.6.tar.bz2 | shasum -a 256 -c - tar -xjf .runtime/postgresql-source/postgresql-18.6.tar.bz2 -C .runtime/postgresql-source cd .runtime/postgresql-build && ../postgresql-source/postgresql-18.6/configure --prefix="$$(pwd)/../postgresql/18.6" --without-icu --without-readline --without-zlib - $(MAKE) -C .runtime/postgresql-build -j 4 - $(MAKE) -C .runtime/postgresql-build install + env MAKELEVEL=0 $(MAKE) -C .runtime/postgresql-build -j 4 + env MAKELEVEL=0 $(MAKE) -C .runtime/postgresql-build install cp .runtime/postgresql-source/postgresql-18.6/COPYRIGHT .runtime/postgresql/18.6/COPYRIGHT postgres-init: diff --git a/blueprints/convergence-practice/application-delivery/README.md b/blueprints/convergence-practice/application-delivery/README.md index b5abffe57..66e06a17a 100644 --- a/blueprints/convergence-practice/application-delivery/README.md +++ b/blueprints/convergence-practice/application-delivery/README.md @@ -81,6 +81,31 @@ The nested [project contract](project-contract.json) supplies actual setup, run, test and verify commands for native Codex/Claude integration. The enclosing repository's global actions were not modified by this bounded contribution. +## Recipe portability follow-up + +The current PostgreSQL build/install entrypoints explicitly reset `MAKELEVEL=0` +at the external source-tree boundary. PostgreSQL's own recursive make calls still +advance normally. This prevents the enclosing application Makefile from causing +PostgreSQL to skip its top-level generated-header prerequisites. The application +port probe now uses `SO_REUSEADDR`, allowing normal restart after TIME_WAIT while +still refusing a live listener. It does not enable `SO_REUSEPORT` or stop any +unknown process. + +Five focused tests exercise both actual make command boundaries, reproduce the +old recursion failure, create real loopback TIME_WAIT and live-listener sockets, +and check historical byte identity. They pass on the Mac without rebuilding the +application or PostgreSQL: + +```sh +python3 -m unittest discover -s blueprints/convergence-practice/application-delivery -p 'test_portability.py' -v +``` + +Run that command from the repository root. The [recipe revision mapping](history/recipe-revisions.json) +preserves the original Makefile and launcher bytes under their recorded hashes. +The original receipt and experiment are unchanged and still describe that earlier +recipe. These portability checks qualify only the two changes; later WSL full-stack +acceptance is recorded separately. + ## Qualification and limits [acceptance-plan.json](acceptance-plan.json) fixed the acceptance criteria; diff --git a/blueprints/convergence-practice/application-delivery/history/Makefile.cabbe2c b/blueprints/convergence-practice/application-delivery/history/Makefile.cabbe2c new file mode 100644 index 000000000..318df54a6 --- /dev/null +++ b/blueprints/convergence-practice/application-delivery/history/Makefile.cabbe2c @@ -0,0 +1,59 @@ +.PHONY: setup schema migrate migrate-test run test verify browser postgres-install postgres-init postgres-start postgres-stop postgres-databases + +setup: + UV_CACHE_DIR=.runtime/uv-cache uv sync --frozen --no-build + pnpm install --frozen-lockfile --ignore-scripts --store-dir .runtime/pnpm-store + +schema: + uv run --frozen python -m backend.export_openapi + pnpm types + +migrate: + uv run --frozen alembic upgrade head + +migrate-test: + DATABASE_URL=postgresql://postgres@127.0.0.1:15432/ledger_test uv run --frozen alembic upgrade head + +run: + python3 serve.py + +test: + DATABASE_URL=postgresql://postgres@127.0.0.1:15432/ledger_test uv run --frozen pytest -q + +browser: + pnpm test:e2e + +verify: + pnpm peers check + uv run --frozen python verify_schema.py + pnpm typecheck + NEXT_TELEMETRY_DISABLED=1 pnpm build + DATABASE_URL=postgresql://postgres@127.0.0.1:15432/ledger_test uv run --frozen pytest -q + pnpm test:e2e + +# One-time native source build. Refuse to overwrite an existing installation. +postgres-install: + test ! -e .runtime/postgresql/18.6 + mkdir -p .runtime/postgresql-source .runtime/postgresql-build + curl --fail --location --proto '=https' --tlsv1.2 https://ftp.postgresql.org/pub/source/v18.6/postgresql-18.6.tar.bz2 --output .runtime/postgresql-source/postgresql-18.6.tar.bz2 + printf '%s %s\n' 555610c24d53e4316da5b7d3fc25c279d96856d5e0e23ee308c328c5fa881d9f .runtime/postgresql-source/postgresql-18.6.tar.bz2 | shasum -a 256 -c - + tar -xjf .runtime/postgresql-source/postgresql-18.6.tar.bz2 -C .runtime/postgresql-source + cd .runtime/postgresql-build && ../postgresql-source/postgresql-18.6/configure --prefix="$$(pwd)/../postgresql/18.6" --without-icu --without-readline --without-zlib + $(MAKE) -C .runtime/postgresql-build -j 4 + $(MAKE) -C .runtime/postgresql-build install + cp .runtime/postgresql-source/postgresql-18.6/COPYRIGHT .runtime/postgresql/18.6/COPYRIGHT + +postgres-init: + test ! -e .runtime/native-pgdata + .runtime/postgresql/18.6/bin/initdb --pgdata=.runtime/native-pgdata --username=postgres --auth=trust --no-locale --encoding=UTF8 + printf "\nlisten_addresses = '127.0.0.1'\nport = 15432\nunix_socket_directories = ''\n" >> .runtime/native-pgdata/postgresql.conf + +postgres-start: + .runtime/postgresql/18.6/bin/pg_ctl -D .runtime/native-pgdata -l .runtime/postgres.log -w start + +postgres-stop: + .runtime/postgresql/18.6/bin/pg_ctl -D .runtime/native-pgdata -m fast -w stop + +postgres-databases: + .runtime/postgresql/18.6/bin/createdb --host=127.0.0.1 --port=15432 --username=postgres ledger + .runtime/postgresql/18.6/bin/createdb --host=127.0.0.1 --port=15432 --username=postgres ledger_test diff --git a/blueprints/convergence-practice/application-delivery/history/recipe-revisions.json b/blueprints/convergence-practice/application-delivery/history/recipe-revisions.json new file mode 100644 index 000000000..5bed0de7f --- /dev/null +++ b/blueprints/convergence-practice/application-delivery/history/recipe-revisions.json @@ -0,0 +1,67 @@ +{ + "schema_version": 1, + "scope": "Separate native make and loopback socket portability regressions; no full application/PostgreSQL build or model rerun.", + "historical_acceptance": "Original receipt and experiment retain their original hashes. Resolve original Makefile/serve.py bytes through this explicit hash-to-retained-file mapping; original full-stack acceptance does not qualify the changed recipe.", + "recipes": [ + { + "current_path": "Makefile", + "original": { + "revision": "cabbe2c96e39096b510f739f07a6e4132da082de", + "sha256": "dbab0b62a259b26a86a8e174b2ab17ba7ce28ac5d19f8412fb41c016f75bc011", + "retained_path": "history/Makefile.cabbe2c" + }, + "current_sha256": "799c61469b98dddbc20870b6166737312968a97ddf16aa6ed3e7d50104278e80", + "change": "Reset MAKELEVEL only at both external PostgreSQL build/install entrypoints; internal recursive make still advances normally." + }, + { + "current_path": "serve.py", + "original": { + "revision": "cabbe2c96e39096b510f739f07a6e4132da082de", + "sha256": "e3e59b5315d5f2b3c2fe863cdecabfd9f7ffd1977a83d332331a10e33a42a14e", + "retained_path": "history/serve.cabbe2c.py" + }, + "current_sha256": "bba1f9655cce0b412257fbd0c40680b6b0ccc0ecffb91a2f3605323491655aed", + "change": "Set SO_REUSEADDR on the preflight bind so TIME_WAIT does not mimic a live listener; keep live listener refusal and never enable SO_REUSEPORT." + } + ], + "unchanged_historical_evidence": { + "receipt.json": "3c7fb4ec3b477b90f47b3765a0122a89aa39fb6c0fe3529818f6c4b4145e1cd7", + "experiment.json": "1d6df4651976293bef2a18867430912db51496ecb3fd60224b44061f31098556", + "freeze.json": "333198ba238dd35bea47882dea9e15fcadf1ab5b8609ed2bfa93aa21a1911720" + }, + "qualification": { + "command": "python3 -m unittest discover -s blueprints/convergence-practice/application-delivery -p 'test_portability.py' -v", + "status": "passed", + "tests": 5, + "scope": "Native synthetic make recursion plus actual owned loopback TIME_WAIT/live-listener sockets; no unknown process stopped.", + "exit_code": 0, + "host": { + "system": "Darwin", + "macos": "26.5.1", + "architecture": "arm64", + "python": "3.14.7", + "make": "GNU Make 3.81" + }, + "observed_make_levels": { + "original_external": [ + "all:1" + ], + "fixed_build_install": [ + "all:0", + "internal:1", + "install:0", + "internal:1" + ] + }, + "observed_socket_results": { + "ordinary_bind_after_TIME_WAIT": "EADDRINUSE", + "reuseaddr_probe_after_TIME_WAIT": "passed", + "reuseaddr_probe_with_live_listener": "EADDRINUSE; listener remained usable" + }, + "lint": { + "command": "ruff check --ignore EXE001 serve.py test_portability.py", + "status": "passed", + "retained_baseline_note": "serve.py already had a shebang with non-executable mode at cabbe2c and is invoked explicitly with python3; its mode is unchanged. EXE001 is excluded only from this focused lint invocation." + } + } +} diff --git a/blueprints/convergence-practice/application-delivery/history/serve.cabbe2c.py b/blueprints/convergence-practice/application-delivery/history/serve.cabbe2c.py new file mode 100644 index 000000000..e47e757ed --- /dev/null +++ b/blueprints/convergence-practice/application-delivery/history/serve.cabbe2c.py @@ -0,0 +1,54 @@ +#!/usr/bin/env python3 +"""Run only the two owned loopback application processes in the foreground.""" +import os +from pathlib import Path +import signal +import socket +import subprocess +import time + +HERE = Path(__file__).resolve().parent + + +def main(): + for port in (18080, 18081): + with socket.socket() as probe: + probe.bind(("127.0.0.1", port)) + logs = HERE / ".runtime" + logs.mkdir(exist_ok=True) + children, handles = [], [] + + def interrupted(_number, _frame): + raise KeyboardInterrupt + + signal.signal(signal.SIGTERM, interrupted) + try: + for name, command in [ + ("api", [str(HERE / ".venv/bin/python"), "-m", "uvicorn", "backend.app:app", "--host", "127.0.0.1", "--port", "18081"]), + ("web", ["pnpm", "start"]), + ]: + handle = (logs / f"{name}.log").open("a") + handles.append(handle) + children.append(subprocess.Popen(command, cwd=HERE, stdout=handle, stderr=subprocess.STDOUT, + env={**os.environ, "NEXT_TELEMETRY_DISABLED": "1"}, start_new_session=True)) + print("Run ledger: http://127.0.0.1:18080 (Ctrl-C stops both owned application processes)", flush=True) + while all(child.poll() is None for child in children): + time.sleep(0.2) + return 1 + except KeyboardInterrupt: + return 0 + finally: + for child in children: + if child.poll() is None: + os.killpg(child.pid, signal.SIGTERM) + try: + child.wait(timeout=5) + except subprocess.TimeoutExpired: + os.killpg(child.pid, signal.SIGKILL) + child.wait(timeout=5) + for handle in handles: + handle.close() + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/blueprints/convergence-practice/application-delivery/serve.py b/blueprints/convergence-practice/application-delivery/serve.py index e47e757ed..feca81116 100644 --- a/blueprints/convergence-practice/application-delivery/serve.py +++ b/blueprints/convergence-practice/application-delivery/serve.py @@ -1,19 +1,25 @@ #!/usr/bin/env python3 """Run only the two owned loopback application processes in the foreground.""" import os -from pathlib import Path import signal import socket import subprocess import time +from pathlib import Path HERE = Path(__file__).resolve().parent -def main(): - for port in (18080, 18081): +def probe_ports(ports): + """Allow ordinary restart reuse while refusing a live loopback listener.""" + for port in ports: with socket.socket() as probe: + probe.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) probe.bind(("127.0.0.1", port)) + + +def main(): + probe_ports((18080, 18081)) logs = HERE / ".runtime" logs.mkdir(exist_ok=True) children, handles = [], [] diff --git a/blueprints/convergence-practice/application-delivery/test_portability.py b/blueprints/convergence-practice/application-delivery/test_portability.py new file mode 100644 index 000000000..f9b27c9a0 --- /dev/null +++ b/blueprints/convergence-practice/application-delivery/test_portability.py @@ -0,0 +1,119 @@ +"""Small native make/socket regressions; no application or PostgreSQL build.""" +import errno +import hashlib +import importlib.util +import json +import os +import shutil +import socket +import subprocess +import tempfile +import unittest +from pathlib import Path + +HERE = Path(__file__).resolve().parent +spec = importlib.util.spec_from_file_location("ledger_serve", HERE / "serve.py") +serve = importlib.util.module_from_spec(spec) +spec.loader.exec_module(serve) + + +class MakeBoundaryTests(unittest.TestCase): + def exercise(self, source): + make = shutil.which("make") + self.assertIsNotNone(make, "native make is required for this regression") + commands = [line for line in source.read_text().splitlines() + if "$(MAKE)" in line and "-C .runtime/postgresql-build" in line] + self.assertEqual(len(commands), 2, "exercise both actual build/install boundaries") + with tempfile.TemporaryDirectory(prefix="ledger-make-boundary-") as folder: + root = Path(folder) + external = root / ".runtime/postgresql-build" + external.mkdir(parents=True) + (root / "Makefile").write_text(".PHONY: all\nall:\n" + "\n".join(commands) + "\n") + (external / "Makefile").write_text( + ".PHONY: all install internal\n" + "all install:\n" + "\t@printf '%s:%s\\n' '$@' '$(MAKELEVEL)' >> levels.txt\n" + "\t@test '$(MAKELEVEL)' = '0'\n" + "\t@$(MAKE) --no-print-directory internal\n" + "internal:\n" + "\t@printf 'internal:%s\\n' '$(MAKELEVEL)' >> levels.txt\n" + "\t@test '$(MAKELEVEL)' = '1'\n" + ) + result = subprocess.run([make, "--no-print-directory"], cwd=root, + env={"PATH": os.defpath, "LC_ALL": "C"}, capture_output=True, text=True, + timeout=10, check=False) + levels = (external / "levels.txt").read_text().splitlines() + return result, levels + + def test_original_recipe_reproduces_external_recursion_bug(self): + result, levels = self.exercise(HERE / "history/Makefile.cabbe2c") + self.assertNotEqual(result.returncode, 0) + self.assertEqual(levels, ["all:1"]) + + def test_build_and_install_reset_only_external_boundary(self): + result, levels = self.exercise(HERE / "Makefile") + self.assertEqual(result.returncode, 0, result.stderr) + self.assertEqual(levels, ["all:0", "internal:1", "install:0", "internal:1"]) + + +class RestartPortTests(unittest.TestCase): + def test_time_wait_restart_is_allowed(self): + # The accepted server socket actively closes, leaving its local port in + # TIME_WAIT. Both listener and accepted socket inherit SO_REUSEADDR, + # matching ordinary native application server behavior. + with socket.socket() as listener: + listener.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + listener.bind(("127.0.0.1", 0)) + listener.listen(1) + address = listener.getsockname() + with socket.create_connection(address, timeout=2) as client: + accepted, _ = listener.accept() + with accepted: + accepted.settimeout(2) + accepted.shutdown(socket.SHUT_WR) + self.assertEqual(client.recv(1), b"") + client.shutdown(socket.SHUT_WR) + self.assertEqual(accepted.recv(1), b"") + with socket.socket() as old_probe: + with self.assertRaises(OSError) as raised: + old_probe.bind(address) + self.assertEqual(raised.exception.errno, errno.EADDRINUSE) + serve.probe_ports([address[1]]) + + def test_live_listener_is_refused_and_remains_usable(self): + with socket.socket() as listener: + listener.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + listener.bind(("127.0.0.1", 0)) + listener.listen(1) + listener.settimeout(2) + address = listener.getsockname() + with self.assertRaises(OSError) as raised: + serve.probe_ports([address[1]]) + self.assertEqual(raised.exception.errno, errno.EADDRINUSE) + with socket.create_connection(address, timeout=2) as client: + accepted, _ = listener.accept() + with accepted: + accepted.sendall(b"owned listener remains alive") + self.assertEqual(client.recv(128), b"owned listener remains alive") + + +class RecipeHistoryTests(unittest.TestCase): + def test_retained_originals_and_current_mapping(self): + history = json.loads((HERE / "history/recipe-revisions.json").read_text()) + original_receipt = json.loads((HERE / "receipt.json").read_text()) + accepted_hashes = {row["artifact"]: row["sha256"] + for row in original_receipt["artifact_sha256"]} + for row in history["recipes"]: + with self.subTest(recipe=row["current_path"]): + old = HERE / row["original"]["retained_path"] + current = HERE / row["current_path"] + self.assertEqual(hashlib.sha256(old.read_bytes()).hexdigest(), row["original"]["sha256"]) + self.assertEqual(accepted_hashes[row["current_path"]], row["original"]["sha256"]) + self.assertEqual(hashlib.sha256(current.read_bytes()).hexdigest(), row["current_sha256"]) + self.assertNotEqual(old.read_bytes(), current.read_bytes()) + for name, expected in history["unchanged_historical_evidence"].items(): + self.assertEqual(hashlib.sha256((HERE / name).read_bytes()).hexdigest(), expected) + + +if __name__ == "__main__": + unittest.main() From 3df1cc1ced71a9ae32d22a2ca045ea92b4c96a44 Mon Sep 17 00:00:00 2001 From: seathatflowsinourveins <234074349+seathatflowsinourveins@users.noreply.github.com> Date: Sun, 20 Sep 2026 03:23:47 -0400 Subject: [PATCH 4/6] Record native WSL acceptance of portability regressions --- .../wsl-application/portability-followup.json | 107 ++++++++++++++++++ 1 file changed, 107 insertions(+) create mode 100644 blueprints/convergence-practice/wsl-application/portability-followup.json diff --git a/blueprints/convergence-practice/wsl-application/portability-followup.json b/blueprints/convergence-practice/wsl-application/portability-followup.json new file mode 100644 index 000000000..8dde1a1f5 --- /dev/null +++ b/blueprints/convergence-practice/wsl-application/portability-followup.json @@ -0,0 +1,107 @@ +{ + "schema_version": 1, + "kind": "native_cli_e2e", + "status": "passed", + "scope": "Five actual native make/socket/history regressions for the corrected recipe on WSL; original full-stack fixture left unchanged.", + "source_revision": "d4923dc34221e6c727078bc835128ffb04b009ad", + "source_repository": "https://github.com/seathatflowsinourveins/native-agent-stack", + "source_transfer": "Exact git archive files copied into a new task-only followup prefix; all nine SHA256 values verified before and after native execution.", + "source_files": [ + { + "path": "blueprints/convergence-practice/application-delivery/Makefile", + "sha256": "799c61469b98dddbc20870b6166737312968a97ddf16aa6ed3e7d50104278e80" + }, + { + "path": "blueprints/convergence-practice/application-delivery/serve.py", + "sha256": "bba1f9655cce0b412257fbd0c40680b6b0ccc0ecffb91a2f3605323491655aed" + }, + { + "path": "blueprints/convergence-practice/application-delivery/test_portability.py", + "sha256": "f36b9561325821310d11ac3c4bae9b8b2f14a75573d60466eac5bea58b4b1901" + }, + { + "path": "blueprints/convergence-practice/application-delivery/history/Makefile.cabbe2c", + "sha256": "dbab0b62a259b26a86a8e174b2ab17ba7ce28ac5d19f8412fb41c016f75bc011" + }, + { + "path": "blueprints/convergence-practice/application-delivery/history/serve.cabbe2c.py", + "sha256": "e3e59b5315d5f2b3c2fe863cdecabfd9f7ffd1977a83d332331a10e33a42a14e" + }, + { + "path": "blueprints/convergence-practice/application-delivery/history/recipe-revisions.json", + "sha256": "d7eb27d31cfdeac5a1664306d1ff94d5df1095f43f0d1041796dc6ef384132b1" + }, + { + "path": "blueprints/convergence-practice/application-delivery/receipt.json", + "sha256": "3c7fb4ec3b477b90f47b3765a0122a89aa39fb6c0fe3529818f6c4b4145e1cd7" + }, + { + "path": "blueprints/convergence-practice/application-delivery/experiment.json", + "sha256": "1d6df4651976293bef2a18867430912db51496ecb3fd60224b44061f31098556" + }, + { + "path": "blueprints/convergence-practice/application-delivery/freeze.json", + "sha256": "333198ba238dd35bea47882dea9e15fcadf1ab5b8609ed2bfa93aa21a1911720" + } + ], + "host": { + "role": "velanext", + "system": "Linux", + "kernel": "6.18.33.2-microsoft-standard-WSL2", + "architecture": "x86_64", + "python": "3.13.15", + "make": "GNU Make 4.3" + }, + "started_at_utc": "2026-09-20T07:22:19.774901+00:00", + "completed_at_utc": "2026-09-20T07:22:19.940218+00:00", + "command": "python3.13 -m unittest discover -s blueprints/convergence-practice/application-delivery -p test_portability.py -v", + "exit_code": 0, + "tests": { + "passed": 5, + "failed": 0, + "skipped": 0, + "names": [ + "test_build_and_install_reset_only_external_boundary", + "test_original_recipe_reproduces_external_recursion_bug", + "test_retained_originals_and_current_mapping", + "test_live_listener_is_refused_and_remains_usable", + "test_time_wait_restart_is_allowed" + ] + }, + "observed_assertions": { + "original_external_make": "Expected nonzero exit with all:1; negative control reproduced.", + "fixed_make_levels": [ + "all:0", + "internal:1", + "install:0", + "internal:1" + ], + "history": "Retained originals match historical receipt hashes; corrected current files match explicit recipe mapping; receipt/experiment/freeze hashes unchanged.", + "ordinary_bind_after_time_wait": "EADDRINUSE", + "corrected_probe_after_time_wait": "passed", + "corrected_probe_with_live_listener": "EADDRINUSE; original owned listener remains usable" + }, + "unexpected_native_failures": [], + "source_files_unchanged": true, + "original_frozen_wsl_lane_unchanged": true, + "cleanup": { + "temporary_test_directories_remaining": [], + "sockets": "All owned loopback listeners and connections were closed by test context managers.", + "persistent_servers_started": false, + "existing_listener_stopped": false, + "global_changes": false + }, + "private_evidence": { + "native_log_sha256": "36b074b0fb8b332527e73c036593ee7fc914fbb47f5223b6b6100954b9677c29", + "source_manifest_sha256": "85afef9fc5e2fa5e9163c26f3fac9f5843e45045abe24938c2ee7697b3b23e97", + "report_sha256": "111bba79dbd546c3dc1e49d8da90bbe7050757c1a22326a2c68b20cdda396787", + "location": "New task-owned WSL followup prefix; native test log, exit status and exact source manifest retained privately." + }, + "limits": [ + "Executed WSL regression receipt, not a full PostgreSQL/application rebuild.", + "No dependency setup, model/provider call, GPU workload or original full-stack acceptance repeat.", + "Original WSL full-stack receipt remains scoped to cabbe2c; this followup qualifies only the corrected make boundary, restart probe and history mapping at d4923dc.", + "Whole-task model usage unknown; no token-saving claim." + ], + "rollback": "No persistent service or global state changed; remove only the newly created followup prefix after preserving required evidence." +} From 1d42918df85d9c3dd3795da6bf7660e8be58e820 Mon Sep 17 00:00:00 2001 From: seathatflowsinourveins <234074349+seathatflowsinourveins@users.noreply.github.com> Date: Sun, 20 Sep 2026 03:30:51 -0400 Subject: [PATCH 5/6] Bind native maintenance and WSL acceptance to complete evidence validation --- .github/workflows/validate.yml | 3 +- adoption/manifest.json | 3 +- .../ci-security/README.md | 11 + .../ci-security/experiment.json | 2 +- .../ci-security/qualified-workflow.yml.txt | 40 +++ .../convergence-practice/layer-acceptance.md | 2 + catalogs/us-equities/decision-index.json | 24 +- catalogs/us-equities/manifest.json | 4 +- docs/ecosystem/index.html | 2 +- docs/ecosystem/manifest.json | 14 + .../receipts/mac-memory-patch-20260920.json | 19 ++ .../receipts/wsl-application-20260920.json | 22 ++ manifests/evidence.json | 254 ++++++++++++++++-- manifests/stack.json | 41 ++- scripts/validate_convergence.py | 57 +++- tests/test_convergence_contract.py | 70 ++++- tests/test_native_maintenance.py | 20 ++ 17 files changed, 538 insertions(+), 50 deletions(-) create mode 100644 blueprints/convergence-practice/ci-security/qualified-workflow.yml.txt create mode 100644 evidence/receipts/mac-memory-patch-20260920.json create mode 100644 evidence/receipts/wsl-application-20260920.json create mode 100644 tests/test_native_maintenance.py diff --git a/.github/workflows/validate.yml b/.github/workflows/validate.yml index b2b36733f..dd24742cb 100644 --- a/.github/workflows/validate.yml +++ b/.github/workflows/validate.yml @@ -32,8 +32,7 @@ jobs: - name: Validate declared convergence evidence and scope run: >- python3 scripts/validate_convergence.py - blueprints/convergence-practice/ci-security/experiment.json - blueprints/convergence-practice/native-worker/experiment.json --root . --json + --all-recorded --root . --json - name: Check offline ecosystem explorer rebuild run: python3 scripts/build_ecosystem.py --check - name: Test validation failure modes diff --git a/adoption/manifest.json b/adoption/manifest.json index 942459496..25f8c0302 100644 --- a/adoption/manifest.json +++ b/adoption/manifest.json @@ -134,7 +134,8 @@ "fastapi": "blueprints/convergence-practice/application-delivery/README.md", "postgresql": "blueprints/convergence-practice/application-delivery/README.md", "poppler": "blueprints/convergence-practice/document-ingestion/README.md", - "apple-container": "blueprints/convergence-practice/container-storage/README.md" + "apple-container": "blueprints/convergence-practice/container-storage/README.md", + "playwright-test": "blueprints/convergence-practice/wsl-application/README.md" }, "profiles": [ { diff --git a/blueprints/convergence-practice/ci-security/README.md b/blueprints/convergence-practice/ci-security/README.md index 013ec4e35..dc76e79ff 100644 --- a/blueprints/convergence-practice/ci-security/README.md +++ b/blueprints/convergence-practice/ci-security/README.md @@ -56,3 +56,14 @@ wheel hash and replay of both accepted and rejected cases. Rollback removes the selected CI analyzer step, lock and its tests together; the existing evidence and catalog validation remain the baseline. Public CI results qualify that runner only; another host must run its own acceptance. + +The original accepted workflow bytes are retained in `qualified-workflow.yml.txt`. +The historical experiment references that immutable copy; current CI validates +every convergence record registered in the evidence manifest with +`python3 scripts/validate_convergence.py --all-recorded --json`. This checks +declared hashes and scope without rerunning native commands or model trials. + +Every contract is explicitly listed in `manifests/evidence.json` under +`convergence_records`. Discovery also rejects undeclared canonical experiment +paths or tagged records. Missing/misspelled `kind` fields are validated instead +of silently excluding a declared experiment. diff --git a/blueprints/convergence-practice/ci-security/experiment.json b/blueprints/convergence-practice/ci-security/experiment.json index 6ecc849a2..a3eb40e12 100644 --- a/blueprints/convergence-practice/ci-security/experiment.json +++ b/blueprints/convergence-practice/ci-security/experiment.json @@ -81,7 +81,7 @@ ], "inputs": [ { - "path": ".github/workflows/validate.yml", + "path": "blueprints/convergence-practice/ci-security/qualified-workflow.yml.txt", "sha256": "7f1657842cd563b64474a3c44bd0a24ce4aa2df81ad6cf977e193d9af11d13d9" }, { diff --git a/blueprints/convergence-practice/ci-security/qualified-workflow.yml.txt b/blueprints/convergence-practice/ci-security/qualified-workflow.yml.txt new file mode 100644 index 000000000..b2b36733f --- /dev/null +++ b/blueprints/convergence-practice/ci-security/qualified-workflow.yml.txt @@ -0,0 +1,40 @@ +name: Validate published evidence + +on: + push: + pull_request: + workflow_dispatch: + +permissions: + contents: read + +jobs: + validate: + runs-on: ubuntu-24.04 + timeout-minutes: 5 + steps: + - name: Check out repository + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false + - name: Install checksum-locked CI analyzer + run: >- + python3 -m pip install --disable-pip-version-check --no-input + --only-binary=:all: --require-hashes + --index-url https://pypi.org/simple + -r .github/requirements-ci.lock + - name: Audit GitHub workflows without network or credentials + run: zizmor --offline --no-config --no-ignores --persona regular --strict-collection .github/workflows + - name: Validate manifests and evidence integrity + run: python3 scripts/validate.py + - name: Validate catalog evidence and coverage joins + run: python3 scripts/validate_catalogs.py + - name: Validate declared convergence evidence and scope + run: >- + python3 scripts/validate_convergence.py + blueprints/convergence-practice/ci-security/experiment.json + blueprints/convergence-practice/native-worker/experiment.json --root . --json + - name: Check offline ecosystem explorer rebuild + run: python3 scripts/build_ecosystem.py --check + - name: Test validation failure modes + run: python3 -m unittest diff --git a/blueprints/convergence-practice/layer-acceptance.md b/blueprints/convergence-practice/layer-acceptance.md index e441cc2b6..dee9977a9 100644 --- a/blueprints/convergence-practice/layer-acceptance.md +++ b/blueprints/convergence-practice/layer-acceptance.md @@ -9,6 +9,8 @@ and deployment remain distinct. | [Application delivery](application-delivery/README.md) | Locked Next16.3.5/React19.3.0 UI, FastAPI0.141.1, real PostgreSQL18.6,12 API checks, browser create/update and exact row after full restart | Mac synthetic project; no production/user authentication/cloud acceptance. Supported TypeScript5.9.3 retained after7.0.2 failed the native generator. | | [Document ingestion](document-ingestion/README.md) | Current Poppler26.09.0,3 permitted pages,24 table cells,8 cited positive and4 absent queries; strict frozen-source guard | Designed born-digital fixture with explicit table geometry; OCR, arbitrary layout and semantic search remain unqualified. | | [Container storage](container-storage/README.md) | Apple container1.4.1, pinned PostgreSQL18.6 image, native ext4 volume and row retained after stop/start | Mac Documents bind mount stalled; named volume passed. No crash/reboot or production durability claim. | +| [WSL application](wsl-application/README.md) | Same locked app,12 API checks, real Linux browser, migration reversal and exact row/history across full restart | Isolated Ubuntu24.04 prefix; signed package extraction only. Five native portability regressions pass on Mac and WSL. | +| [Mac memory patch](mac-memory-patch/README.md) |56 synthetic checks for native2.3.1→2.3.2 migration, scope isolation, Unicode/reserved paths and persistence | No-model/no-capture synthetic store; failed OS sandbox attempt retained. Production adoption is separate private host evidence. | | [WSL recovery](wsl-restore/README.md) | Native restic0.19.1, two exact synthetic snapshot restores, wrong-password/corrupt-copy refusals, fresh SSH recovery | Same physical WSL host; independent off-host key-loss disaster recovery remains open. | [WSL native quality tools](wsl-native-tools/README.md) add verified gitleaks8.30.1 diff --git a/catalogs/us-equities/decision-index.json b/catalogs/us-equities/decision-index.json index fe61c3852..0bb9f3f61 100644 --- a/catalogs/us-equities/decision-index.json +++ b/catalogs/us-equities/decision-index.json @@ -161,13 +161,13 @@ "zep-ai/graphiti": "getzep/graphiti" }, "counts": { - "repositories": 511, + "repositories": 512, "public_star_repositories": 342, - "beyond_public_stars": 169, - "references": 1063, + "beyond_public_stars": 170, + "references": 1064, "repositories_by_record_type": { "catalog_card": 147, - "component_record": 64, + "component_record": 65, "legacy_candidate": 20, "public_star": 342, "research_supplement": 103, @@ -6995,6 +6995,22 @@ } ] }, + { + "repository": "https://github.com/microsoft/playwright", + "aliases": [], + "public_star": false, + "record_types": [ + "component_record" + ], + "references": [ + { + "kind": "component_record", + "path": "manifests/stack.json", + "pointer": "/components/64", + "id": "playwright-test" + } + ] + }, { "repository": "https://github.com/microsoft/playwright-cli", "aliases": [], diff --git a/catalogs/us-equities/manifest.json b/catalogs/us-equities/manifest.json index c00aa2f49..dfeb92ae3 100644 --- a/catalogs/us-equities/manifest.json +++ b/catalogs/us-equities/manifest.json @@ -56,7 +56,7 @@ "harness_contract": "blueprints/us-equities/harness-contract.json", "broader_reference_union": 171, "star_audit_file": "catalogs/us-equities/star-audit.json", - "grand_index_repositories": 511, - "grand_index_beyond_stars": 169, + "grand_index_repositories": 512, + "grand_index_beyond_stars": 170, "decision_index_file": "catalogs/us-equities/decision-index.json" } diff --git a/docs/ecosystem/index.html b/docs/ecosystem/index.html index f123728c3..6b1ef09a9 100644 --- a/docs/ecosystem/index.html +++ b/docs/ecosystem/index.html @@ -60,7 +60,7 @@

One offline file. No external scripts, fonts, analytics, account access or background requests. Links open public sources when you choose. Reference evidence is never authority to install, deploy or trade.

Open the public repository ↗

- + +