From 7f379be69d22860facd1cd3f73ab1567af313e2a Mon Sep 17 00:00:00 2001 From: seathatflowsinourveins <234074349+seathatflowsinourveins@users.noreply.github.com> Date: Sun, 27 Sep 2026 03:30:08 -0400 Subject: [PATCH 01/12] Host receipts: claude-code and codex use-stage on mac-coordinator-64gb-20260925 (#382) Records native_proven use-stage receipts for the installed claude-code and codex clients on the Mac's Stage 1 client layer (host request #382): a version-resolving command, a headless claude -p turn with a random-fixture positive control plus claude mcp list, and a codex exec turn (JSON event stream, command_execution positive control) plus codex mcp list --json and codex features list cross-checked against this host's own config.toml. Both receipts are recorded with --allow-unbound-version (installed builds are newer than the current catalog pins) and superseded once each to back the version claim with a retained command instead of only --component-version. Refreshes the derived component-evidence-matrix accordingly. Co-Authored-By: Claude Sonnet 5 --- .../landscape/component-evidence-matrix.json | 16 ++-- docs/component-evidence-matrix.md | 6 +- ...0260925--claude-code--use--20260927-2.json | 75 +++++++++++++++++ ...-20260925--claude-code--use--20260927.json | 67 +++++++++++++++ ...64gb-20260925--codex--use--20260927-2.json | 84 +++++++++++++++++++ ...r-64gb-20260925--codex--use--20260927.json | 75 +++++++++++++++++ manifests/evidence.json | 26 +++++- 7 files changed, 335 insertions(+), 14 deletions(-) create mode 100644 evidence/hosts/mac-coordinator-64gb-20260925/mac-coordinator-64gb-20260925--claude-code--use--20260927-2.json create mode 100644 evidence/hosts/mac-coordinator-64gb-20260925/mac-coordinator-64gb-20260925--claude-code--use--20260927.json create mode 100644 evidence/hosts/mac-coordinator-64gb-20260925/mac-coordinator-64gb-20260925--codex--use--20260927-2.json create mode 100644 evidence/hosts/mac-coordinator-64gb-20260925/mac-coordinator-64gb-20260925--codex--use--20260927.json diff --git a/catalogs/landscape/component-evidence-matrix.json b/catalogs/landscape/component-evidence-matrix.json index 7e6476f03..3eae44f21 100644 --- a/catalogs/landscape/component-evidence-matrix.json +++ b/catalogs/landscape/component-evidence-matrix.json @@ -83,8 +83,8 @@ "fail": 0, "independently_reviewed_fail": 0, "independently_reviewed_pass": 0, - "latest": null, - "pass": 0 + "latest": "2026-09-27T07:21:43Z", + "pass": 1 }, "qualified_models": [] } @@ -1626,8 +1626,8 @@ "fail": 0, "independently_reviewed_fail": 0, "independently_reviewed_pass": 0, - "latest": null, - "pass": 0 + "latest": "2026-09-27T07:21:34Z", + "pass": 1 }, "qualified_models": [] } @@ -1676,8 +1676,8 @@ "fail": 0, "independently_reviewed_fail": 0, "independently_reviewed_pass": 0, - "latest": null, - "pass": 0 + "latest": "2026-09-27T07:21:43Z", + "pass": 1 }, "qualified_models": [] } @@ -3219,8 +3219,8 @@ "fail": 0, "independently_reviewed_fail": 0, "independently_reviewed_pass": 0, - "latest": null, - "pass": 0 + "latest": "2026-09-27T07:21:34Z", + "pass": 1 }, "qualified_models": [] } diff --git a/docs/component-evidence-matrix.md b/docs/component-evidence-matrix.md index cd478372b..aeb6725d3 100644 --- a/docs/component-evidence-matrix.md +++ b/docs/component-evidence-matrix.md @@ -20,7 +20,7 @@ Each winner shows, for linux-wsl2-x86_64 / macos-arm64, its `e2e_state` and host | Layer | Independent review | Winners: e2e_state [receipts] (linux-wsl2-x86_64 / macos-arm64) | | --- | --- | --- | -| `foundation/agent-sdks` | dual_lane_same_winner | codex (host_verified [8/0/5/0] dissented 3 / untested [0/0/0/0]) | +| `foundation/agent-sdks` | dual_lane_same_winner | codex (host_verified [8/0/5/0] dissented 3 / untested [1/0/0/0]) | | `foundation/ci-supply-chain` | dual_lane_same_winner | zizmor (host_verified [2/0/2/0] / untested [0/0/0/0]); syft (host_verified [2/0/2/0] / untested [0/0/0/0]); candidate:actions-attest (accepted [0/0/0/0] / untested [0/0/0/0]) | | `foundation/code-navigation` | dual_lane_adjudicated (adjudication: `evidence/artifacts/layer-verdicts-20260922/adjudication/foundation-code-navigation-20260922.json`) | serena (host_verified [3/0/2/0] dissented 1 / untested [0/0/0/0]) | | `foundation/document-retrieval` | dual_lane_adjudicated (adjudication: `evidence/artifacts/layer-verdicts-20260922/adjudication/foundation-document-retrieval-20260922.json`) | qmd (host_verified [2/0/2/0] / untested [1/0/0/0]); markitdown (host_verified [2/0/2/0] / untested [0/0/0/0]); poppler (host_verified [4/0/3/0] dissented 1 / untested [0/0/0/0]) | @@ -30,7 +30,7 @@ Each winner shows, for linux-wsl2-x86_64 / macos-arm64, its `e2e_state` and host | `foundation/instructions-skills` | dual_lane_adjudicated (adjudication: `evidence/artifacts/layer-verdicts-20260922/adjudication/foundation-instructions-skills-20260922.json`) | affaan-m/ECC (conditional [2/0/1/0] dissented 1 / untested [0/0/0/0]); candidate:typesafe-ai-skills (conditional [0/0/0/0] / untested [0/0/0/0]); candidate:openai-skills (conditional [0/0/0/0] / untested [0/0/0/0]) | | `foundation/isolation` | dual_lane_same_winner | worktrunk (host_verified [2/0/2/0] / host_verified [1/0/1/0]); sandbox-runtime (host_verified [1/0/1/0] / untested [0/0/0/0]) | | `foundation/mcp-surfaces` | dual_lane_same_winner | mcporter (host_verified [6/0/2/0] dissented 4 / untested [0/0/0/0]); mcp-inspector (host_verified [2/0/1/0] dissented 1 / untested [0/0/0/0]) | -| `foundation/native-clients` | dual_lane_same_winner | claude-code (accepted [1/0/1/0] / untested [0/0/0/0]); codex (host_verified [8/0/5/0] dissented 3 / untested [0/0/0/0]) | +| `foundation/native-clients` | dual_lane_same_winner | claude-code (accepted [1/0/1/0] / untested [1/0/0/0]); codex (host_verified [8/0/5/0] dissented 3 / untested [1/0/0/0]) | | `foundation/observation-inference` | dual_lane_adjudicated (adjudication: `evidence/artifacts/layer-verdicts-20260922/adjudication/foundation-observation-inference-20260922.json`) | opentelemetry-collector-contrib (host_verified [2/0/2/0] / untested [0/0/0/0]); prometheus (host_verified [2/0/2/0] / untested [0/0/0/0]); loki (host_verified [2/0/2/0] / untested [0/0/0/0]) | | `foundation/quality-evaluation` | dual_lane_same_winner | promptfoo (host_verified [6/0/2/0] dissented 4 / untested [0/0/0/0]); playwright-test (conditional [0/0/0/0] / untested [1/0/0/0] dissented 1) | | `foundation/recovery-portability` | dual_lane_same_winner | restic (host_verified [3/0/3/0] / untested [1/0/0/0]); candidate:astral-sh-uv (conditional [0/0/0/0] / untested [0/0/0/0]) | @@ -39,7 +39,7 @@ Each winner shows, for linux-wsl2-x86_64 / macos-arm64, its `e2e_state` and host | `foundation/semantic-rag` | dual_lane_same_winner | socraticode (host_verified [5/0/2/0] dissented 3 / untested [1/0/0/0]); qdrant (host_verified [3/0/3/0] / untested [1/0/0/0]); vllm (host_verified [6/0/3/0] dissented 2 / untested [0/0/0/0]) | | `foundation/token-efficiency` | dual_lane_adjudicated (adjudication: `evidence/artifacts/layer-verdicts-20260922/adjudication/foundation-token-efficiency-20260922.json`) | rtk (host_verified [7/0/4/0] dissented 2 / host_verified [1/0/1/0]); headroom (host_verified [4/0/3/0] dissented 1 / untested [0/0/0/0]); ccusage (host_verified [2/0/2/0] / untested [0/0/0/0]) | | `foundation/web-research` | dual_lane_adjudicated (adjudication: `evidence/artifacts/layer-verdicts-20260922/adjudication/foundation-web-research-20260922.json`) | tavily-cli (conditional [0/0/0/0] / untested [0/0/0/0]); agent-browser (conditional [0/0/0/0] / untested [0/0/0/0]); openresearch (conditional [0/0/0/0] / untested [0/0/0/0]) | -| `foundation/workers` | dual_lane_adjudicated (adjudication: `evidence/artifacts/layer-verdicts-20260922/adjudication/foundation-workers-20260922.json`) | claude-code (conditional [1/0/1/0] / untested [0/0/0/0]); worktrunk (host_verified [2/0/2/0] / host_verified [1/0/1/0]) | +| `foundation/workers` | dual_lane_adjudicated (adjudication: `evidence/artifacts/layer-verdicts-20260922/adjudication/foundation-workers-20260922.json`) | claude-code (conditional [1/0/1/0] / untested [1/0/0/0]); worktrunk (host_verified [2/0/2/0] / host_verified [1/0/1/0]) | | `us-equities/agents-models-workers` | dual_lane_same_winner | codex-native-sdk (accepted [0/0/0/0] / untested [0/0/0/0]); foundation-ai-memory (accepted [0/0/0/0] / untested [0/0/0/0]); foundation-socraticode (accepted [0/0/0/0] / untested [0/0/0/0]) | | `us-equities/backtesting-engine` | dual_lane_same_winner | nautilustrader (host_verified [1/0/1/0] / untested [0/0/0/0] +1 alias receipt(s), not counted); lean (host_verified [2/0/1/0] dissented 1 / untested [0/0/0/0]) | | `us-equities/data-quality-orchestration` | dual_lane_adjudicated (adjudication: `evidence/artifacts/layer-verdicts-20260922/adjudication/us-equities-data-quality-orchestration-20260922.json`) | dagu (host_verified [2/0/2/0] / untested [0/0/0/0]); data-pandera (host_verified [3/0/1/0] dissented 2 / untested [0/0/0/0]) | diff --git a/evidence/hosts/mac-coordinator-64gb-20260925/mac-coordinator-64gb-20260925--claude-code--use--20260927-2.json b/evidence/hosts/mac-coordinator-64gb-20260925/mac-coordinator-64gb-20260925--claude-code--use--20260927-2.json new file mode 100644 index 000000000..f2c5f0e22 --- /dev/null +++ b/evidence/hosts/mac-coordinator-64gb-20260925/mac-coordinator-64gb-20260925--claude-code--use--20260927-2.json @@ -0,0 +1,75 @@ +{ + "schema_version": 1, + "id": "mac-coordinator-64gb-20260925--claude-code--use--20260927-2", + "kind": "host_acceptance", + "host": { + "host_id": "mac-coordinator-64gb-20260925", + "platform_id": "macos-arm64", + "os": "macos", + "architecture": "arm64", + "second_physical_machine": true, + "hardware_profile_ref": "mac-coordinator-64gb-20260925" + }, + "catalog_revision": "1aa9776591847b4860bf258f8953315ae71d7bc4", + "recorded_by": { + "identity_sha256": "91719ef8aa813c0bf50b26570098baa57e4c043d7d23d4cc5c26ce7c17710954", + "model": "claude-sonnet-5" + }, + "component_id": "claude-code", + "stage": "use", + "commands": [ + { + "cmd": "p=$(command -v claude)\necho \"resolved: $p\"\necho \"readlink: $(readlink -f \"$p\" 2>/dev/null || echo \"$p (not a symlink)\")\"\nclaude --version", + "exit": 0, + "duration_s": 0.014, + "output_sha256": "73436ead43a0c9c18663723a30ad3e166719def4b5eca2219418aa57432d886c", + "output_excerpt": "resolved: ~/.local/bin/claude\nreadlink: ~/.local/share/claude/versions/2.1.283\n2.1.283 (Claude Code)\n" + }, + { + "cmd": "D=\"$(mktemp -d)\"\nn=$((3 + RANDOM % 6))\n: > \"$D/fixture.txt\"\nfor i in $(seq 1 \"$n\"); do echo $((RANDOM % 900 + 1)) >> \"$D/fixture.txt\"; done\nreal=$(wc -l < \"$D/fixture.txt\" | tr -d ' ')\ncd \"$D\"\nclaude -p --output-format stream-json --verbose \"Count the lines in the file ./fixture.txt in your current working directory using your Read tool, then reply with exactly one line of the form COUNT= and nothing else.\" < /dev/null > out.jsonl 2> err.log\nrc=$?\npython3 - \"$real\" \"$rc\" <<'PY'\nimport json, re, sys\nreal, rc = sys.argv[1], sys.argv[2]\ninit = {}\nfinal = {}\nfor line in open(\"out.jsonl\"):\n line = line.strip()\n if not line:\n continue\n try:\n ev = json.loads(line)\n except ValueError:\n continue\n if ev.get(\"type\") == \"system\" and ev.get(\"subtype\") == \"init\" and not init:\n init = ev\n if ev.get(\"type\") == \"result\":\n final = ev\ncounts = {}\nfor key in (\"agents\", \"skills\", \"plugins\", \"mcp_servers\", \"slash_commands\", \"tools\"):\n v = init.get(key)\n if isinstance(v, list):\n counts[key] = len(v)\nmcp_status = sorted({s.get(\"status\") for s in init.get(\"mcp_servers\", []) if isinstance(s, dict)})\ntext = final.get(\"result\") or \"\"\nm = re.search(r\"COUNT=(\\d+)\", text)\ngot = m.group(1) if m else None\nok = (rc == \"0\") and (not final.get(\"is_error\")) and (got == real)\nprint(\"permissionMode=\" + str(init.get(\"permissionMode\")) + \" model=\" + str(init.get(\"model\")))\nprint(\"counts=\" + json.dumps(counts, sort_keys=True))\nprint(\"mcp_status=\" + json.dumps(mcp_status))\nprint(\"turn_subtype=\" + str(final.get(\"subtype\")) + \" is_error=\" + str(final.get(\"is_error\")))\nprint(\"positive_control expected=\" + real + \" got=\" + str(got) + \" match=\" + str(got == real))\nraise SystemExit(0 if ok else 1)\nPY", + "exit": 0, + "duration_s": 10.266, + "output_sha256": "3907e536551fa1de32f29cdbb218574671424a86197f803e969d9333e07881d5", + "output_excerpt": "permissionMode=bypassPermissions model=claude-opus-5-5[1m]\ncounts={\"agents\": 18, \"mcp_servers\": 5, \"plugins\": 11, \"skills\": 67, \"slash_commands\": 107, \"tools\": 118}\nmcp_status=[\"connected\"]\nturn_subtype=success is_error=False\npositive_control expected=5 got=5 match=True\n" + }, + { + "cmd": "D=\"$(mktemp -d)\"\ncd \"$D\"\nclaude mcp list < /dev/null 2>&1 | python3 -c \"\nimport sys\nrows = []\nfor line in sys.stdin:\n line = line.rstrip(chr(10))\n if ' - ' not in line or ': ' not in line:\n continue\n name, _, _ = line.partition(': ')\n _, _, status = line.rpartition(' - ')\n rows.append((name.strip(), status.strip()))\nrows.sort()\nfor name, status in rows:\n print(name + ': ' + status)\nprint('count=' + str(len(rows)))\n\"", + "exit": 0, + "duration_s": 1.587, + "output_sha256": "e3a146db303fe5ed9bbf4a55a1160f0442ae4d520117e5e50e4438befd67ac14", + "output_excerpt": "ai-memory: \u2714 Connected\nopenaiDeveloperDocs: \u2714 Connected\nplugin:context-mode:context-mode: \u2714 Connected\nserena: \u2714 Connected\nsocraticode: \u2714 Connected\ncount=5\n" + } + ], + "tool_versions": { + "claude-code": "2.1.283" + }, + "observed_at_utc": "2026-09-27T07:28:48Z", + "result": "pass", + "claim": "On host mac-coordinator-64gb-20260925 (macOS arm64), the installed Claude Code client, resolved and versioned by the first command below, performs a real headless turn from a freshly created scratch working directory under this Mac's user-scope client-layer profile (~/.claude): given a fixture file it creates itself with a random line count, `claude -p --output-format stream-json --verbose` reads the file with its own Read tool and replies with the correct count, while the run's init event reports the loaded profile's agent/skill/plugin/MCP-server/slash-command/tool counts and every configured MCP server's connection status. A separate `claude mcp list` from another fresh scratch directory independently reports every configured MCP server's name and health status. All commands exit 0 only when the reported count matches the independently computed one and the turn reports no error.", + "limitations": [ + "Recorded from a Claude Code session in a git worktree of this repository at commit 1aa97765 (the catalog_revision), not a pinned install checkout; the first command's --version reports 2.1.283, newer than the catalog's claude-code pin 2.1.278, so this receipt is recorded with --allow-unbound-version and does not count toward the winner's status.", + "second_physical_machine is declared, not proven by this file: this host's measured profile (evidence/artifacts/hw-profiles/mac-coordinator-64gb-20260925/profile.json) differs from the catalog's WSL authoring laptop. The receipt carries only the recorder's self review; accepted needs an independent review from a separate session.", + "Counts and connection statuses only: no MCP server command line, argument, environment value, session id, uuid or working-directory path is copied into this receipt; the --cmd values print only names, counts and statuses by construction, and the underlying stream-json/mcp list output (which does carry those fields) is never itself echoed to stdout.", + "This receipt exercises the native-clients role (a version check, one headless turn and an MCP listing); it does not exercise claude-code's owned-writing-child role in the workers layer, which needs a different command shape." + ], + "evidence_class": "native_proven", + "reviews": [ + { + "kind": "self", + "ref": "scripts/host_receipts.py record", + "verdict": "agree", + "at_utc": "2026-09-27T07:28:48Z", + "reviewer": { + "identity_sha256": "91719ef8aa813c0bf50b26570098baa57e4c043d7d23d4cc5c26ce7c17710954", + "model": "claude-sonnet-5" + } + } + ], + "layer_refs": [ + { + "catalog": "foundation", + "layer_id": "native-clients" + } + ], + "supersedes": "mac-coordinator-64gb-20260925--claude-code--use--20260927" +} diff --git a/evidence/hosts/mac-coordinator-64gb-20260925/mac-coordinator-64gb-20260925--claude-code--use--20260927.json b/evidence/hosts/mac-coordinator-64gb-20260925/mac-coordinator-64gb-20260925--claude-code--use--20260927.json new file mode 100644 index 000000000..02a359406 --- /dev/null +++ b/evidence/hosts/mac-coordinator-64gb-20260925/mac-coordinator-64gb-20260925--claude-code--use--20260927.json @@ -0,0 +1,67 @@ +{ + "schema_version": 1, + "id": "mac-coordinator-64gb-20260925--claude-code--use--20260927", + "kind": "host_acceptance", + "host": { + "host_id": "mac-coordinator-64gb-20260925", + "platform_id": "macos-arm64", + "os": "macos", + "architecture": "arm64", + "second_physical_machine": true, + "hardware_profile_ref": "mac-coordinator-64gb-20260925" + }, + "catalog_revision": "1aa9776591847b4860bf258f8953315ae71d7bc4", + "recorded_by": { + "identity_sha256": "91719ef8aa813c0bf50b26570098baa57e4c043d7d23d4cc5c26ce7c17710954", + "model": "claude-sonnet-5" + }, + "component_id": "claude-code", + "stage": "use", + "commands": [ + { + "cmd": "D=\"$(mktemp -d)\"\nn=$((3 + RANDOM % 6))\n: > \"$D/fixture.txt\"\nfor i in $(seq 1 \"$n\"); do echo $((RANDOM % 900 + 1)) >> \"$D/fixture.txt\"; done\nreal=$(wc -l < \"$D/fixture.txt\" | tr -d ' ')\ncd \"$D\"\nclaude -p --output-format stream-json --verbose \"Count the lines in the file ./fixture.txt in your current working directory using your Read tool, then reply with exactly one line of the form COUNT= and nothing else.\" < /dev/null > out.jsonl 2> err.log\nrc=$?\npython3 - \"$real\" \"$rc\" <<'PY'\nimport json, re, sys\nreal, rc = sys.argv[1], sys.argv[2]\ninit = {}\nfinal = {}\nfor line in open(\"out.jsonl\"):\n line = line.strip()\n if not line:\n continue\n try:\n ev = json.loads(line)\n except ValueError:\n continue\n if ev.get(\"type\") == \"system\" and ev.get(\"subtype\") == \"init\" and not init:\n init = ev\n if ev.get(\"type\") == \"result\":\n final = ev\ncounts = {}\nfor key in (\"agents\", \"skills\", \"plugins\", \"mcp_servers\", \"slash_commands\", \"tools\"):\n v = init.get(key)\n if isinstance(v, list):\n counts[key] = len(v)\nmcp_status = sorted({s.get(\"status\") for s in init.get(\"mcp_servers\", []) if isinstance(s, dict)})\ntext = final.get(\"result\") or \"\"\nm = re.search(r\"COUNT=(\\d+)\", text)\ngot = m.group(1) if m else None\nok = (rc == \"0\") and (not final.get(\"is_error\")) and (got == real)\nprint(\"permissionMode=\" + str(init.get(\"permissionMode\")) + \" model=\" + str(init.get(\"model\")))\nprint(\"counts=\" + json.dumps(counts, sort_keys=True))\nprint(\"mcp_status=\" + json.dumps(mcp_status))\nprint(\"turn_subtype=\" + str(final.get(\"subtype\")) + \" is_error=\" + str(final.get(\"is_error\")))\nprint(\"positive_control expected=\" + real + \" got=\" + str(got) + \" match=\" + str(got == real))\nraise SystemExit(0 if ok else 1)\nPY", + "exit": 0, + "duration_s": 7.66, + "output_sha256": "8ce866b9a7c62f0a67e71589d873cda5e5c8d70dea5e245dac071db09f960e4d", + "output_excerpt": "permissionMode=bypassPermissions model=claude-opus-5-5[1m]\ncounts={\"agents\": 18, \"mcp_servers\": 5, \"plugins\": 11, \"skills\": 67, \"slash_commands\": 107, \"tools\": 118}\nmcp_status=[\"connected\"]\nturn_subtype=success is_error=False\npositive_control expected=4 got=4 match=True\n" + }, + { + "cmd": "D=\"$(mktemp -d)\"\ncd \"$D\"\nclaude mcp list < /dev/null 2>&1 | python3 -c \"\nimport sys\nrows = []\nfor line in sys.stdin:\n line = line.rstrip(chr(10))\n if ' - ' not in line or ': ' not in line:\n continue\n name, _, _ = line.partition(': ')\n _, _, status = line.rpartition(' - ')\n rows.append((name.strip(), status.strip()))\nrows.sort()\nfor name, status in rows:\n print(name + ': ' + status)\nprint('count=' + str(len(rows)))\n\"", + "exit": 0, + "duration_s": 1.372, + "output_sha256": "e3a146db303fe5ed9bbf4a55a1160f0442ae4d520117e5e50e4438befd67ac14", + "output_excerpt": "ai-memory: \u2714 Connected\nopenaiDeveloperDocs: \u2714 Connected\nplugin:context-mode:context-mode: \u2714 Connected\nserena: \u2714 Connected\nsocraticode: \u2714 Connected\ncount=5\n" + } + ], + "tool_versions": { + "claude-code": "2.1.283" + }, + "observed_at_utc": "2026-09-27T07:21:34Z", + "result": "pass", + "claim": "On host mac-coordinator-64gb-20260925 (macOS arm64), the installed Claude Code client (claude-code 2.1.283) performs a real headless turn from a freshly created scratch working directory under this Mac's user-scope client-layer profile (~/.claude): given a fixture file it creates itself with a random line count, `claude -p --output-format stream-json --verbose` reads the file with its own Read tool and replies with the correct count, while the run's init event reports the loaded profile's agent/skill/plugin/MCP-server/slash-command/tool counts and every configured MCP server's connection status. A separate `claude mcp list` from another fresh scratch directory independently reports every configured MCP server's name and health status. Both commands exit 0 only when the reported count matches the independently computed one, the turn reports no error, and (for the first command) the init event was found at all.", + "limitations": [ + "Recorded from a Claude Code session in a git worktree of this repository at commit 1aa97765 (the catalog_revision), not a pinned install checkout; the installed client is 2.1.283, newer than the catalog's claude-code pin 2.1.278, so this receipt is recorded with --allow-unbound-version and does not count toward the winner's status.", + "second_physical_machine is declared, not proven by this file: this host's measured profile (evidence/artifacts/hw-profiles/mac-coordinator-64gb-20260925/profile.json) differs from the catalog's WSL authoring laptop. The receipt carries only the recorder's self review; accepted needs an independent review from a separate session.", + "Counts and connection statuses only: no MCP server command line, argument, environment value, session id, uuid or working-directory path is copied into this receipt; both --cmd values print only names, counts and statuses by construction, and the underlying stream-json/mcp list output (which does carry those fields) is never itself echoed to stdout.", + "This receipt exercises the native-clients role (one headless turn plus an MCP listing); it does not exercise claude-code's owned-writing-child role in the workers layer, which needs a different command shape." + ], + "evidence_class": "native_proven", + "reviews": [ + { + "kind": "self", + "ref": "scripts/host_receipts.py record", + "verdict": "agree", + "at_utc": "2026-09-27T07:21:34Z", + "reviewer": { + "identity_sha256": "91719ef8aa813c0bf50b26570098baa57e4c043d7d23d4cc5c26ce7c17710954", + "model": "claude-sonnet-5" + } + } + ], + "layer_refs": [ + { + "catalog": "foundation", + "layer_id": "native-clients" + } + ] +} diff --git a/evidence/hosts/mac-coordinator-64gb-20260925/mac-coordinator-64gb-20260925--codex--use--20260927-2.json b/evidence/hosts/mac-coordinator-64gb-20260925/mac-coordinator-64gb-20260925--codex--use--20260927-2.json new file mode 100644 index 000000000..f698fdbe9 --- /dev/null +++ b/evidence/hosts/mac-coordinator-64gb-20260925/mac-coordinator-64gb-20260925--codex--use--20260927-2.json @@ -0,0 +1,84 @@ +{ + "schema_version": 1, + "id": "mac-coordinator-64gb-20260925--codex--use--20260927-2", + "kind": "host_acceptance", + "host": { + "host_id": "mac-coordinator-64gb-20260925", + "platform_id": "macos-arm64", + "os": "macos", + "architecture": "arm64", + "second_physical_machine": true, + "hardware_profile_ref": "mac-coordinator-64gb-20260925" + }, + "catalog_revision": "1aa9776591847b4860bf258f8953315ae71d7bc4", + "recorded_by": { + "identity_sha256": "91719ef8aa813c0bf50b26570098baa57e4c043d7d23d4cc5c26ce7c17710954", + "model": "claude-sonnet-5" + }, + "component_id": "codex", + "stage": "use", + "commands": [ + { + "cmd": "p=$(command -v codex)\necho \"resolved: $p\"\necho \"readlink: $(readlink -f \"$p\" 2>/dev/null || echo \"$p (not a symlink)\")\"\ncodex --version\necho \"file_type: $(file \"$p\" | sed 's/^[^:]*: //')\"\necho \"chatgpt_app_reference_count: $(grep -c \"ChatGPT.app\" \"$p\" 2>/dev/null || echo 0)\"", + "exit": 0, + "duration_s": 0.042, + "output_sha256": "ea61e2c71fcd24712fa4400cd5a5e14e9ad305e8d15bb6278a613db22b348bc9", + "output_excerpt": "resolved: ~/.local/bin/codex\nreadlink: ~/.local/bin/codex\ncodex-cli 0.158.0-alpha.2.1\nfile_type: POSIX shell script text executable, ASCII text\nchatgpt_app_reference_count: 1\n" + }, + { + "cmd": "D=\"$(mktemp -d)\"\nn=$((3 + RANDOM % 6))\n: > \"$D/fixture.txt\"\nfor i in $(seq 1 \"$n\"); do echo $((RANDOM % 900 + 1)) >> \"$D/fixture.txt\"; done\nreal=$(wc -l < \"$D/fixture.txt\" | tr -d ' ')\n\"$HOME/.local/bin/codex\" exec -C \"$D\" --skip-git-repo-check --sandbox read-only --ephemeral --json \"Count the lines in the file fixture.txt in your working directory using your own tools, then reply with exactly one line of the form COUNT= and nothing else.\" < /dev/null > \"$D/out.jsonl\" 2> \"$D/err.log\"\nrc=$?\npython3 - \"$real\" \"$rc\" \"$D/out.jsonl\" <<'PY'\nimport json, re, sys\nreal, rc, path = sys.argv[1], sys.argv[2], sys.argv[3]\nevents = []\nfor line in open(path):\n line = line.strip()\n if not line:\n continue\n try:\n events.append(json.loads(line))\n except ValueError:\n continue\nkinds = {}\nfor ev in events:\n t = ev.get(\"type\")\n kinds[t] = kinds.get(t, 0) + 1\nran_command = False\ngot = None\nfor ev in events:\n item = ev.get(\"item\") or {}\n if ev.get(\"type\") == \"item.completed\" and item.get(\"type\") == \"command_execution\" and item.get(\"exit_code\") == 0:\n ran_command = True\n if ev.get(\"type\") == \"item.completed\" and item.get(\"type\") == \"agent_message\":\n m = re.search(r\"COUNT=(\\d+)\", item.get(\"text\") or \"\")\n if m:\n got = m.group(1)\nok = (rc == \"0\") and ran_command and (got == real)\nprint(\"event_kinds=\" + json.dumps(kinds, sort_keys=True))\nprint(\"command_execution_seen=\" + str(ran_command))\nprint(\"positive_control expected=\" + real + \" got=\" + str(got) + \" match=\" + str(got == real))\nraise SystemExit(0 if ok else 1)\nPY", + "exit": 0, + "duration_s": 18.526, + "output_sha256": "3ca485b2e27f455223710636816a32c6e76c89a7faf4f030ca0ab933d71e9af8", + "output_excerpt": "event_kinds={\"item.completed\": 3, \"item.started\": 1, \"thread.started\": 1, \"turn.completed\": 1, \"turn.started\": 1}\ncommand_execution_seen=True\npositive_control expected=3 got=3 match=True\n" + }, + { + "cmd": "\"$HOME/.local/bin/codex\" mcp list --json < /dev/null 2>&1 | python3 -c \"\nimport json, os, sys, tomllib\nraw = sys.stdin.read()\ntry:\n data = json.loads(raw)\nexcept ValueError:\n print('PARSE_ERROR: ' + raw[:120])\n raise SystemExit(1)\nrows = []\nfor item in data:\n transport = item.get('transport') or {}\n rows.append((item.get('name'), item.get('enabled'), transport.get('type')))\nrows.sort(key=lambda r: str(r[0]))\nfor name, enabled, ttype in rows:\n print(str(name) + ' | enabled=' + str(enabled) + ' | transport=' + str(ttype))\ncfg = tomllib.load(open(os.path.expanduser('~/.codex/config.toml'), 'rb'))\ndeclared = set((cfg.get('mcp_servers') or {}).keys())\nlive = {r[0] for r in rows}\nmissing = sorted(declared - live)\nprint('declared_count=' + str(len(declared)) + ' live_count=' + str(len(rows)) + ' declared_missing_from_live=' + str(missing))\nraise SystemExit(0 if not missing else 1)\n\"", + "exit": 0, + "duration_s": 0.448, + "output_sha256": "69c559f75dd56cc707c91ddf519f03d1e35fa65e6ec29cf6466fd3cc34acfce3", + "output_excerpt": "ai-memory | enabled=True | transport=streamable_http\ncodex_app | enabled=False | transport=stdio\ncontext-mode | enabled=True | transport=stdio\ncua_repl | enabled=True | transport=stdio\nheadroom | enabled=True | transport=stdio\nnode_repl | enabled=True | transport=stdio\nopenaiDeveloperDocs | enabled=True | transport=streamable_http\nqmd | enabled=True | transport=stdio\nserena | enabled=True | transp" + }, + { + "cmd": "\"$HOME/.local/bin/codex\" features list < /dev/null 2>&1 | python3 -c \"\nimport os, sys, tomllib\nlines = [l.rstrip(chr(10)) for l in sys.stdin if l.strip()]\ntotal = len(lines)\nseen = {}\nfor l in lines:\n parts = l.split()\n if len(parts) >= 2 and parts[0] in ('daemon_auto_start', 'hooks'):\n seen[parts[0]] = parts[-1].lower() == 'true'\ncfg = tomllib.load(open(os.path.expanduser('~/.codex/config.toml'), 'rb'))\ndeclared = cfg.get('features') or {}\nok = True\nfor name in ('daemon_auto_start', 'hooks'):\n want = bool(declared[name]) if name in declared else None\n got = seen.get(name)\n match = (want is None) or (got == want)\n ok = ok and (got is not None) and match\n print(name + ': cli=' + str(got) + ' config_declares=' + str(want) + ' match=' + str(match))\nprint('total_features=' + str(total))\nraise SystemExit(0 if ok else 1)\n\"", + "exit": 0, + "duration_s": 0.051, + "output_sha256": "156b7cfc9d55193f581107147102f5435dc4d671b3e707973176a32455d9d237", + "output_excerpt": "daemon_auto_start: cli=False config_declares=False match=True\nhooks: cli=True config_declares=True match=True\ntotal_features=150\n" + } + ], + "tool_versions": { + "codex": "0.158.0-alpha.2.1" + }, + "observed_at_utc": "2026-09-27T07:29:00Z", + "result": "pass", + "claim": "On host mac-coordinator-64gb-20260925 (macOS arm64), the installed Codex client, resolved and versioned by the first command below (which also discloses its distribution channel), performs a real `codex exec --skip-git-repo-check --sandbox read-only --ephemeral` turn from a freshly created scratch working directory under this Mac's ~/.codex user-scope profile (approval_policy never, sandbox_mode danger-full-access, its configured MCP servers and hooks feature all loaded from config.toml): given a fixture file it creates itself with a random line count, the run's `--json` event stream contains a real `command_execution` item (the model's own `wc -l < fixture.txt`) that exited 0, and its final agent message reports the correct count. `codex mcp list --json` and `codex features list` from the same install are each cross-checked against this host's own ~/.codex/config.toml: every MCP server config.toml declares appears in the live listing, and the live `daemon_auto_start`/`hooks` feature booleans match what config.toml declares. All commands exit 0 only when their respective check passes.", + "limitations": [ + "Recorded from a Claude Code session in a git worktree of this repository at commit 1aa97765 (the catalog_revision), not a pinned install checkout; the first command's --version reports 0.158.0-alpha.2.1, newer than the catalog's codex pin 0.155.1, so this receipt is recorded with --allow-unbound-version and does not count toward the winner's status.", + "The resolved codex on this host is a shell-script launcher at ~/.local/bin/codex whose own comment says it runs \"the ChatGPT-bundled Codex through the app's declared entrypoint\"; the first command's file_type and chatgpt_app_reference_count lines show this without printing the launcher's contents. The tested binary is therefore the ChatGPT desktop app's bundled Codex CLI build, not a separately downloaded openai/codex release of the winner's pin.", + "second_physical_machine is declared, not proven by this file: this host's measured profile (evidence/artifacts/hw-profiles/mac-coordinator-64gb-20260925/profile.json) differs from the catalog's WSL authoring laptop. The receipt carries only the recorder's self review; accepted needs an independent review from a separate session.", + "Names, booleans and counts only: no MCP server command, args, env, url or cwd, and no session id or working-directory path, is copied into this receipt; the mcp/features listings are filtered inline in their own commands before anything reaches stdout.", + "This receipt exercises the native-clients role (a version/channel check, one bounded exec turn and two read-only listing/feature checks); it does not exercise codex's structured-session-control role in the agent-sdks layer (the streamed events above are read for one command_execution item and one final message, not resumed, forked or driven through the SDK).", + "codex exec must be run with stdin redirected from /dev/null: with an interactive/inherited stdin attached it blocks indefinitely on \"Reading additional input from stdin...\" before doing any work, on this host and this codex-cli build; each exec command above already does this." + ], + "evidence_class": "native_proven", + "reviews": [ + { + "kind": "self", + "ref": "scripts/host_receipts.py record", + "verdict": "agree", + "at_utc": "2026-09-27T07:29:00Z", + "reviewer": { + "identity_sha256": "91719ef8aa813c0bf50b26570098baa57e4c043d7d23d4cc5c26ce7c17710954", + "model": "claude-sonnet-5" + } + } + ], + "layer_refs": [ + { + "catalog": "foundation", + "layer_id": "native-clients" + } + ], + "supersedes": "mac-coordinator-64gb-20260925--codex--use--20260927" +} diff --git a/evidence/hosts/mac-coordinator-64gb-20260925/mac-coordinator-64gb-20260925--codex--use--20260927.json b/evidence/hosts/mac-coordinator-64gb-20260925/mac-coordinator-64gb-20260925--codex--use--20260927.json new file mode 100644 index 000000000..bd321a7ec --- /dev/null +++ b/evidence/hosts/mac-coordinator-64gb-20260925/mac-coordinator-64gb-20260925--codex--use--20260927.json @@ -0,0 +1,75 @@ +{ + "schema_version": 1, + "id": "mac-coordinator-64gb-20260925--codex--use--20260927", + "kind": "host_acceptance", + "host": { + "host_id": "mac-coordinator-64gb-20260925", + "platform_id": "macos-arm64", + "os": "macos", + "architecture": "arm64", + "second_physical_machine": true, + "hardware_profile_ref": "mac-coordinator-64gb-20260925" + }, + "catalog_revision": "1aa9776591847b4860bf258f8953315ae71d7bc4", + "recorded_by": { + "identity_sha256": "91719ef8aa813c0bf50b26570098baa57e4c043d7d23d4cc5c26ce7c17710954", + "model": "claude-sonnet-5" + }, + "component_id": "codex", + "stage": "use", + "commands": [ + { + "cmd": "D=\"$(mktemp -d)\"\nn=$((3 + RANDOM % 6))\n: > \"$D/fixture.txt\"\nfor i in $(seq 1 \"$n\"); do echo $((RANDOM % 900 + 1)) >> \"$D/fixture.txt\"; done\nreal=$(wc -l < \"$D/fixture.txt\" | tr -d ' ')\n\"$HOME/.local/bin/codex\" exec -C \"$D\" --skip-git-repo-check --sandbox read-only --ephemeral --json \"Count the lines in the file fixture.txt in your working directory using your own tools, then reply with exactly one line of the form COUNT= and nothing else.\" < /dev/null > \"$D/out.jsonl\" 2> \"$D/err.log\"\nrc=$?\npython3 - \"$real\" \"$rc\" \"$D/out.jsonl\" <<'PY'\nimport json, re, sys\nreal, rc, path = sys.argv[1], sys.argv[2], sys.argv[3]\nevents = []\nfor line in open(path):\n line = line.strip()\n if not line:\n continue\n try:\n events.append(json.loads(line))\n except ValueError:\n continue\nkinds = {}\nfor ev in events:\n t = ev.get(\"type\")\n kinds[t] = kinds.get(t, 0) + 1\nran_command = False\ngot = None\nfor ev in events:\n item = ev.get(\"item\") or {}\n if ev.get(\"type\") == \"item.completed\" and item.get(\"type\") == \"command_execution\" and item.get(\"exit_code\") == 0:\n ran_command = True\n if ev.get(\"type\") == \"item.completed\" and item.get(\"type\") == \"agent_message\":\n m = re.search(r\"COUNT=(\\d+)\", item.get(\"text\") or \"\")\n if m:\n got = m.group(1)\nok = (rc == \"0\") and ran_command and (got == real)\nprint(\"event_kinds=\" + json.dumps(kinds, sort_keys=True))\nprint(\"command_execution_seen=\" + str(ran_command))\nprint(\"positive_control expected=\" + real + \" got=\" + str(got) + \" match=\" + str(got == real))\nraise SystemExit(0 if ok else 1)\nPY", + "exit": 0, + "duration_s": 9.126, + "output_sha256": "7116a800b5182c0768f3ca6f03162ef9e1eebc1ff57cd82668ee0b107c171fc1", + "output_excerpt": "event_kinds={\"item.completed\": 3, \"item.started\": 1, \"thread.started\": 1, \"turn.completed\": 1, \"turn.started\": 1}\ncommand_execution_seen=True\npositive_control expected=7 got=7 match=True\n" + }, + { + "cmd": "\"$HOME/.local/bin/codex\" mcp list --json < /dev/null 2>&1 | python3 -c \"\nimport json, os, sys, tomllib\nraw = sys.stdin.read()\ntry:\n data = json.loads(raw)\nexcept ValueError:\n print('PARSE_ERROR: ' + raw[:120])\n raise SystemExit(1)\nrows = []\nfor item in data:\n transport = item.get('transport') or {}\n rows.append((item.get('name'), item.get('enabled'), transport.get('type')))\nrows.sort(key=lambda r: str(r[0]))\nfor name, enabled, ttype in rows:\n print(str(name) + ' | enabled=' + str(enabled) + ' | transport=' + str(ttype))\ncfg = tomllib.load(open(os.path.expanduser('~/.codex/config.toml'), 'rb'))\ndeclared = set((cfg.get('mcp_servers') or {}).keys())\nlive = {r[0] for r in rows}\nmissing = sorted(declared - live)\nprint('declared_count=' + str(len(declared)) + ' live_count=' + str(len(rows)) + ' declared_missing_from_live=' + str(missing))\nraise SystemExit(0 if not missing else 1)\n\"", + "exit": 0, + "duration_s": 0.439, + "output_sha256": "69c559f75dd56cc707c91ddf519f03d1e35fa65e6ec29cf6466fd3cc34acfce3", + "output_excerpt": "ai-memory | enabled=True | transport=streamable_http\ncodex_app | enabled=False | transport=stdio\ncontext-mode | enabled=True | transport=stdio\ncua_repl | enabled=True | transport=stdio\nheadroom | enabled=True | transport=stdio\nnode_repl | enabled=True | transport=stdio\nopenaiDeveloperDocs | enabled=True | transport=streamable_http\nqmd | enabled=True | transport=stdio\nserena | enabled=True | transp" + }, + { + "cmd": "\"$HOME/.local/bin/codex\" features list < /dev/null 2>&1 | python3 -c \"\nimport os, sys, tomllib\nlines = [l.rstrip(chr(10)) for l in sys.stdin if l.strip()]\ntotal = len(lines)\nseen = {}\nfor l in lines:\n parts = l.split()\n if len(parts) >= 2 and parts[0] in ('daemon_auto_start', 'hooks'):\n seen[parts[0]] = parts[-1].lower() == 'true'\ncfg = tomllib.load(open(os.path.expanduser('~/.codex/config.toml'), 'rb'))\ndeclared = cfg.get('features') or {}\nok = True\nfor name in ('daemon_auto_start', 'hooks'):\n want = bool(declared[name]) if name in declared else None\n got = seen.get(name)\n match = (want is None) or (got == want)\n ok = ok and (got is not None) and match\n print(name + ': cli=' + str(got) + ' config_declares=' + str(want) + ' match=' + str(match))\nprint('total_features=' + str(total))\nraise SystemExit(0 if ok else 1)\n\"", + "exit": 0, + "duration_s": 0.052, + "output_sha256": "156b7cfc9d55193f581107147102f5435dc4d671b3e707973176a32455d9d237", + "output_excerpt": "daemon_auto_start: cli=False config_declares=False match=True\nhooks: cli=True config_declares=True match=True\ntotal_features=150\n" + } + ], + "tool_versions": { + "codex": "0.158.0-alpha.2.1" + }, + "observed_at_utc": "2026-09-27T07:21:43Z", + "result": "pass", + "claim": "On host mac-coordinator-64gb-20260925 (macOS arm64), the installed Codex client (codex-cli 0.158.0-alpha.2.1) performs a real `codex exec --skip-git-repo-check --sandbox read-only --ephemeral` turn from a freshly created scratch working directory under this Mac's ~/.codex user-scope profile (approval_policy never, sandbox_mode danger-full-access, its configured MCP servers and hooks feature all loaded from config.toml): given a fixture file it creates itself with a random line count, the run's `--json` event stream contains a real `command_execution` item (the model's own `wc -l < fixture.txt`) that exited 0, and its final agent message reports the correct count. `codex mcp list --json` and `codex features list` from the same install are each cross-checked in the same command against this host's own ~/.codex/config.toml: every MCP server config.toml declares appears in the live listing, and the live `daemon_auto_start`/`hooks` feature booleans match what config.toml declares. All three commands exit 0 only when their respective check passes.", + "limitations": [ + "Recorded from a Claude Code session in a git worktree of this repository at commit 1aa97765 (the catalog_revision), not a pinned install checkout; the installed client is 0.158.0-alpha.2.1, newer than the catalog's codex pin 0.155.1, so this receipt is recorded with --allow-unbound-version and does not count toward the winner's status.", + "second_physical_machine is declared, not proven by this file: this host's measured profile (evidence/artifacts/hw-profiles/mac-coordinator-64gb-20260925/profile.json) differs from the catalog's WSL authoring laptop. The receipt carries only the recorder's self review; accepted needs an independent review from a separate session.", + "Names, booleans and counts only: no MCP server command, args, env, url or cwd, and no session id or working-directory path, is copied into this receipt; the --json/--json mcp listing are filtered inline in the command itself before anything reaches stdout.", + "This receipt exercises the native-clients role (one bounded exec turn plus two read-only listing/feature checks); it does not exercise codex's structured-session-control role in the agent-sdks layer (streamed events here are read for one command_execution item and one final message, not resumed, forked or driven through the SDK).", + "codex exec must be run with stdin redirected from /dev/null: with an interactive/inherited stdin attached it blocks indefinitely on \"Reading additional input from stdin...\" before doing any work, on this host and this codex-cli build; every command below already does this." + ], + "evidence_class": "native_proven", + "reviews": [ + { + "kind": "self", + "ref": "scripts/host_receipts.py record", + "verdict": "agree", + "at_utc": "2026-09-27T07:21:43Z", + "reviewer": { + "identity_sha256": "91719ef8aa813c0bf50b26570098baa57e4c043d7d23d4cc5c26ce7c17710954", + "model": "claude-sonnet-5" + } + } + ], + "layer_refs": [ + { + "catalog": "foundation", + "layer_id": "native-clients" + } + ] +} diff --git a/manifests/evidence.json b/manifests/evidence.json index 3bbbe7c44..22db324e7 100644 --- a/manifests/evidence.json +++ b/manifests/evidence.json @@ -13038,8 +13038,8 @@ }, { "path": "catalogs/landscape/component-evidence-matrix.json", - "sha256": "675416e13d771bb65e154dfad33d8b5d10d708c418c517e3b84618f651a02471", - "bytes": 189662 + "sha256": "729bd9bb7a4f29332de9ad6aba03e472d21b4cb348d23ebb8a16142d35d096d9", + "bytes": 189734 }, { "path": "catalogs/landscape/foundation.json", @@ -13553,7 +13553,7 @@ }, { "path": "docs/component-evidence-matrix.md", - "sha256": "819ab53a4d29d4b881ec15674b5ecfa7f716b1e8bce3a27d83140956cfe36bb9", + "sha256": "cf1867b290f67573580d0c8dbea4a599a9d31214dfa266a47522e266d3d1eafe", "bytes": 19505 }, { @@ -36016,6 +36016,26 @@ "sha256": "491a43789016027cd144f38a0bc9fc30f6d305a32025a9dc8972e542f96fd8c4", "bytes": 7687 }, + { + "path": "evidence/hosts/mac-coordinator-64gb-20260925/mac-coordinator-64gb-20260925--claude-code--use--20260927-2.json", + "sha256": "8a612acf5d43d131af2871227b29f7d44f07aa9c98fe0a34f3e1832dc83cfd1e", + "bytes": 7174 + }, + { + "path": "evidence/hosts/mac-coordinator-64gb-20260925/mac-coordinator-64gb-20260925--claude-code--use--20260927.json", + "sha256": "45eb8886eba9eea56fad70d181c299061b0d314c27a21acaa92ee27f73d5d713", + "bytes": 6649 + }, + { + "path": "evidence/hosts/mac-coordinator-64gb-20260925/mac-coordinator-64gb-20260925--codex--use--20260927-2.json", + "sha256": "9fd2c2dfe47a5422755dd94526eda66347f1550cd069d1d13d4848de1cc55336", + "bytes": 10009 + }, + { + "path": "evidence/hosts/mac-coordinator-64gb-20260925/mac-coordinator-64gb-20260925--codex--use--20260927.json", + "sha256": "49cfbdfc06c5626d3e3244cce2efbad58d37cddc059bcb1ea793f195b7350dd5", + "bytes": 8718 + }, { "path": "evidence/hosts/mac-coordinator-64gb-20260925/mac-coordinator-64gb-20260925--qdrant--use--20260925.json", "sha256": "500f736cb5e4ea23935fc1e8e9ad7ddb38479129dd59474123962e1aa6e2b98a", From 0f45c0cb16db800e1d6c910a16f1b82167ae2ed5 Mon Sep 17 00:00:00 2001 From: seathatflowsinourveins <234074349+seathatflowsinourveins@users.noreply.github.com> Date: Sun, 27 Sep 2026 03:32:56 -0400 Subject: [PATCH 02/12] Merge origin/main; add Stage 1 client-layer evidence README (#382) Merges origin/main (no conflicts) and re-registers the derived matrix/grand- list files. Adds evidence/artifacts/mac-stage1-client-layer-20260927/README.md: the coordinator's Stage 1 client-layer install on mac-coordinator-64gb-20260925 (backup summary and rollback, launchctl before/after plus a fresh live re-check, the headless read-back names/counts, plugin revision check, skills status, token-efficiency/client-wiring coverage, the Codex profile, and the macOS template findings), each line marked as coordinator-reported or independently re-checked in this session. Notes two additional findings this session found while recording the codex receipt: the installed codex-cli routes through the ChatGPT desktop app's bundled build, and codex exec needs stdin redirected from /dev/null or it blocks indefinitely. Co-Authored-By: Claude Sonnet 5 --- .../landscape/component-evidence-matrix.json | 16 +- docs/component-evidence-matrix.md | 6 +- .../README.md | 198 ++++++++++++++++++ manifests/evidence.json | 9 +- 4 files changed, 216 insertions(+), 13 deletions(-) create mode 100644 evidence/artifacts/mac-stage1-client-layer-20260927/README.md diff --git a/catalogs/landscape/component-evidence-matrix.json b/catalogs/landscape/component-evidence-matrix.json index 3eae44f21..64ee578c1 100644 --- a/catalogs/landscape/component-evidence-matrix.json +++ b/catalogs/landscape/component-evidence-matrix.json @@ -83,8 +83,8 @@ "fail": 0, "independently_reviewed_fail": 0, "independently_reviewed_pass": 0, - "latest": "2026-09-27T07:21:43Z", - "pass": 1 + "latest": "2026-09-27T07:29:00Z", + "pass": 2 }, "qualified_models": [] } @@ -1626,8 +1626,8 @@ "fail": 0, "independently_reviewed_fail": 0, "independently_reviewed_pass": 0, - "latest": "2026-09-27T07:21:34Z", - "pass": 1 + "latest": "2026-09-27T07:28:48Z", + "pass": 2 }, "qualified_models": [] } @@ -1676,8 +1676,8 @@ "fail": 0, "independently_reviewed_fail": 0, "independently_reviewed_pass": 0, - "latest": "2026-09-27T07:21:43Z", - "pass": 1 + "latest": "2026-09-27T07:29:00Z", + "pass": 2 }, "qualified_models": [] } @@ -3219,8 +3219,8 @@ "fail": 0, "independently_reviewed_fail": 0, "independently_reviewed_pass": 0, - "latest": "2026-09-27T07:21:34Z", - "pass": 1 + "latest": "2026-09-27T07:28:48Z", + "pass": 2 }, "qualified_models": [] } diff --git a/docs/component-evidence-matrix.md b/docs/component-evidence-matrix.md index aeb6725d3..e2ab46a85 100644 --- a/docs/component-evidence-matrix.md +++ b/docs/component-evidence-matrix.md @@ -20,7 +20,7 @@ Each winner shows, for linux-wsl2-x86_64 / macos-arm64, its `e2e_state` and host | Layer | Independent review | Winners: e2e_state [receipts] (linux-wsl2-x86_64 / macos-arm64) | | --- | --- | --- | -| `foundation/agent-sdks` | dual_lane_same_winner | codex (host_verified [8/0/5/0] dissented 3 / untested [1/0/0/0]) | +| `foundation/agent-sdks` | dual_lane_same_winner | codex (host_verified [8/0/5/0] dissented 3 / untested [2/0/0/0]) | | `foundation/ci-supply-chain` | dual_lane_same_winner | zizmor (host_verified [2/0/2/0] / untested [0/0/0/0]); syft (host_verified [2/0/2/0] / untested [0/0/0/0]); candidate:actions-attest (accepted [0/0/0/0] / untested [0/0/0/0]) | | `foundation/code-navigation` | dual_lane_adjudicated (adjudication: `evidence/artifacts/layer-verdicts-20260922/adjudication/foundation-code-navigation-20260922.json`) | serena (host_verified [3/0/2/0] dissented 1 / untested [0/0/0/0]) | | `foundation/document-retrieval` | dual_lane_adjudicated (adjudication: `evidence/artifacts/layer-verdicts-20260922/adjudication/foundation-document-retrieval-20260922.json`) | qmd (host_verified [2/0/2/0] / untested [1/0/0/0]); markitdown (host_verified [2/0/2/0] / untested [0/0/0/0]); poppler (host_verified [4/0/3/0] dissented 1 / untested [0/0/0/0]) | @@ -30,7 +30,7 @@ Each winner shows, for linux-wsl2-x86_64 / macos-arm64, its `e2e_state` and host | `foundation/instructions-skills` | dual_lane_adjudicated (adjudication: `evidence/artifacts/layer-verdicts-20260922/adjudication/foundation-instructions-skills-20260922.json`) | affaan-m/ECC (conditional [2/0/1/0] dissented 1 / untested [0/0/0/0]); candidate:typesafe-ai-skills (conditional [0/0/0/0] / untested [0/0/0/0]); candidate:openai-skills (conditional [0/0/0/0] / untested [0/0/0/0]) | | `foundation/isolation` | dual_lane_same_winner | worktrunk (host_verified [2/0/2/0] / host_verified [1/0/1/0]); sandbox-runtime (host_verified [1/0/1/0] / untested [0/0/0/0]) | | `foundation/mcp-surfaces` | dual_lane_same_winner | mcporter (host_verified [6/0/2/0] dissented 4 / untested [0/0/0/0]); mcp-inspector (host_verified [2/0/1/0] dissented 1 / untested [0/0/0/0]) | -| `foundation/native-clients` | dual_lane_same_winner | claude-code (accepted [1/0/1/0] / untested [1/0/0/0]); codex (host_verified [8/0/5/0] dissented 3 / untested [1/0/0/0]) | +| `foundation/native-clients` | dual_lane_same_winner | claude-code (accepted [1/0/1/0] / untested [2/0/0/0]); codex (host_verified [8/0/5/0] dissented 3 / untested [2/0/0/0]) | | `foundation/observation-inference` | dual_lane_adjudicated (adjudication: `evidence/artifacts/layer-verdicts-20260922/adjudication/foundation-observation-inference-20260922.json`) | opentelemetry-collector-contrib (host_verified [2/0/2/0] / untested [0/0/0/0]); prometheus (host_verified [2/0/2/0] / untested [0/0/0/0]); loki (host_verified [2/0/2/0] / untested [0/0/0/0]) | | `foundation/quality-evaluation` | dual_lane_same_winner | promptfoo (host_verified [6/0/2/0] dissented 4 / untested [0/0/0/0]); playwright-test (conditional [0/0/0/0] / untested [1/0/0/0] dissented 1) | | `foundation/recovery-portability` | dual_lane_same_winner | restic (host_verified [3/0/3/0] / untested [1/0/0/0]); candidate:astral-sh-uv (conditional [0/0/0/0] / untested [0/0/0/0]) | @@ -39,7 +39,7 @@ Each winner shows, for linux-wsl2-x86_64 / macos-arm64, its `e2e_state` and host | `foundation/semantic-rag` | dual_lane_same_winner | socraticode (host_verified [5/0/2/0] dissented 3 / untested [1/0/0/0]); qdrant (host_verified [3/0/3/0] / untested [1/0/0/0]); vllm (host_verified [6/0/3/0] dissented 2 / untested [0/0/0/0]) | | `foundation/token-efficiency` | dual_lane_adjudicated (adjudication: `evidence/artifacts/layer-verdicts-20260922/adjudication/foundation-token-efficiency-20260922.json`) | rtk (host_verified [7/0/4/0] dissented 2 / host_verified [1/0/1/0]); headroom (host_verified [4/0/3/0] dissented 1 / untested [0/0/0/0]); ccusage (host_verified [2/0/2/0] / untested [0/0/0/0]) | | `foundation/web-research` | dual_lane_adjudicated (adjudication: `evidence/artifacts/layer-verdicts-20260922/adjudication/foundation-web-research-20260922.json`) | tavily-cli (conditional [0/0/0/0] / untested [0/0/0/0]); agent-browser (conditional [0/0/0/0] / untested [0/0/0/0]); openresearch (conditional [0/0/0/0] / untested [0/0/0/0]) | -| `foundation/workers` | dual_lane_adjudicated (adjudication: `evidence/artifacts/layer-verdicts-20260922/adjudication/foundation-workers-20260922.json`) | claude-code (conditional [1/0/1/0] / untested [1/0/0/0]); worktrunk (host_verified [2/0/2/0] / host_verified [1/0/1/0]) | +| `foundation/workers` | dual_lane_adjudicated (adjudication: `evidence/artifacts/layer-verdicts-20260922/adjudication/foundation-workers-20260922.json`) | claude-code (conditional [1/0/1/0] / untested [2/0/0/0]); worktrunk (host_verified [2/0/2/0] / host_verified [1/0/1/0]) | | `us-equities/agents-models-workers` | dual_lane_same_winner | codex-native-sdk (accepted [0/0/0/0] / untested [0/0/0/0]); foundation-ai-memory (accepted [0/0/0/0] / untested [0/0/0/0]); foundation-socraticode (accepted [0/0/0/0] / untested [0/0/0/0]) | | `us-equities/backtesting-engine` | dual_lane_same_winner | nautilustrader (host_verified [1/0/1/0] / untested [0/0/0/0] +1 alias receipt(s), not counted); lean (host_verified [2/0/1/0] dissented 1 / untested [0/0/0/0]) | | `us-equities/data-quality-orchestration` | dual_lane_adjudicated (adjudication: `evidence/artifacts/layer-verdicts-20260922/adjudication/us-equities-data-quality-orchestration-20260922.json`) | dagu (host_verified [2/0/2/0] / untested [0/0/0/0]); data-pandera (host_verified [3/0/1/0] dissented 2 / untested [0/0/0/0]) | diff --git a/evidence/artifacts/mac-stage1-client-layer-20260927/README.md b/evidence/artifacts/mac-stage1-client-layer-20260927/README.md new file mode 100644 index 000000000..3f54fdb55 --- /dev/null +++ b/evidence/artifacts/mac-stage1-client-layer-20260927/README.md @@ -0,0 +1,198 @@ +# Stage 1 client layer on mac-coordinator-64gb-20260925 (2026-09-27) + +Host request [#382](https://github.com/seathatflowsinourveins/native-agent-stack/issues/382): +native-agent-stack becomes this Mac's client-layer writer (Stage 1 of the +[2026-09-27 staged decision](../../../docs/decisions/2026-09-27-mac-single-writer-staged.md)), +with no running service touched. The coordinator session applied the client layer on this +Mac; this document and the [host receipts](#host-receipts) below are the evidence PR for +that work. Facts below are sanitized to names, counts and booleans; where a line was +independently re-run in this evidence-PR session rather than only read from the +coordinator's retained output, it says so. + +## Backup and rollback + +Before any write, the coordinator copied `~/.claude` and `~/.codex` (settings, hooks, +plugins, skills, agents) to a private, dated, `0700` folder outside every worktree: 4,516 +files, manifest sha256 `a7478603be747dfd52a18dd05f4f0d80510af5bd736c7af4581c0e7cd6b2c5c4`. +`auth.json`, transcripts, sessions, history and caches were excluded. The backup folder's +path is not recorded here (personal path). + +**Rollback, one line:** copy the dated backup's `claude/`, `claude.json` and `codex/` back +over `~/.claude`, `~/.claude.json` and `~/.codex` (`apply_claude_settings.py` also left its +own timestamped `settings.json` backup alongside the live one). + +## Service continuity + +`launchctl list | grep -E 'agent-ecosystem|native-stack'` before and after the Stage 1 +work showed the same four labels, unchanged: + +| Label | Before | After | This session, live | +| --- | --- | --- | --- | +| `local.agent-ecosystem.ai-memory` | PID present, last exit 0 | PID present, last exit 0 | same PID, last exit 0 | +| `local.agent-ecosystem.maintenance` | not running, last exit 1 | not running, last exit 1 | not running, last exit 1 | +| `local.agent-ecosystem.ollama` | PID present, last exit 0 | PID present, last exit 0 | same PID, last exit 0 | +| `local.agent-ecosystem.qdrant` | PID present, last exit 0 | PID present, last exit 0 | same PID, last exit 0 | + +No `local.agent-ecosystem.*` service or Ollama was stopped, replaced or duplicated. This +session independently re-ran `launchctl list | grep -E 'agent-ecosystem|native-stack'` +while preparing this PR (over an hour after the coordinator's "after" capture): all three +running PIDs were still the exact same PIDs as both the "before" and "after" captures, and +`maintenance` was still not running with the same last exit code, which is stronger +continuity evidence than a single before/after pair. + +## Headless read-back (names and counts only) + +A headless `claude -p --output-format stream-json --verbose` turn from a scratch working +directory, parsed for its `init` event: + +- `permissionMode`: `bypassPermissions`; `model`: `claude-opus-5-5[1m]` +- agents: 18; skills: 67; plugins: 11; MCP servers: 5 (all `connected`); slash commands: 107; tools: 118 + +This session's own [claude-code host receipt](#host-receipts) independently reproduced the +same shape (18/67/11/5-connected/107/118) from a fresh scratch turn, so the counts are +reproducible, not a one-off capture. + +## Plugin revision check + +Compares each installed plugin's `installed_plugins.json` `gitCommitSha` against the +revision `recipes/README.md` names as reviewed, allowing "ahead of the reviewed revision +in `stats.json` only" (confirmed by diffing the two revisions through the GitHub compare +API) since that file is a self-reported counter, not plugin logic: + +| Plugin | Reviewed revision | Coordinator's observation | This session's fresh re-run | +| --- | --- | --- | --- | +| `context-mode@context-mode` | `6f0cc684` | ahead, `stats.json` only | still ahead, `stats.json` only (at a newer commit again — the plugin keeps self-updating that one file) | +| `claude-hud@claude-hud` | `ef5f1c8b` | exact match | exact match | +| `codex@openai-codex` | `db52e28f` | exact match | exact match | + +## Skills + +`DISABLE_TELEMETRY=1 python3 scripts/skills_status.py --skills-bin `: **ok, 28/28**. + +## Token-efficiency / client-wiring coverage + +`scripts/adoption_status.py --profile token-efficiency --client-wiring --json`, with the +ecosystem tool prefix first on `PATH`: + +- `profiles[token-efficiency].status`: `prerequisites_present` (all 13 profile commands and + 4 recipes present). +- `client_wiring.complete`: `true` (Claude: rtk hook wired, ai-memory hook events present, + context-mode plugin enabled, subagent-spawn depth and workflow concurrency set, no + `CLAUDE_CODE_EFFORT_LEVEL` override, agent-teams off; Codex: rtk instructions present, + context-mode plugin enabled, `serena`/`socraticode`/`ai-memory` all registered, hooks + feature on with matching trusted-hash counts). +- Top-level `status`: `prerequisites_missing` only because this profile's manifest entry + declares `supported_platforms: ["linux-x86_64"]`; every individual command and recipe + check underneath still reports present. This is a manifest-scoping gap, not a missing + tool. + +## Codex + +Config read directly from this host's own `~/.codex/config.toml` in this session: +`approval_policy = "never"`, `sandbox_mode = "danger-full-access"`, +`features.daemon_auto_start = false`, `features.hooks = true`, and eight `[mcp_servers.*]` +entries (`ai-memory`, `context-mode`, `headroom`, `node_repl`, `openaiDeveloperDocs`, +`qmd`, `serena`, `socraticode`). The [codex host receipt](#host-receipts) below +independently cross-checks the live `codex features list` and `codex mcp list --json` +output against these same config.toml values rather than only reading the file. + +`app-server-daemon` `updater.autoUpdateEnabled`: `false` (per the coordinator's report; +not independently re-checked in this session, since that setting lives under `CODEX_HOME` +outside the profile files this session read). + +`shell_environment_policy.set` carries the pinned `PATH`, `RTK_TELEMETRY_DISABLED=1` and +`MCP_AUTO_OPEN_ENABLED=false` (per the coordinator's report). + +RTK.md was inlined into `~/.codex/AGENTS.md` from a scratch-home `rtk init -g --codex`; the +generated unqualified Codex hook from that scratch run was not installed. 16 +`[[skills.config]]` disable entries were added (all per the coordinator's report). + +## Host value file + +`adoption/hosts/mac-coordinator-64gb-20260925.json` was rendered from the measured +hardware profile, but it carries personal paths, so **it stays private and is not +committed**. + +## Host receipts + +Four receipts under +[`evidence/hosts/mac-coordinator-64gb-20260925/`](../../hosts/mac-coordinator-64gb-20260925/), +all `evidence_class: native_proven`, `stage: use`, `result: pass`, `layer_refs: +foundation/native-clients`, `second_physical_machine: true`: + +| Receipt | Component / version run | What it backs | +| --- | --- | --- | +| [`...--claude-code--use--20260927.json`](../../hosts/mac-coordinator-64gb-20260925/mac-coordinator-64gb-20260925--claude-code--use--20260927.json) | claude-code 2.1.283 | superseded once (see next row); version was only a flag here, not a retained command | +| [`...--claude-code--use--20260927-2.json`](../../hosts/mac-coordinator-64gb-20260925/mac-coordinator-64gb-20260925--claude-code--use--20260927-2.json) | claude-code 2.1.283 | `command -v`/`readlink -f`/`--version`, a headless `claude -p` turn (random-fixture line-count positive control, matched) and `claude mcp list` (5 servers, all Connected) | +| [`...--codex--use--20260927.json`](../../hosts/mac-coordinator-64gb-20260925/mac-coordinator-64gb-20260925--codex--use--20260927.json) | codex-cli 0.158.0-alpha.2.1 | superseded once (see next row); version was only a flag here, not a retained command | +| [`...--codex--use--20260927-2.json`](../../hosts/mac-coordinator-64gb-20260925/mac-coordinator-64gb-20260925--codex--use--20260927-2.json) | codex-cli 0.158.0-alpha.2.1 | version/channel check, `codex exec --skip-git-repo-check --sandbox read-only --ephemeral` (random-fixture positive control via a real `command_execution` event, matched), `codex mcp list --json` and `codex features list` cross-checked live against `config.toml` | + +Both installed builds are newer than the current catalog pins (claude-code 2.1.278, codex +0.155.1), so both receipts use `--allow-unbound-version` and do not by themselves change +either component's `macos-arm64` `platform_status` (still `untested`); that needs +independent review plus the matrix flip rule in +[`docs/component-evidence-matrix.md`](../../../docs/component-evidence-matrix.md). + +Two findings surfaced while recording the codex receipt, backed by the receipt's own +retained commands: + +- **Distribution channel.** `~/.local/bin/codex` is a POSIX shell script whose own comment + says it runs "the ChatGPT-bundled Codex through the app's declared entrypoint"; the + tested `codex-cli 0.158.0-alpha.2.1` is the ChatGPT desktop app's bundled build, not a + separately downloaded `openai/codex` release. The receipt shows this with a file-type + line and a redacted reference count, not the launcher's contents. +- **`codex exec` needs `< /dev/null`.** Without redirected stdin, `codex exec` blocks + indefinitely on "Reading additional input from stdin..." before doing any work, on this + host and this codex-cli build, even for a prompt passed as a CLI argument with no `-` + and no piped stdin. Every exec command in the receipt redirects stdin from `/dev/null`. + +## macOS template findings + +From the coordinator's Stage 1 run, plus this session's own checks where noted: + +- The settings template's ai-memory 2.4.1 hooks were not merged; the live hooks reach the + running ai-memory 19b6429 build and its own store instead. +- The rtk hook is wired (independently confirmed in this session: Claude's `PreToolUse` + `Bash` matcher runs `rtk hook claude`) and needs rtk >= 0.50.0 plus a five-entry + `exclude_commands` list. This session's own check found **both** rtk builds present on + this host: a `mise`-managed install at 0.49.0, and the ecosystem install at 0.50.0 + (`~/.local/share/codex-ecosystem/bin/rtk`, itself a symlink into a `-staging` tree). Since + `~/.claude/settings.json`'s `env.PATH` lists the ecosystem `bin` directory before + `.local/bin`, hooks that Claude Code runs (including `rtk hook claude`) resolve rtk + 0.50.0; a plain interactive shell without that override resolves the mise-managed 0.49.0. + The "done here" therefore holds for hook execution specifically, not for every possible + invocation of the bare `rtk` command on this host. +- The context-mode cache-heal hook is registered by the plugin itself, not by the settings + template. +- The Qdrant URL wired into this profile is `127.0.0.1:6333` (independently confirmed in + this session via `codex mcp list --json`'s `socraticode` entry), not the template's + `16333`. +- No Homebrew on this host. +- No OTel collector is running yet, so telemetry exports fail silently. +- `mcp_oauth_credentials_store` was left at its default. +- `codebase-memory` has no macOS pin. +- The user-scope context-mode MCP registration duplicated the plugin's own server and was + removed. +- The two pre-existing agent-ecosystem agents (`ecosystem-researcher`, `ecosystem-worker`) + fail the workflow contract's tools-allowlist checks. +- User-scope workflows need absolute contract paths, which `test-contract-mutations` + rejects. +- `secret_path_guard` false-positives on Python `set(` inside a Bash heredoc. +- iTerm2 is not installed; Ghostty is, the documented alternative. `/terminal-setup` is + left to the operator. + +## Limits + +- This document and its two `-2` receipts are the evidence-PR session's own work; the + client-layer install itself (backup, agents/guard/MCP install, settings render/apply, + skills/plugins/workflows, Codex wiring) was performed by the coordinator session and is + reported here from its retained outputs, not re-run end to end by this session. Where a + line was independently re-checked here, it says so above. +- Both host receipts carry only the recorder's self-review; `accepted` needs an + independent review from a separate session (requested in the PR). +- No `platform_status` is changed by this PR. `adoption/manifest.json`'s macOS platform + profile status is a separate, maintainer-judgment field this PR does not touch. +- Counts, booleans and file names only: no session id, uuid, working-directory path, MCP + server command/args/env, or personal path appears in this document or in either + receipt's retained command output. diff --git a/manifests/evidence.json b/manifests/evidence.json index ac8116840..d7cda0d3a 100644 --- a/manifests/evidence.json +++ b/manifests/evidence.json @@ -13058,7 +13058,7 @@ }, { "path": "catalogs/landscape/component-evidence-matrix.json", - "sha256": "729bd9bb7a4f29332de9ad6aba03e472d21b4cb348d23ebb8a16142d35d096d9", + "sha256": "377da64df009e127764a359afe3080c9e1b06632323cabc5d22ce89e2bf85334", "bytes": 189734 }, { @@ -13573,7 +13573,7 @@ }, { "path": "docs/component-evidence-matrix.md", - "sha256": "cf1867b290f67573580d0c8dbea4a599a9d31214dfa266a47522e266d3d1eafe", + "sha256": "eea012431ea3b86e2e59dccccc8b14d911d925c95752c54fbbe076e2e2b3a80f", "bytes": 19505 }, { @@ -30466,6 +30466,11 @@ "sha256": "eea0ecfdfd6c022208f0c812dd634c7ba6fff4b0455e875dce017d051ba4ab73", "bytes": 4691 }, + { + "path": "evidence/artifacts/mac-stage1-client-layer-20260927/README.md", + "sha256": "5d5edb426112086293da22262d58d9a8ae3d9ff970fe19f969a54cdb8f263eaf", + "bytes": 12442 + }, { "path": "evidence/artifacts/macos-application-20260924/run-summary.json", "sha256": "0b2647471d67bd15bdacdb949f33d9647d72d5f7d2b1b861db77279c63defc2b", From 54713fee7be08bef6a690878ba64bcd177bb1722 Mon Sep 17 00:00:00 2001 From: seathatflowsinourveins <234074349+seathatflowsinourveins@users.noreply.github.com> Date: Sun, 27 Sep 2026 03:37:12 -0400 Subject: [PATCH 03/12] README: back the rtk-hook-version finding with a real command, not PATH inference Reads ~/.claude/settings.json's own env.PATH value and re-runs command -v rtk / rtk --version with exactly that PATH (the environment Claude Code gives its hooks) instead of inferring resolution order from the PATH list. Confirms it resolves to the ecosystem install and reports rtk 0.50.0. Co-Authored-By: Claude Sonnet 5 --- .../mac-stage1-client-layer-20260927/README.md | 13 +++++++------ manifests/evidence.json | 4 ++-- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/evidence/artifacts/mac-stage1-client-layer-20260927/README.md b/evidence/artifacts/mac-stage1-client-layer-20260927/README.md index 3f54fdb55..9aeeb5656 100644 --- a/evidence/artifacts/mac-stage1-client-layer-20260927/README.md +++ b/evidence/artifacts/mac-stage1-client-layer-20260927/README.md @@ -157,12 +157,13 @@ From the coordinator's Stage 1 run, plus this session's own checks where noted: `Bash` matcher runs `rtk hook claude`) and needs rtk >= 0.50.0 plus a five-entry `exclude_commands` list. This session's own check found **both** rtk builds present on this host: a `mise`-managed install at 0.49.0, and the ecosystem install at 0.50.0 - (`~/.local/share/codex-ecosystem/bin/rtk`, itself a symlink into a `-staging` tree). Since - `~/.claude/settings.json`'s `env.PATH` lists the ecosystem `bin` directory before - `.local/bin`, hooks that Claude Code runs (including `rtk hook claude`) resolve rtk - 0.50.0; a plain interactive shell without that override resolves the mise-managed 0.49.0. - The "done here" therefore holds for hook execution specifically, not for every possible - invocation of the bare `rtk` command on this host. + (`~/.local/share/codex-ecosystem/bin/rtk`, itself a symlink into a `-staging` tree). A + plain interactive shell resolves the mise-managed 0.49.0. This session read + `~/.claude/settings.json`'s own `env.PATH` value and re-ran `command -v rtk`/`rtk + --version` with exactly that `PATH` (the environment Claude Code gives its hooks, + including `rtk hook claude`): it resolves to the ecosystem install and reports **rtk + 0.50.0**, confirming the "done here" holds for hook execution specifically, not for + every possible invocation of the bare `rtk` command on this host. - The context-mode cache-heal hook is registered by the plugin itself, not by the settings template. - The Qdrant URL wired into this profile is `127.0.0.1:6333` (independently confirmed in diff --git a/manifests/evidence.json b/manifests/evidence.json index d7cda0d3a..b0b95bb13 100644 --- a/manifests/evidence.json +++ b/manifests/evidence.json @@ -30468,8 +30468,8 @@ }, { "path": "evidence/artifacts/mac-stage1-client-layer-20260927/README.md", - "sha256": "5d5edb426112086293da22262d58d9a8ae3d9ff970fe19f969a54cdb8f263eaf", - "bytes": 12442 + "sha256": "abe13a444f6dce832c44e11434623f9bf3f43ad4e273bf8dbea6e1b82a02ef8f", + "bytes": 12520 }, { "path": "evidence/artifacts/macos-application-20260924/run-summary.json", From b521b798782c28fdce3404cc9b15870f20eb3db5 Mon Sep 17 00:00:00 2001 From: seathatflowsinourveins <234074349+seathatflowsinourveins@users.noreply.github.com> Date: Sun, 27 Sep 2026 04:38:04 -0400 Subject: [PATCH 04/12] Address review on #391: relabel unbacked evidence-class claims, re-record receipts with verified checks, disclose Codex/cross-host surface Applies the round of review findings against PR #391: - Record -3 generations of both host receipts, superseding -2: fix the codex version-check command's exit-code bug (a later echo, not `codex --version`, decided it), capture the model's actual command_execution text instead of assuming `wc -l`, disclose live-only MCP servers (cua_repl, codex_app) without failing the receipt on them, drop the unchecked approval_policy/ sandbox_mode assertion, add a Read-tool-use check and a real claude mcp list exit-code/status gate to the claude-code receipt, and add an in-transcript negative control to both. - Relabel three PR-body evidence-class rows from native_proven to source_review where no retained command backs the claim (launchctl PID-continuity comparison to the coordinator's private captures, the Codex profile's approval_policy/sandbox_mode, and the rtk-hook/Qdrant-URL "independently reconfirmed" line), and remove a corroboration claim that shared its source with what it claimed to corroborate. - README: disclose the Codex live MCP surface (10 servers vs. 8 declared in config.toml, the two extras plugin-provided) and the applied remoteControlAtStartup/crossSessionInbound settings, their user scope and interaction with this profile's bypassPermissions default; correct the backup/rollback section to state what is and is not confirmed and to actually undo Stage 1's additions instead of merging over them; record the plugin-revision check's installed SHAs and GitHub compare API output; state that a compliant independent review of the -3 receipts cannot return agree (both are --allow-unbound-version). - Open #394 for the two pre-existing ecosystem agents' tools-allowlist gaps (host state, not in this repository's diff). - Fix a lanes.md wording nit: manifests/evidence.json is a shared hot file touched for registration only, not foundation-owned. Co-Authored-By: Claude Sonnet 5 --- .../landscape/component-evidence-matrix.json | 16 +- docs/component-evidence-matrix.md | 6 +- .../README.md | 271 ++++++++++++++---- ...0260925--claude-code--use--20260927-3.json | 77 +++++ ...64gb-20260925--codex--use--20260927-3.json | 87 ++++++ manifests/evidence.json | 18 +- 6 files changed, 401 insertions(+), 74 deletions(-) create mode 100644 evidence/hosts/mac-coordinator-64gb-20260925/mac-coordinator-64gb-20260925--claude-code--use--20260927-3.json create mode 100644 evidence/hosts/mac-coordinator-64gb-20260925/mac-coordinator-64gb-20260925--codex--use--20260927-3.json diff --git a/catalogs/landscape/component-evidence-matrix.json b/catalogs/landscape/component-evidence-matrix.json index 64ee578c1..1965e3d1f 100644 --- a/catalogs/landscape/component-evidence-matrix.json +++ b/catalogs/landscape/component-evidence-matrix.json @@ -83,8 +83,8 @@ "fail": 0, "independently_reviewed_fail": 0, "independently_reviewed_pass": 0, - "latest": "2026-09-27T07:29:00Z", - "pass": 2 + "latest": "2026-09-27T08:15:36Z", + "pass": 3 }, "qualified_models": [] } @@ -1626,8 +1626,8 @@ "fail": 0, "independently_reviewed_fail": 0, "independently_reviewed_pass": 0, - "latest": "2026-09-27T07:28:48Z", - "pass": 2 + "latest": "2026-09-27T08:16:04Z", + "pass": 3 }, "qualified_models": [] } @@ -1676,8 +1676,8 @@ "fail": 0, "independently_reviewed_fail": 0, "independently_reviewed_pass": 0, - "latest": "2026-09-27T07:29:00Z", - "pass": 2 + "latest": "2026-09-27T08:15:36Z", + "pass": 3 }, "qualified_models": [] } @@ -3219,8 +3219,8 @@ "fail": 0, "independently_reviewed_fail": 0, "independently_reviewed_pass": 0, - "latest": "2026-09-27T07:28:48Z", - "pass": 2 + "latest": "2026-09-27T08:16:04Z", + "pass": 3 }, "qualified_models": [] } diff --git a/docs/component-evidence-matrix.md b/docs/component-evidence-matrix.md index e2ab46a85..a7f7c5e8f 100644 --- a/docs/component-evidence-matrix.md +++ b/docs/component-evidence-matrix.md @@ -20,7 +20,7 @@ Each winner shows, for linux-wsl2-x86_64 / macos-arm64, its `e2e_state` and host | Layer | Independent review | Winners: e2e_state [receipts] (linux-wsl2-x86_64 / macos-arm64) | | --- | --- | --- | -| `foundation/agent-sdks` | dual_lane_same_winner | codex (host_verified [8/0/5/0] dissented 3 / untested [2/0/0/0]) | +| `foundation/agent-sdks` | dual_lane_same_winner | codex (host_verified [8/0/5/0] dissented 3 / untested [3/0/0/0]) | | `foundation/ci-supply-chain` | dual_lane_same_winner | zizmor (host_verified [2/0/2/0] / untested [0/0/0/0]); syft (host_verified [2/0/2/0] / untested [0/0/0/0]); candidate:actions-attest (accepted [0/0/0/0] / untested [0/0/0/0]) | | `foundation/code-navigation` | dual_lane_adjudicated (adjudication: `evidence/artifacts/layer-verdicts-20260922/adjudication/foundation-code-navigation-20260922.json`) | serena (host_verified [3/0/2/0] dissented 1 / untested [0/0/0/0]) | | `foundation/document-retrieval` | dual_lane_adjudicated (adjudication: `evidence/artifacts/layer-verdicts-20260922/adjudication/foundation-document-retrieval-20260922.json`) | qmd (host_verified [2/0/2/0] / untested [1/0/0/0]); markitdown (host_verified [2/0/2/0] / untested [0/0/0/0]); poppler (host_verified [4/0/3/0] dissented 1 / untested [0/0/0/0]) | @@ -30,7 +30,7 @@ Each winner shows, for linux-wsl2-x86_64 / macos-arm64, its `e2e_state` and host | `foundation/instructions-skills` | dual_lane_adjudicated (adjudication: `evidence/artifacts/layer-verdicts-20260922/adjudication/foundation-instructions-skills-20260922.json`) | affaan-m/ECC (conditional [2/0/1/0] dissented 1 / untested [0/0/0/0]); candidate:typesafe-ai-skills (conditional [0/0/0/0] / untested [0/0/0/0]); candidate:openai-skills (conditional [0/0/0/0] / untested [0/0/0/0]) | | `foundation/isolation` | dual_lane_same_winner | worktrunk (host_verified [2/0/2/0] / host_verified [1/0/1/0]); sandbox-runtime (host_verified [1/0/1/0] / untested [0/0/0/0]) | | `foundation/mcp-surfaces` | dual_lane_same_winner | mcporter (host_verified [6/0/2/0] dissented 4 / untested [0/0/0/0]); mcp-inspector (host_verified [2/0/1/0] dissented 1 / untested [0/0/0/0]) | -| `foundation/native-clients` | dual_lane_same_winner | claude-code (accepted [1/0/1/0] / untested [2/0/0/0]); codex (host_verified [8/0/5/0] dissented 3 / untested [2/0/0/0]) | +| `foundation/native-clients` | dual_lane_same_winner | claude-code (accepted [1/0/1/0] / untested [3/0/0/0]); codex (host_verified [8/0/5/0] dissented 3 / untested [3/0/0/0]) | | `foundation/observation-inference` | dual_lane_adjudicated (adjudication: `evidence/artifacts/layer-verdicts-20260922/adjudication/foundation-observation-inference-20260922.json`) | opentelemetry-collector-contrib (host_verified [2/0/2/0] / untested [0/0/0/0]); prometheus (host_verified [2/0/2/0] / untested [0/0/0/0]); loki (host_verified [2/0/2/0] / untested [0/0/0/0]) | | `foundation/quality-evaluation` | dual_lane_same_winner | promptfoo (host_verified [6/0/2/0] dissented 4 / untested [0/0/0/0]); playwright-test (conditional [0/0/0/0] / untested [1/0/0/0] dissented 1) | | `foundation/recovery-portability` | dual_lane_same_winner | restic (host_verified [3/0/3/0] / untested [1/0/0/0]); candidate:astral-sh-uv (conditional [0/0/0/0] / untested [0/0/0/0]) | @@ -39,7 +39,7 @@ Each winner shows, for linux-wsl2-x86_64 / macos-arm64, its `e2e_state` and host | `foundation/semantic-rag` | dual_lane_same_winner | socraticode (host_verified [5/0/2/0] dissented 3 / untested [1/0/0/0]); qdrant (host_verified [3/0/3/0] / untested [1/0/0/0]); vllm (host_verified [6/0/3/0] dissented 2 / untested [0/0/0/0]) | | `foundation/token-efficiency` | dual_lane_adjudicated (adjudication: `evidence/artifacts/layer-verdicts-20260922/adjudication/foundation-token-efficiency-20260922.json`) | rtk (host_verified [7/0/4/0] dissented 2 / host_verified [1/0/1/0]); headroom (host_verified [4/0/3/0] dissented 1 / untested [0/0/0/0]); ccusage (host_verified [2/0/2/0] / untested [0/0/0/0]) | | `foundation/web-research` | dual_lane_adjudicated (adjudication: `evidence/artifacts/layer-verdicts-20260922/adjudication/foundation-web-research-20260922.json`) | tavily-cli (conditional [0/0/0/0] / untested [0/0/0/0]); agent-browser (conditional [0/0/0/0] / untested [0/0/0/0]); openresearch (conditional [0/0/0/0] / untested [0/0/0/0]) | -| `foundation/workers` | dual_lane_adjudicated (adjudication: `evidence/artifacts/layer-verdicts-20260922/adjudication/foundation-workers-20260922.json`) | claude-code (conditional [1/0/1/0] / untested [2/0/0/0]); worktrunk (host_verified [2/0/2/0] / host_verified [1/0/1/0]) | +| `foundation/workers` | dual_lane_adjudicated (adjudication: `evidence/artifacts/layer-verdicts-20260922/adjudication/foundation-workers-20260922.json`) | claude-code (conditional [1/0/1/0] / untested [3/0/0/0]); worktrunk (host_verified [2/0/2/0] / host_verified [1/0/1/0]) | | `us-equities/agents-models-workers` | dual_lane_same_winner | codex-native-sdk (accepted [0/0/0/0] / untested [0/0/0/0]); foundation-ai-memory (accepted [0/0/0/0] / untested [0/0/0/0]); foundation-socraticode (accepted [0/0/0/0] / untested [0/0/0/0]) | | `us-equities/backtesting-engine` | dual_lane_same_winner | nautilustrader (host_verified [1/0/1/0] / untested [0/0/0/0] +1 alias receipt(s), not counted); lean (host_verified [2/0/1/0] dissented 1 / untested [0/0/0/0]) | | `us-equities/data-quality-orchestration` | dual_lane_adjudicated (adjudication: `evidence/artifacts/layer-verdicts-20260922/adjudication/us-equities-data-quality-orchestration-20260922.json`) | dagu (host_verified [2/0/2/0] / untested [0/0/0/0]); data-pandera (host_verified [3/0/1/0] dissented 2 / untested [0/0/0/0]) | diff --git a/evidence/artifacts/mac-stage1-client-layer-20260927/README.md b/evidence/artifacts/mac-stage1-client-layer-20260927/README.md index 9aeeb5656..5de6bb80e 100644 --- a/evidence/artifacts/mac-stage1-client-layer-20260927/README.md +++ b/evidence/artifacts/mac-stage1-client-layer-20260927/README.md @@ -15,11 +15,36 @@ Before any write, the coordinator copied `~/.claude` and `~/.codex` (settings, h plugins, skills, agents) to a private, dated, `0700` folder outside every worktree: 4,516 files, manifest sha256 `a7478603be747dfd52a18dd05f4f0d80510af5bd736c7af4581c0e7cd6b2c5c4`. `auth.json`, transcripts, sessions, history and caches were excluded. The backup folder's -path is not recorded here (personal path). - -**Rollback, one line:** copy the dated backup's `claude/`, `claude.json` and `codex/` back -over `~/.claude`, `~/.claude.json` and `~/.codex` (`apply_claude_settings.py` also left its -own timestamped `settings.json` backup alongside the live one). +path is not recorded here (personal path). **Not confirmed by this session:** whether the +4,516-file manifest also covers `~/.claude.json` (a separate file, not under `~/.claude`, +that holds the user-scope MCP registration Stage 1 changed) is not stated in the +coordinator's report, and this session did not re-hash the private manifest to check either +way. + +**Rollback (unrehearsed on this host; replaces Stage 1's additions instead of merging over +them):** + +```sh +mv ~/.claude ~/.claude.pre-rollback && mv ~/.codex ~/.codex.pre-rollback +rsync -a --delete \ + --exclude 'auth.json' --exclude 'transcripts/' --exclude 'sessions/' \ + --exclude 'history*' --exclude '*cache*' \ + "/claude/" ~/.claude/ +rsync -a --delete "/codex/" ~/.codex/ +# ~/.claude.json: restore from the backup only once it is confirmed to be in the manifest +# (see above); otherwise leave the live ~/.claude.json alone. +cp ~/.claude.pre-rollback/auth.json ~/.claude/auth.json 2>/dev/null +rsync -a ~/.claude.pre-rollback/transcripts/ ~/.claude/transcripts/ 2>/dev/null +rsync -a ~/.claude.pre-rollback/sessions/ ~/.claude/sessions/ 2>/dev/null +rm -rf ~/.claude.pre-rollback ~/.codex.pre-rollback +``` + +The previous one-line "copy the backup's files back over `~/.claude`/`~/.codex`" merges +rather than replaces: Stage 1 added agents, guard hooks, skills, plugins and workflows (see +below), and a copy-over leaves every one of those additions in place, so following it would +not actually undo Stage 1. The `rsync --delete` form above removes what Stage 1 added while +keeping the excluded files. `apply_claude_settings.py` also left its own timestamped +`settings.json` backup alongside the live one, independent of the manifest above. ## Service continuity @@ -38,7 +63,11 @@ session independently re-ran `launchctl list | grep -E 'agent-ecosystem|native-s while preparing this PR (over an hour after the coordinator's "after" capture): all three running PIDs were still the exact same PIDs as both the "before" and "after" captures, and `maintenance` was still not running with the same last exit code, which is stronger -continuity evidence than a single before/after pair. +continuity evidence than a single before/after pair. The "Before" and "After" columns above +are the coordinator's own captures, relayed here and not independently re-verifiable by this +session (the same situation as the backup manifest above); only the "This session, live" +column is something this session directly watched happen. See the PR's evidence-class +table: this claim is `source_review` overall, not `native_proven`, for exactly that reason. ## Headless read-back (names and counts only) @@ -57,13 +86,22 @@ reproducible, not a one-off capture. Compares each installed plugin's `installed_plugins.json` `gitCommitSha` against the revision `recipes/README.md` names as reviewed, allowing "ahead of the reviewed revision in `stats.json` only" (confirmed by diffing the two revisions through the GitHub compare -API) since that file is a self-reported counter, not plugin logic: - -| Plugin | Reviewed revision | Coordinator's observation | This session's fresh re-run | -| --- | --- | --- | --- | -| `context-mode@context-mode` | `6f0cc684` | ahead, `stats.json` only | still ahead, `stats.json` only (at a newer commit again — the plugin keeps self-updating that one file) | -| `claude-hud@claude-hud` | `ef5f1c8b` | exact match | exact match | -| `codex@openai-codex` | `db52e28f` | exact match | exact match | +API) since that file is a self-reported counter, not plugin logic. Neither the +coordinator's check nor this evidence-PR session's first re-run recorded the installed +`gitCommitSha` or the compare API's `{status, files}` result (`adoption/bootstrap.md` +step 4a asks for both); a later review-fix pass records them for the first time in the +rightmost column below. This whole claim is `source_review`, not `native_proven`: + +| Plugin | Reviewed revision | Coordinator's observation | Evidence-PR session's re-run | Review-fix pass (2026-09-27): installed SHA + compare API | +| --- | --- | --- | --- | --- | +| `context-mode@context-mode` | `6f0cc6841c687e754059f36714a11233fda1a02b` | ahead, `stats.json` only (SHA not retained) | still ahead, `stats.json` only, at a newer commit again — the plugin keeps self-updating that one file (SHA not retained) | installed `a2fda46b3cb82753f8c2d67953c881a0dd48b648`; `gh api repos/mksglu/context-mode/compare/6f0cc6841c687e754059f36714a11233fda1a02b...a2fda46b3cb82753f8c2d67953c881a0dd48b648` returned `{"status":"ahead","files":["stats.json"]}` | +| `claude-hud@claude-hud` | `ef5f1c8b167572ad1443c70629763ea8780af96b` | exact match (SHA not retained) | exact match (SHA not retained) | installed `ef5f1c8b167572ad1443c70629763ea8780af96b` — exact match, no compare call needed | +| `codex@openai-codex` | `db52e28f4d9ded852ab3942cea316258ae4ef346` | exact match (SHA not retained) | exact match (SHA not retained) | installed `db52e28f4d9ded852ab3942cea316258ae4ef346` — exact match, no compare call needed | + +Three checks at three different times on this host saw three different `context-mode` +installed revisions, each "ahead, `stats.json` only" of the reviewed revision: the plugin's +marketplace tracks its default branch, not a pin, so this result holds only for the moment +each check was taken, not as a standing fact about the install. ## Skills @@ -82,24 +120,52 @@ ecosystem tool prefix first on `PATH`: `CLAUDE_CODE_EFFORT_LEVEL` override, agent-teams off; Codex: rtk instructions present, context-mode plugin enabled, `serena`/`socraticode`/`ai-memory` all registered, hooks feature on with matching trusted-hash counts). -- Top-level `status`: `prerequisites_missing` only because this profile's manifest entry - declares `supported_platforms: ["linux-x86_64"]`; every individual command and recipe - check underneath still reports present. This is a manifest-scoping gap, not a missing - tool. +- Top-level `status`: `prerequisites_missing` only because `adoption/manifest.json`'s + `supported_platforms` (manifest-wide, not per-profile: linux/x86_64/Python 3.13) does not + match this macOS arm64 host; every individual command and recipe check for this profile + still reports present. This is the manifest's stated intended platform for now — macOS is + separately `drafted_not_accepted` in the same manifest's `platform_profiles` — not a + per-profile scoping gap and not a missing tool. Run with + `uv run --no-project --python 3.13 python scripts/adoption_status.py ...` per + [bootstrap.md](../../../adoption/bootstrap.md) step 6, matching the manifest's Python. ## Codex Config read directly from this host's own `~/.codex/config.toml` in this session: `approval_policy = "never"`, `sandbox_mode = "danger-full-access"`, -`features.daemon_auto_start = false`, `features.hooks = true`, and eight `[mcp_servers.*]` -entries (`ai-memory`, `context-mode`, `headroom`, `node_repl`, `openaiDeveloperDocs`, -`qmd`, `serena`, `socraticode`). The [codex host receipt](#host-receipts) below -independently cross-checks the live `codex features list` and `codex mcp list --json` -output against these same config.toml values rather than only reading the file. - -`app-server-daemon` `updater.autoUpdateEnabled`: `false` (per the coordinator's report; -not independently re-checked in this session, since that setting lives under `CODEX_HOME` -outside the profile files this session read). +`features.daemon_auto_start = false`, `features.hooks = true`. These four values are +`source_review` (a direct file read, not a live check): no command in either codex receipt +checks `approval_policy` or `sandbox_mode` live, and the codex receipt's own exec turn +explicitly runs under `--sandbox read-only`, not `danger-full-access`, so this README does +not claim those two as `native_proven`. `features.daemon_auto_start`/`features.hooks` *are* +cross-checked live by the [codex host receipt](#host-receipts) below (`codex features list` +against config.toml). + +**MCP servers: config.toml declares eight, the live surface has ten.** `config.toml` has +eight `[mcp_servers.*]` tables (`ai-memory`, `context-mode`, `headroom`, `node_repl`, +`openaiDeveloperDocs`, `qmd`, `serena`, `socraticode`); the codex receipt's own +`codex mcp list --json` check confirms all eight are present live (`declared` is a subset +of `live`, which gates the command's exit code), but the live listing also has two servers +`config.toml` does not declare: `cua_repl` (enabled) and `codex_app` (disabled), both +printed by the receipt as `live_only_not_in_config_toml`. Each comes from a Codex plugin +enabled in `config.toml`'s `[plugins."*@*"]` tables (`unified-computer-use@openai-bundled` +and `codex-app-tools@openai-bundled` respectively; each plugin's own `.mcp.json` under +`~/.codex/plugins/cache/openai-bundled/` declares its server), installed from the ChatGPT +desktop app's bundled `openai-bundled` marketplace, not from this repository's Stage 1 +install. `config.toml` enables 13 plugins in total (its `[plugins."*@*"]` entries), including +`unified-computer-use`, `computer-use`, `chrome` and `browser`; every Codex turn on this +host — including a `codex exec --sandbox read-only` receipt command — has these +plugin-provided tools available under `approval_policy = "never"`, since the read-only +sandbox restricts shell commands, not plugin tools. Whether this extra surface is accepted +for a never/danger-full-access profile is an open question for the owner, not decided here; +this README previously described the live listing as matching config.toml, which undercounted +it, and no longer does. + +`app-server-daemon` `updater.autoUpdateEnabled`: `false` (per the coordinator's report; not +independently re-checked in this session, since that setting lives under `CODEX_HOME` +outside the profile files this session read; stays `source_review` and unverified by any +receipt — the codex receipt proves only `features.daemon_auto_start = false`, a different +setting). `shell_environment_policy.set` carries the pinned `PATH`, `RTK_TELEMETRY_DISABLED=1` and `MCP_AUTO_OPEN_ENABLED=false` (per the coordinator's report). @@ -108,6 +174,39 @@ RTK.md was inlined into `~/.codex/AGENTS.md` from a scratch-home `rtk init -g -- generated unqualified Codex hook from that scratch run was not installed. 16 `[[skills.config]]` disable entries were added (all per the coordinator's report). +The Codex binary every command above runs, `~/.local/bin/codex`, is a launcher into the +ChatGPT desktop app's bundled build (see "Distribution channel" below); an app update can +replace it with no receipt, independent of `features.daemon_auto_start` or the updater +setting above. Not remedied here; a pinned, separately downloaded `openai/codex` release +placed first on `PATH` would close this gap. + +## Cross-host coordination + +The coordinator applied two settings from +[Remote Control](https://code.claude.com/docs/en/remote-control) and +[cross-session messaging](https://code.claude.com/docs/en/cross-session-messaging), both at +**user scope** (`~/.claude/settings.json`, so every session on this Mac, not only the +coordinator's): `remoteControlAtStartup: true` and `crossSessionInbound: "accept"`. The same +user-scope settings file also sets `defaultMode: "bypassPermissions"` and +`skipDangerousModePermissionPrompt: true`; no `isolatePeerMachines` key is set (this README +does not describe what that key does; see the Claude Code docs above for that). + +The [Stage 1 decision record](../../../docs/decisions/2026-09-27-mac-single-writer-staged.md) +approves `crossSessionInbound: "accept"` on the premise that "a message cannot approve a +prompt, change configuration or run a command, and each host's own permissions apply." On +this host, every session currently runs under `bypassPermissions`, so "each host's own +permissions" means an idle session that receives a message starts a new model turn (per +[the cooperation recipe](../../../recipes/claude-native-ultracode.md)) whose Bash, Write and +MCP calls then run with no prompt. This is disclosed here as the applied configuration and +its interaction with the profile's permission mode, not as a recommendation. The owner has +approved `crossSessionInbound: "accept"`; either confirming the accepted risk in the +decision record or scoping it to only the participating sessions (the recipe's own +guidance — opt in per session with `claude --settings +'{"crossSessionInbound":"accept"}'` rather than user-wide) is an open decision for the +owner, not resolved by this PR. This claim (the applied values and their scope) is +`source_review`: read directly from `~/.claude/settings.json` in this session, not exercised +by a receipt. + ## Host value file `adoption/hosts/mac-coordinator-64gb-20260925.json` was rendered from the measured @@ -116,36 +215,62 @@ committed**. ## Host receipts -Four receipts under +Six receipts under [`evidence/hosts/mac-coordinator-64gb-20260925/`](../../hosts/mac-coordinator-64gb-20260925/), all `evidence_class: native_proven`, `stage: use`, `result: pass`, `layer_refs: -foundation/native-clients`, `second_physical_machine: true`: +foundation/native-clients`, `second_physical_machine: true`. Each component's `-3` generation +supersedes `-2`, which supersedes the original; only the `-3` file is current evidence, and +the schema keeps the earlier generations byte-identical rather than deleting them: | Receipt | Component / version run | What it backs | | --- | --- | --- | -| [`...--claude-code--use--20260927.json`](../../hosts/mac-coordinator-64gb-20260925/mac-coordinator-64gb-20260925--claude-code--use--20260927.json) | claude-code 2.1.283 | superseded once (see next row); version was only a flag here, not a retained command | -| [`...--claude-code--use--20260927-2.json`](../../hosts/mac-coordinator-64gb-20260925/mac-coordinator-64gb-20260925--claude-code--use--20260927-2.json) | claude-code 2.1.283 | `command -v`/`readlink -f`/`--version`, a headless `claude -p` turn (random-fixture line-count positive control, matched) and `claude mcp list` (5 servers, all Connected) | -| [`...--codex--use--20260927.json`](../../hosts/mac-coordinator-64gb-20260925/mac-coordinator-64gb-20260925--codex--use--20260927.json) | codex-cli 0.158.0-alpha.2.1 | superseded once (see next row); version was only a flag here, not a retained command | -| [`...--codex--use--20260927-2.json`](../../hosts/mac-coordinator-64gb-20260925/mac-coordinator-64gb-20260925--codex--use--20260927-2.json) | codex-cli 0.158.0-alpha.2.1 | version/channel check, `codex exec --skip-git-repo-check --sandbox read-only --ephemeral` (random-fixture positive control via a real `command_execution` event, matched), `codex mcp list --json` and `codex features list` cross-checked live against `config.toml` | +| [`...--claude-code--use--20260927.json`](../../hosts/mac-coordinator-64gb-20260925/mac-coordinator-64gb-20260925--claude-code--use--20260927.json) | claude-code 2.1.283 | superseded twice; version was only a flag here, not a retained command | +| [`...--claude-code--use--20260927-2.json`](../../hosts/mac-coordinator-64gb-20260925/mac-coordinator-64gb-20260925--claude-code--use--20260927-2.json) | claude-code 2.1.283 | superseded by `-3` (review findings: the claim asserted a Read-tool check and a `claude mcp list` failure-mode the commands did not perform; see below) | +| [`...--claude-code--use--20260927-3.json`](../../hosts/mac-coordinator-64gb-20260925/mac-coordinator-64gb-20260925--claude-code--use--20260927-3.json) | claude-code 2.1.283 | `command -v`/`readlink -f`/`--version`; a headless `claude -p` turn (random-fixture line-count positive control, matched, plus an in-transcript negative control on a deliberately wrong count, correctly rejected) that also scans the transcript's own `tool_use` events and fails unless a `Read` call is present; and a `claude mcp list` whose own exit code is captured with no shell pipe, failing unless it is 0 and every reported server's status contains `Connected` (5 servers, all Connected) | +| [`...--codex--use--20260927.json`](../../hosts/mac-coordinator-64gb-20260925/mac-coordinator-64gb-20260925--codex--use--20260927.json) | codex-cli 0.158.0-alpha.2.1 | superseded twice; version was only a flag here, not a retained command | +| [`...--codex--use--20260927-2.json`](../../hosts/mac-coordinator-64gb-20260925/mac-coordinator-64gb-20260925--codex--use--20260927-2.json) | codex-cli 0.158.0-alpha.2.1 | superseded by `-3` (review findings: the version-check command's exit code was actually a later `echo`'s, not `codex --version`'s; the claim named a specific model command that was not checked; `approval_policy`/`sandbox_mode` were claimed without a live check; the mcp-list check's summary line and two live-only servers fell outside the 400-char excerpt; see below) | +| [`...--codex--use--20260927-3.json`](../../hosts/mac-coordinator-64gb-20260925/mac-coordinator-64gb-20260925--codex--use--20260927-3.json) | codex-cli 0.158.0-alpha.2.1 | version/channel check whose exit code is now `codex --version`'s own; `codex exec --skip-git-repo-check --sandbox read-only --ephemeral` (random-fixture positive control via a real `command_execution` event, matched — the event's own command text is captured and printed rather than assumed — plus an in-transcript negative control on a deliberately wrong count, correctly rejected); `codex mcp list --json` (declared ⊆ live gates the exit code; the summary line now prints first, and any live-only server is disclosed, not a failure — this run: `cua_repl`, `codex_app`); `codex features list` cross-checked live against `config.toml`. No longer claims `approval_policy`/`sandbox_mode` (see Codex section above) | Both installed builds are newer than the current catalog pins (claude-code 2.1.278, codex -0.155.1), so both receipts use `--allow-unbound-version` and do not by themselves change -either component's `macos-arm64` `platform_status` (still `untested`); that needs -independent review plus the matrix flip rule in +0.155.1), so all four `-2`/`-3` receipts use `--allow-unbound-version` and do not by +themselves change either component's `macos-arm64` `platform_status` (still `untested`); +that needs independent review plus the matrix flip rule in [`docs/component-evidence-matrix.md`](../../../docs/component-evidence-matrix.md). -Two findings surfaced while recording the codex receipt, backed by the receipt's own -retained commands: - -- **Distribution channel.** `~/.local/bin/codex` is a POSIX shell script whose own comment - says it runs "the ChatGPT-bundled Codex through the app's declared entrypoint"; the - tested `codex-cli 0.158.0-alpha.2.1` is the ChatGPT desktop app's bundled build, not a - separately downloaded `openai/codex` release. The receipt shows this with a file-type - line and a redacted reference count, not the launcher's contents. -- **`codex exec` needs `< /dev/null`.** Without redirected stdin, `codex exec` blocks - indefinitely on "Reading additional input from stdin..." before doing any work, on this - host and this codex-cli build, even for a prompt passed as a CLI argument with no `-` - and no piped stdin. Every exec command in the receipt redirects stdin from `/dev/null`. +**A compliant independent review of these receipts cannot return `agree`, by construction, +and this PR's merge does not wait on that being fixed.** `docs/contributing-evidence.md`'s +four review points include "bound to the winner": the receipt's `tool_versions` must match +the landscape winner's pin. Both `-3` receipts are `--allow-unbound-version` (point 3 +above), and the tested codex is the ChatGPT app's bundled alpha build, which cannot bind to +an `openai/codex` release pin at all. So a review that adequacy-checks all four points must +record `needs_changes` on point 4, which — per `contributing-evidence.md` — withholds +`accepted` regardless of the other three points. The Opus same-host review and the +workstation's GPT-6 cross-family review requested in this PR's Review section can only +adequacy-check points 1-3 (layer role, positive control, backed claims); point 4 fails by +construction, so these receipts stay informational and are not expected to reach `accepted` +through this PR. The route to bound, `accepted`-eligible evidence is either installing the +pinned official `claude-code` 2.1.278 and `openai/codex` 0.155.1 releases and re-recording, +or moving the landscape pins forward through the re-record process in +`docs/contributing-evidence.md` section 4. + +Two findings surfaced while recording the codex receipt, from this session's own +observation, not all backed by a retained command: + +- **Distribution channel** (backed by the receipt's own retained command 1). + `~/.local/bin/codex` is a POSIX shell script whose own comment says it runs "the + ChatGPT-bundled Codex through the app's declared entrypoint"; the tested + `codex-cli 0.158.0-alpha.2.1` is the ChatGPT desktop app's bundled build, not a separately + downloaded `openai/codex` release. The receipt shows this with a file-type line and a + redacted reference count, not the launcher's contents. +- **`codex exec` needs `< /dev/null`** (an unretained observation from this session, not a + new finding: no retained command in either receipt generation runs `codex exec` without + `< /dev/null` to show the alternative). Without redirected stdin, `codex exec` blocks + indefinitely on "Reading additional input from stdin...". This is documented upstream + behavior, not new to this host or this codex-cli build: + [`evidence/artifacts/gap-wave2-20260923/foundation__quality-evaluation/README.md`](../gap-wave2-20260923/foundation__quality-evaluation/README.md) + traces the same blocking `read_to_end` on stdin to `codex-cli` 0.155.1's own + `resolve_root_prompt` (tag `rust-v0.155.1`, `codex-rs/exec/src/lib.rs`). Every exec command + in both receipts already redirects stdin from `/dev/null`. ## macOS template findings @@ -175,8 +300,19 @@ From the coordinator's Stage 1 run, plus this session's own checks where noted: - `codebase-memory` has no macOS pin. - The user-scope context-mode MCP registration duplicated the plugin's own server and was removed. -- The two pre-existing agent-ecosystem agents (`ecosystem-researcher`, `ecosystem-worker`) - fail the workflow contract's tools-allowlist checks. +- The two pre-existing `local.agent-ecosystem` agents (user scope, `~/.claude/agents/`, not + tracked in this repository and predating this PR) fail the tools-allowlist rules this + repository's own `test-envelope.mjs` holds its project agents to: `ecosystem-worker.md` + has `isolation: worktree` and no `tools:` line at all, so (per Claude Code's documented + subagent behavior) it inherits every tool, including Serena's symbol-edit tools that + `docs/decisions/2026-09-26-stack-agents-role-dispatch.md` deliberately withheld from + `isolated-builder` for the same worktree-isolation reason; `ecosystem-researcher.md` + grants `Bash`, `WebFetch`, `WebSearch` and the wildcard `mcp__openaiDeveloperDocs__*` (a + bare-server wildcard, not an explicit per-tool grant), where the role table excludes + `WebFetch`. Both run under this profile's `bypassPermissions` default, so neither prompts + before using these tools. Tracked as + [#394](https://github.com/seathatflowsinourveins/native-agent-stack/issues/394); not + fixed by this PR, since neither file is in this repository's diff. - User-scope workflows need absolute contract paths, which `test-contract-mutations` rejects. - `secret_path_guard` false-positives on Python `set(` inside a Bash heredoc. @@ -185,15 +321,32 @@ From the coordinator's Stage 1 run, plus this session's own checks where noted: ## Limits -- This document and its two `-2` receipts are the evidence-PR session's own work; the - client-layer install itself (backup, agents/guard/MCP install, settings render/apply, - skills/plugins/workflows, Codex wiring) was performed by the coordinator session and is - reported here from its retained outputs, not re-run end to end by this session. Where a - line was independently re-checked here, it says so above. -- Both host receipts carry only the recorder's self-review; `accepted` needs an - independent review from a separate session (requested in the PR). +- This document and its `-2`/`-3` receipts are the evidence-PR session's own work (the + `-3` generations were recorded in a later, review-fix pass on 2026-09-27, applying this + PR's own review findings); the client-layer install itself (backup, agents/guard/MCP + install, settings render/apply, skills/plugins/workflows, Codex wiring) was performed by + the coordinator session and is reported here from its retained outputs, not re-run end to + end by this session. Where a line was independently re-checked here, it says so above. +- All four current receipts (`-2` superseded, `-3` current, per component) carry only the + recorder's self-review; `accepted` needs an independent review from a separate session + (requested in the PR). See "Host receipts" above: a compliant review of the `-3` + generations cannot return `agree` regardless, because both are `--allow-unbound-version`. - No `platform_status` is changed by this PR. `adoption/manifest.json`'s macOS platform profile status is a separate, maintainer-judgment field this PR does not touch. -- Counts, booleans and file names only: no session id, uuid, working-directory path, MCP - server command/args/env, or personal path appears in this document or in either - receipt's retained command output. +- Counts, booleans, file names and (in the `-3` receipts) tool names and one sanitized + shell command line appear; no session id, uuid, working-directory path, MCP server + command/args/env, or personal path appears in this document or in any receipt's retained + command output (the `-3` receipts replace the scratch directory with `` in the + one command line they print). +- Host request [#382](https://github.com/seathatflowsinourveins/native-agent-stack/issues/382) + still carries the `request:blocked` label as of this PR. Its status comment (written by + `scripts/host_requests.py`, updated 2026-09-27T05:08:09Z) gives the reason: "Claude Code's + auto-mode classifier refused `install_claude_profile.py` as Self-Modification: this + session may not write its own `~/.claude` or `~/.codex` until the user adds a permission + rule or gives an explicit, specific approval," noting only the private backup as done + before that block. The receipts and live host state in this PR show the agents, hooks, + skills, plugins, MCP servers and Codex config this classifier initially refused to write + are now present and working, so the block was evidently resolved on a later attempt (most + plausibly the "explicit, specific approval" the message names), but this session did not + witness that and the issue's label was never updated to reflect it. Reconciling the label + with the outcome is for the coordinator or a maintainer, not decided here. diff --git a/evidence/hosts/mac-coordinator-64gb-20260925/mac-coordinator-64gb-20260925--claude-code--use--20260927-3.json b/evidence/hosts/mac-coordinator-64gb-20260925/mac-coordinator-64gb-20260925--claude-code--use--20260927-3.json new file mode 100644 index 000000000..db1e9c4f5 --- /dev/null +++ b/evidence/hosts/mac-coordinator-64gb-20260925/mac-coordinator-64gb-20260925--claude-code--use--20260927-3.json @@ -0,0 +1,77 @@ +{ + "schema_version": 1, + "id": "mac-coordinator-64gb-20260925--claude-code--use--20260927-3", + "kind": "host_acceptance", + "host": { + "host_id": "mac-coordinator-64gb-20260925", + "platform_id": "macos-arm64", + "os": "macos", + "architecture": "arm64", + "second_physical_machine": true, + "hardware_profile_ref": "mac-coordinator-64gb-20260925" + }, + "catalog_revision": "c60f3ec5cd9ee30edb95799bb69fe470dccbdce3", + "recorded_by": { + "identity_sha256": "91719ef8aa813c0bf50b26570098baa57e4c043d7d23d4cc5c26ce7c17710954", + "model": "claude-sonnet-5" + }, + "component_id": "claude-code", + "stage": "use", + "commands": [ + { + "cmd": "p=$(command -v claude)\necho \"resolved: $p\"\necho \"readlink: $(readlink -f \"$p\" 2>/dev/null || echo \"$p (not a symlink)\")\"\nclaude --version", + "exit": 0, + "duration_s": 0.019, + "output_sha256": "73436ead43a0c9c18663723a30ad3e166719def4b5eca2219418aa57432d886c", + "output_excerpt": "resolved: ~/.local/bin/claude\nreadlink: ~/.local/share/claude/versions/2.1.283\n2.1.283 (Claude Code)\n" + }, + { + "cmd": "D=\"$(mktemp -d)\"\nn=$((7 + RANDOM % 90))\n: > \"$D/fixture.txt\"\nfor i in $(seq 1 \"$n\"); do echo $((RANDOM % 900 + 1)) >> \"$D/fixture.txt\"; done\nreal=$(wc -l < \"$D/fixture.txt\" | tr -d ' ')\ncd \"$D\"\nclaude -p --output-format stream-json --verbose \"Count the lines in the file ./fixture.txt in your current working directory using your Read tool, then reply with exactly one line of the form COUNT= and nothing else.\" < /dev/null > out.jsonl 2> err.log\nrc=$?\npython3 - \"$real\" \"$rc\" <<'PY'\nimport json, re, sys\nreal, rc = sys.argv[1], sys.argv[2]\nevents = []\nfor line in open(\"out.jsonl\"):\n line = line.strip()\n if not line:\n continue\n try:\n events.append(json.loads(line))\n except ValueError:\n continue\ninit = {}\nfinal = {}\ntool_names = []\nfor ev in events:\n if ev.get(\"type\") == \"system\" and ev.get(\"subtype\") == \"init\" and not init:\n init = ev\n if ev.get(\"type\") == \"result\":\n final = ev\n if ev.get(\"type\") == \"assistant\":\n msg = ev.get(\"message\") or {}\n for block in msg.get(\"content\") or []:\n if isinstance(block, dict) and block.get(\"type\") == \"tool_use\":\n tool_names.append(block.get(\"name\"))\n\ndef check(expected):\n text = final.get(\"result\") or \"\"\n m = re.search(r\"COUNT=(\\d+)\", text)\n got = m.group(1) if m else None\n ok = (not final.get(\"is_error\")) and (got == expected)\n return ok, got\n\ncounts = {}\nfor key in (\"agents\", \"skills\", \"plugins\", \"mcp_servers\", \"slash_commands\", \"tools\"):\n v = init.get(key)\n if isinstance(v, list):\n counts[key] = len(v)\nmcp_status = sorted({s.get(\"status\") for s in init.get(\"mcp_servers\", []) if isinstance(s, dict)})\nok, got = check(real)\nunique_tools = {t for t in tool_names}\nread_used = \"Read\" in unique_tools\nwrong = str(int(real) + 1)\nneg_ok, neg_got = check(wrong)\nprint(\"permissionMode=\" + str(init.get(\"permissionMode\")) + \" model=\" + str(init.get(\"model\")))\nprint(\"counts=\" + json.dumps(counts, sort_keys=True))\nprint(\"mcp_status=\" + json.dumps(mcp_status))\nprint(\"tool_use_names=\" + json.dumps(sorted(unique_tools)))\nprint(\"read_tool_used=\" + str(read_used))\nprint(\"turn_subtype=\" + str(final.get(\"subtype\")) + \" is_error=\" + str(final.get(\"is_error\")))\nprint(\"positive_control expected=\" + real + \" got=\" + str(got) + \" match=\" + str(got == real))\nprint(\"negative_control expected=\" + wrong + \" got=\" + str(neg_got) + \" correctly_rejected=\" + str(not neg_ok))\noverall_ok = (rc == \"0\") and ok and read_used and (not neg_ok)\nraise SystemExit(0 if overall_ok else 1)\nPY", + "exit": 0, + "duration_s": 10.055, + "output_sha256": "1905fbeedd8d8214168bb862be7a16d859268c0b12765571589da8656ec685d2", + "output_excerpt": "permissionMode=bypassPermissions model=claude-opus-5-5[1m]\ncounts={\"agents\": 18, \"mcp_servers\": 5, \"plugins\": 11, \"skills\": 67, \"slash_commands\": 107, \"tools\": 118}\nmcp_status=[\"connected\"]\ntool_use_names=[\"Bash\", \"Read\"]\nread_tool_used=True\nturn_subtype=success is_error=False\npositive_control expected=44 got=44 match=True\nnegative_control expected=45 got=44 correctly_rejected=True\n" + }, + { + "cmd": "D=\"$(mktemp -d)\"\ncd \"$D\"\nclaude mcp list < /dev/null > mcp.txt 2> mcp.err\nrc=$?\npython3 - \"$rc\" <<'PY'\nimport sys\nrc = sys.argv[1]\nrows = []\nfor line in open(\"mcp.txt\"):\n line = line.rstrip(\"\\n\")\n if \" - \" not in line or \": \" not in line:\n continue\n name, _, _ = line.partition(\": \")\n _, _, status = line.rpartition(\" - \")\n rows.append((name.strip(), status.strip()))\nrows.sort()\nfor name, status in rows:\n print(name + \": \" + status)\nprint(\"count=\" + str(len(rows)))\nall_connected = len(rows) > 0\nfor _, status in rows:\n if \"Connected\" not in status:\n all_connected = False\nprint(\"all_connected=\" + str(all_connected))\nok = (rc == \"0\") and all_connected\nraise SystemExit(0 if ok else 1)\nPY", + "exit": 0, + "duration_s": 1.416, + "output_sha256": "e9cb063aaaa533b0784fe1c29fece9b4df655f35d6f3ecc87bc4480b31204975", + "output_excerpt": "ai-memory: \u2714 Connected\nopenaiDeveloperDocs: \u2714 Connected\nplugin:context-mode:context-mode: \u2714 Connected\nserena: \u2714 Connected\nsocraticode: \u2714 Connected\ncount=5\nall_connected=True\n" + } + ], + "tool_versions": { + "claude-code": "2.1.283" + }, + "observed_at_utc": "2026-09-27T08:16:04Z", + "result": "pass", + "claim": "On host mac-coordinator-64gb-20260925 (macOS arm64), the installed Claude Code client, resolved and versioned by the first command below, performs a real headless turn from a freshly created scratch working directory under this Mac's user-scope client-layer profile (~/.claude): given a fixture file it creates itself with a random line count (7-96), `claude -p --output-format stream-json --verbose` replies with the correct count, while the run's init event reports the loaded profile's agent/skill/plugin/MCP-server/slash-command/tool counts and every configured MCP server's connection status. The transcript's own tool_use events are scanned and every distinct name printed; the check fails unless a `Read` tool_use is present, so 'reads the file with its own Read tool' is a checked claim here, not an assumption (the model may use other tools in the same turn; all used tool names are printed, never their input). The same command then re-runs the identical check against the identical transcript with a deliberately wrong expected count as a negative control and confirms that comparison is rejected (a self-test of the checker's discriminating power on one transcript, not a second turn where the model itself answered wrong). A separate `claude mcp list` from another fresh scratch directory captures its own exit code directly with no shell pipe between it and the check, and the check fails unless that exit code is 0 and every reported server's status contains 'Connected'. All commands exit 0 only when their respective checks pass.", + "limitations": [ + "Recorded from a Claude Code session in a git worktree of this repository (see this receipt's own catalog_revision), not a pinned install checkout; the first command's --version reports 2.1.283, newer than the catalog's claude-code pin 2.1.278, so this receipt is recorded with --allow-unbound-version and does not count toward the winner's status.", + "second_physical_machine is declared, not proven by this file: this host's measured profile (evidence/artifacts/hw-profiles/mac-coordinator-64gb-20260925/profile.json) differs from the catalog's WSL authoring laptop. The receipt carries only the recorder's self review; accepted needs an independent review from a separate session.", + "Counts, connection statuses and tool_use names only: no MCP server command line, argument, environment value, session id, uuid or working-directory path is copied into this receipt; tool_use blocks are scanned only for their name field, never their input (which could carry file contents or paths), and the underlying stream-json/mcp list output is never itself echoed to stdout.", + "This receipt exercises the native-clients role (a version check, one headless turn and an MCP listing); it does not exercise claude-code's owned-writing-child role in the workers layer, which needs a different command shape.", + "The negative control in command 2 re-runs the same in-transcript check with a deliberately wrong expected value; it demonstrates the comparison logic rejects a mismatch on one real transcript, not that a second, independent model turn produced a wrong answer.", + "This turn ran claude -p with no --permission-mode/--allowedTools/--permission-prompts; the init event's own permissionMode is bypassPermissions, inherited from this profile's user-scope settings.json, so every tool call in the turn was pre-approved. docs/harness-rules-convergence-20260922.md's PERM-03 recommends an explicit --permission-mode (or --allowedTools) plus --permission-prompts none for an unattended headless run; this receipt is a known, unremedied deviation (fixture-only input in a fresh mktemp directory, no mutation evidenced)." + ], + "evidence_class": "native_proven", + "reviews": [ + { + "kind": "self", + "ref": "scripts/host_receipts.py record", + "verdict": "agree", + "at_utc": "2026-09-27T08:16:04Z", + "reviewer": { + "identity_sha256": "91719ef8aa813c0bf50b26570098baa57e4c043d7d23d4cc5c26ce7c17710954", + "model": "claude-sonnet-5" + } + } + ], + "layer_refs": [ + { + "catalog": "foundation", + "layer_id": "native-clients" + } + ], + "supersedes": "mac-coordinator-64gb-20260925--claude-code--use--20260927-2" +} diff --git a/evidence/hosts/mac-coordinator-64gb-20260925/mac-coordinator-64gb-20260925--codex--use--20260927-3.json b/evidence/hosts/mac-coordinator-64gb-20260925/mac-coordinator-64gb-20260925--codex--use--20260927-3.json new file mode 100644 index 000000000..1beb9ba85 --- /dev/null +++ b/evidence/hosts/mac-coordinator-64gb-20260925/mac-coordinator-64gb-20260925--codex--use--20260927-3.json @@ -0,0 +1,87 @@ +{ + "schema_version": 1, + "id": "mac-coordinator-64gb-20260925--codex--use--20260927-3", + "kind": "host_acceptance", + "host": { + "host_id": "mac-coordinator-64gb-20260925", + "platform_id": "macos-arm64", + "os": "macos", + "architecture": "arm64", + "second_physical_machine": true, + "hardware_profile_ref": "mac-coordinator-64gb-20260925" + }, + "catalog_revision": "c60f3ec5cd9ee30edb95799bb69fe470dccbdce3", + "recorded_by": { + "identity_sha256": "91719ef8aa813c0bf50b26570098baa57e4c043d7d23d4cc5c26ce7c17710954", + "model": "claude-sonnet-5" + }, + "component_id": "codex", + "stage": "use", + "commands": [ + { + "cmd": "p=$(command -v codex)\necho \"resolved: $p\"\necho \"readlink: $(readlink -f \"$p\" 2>/dev/null || echo \"$p (not a symlink)\")\"\ncodex --version\nrc=$?\necho \"file_type: $(file \"$p\" | sed 's/^[^:]*: //')\"\necho \"chatgpt_app_reference_count: $(grep -c \"ChatGPT.app\" \"$p\" 2>/dev/null || echo 0)\"\nexit \"$rc\"", + "exit": 0, + "duration_s": 0.031, + "output_sha256": "ea61e2c71fcd24712fa4400cd5a5e14e9ad305e8d15bb6278a613db22b348bc9", + "output_excerpt": "resolved: ~/.local/bin/codex\nreadlink: ~/.local/bin/codex\ncodex-cli 0.158.0-alpha.2.1\nfile_type: POSIX shell script text executable, ASCII text\nchatgpt_app_reference_count: 1\n" + }, + { + "cmd": "D=\"$(mktemp -d)\"\nn=$((7 + RANDOM % 90))\n: > \"$D/fixture.txt\"\nfor i in $(seq 1 \"$n\"); do echo $((RANDOM % 900 + 1)) >> \"$D/fixture.txt\"; done\nreal=$(wc -l < \"$D/fixture.txt\" | tr -d ' ')\n\"$HOME/.local/bin/codex\" exec -C \"$D\" --skip-git-repo-check --sandbox read-only --ephemeral --json \"Count the lines in the file fixture.txt in your working directory using your own tools, then reply with exactly one line of the form COUNT= and nothing else.\" < /dev/null > \"$D/out.jsonl\" 2> \"$D/err.log\"\nrc=$?\npython3 - \"$real\" \"$rc\" \"$D/out.jsonl\" \"$D\" <<'PY'\nimport json, re, sys\nreal, rc, path, scratch = sys.argv[1], sys.argv[2], sys.argv[3], sys.argv[4]\nevents = []\nfor line in open(path):\n line = line.strip()\n if not line:\n continue\n try:\n events.append(json.loads(line))\n except ValueError:\n continue\n\ndef check(expected):\n kinds = {}\n ran_command = False\n seen_cmd = None\n got = None\n for ev in events:\n item = ev.get(\"item\") or {}\n t = ev.get(\"type\")\n kinds[t] = kinds.get(t, 0) + 1\n if t == \"item.completed\" and item.get(\"type\") == \"command_execution\" and item.get(\"exit_code\") == 0:\n ran_command = True\n if seen_cmd is None:\n seen_cmd = item.get(\"command\")\n if t == \"item.completed\" and item.get(\"type\") == \"agent_message\":\n m = re.search(r\"COUNT=(\\d+)\", item.get(\"text\") or \"\")\n if m:\n got = m.group(1)\n return ran_command, seen_cmd, got, kinds\n\nran_command, seen_cmd, got, kinds = check(real)\nok = (rc == \"0\") and ran_command and (got == real)\nsanitized_cmd = (seen_cmd or \"\").replace(scratch, \"\")\nprint(\"event_kinds=\" + json.dumps(kinds, sort_keys=True))\nprint(\"command_execution_seen=\" + str(ran_command))\nprint(\"command_execution_text=\" + sanitized_cmd)\nprint(\"positive_control expected=\" + real + \" got=\" + str(got) + \" match=\" + str(got == real))\n\nwrong = str(int(real) + 1)\nran_command2, seen_cmd2, got2, _ = check(wrong)\nneg_ok = (rc == \"0\") and ran_command2 and (got2 == wrong)\nprint(\"negative_control expected=\" + wrong + \" got=\" + str(got2) + \" correctly_rejected=\" + str(not neg_ok))\n\noverall_ok = ok and (not neg_ok)\nraise SystemExit(0 if overall_ok else 1)\nPY", + "exit": 0, + "duration_s": 23.899, + "output_sha256": "195c83fdf124f936ee07129768c7b973000f2c096da7f75fd1e9d9b1a6885747", + "output_excerpt": "event_kinds={\"item.completed\": 4, \"item.started\": 2, \"thread.started\": 1, \"turn.completed\": 1, \"turn.started\": 1}\ncommand_execution_seen=True\ncommand_execution_text=/bin/zsh -lc 'cat ~/.codex/plugins/cache/context-mode/context-mode/1.0.169/skills/context-mode/SKILL.md'\npositive_control expected=71 got=71 match=True\nnegative_control expected=72 got=71 correctly_rejected=True\n" + }, + { + "cmd": "\"$HOME/.local/bin/codex\" mcp list --json < /dev/null 2>&1 | python3 -c \"\nimport json, os, sys, tomllib\nraw = sys.stdin.read()\ntry:\n data = json.loads(raw)\nexcept ValueError:\n print('PARSE_ERROR: ' + raw[:120])\n raise SystemExit(1)\nrows = []\nfor item in data:\n transport = item.get('transport') or {}\n rows.append((item.get('name'), item.get('enabled'), transport.get('type')))\nrows.sort(key=lambda r: str(r[0]))\ncfg = tomllib.load(open(os.path.expanduser('~/.codex/config.toml'), 'rb'))\ndeclared = set((cfg.get('mcp_servers') or {}).keys())\nlive = {r[0] for r in rows}\nmissing = sorted(declared - live)\nlive_only = sorted(live - declared)\nprint('declared_count=' + str(len(declared)) + ' live_count=' + str(len(rows)) + ' declared_missing_from_live=' + str(missing) + ' live_only_not_in_config_toml=' + str(live_only))\nfor name, enabled, ttype in rows:\n print(str(name) + ' | enabled=' + str(enabled) + ' | transport=' + str(ttype))\nraise SystemExit(0 if not missing else 1)\n\"", + "exit": 0, + "duration_s": 0.51, + "output_sha256": "0e98bae81417ffb609ec72022b0137db70e89ae7b9dc9757d9c807093fa37c31", + "output_excerpt": "declared_count=8 live_count=10 declared_missing_from_live=[] live_only_not_in_config_toml=['codex_app', 'cua_repl']\nai-memory | enabled=True | transport=streamable_http\ncodex_app | enabled=False | transport=stdio\ncontext-mode | enabled=True | transport=stdio\ncua_repl | enabled=True | transport=stdio\nheadroom | enabled=True | transport=stdio\nnode_repl | enabled=True | transport=stdio\nopenaiDevelope" + }, + { + "cmd": "\"$HOME/.local/bin/codex\" features list < /dev/null 2>&1 | python3 -c \"\nimport os, sys, tomllib\nlines = [l.rstrip(chr(10)) for l in sys.stdin if l.strip()]\ntotal = len(lines)\nseen = {}\nfor l in lines:\n parts = l.split()\n if len(parts) >= 2 and parts[0] in ('daemon_auto_start', 'hooks'):\n seen[parts[0]] = parts[-1].lower() == 'true'\ncfg = tomllib.load(open(os.path.expanduser('~/.codex/config.toml'), 'rb'))\ndeclared = cfg.get('features') or {}\nok = True\nfor name in ('daemon_auto_start', 'hooks'):\n want = bool(declared[name]) if name in declared else None\n got = seen.get(name)\n match = (want is None) or (got == want)\n ok = ok and (got is not None) and match\n print(name + ': cli=' + str(got) + ' config_declares=' + str(want) + ' match=' + str(match))\nprint('total_features=' + str(total))\nraise SystemExit(0 if ok else 1)\n\"", + "exit": 0, + "duration_s": 0.052, + "output_sha256": "156b7cfc9d55193f581107147102f5435dc4d671b3e707973176a32455d9d237", + "output_excerpt": "daemon_auto_start: cli=False config_declares=False match=True\nhooks: cli=True config_declares=True match=True\ntotal_features=150\n" + } + ], + "tool_versions": { + "codex": "0.158.0-alpha.2.1" + }, + "observed_at_utc": "2026-09-27T08:15:36Z", + "result": "pass", + "claim": "On host mac-coordinator-64gb-20260925 (macOS arm64), the installed Codex client, resolved and versioned by the first command below (its own exit code, not a later echo's, decides the command's result), performs a real `codex exec --skip-git-repo-check --sandbox read-only --ephemeral` turn from a freshly created scratch working directory: given a fixture file it creates itself with a random line count (7-96), the run's `--json` event stream contains a real `command_execution` item whose own command text is captured and printed (scratch path sanitized), which exited 0, and its final agent message reports the correct count; the same command then re-runs the identical check against the identical transcript with a deliberately wrong expected count as a negative control and confirms that comparison is rejected (a self-test of the checker's discriminating power on one transcript, not a second turn where the model itself answered wrong). `codex mcp list --json` is compared against this host's own ~/.codex/config.toml `[mcp_servers.*]` tables: every server config.toml declares is present live (this alone gates the command's exit code), and any live server config.toml does not declare is printed separately as `live_only_not_in_config_toml`, disclosed rather than treated as a failure (config.toml's declared servers are not this host's whole live MCP surface; see limitations). `codex features list`'s live `daemon_auto_start`/`hooks` booleans are compared against config.toml's own declared values. Unlike the superseded -2 receipt's claim, this one does not assert `approval_policy` or `sandbox_mode`: no command here checks either value live, and the turn above explicitly overrides sandbox to read-only for safety; both are reported only as a direct config.toml read (source_review class) in the evidence-PR README's Codex section. All commands exit 0 only when their respective check passes.", + "limitations": [ + "Recorded from a Claude Code session in a git worktree of this repository (see this receipt's own catalog_revision), not a pinned install checkout; the first command's --version reports 0.158.0-alpha.2.1, newer than the catalog's codex pin 0.155.1, so this receipt is recorded with --allow-unbound-version and does not count toward the winner's status.", + "The resolved codex on this host is a shell-script launcher at ~/.local/bin/codex whose own comment says it runs \"the ChatGPT-bundled Codex through the app's declared entrypoint\"; the first command's file_type and chatgpt_app_reference_count lines show this without printing the launcher's contents. The tested binary is therefore the ChatGPT desktop app's bundled Codex CLI build, not a separately downloaded openai/codex release of the winner's pin.", + "second_physical_machine is declared, not proven by this file: this host's measured profile (evidence/artifacts/hw-profiles/mac-coordinator-64gb-20260925/profile.json) differs from the catalog's WSL authoring laptop. The receipt carries only the recorder's self review; accepted needs an independent review from a separate session.", + "Names, booleans, counts and the model's own recorded shell command are captured; no MCP server config, args, env, url or cwd, and no session id or working-directory path is copied into this receipt (the scratch directory is replaced with in the printed command text; the mcp/features listings are filtered inline in their own commands before anything reaches stdout).", + "This receipt exercises the native-clients role (a version/channel check, one bounded exec turn and two read-only listing/feature checks); it does not exercise codex's structured-session-control role in the agent-sdks layer (the streamed events above are read for one command_execution item and one final message, not resumed, forked or driven through the SDK).", + "codex exec must be run with stdin redirected from /dev/null: without it, it blocks indefinitely on \"Reading additional input from stdin...\" before doing any work. This is documented upstream behavior, not new to this host or build: evidence/artifacts/gap-wave2-20260923/foundation__quality-evaluation/README.md (codex-cli 0.155.1, tag rust-v0.155.1, codex-rs/exec/src/lib.rs resolve_root_prompt's blocking read_to_end on stdin), observed again here on codex-cli 0.158.0-alpha.2.1. Each exec command above already redirects stdin from /dev/null.", + "The live `codex mcp list --json` surface includes two servers this host's config.toml does not declare: cua_repl (enabled) and codex_app (disabled). Both are provided by Codex plugins enabled in config.toml (unified-computer-use@openai-bundled and codex-app-tools@openai-bundled respectively), each installed from the ChatGPT desktop app's bundled openai-bundled marketplace, not from this repository's Stage 1 install; see their own .mcp.json files under ~/.codex/plugins/cache/openai-bundled/. This command's exit code is gated only on config.toml's declared servers all being present live (declared subset of live); an extra live server is disclosed, not a failure, so it cannot make this receipt fail.", + "The negative control in commands 2 re-runs the same in-transcript check with a deliberately wrong expected value; it demonstrates the comparison logic rejects a mismatch on one real transcript, not that a second, independent model turn produced a wrong answer.", + "approval_policy and sandbox_mode are not checked live by any command in this receipt (command 2's exec turn explicitly overrides sandbox to read-only); both are reported only from a direct config.toml read, source_review class, in the evidence-PR README's Codex section, not as a claim of this receipt." + ], + "evidence_class": "native_proven", + "reviews": [ + { + "kind": "self", + "ref": "scripts/host_receipts.py record", + "verdict": "agree", + "at_utc": "2026-09-27T08:15:36Z", + "reviewer": { + "identity_sha256": "91719ef8aa813c0bf50b26570098baa57e4c043d7d23d4cc5c26ce7c17710954", + "model": "claude-sonnet-5" + } + } + ], + "layer_refs": [ + { + "catalog": "foundation", + "layer_id": "native-clients" + } + ], + "supersedes": "mac-coordinator-64gb-20260925--codex--use--20260927-2" +} diff --git a/manifests/evidence.json b/manifests/evidence.json index 1a8a9d284..01804e477 100644 --- a/manifests/evidence.json +++ b/manifests/evidence.json @@ -13058,7 +13058,7 @@ }, { "path": "catalogs/landscape/component-evidence-matrix.json", - "sha256": "377da64df009e127764a359afe3080c9e1b06632323cabc5d22ce89e2bf85334", + "sha256": "4b447dc976dccc0c740299e26373c40e4c8cf2d320f4eb8fa54e593ec27066a3", "bytes": 189734 }, { @@ -13573,7 +13573,7 @@ }, { "path": "docs/component-evidence-matrix.md", - "sha256": "eea012431ea3b86e2e59dccccc8b14d911d925c95752c54fbbe076e2e2b3a80f", + "sha256": "2205a68290b226dd472e25329eae532a9ea862edb0bc15cb3276c297401d8199", "bytes": 19505 }, { @@ -30468,8 +30468,8 @@ }, { "path": "evidence/artifacts/mac-stage1-client-layer-20260927/README.md", - "sha256": "abe13a444f6dce832c44e11434623f9bf3f43ad4e273bf8dbea6e1b82a02ef8f", - "bytes": 12520 + "sha256": "edccf7aacb621146cbbc3c549c7d016e395d3e65804933cbb473ddd96baebb52", + "bytes": 26510 }, { "path": "evidence/artifacts/macos-application-20260924/run-summary.json", @@ -36221,6 +36221,11 @@ "sha256": "8a612acf5d43d131af2871227b29f7d44f07aa9c98fe0a34f3e1832dc83cfd1e", "bytes": 7174 }, + { + "path": "evidence/hosts/mac-coordinator-64gb-20260925/mac-coordinator-64gb-20260925--claude-code--use--20260927-3.json", + "sha256": "71f4475c70a2dddf0143f0288218a021728134a7269c5ba36479db480ca8598d", + "bytes": 9974 + }, { "path": "evidence/hosts/mac-coordinator-64gb-20260925/mac-coordinator-64gb-20260925--claude-code--use--20260927.json", "sha256": "45eb8886eba9eea56fad70d181c299061b0d314c27a21acaa92ee27f73d5d713", @@ -36231,6 +36236,11 @@ "sha256": "9fd2c2dfe47a5422755dd94526eda66347f1550cd069d1d13d4848de1cc55336", "bytes": 10009 }, + { + "path": "evidence/hosts/mac-coordinator-64gb-20260925/mac-coordinator-64gb-20260925--codex--use--20260927-3.json", + "sha256": "dfb3afad5fc07a9dd5d3c1e508fc05e2b7447d9ea03905cb5071dc4dc84ec1a1", + "bytes": 13478 + }, { "path": "evidence/hosts/mac-coordinator-64gb-20260925/mac-coordinator-64gb-20260925--codex--use--20260927.json", "sha256": "49cfbdfc06c5626d3e3244cce2efbad58d37cddc059bcb1ea793f195b7350dd5", From 7a045f3dbd37a3b793fde1a65787e4b9d576e850 Mon Sep 17 00:00:00 2001 From: seathatflowsinourveins <234074349+seathatflowsinourveins@users.noreply.github.com> Date: Sun, 27 Sep 2026 08:26:03 -0400 Subject: [PATCH 05/12] Fix residual native_proven mislabel: rtk-hook-wiring and Qdrant URL are source_review Both claims were checked directly in this session, not through either host receipt's own retained `commands` (neither's command array prints an rtk version or a server address), so they were still labeled `native_proven` in the README even after the prior review-fix pass (b521b798), which relabeled three other rows the same way but left this exact fragment ("rtk-hook-wiring and the Qdrant URL were independently reconfirmed native_proven") unchanged. Confirmed against both -3 receipts' full command arrays: neither runs an rtk command, and the codex mcp-list command's own filter only ever prints name/enabled/transport, never a server URL, by design (to avoid capturing MCP server config in the receipt). README: both bullets now state the claim is source_review, matching the wording already used for the Codex profile and launchctl-continuity claims in the same document. The PR body's evidence-class table gets the same relabel via gh pr edit (not a commit), alongside refreshed base-commit/ verified-file-list/head references for the origin/main merge below. Also completes the hot-file merge this commit's parent started: took main's manifests/evidence.json (2 new commits landed upstream: 805991bc, 6c073fcc) rather than trust the clean auto-merge, and re-registered only this branch's 7 files (6 receipts + README) through host_receipts.py's register_file. Re-verified: python3 scripts/host_receipts.py validate, scripts/component_matrix.py --write, scripts/new_host_grand_list.py --write, scripts/validate.py (FAILS=0), git diff --check, gitleaks over both touched evidence directories (0 leaks), and the three targeted unittest modules (tests.test_host_receipts, tests.test_component_matrix, tests.test_new_host_grand_list -- 261 tests, OK). Co-Authored-By: Claude Sonnet 5 Claude-Session: https://claude.ai/code/session_017d27CMzkbLezdLv7vAStPu --- .../README.md | 35 +++++++++++-------- manifests/evidence.json | 4 +-- 2 files changed, 23 insertions(+), 16 deletions(-) diff --git a/evidence/artifacts/mac-stage1-client-layer-20260927/README.md b/evidence/artifacts/mac-stage1-client-layer-20260927/README.md index 5de6bb80e..eb9b9f9c0 100644 --- a/evidence/artifacts/mac-stage1-client-layer-20260927/README.md +++ b/evidence/artifacts/mac-stage1-client-layer-20260927/README.md @@ -278,22 +278,29 @@ From the coordinator's Stage 1 run, plus this session's own checks where noted: - The settings template's ai-memory 2.4.1 hooks were not merged; the live hooks reach the running ai-memory 19b6429 build and its own store instead. -- The rtk hook is wired (independently confirmed in this session: Claude's `PreToolUse` - `Bash` matcher runs `rtk hook claude`) and needs rtk >= 0.50.0 plus a five-entry - `exclude_commands` list. This session's own check found **both** rtk builds present on - this host: a `mise`-managed install at 0.49.0, and the ecosystem install at 0.50.0 - (`~/.local/share/codex-ecosystem/bin/rtk`, itself a symlink into a `-staging` tree). A - plain interactive shell resolves the mise-managed 0.49.0. This session read - `~/.claude/settings.json`'s own `env.PATH` value and re-ran `command -v rtk`/`rtk - --version` with exactly that `PATH` (the environment Claude Code gives its hooks, - including `rtk hook claude`): it resolves to the ecosystem install and reports **rtk - 0.50.0**, confirming the "done here" holds for hook execution specifically, not for - every possible invocation of the bare `rtk` command on this host. +- The rtk hook is wired (Claude's `PreToolUse` `Bash` matcher runs `rtk hook claude`) and + needs rtk >= 0.50.0 plus a five-entry `exclude_commands` list. This session's own check + found **both** rtk builds present on this host: a `mise`-managed install at 0.49.0, and + the ecosystem install at 0.50.0 (`~/.local/share/codex-ecosystem/bin/rtk`, itself a + symlink into a `-staging` tree). A plain interactive shell resolves the mise-managed + 0.49.0. This session read `~/.claude/settings.json`'s own `env.PATH` value and re-ran + `command -v rtk`/`rtk --version` with exactly that `PATH` (the environment Claude Code + gives its hooks, including `rtk hook claude`): it resolves to the ecosystem install and + reports **rtk 0.50.0**, so the "done here" holds for hook execution specifically, not + for every possible invocation of the bare `rtk` command on this host. **This check ran + directly in this session, not through either receipt: neither receipt's own retained + `commands` runs an rtk command, so its result is quoted here but not retained the way a + receipt's output is. This claim is `source_review`, not `native_proven` (relabeled on + review; the PR's evidence-class table matches).** - The context-mode cache-heal hook is registered by the plugin itself, not by the settings template. -- The Qdrant URL wired into this profile is `127.0.0.1:6333` (independently confirmed in - this session via `codex mcp list --json`'s `socraticode` entry), not the template's - `16333`. +- The Qdrant URL wired into this profile is `127.0.0.1:6333`, not the template's `16333` + (checked directly in this session against this host's live `codex mcp list --json` + output). **The codex receipt's own retained `mcp list` command deliberately never prints + a server's URL or any other connection detail, to avoid capturing MCP server config in + the receipt (see its `limitations`), so this value is not itself in any retained command + output. This claim is `source_review`, not `native_proven` (relabeled on review; the + PR's evidence-class table matches).** - No Homebrew on this host. - No OTel collector is running yet, so telemetry exports fail silently. - `mcp_oauth_credentials_store` was left at its default. diff --git a/manifests/evidence.json b/manifests/evidence.json index 901421102..6cb60c202 100644 --- a/manifests/evidence.json +++ b/manifests/evidence.json @@ -30488,8 +30488,8 @@ }, { "path": "evidence/artifacts/mac-stage1-client-layer-20260927/README.md", - "sha256": "edccf7aacb621146cbbc3c549c7d016e395d3e65804933cbb473ddd96baebb52", - "bytes": 26510 + "sha256": "e73ae4f3e9b07dc295205416b0849f8b25546919b6339f91f16f4add572d7d27", + "bytes": 27179 }, { "path": "evidence/artifacts/macos-application-20260924/run-summary.json", From 17ba4b1b7af03131e33f1671215959382acb71b8 Mon Sep 17 00:00:00 2001 From: seathatflowsinourveins <234074349+seathatflowsinourveins@users.noreply.github.com> Date: Sun, 27 Sep 2026 09:23:23 -0400 Subject: [PATCH 06/12] Address re-review on #391: non-destructive rollback, disclose ai-memory writes, record codex -4 with a fixture-gated positive control Rewrites the README rollback so it can only add or overwrite files the private backup holds (rsync/cp, no --delete, no rm) and lists every Stage 1 addition it does not remove with its own native removal command. Discloses that every receipt's model turn fires the live ai-memory hooks and writes to the running production store, and that the declared context-mode MCP server and Codex's plugin-provided tools both run outside --sandbox read-only. Records mac-coordinator-64gb-20260925--codex--use--20260927-4.json (supersedes -3): its positive control now gates on and prints a command_execution whose command text actually references the fixture, rather than the first successful command_execution of any kind; also fixes mcp list/features list to use set -o pipefail with stderr discarded before the parse. Relabels the MCP-surface provenance sub-claim source_review instead of native_proven in the README and PR body. Fixes wording that treated the coordinator session and this evidence-PR session as independent observers -- every receipt in this PR carries the identical recorded_by.identity_sha256, so they are the same session -- and reroutes the same-host independent review to a fresh session accordingly. Plus the cross-reference, excerpt-description, pin-wording and merge-count nits from the re-review. Co-Authored-By: Claude Sonnet 5 --- .../landscape/component-evidence-matrix.json | 8 +- docs/component-evidence-matrix.md | 4 +- .../README.md | 347 ++++++++++++------ ...64gb-20260925--codex--use--20260927-4.json | 88 +++++ manifests/evidence.json | 13 +- 5 files changed, 337 insertions(+), 123 deletions(-) create mode 100644 evidence/hosts/mac-coordinator-64gb-20260925/mac-coordinator-64gb-20260925--codex--use--20260927-4.json diff --git a/catalogs/landscape/component-evidence-matrix.json b/catalogs/landscape/component-evidence-matrix.json index 1965e3d1f..e3997c9c1 100644 --- a/catalogs/landscape/component-evidence-matrix.json +++ b/catalogs/landscape/component-evidence-matrix.json @@ -83,8 +83,8 @@ "fail": 0, "independently_reviewed_fail": 0, "independently_reviewed_pass": 0, - "latest": "2026-09-27T08:15:36Z", - "pass": 3 + "latest": "2026-09-27T13:10:37Z", + "pass": 4 }, "qualified_models": [] } @@ -1676,8 +1676,8 @@ "fail": 0, "independently_reviewed_fail": 0, "independently_reviewed_pass": 0, - "latest": "2026-09-27T08:15:36Z", - "pass": 3 + "latest": "2026-09-27T13:10:37Z", + "pass": 4 }, "qualified_models": [] } diff --git a/docs/component-evidence-matrix.md b/docs/component-evidence-matrix.md index a7f7c5e8f..9329dfc75 100644 --- a/docs/component-evidence-matrix.md +++ b/docs/component-evidence-matrix.md @@ -20,7 +20,7 @@ Each winner shows, for linux-wsl2-x86_64 / macos-arm64, its `e2e_state` and host | Layer | Independent review | Winners: e2e_state [receipts] (linux-wsl2-x86_64 / macos-arm64) | | --- | --- | --- | -| `foundation/agent-sdks` | dual_lane_same_winner | codex (host_verified [8/0/5/0] dissented 3 / untested [3/0/0/0]) | +| `foundation/agent-sdks` | dual_lane_same_winner | codex (host_verified [8/0/5/0] dissented 3 / untested [4/0/0/0]) | | `foundation/ci-supply-chain` | dual_lane_same_winner | zizmor (host_verified [2/0/2/0] / untested [0/0/0/0]); syft (host_verified [2/0/2/0] / untested [0/0/0/0]); candidate:actions-attest (accepted [0/0/0/0] / untested [0/0/0/0]) | | `foundation/code-navigation` | dual_lane_adjudicated (adjudication: `evidence/artifacts/layer-verdicts-20260922/adjudication/foundation-code-navigation-20260922.json`) | serena (host_verified [3/0/2/0] dissented 1 / untested [0/0/0/0]) | | `foundation/document-retrieval` | dual_lane_adjudicated (adjudication: `evidence/artifacts/layer-verdicts-20260922/adjudication/foundation-document-retrieval-20260922.json`) | qmd (host_verified [2/0/2/0] / untested [1/0/0/0]); markitdown (host_verified [2/0/2/0] / untested [0/0/0/0]); poppler (host_verified [4/0/3/0] dissented 1 / untested [0/0/0/0]) | @@ -30,7 +30,7 @@ Each winner shows, for linux-wsl2-x86_64 / macos-arm64, its `e2e_state` and host | `foundation/instructions-skills` | dual_lane_adjudicated (adjudication: `evidence/artifacts/layer-verdicts-20260922/adjudication/foundation-instructions-skills-20260922.json`) | affaan-m/ECC (conditional [2/0/1/0] dissented 1 / untested [0/0/0/0]); candidate:typesafe-ai-skills (conditional [0/0/0/0] / untested [0/0/0/0]); candidate:openai-skills (conditional [0/0/0/0] / untested [0/0/0/0]) | | `foundation/isolation` | dual_lane_same_winner | worktrunk (host_verified [2/0/2/0] / host_verified [1/0/1/0]); sandbox-runtime (host_verified [1/0/1/0] / untested [0/0/0/0]) | | `foundation/mcp-surfaces` | dual_lane_same_winner | mcporter (host_verified [6/0/2/0] dissented 4 / untested [0/0/0/0]); mcp-inspector (host_verified [2/0/1/0] dissented 1 / untested [0/0/0/0]) | -| `foundation/native-clients` | dual_lane_same_winner | claude-code (accepted [1/0/1/0] / untested [3/0/0/0]); codex (host_verified [8/0/5/0] dissented 3 / untested [3/0/0/0]) | +| `foundation/native-clients` | dual_lane_same_winner | claude-code (accepted [1/0/1/0] / untested [3/0/0/0]); codex (host_verified [8/0/5/0] dissented 3 / untested [4/0/0/0]) | | `foundation/observation-inference` | dual_lane_adjudicated (adjudication: `evidence/artifacts/layer-verdicts-20260922/adjudication/foundation-observation-inference-20260922.json`) | opentelemetry-collector-contrib (host_verified [2/0/2/0] / untested [0/0/0/0]); prometheus (host_verified [2/0/2/0] / untested [0/0/0/0]); loki (host_verified [2/0/2/0] / untested [0/0/0/0]) | | `foundation/quality-evaluation` | dual_lane_same_winner | promptfoo (host_verified [6/0/2/0] dissented 4 / untested [0/0/0/0]); playwright-test (conditional [0/0/0/0] / untested [1/0/0/0] dissented 1) | | `foundation/recovery-portability` | dual_lane_same_winner | restic (host_verified [3/0/3/0] / untested [1/0/0/0]); candidate:astral-sh-uv (conditional [0/0/0/0] / untested [0/0/0/0]) | diff --git a/evidence/artifacts/mac-stage1-client-layer-20260927/README.md b/evidence/artifacts/mac-stage1-client-layer-20260927/README.md index eb9b9f9c0..abab6fe71 100644 --- a/evidence/artifacts/mac-stage1-client-layer-20260927/README.md +++ b/evidence/artifacts/mac-stage1-client-layer-20260927/README.md @@ -2,49 +2,87 @@ Host request [#382](https://github.com/seathatflowsinourveins/native-agent-stack/issues/382): native-agent-stack becomes this Mac's client-layer writer (Stage 1 of the -[2026-09-27 staged decision](../../../docs/decisions/2026-09-27-mac-single-writer-staged.md)), -with no running service touched. The coordinator session applied the client layer on this -Mac; this document and the [host receipts](#host-receipts) below are the evidence PR for -that work. Facts below are sanitized to names, counts and booleans; where a line was -independently re-run in this evidence-PR session rather than only read from the -coordinator's retained output, it says so. +[2026-09-27 staged decision](../../../docs/decisions/2026-09-27-mac-single-writer-staged.md)). +Stage 1's own install steps stopped, restarted, reconfigured or replaced no +`local.agent-ecosystem.*` service or Ollama (see "Service continuity" below) — narrower than +"no running service touched": every receipt's model turn below is a real client turn on +this host's live, already-running `ai-memory` service, and does write to it (see +"Memory-store writes during recording"). The coordinator session applied the client layer +on this Mac; this document and the [host receipts](#host-receipts) below are the evidence +PR for that work. **The coordinator session and this evidence-PR session are the same +Claude Code session** (every receipt below, from the coordinator's original recordings +through this PR's own, carries the identical `recorded_by.identity_sha256`): where this +document says a line was re-run or reproduced in "this session" at a later point, that is +this same session corroborating its own earlier observation over time, not a second, +independent observer — see "Host receipts" below and the PR's Review section for what an +independent review of this evidence still requires. Facts below are sanitized to names, +counts and booleans; where a line was re-run in this session, later, rather than only read +from an earlier retained capture, it says so. ## Backup and rollback Before any write, the coordinator copied `~/.claude` and `~/.codex` (settings, hooks, plugins, skills, agents) to a private, dated, `0700` folder outside every worktree: 4,516 files, manifest sha256 `a7478603be747dfd52a18dd05f4f0d80510af5bd736c7af4581c0e7cd6b2c5c4`. -`auth.json`, transcripts, sessions, history and caches were excluded. The backup folder's -path is not recorded here (personal path). **Not confirmed by this session:** whether the -4,516-file manifest also covers `~/.claude.json` (a separate file, not under `~/.claude`, -that holds the user-scope MCP registration Stage 1 changed) is not stated in the -coordinator's report, and this session did not re-hash the private manifest to check either -way. +The backup folder's path is not recorded here (personal path). -**Rollback (unrehearsed on this host; replaces Stage 1's additions instead of merging over -them):** +**Never in the backup, and never touched by the rollback below, in either direction:** +credentials (the Codex credential store `~/.codex/auth.json`; Claude Code's own native +credential store, not a file this backup or rollback names), transcripts, sessions, history +files or caches, for both clients. The rollback below only ever adds or overwrites files +that the backup does hold; it is structurally unable to delete any of these, because it +never runs `rm` or `rsync --delete` against a live client tree. + +**Rollback — the one-line form (restores only what the backup holds, in place, over the +live trees; adds and overwrites, never moves or deletes anything):** + +```sh +rsync -a /claude/ ~/.claude/ && cp -p /claude.json ~/.claude.json && rsync -a /codex/ ~/.codex/ +``` + +Spelled out: ```sh -mv ~/.claude ~/.claude.pre-rollback && mv ~/.codex ~/.codex.pre-rollback -rsync -a --delete \ - --exclude 'auth.json' --exclude 'transcripts/' --exclude 'sessions/' \ - --exclude 'history*' --exclude '*cache*' \ - "/claude/" ~/.claude/ -rsync -a --delete "/codex/" ~/.codex/ -# ~/.claude.json: restore from the backup only once it is confirmed to be in the manifest -# (see above); otherwise leave the live ~/.claude.json alone. -cp ~/.claude.pre-rollback/auth.json ~/.claude/auth.json 2>/dev/null -rsync -a ~/.claude.pre-rollback/transcripts/ ~/.claude/transcripts/ 2>/dev/null -rsync -a ~/.claude.pre-rollback/sessions/ ~/.claude/sessions/ 2>/dev/null -rm -rf ~/.claude.pre-rollback ~/.codex.pre-rollback +rsync -a "/claude/" ~/.claude/ +cp -p "/claude.json" ~/.claude.json +rsync -a "/codex/" ~/.codex/ ``` -The previous one-line "copy the backup's files back over `~/.claude`/`~/.codex`" merges -rather than replaces: Stage 1 added agents, guard hooks, skills, plugins and workflows (see -below), and a copy-over leaves every one of those additions in place, so following it would -not actually undo Stage 1. The `rsync --delete` form above removes what Stage 1 added while -keeping the excluded files. `apply_claude_settings.py` also left its own timestamped -`settings.json` backup alongside the live one, independent of the manifest above. +No `--delete` on either `rsync`, and no `rm` anywhere in this procedure: every command only +adds a file the backup holds or overwrites a live file with the backup's copy, so a wrong +`` path, a partial run, or stopping partway through never deletes anything — +worst case, an unwritable destination or a missing source makes one line fail (non-zero +exit) while leaving every live file exactly as it was, and the remaining lines are still +safe to run. The coordinator's report does not state whether the 4,516-file manifest +covers a sibling `claude.json` next to its `claude/` and `codex/` folders (this session did +not re-hash the private manifest to check); the `cp -p` line is included on a best-effort +basis regardless — a missing source makes only that one `cp` fail, touching nothing, and +the two `rsync` lines are unaffected either way. + +This restores Stage 1's own overwrites (settings.json, config.toml and the other files the +backup held before Stage 1 touched them). It does **not** remove anything Stage 1 *added* +that the backup, by construction, never had a prior copy of to restore. Undo each with its +own native command (all read-only to verify first: `claude plugin list`, `claude mcp list`, +`codex mcp list`, `codex plugin list`): + +| Stage 1 addition | Native removal | +| --- | --- | +| The 10 catalog agents ([`adoption/agents/claude/`](../../../adoption/agents/claude/)) under `~/.claude/agents/` | `rm ~/.claude/agents/{blind-adjudicator,blind-judge,blind-lane-reviewer,evidence-reviewer,isolated-builder,security-reviewer,semantic-evidence-reviewer,source-scout,stack-researcher,stack-verifier}.md` | +| The two guard hooks, `~/.claude/hooks/secret_path_guard.py` and `~/.claude/hooks/effort-default-guard.py` | `rm ~/.claude/hooks/secret_path_guard.py ~/.claude/hooks/effort-default-guard.py` (their `hooks` entries in `settings.json` go with the settings restore below) | +| `~/.claude/workflows` | `rm -rf ~/.claude/workflows` | +| The `context-mode`, `claude-hud` and `codex` Claude plugins | `claude plugin uninstall context-mode@context-mode`, `claude plugin uninstall claude-hud@claude-hud`, `claude plugin uninstall codex@openai-codex` | +| The `serena` user-scope Claude MCP registration | `claude mcp remove serena -s user` | +| The Codex MCP servers `serena`, `headroom` and `qmd` | `codex mcp remove serena`, `codex mcp remove headroom`, `codex mcp remove qmd` | +| The Codex `context-mode` plugin | `codex plugin remove context-mode@context-mode` | +| `~/.codex/RTK.md` | `rm ~/.codex/RTK.md` (the inline RTK block this file's text was copied into, inside `~/.codex/AGENTS.md` — a pre-existing file, see "Codex" above — needs manual editing to remove; deleting `AGENTS.md` itself would remove more than Stage 1 added) | +| `~/.codex/app-server-daemon/settings.json` | `rm ~/.codex/app-server-daemon/settings.json` | +| The pinned skills manifest ([`adoption/skills/manifest.json`](../../../adoption/skills/manifest.json)) | ` remove --all` (see "Skills" below for this host's `` path) | + +`apply_claude_settings.py` also wrote its own timestamped backup of the pre-Stage-1 +`~/.claude/settings.json`, separate from the private folder backup above; restoring that +one file undoes every `settings.json` edit (both guard hooks' registration, the plugin and +MCP entries, `effortLevel`, etc.) in a single step, but it does not uninstall the plugin, +MCP-server or skill payloads themselves — those still need the commands above. ## Service continuity @@ -59,15 +97,19 @@ work showed the same four labels, unchanged: | `local.agent-ecosystem.qdrant` | PID present, last exit 0 | PID present, last exit 0 | same PID, last exit 0 | No `local.agent-ecosystem.*` service or Ollama was stopped, replaced or duplicated. This -session independently re-ran `launchctl list | grep -E 'agent-ecosystem|native-stack'` -while preparing this PR (over an hour after the coordinator's "after" capture): all three -running PIDs were still the exact same PIDs as both the "before" and "after" captures, and +session later re-ran `launchctl list | grep -E 'agent-ecosystem|native-stack'` while +preparing this PR (over an hour after the coordinator's "after" capture, and — see the +intro above — the same Claude Code session as the one that took it): all three running +PIDs were still the exact same PIDs as both the "before" and "after" captures, and `maintenance` was still not running with the same last exit code, which is stronger -continuity evidence than a single before/after pair. The "Before" and "After" columns above -are the coordinator's own captures, relayed here and not independently re-verifiable by this -session (the same situation as the backup manifest above); only the "This session, live" -column is something this session directly watched happen. See the PR's evidence-class -table: this claim is `source_review` overall, not `native_proven`, for exactly that reason. +continuity evidence over time than a single before/after pair, though still this one +session's own observations rather than a second observer's. The "Before" and "After" +columns above are the coordinator's own earlier captures, relayed here rather than +re-observed at the time (the same situation as the backup manifest above, and, being an +earlier point in time, not something even this same session can go back and re-verify); +only the "This session, live" column is something this session directly watched happen +just now. See the PR's evidence-class table: this claim is `source_review` overall, not +`native_proven`, for exactly that reason. ## Headless read-back (names and counts only) @@ -77,9 +119,10 @@ directory, parsed for its `init` event: - `permissionMode`: `bypassPermissions`; `model`: `claude-opus-5-5[1m]` - agents: 18; skills: 67; plugins: 11; MCP servers: 5 (all `connected`); slash commands: 107; tools: 118 -This session's own [claude-code host receipt](#host-receipts) independently reproduced the -same shape (18/67/11/5-connected/107/118) from a fresh scratch turn, so the counts are -reproducible, not a one-off capture. +This session's own [claude-code host receipt](#host-receipts) reproduced the same shape +(18/67/11/5-connected/107/118) from a fresh scratch turn later, so the counts are +reproducible over time by this session, not only a one-off capture — not a second, +independent observer's confirmation (see the intro above). ## Plugin revision check @@ -141,29 +184,40 @@ not claim those two as `native_proven`. `features.daemon_auto_start`/`features.h cross-checked live by the [codex host receipt](#host-receipts) below (`codex features list` against config.toml). -**MCP servers: config.toml declares eight, the live surface has ten.** `config.toml` has -eight `[mcp_servers.*]` tables (`ai-memory`, `context-mode`, `headroom`, `node_repl`, -`openaiDeveloperDocs`, `qmd`, `serena`, `socraticode`); the codex receipt's own -`codex mcp list --json` check confirms all eight are present live (`declared` is a subset -of `live`, which gates the command's exit code), but the live listing also has two servers -`config.toml` does not declare: `cua_repl` (enabled) and `codex_app` (disabled), both -printed by the receipt as `live_only_not_in_config_toml`. Each comes from a Codex plugin -enabled in `config.toml`'s `[plugins."*@*"]` tables (`unified-computer-use@openai-bundled` -and `codex-app-tools@openai-bundled` respectively; each plugin's own `.mcp.json` under -`~/.codex/plugins/cache/openai-bundled/` declares its server), installed from the ChatGPT -desktop app's bundled `openai-bundled` marketplace, not from this repository's Stage 1 -install. `config.toml` enables 13 plugins in total (its `[plugins."*@*"]` entries), including -`unified-computer-use`, `computer-use`, `chrome` and `browser`; every Codex turn on this -host — including a `codex exec --sandbox read-only` receipt command — has these -plugin-provided tools available under `approval_policy = "never"`, since the read-only -sandbox restricts shell commands, not plugin tools. Whether this extra surface is accepted -for a never/danger-full-access profile is an open question for the owner, not decided here; -this README previously described the live listing as matching config.toml, which undercounted +**MCP servers: config.toml declares eight, the live surface has ten** (`native_proven`: the +codex receipt's own `codex mcp list --json` check counts both). `config.toml` has eight +`[mcp_servers.*]` tables (`ai-memory`, `context-mode`, `headroom`, `node_repl`, +`openaiDeveloperDocs`, `qmd`, `serena`, `socraticode`); the receipt's check confirms all +eight are present live (`declared` is a subset of `live`, which gates the command's exit +code), but the live listing also has two servers `config.toml` does not declare: `cua_repl` +(enabled) and `codex_app` (disabled), both printed by the receipt as +`live_only_not_in_config_toml`. **Their provenance is `source_review`, not +`native_proven`:** the receipt's `mcp list` command prints only each server's name, +`enabled` state and transport, never where it came from. This session separately read each +plugin's own `.mcp.json` under `~/.codex/plugins/cache/openai-bundled/` directly and found +each server declared by a Codex plugin enabled in `config.toml`'s `[plugins."*@*"]` tables +(`unified-computer-use@openai-bundled` and `codex-app-tools@openai-bundled` respectively), +installed from the ChatGPT desktop app's bundled `openai-bundled` marketplace, not from +this repository's Stage 1 install — a claim no command in any receipt backs. `config.toml` +enables 13 plugins in total (its `[plugins."*@*"]` entries), including `unified-computer-use`, +`computer-use`, `chrome` and `browser`; every Codex turn on this host — including a +`codex exec --sandbox read-only` receipt command — has these plugin-provided tools +available under `approval_policy = "never"`, because the read-only sandbox bounds the +agent's own shell commands, not plugin tools. The same is true of a *declared* server +Stage 1 approved individually: `config.toml`'s own `[mcp_servers.context-mode]` table sets +`default_tools_approval_mode = "approve"` +([`adoption/templates/codex.config.template.toml` lines 115-119](../../../adoption/templates/codex.config.template.toml)), +which is equally outside `--sandbox read-only`'s scope and runs shell commands of its own +(`ctx_execute`) as a separate process, by that same template's own comment (lines 105-114). +See "Memory-store writes during recording" below for what this means for the codex +receipt's exec turn specifically. Whether this extra surface is accepted for a +never/danger-full-access profile is an open question for the owner, not decided here; this +README previously described the live listing as matching config.toml, which undercounted it, and no longer does. `app-server-daemon` `updater.autoUpdateEnabled`: `false` (per the coordinator's report; not -independently re-checked in this session, since that setting lives under `CODEX_HOME` -outside the profile files this session read; stays `source_review` and unverified by any +re-checked in this session either, since that setting lives under `CODEX_HOME` outside the +profile files this session read; stays `source_review` and unverified by any receipt — the codex receipt proves only `features.daemon_auto_start = false`, a different setting). @@ -180,6 +234,45 @@ replace it with no receipt, independent of `features.daemon_auto_start` or the u setting above. Not remedied here; a pinned, separately downloaded `openai/codex` release placed first on `PATH` would close this gap. +## Memory-store writes during recording + +Every model turn behind a host receipt below is a real client turn on this host's live, +already-running `local.agent-ecosystem.ai-memory` service (see "Service continuity" +above), not a synthetic or isolated one. Both clients' user-scope lifecycle hooks are +wired to that service (["Token-efficiency / client-wiring coverage"](#token-efficiency--client-wiring-coverage) +above: `ai-memory hook events present` for Claude, `hooks feature on` for Codex, the +latter cross-checked live by the codex receipt's `codex features list` command), and they +fire on these turns: the claude-code receipt's headless `claude -p` turn and the codex +receipt's `codex exec` turn each write a new session and project into ai-memory's own +store (agent-tagged `claude-code`/`codex` respectively), named after that turn's own +scratch `mktemp` directory. Codex's `--ephemeral` flag governs only that run's own session +history (whether it can later be resumed or forked); it does not disable these hooks or +stop this write. Neither `scripts/host_receipts.py` nor any command in any receipt below +cleans up these writes: they are left in the production ai-memory store, as ordinary +session pages, for the owner to review or remove. + +This corrects two claims made elsewhere that this fact contradicts: + +- The current `claude-code--use--20260927-3` receipt's own limitations (its own text, + frozen — a receipt changes only by recording a new superseding generation) end with + "fixture-only input in a fresh mktemp directory, **no mutation evidenced**." That + sentence is true of the fixture's own scratch directory, but "no mutation evidenced" is + not something any command in that receipt checks: its checker records tool *names* + (`tool_use_names`), never tool inputs or outputs, and nothing in it compares any state + before and after the turn. Read plainly, "no mutation evidenced" could suggest nothing + changed; in fact the turn did write to the ai-memory store, as above, and this receipt is + not evidence either way for anything else. +- The superseded `codex--use--20260927-3` receipt's claim text (and this README, before + this revision) described its exec turn as overriding "sandbox to read-only **for + safety**." As the "Codex" section above now states, `--sandbox read-only` bounds only + the shell commands Codex's own agent loop runs directly; it does not bound the declared + `context-mode` MCP server (approved individually, `default_tools_approval_mode = + "approve"`) or Codex's plugin-provided tools, both of which run outside it. Calling that + flag a safety boundary on the whole turn overstated what it does. The current + `codex--use--20260927-4` receipt (see "Host receipts" below) drops "for safety" and + states this scope explicitly in its own claim and limitations, and its own exec turn + fires the same ai-memory hooks the first bullet above describes. + ## Cross-host coordination The coordinator applied two settings from @@ -215,62 +308,85 @@ committed**. ## Host receipts -Six receipts under +Seven receipts under [`evidence/hosts/mac-coordinator-64gb-20260925/`](../../hosts/mac-coordinator-64gb-20260925/), all `evidence_class: native_proven`, `stage: use`, `result: pass`, `layer_refs: -foundation/native-clients`, `second_physical_machine: true`. Each component's `-3` generation -supersedes `-2`, which supersedes the original; only the `-3` file is current evidence, and -the schema keeps the earlier generations byte-identical rather than deleting them: +foundation/native-clients`, `second_physical_machine: true`. Each component's receipts form +one superseding chain per host/component/stage/date; only the latest generation is current +evidence, and the schema keeps every earlier generation byte-identical rather than deleting +it. claude-code's current generation is `-3` (original, then `-2`, then `-3`); codex's is +`-4` (original, then `-2`, `-3`, then `-4` — recorded in this review-fix pass so its +positive control gates on, and prints, a `command_execution` that actually references the +fixture, rather than the first successful `command_execution` of any kind; see the findings +below): | Receipt | Component / version run | What it backs | | --- | --- | --- | | [`...--claude-code--use--20260927.json`](../../hosts/mac-coordinator-64gb-20260925/mac-coordinator-64gb-20260925--claude-code--use--20260927.json) | claude-code 2.1.283 | superseded twice; version was only a flag here, not a retained command | | [`...--claude-code--use--20260927-2.json`](../../hosts/mac-coordinator-64gb-20260925/mac-coordinator-64gb-20260925--claude-code--use--20260927-2.json) | claude-code 2.1.283 | superseded by `-3` (review findings: the claim asserted a Read-tool check and a `claude mcp list` failure-mode the commands did not perform; see below) | -| [`...--claude-code--use--20260927-3.json`](../../hosts/mac-coordinator-64gb-20260925/mac-coordinator-64gb-20260925--claude-code--use--20260927-3.json) | claude-code 2.1.283 | `command -v`/`readlink -f`/`--version`; a headless `claude -p` turn (random-fixture line-count positive control, matched, plus an in-transcript negative control on a deliberately wrong count, correctly rejected) that also scans the transcript's own `tool_use` events and fails unless a `Read` call is present; and a `claude mcp list` whose own exit code is captured with no shell pipe, failing unless it is 0 and every reported server's status contains `Connected` (5 servers, all Connected) | -| [`...--codex--use--20260927.json`](../../hosts/mac-coordinator-64gb-20260925/mac-coordinator-64gb-20260925--codex--use--20260927.json) | codex-cli 0.158.0-alpha.2.1 | superseded twice; version was only a flag here, not a retained command | -| [`...--codex--use--20260927-2.json`](../../hosts/mac-coordinator-64gb-20260925/mac-coordinator-64gb-20260925--codex--use--20260927-2.json) | codex-cli 0.158.0-alpha.2.1 | superseded by `-3` (review findings: the version-check command's exit code was actually a later `echo`'s, not `codex --version`'s; the claim named a specific model command that was not checked; `approval_policy`/`sandbox_mode` were claimed without a live check; the mcp-list check's summary line and two live-only servers fell outside the 400-char excerpt; see below) | -| [`...--codex--use--20260927-3.json`](../../hosts/mac-coordinator-64gb-20260925/mac-coordinator-64gb-20260925--codex--use--20260927-3.json) | codex-cli 0.158.0-alpha.2.1 | version/channel check whose exit code is now `codex --version`'s own; `codex exec --skip-git-repo-check --sandbox read-only --ephemeral` (random-fixture positive control via a real `command_execution` event, matched — the event's own command text is captured and printed rather than assumed — plus an in-transcript negative control on a deliberately wrong count, correctly rejected); `codex mcp list --json` (declared ⊆ live gates the exit code; the summary line now prints first, and any live-only server is disclosed, not a failure — this run: `cua_repl`, `codex_app`); `codex features list` cross-checked live against `config.toml`. No longer claims `approval_policy`/`sandbox_mode` (see Codex section above) | +| [`...--claude-code--use--20260927-3.json`](../../hosts/mac-coordinator-64gb-20260925/mac-coordinator-64gb-20260925--claude-code--use--20260927-3.json) | claude-code 2.1.283 | current. `command -v`/`readlink -f`/`--version`; a headless `claude -p` turn (random-fixture line-count positive control, matched, plus an in-transcript negative control on a deliberately wrong count, correctly rejected) that also scans the transcript's own `tool_use` events and fails unless a `Read` call is present (it does not check what that `Read` call's input was, only that its name appears among the used tools); and a `claude mcp list` whose own exit code is captured with no shell pipe, failing unless it is 0 and every reported server's status contains `Connected` (5 servers, all Connected). Its own limitations end "no mutation evidenced" — see "Memory-store writes during recording" above for why that is not a check this receipt runs | +| [`...--codex--use--20260927.json`](../../hosts/mac-coordinator-64gb-20260925/mac-coordinator-64gb-20260925--codex--use--20260927.json) | codex-cli 0.158.0-alpha.2.1 | superseded three times; version was only a flag here, not a retained command | +| [`...--codex--use--20260927-2.json`](../../hosts/mac-coordinator-64gb-20260925/mac-coordinator-64gb-20260925--codex--use--20260927-2.json) | codex-cli 0.158.0-alpha.2.1 | superseded by `-3` (review findings: the version-check command's exit code was actually a later `echo`'s, not `codex --version`'s; the claim named a specific model command that was not checked; `approval_policy`/`sandbox_mode` were claimed without a live check; the mcp-list check's summary line and the `socraticode` row fell outside the 400-char excerpt — `cua_repl` and `codex_app` were inside it, not cut off; see below) | +| [`...--codex--use--20260927-3.json`](../../hosts/mac-coordinator-64gb-20260925/mac-coordinator-64gb-20260925--codex--use--20260927-3.json) | codex-cli 0.158.0-alpha.2.1 | superseded by `-4` (review findings: the positive control's checker accepted the first successful `command_execution` in the transcript, whichever it was — this generation's own retained excerpt shows a plugin `SKILL.md` read satisfied it, with no relation to the fixture; `mcp list`/`features list` piped codex's own stderr into the JSON/text parse and discarded codex's own exit code behind `python3`'s exit code; the claim called `--sandbox read-only` a safety boundary though it does not bound the declared `context-mode` MCP server or Codex's plugin-provided tools; see below and "Memory-store writes during recording" above) | +| [`...--codex--use--20260927-4.json`](../../hosts/mac-coordinator-64gb-20260925/mac-coordinator-64gb-20260925--codex--use--20260927-4.json) | codex-cli 0.158.0-alpha.2.1 | current. Version/channel check whose exit code is `codex --version`'s own; `codex exec --skip-git-repo-check --sandbox read-only --ephemeral` (random-fixture positive control gated on, and printing, a `command_execution` event whose own command text contains the fixture's filename and exited 0 — not merely the first successful `command_execution`, whichever it is — plus an in-transcript negative control on a deliberately wrong count, correctly rejected; both `event_kinds`, per top-level event type, and `item_kinds`, per completed item type, are printed); `codex mcp list --json` and `codex features list`, both now run with `set -o pipefail` and codex's own stderr discarded before the parse instead of merged into it (declared ⊆ live gates the exit code together with codex's own; any live-only server is disclosed, not a failure — this run: `cua_repl`, `codex_app`). No longer claims `approval_policy`/`sandbox_mode`, and no longer calls `--sandbox read-only` a safety boundary (see "Codex" and "Memory-store writes during recording" above) | Both installed builds are newer than the current catalog pins (claude-code 2.1.278, codex -0.155.1), so all four `-2`/`-3` receipts use `--allow-unbound-version` and do not by -themselves change either component's `macos-arm64` `platform_status` (still `untested`); -that needs independent review plus the matrix flip rule in +0.155.1), so every `-2` and later receipt uses `--allow-unbound-version` and does not by +itself change either component's `macos-arm64` `platform_status` (still `untested`); that +needs independent review plus the matrix flip rule in [`docs/component-evidence-matrix.md`](../../../docs/component-evidence-matrix.md). **A compliant independent review of these receipts cannot return `agree`, by construction, -and this PR's merge does not wait on that being fixed.** `docs/contributing-evidence.md`'s -four review points include "bound to the winner": the receipt's `tool_versions` must match -the landscape winner's pin. Both `-3` receipts are `--allow-unbound-version` (point 3 -above), and the tested codex is the ChatGPT app's bundled alpha build, which cannot bind to -an `openai/codex` release pin at all. So a review that adequacy-checks all four points must -record `needs_changes` on point 4, which — per `contributing-evidence.md` — withholds -`accepted` regardless of the other three points. The Opus same-host review and the -workstation's GPT-6 cross-family review requested in this PR's Review section can only -adequacy-check points 1-3 (layer role, positive control, backed claims); point 4 fails by -construction, so these receipts stay informational and are not expected to reach `accepted` -through this PR. The route to bound, `accepted`-eligible evidence is either installing the -pinned official `claude-code` 2.1.278 and `openai/codex` 0.155.1 releases and re-recording, -or moving the landscape pins forward through the re-record process in -`docs/contributing-evidence.md` section 4. - -Two findings surfaced while recording the codex receipt, from this session's own +and this PR's merge does not wait on that being fixed.** `docs/contributing-evidence.md` +section 8's four review points include, as point 4, "bound to the winner": the receipt's +`tool_versions` must match the landscape winner's pin. The current claude-code `-3` and +codex `-4` receipts are both `--allow-unbound-version`; the tested codex is the ChatGPT +app's bundled alpha build, which cannot bind to an `openai/codex` release pin at all, at any +version. So a review that adequacy-checks all four points must record `needs_changes` on +point 4, which — per `contributing-evidence.md` — withholds `accepted` regardless of the +other three points. The Opus same-host review and the workstation's GPT-6 cross-family +review requested in this PR's Review section can only adequacy-check points 1-3 (layer +role, positive control, backed claims); point 4 fails by construction, so these receipts +stay informational and are not expected to reach `accepted` through this PR. The route to +bound, `accepted`-eligible evidence is installing the pinned official `claude-code` 2.1.278 +and `openai/codex` 0.155.1 releases and re-recording. For claude-code alone, moving the +landscape pin forward through the re-record process in `docs/contributing-evidence.md` +section 4 is a second route; it is not one for codex, whose tested build is a +ChatGPT-bundled alpha and not an `openai/codex` release at all — no landscape pin change +makes a non-`openai/codex` build bind to an `openai/codex` pin, so only installing the +pinned official release closes this for codex. + +Three findings surfaced while recording the codex receipts, from this session's own observation, not all backed by a retained command: -- **Distribution channel** (backed by the receipt's own retained command 1). - `~/.local/bin/codex` is a POSIX shell script whose own comment says it runs "the - ChatGPT-bundled Codex through the app's declared entrypoint"; the tested - `codex-cli 0.158.0-alpha.2.1` is the ChatGPT desktop app's bundled build, not a separately - downloaded `openai/codex` release. The receipt shows this with a file-type line and a - redacted reference count, not the launcher's contents. +- **Distribution channel.** The first command's `file_type` and + `chatgpt_app_reference_count` lines (backed by that retained command) show + `~/.local/bin/codex` is a shell script that references `ChatGPT.app`, without printing + its contents. That the script's own comment reads "the ChatGPT-bundled Codex through the + app's declared entrypoint", and that the tested `codex-cli 0.158.0-alpha.2.1` is + therefore the ChatGPT desktop app's bundled build rather than a separately downloaded + `openai/codex` release, is this session's own direct read of the script's text + (`source_review`): no command in any receipt generation prints that comment, only the + file-type line and the redacted reference count. - **`codex exec` needs `< /dev/null`** (an unretained observation from this session, not a - new finding: no retained command in either receipt generation runs `codex exec` without + new finding: no retained command in any receipt generation runs `codex exec` without `< /dev/null` to show the alternative). Without redirected stdin, `codex exec` blocks indefinitely on "Reading additional input from stdin...". This is documented upstream behavior, not new to this host or this codex-cli build: [`evidence/artifacts/gap-wave2-20260923/foundation__quality-evaluation/README.md`](../gap-wave2-20260923/foundation__quality-evaluation/README.md) traces the same blocking `read_to_end` on stdin to `codex-cli` 0.155.1's own `resolve_root_prompt` (tag `rust-v0.155.1`, `codex-rs/exec/src/lib.rs`). Every exec command - in both receipts already redirects stdin from `/dev/null`. + in every receipt generation already redirects stdin from `/dev/null`. +- **The superseded `-3` receipt's positive control accepted the wrong command** (fixed in + `-4`, above). Its checker recorded the first `command_execution` item that exited 0, + whichever it was, as the printed "proof" text; this run's own retained excerpt shows that + was a plugin's `SKILL.md` read (`cat + ~/.codex/plugins/cache/context-mode/context-mode/1.0.169/skills/context-mode/SKILL.md`), + unrelated to the fixture the positive control exists to count. The turn's final answer + was still correct on its own terms (the model's own arithmetic on the fixture, checked + against the actual line count), but the *printed command text* was not evidence of how it + got that answer. `-4`'s checker instead requires and prints a `command_execution` whose + own text contains the fixture's filename. ## macOS template findings @@ -328,23 +444,28 @@ From the coordinator's Stage 1 run, plus this session's own checks where noted: ## Limits -- This document and its `-2`/`-3` receipts are the evidence-PR session's own work (the - `-3` generations were recorded in a later, review-fix pass on 2026-09-27, applying this - PR's own review findings); the client-layer install itself (backup, agents/guard/MCP - install, settings render/apply, skills/plugins/workflows, Codex wiring) was performed by - the coordinator session and is reported here from its retained outputs, not re-run end to - end by this session. Where a line was independently re-checked here, it says so above. -- All four current receipts (`-2` superseded, `-3` current, per component) carry only the - recorder's self-review; `accepted` needs an independent review from a separate session - (requested in the PR). See "Host receipts" above: a compliant review of the `-3` - generations cannot return `agree` regardless, because both are `--allow-unbound-version`. +- This document and its `-2` and later receipt generations are the evidence-PR session's + own work (claude-code's `-3` and codex's `-3`/`-4` generations were recorded in later + review-fix passes on 2026-09-27, applying this PR's own review findings); the + client-layer install itself (backup, agents/guard/MCP install, settings render/apply, + skills/plugins/workflows, Codex wiring) was performed earlier by this same session, + acting as coordinator, and is reported here from its retained outputs, not re-run end to + end within this document. Where a line was re-checked here, later, it says so above — see + the intro's note that the coordinator session and this evidence-PR session are the same + session, not two observers. +- Every receipt generation carries only the recorder's self-review; `accepted` needs an + independent review from a separate session (requested in the PR). See "Host receipts" + above for why the current claude-code `-3` and codex `-4` generations cannot reach + `agree` from any reviewer, by construction, regardless of who reviews them (both are + `--allow-unbound-version`). - No `platform_status` is changed by this PR. `adoption/manifest.json`'s macOS platform profile status is a separate, maintainer-judgment field this PR does not touch. -- Counts, booleans, file names and (in the `-3` receipts) tool names and one sanitized - shell command line appear; no session id, uuid, working-directory path, MCP server - command/args/env, or personal path appears in this document or in any receipt's retained - command output (the `-3` receipts replace the scratch directory with `` in the - one command line they print). +- Counts, booleans, file names and (in the current `-3` claude-code and `-4` codex + receipts) tool names, item-type tallies and one sanitized shell command line appear; no + session id, uuid, working-directory path, MCP server command/args/env, or personal path + appears in this document or in any receipt's retained command output (those two current + receipts replace the scratch directory with `` in the one command line they + print). - Host request [#382](https://github.com/seathatflowsinourveins/native-agent-stack/issues/382) still carries the `request:blocked` label as of this PR. Its status comment (written by `scripts/host_requests.py`, updated 2026-09-27T05:08:09Z) gives the reason: "Claude Code's diff --git a/evidence/hosts/mac-coordinator-64gb-20260925/mac-coordinator-64gb-20260925--codex--use--20260927-4.json b/evidence/hosts/mac-coordinator-64gb-20260925/mac-coordinator-64gb-20260925--codex--use--20260927-4.json new file mode 100644 index 000000000..aa158ef67 --- /dev/null +++ b/evidence/hosts/mac-coordinator-64gb-20260925/mac-coordinator-64gb-20260925--codex--use--20260927-4.json @@ -0,0 +1,88 @@ +{ + "schema_version": 1, + "id": "mac-coordinator-64gb-20260925--codex--use--20260927-4", + "kind": "host_acceptance", + "host": { + "host_id": "mac-coordinator-64gb-20260925", + "platform_id": "macos-arm64", + "os": "macos", + "architecture": "arm64", + "second_physical_machine": true, + "hardware_profile_ref": "mac-coordinator-64gb-20260925" + }, + "catalog_revision": "4212116cb093eef2867e874b72a172f8031fea03", + "recorded_by": { + "identity_sha256": "91719ef8aa813c0bf50b26570098baa57e4c043d7d23d4cc5c26ce7c17710954", + "model": "claude-sonnet-5" + }, + "component_id": "codex", + "stage": "use", + "commands": [ + { + "cmd": "p=$(command -v codex)\necho \"resolved: $p\"\necho \"readlink: $(readlink -f \"$p\" 2>/dev/null || echo \"$p (not a symlink)\")\"\ncodex --version\nrc=$?\necho \"file_type: $(file \"$p\" | sed 's/^[^:]*: //')\"\necho \"chatgpt_app_reference_count: $(grep -c \"ChatGPT.app\" \"$p\" 2>/dev/null || echo 0)\"\nexit \"$rc\"", + "exit": 0, + "duration_s": 0.035, + "output_sha256": "ea61e2c71fcd24712fa4400cd5a5e14e9ad305e8d15bb6278a613db22b348bc9", + "output_excerpt": "resolved: ~/.local/bin/codex\nreadlink: ~/.local/bin/codex\ncodex-cli 0.158.0-alpha.2.1\nfile_type: POSIX shell script text executable, ASCII text\nchatgpt_app_reference_count: 1\n" + }, + { + "cmd": "D=\"$(mktemp -d)\"\nn=$((7 + RANDOM % 90))\n: > \"$D/fixture.txt\"\nfor i in $(seq 1 \"$n\"); do echo $((RANDOM % 900 + 1)) >> \"$D/fixture.txt\"; done\nreal=$(wc -l < \"$D/fixture.txt\" | tr -d ' ')\n\"$HOME/.local/bin/codex\" exec -C \"$D\" --skip-git-repo-check --sandbox read-only --ephemeral --json \"Count the lines in the file fixture.txt in your working directory using a shell command, then reply with exactly one line of the form COUNT= and nothing else.\" < /dev/null > \"$D/out.jsonl\" 2> \"$D/err.log\"\nrc=$?\npython3 - \"$real\" \"$rc\" \"$D/out.jsonl\" \"$D\" <<'PY'\nimport json, re, sys\nreal, rc, path, scratch = sys.argv[1], sys.argv[2], sys.argv[3], sys.argv[4]\nevents = []\nfor line in open(path):\n line = line.strip()\n if not line:\n continue\n try:\n events.append(json.loads(line))\n except ValueError:\n continue\n\ndef check(expected):\n kinds = {}\n item_kinds = {}\n ran_command = False\n fixture_cmd = None\n got = None\n for ev in events:\n item = ev.get(\"item\") or {}\n t = ev.get(\"type\")\n kinds[t] = kinds.get(t, 0) + 1\n if t == \"item.completed\":\n it = item.get(\"type\")\n item_kinds[it] = item_kinds.get(it, 0) + 1\n if t == \"item.completed\" and item.get(\"type\") == \"command_execution\" and item.get(\"exit_code\") == 0:\n ran_command = True\n c = item.get(\"command\") or \"\"\n if fixture_cmd is None and \"fixture.txt\" in c:\n fixture_cmd = c\n if t == \"item.completed\" and item.get(\"type\") == \"agent_message\":\n m = re.search(r\"COUNT=(\\d+)\", item.get(\"text\") or \"\")\n if m:\n got = m.group(1)\n return ran_command, fixture_cmd, got, kinds, item_kinds\n\nran_command, fixture_cmd, got, kinds, item_kinds = check(real)\nok = (rc == \"0\") and ran_command and (fixture_cmd is not None) and (got == real)\nsanitized_cmd = (fixture_cmd or \"\").replace(scratch, \"\")\nprint(\"event_kinds=\" + json.dumps(kinds, sort_keys=True))\nprint(\"item_kinds=\" + json.dumps(item_kinds, sort_keys=True))\nprint(\"command_execution_seen=\" + str(ran_command))\nprint(\"fixture_command_execution_seen=\" + str(fixture_cmd is not None))\nprint(\"command_execution_text=\" + sanitized_cmd)\nprint(\"positive_control expected=\" + real + \" got=\" + str(got) + \" match=\" + str(got == real))\n\nwrong = str(int(real) + 1)\nran_command2, fixture_cmd2, got2, _, _ = check(wrong)\nneg_ok = (rc == \"0\") and ran_command2 and (fixture_cmd2 is not None) and (got2 == wrong)\nprint(\"negative_control expected=\" + wrong + \" got=\" + str(got2) + \" correctly_rejected=\" + str(not neg_ok))\n\noverall_ok = ok and (not neg_ok)\nraise SystemExit(0 if overall_ok else 1)\nPY", + "exit": 0, + "duration_s": 10.072, + "output_sha256": "104f2baa282db789bce2209a1afe761b06c255714ea62f4384cd2766a7d94675", + "output_excerpt": "event_kinds={\"item.completed\": 3, \"item.started\": 1, \"thread.started\": 1, \"turn.completed\": 1, \"turn.started\": 1}\nitem_kinds={\"agent_message\": 2, \"command_execution\": 1}\ncommand_execution_seen=True\nfixture_command_execution_seen=True\ncommand_execution_text=/bin/zsh -lc 'wc -l < fixture.txt'\npositive_control expected=32 got=32 match=True\nnegative_control expected=33 got=32 correctly_rejected=True\n" + }, + { + "cmd": "set -o pipefail\n\"$HOME/.local/bin/codex\" mcp list --json < /dev/null 2>/dev/null | python3 -c \"\nimport json, os, sys, tomllib\nraw = sys.stdin.read()\ntry:\n data = json.loads(raw)\nexcept ValueError:\n print('PARSE_ERROR: len=' + str(len(raw)))\n raise SystemExit(1)\nrows = []\nfor item in data:\n transport = item.get('transport') or {}\n rows.append((item.get('name'), item.get('enabled'), transport.get('type')))\nrows.sort(key=lambda r: str(r[0]))\ncfg = tomllib.load(open(os.path.expanduser('~/.codex/config.toml'), 'rb'))\ndeclared = set((cfg.get('mcp_servers') or {}).keys())\nlive = {r[0] for r in rows}\nmissing = sorted(declared - live)\nlive_only = sorted(live - declared)\nprint('declared_count=' + str(len(declared)) + ' live_count=' + str(len(rows)) + ' declared_missing_from_live=' + str(missing) + ' live_only_not_in_config_toml=' + str(live_only))\nfor name, enabled, ttype in rows:\n print(str(name) + ' | enabled=' + str(enabled) + ' | transport=' + str(ttype))\nraise SystemExit(0 if not missing else 1)\n\"", + "exit": 0, + "duration_s": 0.508, + "output_sha256": "0e98bae81417ffb609ec72022b0137db70e89ae7b9dc9757d9c807093fa37c31", + "output_excerpt": "declared_count=8 live_count=10 declared_missing_from_live=[] live_only_not_in_config_toml=['codex_app', 'cua_repl']\nai-memory | enabled=True | transport=streamable_http\ncodex_app | enabled=False | transport=stdio\ncontext-mode | enabled=True | transport=stdio\ncua_repl | enabled=True | transport=stdio\nheadroom | enabled=True | transport=stdio\nnode_repl | enabled=True | transport=stdio\nopenaiDevelope" + }, + { + "cmd": "set -o pipefail\n\"$HOME/.local/bin/codex\" features list < /dev/null 2>/dev/null | python3 -c \"\nimport os, sys, tomllib\nlines = [l.rstrip(chr(10)) for l in sys.stdin if l.strip()]\ntotal = len(lines)\nseen = {}\nfor l in lines:\n parts = l.split()\n if len(parts) >= 2 and parts[0] in ('daemon_auto_start', 'hooks'):\n seen[parts[0]] = parts[-1].lower() == 'true'\ncfg = tomllib.load(open(os.path.expanduser('~/.codex/config.toml'), 'rb'))\ndeclared = cfg.get('features') or {}\nok = True\nfor name in ('daemon_auto_start', 'hooks'):\n want = bool(declared[name]) if name in declared else None\n got = seen.get(name)\n match = (want is None) or (got == want)\n ok = ok and (got is not None) and match\n print(name + ': cli=' + str(got) + ' config_declares=' + str(want) + ' match=' + str(match))\nprint('total_features=' + str(total))\nraise SystemExit(0 if ok else 1)\n\"", + "exit": 0, + "duration_s": 0.041, + "output_sha256": "156b7cfc9d55193f581107147102f5435dc4d671b3e707973176a32455d9d237", + "output_excerpt": "daemon_auto_start: cli=False config_declares=False match=True\nhooks: cli=True config_declares=True match=True\ntotal_features=150\n" + } + ], + "tool_versions": { + "codex": "0.158.0-alpha.2.1" + }, + "observed_at_utc": "2026-09-27T13:10:37Z", + "result": "pass", + "claim": "On host mac-coordinator-64gb-20260925 (macOS arm64), the installed Codex client, resolved and versioned by the first command below (its own exit code, not a later echo's, decides the command's result), performs a real `codex exec --skip-git-repo-check --sandbox read-only --ephemeral` turn from a freshly created scratch working directory: given a fixture file it creates itself with a random line count (7-96) and a prompt that asks for a shell command, the run's `--json` event stream must contain a `command_execution` item whose own command text contains the fixture file's name (`fixture.txt`) and which exited 0 -- not merely the first successful `command_execution` in the transcript, whichever it is, as the superseded `-3` receipt's checker accepted (that generation's own retained excerpt shows a plugin `SKILL.md` read, unrelated to the fixture, satisfied its check). That fixture-referencing command's text is captured and printed (scratch path sanitized), and the transcript's final agent message reports the correct count. The same command then re-runs the identical check against the identical transcript with a deliberately wrong expected count as a negative control and confirms that comparison is rejected (a self-test of the checker's discriminating power on one transcript, not a second turn where the model itself answered wrong). Both `event_kinds` (per top-level event type) and `item_kinds` (per completed item type, e.g. `command_execution`/`agent_message`) are printed. `codex mcp list --json` is compared against this host's own ~/.codex/config.toml `[mcp_servers.*]` tables, run with `set -o pipefail` and codex's own stderr discarded before the pipe rather than merged into the JSON parse (unlike the superseded generations): every server config.toml declares is present live (this alone gates the command's exit code, together with codex's own exit code via pipefail), and any live server config.toml does not declare is printed separately as `live_only_not_in_config_toml`, disclosed rather than treated as a failure (config.toml's declared servers are not this host's whole live MCP surface; see limitations). `codex features list`'s live `daemon_auto_start`/`hooks` booleans are compared against config.toml's own declared values, with the same pipefail fix. This receipt does not assert `approval_policy` or `sandbox_mode`, and does not describe `--sandbox read-only` as a safety boundary: no command here checks either value live, and the read-only sandbox bounds the agent's own shell commands only -- not the declared `context-mode` MCP server (approved individually in config.toml, `default_tools_approval_mode = \"approve\"`) or Codex's plugin-provided tools, both of which run outside it (see limitations, and the evidence-PR README's Codex section, source_review class). All commands exit 0 only when their respective check passes.", + "limitations": [ + "Recorded from a Claude Code session in a git worktree of this repository (see this receipt's own catalog_revision), not a pinned install checkout; the first command's --version reports 0.158.0-alpha.2.1, newer than the catalog's codex pin 0.155.1, so this receipt is recorded with --allow-unbound-version and does not count toward the winner's status.", + "The resolved codex on this host is a shell-script launcher at ~/.local/bin/codex whose own comment says it runs \"the ChatGPT-bundled Codex through the app's declared entrypoint\"; the first command's file_type and chatgpt_app_reference_count lines show this without printing the launcher's contents. The tested binary is therefore the ChatGPT desktop app's bundled Codex CLI build, not a separately downloaded openai/codex release of the winner's pin.", + "second_physical_machine is declared, not proven by this file: this host's measured profile (evidence/artifacts/hw-profiles/mac-coordinator-64gb-20260925/profile.json) differs from the catalog's WSL authoring laptop. The receipt carries only the recorder's self review; accepted needs an independent review from a separate session.", + "Names, booleans, counts, item-type tallies (event_kinds, item_kinds) and the one gated command's own text are captured; no MCP server config, args, env, url or cwd, and no session id or working-directory path is copied into this receipt (the scratch directory is replaced with in the printed command text; the mcp/features listings are filtered inline in their own commands before anything reaches stdout; any other command_execution or agent_message item in the transcript is counted in item_kinds but its own text is never printed).", + "This receipt exercises the native-clients role (a version/channel check, one bounded exec turn and two read-only listing/feature checks); it does not exercise codex's structured-session-control role in the agent-sdks layer (the streamed events above are read for item-type tallies and one gated command_execution/one final message, not resumed, forked or driven through the SDK).", + "codex exec must be run with stdin redirected from /dev/null: without it, it blocks indefinitely on \"Reading additional input from stdin...\" before doing any work. This is documented upstream behavior, not new to this host or build: evidence/artifacts/gap-wave2-20260923/foundation__quality-evaluation/README.md (codex-cli 0.155.1, tag rust-v0.155.1, codex-rs/exec/src/lib.rs resolve_root_prompt's blocking read_to_end on stdin), observed again here on codex-cli 0.158.0-alpha.2.1. Each exec command above already redirects stdin from /dev/null.", + "The live `codex mcp list --json` surface includes two servers this host's config.toml does not declare: cua_repl (enabled) and codex_app (disabled). Both are provided by Codex plugins enabled in config.toml (unified-computer-use@openai-bundled and codex-app-tools@openai-bundled respectively). This command's exit code is gated only on config.toml's declared servers all being present live (declared subset of live); an extra live server is disclosed, not a failure, so it cannot make this receipt fail. That each plugin's own server was installed from the ChatGPT desktop app's bundled openai-bundled marketplace, not from this repository's Stage 1 install, is a direct read of each plugin's own .mcp.json file under ~/.codex/plugins/cache/openai-bundled/, not something this command's name/enabled/transport-only output shows; that provenance detail is source_review class, reported in the evidence-PR README, not a claim of this receipt's command.", + "The negative control in command 2 re-runs the same in-transcript check with a deliberately wrong expected value; it demonstrates the comparison logic rejects a mismatch on one real transcript, not that a second, independent model turn produced a wrong answer.", + "approval_policy and sandbox_mode are not checked live by any command in this receipt. Command 2's exec turn overrides sandbox to read-only, which is not a safety guarantee for the whole turn: the sandbox flag bounds the agent's own shell command_executions, not the declared context-mode MCP server, which config.toml approves individually (default_tools_approval_mode = \"approve\") and which runs shell commands of its own (ctx_execute) outside that sandbox, or Codex's plugin-provided tools (command 3's live_only servers). Both approval_policy and sandbox_mode are reported only from a direct config.toml read, source_review class, in the evidence-PR README's Codex section, not as a claim of this receipt.", + "Command 2's codex exec turn is a real client turn on this host's live, already-running ai-memory service, not a synthetic or isolated one: this host's user-scope Codex hooks (features.hooks, cross-checked live by command 4) fire on it and write a new session and project into that running service's own store (agent=codex), keyed to this command's scratch mktemp directory. `--ephemeral` is codex's own session-history flag (about resuming or forking this run later) and does not disable those hooks or stop that write. Neither this command nor scripts/host_receipts.py cleans up that write; it is left in the production ai-memory store for the owner to review or remove; see the evidence-PR README." + ], + "evidence_class": "native_proven", + "reviews": [ + { + "kind": "self", + "ref": "scripts/host_receipts.py record", + "verdict": "agree", + "at_utc": "2026-09-27T13:10:37Z", + "reviewer": { + "identity_sha256": "91719ef8aa813c0bf50b26570098baa57e4c043d7d23d4cc5c26ce7c17710954", + "model": "claude-sonnet-5" + } + } + ], + "layer_refs": [ + { + "catalog": "foundation", + "layer_id": "native-clients" + } + ], + "supersedes": "mac-coordinator-64gb-20260925--codex--use--20260927-3" +} diff --git a/manifests/evidence.json b/manifests/evidence.json index 7719ea5e8..0804c03e7 100644 --- a/manifests/evidence.json +++ b/manifests/evidence.json @@ -13208,7 +13208,7 @@ }, { "path": "catalogs/landscape/component-evidence-matrix.json", - "sha256": "4b447dc976dccc0c740299e26373c40e4c8cf2d320f4eb8fa54e593ec27066a3", + "sha256": "15ab971b4e16347afb29da1a2e6cb05da99471dfe7b255b932b8fa2f74442f42", "bytes": 189734 }, { @@ -13723,7 +13723,7 @@ }, { "path": "docs/component-evidence-matrix.md", - "sha256": "2205a68290b226dd472e25329eae532a9ea862edb0bc15cb3276c297401d8199", + "sha256": "46b5c8cefc73ba82c0e92f3b06dbd2c3757b2cc01d33c67cf1e2cd6cb651d95f", "bytes": 19505 }, { @@ -30638,8 +30638,8 @@ }, { "path": "evidence/artifacts/mac-stage1-client-layer-20260927/README.md", - "sha256": "e73ae4f3e9b07dc295205416b0849f8b25546919b6339f91f16f4add572d7d27", - "bytes": 27179 + "sha256": "bd8bb6a937acee60e93748f3a1ab3776037f0970b4ab0ba8fd72e314717908c3", + "bytes": 38508 }, { "path": "evidence/artifacts/macos-application-20260924/run-summary.json", @@ -36586,6 +36586,11 @@ "sha256": "dfb3afad5fc07a9dd5d3c1e508fc05e2b7447d9ea03905cb5071dc4dc84ec1a1", "bytes": 13478 }, + { + "path": "evidence/hosts/mac-coordinator-64gb-20260925/mac-coordinator-64gb-20260925--codex--use--20260927-4.json", + "sha256": "3b2c4662cbf0f0e95d93287ccc198fcde052725e3878303f25193d66808dde11", + "bytes": 16527 + }, { "path": "evidence/hosts/mac-coordinator-64gb-20260925/mac-coordinator-64gb-20260925--codex--use--20260927.json", "sha256": "49cfbdfc06c5626d3e3244cce2efbad58d37cddc059bcb1ea793f195b7350dd5", From 392f69609b01bd13d8e86a922d73c22eb15014b9 Mon Sep 17 00:00:00 2001 From: seathatflowsinourveins <234074349+seathatflowsinourveins@users.noreply.github.com> Date: Sun, 27 Sep 2026 10:00:33 -0400 Subject: [PATCH 07/12] Address second re-review on #391: scope skills/workflow rollback, fix ordering and receipt citations Fixes nine defects from an independent Opus re-review of the Stage 1 client-layer README: - Replaces the unscoped ` remove --all` with one `skills remove -g -y` per pinned skill (all 28), citing the decision record's -g scoping rule and lifecycle.md's "never uninstall all user tools to roll back one package". - Replaces the directory-wide workflows delete with a name-and-sha256 verified per-file removal of the 13 files Stage 1 actually placed in ~/.claude/workflows (12 byte-identical to the repo source, one a per-host template render). - Reorders the rollback so every removal runs before the restore -- a restore run first would overwrite the live state the removal table was built from -- and rescopes the "never runs rm" claim to the restore step alone, since removal now legitimately runs rm. - Joins the one-line restore's three commands with `;` instead of `&&` so a missing claude.json backup can't silently skip the codex rsync. - Documents that only two of the four hook files install_claude_profile.py's HOOKS map can place actually exist on this host; the other two were added to that map after Stage 1's own install ran here. - Replaces the blind rm of app-server-daemon/settings.json with a conditional that restores from the private backup if it holds a copy, otherwise removes only the one key this session is known to have written, since the file's prior existence is unrecorded. - Corrects the claim that both current receipts print a sanitized command line: only codex -4 does; claude-code -3 prints tool names only. - Fixes a section citation (contributing-evidence.md section 3 step 8, not section 8). - Adds a sentence labeling the -4 receipt's plugin-to-server attribution (line 63) source_review, read from each plugin's own .mcp.json. Re-registers this branch's evidence files in manifests/evidence.json against main's copy per the docs/lanes.md hot-file protocol (merged origin/main first) and regenerates the component matrix and grand list. Co-Authored-By: Claude Sonnet 5 Claude-Session: https://claude.ai/code/session_017d27CMzkbLezdLv7vAStPu --- .../README.md | 229 ++++++++++++++---- manifests/evidence.json | 4 +- 2 files changed, 185 insertions(+), 48 deletions(-) diff --git a/evidence/artifacts/mac-stage1-client-layer-20260927/README.md b/evidence/artifacts/mac-stage1-client-layer-20260927/README.md index abab6fe71..6314b0eea 100644 --- a/evidence/artifacts/mac-stage1-client-layer-20260927/README.md +++ b/evidence/artifacts/mac-stage1-client-layer-20260927/README.md @@ -26,18 +26,161 @@ plugins, skills, agents) to a private, dated, `0700` folder outside every worktr files, manifest sha256 `a7478603be747dfd52a18dd05f4f0d80510af5bd736c7af4581c0e7cd6b2c5c4`. The backup folder's path is not recorded here (personal path). -**Never in the backup, and never touched by the rollback below, in either direction:** -credentials (the Codex credential store `~/.codex/auth.json`; Claude Code's own native -credential store, not a file this backup or rollback names), transcripts, sessions, history -files or caches, for both clients. The rollback below only ever adds or overwrites files -that the backup does hold; it is structurally unable to delete any of these, because it -never runs `rm` or `rsync --delete` against a live client tree. +**Never in the backup, and never touched by either step below:** credentials (the Codex +credential store `~/.codex/auth.json`; Claude Code's own native credential store, not a file +this backup or rollback names), transcripts, sessions, history files or caches, for both +clients. Neither step deletes any of these: the removal step immediately below runs `rm` (or +`skills remove`) only on the specific Stage 1 files and skills its table names, never on a +credential, transcript, session, history or cache path; the restore step further below runs +no `rm` or `rsync --delete` at all (see the note at that step). + +**Order: removal first, then restore — not the reverse.** The two steps undo different +things. Removal deletes what Stage 1 *added*: files and registrations the backup, by +construction, never held a prior copy of, so restoring cannot touch them. Restore overwrites +live files with the backup's pre-Stage-1 copies (settings.json, config.toml, and so on) *in +place*. Running restore first would rewrite exactly the live state — hook and MCP +registrations, config values — that the removal table below was built from by reading this +host, before removal has used that state to confirm exactly what is still there to delete; +doing removal first, while that state is still live, avoids masking it. This is also the +order the two steps appear in below. + +### Removal (what Stage 1 added) + +Undo each with its own native command (all read-only to verify first: `claude plugin list`, +`claude mcp list`, `codex mcp list`, `codex plugin list`): -**Rollback — the one-line form (restores only what the backup holds, in place, over the -live trees; adds and overwrites, never moves or deletes anything):** +| Stage 1 addition | Native removal | +| --- | --- | +| The 10 catalog agents ([`adoption/agents/claude/`](../../../adoption/agents/claude/)) under `~/.claude/agents/` | `rm ~/.claude/agents/{blind-adjudicator,blind-judge,blind-lane-reviewer,evidence-reviewer,isolated-builder,security-reviewer,semantic-evidence-reviewer,source-scout,stack-researcher,stack-verifier}.md` | +| Two guard hooks under `~/.claude/hooks/` — of the four files [`tools/adoption/install_claude_profile.py`](../../../tools/adoption/install_claude_profile.py)'s `HOOKS` map (lines 48-53) can place; see note below | `rm ~/.claude/hooks/secret_path_guard.py`; `rm ~/.claude/hooks/effort-default-guard.py` (their `hooks` entries in `settings.json` go with the settings restore below) | +| Every file under `~/.claude/workflows/` (13 files; see note below) — never the directory itself | one `rm` per file, listed below | +| The `context-mode`, `claude-hud` and `codex` Claude plugins | `claude plugin uninstall context-mode@context-mode`, `claude plugin uninstall claude-hud@claude-hud`, `claude plugin uninstall codex@openai-codex` | +| The `serena` user-scope Claude MCP registration | `claude mcp remove serena -s user` | +| The Codex MCP servers `serena`, `headroom` and `qmd` | `codex mcp remove serena`, `codex mcp remove headroom`, `codex mcp remove qmd` | +| The Codex `context-mode` plugin | `codex plugin remove context-mode@context-mode` | +| `~/.codex/RTK.md` | `rm ~/.codex/RTK.md` (the inline RTK block this file's text was copied into, inside `~/.codex/AGENTS.md` — a pre-existing file, see "Codex" above — needs manual editing to remove; deleting `AGENTS.md` itself would remove more than Stage 1 added) | +| The `updater.autoUpdateEnabled` key this session wrote into `~/.codex/app-server-daemon/settings.json` (whether the file existed before Stage 1 is not recorded; see note below) | conditional, not a blind `rm` — see note below | +| The 28 skills pinned in [`adoption/skills/manifest.json`](../../../adoption/skills/manifest.json), the skills@1.7.0 manifest Stage 1 installed | one `skills remove -g -y` per skill, listed below | + +**Hooks.** The `HOOKS` map names four files it can place under `~/.claude/hooks/`: +`effort-default-guard.py`, `secret_path_guard.py`, `token-lanes-block.md` and +`token-lanes-subagent-start.py`. Only the first two exist on this host (sha256-verified equal +to their repository source, `adoption/hooks/claude/effort-default-guard.py` and +`scripts/hooks/secret_path_guard.py`); the other two were added to that map by +[#378](https://github.com/seathatflowsinourveins/native-agent-stack/issues/378) +(`0c33b37a`) after Stage 1's own install ran on this host, so there is nothing to remove for +them here. A third file also lives in `~/.claude/hooks/`, `context-mode-cache-heal.mjs` — +that one is not this installer's own: per the [macOS template findings](#macos-template-findings) +above, it is registered by the `context-mode` plugin itself, and goes with that plugin's own +removal command in the table above, not with these two. + +**`~/.claude/workflows/`.** `ls -la ~/.claude/workflows` lists 13 files. Compared by name and +sha256 against this repository's own +[`examples/claude-native/workflows/`](../../../examples/claude-native/workflows) (whose own +`README.md` and `SHA256SUMS` are documentation, not installed files, so they are not expected +here): all 13 names match, and 12 match by sha256 exactly. The 13th, `contract.config.json`, +does not match by sha256 because it is a per-host *render* of that same template — this +host's own absolute paths in place of the template's relative ones — the same gap the +[macOS template findings](#macos-template-findings) above record ("User-scope workflows need +absolute contract paths, which `test-contract-mutations` rejects"), not a different file. +Every file present is therefore accounted for as Stage 1's own; there is nothing in this +directory today that is the user's own to preserve, and all 13 are named individually below, +never the directory itself: ```sh -rsync -a /claude/ ~/.claude/ && cp -p /claude.json ~/.claude.json && rsync -a /codex/ ~/.codex/ +rm ~/.claude/workflows/check-syntax.mjs +rm ~/.claude/workflows/child-usage.mjs +rm ~/.claude/workflows/codex-cross-review.mjs +rm ~/.claude/workflows/contract.config.json +rm ~/.claude/workflows/layer-verdict-lane.js +rm ~/.claude/workflows/readiness-audit.js +rm ~/.claude/workflows/review-changes.js +rm ~/.claude/workflows/test-child-usage.mjs +rm ~/.claude/workflows/test-codex-envelope.mjs +rm ~/.claude/workflows/test-contract-mutations.mjs +rm ~/.claude/workflows/test-envelope.mjs +rm ~/.claude/workflows/test-usage-receipts.mjs +rm ~/.claude/workflows/vendored-lanes.json +``` + +Any file that later appears in `~/.claude/workflows/` outside this list of 13 names is the +user's own and stays; re-run the same name-and-sha256 comparison against +`examples/claude-native/workflows/` before assuming otherwise. + +**`~/.codex/app-server-daemon/settings.json`.** This Mac's coordinator session wrote this +file during Stage 1 with `{"updater": {"autoUpdateEnabled": false}}` — read directly again in +this round-2 fix pass, still exactly that one key and value. Whether the file existed before +Stage 1 is not recorded, so rollback must not delete it blindly: if the private backup holds +a copy, the restore step below already puts that copy back (its `codex/` rsync is not +`--delete`d, so it only overwrites, never skips, this path); if the backup holds no such +file, remove only the key Stage 1 is known to have written, not the file: + +```sh +if [ -f "/codex/app-server-daemon/settings.json" ]; then + : # nothing to do here — the restore step's rsync of /codex/ already restores it +else + python3 -c " +import json, pathlib +p = pathlib.Path.home() / '.codex/app-server-daemon/settings.json' +d = json.loads(p.read_text()) +d.get('updater', {}).pop('autoUpdateEnabled', None) +p.write_text(json.dumps(d, indent=2) + chr(10)) +" +fi +``` + +**Skills.** The skills@1.7.0 CLI's `remove` needs `-g` for global scope: Stage 1 installed +these skills globally, and without `-g` the CLI acts on the current directory's *project* +skills instead, not the global ones Stage 1 placed +(`docs/decisions/2026-09-25-skills-trial-and-usage.md:43`, verbatim: "`skills remove +-g -y` (no `-a`) removes the canonical copy, both links and the lock entry" — the same call +this repository's own installer runs on a mismatched install, +[`tools/adoption/install_skills.py`](../../../tools/adoption/install_skills.py) lines 17-21 +and its `remove` call at line 196). The `skills` binary is the pinned 1.7.0 package the +[Skills](#skills) section below names — there is no separate `` path to look up. +`DISABLE_TELEMETRY=1` matches the manifest's own `cli.env` and what the installer sets. There +is no bulk form here, only one call per skill +([`adoption/lifecycle.md`](../../../adoption/lifecycle.md):100, verbatim: "Never uninstall +all user tools to roll back one package"): + +```sh +DISABLE_TELEMETRY=1 skills remove typesafe-ai -g -y +DISABLE_TELEMETRY=1 skills remove gh-fix-ci -g -y +DISABLE_TELEMETRY=1 skills remove security-best-practices -g -y +DISABLE_TELEMETRY=1 skills remove iterative-retrieval -g -y +DISABLE_TELEMETRY=1 skills remove search-first -g -y +DISABLE_TELEMETRY=1 skills remove diagnosing-bugs -g -y +DISABLE_TELEMETRY=1 skills remove tdd -g -y +DISABLE_TELEMETRY=1 skills remove codebase-design -g -y +DISABLE_TELEMETRY=1 skills remove resolving-merge-conflicts -g -y +DISABLE_TELEMETRY=1 skills remove grill-me -g -y +DISABLE_TELEMETRY=1 skills remove improve-codebase-architecture -g -y +DISABLE_TELEMETRY=1 skills remove verification-before-completion -g -y +DISABLE_TELEMETRY=1 skills remove security-threat-model -g -y +DISABLE_TELEMETRY=1 skills remove gh-address-comments -g -y +DISABLE_TELEMETRY=1 skills remove semgrep -g -y +DISABLE_TELEMETRY=1 skills remove codeql -g -y +DISABLE_TELEMETRY=1 skills remove supply-chain-risk-auditor -g -y +DISABLE_TELEMETRY=1 skills remove agentic-actions-auditor -g -y +DISABLE_TELEMETRY=1 skills remove property-based-testing -g -y +DISABLE_TELEMETRY=1 skills remove modern-python -g -y +DISABLE_TELEMETRY=1 skills remove sarif-parsing -g -y +DISABLE_TELEMETRY=1 skills remove fp-check -g -y +DISABLE_TELEMETRY=1 skills remove mcp-builder -g -y +DISABLE_TELEMETRY=1 skills remove frontend-design -g -y +DISABLE_TELEMETRY=1 skills remove agent-browser -g -y +DISABLE_TELEMETRY=1 skills remove find-skills -g -y +DISABLE_TELEMETRY=1 skills remove variant-analysis -g -y +DISABLE_TELEMETRY=1 skills remove writing-for-agents -g -y +``` + +### Restore (what Stage 1 overwrote) + +**The one-line form** (restores only what the backup holds, in place, over the live trees; +adds and overwrites, never moves or deletes anything): + +```sh +rsync -a /claude/ ~/.claude/ ; cp -p /claude.json ~/.claude.json ; rsync -a /codex/ ~/.codex/ ``` Spelled out: @@ -48,41 +191,31 @@ cp -p "/claude.json" ~/.claude.json rsync -a "/codex/" ~/.codex/ ``` -No `--delete` on either `rsync`, and no `rm` anywhere in this procedure: every command only -adds a file the backup holds or overwrites a live file with the backup's copy, so a wrong +No `--delete` on either `rsync`, and no `rm` anywhere in this step: every command only adds +a file the backup holds or overwrites a live file with the backup's copy, so a wrong `` path, a partial run, or stopping partway through never deletes anything — worst case, an unwritable destination or a missing source makes one line fail (non-zero exit) while leaving every live file exactly as it was, and the remaining lines are still -safe to run. The coordinator's report does not state whether the 4,516-file manifest -covers a sibling `claude.json` next to its `claude/` and `codex/` folders (this session did -not re-hash the private manifest to check); the `cp -p` line is included on a best-effort -basis regardless — a missing source makes only that one `cp` fail, touching nothing, and -the two `rsync` lines are unaffected either way. +safe to run. That independence is also why the one-line form above joins its three commands +with `;` rather than `&&`: a missing `claude.json` backup (see below) would make only the +`cp` fail, and an `&&` chain would then skip the second `rsync` for no reason it needs to — +each command's own success or failure here is independent of the others, matching the +spelled-out form below it. The coordinator's report does not state whether the 4,516-file +manifest covers a sibling `claude.json` next to its `claude/` and `codex/` folders (this +session did not re-hash the private manifest to check); the `cp -p` line is included on a +best-effort basis regardless — a missing source makes only that one `cp` fail, touching +nothing, and the two `rsync` lines are unaffected either way. This restores Stage 1's own overwrites (settings.json, config.toml and the other files the -backup held before Stage 1 touched them). It does **not** remove anything Stage 1 *added* -that the backup, by construction, never had a prior copy of to restore. Undo each with its -own native command (all read-only to verify first: `claude plugin list`, `claude mcp list`, -`codex mcp list`, `codex plugin list`): - -| Stage 1 addition | Native removal | -| --- | --- | -| The 10 catalog agents ([`adoption/agents/claude/`](../../../adoption/agents/claude/)) under `~/.claude/agents/` | `rm ~/.claude/agents/{blind-adjudicator,blind-judge,blind-lane-reviewer,evidence-reviewer,isolated-builder,security-reviewer,semantic-evidence-reviewer,source-scout,stack-researcher,stack-verifier}.md` | -| The two guard hooks, `~/.claude/hooks/secret_path_guard.py` and `~/.claude/hooks/effort-default-guard.py` | `rm ~/.claude/hooks/secret_path_guard.py ~/.claude/hooks/effort-default-guard.py` (their `hooks` entries in `settings.json` go with the settings restore below) | -| `~/.claude/workflows` | `rm -rf ~/.claude/workflows` | -| The `context-mode`, `claude-hud` and `codex` Claude plugins | `claude plugin uninstall context-mode@context-mode`, `claude plugin uninstall claude-hud@claude-hud`, `claude plugin uninstall codex@openai-codex` | -| The `serena` user-scope Claude MCP registration | `claude mcp remove serena -s user` | -| The Codex MCP servers `serena`, `headroom` and `qmd` | `codex mcp remove serena`, `codex mcp remove headroom`, `codex mcp remove qmd` | -| The Codex `context-mode` plugin | `codex plugin remove context-mode@context-mode` | -| `~/.codex/RTK.md` | `rm ~/.codex/RTK.md` (the inline RTK block this file's text was copied into, inside `~/.codex/AGENTS.md` — a pre-existing file, see "Codex" above — needs manual editing to remove; deleting `AGENTS.md` itself would remove more than Stage 1 added) | -| `~/.codex/app-server-daemon/settings.json` | `rm ~/.codex/app-server-daemon/settings.json` | -| The pinned skills manifest ([`adoption/skills/manifest.json`](../../../adoption/skills/manifest.json)) | ` remove --all` (see "Skills" below for this host's `` path) | +backup held before Stage 1 touched them); it was never going to remove anything Stage 1 +*added* — the backup, by construction, never had a prior copy of an addition to restore, +which is exactly why removal comes first, above. `apply_claude_settings.py` also wrote its own timestamped backup of the pre-Stage-1 `~/.claude/settings.json`, separate from the private folder backup above; restoring that one file undoes every `settings.json` edit (both guard hooks' registration, the plugin and MCP entries, `effortLevel`, etc.) in a single step, but it does not uninstall the plugin, -MCP-server or skill payloads themselves — those still need the commands above. +MCP-server or skill payloads themselves — those still need the removal commands above. ## Service continuity @@ -215,10 +348,11 @@ never/danger-full-access profile is an open question for the owner, not decided README previously described the live listing as matching config.toml, which undercounted it, and no longer does. -`app-server-daemon` `updater.autoUpdateEnabled`: `false` (per the coordinator's report; not -re-checked in this session either, since that setting lives under `CODEX_HOME` outside the -profile files this session read; stays `source_review` and unverified by any -receipt — the codex receipt proves only `features.daemon_auto_start = false`, a different +`app-server-daemon` `updater.autoUpdateEnabled`: `false` (per the coordinator's report, and +confirmed again by a direct read of the file in this round-2 fix pass — still exactly +`{"updater": {"autoUpdateEnabled": false}}` — since that setting lives under `CODEX_HOME` +outside the profile files this document otherwise reads directly; stays `source_review` and +unverified by any receipt — the codex receipt proves only `features.daemon_auto_start = false`, a different setting). `shell_environment_policy.set` carries the pinned `PATH`, `RTK_TELEMETRY_DISABLED=1` and @@ -328,7 +462,7 @@ below): | [`...--codex--use--20260927.json`](../../hosts/mac-coordinator-64gb-20260925/mac-coordinator-64gb-20260925--codex--use--20260927.json) | codex-cli 0.158.0-alpha.2.1 | superseded three times; version was only a flag here, not a retained command | | [`...--codex--use--20260927-2.json`](../../hosts/mac-coordinator-64gb-20260925/mac-coordinator-64gb-20260925--codex--use--20260927-2.json) | codex-cli 0.158.0-alpha.2.1 | superseded by `-3` (review findings: the version-check command's exit code was actually a later `echo`'s, not `codex --version`'s; the claim named a specific model command that was not checked; `approval_policy`/`sandbox_mode` were claimed without a live check; the mcp-list check's summary line and the `socraticode` row fell outside the 400-char excerpt — `cua_repl` and `codex_app` were inside it, not cut off; see below) | | [`...--codex--use--20260927-3.json`](../../hosts/mac-coordinator-64gb-20260925/mac-coordinator-64gb-20260925--codex--use--20260927-3.json) | codex-cli 0.158.0-alpha.2.1 | superseded by `-4` (review findings: the positive control's checker accepted the first successful `command_execution` in the transcript, whichever it was — this generation's own retained excerpt shows a plugin `SKILL.md` read satisfied it, with no relation to the fixture; `mcp list`/`features list` piped codex's own stderr into the JSON/text parse and discarded codex's own exit code behind `python3`'s exit code; the claim called `--sandbox read-only` a safety boundary though it does not bound the declared `context-mode` MCP server or Codex's plugin-provided tools; see below and "Memory-store writes during recording" above) | -| [`...--codex--use--20260927-4.json`](../../hosts/mac-coordinator-64gb-20260925/mac-coordinator-64gb-20260925--codex--use--20260927-4.json) | codex-cli 0.158.0-alpha.2.1 | current. Version/channel check whose exit code is `codex --version`'s own; `codex exec --skip-git-repo-check --sandbox read-only --ephemeral` (random-fixture positive control gated on, and printing, a `command_execution` event whose own command text contains the fixture's filename and exited 0 — not merely the first successful `command_execution`, whichever it is — plus an in-transcript negative control on a deliberately wrong count, correctly rejected; both `event_kinds`, per top-level event type, and `item_kinds`, per completed item type, are printed); `codex mcp list --json` and `codex features list`, both now run with `set -o pipefail` and codex's own stderr discarded before the parse instead of merged into it (declared ⊆ live gates the exit code together with codex's own; any live-only server is disclosed, not a failure — this run: `cua_repl`, `codex_app`). No longer claims `approval_policy`/`sandbox_mode`, and no longer calls `--sandbox read-only` a safety boundary (see "Codex" and "Memory-store writes during recording" above) | +| [`...--codex--use--20260927-4.json`](../../hosts/mac-coordinator-64gb-20260925/mac-coordinator-64gb-20260925--codex--use--20260927-4.json) | codex-cli 0.158.0-alpha.2.1 | current. Version/channel check whose exit code is `codex --version`'s own; `codex exec --skip-git-repo-check --sandbox read-only --ephemeral` (random-fixture positive control gated on, and printing, a `command_execution` event whose own command text contains the fixture's filename and exited 0 — not merely the first successful `command_execution`, whichever it is — plus an in-transcript negative control on a deliberately wrong count, correctly rejected; both `event_kinds`, per top-level event type, and `item_kinds`, per completed item type, are printed); `codex mcp list --json` and `codex features list`, both now run with `set -o pipefail` and codex's own stderr discarded before the parse instead of merged into it (declared ⊆ live gates the exit code together with codex's own; any live-only server is disclosed, not a failure — this run: `cua_repl`, `codex_app`; the receipt's own line naming which plugin provides each, `unified-computer-use@openai-bundled` and `codex-app-tools@openai-bundled` respectively, carries no evidence-class label of its own — that plugin-to-server mapping is `source_review`, same as the marketplace-origin claim beside it, both read from each plugin's own `.mcp.json`, not from this command's name/enabled/transport-only output; see "Codex" above). No longer claims `approval_policy`/`sandbox_mode`, and no longer calls `--sandbox read-only` a safety boundary (see "Codex" and "Memory-store writes during recording" above) | Both installed builds are newer than the current catalog pins (claude-code 2.1.278, codex 0.155.1), so every `-2` and later receipt uses `--allow-unbound-version` and does not by @@ -338,7 +472,8 @@ needs independent review plus the matrix flip rule in **A compliant independent review of these receipts cannot return `agree`, by construction, and this PR's merge does not wait on that being fixed.** `docs/contributing-evidence.md` -section 8's four review points include, as point 4, "bound to the winner": the receipt's +section 3, step 8's four review points (`docs/contributing-evidence.md:340-363`) include, as +point 4, "bound to the winner": the receipt's `tool_versions` must match the landscape winner's pin. The current claude-code `-3` and codex `-4` receipts are both `--allow-unbound-version`; the tested codex is the ChatGPT app's bundled alpha build, which cannot bind to an `openai/codex` release pin at all, at any @@ -460,12 +595,14 @@ From the coordinator's Stage 1 run, plus this session's own checks where noted: `--allow-unbound-version`). - No `platform_status` is changed by this PR. `adoption/manifest.json`'s macOS platform profile status is a separate, maintainer-judgment field this PR does not touch. -- Counts, booleans, file names and (in the current `-3` claude-code and `-4` codex - receipts) tool names, item-type tallies and one sanitized shell command line appear; no - session id, uuid, working-directory path, MCP server command/args/env, or personal path - appears in this document or in any receipt's retained command output (those two current - receipts replace the scratch directory with `` in the one command line they - print). +- Counts, booleans, file names and, in the current `-3` claude-code and `-4` codex receipts, + tool names and item-type tallies appear; no session id, uuid, working-directory path, MCP + server command/args/env, or personal path appears in this document or in any receipt's + retained command output. Only one of the two prints a command line at all: the `-4` codex + receipt captures the one `command_execution` its positive control gates on, with its + scratch directory replaced by `` in the printed text; the `-3` claude-code + receipt's own retained output has no command line anywhere in it, only the `tool_use_names` + its transcript scan records (see "Host receipts" above for both). - Host request [#382](https://github.com/seathatflowsinourveins/native-agent-stack/issues/382) still carries the `request:blocked` label as of this PR. Its status comment (written by `scripts/host_requests.py`, updated 2026-09-27T05:08:09Z) gives the reason: "Claude Code's diff --git a/manifests/evidence.json b/manifests/evidence.json index c017c2de3..f9c1a762e 100644 --- a/manifests/evidence.json +++ b/manifests/evidence.json @@ -30638,8 +30638,8 @@ }, { "path": "evidence/artifacts/mac-stage1-client-layer-20260927/README.md", - "sha256": "bd8bb6a937acee60e93748f3a1ab3776037f0970b4ab0ba8fd72e314717908c3", - "bytes": 38508 + "sha256": "5989302cf030e8913bbfc0e747b6d1e27cc6e0f446360a2b8299455421988da8", + "bytes": 47442 }, { "path": "evidence/artifacts/macos-application-20260924/run-summary.json", From d38c995a66f662887ededd1c701e63c103c12b77 Mon Sep 17 00:00:00 2001 From: seathatflowsinourveins <234074349+seathatflowsinourveins@users.noreply.github.com> Date: Sun, 27 Sep 2026 10:03:27 -0400 Subject: [PATCH 08/12] Follow-up on #391: point the skills binary citation at the pinned manifest, not the Skills section Item 1's "replace the dangling Skills pointer" sub-bullet pointed the rollback's skills-binary reference at the README's own Skills section, but that section names the binary through its own --skills-bin placeholder rather than a concrete path or version -- a reader following the link would land on another placeholder. Cites adoption/skills/manifest.json's cli block directly instead (version "1.7.0"), which is the actual pin. Co-Authored-By: Claude Sonnet 5 Claude-Session: https://claude.ai/code/session_017d27CMzkbLezdLv7vAStPu --- .../artifacts/mac-stage1-client-layer-20260927/README.md | 9 ++++++--- manifests/evidence.json | 4 ++-- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/evidence/artifacts/mac-stage1-client-layer-20260927/README.md b/evidence/artifacts/mac-stage1-client-layer-20260927/README.md index 6314b0eea..8c324419a 100644 --- a/evidence/artifacts/mac-stage1-client-layer-20260927/README.md +++ b/evidence/artifacts/mac-stage1-client-layer-20260927/README.md @@ -136,9 +136,12 @@ skills instead, not the global ones Stage 1 placed -g -y` (no `-a`) removes the canonical copy, both links and the lock entry" — the same call this repository's own installer runs on a mismatched install, [`tools/adoption/install_skills.py`](../../../tools/adoption/install_skills.py) lines 17-21 -and its `remove` call at line 196). The `skills` binary is the pinned 1.7.0 package the -[Skills](#skills) section below names — there is no separate `` path to look up. -`DISABLE_TELEMETRY=1` matches the manifest's own `cli.env` and what the installer sets. There +and its `remove` call at line 196). The `skills` binary is the `skills@1.7.0` CLI that +[`adoption/skills/manifest.json`](../../../adoption/skills/manifest.json)'s `cli` block pins +(`"version": "1.7.0"`), resolved as `skills` first on `PATH` — there is no separate +`` path to look up (the [Skills](#skills) section below's own `--skills-bin` flag +names this same binary, just not by a fixed path). `DISABLE_TELEMETRY=1` matches the +manifest's own `cli.env` and what the installer sets. There is no bulk form here, only one call per skill ([`adoption/lifecycle.md`](../../../adoption/lifecycle.md):100, verbatim: "Never uninstall all user tools to roll back one package"): diff --git a/manifests/evidence.json b/manifests/evidence.json index f9c1a762e..d23a07bbf 100644 --- a/manifests/evidence.json +++ b/manifests/evidence.json @@ -30638,8 +30638,8 @@ }, { "path": "evidence/artifacts/mac-stage1-client-layer-20260927/README.md", - "sha256": "5989302cf030e8913bbfc0e747b6d1e27cc6e0f446360a2b8299455421988da8", - "bytes": 47442 + "sha256": "b66b0bb3404ad4de865540424c5e6a89770d0f79f8fd57c6d425d1fbc4f271e8", + "bytes": 47670 }, { "path": "evidence/artifacts/macos-application-20260924/run-summary.json", From 327d139d99f85a31d9cc50321838fec210278951 Mon Sep 17 00:00:00 2001 From: seathatflowsinourveins <234074349+seathatflowsinourveins@users.noreply.github.com> Date: Sun, 27 Sep 2026 10:05:25 -0400 Subject: [PATCH 09/12] #391 README: the RTK.md removal row points to the Codex section below it The removal table (line 61) sits above "## Codex"; the receipts-table pointer at line 468 correctly says "above" and is unchanged. README re-registered in manifests/evidence.json; validate.py and host_receipts.py validate pass. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_017d27CMzkbLezdLv7vAStPu --- evidence/artifacts/mac-stage1-client-layer-20260927/README.md | 2 +- manifests/evidence.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/evidence/artifacts/mac-stage1-client-layer-20260927/README.md b/evidence/artifacts/mac-stage1-client-layer-20260927/README.md index 8c324419a..374eb32f4 100644 --- a/evidence/artifacts/mac-stage1-client-layer-20260927/README.md +++ b/evidence/artifacts/mac-stage1-client-layer-20260927/README.md @@ -58,7 +58,7 @@ Undo each with its own native command (all read-only to verify first: `claude pl | The `serena` user-scope Claude MCP registration | `claude mcp remove serena -s user` | | The Codex MCP servers `serena`, `headroom` and `qmd` | `codex mcp remove serena`, `codex mcp remove headroom`, `codex mcp remove qmd` | | The Codex `context-mode` plugin | `codex plugin remove context-mode@context-mode` | -| `~/.codex/RTK.md` | `rm ~/.codex/RTK.md` (the inline RTK block this file's text was copied into, inside `~/.codex/AGENTS.md` — a pre-existing file, see "Codex" above — needs manual editing to remove; deleting `AGENTS.md` itself would remove more than Stage 1 added) | +| `~/.codex/RTK.md` | `rm ~/.codex/RTK.md` (the inline RTK block this file's text was copied into, inside `~/.codex/AGENTS.md` — a pre-existing file, see "Codex" below — needs manual editing to remove; deleting `AGENTS.md` itself would remove more than Stage 1 added) | | The `updater.autoUpdateEnabled` key this session wrote into `~/.codex/app-server-daemon/settings.json` (whether the file existed before Stage 1 is not recorded; see note below) | conditional, not a blind `rm` — see note below | | The 28 skills pinned in [`adoption/skills/manifest.json`](../../../adoption/skills/manifest.json), the skills@1.7.0 manifest Stage 1 installed | one `skills remove -g -y` per skill, listed below | diff --git a/manifests/evidence.json b/manifests/evidence.json index d23a07bbf..f10b300c6 100644 --- a/manifests/evidence.json +++ b/manifests/evidence.json @@ -30638,7 +30638,7 @@ }, { "path": "evidence/artifacts/mac-stage1-client-layer-20260927/README.md", - "sha256": "b66b0bb3404ad4de865540424c5e6a89770d0f79f8fd57c6d425d1fbc4f271e8", + "sha256": "bc5fc0040cce6aea059c60fe342e47632526067fe4e83bb61aa470eecaa35575", "bytes": 47670 }, { From d05f5d621557673480a2ccdc43461c5c3d326a8f Mon Sep 17 00:00:00 2001 From: seathatflowsinourveins <234074349+seathatflowsinourveins@users.noreply.github.com> Date: Sun, 27 Sep 2026 10:48:34 -0400 Subject: [PATCH 10/12] PR #391 fix round 3: address GPT-6 cross-family review at 327d139d - Skills rollback: scope every `skills remove` to `-a claude-code codex` (upstream skills@1.7.0 src/remove.ts otherwise targets every known agent format, ~30 of them, not only the two Stage 1 touched); exclude `typesafe-ai` from the automated list, since the pre-Stage-1 backup shows it already linked under claude-code before Stage 1 ran. - Plugin rollback: add `--keep-data` to all three `claude plugin uninstall` commands and document what each retains vs. removes; document that `codex plugin remove` has no equivalent flag and removes the plugin's cache unconditionally. - Workflow/agent/hook/RTK.md rollback: gate every removal on a recorded sha256 digest (repository digest where this document already established byte-identity; a live digest recorded today, labeled as such, otherwise), keeping the file and printing why when it does not match. Pull `contract.config.json` out of automatic removal (no install-time digest exists for a per-host render) and list it as a manual step instead. - Record a superseding claude-code `-4` host receipt: the positive control now requires, and prints only a constant sanitized target for, a `Read` tool_use whose own `input.file_path` (compared by basename only) names the fixture, instead of merely scanning tool_use names. Rehearsed by hand before recording. Updates every README reference to the claude-code receipt chain accordingly. Co-Authored-By: Claude Sonnet 5 Claude-Session: https://claude.ai/code/session_017d27CMzkbLezdLv7vAStPu --- .../landscape/component-evidence-matrix.json | 8 +- docs/component-evidence-matrix.md | 4 +- .../README.md | 272 +++++++++++++----- ...0260925--claude-code--use--20260927-4.json | 77 +++++ manifests/evidence.json | 13 +- 5 files changed, 286 insertions(+), 88 deletions(-) create mode 100644 evidence/hosts/mac-coordinator-64gb-20260925/mac-coordinator-64gb-20260925--claude-code--use--20260927-4.json diff --git a/catalogs/landscape/component-evidence-matrix.json b/catalogs/landscape/component-evidence-matrix.json index e3997c9c1..23d290ab2 100644 --- a/catalogs/landscape/component-evidence-matrix.json +++ b/catalogs/landscape/component-evidence-matrix.json @@ -1626,8 +1626,8 @@ "fail": 0, "independently_reviewed_fail": 0, "independently_reviewed_pass": 0, - "latest": "2026-09-27T08:16:04Z", - "pass": 3 + "latest": "2026-09-27T14:39:22Z", + "pass": 4 }, "qualified_models": [] } @@ -3219,8 +3219,8 @@ "fail": 0, "independently_reviewed_fail": 0, "independently_reviewed_pass": 0, - "latest": "2026-09-27T08:16:04Z", - "pass": 3 + "latest": "2026-09-27T14:39:22Z", + "pass": 4 }, "qualified_models": [] } diff --git a/docs/component-evidence-matrix.md b/docs/component-evidence-matrix.md index 9329dfc75..7c9966b88 100644 --- a/docs/component-evidence-matrix.md +++ b/docs/component-evidence-matrix.md @@ -30,7 +30,7 @@ Each winner shows, for linux-wsl2-x86_64 / macos-arm64, its `e2e_state` and host | `foundation/instructions-skills` | dual_lane_adjudicated (adjudication: `evidence/artifacts/layer-verdicts-20260922/adjudication/foundation-instructions-skills-20260922.json`) | affaan-m/ECC (conditional [2/0/1/0] dissented 1 / untested [0/0/0/0]); candidate:typesafe-ai-skills (conditional [0/0/0/0] / untested [0/0/0/0]); candidate:openai-skills (conditional [0/0/0/0] / untested [0/0/0/0]) | | `foundation/isolation` | dual_lane_same_winner | worktrunk (host_verified [2/0/2/0] / host_verified [1/0/1/0]); sandbox-runtime (host_verified [1/0/1/0] / untested [0/0/0/0]) | | `foundation/mcp-surfaces` | dual_lane_same_winner | mcporter (host_verified [6/0/2/0] dissented 4 / untested [0/0/0/0]); mcp-inspector (host_verified [2/0/1/0] dissented 1 / untested [0/0/0/0]) | -| `foundation/native-clients` | dual_lane_same_winner | claude-code (accepted [1/0/1/0] / untested [3/0/0/0]); codex (host_verified [8/0/5/0] dissented 3 / untested [4/0/0/0]) | +| `foundation/native-clients` | dual_lane_same_winner | claude-code (accepted [1/0/1/0] / untested [4/0/0/0]); codex (host_verified [8/0/5/0] dissented 3 / untested [4/0/0/0]) | | `foundation/observation-inference` | dual_lane_adjudicated (adjudication: `evidence/artifacts/layer-verdicts-20260922/adjudication/foundation-observation-inference-20260922.json`) | opentelemetry-collector-contrib (host_verified [2/0/2/0] / untested [0/0/0/0]); prometheus (host_verified [2/0/2/0] / untested [0/0/0/0]); loki (host_verified [2/0/2/0] / untested [0/0/0/0]) | | `foundation/quality-evaluation` | dual_lane_same_winner | promptfoo (host_verified [6/0/2/0] dissented 4 / untested [0/0/0/0]); playwright-test (conditional [0/0/0/0] / untested [1/0/0/0] dissented 1) | | `foundation/recovery-portability` | dual_lane_same_winner | restic (host_verified [3/0/3/0] / untested [1/0/0/0]); candidate:astral-sh-uv (conditional [0/0/0/0] / untested [0/0/0/0]) | @@ -39,7 +39,7 @@ Each winner shows, for linux-wsl2-x86_64 / macos-arm64, its `e2e_state` and host | `foundation/semantic-rag` | dual_lane_same_winner | socraticode (host_verified [5/0/2/0] dissented 3 / untested [1/0/0/0]); qdrant (host_verified [3/0/3/0] / untested [1/0/0/0]); vllm (host_verified [6/0/3/0] dissented 2 / untested [0/0/0/0]) | | `foundation/token-efficiency` | dual_lane_adjudicated (adjudication: `evidence/artifacts/layer-verdicts-20260922/adjudication/foundation-token-efficiency-20260922.json`) | rtk (host_verified [7/0/4/0] dissented 2 / host_verified [1/0/1/0]); headroom (host_verified [4/0/3/0] dissented 1 / untested [0/0/0/0]); ccusage (host_verified [2/0/2/0] / untested [0/0/0/0]) | | `foundation/web-research` | dual_lane_adjudicated (adjudication: `evidence/artifacts/layer-verdicts-20260922/adjudication/foundation-web-research-20260922.json`) | tavily-cli (conditional [0/0/0/0] / untested [0/0/0/0]); agent-browser (conditional [0/0/0/0] / untested [0/0/0/0]); openresearch (conditional [0/0/0/0] / untested [0/0/0/0]) | -| `foundation/workers` | dual_lane_adjudicated (adjudication: `evidence/artifacts/layer-verdicts-20260922/adjudication/foundation-workers-20260922.json`) | claude-code (conditional [1/0/1/0] / untested [3/0/0/0]); worktrunk (host_verified [2/0/2/0] / host_verified [1/0/1/0]) | +| `foundation/workers` | dual_lane_adjudicated (adjudication: `evidence/artifacts/layer-verdicts-20260922/adjudication/foundation-workers-20260922.json`) | claude-code (conditional [1/0/1/0] / untested [4/0/0/0]); worktrunk (host_verified [2/0/2/0] / host_verified [1/0/1/0]) | | `us-equities/agents-models-workers` | dual_lane_same_winner | codex-native-sdk (accepted [0/0/0/0] / untested [0/0/0/0]); foundation-ai-memory (accepted [0/0/0/0] / untested [0/0/0/0]); foundation-socraticode (accepted [0/0/0/0] / untested [0/0/0/0]) | | `us-equities/backtesting-engine` | dual_lane_same_winner | nautilustrader (host_verified [1/0/1/0] / untested [0/0/0/0] +1 alias receipt(s), not counted); lean (host_verified [2/0/1/0] dissented 1 / untested [0/0/0/0]) | | `us-equities/data-quality-orchestration` | dual_lane_adjudicated (adjudication: `evidence/artifacts/layer-verdicts-20260922/adjudication/us-equities-data-quality-orchestration-20260922.json`) | dagu (host_verified [2/0/2/0] / untested [0/0/0/0]); data-pandera (host_verified [3/0/1/0] dissented 2 / untested [0/0/0/0]) | diff --git a/evidence/artifacts/mac-stage1-client-layer-20260927/README.md b/evidence/artifacts/mac-stage1-client-layer-20260927/README.md index 374eb32f4..0aac1dae5 100644 --- a/evidence/artifacts/mac-stage1-client-layer-20260927/README.md +++ b/evidence/artifacts/mac-stage1-client-layer-20260927/README.md @@ -51,16 +51,36 @@ Undo each with its own native command (all read-only to verify first: `claude pl | Stage 1 addition | Native removal | | --- | --- | -| The 10 catalog agents ([`adoption/agents/claude/`](../../../adoption/agents/claude/)) under `~/.claude/agents/` | `rm ~/.claude/agents/{blind-adjudicator,blind-judge,blind-lane-reviewer,evidence-reviewer,isolated-builder,security-reviewer,semantic-evidence-reviewer,source-scout,stack-researcher,stack-verifier}.md` | -| Two guard hooks under `~/.claude/hooks/` — of the four files [`tools/adoption/install_claude_profile.py`](../../../tools/adoption/install_claude_profile.py)'s `HOOKS` map (lines 48-53) can place; see note below | `rm ~/.claude/hooks/secret_path_guard.py`; `rm ~/.claude/hooks/effort-default-guard.py` (their `hooks` entries in `settings.json` go with the settings restore below) | -| Every file under `~/.claude/workflows/` (13 files; see note below) — never the directory itself | one `rm` per file, listed below | -| The `context-mode`, `claude-hud` and `codex` Claude plugins | `claude plugin uninstall context-mode@context-mode`, `claude plugin uninstall claude-hud@claude-hud`, `claude plugin uninstall codex@openai-codex` | +| The 10 catalog agents ([`adoption/agents/claude/`](../../../adoption/agents/claude/)) under `~/.claude/agents/` | gated on a recorded digest, one line per file, listed below | +| Two guard hooks under `~/.claude/hooks/` — of the four files [`tools/adoption/install_claude_profile.py`](../../../tools/adoption/install_claude_profile.py)'s `HOOKS` map (lines 48-53) can place; see note below | gated on a recorded digest, one line per file, listed below (their `hooks` entries in `settings.json` go with the settings restore below) | +| Every file under `~/.claude/workflows/` (13 files; see note below) — never the directory itself | 12 gated on a recorded digest, one line per file, listed below; the 13th, `contract.config.json`, is a manual step, not automatic (see note below) | +| The `context-mode`, `claude-hud` and `codex` Claude plugins | `claude plugin uninstall context-mode@context-mode --keep-data`, `claude plugin uninstall claude-hud@claude-hud --keep-data`, `claude plugin uninstall codex@openai-codex --keep-data` (see note below for what `--keep-data` retains and what each command removes regardless) | | The `serena` user-scope Claude MCP registration | `claude mcp remove serena -s user` | | The Codex MCP servers `serena`, `headroom` and `qmd` | `codex mcp remove serena`, `codex mcp remove headroom`, `codex mcp remove qmd` | -| The Codex `context-mode` plugin | `codex plugin remove context-mode@context-mode` | -| `~/.codex/RTK.md` | `rm ~/.codex/RTK.md` (the inline RTK block this file's text was copied into, inside `~/.codex/AGENTS.md` — a pre-existing file, see "Codex" below — needs manual editing to remove; deleting `AGENTS.md` itself would remove more than Stage 1 added) | +| The Codex `context-mode` plugin | `codex plugin remove context-mode@context-mode` (this build's `plugin remove` has no data-preserving flag at all; see note below for what it removes) | +| `~/.codex/RTK.md` | gated on a recorded digest, listed below (the inline RTK block this file's text was copied into, inside `~/.codex/AGENTS.md` — a pre-existing file, see "Codex" below — needs manual editing to remove; deleting `AGENTS.md` itself would remove more than Stage 1 added) | | The `updater.autoUpdateEnabled` key this session wrote into `~/.codex/app-server-daemon/settings.json` (whether the file existed before Stage 1 is not recorded; see note below) | conditional, not a blind `rm` — see note below | -| The 28 skills pinned in [`adoption/skills/manifest.json`](../../../adoption/skills/manifest.json), the skills@1.7.0 manifest Stage 1 installed | one `skills remove -g -y` per skill, listed below | +| 27 of the 28 skills pinned in [`adoption/skills/manifest.json`](../../../adoption/skills/manifest.json), the skills@1.7.0 manifest Stage 1 installed | one `skills remove -g -y -a claude-code codex` per skill, listed below; the 28th, `typesafe-ai`, predates Stage 1 and is kept — see note below | + +**Agents.** No prior claim in this document verified these 10 files byte-identical to their +repository source, so each removal is gated on a digest read directly from the live file in +this review-fix pass — recorded 2026-09-27 from the live file, not an install-time digest — +rather than assumed from the repository copy. As a factual aside, not part of the gate +itself, all 10 also match their [`adoption/agents/claude/`](../../../adoption/agents/claude/) +repository copies exactly today: + +```sh +f=~/.claude/agents/blind-adjudicator.md; [ "$(shasum -a 256 "$f" | cut -d' ' -f1)" = "ef8d07f15b7c219f1b5ada705cf185146088fd013974b5ca51c1d29fdeee9fc4" ] && rm "$f" || echo "kept $f (missing, or changed since Stage 1)" +f=~/.claude/agents/blind-judge.md; [ "$(shasum -a 256 "$f" | cut -d' ' -f1)" = "c08be2e54336a5cefe354c2e47bd32ed8a42325c90b96034a875aed5d7b22170" ] && rm "$f" || echo "kept $f (missing, or changed since Stage 1)" +f=~/.claude/agents/blind-lane-reviewer.md; [ "$(shasum -a 256 "$f" | cut -d' ' -f1)" = "a87a9883618b320c8b97a442a43c471c0994fb70ea9bb64ce0b5f513ba31500c" ] && rm "$f" || echo "kept $f (missing, or changed since Stage 1)" +f=~/.claude/agents/evidence-reviewer.md; [ "$(shasum -a 256 "$f" | cut -d' ' -f1)" = "3aa5e3f0aac4b43f7196cb46aee3ce1ef06e795ae93ba2a925ea53ac62f5e256" ] && rm "$f" || echo "kept $f (missing, or changed since Stage 1)" +f=~/.claude/agents/isolated-builder.md; [ "$(shasum -a 256 "$f" | cut -d' ' -f1)" = "daaeca8baaab3c6471f70aa12299fe14ff1de9f54f57e8683ac593f70e7ee370" ] && rm "$f" || echo "kept $f (missing, or changed since Stage 1)" +f=~/.claude/agents/security-reviewer.md; [ "$(shasum -a 256 "$f" | cut -d' ' -f1)" = "73eb483d22760e6b75226d58714a1354a848382bad032d8876e172fc8f656b9b" ] && rm "$f" || echo "kept $f (missing, or changed since Stage 1)" +f=~/.claude/agents/semantic-evidence-reviewer.md; [ "$(shasum -a 256 "$f" | cut -d' ' -f1)" = "5b0fc7e5451054baa40d879194d95d537e2ec5e0c44cbf7fe620f9c2e871ef6c" ] && rm "$f" || echo "kept $f (missing, or changed since Stage 1)" +f=~/.claude/agents/source-scout.md; [ "$(shasum -a 256 "$f" | cut -d' ' -f1)" = "b879b0b873f6346ca5a2e03154d20d400aac06692267075a3eb8cf982fe768de" ] && rm "$f" || echo "kept $f (missing, or changed since Stage 1)" +f=~/.claude/agents/stack-researcher.md; [ "$(shasum -a 256 "$f" | cut -d' ' -f1)" = "a35b015fcf7e8d608b5cf60e4172c6f1033bf4d9b3b8047a008efc5e89dcb446" ] && rm "$f" || echo "kept $f (missing, or changed since Stage 1)" +f=~/.claude/agents/stack-verifier.md; [ "$(shasum -a 256 "$f" | cut -d' ' -f1)" = "97b21d6ed2d1747c7e3cc4e80335595670025531ae48debdac18ef4889524503" ] && rm "$f" || echo "kept $f (missing, or changed since Stage 1)" +``` **Hooks.** The `HOOKS` map names four files it can place under `~/.claude/hooks/`: `effort-default-guard.py`, `secret_path_guard.py`, `token-lanes-block.md` and @@ -72,7 +92,14 @@ to their repository source, `adoption/hooks/claude/effort-default-guard.py` and them here. A third file also lives in `~/.claude/hooks/`, `context-mode-cache-heal.mjs` — that one is not this installer's own: per the [macOS template findings](#macos-template-findings) above, it is registered by the `context-mode` plugin itself, and goes with that plugin's own -removal command in the table above, not with these two. +removal command in the table above, not with these two. Both existing hooks are already +verified byte-identical to their repository source (just above), so their removal is gated +on that repository digest, not a freshly read live one: + +```sh +f=~/.claude/hooks/effort-default-guard.py; [ "$(shasum -a 256 "$f" | cut -d' ' -f1)" = "df3248659c191d8800dfd64a8c7d415fc13652cebee08c9437bf579862c2e561" ] && rm "$f" || echo "kept $f (missing, or changed since Stage 1)" +f=~/.claude/hooks/secret_path_guard.py; [ "$(shasum -a 256 "$f" | cut -d' ' -f1)" = "ed5556f0cb4942859cf9e8e2e6f709de4dbc5b96163fc6ef65fcd0dcab8da153" ] && rm "$f" || echo "kept $f (missing, or changed since Stage 1)" +``` **`~/.claude/workflows/`.** `ls -la ~/.claude/workflows` lists 13 files. Compared by name and sha256 against this repository's own @@ -84,29 +111,71 @@ host's own absolute paths in place of the template's relative ones — the same [macOS template findings](#macos-template-findings) above record ("User-scope workflows need absolute contract paths, which `test-contract-mutations` rejects"), not a different file. Every file present is therefore accounted for as Stage 1's own; there is nothing in this -directory today that is the user's own to preserve, and all 13 are named individually below, -never the directory itself: +directory today that is the user's own to preserve. The 12 that matched by sha256 above are +named individually below, each gated on that same repository digest (from +`examples/claude-native/workflows/SHA256SUMS`, cross-checked in this review-fix pass against +the repository files it lists and found to match exactly) rather than removed unconditionally, +so a user edit made after Stage 1 installed them is kept, not silently deleted: ```sh -rm ~/.claude/workflows/check-syntax.mjs -rm ~/.claude/workflows/child-usage.mjs -rm ~/.claude/workflows/codex-cross-review.mjs -rm ~/.claude/workflows/contract.config.json -rm ~/.claude/workflows/layer-verdict-lane.js -rm ~/.claude/workflows/readiness-audit.js -rm ~/.claude/workflows/review-changes.js -rm ~/.claude/workflows/test-child-usage.mjs -rm ~/.claude/workflows/test-codex-envelope.mjs -rm ~/.claude/workflows/test-contract-mutations.mjs -rm ~/.claude/workflows/test-envelope.mjs -rm ~/.claude/workflows/test-usage-receipts.mjs -rm ~/.claude/workflows/vendored-lanes.json +f=~/.claude/workflows/check-syntax.mjs; [ "$(shasum -a 256 "$f" | cut -d' ' -f1)" = "ca62177687420fe22e03d0510a18e4f32b5d150e0156f6651c48367c3da506e1" ] && rm "$f" || echo "kept $f (missing, or changed since Stage 1)" +f=~/.claude/workflows/child-usage.mjs; [ "$(shasum -a 256 "$f" | cut -d' ' -f1)" = "f5ea9c3a1b47cab91e90a515f455bcf6a960fb696db89717e04b7424e4ff42a0" ] && rm "$f" || echo "kept $f (missing, or changed since Stage 1)" +f=~/.claude/workflows/codex-cross-review.mjs; [ "$(shasum -a 256 "$f" | cut -d' ' -f1)" = "cd303779df6521c804070a319aa04c86ed2d6fe1c099c537836f037dec5f4e8b" ] && rm "$f" || echo "kept $f (missing, or changed since Stage 1)" +f=~/.claude/workflows/layer-verdict-lane.js; [ "$(shasum -a 256 "$f" | cut -d' ' -f1)" = "fd77b74945e9d2bd0b26b7822aabcde00e7e650c327da16d852fdbfd5984c0d6" ] && rm "$f" || echo "kept $f (missing, or changed since Stage 1)" +f=~/.claude/workflows/readiness-audit.js; [ "$(shasum -a 256 "$f" | cut -d' ' -f1)" = "1d3d816cc219a252760a471a3b68a979057e2c417c429d6c094df4c474e612bb" ] && rm "$f" || echo "kept $f (missing, or changed since Stage 1)" +f=~/.claude/workflows/review-changes.js; [ "$(shasum -a 256 "$f" | cut -d' ' -f1)" = "bb298f9ab63a6d43173d2c4f87ab31d00dd79184e961dc84d69cbef3966bce0b" ] && rm "$f" || echo "kept $f (missing, or changed since Stage 1)" +f=~/.claude/workflows/test-child-usage.mjs; [ "$(shasum -a 256 "$f" | cut -d' ' -f1)" = "07d9b6553ea5535f005c68830047c99bdec8d26d6b7edd86406028f4dd8a7cab" ] && rm "$f" || echo "kept $f (missing, or changed since Stage 1)" +f=~/.claude/workflows/test-codex-envelope.mjs; [ "$(shasum -a 256 "$f" | cut -d' ' -f1)" = "2617c081f606268ed20a6e00f6472495fad950db433ca3afbb44ea970aaac446" ] && rm "$f" || echo "kept $f (missing, or changed since Stage 1)" +f=~/.claude/workflows/test-contract-mutations.mjs; [ "$(shasum -a 256 "$f" | cut -d' ' -f1)" = "3027d75134276fee25000ea74832abede9a421ff0d301947eaa6c015b5678e85" ] && rm "$f" || echo "kept $f (missing, or changed since Stage 1)" +f=~/.claude/workflows/test-envelope.mjs; [ "$(shasum -a 256 "$f" | cut -d' ' -f1)" = "bae756a8f2706043c734d07a8cd460ab1c5a812e9a6f1031faf0e8b1b2d9723b" ] && rm "$f" || echo "kept $f (missing, or changed since Stage 1)" +f=~/.claude/workflows/test-usage-receipts.mjs; [ "$(shasum -a 256 "$f" | cut -d' ' -f1)" = "2ed3323db76d0104327a0c0bb35f00cf6a05018bdd9f49982b0c279cf2540871" ] && rm "$f" || echo "kept $f (missing, or changed since Stage 1)" +f=~/.claude/workflows/vendored-lanes.json; [ "$(shasum -a 256 "$f" | cut -d' ' -f1)" = "452712bf2eeee0ad158a061cc6a9291d305aaf9e01d9564aca7b428e1d4ee83e" ] && rm "$f" || echo "kept $f (missing, or changed since Stage 1)" ``` +**`~/.claude/workflows/contract.config.json` is a manual step, not part of the block above.** +It is a per-host *render*, not a copy of the repository template, so this document holds no +install-time checksum it could ever match: gating it on the repository template's own digest +would compare it against a file it was never going to equal (the render intentionally differs, +per the paragraph above), and a freshly read live digest would only prove the file has not +changed since this review-fix pass read it, not since Stage 1 installed it — a live-digest +gate would be misleading here in a way it is not for the agents and RTK.md files below, which +carry no comparably confusing same-named repository counterpart. Remove it by hand if desired: +`rm ~/.claude/workflows/contract.config.json`. + Any file that later appears in `~/.claude/workflows/` outside this list of 13 names is the user's own and stays; re-run the same name-and-sha256 comparison against `examples/claude-native/workflows/` before assuming otherwise. +**Plugins.** `claude plugin uninstall --help` on this host's installed Claude Code 2.1.283 +documents `--keep-data`: "Preserve the plugin's persistent data directory +(`~/.claude/plugins/data/{id}/`)". Without it, uninstalling a plugin's last installation +deletes that directory; with it, the plugin's registration and its `installed_plugins.json` +entry are still removed (that is what makes it "uninstalled"), only the data directory +survives for a future reinstall to reuse. A value-free listing of `~/.claude/plugins/data/` +in this review-fix pass shows two of these three plugins currently have one: +`context-mode-context-mode/` and `codex-openai-codex/` both exist (so `--keep-data` on their +uninstalls above actually preserves live content); `claude-hud-claude-hud/` does not exist +today, so `--keep-data` on that one preserves nothing that is not already empty — harmless +either way, but its listed benefit is currently theoretical for that plugin specifically. +`codex plugin remove --help` documents no equivalent flag at all: its own summary line reads +"Uninstall a plugin and remove its local cache," and its full option list (`-c/--config`, +`-m/--marketplace`, `--enable`, `--disable`, `--json`, `-h/--help`) has nothing that preserves +data. So `codex plugin remove context-mode@context-mode` above unconditionally removes both +the plugin's registration and its cache directory under +`~/.codex/plugins/cache/openai-bundled/context-mode/` (or whichever marketplace it resolves +through) — there is no partial-preserve option in this build. Whether it also edits +`config.toml`'s own `[plugins."*@*"]` table is not stated by the help text and not tested by +this document. + +**`~/.codex/RTK.md`.** No prior claim in this document verified this file byte-identical to +a repository source — it has none; it is inlined from a scratch-home `rtk init -g --codex` run +(see "Codex" below) — so its removal is gated on a digest read directly from the live file in +this review-fix pass, the same live-not-install-time caveat as the agent files above: + +```sh +f=~/.codex/RTK.md; [ "$(shasum -a 256 "$f" | cut -d' ' -f1)" = "13f973cf9d47899124efae2cdb1684021ea2ed4b523c9a8c7f032197175e1aa1" ] && rm "$f" || echo "kept $f (missing, or changed since Stage 1)" +``` + **`~/.codex/app-server-daemon/settings.json`.** This Mac's coordinator session wrote this file during Stage 1 with `{"updater": {"autoUpdateEnabled": false}}` — read directly again in this round-2 fix pass, still exactly that one key and value. Whether the file existed before @@ -131,12 +200,35 @@ fi **Skills.** The skills@1.7.0 CLI's `remove` needs `-g` for global scope: Stage 1 installed these skills globally, and without `-g` the CLI acts on the current directory's *project* -skills instead, not the global ones Stage 1 placed -(`docs/decisions/2026-09-25-skills-trial-and-usage.md:43`, verbatim: "`skills remove --g -y` (no `-a`) removes the canonical copy, both links and the lock entry" — the same call -this repository's own installer runs on a mismatched install, +skills instead, not the global ones Stage 1 placed. Every call below also adds +`-a claude-code codex`, which +[`docs/decisions/2026-09-25-skills-trial-and-usage.md:43`](../../../docs/decisions/2026-09-25-skills-trial-and-usage.md) +did not use ("`skills remove -g -y` (no `-a`) removes the canonical copy, both links +and the lock entry" — the same unscoped form this repository's own installer still runs on a +mismatched install, [`tools/adoption/install_skills.py`](../../../tools/adoption/install_skills.py) lines 17-21 -and its `remove` call at line 196). The `skills` binary is the `skills@1.7.0` CLI that +and its `remove` call at line 196, not changed by this PR). That decision predates a review +finding on this PR: in the pinned skills@1.7.0 CLI's own source +(`skills-extract/package/dist/cli.mjs`, matching +[upstream `src/remove.ts`](https://github.com/vercel-labs/skills/blob/v1.7.0/src/remove.ts#L209)), +omitting `-a` sets `targetAgents = Object.keys(agents)` — *every* agent format the CLI knows, +some 30-odd (Cursor, Cline, Windsurf, and so on), not only the two Stage 1 ever touched — and +then removes `/` for each one that exists on disk, so a +same-named skill belonging to a tool Stage 1 never installed anything for would be deleted +too if that tool happened to have one. `-a claude-code codex` restricts the per-agent cleanup +loop to exactly those two link locations; `claude-code` and `codex` are the CLI's own agent +keys (confirmed by triggering its own "Invalid agents" validation with a nonsense name, which +lists them). This still fully removes the canonical skill content and its lock entry, not +just the two links: the CLI's own removal loop (`cli.mjs`, matching `remove.ts`) checks, after +the scoped agents are cleaned up, whether any *other* installed-but-untouched agent still +links the skill (`detectInstalledAgents()` minus the `-a` list) before deleting the shared +canonical copy — with only claude-code and codex installed on this host, nothing remains +linked, so the canonical copy and lock entry are still removed exactly as the decision record +describes, just without touching any other tool's directory to get there. One further +syntax note the CLI's own arg parser requires: `-a` must be the *last* flag on the line, +after `-g -y`, not before — it greedily consumes every following bare word as an agent name, +so `-a claude-code codex -g -y` would try to treat `-g` and `-y` themselves as agent names +and fail. The `skills` binary is the `skills@1.7.0` CLI that [`adoption/skills/manifest.json`](../../../adoption/skills/manifest.json)'s `cli` block pins (`"version": "1.7.0"`), resolved as `skills` first on `PATH` — there is no separate `` path to look up (the [Skills](#skills) section below's own `--skills-bin` flag @@ -144,37 +236,53 @@ names this same binary, just not by a fixed path). `DISABLE_TELEMETRY=1` matches manifest's own `cli.env` and what the installer sets. There is no bulk form here, only one call per skill ([`adoption/lifecycle.md`](../../../adoption/lifecycle.md):100, verbatim: "Never uninstall -all user tools to roll back one package"): +all user tools to roll back one package"). + +**`typesafe-ai` is excluded below and kept, not removed.** The coordinator's pre-Stage-1 +backup (taken before any write; see "Backup and rollback" above) already holds real skill +content at `claude/skills/typesafe-ai/` (`LICENSE`, `SKILL.md`) — so the claude-code link to +this skill predates Stage 1. The equivalent `codex/skills/` backup path holds no +`typesafe-ai` entry at all (only an unrelated `.system/` directory), so Stage 1 may well have +added the *codex* link fresh. Both links ultimately point at one canonical copy the `skills` +CLI keeps outside either client, at `~/.agents/skills/typesafe-ai` (`getCanonicalSkillsDir` +in `cli.mjs` resolves the global canonical store to `~/.agents/skills`) — a path the backup, +scoped to `~/.claude` and `~/.codex` only, never captured, so whether that canonical copy +itself predates Stage 1 cannot be determined from it either way. Rather than remove a skill +this evidence cannot confirm is entirely Stage 1's own, this document leaves `typesafe-ai` +out of the automated list below; an owner who separately confirms the codex-side link is +Stage 1's own can remove just that link with +`DISABLE_TELEMETRY=1 skills remove typesafe-ai -g -y -a codex`, which leaves the pre-existing +claude-code link and the canonical copy untouched (the same remaining-agents check above keeps +the canonical copy so long as the claude-code link still uses it): ```sh -DISABLE_TELEMETRY=1 skills remove typesafe-ai -g -y -DISABLE_TELEMETRY=1 skills remove gh-fix-ci -g -y -DISABLE_TELEMETRY=1 skills remove security-best-practices -g -y -DISABLE_TELEMETRY=1 skills remove iterative-retrieval -g -y -DISABLE_TELEMETRY=1 skills remove search-first -g -y -DISABLE_TELEMETRY=1 skills remove diagnosing-bugs -g -y -DISABLE_TELEMETRY=1 skills remove tdd -g -y -DISABLE_TELEMETRY=1 skills remove codebase-design -g -y -DISABLE_TELEMETRY=1 skills remove resolving-merge-conflicts -g -y -DISABLE_TELEMETRY=1 skills remove grill-me -g -y -DISABLE_TELEMETRY=1 skills remove improve-codebase-architecture -g -y -DISABLE_TELEMETRY=1 skills remove verification-before-completion -g -y -DISABLE_TELEMETRY=1 skills remove security-threat-model -g -y -DISABLE_TELEMETRY=1 skills remove gh-address-comments -g -y -DISABLE_TELEMETRY=1 skills remove semgrep -g -y -DISABLE_TELEMETRY=1 skills remove codeql -g -y -DISABLE_TELEMETRY=1 skills remove supply-chain-risk-auditor -g -y -DISABLE_TELEMETRY=1 skills remove agentic-actions-auditor -g -y -DISABLE_TELEMETRY=1 skills remove property-based-testing -g -y -DISABLE_TELEMETRY=1 skills remove modern-python -g -y -DISABLE_TELEMETRY=1 skills remove sarif-parsing -g -y -DISABLE_TELEMETRY=1 skills remove fp-check -g -y -DISABLE_TELEMETRY=1 skills remove mcp-builder -g -y -DISABLE_TELEMETRY=1 skills remove frontend-design -g -y -DISABLE_TELEMETRY=1 skills remove agent-browser -g -y -DISABLE_TELEMETRY=1 skills remove find-skills -g -y -DISABLE_TELEMETRY=1 skills remove variant-analysis -g -y -DISABLE_TELEMETRY=1 skills remove writing-for-agents -g -y +DISABLE_TELEMETRY=1 skills remove gh-fix-ci -g -y -a claude-code codex +DISABLE_TELEMETRY=1 skills remove security-best-practices -g -y -a claude-code codex +DISABLE_TELEMETRY=1 skills remove iterative-retrieval -g -y -a claude-code codex +DISABLE_TELEMETRY=1 skills remove search-first -g -y -a claude-code codex +DISABLE_TELEMETRY=1 skills remove diagnosing-bugs -g -y -a claude-code codex +DISABLE_TELEMETRY=1 skills remove tdd -g -y -a claude-code codex +DISABLE_TELEMETRY=1 skills remove codebase-design -g -y -a claude-code codex +DISABLE_TELEMETRY=1 skills remove resolving-merge-conflicts -g -y -a claude-code codex +DISABLE_TELEMETRY=1 skills remove grill-me -g -y -a claude-code codex +DISABLE_TELEMETRY=1 skills remove improve-codebase-architecture -g -y -a claude-code codex +DISABLE_TELEMETRY=1 skills remove verification-before-completion -g -y -a claude-code codex +DISABLE_TELEMETRY=1 skills remove security-threat-model -g -y -a claude-code codex +DISABLE_TELEMETRY=1 skills remove gh-address-comments -g -y -a claude-code codex +DISABLE_TELEMETRY=1 skills remove semgrep -g -y -a claude-code codex +DISABLE_TELEMETRY=1 skills remove codeql -g -y -a claude-code codex +DISABLE_TELEMETRY=1 skills remove supply-chain-risk-auditor -g -y -a claude-code codex +DISABLE_TELEMETRY=1 skills remove agentic-actions-auditor -g -y -a claude-code codex +DISABLE_TELEMETRY=1 skills remove property-based-testing -g -y -a claude-code codex +DISABLE_TELEMETRY=1 skills remove modern-python -g -y -a claude-code codex +DISABLE_TELEMETRY=1 skills remove sarif-parsing -g -y -a claude-code codex +DISABLE_TELEMETRY=1 skills remove fp-check -g -y -a claude-code codex +DISABLE_TELEMETRY=1 skills remove mcp-builder -g -y -a claude-code codex +DISABLE_TELEMETRY=1 skills remove frontend-design -g -y -a claude-code codex +DISABLE_TELEMETRY=1 skills remove agent-browser -g -y -a claude-code codex +DISABLE_TELEMETRY=1 skills remove find-skills -g -y -a claude-code codex +DISABLE_TELEMETRY=1 skills remove variant-analysis -g -y -a claude-code codex +DISABLE_TELEMETRY=1 skills remove writing-for-agents -g -y -a claude-code codex ``` ### Restore (what Stage 1 overwrote) @@ -390,15 +498,17 @@ session pages, for the owner to review or remove. This corrects two claims made elsewhere that this fact contradicts: -- The current `claude-code--use--20260927-3` receipt's own limitations (its own text, - frozen — a receipt changes only by recording a new superseding generation) end with +- The superseded `claude-code--use--20260927-3` receipt's own limitations (its own text, + frozen — a receipt changes only by recording a new superseding generation) ended with "fixture-only input in a fresh mktemp directory, **no mutation evidenced**." That - sentence is true of the fixture's own scratch directory, but "no mutation evidenced" is - not something any command in that receipt checks: its checker records tool *names* - (`tool_use_names`), never tool inputs or outputs, and nothing in it compares any state + sentence was true of the fixture's own scratch directory, but "no mutation evidenced" was + not something any command in that receipt checked: its checker recorded tool *names* + (`tool_use_names`), never tool inputs or outputs, and nothing in it compared any state before and after the turn. Read plainly, "no mutation evidenced" could suggest nothing - changed; in fact the turn did write to the ai-memory store, as above, and this receipt is - not evidence either way for anything else. + changed; in fact the turn did write to the ai-memory store, as above. The current + `claude-code--use--20260927-4` receipt (see "Host receipts" below) drops that phrase at + the source and states this scope explicitly in its own limitations instead, the same kind + of correction the codex `-4` receipt below already made for "for safety." - The superseded `codex--use--20260927-3` receipt's claim text (and this README, before this revision) described its exec turn as overriding "sandbox to read-only **for safety**." As the "Codex" section above now states, `--sandbox read-only` bounds only @@ -445,23 +555,27 @@ committed**. ## Host receipts -Seven receipts under +Eight receipts under [`evidence/hosts/mac-coordinator-64gb-20260925/`](../../hosts/mac-coordinator-64gb-20260925/), all `evidence_class: native_proven`, `stage: use`, `result: pass`, `layer_refs: foundation/native-clients`, `second_physical_machine: true`. Each component's receipts form one superseding chain per host/component/stage/date; only the latest generation is current evidence, and the schema keeps every earlier generation byte-identical rather than deleting -it. claude-code's current generation is `-3` (original, then `-2`, then `-3`); codex's is -`-4` (original, then `-2`, `-3`, then `-4` — recorded in this review-fix pass so its +it. claude-code's current generation is `-4` (original, then `-2`, `-3`, then `-4` — +recorded in this review-fix pass so its positive control gates on, and prints, a `Read` +tool_use whose own input targets the fixture by basename, not merely the presence of a +same-named tool call anywhere in the transcript; see the findings below); codex's is `-4` +(original, then `-2`, `-3`, then `-4` — recorded in an earlier review-fix pass so its positive control gates on, and prints, a `command_execution` that actually references the fixture, rather than the first successful `command_execution` of any kind; see the findings below): | Receipt | Component / version run | What it backs | | --- | --- | --- | -| [`...--claude-code--use--20260927.json`](../../hosts/mac-coordinator-64gb-20260925/mac-coordinator-64gb-20260925--claude-code--use--20260927.json) | claude-code 2.1.283 | superseded twice; version was only a flag here, not a retained command | +| [`...--claude-code--use--20260927.json`](../../hosts/mac-coordinator-64gb-20260925/mac-coordinator-64gb-20260925--claude-code--use--20260927.json) | claude-code 2.1.283 | superseded three times; version was only a flag here, not a retained command | | [`...--claude-code--use--20260927-2.json`](../../hosts/mac-coordinator-64gb-20260925/mac-coordinator-64gb-20260925--claude-code--use--20260927-2.json) | claude-code 2.1.283 | superseded by `-3` (review findings: the claim asserted a Read-tool check and a `claude mcp list` failure-mode the commands did not perform; see below) | -| [`...--claude-code--use--20260927-3.json`](../../hosts/mac-coordinator-64gb-20260925/mac-coordinator-64gb-20260925--claude-code--use--20260927-3.json) | claude-code 2.1.283 | current. `command -v`/`readlink -f`/`--version`; a headless `claude -p` turn (random-fixture line-count positive control, matched, plus an in-transcript negative control on a deliberately wrong count, correctly rejected) that also scans the transcript's own `tool_use` events and fails unless a `Read` call is present (it does not check what that `Read` call's input was, only that its name appears among the used tools); and a `claude mcp list` whose own exit code is captured with no shell pipe, failing unless it is 0 and every reported server's status contains `Connected` (5 servers, all Connected). Its own limitations end "no mutation evidenced" — see "Memory-store writes during recording" above for why that is not a check this receipt runs | +| [`...--claude-code--use--20260927-3.json`](../../hosts/mac-coordinator-64gb-20260925/mac-coordinator-64gb-20260925--claude-code--use--20260927-3.json) | claude-code 2.1.283 | superseded by `-4` (review findings: the positive control's checker scanned the transcript's `tool_use` events for a `Read` call's *name* only, never its input, so a transcript containing an unrelated `Read` call plus a separate Bash-based fixture count would have satisfied the same check; its own limitations also ended "no mutation evidenced," which "Memory-store writes during recording" above corrects; see below) | +| [`...--claude-code--use--20260927-4.json`](../../hosts/mac-coordinator-64gb-20260925/mac-coordinator-64gb-20260925--claude-code--use--20260927-4.json) | claude-code 2.1.283 | current. `command -v`/`readlink -f`/`--version`; a headless `claude -p` turn (random-fixture line-count positive control, matched, plus an in-transcript negative control on a deliberately wrong count, correctly rejected) whose transcript scan now requires, and prints, a `Read` tool_use whose own `input.file_path` — compared by basename only, never printed in full — equals the fixture's file name, alongside a same-transcript negative control checking for a different, unread basename, correctly rejected; and a `claude mcp list` whose own exit code is captured with no shell pipe, failing unless it is 0 and every reported server's status contains `Connected` (5 servers, all Connected). No longer ends its limitations with "no mutation evidenced" (corrected at the source; see "Memory-store writes during recording" above) | | [`...--codex--use--20260927.json`](../../hosts/mac-coordinator-64gb-20260925/mac-coordinator-64gb-20260925--codex--use--20260927.json) | codex-cli 0.158.0-alpha.2.1 | superseded three times; version was only a flag here, not a retained command | | [`...--codex--use--20260927-2.json`](../../hosts/mac-coordinator-64gb-20260925/mac-coordinator-64gb-20260925--codex--use--20260927-2.json) | codex-cli 0.158.0-alpha.2.1 | superseded by `-3` (review findings: the version-check command's exit code was actually a later `echo`'s, not `codex --version`'s; the claim named a specific model command that was not checked; `approval_policy`/`sandbox_mode` were claimed without a live check; the mcp-list check's summary line and the `socraticode` row fell outside the 400-char excerpt — `cua_repl` and `codex_app` were inside it, not cut off; see below) | | [`...--codex--use--20260927-3.json`](../../hosts/mac-coordinator-64gb-20260925/mac-coordinator-64gb-20260925--codex--use--20260927-3.json) | codex-cli 0.158.0-alpha.2.1 | superseded by `-4` (review findings: the positive control's checker accepted the first successful `command_execution` in the transcript, whichever it was — this generation's own retained excerpt shows a plugin `SKILL.md` read satisfied it, with no relation to the fixture; `mcp list`/`features list` piped codex's own stderr into the JSON/text parse and discarded codex's own exit code behind `python3`'s exit code; the claim called `--sandbox read-only` a safety boundary though it does not bound the declared `context-mode` MCP server or Codex's plugin-provided tools; see below and "Memory-store writes during recording" above) | @@ -477,7 +591,7 @@ needs independent review plus the matrix flip rule in and this PR's merge does not wait on that being fixed.** `docs/contributing-evidence.md` section 3, step 8's four review points (`docs/contributing-evidence.md:340-363`) include, as point 4, "bound to the winner": the receipt's -`tool_versions` must match the landscape winner's pin. The current claude-code `-3` and +`tool_versions` must match the landscape winner's pin. The current claude-code `-4` and codex `-4` receipts are both `--allow-unbound-version`; the tested codex is the ChatGPT app's bundled alpha build, which cannot bind to an `openai/codex` release pin at all, at any version. So a review that adequacy-checks all four points must record `needs_changes` on @@ -583,7 +697,7 @@ From the coordinator's Stage 1 run, plus this session's own checks where noted: ## Limits - This document and its `-2` and later receipt generations are the evidence-PR session's - own work (claude-code's `-3` and codex's `-3`/`-4` generations were recorded in later + own work (claude-code's `-3`/`-4` and codex's `-3`/`-4` generations were recorded in later review-fix passes on 2026-09-27, applying this PR's own review findings); the client-layer install itself (backup, agents/guard/MCP install, settings render/apply, skills/plugins/workflows, Codex wiring) was performed earlier by this same session, @@ -593,19 +707,21 @@ From the coordinator's Stage 1 run, plus this session's own checks where noted: session, not two observers. - Every receipt generation carries only the recorder's self-review; `accepted` needs an independent review from a separate session (requested in the PR). See "Host receipts" - above for why the current claude-code `-3` and codex `-4` generations cannot reach + above for why the current claude-code `-4` and codex `-4` generations cannot reach `agree` from any reviewer, by construction, regardless of who reviews them (both are `--allow-unbound-version`). - No `platform_status` is changed by this PR. `adoption/manifest.json`'s macOS platform profile status is a separate, maintainer-judgment field this PR does not touch. -- Counts, booleans, file names and, in the current `-3` claude-code and `-4` codex receipts, +- Counts, booleans, file names and, in the current `-4` claude-code and `-4` codex receipts, tool names and item-type tallies appear; no session id, uuid, working-directory path, MCP server command/args/env, or personal path appears in this document or in any receipt's - retained command output. Only one of the two prints a command line at all: the `-4` codex - receipt captures the one `command_execution` its positive control gates on, with its - scratch directory replaced by `` in the printed text; the `-3` claude-code - receipt's own retained output has no command line anywhere in it, only the `tool_use_names` - its transcript scan records (see "Host receipts" above for both). + retained command output. Both current generations print something about the one match + their own positive control found, but neither prints a real path: the `-4` codex receipt + captures the one `command_execution` its positive control gates on, with its scratch + directory replaced by `` in the printed text; the `-4` claude-code receipt prints + only the constant string `/fixture.txt` (or `none`) for the matched `Read` call's + target, never the real `input.file_path` value, alongside the `tool_use_names` its + transcript scan already recorded (see "Host receipts" above for both). - Host request [#382](https://github.com/seathatflowsinourveins/native-agent-stack/issues/382) still carries the `request:blocked` label as of this PR. Its status comment (written by `scripts/host_requests.py`, updated 2026-09-27T05:08:09Z) gives the reason: "Claude Code's diff --git a/evidence/hosts/mac-coordinator-64gb-20260925/mac-coordinator-64gb-20260925--claude-code--use--20260927-4.json b/evidence/hosts/mac-coordinator-64gb-20260925/mac-coordinator-64gb-20260925--claude-code--use--20260927-4.json new file mode 100644 index 000000000..b46ffb3a7 --- /dev/null +++ b/evidence/hosts/mac-coordinator-64gb-20260925/mac-coordinator-64gb-20260925--claude-code--use--20260927-4.json @@ -0,0 +1,77 @@ +{ + "schema_version": 1, + "id": "mac-coordinator-64gb-20260925--claude-code--use--20260927-4", + "kind": "host_acceptance", + "host": { + "host_id": "mac-coordinator-64gb-20260925", + "platform_id": "macos-arm64", + "os": "macos", + "architecture": "arm64", + "second_physical_machine": true, + "hardware_profile_ref": "mac-coordinator-64gb-20260925" + }, + "catalog_revision": "327d139d99f85a31d9cc50321838fec210278951", + "recorded_by": { + "identity_sha256": "91719ef8aa813c0bf50b26570098baa57e4c043d7d23d4cc5c26ce7c17710954", + "model": "claude-sonnet-5" + }, + "component_id": "claude-code", + "stage": "use", + "commands": [ + { + "cmd": "p=$(command -v claude)\necho \"resolved: $p\"\necho \"readlink: $(readlink -f \"$p\" 2>/dev/null || echo \"$p (not a symlink)\")\"\nclaude --version", + "exit": 0, + "duration_s": 0.042, + "output_sha256": "73436ead43a0c9c18663723a30ad3e166719def4b5eca2219418aa57432d886c", + "output_excerpt": "resolved: ~/.local/bin/claude\nreadlink: ~/.local/share/claude/versions/2.1.283\n2.1.283 (Claude Code)\n" + }, + { + "cmd": "D=\"$(mktemp -d)\"\nn=$((7 + RANDOM % 90))\n: > \"$D/fixture.txt\"\nfor i in $(seq 1 \"$n\"); do echo $((RANDOM % 900 + 1)) >> \"$D/fixture.txt\"; done\nreal=$(wc -l < \"$D/fixture.txt\" | tr -d ' ')\ncd \"$D\"\nclaude -p --output-format stream-json --verbose \"Count the lines in the file ./fixture.txt in your current working directory using your Read tool, then reply with exactly one line of the form COUNT= and nothing else.\" < /dev/null > out.jsonl 2> err.log\nrc=$?\npython3 - \"$real\" \"$rc\" <<'PY'\nimport json, os, re, sys\nreal, rc = sys.argv[1], sys.argv[2]\nevents = []\nfor line in open(\"out.jsonl\"):\n line = line.strip()\n if not line:\n continue\n try:\n events.append(json.loads(line))\n except ValueError:\n continue\ninit = {}\nfinal = {}\ntool_names = []\nread_basenames = []\nfor ev in events:\n if ev.get(\"type\") == \"system\" and ev.get(\"subtype\") == \"init\" and not init:\n init = ev\n if ev.get(\"type\") == \"result\":\n final = ev\n if ev.get(\"type\") == \"assistant\":\n msg = ev.get(\"message\") or {}\n for block in msg.get(\"content\") or []:\n if isinstance(block, dict) and block.get(\"type\") == \"tool_use\":\n tool_names.append(block.get(\"name\"))\n if block.get(\"name\") == \"Read\":\n inp = block.get(\"input\") or {}\n fp = inp.get(\"file_path\") or \"\"\n if fp:\n read_basenames.append(os.path.basename(fp))\n\ndef check(expected):\n text = final.get(\"result\") or \"\"\n m = re.search(r\"COUNT=(\\d+)\", text)\n got = m.group(1) if m else None\n ok = (not final.get(\"is_error\")) and (got == expected)\n return ok, got\n\ncounts = {}\nfor key in (\"agents\", \"skills\", \"plugins\", \"mcp_servers\", \"slash_commands\", \"tools\"):\n v = init.get(key)\n if isinstance(v, list):\n counts[key] = len(v)\nmcp_status = sorted({s.get(\"status\") for s in init.get(\"mcp_servers\", []) if isinstance(s, dict)})\nok, got = check(real)\nunique_tools = {t for t in tool_names}\nread_used = \"Read\" in unique_tools\nwrong = str(int(real) + 1)\nneg_ok, neg_got = check(wrong)\n\nread_call_count = len(read_basenames)\nfixture_matched = \"fixture.txt\" in read_basenames\nread_target = \"/fixture.txt\" if fixture_matched else \"none\"\nneg_name_matched = \"notfixture.txt\" in read_basenames\n\nprint(\"permissionMode=\" + str(init.get(\"permissionMode\")) + \" model=\" + str(init.get(\"model\")))\nprint(\"counts=\" + json.dumps(counts, sort_keys=True))\nprint(\"mcp_status=\" + json.dumps(mcp_status))\nprint(\"tool_use_names=\" + json.dumps(sorted(unique_tools)))\nprint(\"read_tool_used=\" + str(read_used))\nprint(\"read_call_count=\" + str(read_call_count))\nprint(\"read_target=\" + read_target)\nprint(\"fixture_read_matched=\" + str(fixture_matched))\nprint(\"fixture_read_negative_control_target=/notfixture.txt matched=\" + str(neg_name_matched) + \" correctly_rejected=\" + str(not neg_name_matched))\nprint(\"turn_subtype=\" + str(final.get(\"subtype\")) + \" is_error=\" + str(final.get(\"is_error\")))\nprint(\"positive_control expected=\" + real + \" got=\" + str(got) + \" match=\" + str(got == real))\nprint(\"negative_control expected=\" + wrong + \" got=\" + str(neg_got) + \" correctly_rejected=\" + str(not neg_ok))\noverall_ok = (rc == \"0\") and ok and read_used and (not neg_ok) and fixture_matched and (not neg_name_matched)\nraise SystemExit(0 if overall_ok else 1)\nPY", + "exit": 0, + "duration_s": 16.348, + "output_sha256": "0a684a6890a86b6072a33232ed0733996c3a813342e3a138c04cc08bc733f9c3", + "output_excerpt": "permissionMode=bypassPermissions model=claude-opus-5-5\ncounts={\"agents\": 18, \"mcp_servers\": 5, \"plugins\": 11, \"skills\": 67, \"slash_commands\": 107, \"tools\": 118}\nmcp_status=[\"connected\"]\ntool_use_names=[\"Bash\", \"Read\"]\nread_tool_used=True\nread_call_count=1\nread_target=/fixture.txt\nfixture_read_matched=True\nfixture_read_negative_control_target=/notfixture.txt matched=False correctl" + }, + { + "cmd": "D=\"$(mktemp -d)\"\ncd \"$D\"\nclaude mcp list < /dev/null > mcp.txt 2> mcp.err\nrc=$?\npython3 - \"$rc\" <<'PY'\nimport sys\nrc = sys.argv[1]\nrows = []\nfor line in open(\"mcp.txt\"):\n line = line.rstrip(\"\\n\")\n if \" - \" not in line or \": \" not in line:\n continue\n name, _, _ = line.partition(\": \")\n _, _, status = line.rpartition(\" - \")\n rows.append((name.strip(), status.strip()))\nrows.sort()\nfor name, status in rows:\n print(name + \": \" + status)\nprint(\"count=\" + str(len(rows)))\nall_connected = len(rows) > 0\nfor _, status in rows:\n if \"Connected\" not in status:\n all_connected = False\nprint(\"all_connected=\" + str(all_connected))\nok = (rc == \"0\") and all_connected\nraise SystemExit(0 if ok else 1)\nPY", + "exit": 0, + "duration_s": 1.809, + "output_sha256": "e9cb063aaaa533b0784fe1c29fece9b4df655f35d6f3ecc87bc4480b31204975", + "output_excerpt": "ai-memory: \u2714 Connected\nopenaiDeveloperDocs: \u2714 Connected\nplugin:context-mode:context-mode: \u2714 Connected\nserena: \u2714 Connected\nsocraticode: \u2714 Connected\ncount=5\nall_connected=True\n" + } + ], + "tool_versions": { + "claude-code": "2.1.283" + }, + "observed_at_utc": "2026-09-27T14:39:22Z", + "result": "pass", + "claim": "On host mac-coordinator-64gb-20260925 (macOS arm64), the installed Claude Code client, resolved and versioned by the first command below, performs a real headless turn from a freshly created scratch working directory under this Mac's user-scope client-layer profile (~/.claude): given a fixture file it creates itself with a random line count (7-96), `claude -p --output-format stream-json --verbose` replies with the correct count, while the run's init event reports the loaded profile's agent/skill/plugin/MCP-server/slash-command/tool counts and every configured MCP server's connection status. The transcript's own tool_use events are scanned; the check fails unless a `Read` tool_use is present whose own `input.file_path`, compared by basename only, equals the fixture's file name (`fixture.txt`) -- so \"reads the fixture file with its own Read tool\" is a checked claim here, backed by that call's own input, not merely the presence of a same-named tool used on some other file. The matched call's target is never printed in full, only the constant sanitized form `/fixture.txt`; a same-transcript negative control repeats the same basename check for a different, unread file name (`notfixture.txt`) and confirms it is correctly rejected, alongside the existing negative control on a deliberately wrong line count. A separate `claude mcp list` from another fresh scratch directory captures its own exit code directly with no shell pipe between it and the check, and the check fails unless that exit code is 0 and every reported server's status contains 'Connected'. All commands exit 0 only when their respective checks pass.", + "limitations": [ + "Recorded from a Claude Code session in a git worktree of this repository (see this receipt's own catalog_revision), not a pinned install checkout; the first command's --version reports 2.1.283, newer than the catalog's claude-code pin 2.1.278, so this receipt is recorded with --allow-unbound-version and does not count toward the winner's status.", + "second_physical_machine is declared, not proven by this file: this host's measured profile (evidence/artifacts/hw-profiles/mac-coordinator-64gb-20260925/profile.json) differs from the catalog's WSL authoring laptop. The receipt carries only the recorder's self review; accepted needs an independent review from a separate session.", + "Counts, connection statuses and tool_use names only: no MCP server command line, argument, environment value, session id, uuid or working-directory path is copied into this receipt; a Read tool_use's own input.file_path is compared by basename only and never printed in full -- the receipt prints only the constant sanitized form /fixture.txt (or none) plus booleans; every other tool_use block is scanned only for its name field, never its input, and the underlying stream-json/mcp list output is never itself echoed to stdout.", + "This receipt exercises the native-clients role (a version check, one headless turn and an MCP listing); it does not exercise claude-code's owned-writing-child role in the workers layer, which needs a different command shape.", + "The negative controls in command 2 re-run the same in-transcript checks with a deliberately wrong expected line count and a deliberately wrong file basename (notfixture.txt); each demonstrates its own comparison logic rejects a mismatch on the one real transcript, not that a second, independent model turn produced a wrong answer or read a different file.", + "This turn ran claude -p with no --permission-mode/--allowedTools/--permission-prompts; the init event's own permissionMode is bypassPermissions, inherited from this profile's user-scope settings.json, so every tool call in the turn was pre-approved. docs/harness-rules-convergence-20260922.md's PERM-03 recommends an explicit --permission-mode (or --allowedTools) plus --permission-prompts none for an unattended headless run; this receipt is a known, unremedied deviation. Fixture-only input in a fresh mktemp directory; per this README's \"Memory-store writes during recording\" section, this turn does write a new session/project into this host's live ai-memory store, which no command in this receipt checks." + ], + "evidence_class": "native_proven", + "reviews": [ + { + "kind": "self", + "ref": "scripts/host_receipts.py record", + "verdict": "agree", + "at_utc": "2026-09-27T14:39:22Z", + "reviewer": { + "identity_sha256": "91719ef8aa813c0bf50b26570098baa57e4c043d7d23d4cc5c26ce7c17710954", + "model": "claude-sonnet-5" + } + } + ], + "layer_refs": [ + { + "catalog": "foundation", + "layer_id": "native-clients" + } + ], + "supersedes": "mac-coordinator-64gb-20260925--claude-code--use--20260927-3" +} diff --git a/manifests/evidence.json b/manifests/evidence.json index f10b300c6..23e514019 100644 --- a/manifests/evidence.json +++ b/manifests/evidence.json @@ -13208,7 +13208,7 @@ }, { "path": "catalogs/landscape/component-evidence-matrix.json", - "sha256": "15ab971b4e16347afb29da1a2e6cb05da99471dfe7b255b932b8fa2f74442f42", + "sha256": "658912b57736bf7baab50841dc72f745a1ebbaa7db4986ebb0c1a93b8ede6993", "bytes": 189734 }, { @@ -13723,7 +13723,7 @@ }, { "path": "docs/component-evidence-matrix.md", - "sha256": "46b5c8cefc73ba82c0e92f3b06dbd2c3757b2cc01d33c67cf1e2cd6cb651d95f", + "sha256": "13734fa72536f3645b93a3134f7a48df447d42bff102a16fd4b5362ae0fdc527", "bytes": 19505 }, { @@ -30638,8 +30638,8 @@ }, { "path": "evidence/artifacts/mac-stage1-client-layer-20260927/README.md", - "sha256": "bc5fc0040cce6aea059c60fe342e47632526067fe4e83bb61aa470eecaa35575", - "bytes": 47670 + "sha256": "966ac7b98cd0bc01bef6c0ddfa3332c72d41c995b6da95f3c1e82383e6759d6b", + "bytes": 61977 }, { "path": "evidence/artifacts/macos-application-20260924/run-summary.json", @@ -36576,6 +36576,11 @@ "sha256": "71f4475c70a2dddf0143f0288218a021728134a7269c5ba36479db480ca8598d", "bytes": 9974 }, + { + "path": "evidence/hosts/mac-coordinator-64gb-20260925/mac-coordinator-64gb-20260925--claude-code--use--20260927-4.json", + "sha256": "1c7b633b3b3aa2690911aefbeac30c3e0a75d095ef6e573b2f802bfe11797e4a", + "bytes": 11377 + }, { "path": "evidence/hosts/mac-coordinator-64gb-20260925/mac-coordinator-64gb-20260925--claude-code--use--20260927.json", "sha256": "45eb8886eba9eea56fad70d181c299061b0d314c27a21acaa92ee27f73d5d713", From 9efe6fcf436935d77722b48e62353e2f3a923cad Mon Sep 17 00:00:00 2001 From: seathatflowsinourveins <234074349+seathatflowsinourveins@users.noreply.github.com> Date: Sun, 27 Sep 2026 10:50:12 -0400 Subject: [PATCH 11/12] Hot-file protocol: re-register this branch's evidence files after merging origin/main origin/main moved by 2 commits touching manifests/evidence.json since this branch's last push. Per docs/lanes.md, took main's copy rather than trust git's clean auto-merge, and re-registered this branch's 9 evidence files (8 host receipts + the Stage 1 client-layer README) with host_receipts.register_file, then re-ran component_matrix.py --write and new_host_grand_list.py --write (both no-ops here; content already matched). Also corrects one README aside that origin/main's merge made stale: 3 of the 10 catalog agent files it lists (isolated-builder, source-scout, stack-verifier) were revised on main after this host's Stage 1 install, so they no longer match the repository copy today. The sha256 gate itself is unaffected (it always compared against a live-read digest, never the repository's), only the informational "matches the repo copy" aside needed correcting. Co-Authored-By: Claude Sonnet 5 Claude-Session: https://claude.ai/code/session_017d27CMzkbLezdLv7vAStPu --- .../mac-stage1-client-layer-20260927/README.md | 11 +++++++++-- manifests/evidence.json | 4 ++-- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/evidence/artifacts/mac-stage1-client-layer-20260927/README.md b/evidence/artifacts/mac-stage1-client-layer-20260927/README.md index 0aac1dae5..fedb7d140 100644 --- a/evidence/artifacts/mac-stage1-client-layer-20260927/README.md +++ b/evidence/artifacts/mac-stage1-client-layer-20260927/README.md @@ -66,8 +66,15 @@ Undo each with its own native command (all read-only to verify first: `claude pl repository source, so each removal is gated on a digest read directly from the live file in this review-fix pass — recorded 2026-09-27 from the live file, not an install-time digest — rather than assumed from the repository copy. As a factual aside, not part of the gate -itself, all 10 also match their [`adoption/agents/claude/`](../../../adoption/agents/claude/) -repository copies exactly today: +itself: 7 of the 10 also match their +[`adoption/agents/claude/`](../../../adoption/agents/claude/) repository copies exactly as of +this commit (`blind-adjudicator`, `blind-judge`, `blind-lane-reviewer`, `evidence-reviewer`, +`security-reviewer`, `semantic-evidence-reviewer`, `stack-researcher`); the other 3 +(`isolated-builder.md`, `source-scout.md`, `stack-verifier.md`) do not, because this branch's +merge of `origin/main` (below) revised those three agent definitions after this host installed +its own copies — an ordinary divergence for a file this document never claimed was pinned or +byte-identical, not evidence of anything wrong with the live install, and exactly why the gate +below reads the live digest rather than the repository's: ```sh f=~/.claude/agents/blind-adjudicator.md; [ "$(shasum -a 256 "$f" | cut -d' ' -f1)" = "ef8d07f15b7c219f1b5ada705cf185146088fd013974b5ca51c1d29fdeee9fc4" ] && rm "$f" || echo "kept $f (missing, or changed since Stage 1)" diff --git a/manifests/evidence.json b/manifests/evidence.json index 8cb5e5583..dd2183103 100644 --- a/manifests/evidence.json +++ b/manifests/evidence.json @@ -30643,8 +30643,8 @@ }, { "path": "evidence/artifacts/mac-stage1-client-layer-20260927/README.md", - "sha256": "966ac7b98cd0bc01bef6c0ddfa3332c72d41c995b6da95f3c1e82383e6759d6b", - "bytes": 61977 + "sha256": "317e3628460fd9bc43b9c9612b736d7ec2e414b32cea3656d66f78868c8fec62", + "bytes": 62595 }, { "path": "evidence/artifacts/macos-application-20260924/run-summary.json", From cd0d37ebc206fc16109de9f6a0c1f917217c0bfe Mon Sep 17 00:00:00 2001 From: seathatflowsinourveins <234074349+seathatflowsinourveins@users.noreply.github.com> Date: Sun, 27 Sep 2026 10:54:13 -0400 Subject: [PATCH 12/12] Fix round 3 self-review: correct unverified claims in the skills/plugin rollback prose - Reworded the skills -a validation claim: this session read the CLI's agents object keys directly from cli.mjs rather than triggering a live "Invalid agents" error (the extracted 1.7.0 package has no node_modules of its own to run standalone in this environment). - Fixed the Codex context-mode plugin's cache path: it resolves through the context-mode marketplace (~/.codex/plugins/cache/context-mode/context-mode/), not openai-bundled -- this document's own codex -3 receipt excerpt already retains a command under the correct path, so the two now agree. - Reworded the canonical-skill-removal claim to state the CLI's mechanism (keeps the canonical copy and lock entry only if another installed agent still links them, otherwise removes both) rather than assert an outcome for this host that detectInstalledAgents() was never actually run to confirm. - Dropped a dangling "(below)" with nothing to point to. - Confirmed (ls, names only) that the pre-Stage-1 backup's claude/skills/typesafe-ai/ does hold LICENSE and SKILL.md, matching what the README already claimed from the earlier live-symlink check. Co-Authored-By: Claude Sonnet 5 Claude-Session: https://claude.ai/code/session_017d27CMzkbLezdLv7vAStPu --- .../README.md | 31 ++++++++++++------- manifests/evidence.json | 4 +-- 2 files changed, 22 insertions(+), 13 deletions(-) diff --git a/evidence/artifacts/mac-stage1-client-layer-20260927/README.md b/evidence/artifacts/mac-stage1-client-layer-20260927/README.md index fedb7d140..8bd99dcc5 100644 --- a/evidence/artifacts/mac-stage1-client-layer-20260927/README.md +++ b/evidence/artifacts/mac-stage1-client-layer-20260927/README.md @@ -71,7 +71,7 @@ itself: 7 of the 10 also match their this commit (`blind-adjudicator`, `blind-judge`, `blind-lane-reviewer`, `evidence-reviewer`, `security-reviewer`, `semantic-evidence-reviewer`, `stack-researcher`); the other 3 (`isolated-builder.md`, `source-scout.md`, `stack-verifier.md`) do not, because this branch's -merge of `origin/main` (below) revised those three agent definitions after this host installed +merge of `origin/main` revised those three agent definitions after this host installed its own copies — an ordinary divergence for a file this document never claimed was pinned or byte-identical, not evidence of anything wrong with the live install, and exactly why the gate below reads the live digest rather than the repository's: @@ -169,8 +169,10 @@ either way, but its listed benefit is currently theoretical for that plugin spec `-m/--marketplace`, `--enable`, `--disable`, `--json`, `-h/--help`) has nothing that preserves data. So `codex plugin remove context-mode@context-mode` above unconditionally removes both the plugin's registration and its cache directory under -`~/.codex/plugins/cache/openai-bundled/context-mode/` (or whichever marketplace it resolves -through) — there is no partial-preserve option in this build. Whether it also edits +`~/.codex/plugins/cache/context-mode/context-mode/` (the `context-mode` marketplace this +plugin resolves through — confirmed by this same document's own codex `-3` receipt excerpt +below, which retains a `cat` of a file under that exact path) — there is no partial-preserve +option in this build. Whether it also edits `config.toml`'s own `[plugins."*@*"]` table is not stated by the help text and not tested by this document. @@ -224,14 +226,21 @@ then removes `/` for each one that exists on disk, same-named skill belonging to a tool Stage 1 never installed anything for would be deleted too if that tool happened to have one. `-a claude-code codex` restricts the per-agent cleanup loop to exactly those two link locations; `claude-code` and `codex` are the CLI's own agent -keys (confirmed by triggering its own "Invalid agents" validation with a nonsense name, which -lists them). This still fully removes the canonical skill content and its lock entry, not -just the two links: the CLI's own removal loop (`cli.mjs`, matching `remove.ts`) checks, after -the scoped agents are cleaned up, whether any *other* installed-but-untouched agent still -links the skill (`detectInstalledAgents()` minus the `-a` list) before deleting the shared -canonical copy — with only claude-code and codex installed on this host, nothing remains -linked, so the canonical copy and lock entry are still removed exactly as the decision record -describes, just without touching any other tool's directory to get there. One further +keys, read directly from its `agents` object in `cli.mjs` (`"claude-code": {` and `codex: {`, +the same object the invalid-agent check at removeCommand's start validates `-a` values +against — this document cites the source directly rather than a live CLI run, since the +pinned package as extracted for this review has no `node_modules` of its own to run +standalone). This still aims to fully remove the canonical skill content and its lock entry, +not just the two links: the CLI's own removal loop (`cli.mjs`, matching `remove.ts`) checks, +after the scoped agents are cleaned up, whether any *other* installed-but-untouched agent +still links the skill (`detectInstalledAgents()` minus the `-a` list, including any further +universal agent that shares this same canonical `~/.agents/skills` store) before deleting the +shared canonical copy; this document did not run `detectInstalledAgents()` to confirm the +result for this host, so it states the mechanism, not the outcome: the canonical copy and +lock entry are removed unless the CLI detects another installed agent still linked to them, +in which case it conservatively keeps both rather than deleting them out from under that +other agent — either way, `-a claude-code codex` never causes an *extra* deletion beyond what +the unscoped form would also have removed. One further syntax note the CLI's own arg parser requires: `-a` must be the *last* flag on the line, after `-g -y`, not before — it greedily consumes every following bare word as an agent name, so `-a claude-code codex -g -y` would try to treat `-g` and `-y` themselves as agent names diff --git a/manifests/evidence.json b/manifests/evidence.json index dd2183103..4e9ba9af9 100644 --- a/manifests/evidence.json +++ b/manifests/evidence.json @@ -30643,8 +30643,8 @@ }, { "path": "evidence/artifacts/mac-stage1-client-layer-20260927/README.md", - "sha256": "317e3628460fd9bc43b9c9612b736d7ec2e414b32cea3656d66f78868c8fec62", - "bytes": 62595 + "sha256": "df6c3e4ad05911232fb6d4b027774f9d57730c1a5b59fe973ae382bff9e2a5b8", + "bytes": 63328 }, { "path": "evidence/artifacts/macos-application-20260924/run-summary.json",