Repository navigation
Reconcile the MCP templates with the live registrations: code graph key, promptfoo and a drift report - #1034
Conversation
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 6a7a7ce799
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
…dgement sources; apply the ecosystem root to Codex; call the code graph server by its registered name Four blockers of the first reads of #1034 (Astra at 6a7a7ce and the open review threads), one commit: - Credential-bearing arguments reached both output formats (28 of 28 checks over seven forms, two clients, two formats). A description is now built from names, counts and fixed words: option names, scheme://host, a command's file name, environment and header names; every other argument, and a URL's userinfo, port, path and query, is the placeholder <withheld>. Values are still compared in memory. Names that do not have the shape of a name are withheld too. Tests: the seven forms x two clients x two formats, 300 seeded random values at every position, option-name look-alikes, odd names. - Acknowledgement sources accepted /etc/passwd and ../x. A source is now a relative path to a regular file beneath the repository: absolute paths and `..` are refused and symlinks are resolved before the containment check. - --eco-root (and ECO_INSTALL_ROOT) reached the Claude renderer only, so Codex kept the default prefix (six false DIFFERS rows). The root is set in the host values of the shared render. Test: a non-default prefix renders in both clients and compares SAME from the option and from the environment. - The renamed example registers only `codebase-memory-mcp`, but the published calls selected `codebase-memory.<tool>`, which MCPorter rejects (openclaw/mcporter@e4cb0022 src/cli/call-command.ts L309-346, src/runtime.ts L229-235). The calls in manifests/stack.json, recipes/README.md, docs/token-efficiency-stack.json, the saturation audit and the foundation-memory catalog now select the registered name; the transcript classifiers keep the old alias for sessions recorded before the rename. Test: tests/test_mcporter_selectors.py resolves each published selector against the example. catalogs/landscape/final-stack.json is regenerated from the changed manifests/stack.json (python3 scripts/final_stack.py --write; its digest line is the only change). The evidence rows of the changed files are re-registered at their final bytes. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 4916d3a479
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
… with exit 2, withhold a URL that holds an @, and correct the record Fix wave 2 of #1034, on 4916d3a: the Codex review threads of 4916d3a, the second GPT read (blockers 1 and 2) and the command center's full read (two blockers, six stale claims, P3-a to P3-f). - A token that looks like an option can be a value: the operand of a short option (`-k --x`), a positional value after `--`, the credential in `--api-key --secret-token`. The shape of a token cannot decide what may be printed (CPython Lib/argparse.py L1964 and L2503 at v3.12.3, and Lib/getopt.py, return such tokens as values), so arguments are counted ("2 args") and never shown, on both sides of a row. - A malformed number reached float(), whose ValueError quotes the value with %R (CPython Objects/floatobject.c, float_from_string_inner: v3.12.3 L190-193, v3.13.16 L183-186), and main() caught only DriftError, so the traceback printed it and the exit code was 1. A field of an unexpected shape (a non-numeric timeout, a list that is a string, a table that is a list, a Codex mcp_servers that is not a table) now ends the run with exit 2 and a message that names the server and never the value. - A userinfo that holds an unescaped `/`, `?` or `#` parses as the host (CPython Lib/urllib/parse.py urlsplit, v3.13.16 L472), so a URL that holds an `@` anywhere, a port that does not parse, or a scheme or host of another shape is withheld whole; the transport is one of stdio, http, sse (else withheld); paths are printed relative to the home; a read error names the kind of error, not its text. - recipes/README.md ran `mcporter ... list codebase-memory`, which works only through MCPorter's auto-correction: it names the registered key, and the selector test scans `list SERVER` too. - The decision record states the installed promptfoo (0.124.0 on the first host, pinned 0.123.1), SocratiCode's launcher per client, the four promptfoo tools that only read local state (run_assertion and validate_promptfoo_config do not) and the 2026 transport locator (L58-L61); the property test names the positions it covers. Fail-first: the final tests (37) give 45 failures and 10 errors against the implementation of 4916d3a and 82 failures and 26 errors against 6a7a7ce, and pass here; 29 of 29 mutants killed. The evidence rows of the changed files are updated. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2d131c0 to
cecf039
Compare
…dgement sources; apply the ecosystem root to Codex; call the code graph server by its registered name Four blockers of the first reads of #1034 (Astra at 6a7a7ce and the open review threads), one commit: - Credential-bearing arguments reached both output formats (28 of 28 checks over seven forms, two clients, two formats). A description is now built from names, counts and fixed words: option names, scheme://host, a command's file name, environment and header names; every other argument, and a URL's userinfo, port, path and query, is the placeholder <withheld>. Values are still compared in memory. Names that do not have the shape of a name are withheld too. Tests: the seven forms x two clients x two formats, 300 seeded random values at every position, option-name look-alikes, odd names. - Acknowledgement sources accepted /etc/passwd and ../x. A source is now a relative path to a regular file beneath the repository: absolute paths and `..` are refused and symlinks are resolved before the containment check. - --eco-root (and ECO_INSTALL_ROOT) reached the Claude renderer only, so Codex kept the default prefix (six false DIFFERS rows). The root is set in the host values of the shared render. Test: a non-default prefix renders in both clients and compares SAME from the option and from the environment. - The renamed example registers only `codebase-memory-mcp`, but the published calls selected `codebase-memory.<tool>`, which MCPorter rejects (openclaw/mcporter@e4cb0022 src/cli/call-command.ts L309-346, src/runtime.ts L229-235). The calls in manifests/stack.json, recipes/README.md, docs/token-efficiency-stack.json, the saturation audit and the foundation-memory catalog now select the registered name; the transcript classifiers keep the old alias for sessions recorded before the rename. Test: tests/test_mcporter_selectors.py resolves each published selector against the example. catalogs/landscape/final-stack.json is regenerated from the changed manifests/stack.json (python3 scripts/final_stack.py --write; its digest line is the only change). The evidence rows of the changed files are re-registered at their final bytes. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
… with exit 2, withhold a URL that holds an @, and correct the record Fix wave 2 of #1034, on 4916d3a: the Codex review threads of 4916d3a, the second GPT read (blockers 1 and 2) and the command center's full read (two blockers, six stale claims, P3-a to P3-f). - A token that looks like an option can be a value: the operand of a short option (`-k --x`), a positional value after `--`, the credential in `--api-key --secret-token`. The shape of a token cannot decide what may be printed (CPython Lib/argparse.py L1964 and L2503 at v3.12.3, and Lib/getopt.py, return such tokens as values), so arguments are counted ("2 args") and never shown, on both sides of a row. - A malformed number reached float(), whose ValueError quotes the value with %R (CPython Objects/floatobject.c, float_from_string_inner: v3.12.3 L190-193, v3.13.16 L183-186), and main() caught only DriftError, so the traceback printed it and the exit code was 1. A field of an unexpected shape (a non-numeric timeout, a list that is a string, a table that is a list, a Codex mcp_servers that is not a table) now ends the run with exit 2 and a message that names the server and never the value. - A userinfo that holds an unescaped `/`, `?` or `#` parses as the host (CPython Lib/urllib/parse.py urlsplit, v3.13.16 L472), so a URL that holds an `@` anywhere, a port that does not parse, or a scheme or host of another shape is withheld whole; the transport is one of stdio, http, sse (else withheld); paths are printed relative to the home; a read error names the kind of error, not its text. - recipes/README.md ran `mcporter ... list codebase-memory`, which works only through MCPorter's auto-correction: it names the registered key, and the selector test scans `list SERVER` too. - The decision record states the installed promptfoo (0.124.0 on the first host, pinned 0.123.1), SocratiCode's launcher per client, the four promptfoo tools that only read local state (run_assertion and validate_promptfoo_config do not) and the 2026 transport locator (L58-L61); the property test names the positions it covers. Fail-first: the final tests (37) give 45 failures and 10 errors against the implementation of 4916d3a and 82 failures and 26 errors against 6a7a7ce, and pass here; 29 of 29 mutants killed. The evidence rows of the changed files are updated. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
|
@codex review |
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
… the port in its property test, end three more unreadable inputs with exit 2, and say which shapes the checks name Fix wave 3 of #1034, on cecf039 (the rebased head of the second fix wave): Astra's delta read (~/.cache/ns2604-gpt-reads/fix2-pr1034-cecf039f9/VERDICT.md, one P1) and the command center's Claude micro read (pr1034-claude-micro-cecf039f.md: B2 and P3-1, P3-2, P3-3, P3-5; B1, B3, B4 and P3-4 are claims of the PR body and are corrected there). - P1 (Astra): the refusal of an acknowledgement source interpolated the rejected value with `!r`, so a path of the account, or a malformed object holding a token, reached stderr with rc 2 in both formats (CPython Doc/reference/lexical_analysis.rst v3.13.16 L785-L786: `!r` calls repr, which quotes the operand and does not redact it). A source must now be a string, and the refusal names the entry and the field, never what was given. Tests: the real command as a subprocess, eight kinds of rejected value (an account path, an object and a list holding a token, a number, text, a null byte, a null, a missing file) x text and JSON. - B2 (CC): the property test's docstring listed the port among the positions of the 300 seeded values, but no spec put a value there (a mutant that appends `:{parts.port}` passed the test alone). Two specs are added, a URL without an `@` holding the value as its path, query and fragment and one holding it as the port (a port that is not a number withholds the URL whole), and a valid five-digit port is asserted absent from the description (it is below the 8-character piece the test looks for). - P3-1: `Path.is_file()` re-raises EACCES for a directory that cannot be searched (CPython Lib/pathlib/_abc.py, v3.13.16 L476-L488), outside the conversion, so the run ended with exit 1 and a traceback naming an absolute path. It is now `cannot read ~/.codex/config.toml: PermissionError` and exit 2. - P3-2: the fields of a DIFFERS acknowledgement must be a list of strings; `sorted(entry["fields"])` raised TypeError for a list that mixes types. - P3-3: json and tomllib raise RecursionError on deeply nested input; it is an input that cannot be read (exit 2, the kind of error named), for the live files and the acknowledged file. - P3-5: the sentence "a field of an unexpected shape ends the run with exit 2" is as wide as the checks: it names them, and says that a `type` or `command` of another kind is compared and withheld. Fail-first: the new tests (41 in the module and its selector test) give 16 failures and 3 errors against the implementation of cecf039 (4 tests) and pass here; 36 of 36 mutants of the module killed. The evidence rows of the changed files are updated. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
|
@codex review |
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
…emory-mcp Carries the rename of draft #834 (its commit 6c6d817) onto current main: the typed registration key and tool namespace in the Claude and Codex templates, the client-config map, the token-lane carriers, the child-usage accounting and the tests that pin them. The instruction sources no longer name the server on main, so the instruction copies and their byte pins need no change and the draft's four-byte trim is not carried. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…'s template promptfoo mcp --transport stdio from the installed package of the manifest's promptfoo slot (Promptfoo 0.123.1), with the distribution's own state directory and telemetry and the update check off, as the host registers it. Registered for Claude Code only: the Codex entry forwards a gateway key by name and is a separate decision. The client-config map gains the piece, the record its dated counts (403 pieces, 363 wired), and the tests that pin the rendered server list, the installing slots and the stub registration list expect it. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…rations differ tools/adoption/mcp_template_drift.py renders the new-WSL templates in process with the functions of new_wsl_client_config.py --render, reads the user scope of Claude Code and the mcp_servers tables of Codex, and prints one row per client and server (SAME, DIFFERS with its fields, TEMPLATE-ONLY, LIVE-ONLY) without any env, header, URL userinfo or query value. adoption/new-wsl/mcp-drift-acknowledged.json lists the 12 differences the decision record accepts; an entry that no longer matches a row fails the run. The record carries the measurement, the jcodemunch admission-gate result, the four-route Origin and Host table and the specification citations. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Last commit of the change: the rows of every file it adds or changes, at their final bytes. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…dgement sources; apply the ecosystem root to Codex; call the code graph server by its registered name Four blockers of the first reads of #1034 (Astra at 6a7a7ce and the open review threads), one commit: - Credential-bearing arguments reached both output formats (28 of 28 checks over seven forms, two clients, two formats). A description is now built from names, counts and fixed words: option names, scheme://host, a command's file name, environment and header names; every other argument, and a URL's userinfo, port, path and query, is the placeholder <withheld>. Values are still compared in memory. Names that do not have the shape of a name are withheld too. Tests: the seven forms x two clients x two formats, 300 seeded random values at every position, option-name look-alikes, odd names. - Acknowledgement sources accepted /etc/passwd and ../x. A source is now a relative path to a regular file beneath the repository: absolute paths and `..` are refused and symlinks are resolved before the containment check. - --eco-root (and ECO_INSTALL_ROOT) reached the Claude renderer only, so Codex kept the default prefix (six false DIFFERS rows). The root is set in the host values of the shared render. Test: a non-default prefix renders in both clients and compares SAME from the option and from the environment. - The renamed example registers only `codebase-memory-mcp`, but the published calls selected `codebase-memory.<tool>`, which MCPorter rejects (openclaw/mcporter@e4cb0022 src/cli/call-command.ts L309-346, src/runtime.ts L229-235). The calls in manifests/stack.json, recipes/README.md, docs/token-efficiency-stack.json, the saturation audit and the foundation-memory catalog now select the registered name; the transcript classifiers keep the old alias for sessions recorded before the rename. Test: tests/test_mcporter_selectors.py resolves each published selector against the example. catalogs/landscape/final-stack.json is regenerated from the changed manifests/stack.json (python3 scripts/final_stack.py --write; its digest line is the only change). The evidence rows of the changed files are re-registered at their final bytes. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
… with exit 2, withhold a URL that holds an @, and correct the record Fix wave 2 of #1034, on 4916d3a: the Codex review threads of 4916d3a, the second GPT read (blockers 1 and 2) and the command center's full read (two blockers, six stale claims, P3-a to P3-f). - A token that looks like an option can be a value: the operand of a short option (`-k --x`), a positional value after `--`, the credential in `--api-key --secret-token`. The shape of a token cannot decide what may be printed (CPython Lib/argparse.py L1964 and L2503 at v3.12.3, and Lib/getopt.py, return such tokens as values), so arguments are counted ("2 args") and never shown, on both sides of a row. - A malformed number reached float(), whose ValueError quotes the value with %R (CPython Objects/floatobject.c, float_from_string_inner: v3.12.3 L190-193, v3.13.16 L183-186), and main() caught only DriftError, so the traceback printed it and the exit code was 1. A field of an unexpected shape (a non-numeric timeout, a list that is a string, a table that is a list, a Codex mcp_servers that is not a table) now ends the run with exit 2 and a message that names the server and never the value. - A userinfo that holds an unescaped `/`, `?` or `#` parses as the host (CPython Lib/urllib/parse.py urlsplit, v3.13.16 L472), so a URL that holds an `@` anywhere, a port that does not parse, or a scheme or host of another shape is withheld whole; the transport is one of stdio, http, sse (else withheld); paths are printed relative to the home; a read error names the kind of error, not its text. - recipes/README.md ran `mcporter ... list codebase-memory`, which works only through MCPorter's auto-correction: it names the registered key, and the selector test scans `list SERVER` too. - The decision record states the installed promptfoo (0.124.0 on the first host, pinned 0.123.1), SocratiCode's launcher per client, the four promptfoo tools that only read local state (run_assertion and validate_promptfoo_config do not) and the 2026 transport locator (L58-L61); the property test names the positions it covers. Fail-first: the final tests (37) give 45 failures and 10 errors against the implementation of 4916d3a and 82 failures and 26 errors against 6a7a7ce, and pass here; 29 of 29 mutants killed. The evidence rows of the changed files are updated. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
… the port in its property test, end three more unreadable inputs with exit 2, and say which shapes the checks name Fix wave 3 of #1034, on cecf039 (the rebased head of the second fix wave): Astra's delta read (~/.cache/ns2604-gpt-reads/fix2-pr1034-cecf039f9/VERDICT.md, one P1) and the command center's Claude micro read (pr1034-claude-micro-cecf039f.md: B2 and P3-1, P3-2, P3-3, P3-5; B1, B3, B4 and P3-4 are claims of the PR body and are corrected there). - P1 (Astra): the refusal of an acknowledgement source interpolated the rejected value with `!r`, so a path of the account, or a malformed object holding a token, reached stderr with rc 2 in both formats (CPython Doc/reference/lexical_analysis.rst v3.13.16 L785-L786: `!r` calls repr, which quotes the operand and does not redact it). A source must now be a string, and the refusal names the entry and the field, never what was given. Tests: the real command as a subprocess, eight kinds of rejected value (an account path, an object and a list holding a token, a number, text, a null byte, a null, a missing file) x text and JSON. - B2 (CC): the property test's docstring listed the port among the positions of the 300 seeded values, but no spec put a value there (a mutant that appends `:{parts.port}` passed the test alone). Two specs are added, a URL without an `@` holding the value as its path, query and fragment and one holding it as the port (a port that is not a number withholds the URL whole), and a valid five-digit port is asserted absent from the description (it is below the 8-character piece the test looks for). - P3-1: `Path.is_file()` re-raises EACCES for a directory that cannot be searched (CPython Lib/pathlib/_abc.py, v3.13.16 L476-L488), outside the conversion, so the run ended with exit 1 and a traceback naming an absolute path. It is now `cannot read ~/.codex/config.toml: PermissionError` and exit 2. - P3-2: the fields of a DIFFERS acknowledgement must be a list of strings; `sorted(entry["fields"])` raised TypeError for a list that mixes types. - P3-3: json and tomllib raise RecursionError on deeply nested input; it is an input that cannot be read (exit 2, the kind of error named), for the live files and the acknowledged file. - P3-5: the sentence "a field of an unexpected shape ends the run with exit 2" is as wide as the checks: it names them, and says that a `type` or `command` of another kind is compared and withheld. Fail-first: the new tests (41 in the module and its selector test) give 16 failures and 3 errors against the implementation of cecf039 (4 tests) and pass here; 36 of 36 mutants of the module killed. The evidence rows of the changed files are updated. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…e schema does not define, and withhold a command that is not text Adjudicated commit of #1034 on 55dba7f (the CC's ruling adjudication-pr1034-55dba7f4-20261012.md; Astra's third read ~/.cache/ns2604-gpt-reads/fix3-pr1034-55dba7f4c/VERDICT.md: one P1, two P2, four P3; the CC's micro pr1034-claude-micro-55dba7f4.md: L1, B5, B6, P3-6 to P3-9). - P1 (Astra): shown_stale copied the whole acknowledgement entry (`{**e, ...}`), so a key of the acknowledged file that the schema does not define, nested or not, reached stdout in the JSON format (CPython Doc/reference/expressions.rst L359-L361: dictionary unpacking adds every mapping item; Lib/json/encoder.py L354-L358, _iterencode_dict reads dct.items()); a `reason` that is an object holding a token was accepted and serialised the same way. An entry now holds the keys of ACK_FIELDS and no other (a key outside them ends the run with exit 2 and a message that names the entry and never the value), its `reason` is text, `fields` are a list of strings for every kind of row (Astra's follow-up 1 and the CC's P3-7: a stale LIVE-ONLY entry with `fields: 42` ended in a TypeError traceback), and the report builds the stale entry from the defined keys, so even a loader that let a key through publishes none of it (tested with a stub loader). - P2 (Astra) and B6 (the CC): shown_command called str() on the command, so a number, a float or a boolean, which has the shape of a file name, was printed (90817263 in all four combinations of client and format) although the docstring, the record and the body say that a command of another kind is withheld. A command that is not text is withheld; an absent or empty command stays "(no command)". The code now matches the sentence; the three places keep it, as "a `type` or a `command` that is not text". - P3-6 (the CC): the RecursionError catch of load_acknowledged had no test (dropping it left the module green); the acknowledged file joins the deeply nested live files in that test. - P3-8 (the CC): the mechanisms of two earlier corrections are cited at the pin, python/cpython@v3.13.16 (cbc944f4): sorted() over a list that mixes kinds raises TypeError (Objects/object.c L1032); nested JSON raises RecursionError (Modules/_json.c L1033 and L1041) and nested TOML does too (Lib/tomllib/_parser.py L432 and L628: parse_array and parse_value call each other with no depth guard of their own). - B5 (the CC): the corrected fail-first figures. The tests of 55dba7f over cecf039: 41 tests, FAILED (failures=17, errors=3) in 5 tests (the message of 55dba7f says 16, 3 and 4: it cannot change without a new head, and the squash body states these). The tests of this commit over 55dba7f: 48 tests, FAILED (failures=70, errors=1) in 6 tests; at this head they pass. 43 of 43 mutants of the module killed. - L1 (the CC): the branch sits on main 9cfe3a9, rebased commit by commit: the registry rows, the two rows of examples/claude-native/workflows/SHA256SUMS (child-usage.mjs and test-child-usage.mjs, recomputed over the merged files) and catalogs/landscape/final-stack.json (regenerated by scripts/final_stack.py --write) were written again by their owning tools; the PR body records the equal patch-ids. The evidence rows of the changed files are updated. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
55dba7f to
03d92cb
Compare
|
@codex review |
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
|
@codex review |
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
Scope
codebase-memory-mcp(the rename of draft Align code graph MCP server key with native client registrations #834, carried onto current main), promptfoo is wired for Claude Code, and a new read-only report,tools/adoption/mcp_template_drift.py, names every remaining difference, withadoption/new-wsl/mcp-drift-acknowledged.jsonlisting the ones a decision record accepts. No stored client configuration is changed.d8f7e2051b61bde6361a85b64f41413798015353(main after Apply verified event scopes to CI secret scans #949, the target of the latest rebase of 2026-10-12, below). The branch was cut at83cec12eec323cf3fc3d62177e38fe4163dbd3bb(main after Add fenced Claude usage sampling and Grafana panels #954); the reads before the latest rebase were made ona365d8becd8d9463ea4b58c6003de0c6f1250e82.lane:foundationadoption/new-wsl/(client-config map, the Claude MCP additions template, the new acknowledged-differences file),adoption/mcp/claude-user.json,adoption/templates/codex.config.template.toml,adoption/templates/codex.stack-worker.config.toml,adoption/hooks/claude/(two token-lane carriers and their checksums),examples/claude-native/workflows/(child-usage accounting and its checksums),tools/adoption/mcp_template_drift.py,docs/decisions/(one new record, one dated addendum),docs/token-session-handbook.md,examples/mcporter.json.example, the published MCPorter calls (the selector only:manifests/stack.json,recipes/README.md,docs/token-efficiency-stack.json,blueprints/token-native-focus/saturation-audit.json,catalogs/us-equities/foundation-memory.jsonand.md), the tests that pin these names, andmanifests/evidence.json.6c6d8179f) without its trim; (2) promptfoo for Claude Code; (3) the drift report with its tests, acknowledged differences and decision record; (4) the evidence registry; (5) the fix wave for the first reads of6a7a7ce7; (6) the fix wave for the second reads of4916d3a4; (7) the fix wave for the reads ofcecf039f; (8) the adjudicated commit for the reads of55dba7f4(both below). Each fix wave is one commit that re-registers its own files. Draft Align code graph MCP server key with native client registrations #834 is superseded by this change and is closed with a pointer to it.a365d8bec(the PR was DIRTY: a conflict inmanifests/evidence.jsononly). It is a pure rebase: each commit's diff without the registry has the same patch-id, so has the whole branch diff, and the registry rows of the 36 files the branch registers or changes are identical to those of the old head; the registry conflict was resolved by writing each commit's rows again withscripts/host_receipts.py(register_file) at the rebased bytes. The commit names in this description are the heads the reads were made on (the latest rebase, below, renames them again):6a7a7ce7is now71bc0e925,4916d3a4is95064ff58,2d131c02aiscecf039f9.d8f7e2051(the PR conflicted with fix(landscape): bind completed supersessions and redact scratch sessions #995, Preserve missing-vote candidates in final-stack survivors #1026 and Apply verified event scopes to CI secret scans #949 in three generated files, the CC's finding L1). Each commit was applied withgit cherry-pick --no-commitand the generated files were written again by their owning tools:manifests/evidence.json(the rows of the files the commit changed,scripts/host_receipts.pyregister_file, at the rebased bytes),examples/claude-native/workflows/SHA256SUMSandadoption/hooks/claude/SHA256SUMS(the rows the commit changed, recomputed over the merged files:child-usage.mjsandtest-child-usage.mjsdiffer from both sides), andcatalogs/landscape/final-stack.json(scripts/final_stack.py --write: it carries the digest ofmanifests/stack.json). Pure-rebase evidence: the diff of each of the 8 commits without those three kinds of file has the samegit patch-id --stableas before, so has the whole branch diff; 31 of the 36 registry rows of the files the branch registers or changes are identical to the old head's, and the 5 that differ are files main changed too (final-stack.json, the workflowsSHA256SUMS,child-usage.mjs,test-child-usage.mjs,tests/test_landscape_sweep_harness.py).sha256sum -cpasses on both checksum files;git merge-tree --write-treeagainst main is clean. The names of the commits before and after:aca46e24ais5cba90b65,905a23b9aisf7bc43719,2713c59e7is338e50f81,71bc0e925isba3e038d2,95064ff58(the fix wave for6a7a7ce7) is1454e0b64,cecf039f9is60a984c34,55dba7f4cis7b2e40098, and the adjudicated commitf3bc47ae0is03d92cbde.The adjudicated commit (commit 8), for the reads at
55dba7f4By the command center's ruling (
adjudication-pr1034-55dba7f4-20261012.md: two fix rounds spent; scope-locked to the P1 of Astra's third read, the rebase, B5 and B6 of the Claude micro; the two P2 of the GPT file only where each is small with its test). Inputs: Astra's third read (CHANGES_REQUESTED: 1 P1, 2 P2, 4 P3) and the command center's Claude micro (CHANGES_REQUESTED: no new P1, no P2; L1, B5, B6, P3-6 to P3-9). Fail-first: the tests of this commit run 48 tests and giveFAILED (failures=70, errors=1)in 6 tests on55dba7f4(fail-before-55dba7f4c-final.txt); at the new head they pass (45 + 3, OK).shown_stalecopied the whole acknowledgement entry ({**e, ...}), so a key of the acknowledged file that the schema does not define, nested or not, reached stdout in the JSON format; areasonthat is an object holding a token was accepted and serialised the same wayACK_FIELDSand no other (any other key ends the run with exit 2 and a message that names the entry, never what it holds), itsreasonis text, and the report builds the stale entry from the defined keys, so a loader that let a key through still publishes none of it. CPythonDoc/reference/expressions.rstL359-L361 (dictionary unpacking adds every mapping item),Lib/json/encoder.pyL354-L358 (_iterencode_dictreadsdct.items()), v3.13.16test_an_acknowledgement_with_a_key_the_schema_does_not_define_is_refused_and_never_published(5 shapes x 2 formats, the real command),test_the_reason_of_an_acknowledgement_is_text(7 kinds x 2 formats),test_a_stale_acknowledgement_is_published_from_its_defined_keys_only,test_the_report_copies_no_entry_whatever_the_loader_returned(a stub loader)shown_commandcalledstr()on the command, so a number, a float or a boolean, which has the shape of a file name, was printed (90817263in all four combinations of client and format) although the docstring, the record and the body said a command of another kind is withheld(no command). The code matches the sentence, which now reads "atypeor acommandthat is not text" in the three placestest_a_command_that_is_not_text_is_withheld_for_either_client_in_either_format(an integer, a float,true,false, a list, a table x 2 clients x 2 formats)fieldswas checked for DIFFERS only; a stale LIVE-ONLY entry withfields: 42ended in aTypeErrortracebackfields, when given, is a list of strings for every kind of rowtest_fields_of_an_acknowledgement_are_a_list_of_names_for_every_kind_of_row(2 row kinds x 7 shapes x 2 formats, and the accepted forms)RecursionErrorcatch ofload_acknowledgedhad no testtest_a_deeply_nested_acknowledged_file_ends_the_run_with_exit_two_and_a_fixed_messageObjects/object.cL1032 (theTypeErrorofsorted()over mixed kinds),Modules/_json.cL1033 and L1041 andLib/tomllib/_parser.pyL432 and L628 (theRecursionErrorof nested JSON and TOML)55dba7f4overcecf039fgiveRan 41 tests,FAILED (failures=17, errors=3)in 5 tests (measured by both families and again here,fail-before-cecf039f9-of-55dba7f4c.txt); the commit message of55dba7f4says 16, 3 and 4 and cannot change without a new head. The sixteenth failure was the case "a number that spells a file" of the source test, which also fails there. The corrected figures are in this bodysha256sum -c,scripts/validate.pymanifests/evidence.jsonholds 3 in the exact case and 20 in any case (18 lines), the same at the base, so none is added hereMutation check of the module: 43 mutants (the 36 of commit 7 and these: unknown keys accepted, a reason of any kind,
fieldschecked for DIFFERS only, a command stringified, a falsy command taken for no command, the stale entry copied, a nested acknowledged file not converted, the command directory printed and the names of acknowledged fields not text, both re-anchored): all killed (survivors: none).Fix wave 3 (commit 7), for the reads at
cecf039fInputs: Astra's delta read of
cecf039f(CHANGES_REQUESTED: 1 P1, 4 P3) and the command center's Claude micro read (CHANGES_REQUESTED: four claims of the body, five P3). Fail-first, corrected by the adjudicated commit: the tests of this commit run 41 tests and giveFAILED (failures=17, errors=3)in 5 tests oncecf039f(the commit message of55dba7f4says 16, 3 and 4: stale); at that head they passed (41 tests, OK).!r, so a path of the account, or a malformed object holding a token, reached stderr with rc 2, in both formatsacknowledged[0]: source must be a relative path to a regular file beneath this repository), never what was given. CPythonDoc/reference/lexical_analysis.rst(v3.13.16 L785-L786):!rcallsrepr, which quotes the operand and does not redact ittest_a_rejected_acknowledgement_source_is_never_printed(the real command as a subprocess; an account path, an object and a list holding a token, a number, text, a null byte, a null, a missing file; text and JSON; neither stream); the source test also refuses a number that spells a file@holding the value as its path, query and fragment, and one holding it as the port; a valid five-digit port is asserted absent from the descriptiontest_a_description_is_built_from_names_and_fixed_words_only~/.codexdirectory ended the run with exit 1 and a traceback naming an absolute pathPath.is_file()re-raises EACCES (CPythonLib/pathlib/_abc.py, v3.13.16 L476-L488); it is converted:cannot read ~/.codex/config.toml: PermissionError, exit 2test_a_home_whose_codex_directory_cannot_be_searched_ends_the_run_with_exit_twofieldsmixes types crashedsorted()test_the_fields_of_a_differing_acknowledgement_are_a_list_of_names(six shapes)RecursionError(exit 1, traceback)test_an_input_that_cannot_be_read_ends_the_run_with_exit_two_and_a_fixed_messagetypeorcommandof another kind is compared and withheldFix wave 2 (commit 6), for the second reads at
4916d3a4Inputs: the four review threads opened on
4916d3a4(two fixed here, two answered in the threads: below), Astra's second read (CHANGES_REQUESTED: 2 P1) and the command center's full read (CHANGES_REQUESTED: 2 blockers, 6 stale claims, P3-a to P3-f). Fail-first, re-measured with the final tests: on4916d3a4they run 37 tests and giveFAILED (failures=45, errors=10)(10 of the 37 tests fail); on6a7a7ce7FAILED (failures=82, errors=26)(16 of 37); at the new head they pass (37 tests, OK).shown_arg; the command center's item 1): a token that has the shape of an option is printed, and it can be a value: the credential in--api-key --secret-token, the operand of a short option (-k --x), a positional value after--(24 of 24 probe runs of the command center, 8 of 8 of Astra's). The wave-1 direction ("flag names with one placeholder") had the same holeLib/argparse.pyL1964 and L2503 (v3.12.3) andLib/getopt.pyexecute such tokens as values, so the spelling of a token cannot decide what may be printedtest_no_argument_token_is_printed_whatever_it_looks_like(twelve hostile tokens),test_a_credential_that_looks_like_an_option_is_not_printed_by_either_client_in_either_format(5 forms x 2 clients x 2 formats, stdout and stderr), the seven wave-1 credential formsfloat(), whose error quotes the value (%R);main()caught onlyDriftError, so the traceback put the value on stderr and the exit code was 1Objects/floatobject.cfloat_from_string_inner(v3.12.3 L190-193, v3.13.16 L183-186)/,?or#parses as the host, which was printed (32 of 32 runs); one form contradicted the docstring ("a URL that does not parse is withheld whole")@anywhere, a port that does not parse (not a number, out of range), or a scheme or host of another shape is withheld whole. CPythonLib/urllib/parse.pyurlsplit(v3.13.16 L472)notaport,99999,-1as portsargsgiven as text printed its length as a count; a Codexmcp_serversthat is not a table ended in an uncaughtAttributeError(exit 1)args,env_vars,enabled_tools,disabled_toolsmust be lists,argsholds strings,env,headers,http_headersare tables,mcp_serversis a table; else exit 2, naming the server only[[mcp_servers]]~/.claude.json), else the file name; a read error names the kind of error (JSONDecodeError,IsADirectoryError), not its texttest_paths_are_printed_relative_to_the_home(inside the home, outside it, an error from each client)typeprinted any name-shaped text; the host label and the command's file name still printstdio,http,sse, else<withheld>. The host label and the command's file name are printed as names, not as values, and the module docstring now says sotest_the_description_keeps_what_a_reader_needs_without_a_value, the property testrecipes/README.mdL790 ranmcporter ... list codebase-memory, which works only through MCPorter's auto-correction (installed 0.14.2: "Auto-corrected server name"; at the pinsrc/cli/list-command.tsL493-521)list SERVERas well ascall SERVER.TOOLtests/test_mcporter_selectors.py(3 tests; failed on4916d3a4for this line)mcp --transport(a currency item for the version owner); Claude Code through npx and Codex through node; four of the 14 tools only read local state,run_assertionruns javascript, python and webhook assertions locally (src/commands/mcp/tools/runAssertion.tsL19-24) andvalidate_promptfoo_configimports a JavaScript configuration as code (validatePromptfooConfig.tsL5, L62;src/util/config/load.tsL383-385);streamable-http.mdxL58-61. The property test now names its positions and adds the URL username and the whole transport type; the host label and the command's file name are excluded because they print as names by designtest_a_description_is_built_from_names_and_fixed_words_only(300 seeded values: arguments, an environment value, a header value, the command's directory, a URL's username, password, port, path, query and fragment, the whole type)The two threads answered in place (the command center's rulings on
4916d3a4): binding an acknowledgement to the accepted value is deferred to the research queue (rule 8: a committed signature of a live value is a digest of unsanitized bytes, #161, and a value predicate needs a schema first); removing the legacycodebase-memoryregistration is a follow-up installer migration (the first host already runs the vendor key).Mutation check of the module: 29 mutants (every argument shown again, the singular, a shape error not converted, a URL's path, port or userinfo printed, an
@URL not withheld, a port that does not parse not withheld, the command directory printed, the type printed as it is, unchecked names, a list, a table or a non-string argument accepted, the shape not checked in either normaliser, a path printed in full inside or outside the home, a read error printing its text for either client, a Codexmcp_serversthat is not a table accepted, absolute or..sources allowed, symlink escape, directory source, the root not applied or not passed): all killed by the module's tests (survivors: none). Dropping theisinstance(spec, dict)test ofcheck_shapeis an equivalent mutant, becausecomparealso converts theAttributeErrorthat.getthen raises.Fix wave 1 (commit 5), for the first reads at
6a7a7ce7Astra's read (CHANGES_REQUESTED: 1 P1, 3 P2) and the four review threads, each fail-first (the new tests failed on
6a7a7ce7; they pass at every later head):--api-key VALUE, its percent-encoded value,--api-key=VALUE, URL userinfo or query in an argument,--header 'Authorization: Bearer VALUE', a long credential containing!)Unknown MCP server 'codebase-memory')mcporter ... callselectscodebase-memory-mcp.<tool>; the transcript classifiers keep the short alias for sessions recorded before the renametests/test_mcporter_selectors.pyresolves each published selector againstexamples/mcporter.json.example(8 selectors in 6 files failed before); the classifier tests keep one case per spelling/etc/passwdand../x..are refused and symlinks are resolved before the containment check. CPythonLib/pathlib/_local.pyresolveandis_relative_to(v3.13.16 L664, L393)#heading, a repository symlink to a repository file; refused: absolute (inside and outside),..(also when it returns inside), a symlink to an outside file, a directory, a missing file, a null byte; end to end throughmain()(exit 2)--eco-root(andECO_INSTALL_ROOT) reached the Claude renderer onlyECO_ROOTis set in the host values of the shared render, before either client is renderedSOTA sources
8972ea69c6ad94b1ef1d4ffbf0a92d78d2db1798),README.mdL450-L460: the vendor's own registration is"mcpServers": {"codebase-memory-mcp": {...}}. Both clients show that key on the host (claude mcp list, Codex[mcp_servers.codebase-memory-mcp]).34f74d34e140b5e17d23770dfb2340057b1936b8),site/docs/integrations/mcp-server.mdL37 (promptfoo mcp --transport stdio), L49-L52 (the client entry), L169 (stdio is the transport of desktop AI tools);src/commands/mcp/server.tsL94-L112 registers the 14 tools;src/commands/mcp/tools/runAssertion.tsL19-L24, L43, L166 andvalidatePromptfooConfig.tsL5, L62 withsrc/util/config/load.tsL383-L385 (the two tools that look read-only and are not). The manifest pins 0.123.1; the first host runs 0.124.0 (14 tool names,mcp --transport http|stdio). The entry runs the installed binary, notnpx promptfoo@latest, so the version is the installed one and never a floating one.~/.claude.json, which is the file the report reads; project (.mcp.json), local and plugin servers are not read and the report says so.1f520964b295d58494d944f2aea8a5ab51c79f77:docs/specification/2025-06-18/basic/transports.mdxL76 (servers MUST validateOrigin),docs/specification/2025-11-25/basic/transports.mdxL78-L79 anddocs/specification/2026-07-28/basic/transports/streamable-http.mdxL58-L61 (an invalidOriginMUST get HTTP 403). This is the gate that the loopback routes measured here are held to; the lines were re-read in the local mirror~/code/upstream/modelcontextprotocol/modelcontextprotocol(HEAD is the pin).e4cb002200e44460279d414b0d1dec597b978f06(the pin ofMIRRORS.json, v0.13.13; the installed client is 0.14.2):src/cli/call-command.tsL309-L346 (resolveCallTargetandsplitServerToolSelector: the server is the text before the first.of the selector) andsrc/runtime.tsL229-L235 (getDefinitionlooks the server up by exact name and throwsUnknown MCP server '<name>'.);src/cli/list-command.tsL493-L521 (a near name is auto-corrected: a guess, not a contract). Measured on the installed 0.14.2 withexamples/mcporter.json.exampleas committed (its command paths are placeholders, so nothing starts):call codebase-memory.search_graphanswers rc 1Unknown MCP server 'codebase-memory'.;call codebase-memory-mcp.search_graphresolves the server and stops at the placeholder command (spawn ... ENOENT).f6650f9ad73359051f3e558c2431a109bc016664(v3.12.3):Lib/argparse.pyL1964 and L2503 (end-of-options handling: what follows--is a value) andObjects/floatobject.cL190-L193 (float_from_string_innerformats its error with%Rof the input); and atcbc944f4bc59639a444dd971c737788ba2283a91(v3.13.16, the interpreter that runs the tool):Objects/floatobject.cL183-L186,Lib/urllib/parse.pyL472 (urlsplit) and L165 (hostname),Lib/pathlib/_local.pyL664 (resolve) and L393 (is_relative_to).Lib/getopt.pyreturns the operand of a short option as a value:getopt(['-k', '--x'], 'k:')gives[('-k', '--x')].tools/adoption/new_wsl_client_config.py(analyse,host_values,render: the report calls them, it does not re-implement the render) andtools/adoption/install_claude_profile.py(render_servers,default_eco_root); the closed-world mapadoption/new-wsl/client-config-map.json; the admission gate in.claude/skills/claude-native-practice/reference/mcp-surfaces.mdL24-L32.Evidence-class table
scripts/validate.pyexit 0--checkprintstests.test_new_wsl_client_config(incl.RecordTests),tests.test_mcp_template_drift.test_templates_carry_the_live_names_of_the_two_reconciled_serversenv-wrapped registration as the same server, prints no value of a registration (arguments are counted, environment and header values are withheld, a URL prints asscheme://hostonly when it holds no@and its port parses, the transport is one of three words, paths are home-relative), ends a registration with a field of a shape the checks name with exit 2 and a message that names the server only, withholds atypeor acommandthat is not text, builds the stale entry from the schema's keys and refuses any other key and a reason that is not text, fails on a stale acknowledgement, refuses a malformed one and refuses an acknowledgement source outside the repository without printing the rejected valuetests/test_mcp_template_drift.py(45 tests; with the selector module, 48: 70 failures and 1 error in 6 tests on55dba7f4, none at the new head; commit 7's tests: 17 and 3 in 5 tests oncecf039f; commit 6's tests: 45 and 10 on4916d3a4, 82 and 26 on6a7a7ce7); 43 of 43 mutants killedmcporter ... callandlistselects a server thatexamples/mcporter.json.exampleregisters; the old selector is rejected by the installed MCPorter 0.14.2 and the new one resolvestests/test_mcporter_selectors.py(3 tests); the two calls under "SOTA sources"--eco-rootorECO_INSTALL_ROOT, renders in both clients and compares SAMEtest_the_ecosystem_root_reaches_both_templates,test_a_non_default_prefix_compares_the_same_for_both_clients_from_the_option_and_the_environmentmcp_template_drift.py --with-authorization-settings --acknowledged adoption/new-wsl/mcp-drift-acknowledged.jsonexits 0: 13 SAME, 7 DIFFERS and 5 LIVE-ONLY rows, all 12 acknowledged, 0 stale;claude: promptfooandclaude: codebase-memory-mcpare SAME~/.claude.jsonand~/.codex/config.tomlwith the tool at this head (it prints names and counts only); the sanitized output is retained locallyOriginanswered 200); qmd passes; ai-memory validatesHostbut notOrigin; hindsight validates neitherinitialize-only probes of the four loopback routes (statuses only), tabulated in the decision record; PSS 45.3 MiB (stdio child) against 47.8 MiB (service), tool parity 6 and 6 with equal hashesLocal commands run
Decision record
docs/decisions/2026-10-12-mcp-template-live-reconciliation.mdcarries the measurement, the decision, the gate evidence, the alternatives (rebase #834, put the four live-only servers into the templates, keep the short key, fix the host from here) and the conditions that overturn it. The new-WSL client configuration record gains a dated addendum with its counts.Host evidence
Only relevant when this PR adds or changes files under
evidence/hosts/. This PR changes none.Checklist
permissions: {}and grant each job only what it needs. None changed.Follow-ups
chrome-devtoolsenabled, Codexcodebase-memory-mcpenv_vars, Codex jcodemunchenabled_tools).4916d3a4): an installer migration for hosts installed from the previous template that removescodebase-memorywhen the vendor key is present, with a test that starts from the old registration, is a follow-up PR; the first host already runs the vendor key.30949931, synced 2026-10-12 09:46:05Z).Hostonly; hindsight: neither) go to the co-op's research queue (rule 8) with the specification citations above; the shared jcodemunch service is not retried until a version answers an invalidOriginwith 403..mcp.json, local-scope entries and plugin servers (plugin:context-mode:context-mode) are out of its reach by design;claude mcp listremains the check for those.enabled_toolsacknowledgement is removed in the same step (it goes stale by design); Codexchrome-devtoolsstays disabled (acknowledged); theCBM_*forwarded variables stay; the headroom port and SocratiCode 1.16.0 stay acknowledged until the currency decision (lupe / FIX-6).adoption/templates/codex.config.template.tomlL60 (a comment),examples/claude-native/workflows/child-usage.mjsL716 and L973 (comments citingstack.json:280, stale since the base),adoption/update.mdL149 (the short key, in the present tense) anddocs/token-session-handbook.mdL456 (six Codex servers and local-scope jcodemunch): correct them with a dated supersession and, as history,adoption/bootstrap.mdL566-L567 (add the current key); (2) unpinned moved-line locators inevidence/receipts/codex-serena-startup-port-20261003.jsonandcatalogs/foundation/upstream-surface-dispositions.json: bind them to their recorded revision or add a correction (no rewrite of historical receipts as new measurements); (3) three existing occurrences of the host name inmanifests/evidence.json, none added here; (4) an acknowledgement source need not be a tracked file (repository_fileaccepts an untracked file, or.gitin a worktree, beneath the root, which is all the contract asks); (5) the codebase-memory-mcp v0.11.0 source has no local mirror, so its README lines were read from the raw file at the pin: mirror it.03d92cbdthat stay follow-ups (P3; no P1 was reproduced, the one P2 is the receipt corrected above): (1) missing captures and one correction-provenance omission: the packet captures of the pinned CPython, MCPorter, Promptfoo and MCP specification sources, the vendor pinDeusData/codebase-memory-mcpv0.11.0 (unmirrored), the dated Claude MCP page, the live registration, version and launcher reports, the Origin, PSS and parity probes,research-queue.tsv, the earlier scope-ruling message and the thread reply bodies are not attached and stay measurement boundaries; the correction for a command that is not text names no CPython locator for thestr()coercion it removes (add one beside it); (2) retained prose and moved-line references:adoption/update.mdL149,docs/token-session-handbook.mdL456, the old-key installer migration (with a pre-existing-registration control), the unpinned locators ofevidence/receipts/codex-serena-startup-port-20261003.jsonL1843 andcatalogs/foundation/upstream-surface-dispositions.jsonL997, and 234 inline numeric references at or after lines this change moves (candidates, none asserted by a test); (3) the host name in eight changed files (68 lines, none in the patch or the body); (4) retain the mutation script and the module list behind the two figures of the adjudicated commit (the 43 mutants and the 114 modules, 6,677 tests): they are kept in the private research record (fix-wave-3/:drift_mutants.py,modules-r4.txt,modules-results-r4.txt,mutants-adjudicated.txt) and publish with the next change to this tool.55dba7f4that stay follow-ups (P3): the corrections C2 to C5 and the mixed-fields and recursion fixes have no fail-first assertion that pins their sentences (supply the captures and source-consistency checks, or keep the measurement boundary); the numeric references at or after lines this change moves (239 candidates, none asserted by a test); retained prose and the old-registration migration (above); the missing captures (codebase-memory-mcp v0.11.0 is unmirrored; historical live reports, service probes, mutation receipts, queue and ruling captures, reply bodies); the host name in the changed files (3 occurrences in the exact case and 20 in any case inmanifests/evidence.json, none added here).cecf039fthat stay follow-ups (P3): the corrections C2 to C5 of the record have no fail-first assertion that pins their sentences (supply the captures and source-consistency checks, or keep the measurement boundary); the numeric references at or after lines this change moves (237 detected, none asserted by a test); the host name in eight changed files (68 lines, none in the patch or the body).mcp-surfaceslayer. The row is filed in the co-op'sresearch-queue.tsv(2026-10-12T11:43:12Z) and routed to the research backlog of cc-native-practice (queued; the readiness trigger is this PR landing).🤖 Generated with Claude Code
Follow-ups after landing
Landed at 2f59d74 on 2026-10-12T17:05:25Z from head 03d92cb (Claude-family verification PASS_WITH_P3; GPT delta with no P1, its P2 a body figure corrected before landing; Codex unavailable). The follow-ups listed above carry forward; none blocks.