Repository navigation
Codex rtk hook: the plan's command-output row installs and trusts it (second of two; the user's relayed pointer yes) - #705
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: 1398b21468
ℹ️ 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".
… named hook is not trusted The install plan's acceptance for RTK's Codex hook needs a check that fails when the hook is untrusted or modified, and the tool's dry run exits 0 either way. --check lists the named hooks, makes no edit and no backup, takes no part in the refusal beside a running codex (only --apply has it), and exits 0 when every match is trusted at its current hash, 5 when one is not, 4 when none matches. It is mutually exclusive with --apply. Five tests written first (all red on the tool without the flag); 27 pass; the whole sequence also ran against the real codex app-server in a scratch home (4, 0, 5, 0, 0 for check, init, check, trust, post_install additions). Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> (cherry picked from commit d80544d)
…usts it (decision 2026-10-04; the user's relayed pointer yes of 2026-10-05) Second of the two pull requests of docs/decisions/2026-10-04-codex-rtk-hook-qualified.md. The command-output row gains two commands, `rtk init -g --codex` (upstream's install: the hook group, RTK.md and an inert @RTK.md pointer in the Codex AGENTS.md; no hook-only mode exists with --codex) and codex_hook_trust.py --apply for that one hook; its post_install acceptance adds the two Global [ok] lines of `rtk init --show --codex` and `codex_hook_trust.py --check`; a new after_sign_in acceptance runs a fresh `codex exec` told to add no prefix and requires `rtk git status` in the executed command (UNRUN: the model call needs the sign-in; the jq filter was checked on a recorded stream). install.sh, accept.sh and the plan JSON agree (check_plan.py: 120 commands, 79 acceptance entries). The plan README, the token session handbook paragraph, a dated note on the RTK card (cards are dated editions), the F9 recipe text and its owner-list test (command-output joins the after-sign-in owners), the generated new-WSL handbook and the decision record's addendum follow. The addendum records the user's "yes for rtk pointer" and the standing rule about upstream installer side effects as the user's words relayed by the command center. The artifact README also notes that its grep fixture cannot show rtk's file-list fold (the control of #698 covers it). Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> (cherry picked from commit f99b91f)
…ed handbook The handbook pins the sha256 of adoption/platforms/linux-wsl2-new-distro.md, which the F9 owner-list edit changes, so build_new_wsl_handbook.py --write regenerated docs/new-wsl-handbook.md and .json and the receipt that names their digests (test_new_wsl_handbook: the committed outputs are current and the receipt names them) records the new ones. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
plan_row_scratch_run.py reads the text of the command-output row's steps from install-plan.json (the config install, `rtk init -g --codex`, the trust, the post_install program and the after_sign_in jq filter) and runs them in a scratch HOME with the installed rtk 0.51.0 and codex app-server 0.159.3: --check 4 before the hook exists, init 0 (the hook lands at pre_tool_use:1:0 after a memory hook's group), --check 5 before the trust, the trust 0, the post_install program 0, the jq filter on a synthetic codex exec stream 0. The model call of the after_sign_in check needs the sign-in and is not run. plan-row-scratch-run.json retains the output; the artifact README lists both. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> (cherry picked from commit ee8219c)
…the command center's correction) The addendum gave "about 00:55Z", the command center's estimate when it relayed the user's answer. It has since given the transcript times: 2026-10-05T00:49:16Z for "yes for rtk pointer" (part of a longer message) and 00:50:08Z for the standing rule (a queued message). The words are unchanged, and the record still says the writing session heard neither quotation itself. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
1398b21 to
7c4c8fb
Compare
…n rules (review of #705, thread 3) Codex replaces a call with the PreToolUse hook's updatedInput before its handler's approval path (codex-rs/core/src/tools/registry.rs L603-L660, rust-v0.159.3 and rust-v0.160.0) and matches execution rules against the rewritten command's words (codex-rs/core/src/exec_policy.rs L327-L420); rtk's Codex hook rewrites git push to rtk git push and reads no Codex rules (rtk v0.51.0 hooks/codex/README.md L14-L24, src/hooks/permissions.rs L64-L72). So a rule on git push does not match the rewritten command (codex execpolicy check on 0.159.3: forbidden for git push, no decision for rtk git push). Trusting the hook is what activates it, so --apply now refuses (exit 2, before any backup or write) while <codex home>/rules holds a rules file with content, names the files, and proceeds only with --allow-exec-rules; --check and the dry run name the rules and are not refused. Six tests written first (five red); 33 pass. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…ok statement, and the approval answer with its evidence Thread 1 (accept.sh): the after_sign_in check requires the executed `rtk git status` item to have exit_code 0 and status completed (Codex's JSONL command item, codex-rs/exec/src/exec_events.rs L161-L166); five negative fixtures (a failed rewritten command, a non-zero exit, a declined command, no rtk prefix, no command item) end non-zero in plan_row_scratch_run.py. Thread 2 (install.sh): adoption/new-wsl-profile.json and .md, the definitive manifest and the consensus record that it copies no longer say the plan never runs rtk init --global --codex; they state the command-output row's rtk init -g --codex and trust step with the upstream source (rtk v0.51.0 README L133), the manifest's declared consensus digest, the regenerated handbook and its receipt follow. Thread 3 (install.sh): the decision record's addendum answers the approval-classification question with the Codex source at both pins and rtk 0.51.0 (the rewrite comes first; approval sees the rewritten words; the forced-rm heuristic is untouched; rtk does rewrite mutating commands: 36 of 55 measured), records the guard, the operating rule, the alternatives and the untested boundary; rtk_behaviour_probe.py gains the Codex hook's decisions over 55 commands and plan_row_scratch_run.py the execpolicy demonstration and the refusal and acceptance steps. The plan row notes, the handbook paragraph, the F9 sentence and the artifact README follow. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…ndbook, receipt, record, recipe and scratch-run files of the Codex rtk hook row in manifests/evidence.json Hot-file protocol (docs/lanes.md): evidence.json as on main 4c89741 (with PR 704), the 19 changed hashed files and the two new scratch-run files registered with host_receipts.register_file, then component_matrix.py --write and new_host_grand_list.py --write; validate.py and validate_convergence.py --all-recorded exit 0. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
7c4c8fb to
4739ea8
Compare
…instead of refusing on any rules file Repair round of #705 (one bounded round): 705d P1 (a failed listing of the rules directory read as no rules), 705d P2 (the refusal came after the app-server started), 705d P2 (the scratch run accepted a failed evaluator as "no decision"), job-071 P2 (rules were reported only for a hook still to be trusted) and P3 (approvals off do not switch execution rules off), and the command center's request that rules rtk never rewrites (#713's hcom-deny.rules) must not block the trust step. The tool now lists <codex home>/rules/*.rules as Codex's collect_policy_files does (a missing directory is no rules, any other error fails, a symlink is not loaded), reads the prefix_rule literals with ast, and compares, with rtk hook check --agent codex and codex execpolicy check, the decision on each command a rule names and on a sample of the 36 commands rtk 0.51.0 rewrites with the decision on the rewrite. It refuses --apply (exit 2, before the app-server starts) only when a forbidden or prompt decision gets weaker or a step could not be done; --check exits 6 for a trusted hook beside such a rule, which the post_install acceptance runs; --allow-exec-rules stays as the explicit acceptance. The plan's trust and check commands pass --rtk. Evidence: plan_row_scratch_run.py (33 steps, real rtk 0.51.0 and codex-cli 0.159.3; the hcom rules proceed, a git push forbid rule without a twin is refused, with its twin it proceeds, an unreadable directory is refused, a rule added after the grant makes --check exit 6); 58 unit tests with local stand-ins for the two programs, checked by 14 mutants that each fail a test (rule_review_mutation_check.py). The decision record's addendum is rewritten, including the correction that approvals off do not switch rules off. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…he F9 recipe sentence The handbook lists the sha256 of adoption/platforms/linux-wsl2-new-distro.md, which the review round edited; build_new_wsl_handbook.py --write regenerated both outputs and the receipt's two output digests follow (profile_sha256 is unchanged). Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…manifests/evidence.json Hot-file protocol (docs/lanes.md): evidence.json restored from the base 4c89741, the 19 changed files and the 5 new ones (plan_row_scratch_run.py, plan-row-scratch-run.json, fixtures/hcom-deny.rules, rule_review_mutation_check.py, rule-review-mutation-check.txt) re-registered, component_matrix.py and new_host_grand_list.py regenerated; validate.py and validate_convergence.py --all-recorded exit 0. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
… with a word rtk cannot route (heads derived from rtk's source at the pin) Second repair round of #705, after the 705e read of e6321c0 found three P1s in the behavioural review (probed and sampled commands compared with rtk hook check and codex execpolicy check): - an entry-level FileNotFoundError still failed open: the handler wrapped the iteration, and Codex asks every entry's file type before its extension (exec_policy.rs L1121-L1170). Only opening the directory may now report it missing; the file type of every entry is asked first; - host_executable(name = prefix_rule(...) or "git", ...) is accepted by the real codex evaluator and registers a rule the parser never counted: every argument of both builtins must now be a literal, and unknown arguments are refused; - a prefix rtk leaves alone has extensions it rewrites (git -C . versus git -C . push origin main, broad uv and npx rules), and rtk's rewrites also change words after rtk (cat f -> rtk read f), so neither a sample nor an rtk twin can show a rule is preserved. The probing, the sample, the evaluator calls and the rank comparison are deleted. A forbidden or prompt rule is exposed unless its first pattern token (every alternative, a path reduced to its basename) is a word rtk 0.51.0 cannot route: tools/adoption/rtk_rewrite_heads.json holds the 142 heads derived from rtk's source at e001f773f80b (the leading tokens of the 94 RULES patterns and 62 builtin TOML filters, the process and shell wrappers, the env prefix; line provenance), the review reads the config's transparent_prefixes and user TOML filters for more, and rtk --version must report the version the heads were derived for. hcom's rules (neither hcom nor uvx is a head) pass; twin-covered rules are refused too. A pin move of rtk must re-derive the file: a test compares it with adoption/pins-linux-x86_64.json, and the RTK row of docs/token-efficiency-stack.json carries the step. Evidence: derive_rtk_rewrite_heads.py (walks the parsed regexes) and check_rtk_rewrite_heads.py (94 of 94 RULES patterns rewritten by the real binary, 13,041 scanned commands with 623 rewrites and none outside the heads, 61 wrapper prefixes; the first derivation had 101 gaps that the scan found: the r#"..."# sbt rule, the TOML filters, \b continuations); plan_row_scratch_run.py (42 steps with the real rtk and codex, incl. the three counterexamples); 71 unit tests and 21 mutants that each fail a test. The decision record, README, handbook paragraph, F9 sentence and plan notes are rewritten; the handbook and its receipt follow. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…ests/evidence.json Hot-file protocol (docs/lanes.md): evidence.json restored from the base 4c89741, the changed files and the 8 new ones (the scratch run and its output, the hcom fixture, the mutation check and its output, the heads derivation and check scripts and the binary check's output) re-registered, component_matrix.py and new_host_grand_list.py regenerated; validate.py and validate_convergence.py --all-recorded exit 0, build_new_wsl_handbook.py --check passes. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…s Codex's allow-only format, and parse nothing (705f) 705f found five P1s and a P2 in the head-set version: a raw CR inside a triple-quoted token (Codex's Starlark lexer drops it, Python's reader turns it into a newline), a rule on the whole shell argv for an assignment-prefixed script, the PHP tool spellings rtk normalizes (phpunit.exe), user TOML filter regexes with a second branch, rtk's Unicode word boundary, and DirEntry.is_file() swallowing a missing-entry error. Three analysing versions each modelled Codex's evaluator on one side and rtk's rewrite on the other, and every read found a place where they differ. On 5f's recommendation the tool now decides nothing about what a rule means: - a rule file of <codex home>/rules is accepted when its sha256 is on tools/adoption/exec_rules_reviewed.json (an exact-bytes review for one rtk version: `rtk --version` must match, `rtk config` must show transparent_prefixes = [] and the user TOML filters file must hold no filter) or when it holds nothing but allow rules in Codex's own format (amend.rs lines, hcom's own hcom.rules comment line, empty lines), byte for byte, none with a token `rtk` (the hook's rewrite inserts that word, so such a rule matches the rewritten command and not the original: codex-cli 0.159.3 `execpolicy check` allows `rtk git push origin main` under ["rtk"] and gives no decision for `git push origin main`, a widened approval); anything else is an exposure: --apply refuses with exit 2 before the app-server starts, --check exits 6 for a trusted hook beside one, --allow-exec-rules accepts; - the listing keeps the fail-closed repairs and asks every entry's type from its own lstat (stat(follow_symlinks=False) + S_ISREG), which raises for an entry that vanished; a symlink, directory or named pipe is not loaded and never opened; - the list has one entry, #713's hcom-deny.rules at head 5f295f2, reviewed against the derived rewrite heads and the real binary (352 commands of its first tokens, none rewritten); the heads file moves to the e2e artifact folder as review evidence, and the check script reads it there. Evidence: plan-row-scratch-run.json (70 steps, real rtk 0.51.0 and codex-cli 0.159.3: hcom bytes accepted, one added byte, a configured prefix and a user filter refused, the 705e and 705f counterexamples and an allow rule that names rtk refused, allow-only files accepted); rtk-rewrite-heads-check.json (94/94 patterns, 13,041 scanned commands, 8,884 spellings, 352 reviewed-entry commands, gaps 0); 79 unit tests (synthetic; hcom's file is rebuilt from its installer's source lists) and 58 mutants all killed. Decision record, README, handbook paragraph, F9 sentence, plan notes and the RTK row follow the design. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…nifests/evidence.json The hot-file step (docs/lanes.md): evidence.json restored from the base 4c89741, the changed files re-registered with host_receipts.register_file, the heads file registered under its new path, component_matrix and new_host_grand_list rewritten; validate.py and validate_convergence.py --all-recorded pass. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…54ee, comments and justification strings only) #713 narrowed the comments and the four justification strings of config/hcom-deny.rules (head 7fbe586; 845f06b0 at 5f295f2). The other 25 lines, the patterns, decisions and match/not_match lists, are identical (compared without comment and justification lines), so the first review carries over, but the list is by exact bytes: the entry now holds ac6254ee9bb7ac20deca69bb03bead76dacbe4e53a41cbc563a8b3614fa6a6aa, the kept copy fixtures/hcom-deny.rules is the 7fbe586 file, the real-binary check was re-run (352 commands of the entry's first tokens, none rewritten) and so was the plan-row scratch run (70 steps, all as expected, with the new bytes). Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…713 repair round 2 Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…and no RTK_TRUST_PROJECT_FILTERS (read from rtk's source, measured with the real binary) The reviewed list's host conditions covered rtk's version, [hooks].transparent_prefixes and the user-global filters file, but rtk 0.51.0 has two more inputs that make its hook rewrite a command it otherwise leaves alone (src/hooks/trust.rs, src/core/toml_filter.rs at e001f773): - a TOML filter that `rtk trust` has trusted: the store is global (<data dir>/trusted_filters.json), so `rtk trust --list` shows a project or global filter from any directory; measured in a scratch HOME, a trusted project filter ^reviewalpha\b|^hcom\b makes `rtk hook check --agent codex "hcom kill luna"` print `rtk hcom kill luna` from that project's directory and nothing from another one; - RTK_TRUST_PROJECT_FILTERS=1 with a CI variable (CI, GITHUB_ACTIONS, GITLAB_CI, JENKINS_URL or BUILDKITE): rtk trusts every project filters file without a store entry, `rtk trust --list` still says `No trusted filters.`, and the same rewrite happens (measured). rtk_conditions now also requires `rtk trust --list` to print exactly `No trusted filters.` (exit 0) and RTK_TRUST_PROJECT_FILTERS to be absent from the tool's environment (the variable's value does not matter); both end the review of a reviewed file like the version, a configured prefix or a user filter. This closes the residual "project-trusted filters are not read". Not covered, and recorded: the environment Codex itself runs the hook in. The scratch run gains two homes (a trusted project filter, the override variable) with the real rtk's rewrite recorded before and after; 81 unit tests (FakeRtk answers `trust --list`; every test starts without the variable), 63 mutants all killed, 76 scratch-run steps as expected. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…the reviewed list Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…oject-filter classification and the exclusion alternative (705g) 705g (Sol, through 5f, at 3a2bb97) found two P1s and no P2: - P1-1: the allow-only exemption refused only a complete token `rtk`. Codex cannot split an assignment-prefixed script and evaluates the whole shell argv, where the script is one token, and the hook inserts rtk inside it: `["/bin/bash", "-lc", "FOO=1 rtk git push origin main"]` allows the rewritten script and not the original (real evaluator, recorded in allow_rtk_script_check). The check is now for the letters `rtk` anywhere in an allow rule (REWRITE_WORD = "rtk"); neighbours such as `rtkx` and `rtk-x` are refused too, `RTK`, `rt k` and comments are not (the rewrite inserts lowercase rtk as one word). Regression cases, a whole-token mutant, and a scratch home (real rtk rewrites `FOO=1 git push origin main`). - P1-2: project filters, which rtk loads from the hook's working directory and which `rtk trust --yes` or RTK_TRUST_PROJECT_FILTERS=1 with a CI variable activate, rewrite `hcom kill luna` out of the reviewed forbid rules. The previous commits already classify that state (the trust list must be empty, the variable unset, for a reviewed file: the reviewer's second option, an exposure that needs --allow-exec-rules). The reviewer's first option, an enforced exclusion, was measured with the real rtk: `['^hcom(\s|$)', '^uvx\s+hcom(\s|$)']` in [hooks].exclude_commands keeps both commands unrewritten under a trusted matching project filter and under the CI override (project_filter_check). It is recorded as alternative (j) and not enforced: the entries would join the recipe's shared five-entry table, and an exclusion matches rtk's raw text, so it cannot cover every shell spelling of `hcom` against an unanchored trusted filter. The point-in-time limit (a filter trusted after the review shows at the next --check; the hook's own environment is unseen) is stated in the residuals. Counts: 79 scratch-run steps (19 rule homes), 81 unit tests, 63 mutants all killed. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…into the Codex rtk hook branch Conflicts were only in the generated and hot files: docs/new-wsl-handbook.md, the handbook receipt and manifests/evidence.json. Resolved by the hot-file protocol (docs/lanes.md): main's copies taken, the branch's 44 registry entries re-registered from the pre-merge snapshot, the handbook regenerated with main's generator (#724) and the receipt's output digests refreshed, component_matrix and new_host_grand_list rewritten. validate.py, validate_convergence.py --all-recorded, build_new_wsl_handbook.py --check and check_plan.py (80 rows, 163 commands, 101 acceptance entries) pass on the merged tree. The branch's own content, including the 705g repairs of 1b8d4c0, is unchanged by the merge. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…k and receipt follow (main's unreleased-path marker rule, #720) Main's tests/test_adoption_docs_consistency.py now requires a recipe unit that uses a path missing from the pinned release to say "added after `<tag>`". tools/adoption/exec_rules_reviewed.json is new in this PR, so the F9 sentence that names it says so. The regenerated handbook and the receipt follow, and the receipt's frozen generator and profile digests are refreshed too (the merge took main's receipt, whose profile digest is main's, not this branch's): tests/test_new_wsl_handbook.py checks them. test_adoption_docs_consistency, test_new_wsl_handbook and test_wsl_new_distro_recipe pass (214 tests). Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…ated handbook after the merge of main Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…egistry plus the owned rows) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…fore the final hot-file commit Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… (hot-file protocol: every hot-file edit in the last commit) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…gistry; handbook regenerated, receipt digests refreshed) Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…hot-file protocol: every hot-file edit in the last commit) Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
|
Claude session native-agent-stack-5f: landing at head Observed main Required checks at this head: 7 pass . Unresolved review threads: 0. macOS (advisory). The user decided on 2026-10-05 that macOS checks are advisory. Ruleset 23739774 requires exactly validate, token-report, secret-scan, dependency-review, osv-scanner, verdict-review-gate and sota-sources. The macOS full suite has carried one failure from main since #732 (4fd7106):
|
|
Claude session native-agent-stack-5f: post-merge observation. Landed as |
…es and the refresh that landed (#747) ### Scope - What this PR changes, in one or two sentences: records in the Codex rtk hook decision record that 705h (Sol, through 5f) accepted the guard at `14a8b119f` with no P1 or P2, adds its two unverified boundaries to the residuals (no atomic snapshot across listing, loading and the trust grant; no enforcement after a later change of the rules, filters, HOME or XDG paths or the hook's environment) and notes that the head that landed (`118f579ff`) differs from the accepted one only in the regenerated new-WSL handbook outputs and their receipt. It also qualifies the record's opening Status paragraph (written 2026-10-04) with the landed pull requests: PR 684 `ba1f6876c`, the first of the two #701 `287514581`, the second #705 `0ce953696` (5f's read of `79622e8e7`, one P2). Record-only; no code, plan or generated file changes. - Base commit: `0ce953696` - Lane: `lane:foundation` (the same lane as #705) - Owned paths touched: `docs/decisions/2026-10-04-codex-rtk-hook-qualified.md` and its registry row in `manifests/evidence.json` (last commit, hot-file protocol). ### SOTA sources - No new source: a record-only follow-up to #705, which cites its sources in full. The facts added here rest on the same ones: rtk-ai/rtk v0.51.0 (`e001f773f80b22b7dc4c7a79521b30e35aaef026`); openai/codex rust-v0.159.3 (`01fc69f4026735edfdf6789820549727a4867b11`: `codex-rs/tui/src/hooks_rpc.rs` L58-L91, trust written by `config/batchWrite`) and rust-v0.160.0 (`a956835d0207`: `codex-rs/core/src/exec_policy.rs` L1121-L1170, the rules read when a session loads them). - The 705h read is our own cross-family review of the integration (Sol through 5f), recorded as a review, not as an upstream source. ### Evidence-class table | Claim | Evidence class | Command / receipt | | --- | --- | --- | | 705h accepted `14a8b119f`: no P1, no P2, both 705g P1s fixed against the real binaries, two boundaries not verified | `source_review` (cross-family read; verdict held by 5f) | the decision record's review-rounds paragraph | | 28 of the 31 owned files are patch-id-equal between the accepted head and the landed head; the other three are regenerated handbook outputs and their receipt | `local_integration` (`git diff -U0` per file, `git patch-id --stable`) | computed on the #705 branch before the merge; reproducible from `14a8b119f` against its base and `118f579ff` against `cb339488e` | | The probes ran codex-cli 0.159.3 and rtk 0.51.0; rust-v0.160.0 was read from source; no fresh model session | `local_integration` and `source_review` | already recorded by #705; restated as the boundary | ### Local commands run ``` $ python3 scripts/validate.py {"components": 69, "hashed_files": 10169, "profiles": 4, "receipts": 204, "status": "passed"} $ python3 scripts/validate_convergence.py --all-recorded record[30]: valid $ python3 -m unittest tests.test_component_matrix tests.test_evidence_manifest tests.test_new_host_grand_list tests.test_validate tests.test_codex_hook_trust Ran 253 tests ... OK (no test module names the decision record; gitleaks on each commit: no leaks found) ``` ### Decision record `docs/decisions/2026-10-04-codex-rtk-hook-qualified.md` (the residuals and review-rounds paragraphs). ### Host evidence Not applicable (no files under `evidence/hosts/`). ### Checklist - [x] New/changed GitHub Actions are pinned to a full commit SHA with a version comment (no workflow changed). - [x] New/changed workflows declare top-level `permissions: {}` (no workflow changed). - [x] No secrets are printed, logged or committed; no new required secret was added. - [x] No new paid hosting, subscription or billing surface was introduced. - [x] Peer-owned untracked files and worktrees were preserved. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
…715) ### Scope Publish the retained NativeStack2604 observations and correct the handbook after the command center's three-item micro-review. Official readiness remains the historical **30/80** from #700, whose bar is **upstream acceptance, wiring and fresh-session use, with the harness text present**. The command center's captured-status provisional **30/80 is as of 11:44Z**, excluding custody's 13:02Z BY_DESIGN change. It includes difftastic, structural-search, inspect-ai, harbor and codex-sdk despite **fresh-session use not evidenced**, so it is **not measured qualification on the #700 bar**. Earlier 37/40/44/32 proposals are superseded. Generated current/conditional values remain null. The organic native arm differs in one respect: **no harness text names the tool**. Upstream acceptance, wiring and fresh-session use remain required. Its count comes only from the command center's final verified E2E **S4**, independent review and adjudication. - Base: main `ecfa112764c664d35377dd66b8cfcb67e5a94d60` (after #703), merged into this branch at `44bf09713`. Head: `e50f0f480cabd66aea4f0552c1ebd589d45ebbf1`. - Lane: exactly `lane:foundation`. Pending the command center's micro-check and ACK at the exact head. Its ruling at `d25ea1f7d` was ACK_AFTER_THREADS; the four thread fixes and the boundary P3 are applied in `d4db4726c`. - Owned paths: decision, receipts/artifacts, handbook builder/tests, architecture scope/notes and generated outputs; registry committed last. - Serena and MinerU remain demoted while condition-absent controls are open; ccusage and session-analytics remain open. Retained failures, native attempts, local checks and model verdicts keep separate classes. - All 80 historical slot records and main owner/profile/pin fields are preserved. #713 landed as1796303f; #705 changed command-output's historical owners/29 operation. ## SOTA sources - `native-agent-stack@4c89741:evidence/artifacts/ns2604-e2e-20261004/method.md:60`: the frozen #700 qualification bar. [PR #700](#700). - The same pin's `docs/decisions/2026-10-04-ns2604-verified-e2e.md:114–121`: final-readiness authority. - `native-agent-stack@424b8a7:docs/lanes.md:94–128` and `scripts/host_receipts.py:710`: main-registry restoration, native re-registration and registry last. - The same pin's `docs/acceptance-evidence-policy.md:28–69` and `scripts/build_new_wsl_handbook.py:46`: evidence boundaries and existing generator interface. - Command-center source review `task-ns2604-coop-20261005T181852Z:12–23`, SHA256 `fa512269d639605a344f690166c436a208fffb79403bb0f55b2b48f0c9a7ef63`, retained in `review-715-corrections.json#/micro_repair_rulings`. It corrects its earlier bar wording; it is not upstream acceptance. ### Evidence-class table | Claim | Evidence class | Boundary | | --- | --- | --- | | Official #700 30/80 | Historical qualification | Existing dated baseline; no new host run | | Captured-status provisional30 and missing fresh-use proofs | Source review | Not measured #700 qualification or a derived numerator | | Retained native attempts, wrappers, fixtures and verdicts | Original separately scoped classes | Failures and client-leg limits retained | | Generators, tests and registry | Local integration / structural validation | Publication consistency only | | Organic native-arm readiness | None recorded here | Count pending final S4 | ### Local commands run (at head `e50f0f480`; content commits `d4db4726c`, `52a7680d9` and `a305d2cbf`) - `python3 scripts/validate.py`: exit 0; 69 components, 4 profiles, 214 receipts, 10,284 hashes. - `python3 -m unittest tests.test_new_wsl_handbook tests.test_architecture_pin_source tests.test_stack_lifecycle`: exit 0; 97 tests OK. - `python3 scripts/build_new_wsl_handbook.py --check`: exit 0 (regenerated with `--write`). - `python3 scripts/component_matrix.py --check`: exit 0; 32 rows. - `python3 scripts/new_host_grand_list.py --check`: exit 0; 32 layers, 66 winners. - `python3 scripts/evidence_manifest.py --check`: exit 0. - `git diff --check`: exit 0. - CI runs on this head. ### Refresh onto main and the command center's ruling - **Refresh.** `44bf09713` merges main `ecfa11276`: - The catalog merged cleanly as text, and the pin-source test passes. - The handbook was regenerated. - The handbook receipt's `regenerations` were united at the entry level. - The registry is main's 212 receipts plus this PR's 2, with its paths re-registered. - The hot-file pair keeps the registry last. - A GPT-6.1 Sol same-thread delta read of `82c25177f..d25ea1f` returned ACCEPT. - **Ruling.** The command center ruled ACK_AFTER_THREADS at `d25ea1f7d`: no P0 or P1, four valid P2 threads, one P3. `d4db4726c` applies: - **T1:** restores the `#/bounded_repair_rulings` locator. - **T2:** the handbook builder existence-checks and hashes `readiness.official_source` and `independent_review.recorded_source_review`, with a test. - **T3:** amendment times on the later ruling blocks and the two revised receipts. - **T4:** cites the reachable main commit `c148e049`. - **P3:** the `qualification_bar.scope` boundary sentence in the catalog notes (`:8`, `:1208`) and the receipt limitation. - **Optional:** a dated merge note in the decision record. - **T3 completion (`52a7680d9`).** The command center found T3 partial at `c3f4d8ddf`. The ruling blocks' amended_at_utc now carry their revisions' write times: 19:12:17Z from `73d75df4b` and 19:28:40Z from `bfff257c0`. Both equal the receipts' amendment times, and the item times stay in amendment_source_item. The handbook was regenerated and re-registered. - **Round 3 (`a305d2cbf`).** The command center found that `bfff257c0` also revised `bounded_repair_rulings`, adding `captured_status_boundary`, so the block now carries an `amendments` list that mirrors the receipts: - `73d75df4b` at 19:12:17Z (item 170827Z); - `bfff257c0` at 19:28:40Z (item 181852Z). A per-block check over the file's history finds a matching stamp for every content revision. The handbook was regenerated and re-registered. - **Threads.** All four are answered with the command center's text and resolved. Prior failed attempts remain retained. Reads so far: - a GPT-6.1 Sol delta read of the refresh (`82c25177f..d25ea1f`); - the command center's exact-head reads at `d25ea1f7d` (ruling ACK_AFTER_THREADS), `c3f4d8ddf` (T3 partly fixed) and `3457c9beb` (T3's bounded block still incomplete). The round-3 fix at this head awaits the command center's micro-check. No read yet covers it. These are source and integration review, not S4 qualification. All 212 main receipt entries (main `ecfa11276`) are preserved, with two owned receipts re-registered through the existing native library. ### Decision record `docs/decisions/2026-10-05-ns2604-foundation-requalification.md` records methods, sources, open controls/lifecycle gaps, superseded proposals and overturn conditions. Publication review or ACK does not provide S4 qualification. ### Host evidence No host-receipt or platform-status change. The command center is asked to micro-check round 3 at `e50f0f480` and ACK that exact head. Landing waits for the repo-wide fsspec relock (GHSA-27vj-qcqg-25rc). ### Checklist - [x] Main owner data, all80 historical slots and all 212 main registry receipts preserved. - [x] No credentials, active settings, private paths or raw conversations published. - [x] No host/config/install/service/billing change; #750 untouched. - [x] One lane label; registry-only final commit; exact head `e50f0f480` reported to the command center.
Scope
docs/decisions/2026-10-04-codex-rtk-hook-qualified.md(the first, Codex rtk hook: a narrow trust tool, the qualification evidence and its decision record (first of two) #701, landed as287514581; this branch was based on main4c897418f, after Clean default for every host: carriers held out of the shared template and retired on re-apply, removed Codex flags pruned, jCodeMunch at user scope #699 and NativeStack2604 E2E fix wave: 25 slot repairs, wave-4 promptfoo owner default on the repository-quality rule #704, and carries main4af7417b7, after Point new machines at the attested release v2026.10.05.1 #720, Disk headroom: node-mixin filesystem alerts on OTel hostmetrics, a burst-fill page, and copy guards against recursive test scratch (2026-10-04 ENOSPC) #712, Landscape sweep: link killed attempts re-run under a changed call key; redact dash-encoded project dirs #696 and Handbook: hash adoption/manifest.json without its release pointer (unblocks the v2026.10.05.x re-pin) #724, as a merge commit). The install plan'scommand-outputrow now installs RTK's Codex PreToolUse hook with upstream's own command and trusts it:rtk init -g --codex, thenpython3 tools/adoption/codex_hook_trust.py --command "rtk hook codex" --apply;[ok]lines ofrtk init --show --codexandcodex_hook_trust.py --check; a new after_sign_in acceptance runs a freshcodex exectold to add no prefix and requires the firstrtk git statuscommand item to haveexit_code == 0andstatus == "completed"(review thread 1; UNRUN: the model call needs the sign-in);--check. Codex rewrites a call tortk <command>before it matches execution rules on the command words, so aforbiddenorpromptrule on a command rtk can rewrite no longer matches it, and the rewrite space is not finite (env prefixes, global options such asgit -C, absolute paths, wrappers, PHP tool spellings, user filters and Unicode word boundaries all change what rtk rewrites, and the rewrite changes words afterrtktoo:cat fbecomesrtk read f). Three GPT reads each found a bypass in an analysing version of the review, so the tool now parses nothing (the design 5f recommended after 705f): it reads each regular*.rulesfile of<codex home>/rulesas bytes and accepts it only if (1) its sha256 is ontools/adoption/exec_rules_reviewed.json, an exact-bytes review for one rtk version (rtk --versionmust match the entry,rtk configmust showtransparent_prefixes = [],rtk trust --listmust sayNo trusted filters.,RTK_TRUST_PROJECT_FILTERSmust be unset, the user TOML filters file beside rtk's config must hold no filter; today one entry, Final architecture round 2 (wave 5): owners on the repository-quality rule, and NativeStack2604 plan rows for hcom, Chrome DevTools MCP, DSPy, SkillSpector, Inspect Scout and MCP conformance #713'shcom-deny.rulesat head7fbe586f3, sha256ac6254ee…, after its repair round 2 changed comments and justification strings only), or (2) it holds nothing but allow rules in Codex's own format byte for byte (the linesamend.rswrites, hcom's ownhcom.ruleswith its one comment line, empty lines), none containing the lettersrtkanywhere (the rewrite inserts that word, as a token or inside a shell-script token, so such a rule matches the rewritten command and not the original: codex-cli 0.159.3execpolicy checkallowsrtk git push origin mainunder["rtk"], and the script tokenFOO=1 rtk git push origin mainunder["/bin/bash", "-lc", ...], and gives no decision for the originals; 705g P1-1). Anything else is an exposure:--applyrefuses with exit 2 before the app-server starts (so before any write, even for an already trusted hook),--checkexits 6 for a trusted hook beside one (so the post_install acceptance catches a rule file added or edited after the grant),--allow-exec-rulesaccepts it. The listing is Codex'scollect_policy_filesmirrored fail-closed (only opening the directory may report it missing; each entry's type comes from its ownlstat, so an entry that vanished raises; a symlink, directory or named pipe is not loaded and never opened).--checkexits 0 only while every named hook is trusted and no rule file is exposed, 5 when a hook is not trusted, 4 when none matches, 6 when it is trusted beside an exposure; mutually exclusive with--apply, no edit, no backup. The plan's trust and check commands pass--rtk "$e/bin/rtk". 81 unit tests (local stand-ins for the app-server and forrtk --version,rtk configandrtk trust --list), 63 mutants each failing one;git show REV:path,diff,jqandgit branchalone), a dated note on the RTK card (cards are dated editions), the F9 recipe sentence and its owner-list test (command-outputjoins the after-sign-in owners), the new-WSL profile (adoption/new-wsl-profile.{json,md}), the definitive manifest and the consensus record it copies, which no longer say thatrtk init --global --codexis never run (review thread 2; the manifest's declared consensus digest follows), the regenerated new-WSL handbook and its receipt's digests (thewsl-new-distro-imageconvergence record needs no re-pin: NativeStack2604 E2E fix wave: 25 slot repairs, wave-4 promptfoo owner default on the repository-quality rule #704 freezes copies of the recipe and its test); the F9 owner list is NativeStack2604 E2E fix wave: 25 slot repairs, wave-4 promptfoo owner default on the repository-quality rule #704's, withcommand-outputadded;rtk init -g --codexdoes beyond the hook (RTK.md and an inert@<Codex home>/RTK.mdpointer line in the CodexAGENTS.md; there is no hook-only mode with--codex), and a second addendum answering review thread 3: Codex rewrites the call before approval and matches execution rules on the rewritten words, rtk rewrites 36 of 55 measured commands including mutating ones, and rtk has no allow-list, so the trust step is guarded instead of limited (sources at both Codex pins and rtk 0.51.0, alternatives and the untested boundary in the record).4af7417b7(main after Point new machines at the attested release v2026.10.05.1 #720, Disk headroom: node-mixin filesystem alerts on OTel hostmetrics, a burst-fill page, and copy guards against recursive test scratch (2026-10-04 ENOSPC) #712, Landscape sweep: link killed attempts re-run under a changed call key; redact dash-encoded project dirs #696 and Handbook: hash adoption/manifest.json without its release pointer (unblocks the v2026.10.05.x re-pin) #724; the branch's own base was4c897418f)lane:foundationevidence/artifacts/new-wsl-install-plan-20261002/{install-plan.json,install.sh,accept.sh,README.md},evidence/artifacts/token-stack-fresh-session-e2e-20261004/**(README, the scratch-run script and its output,fixtures/hcom-deny.rules, the mutation check, the heads derivation, its binary check and the heads filertk-rewrite-heads.json, now review evidence beside them),tools/adoption/exec_rules_reviewed.json,evidence/artifacts/new-wsl-handbook-20261001/receipt.json,docs/{token-session-handbook.md,token-efficiency-stack.json,new-wsl-handbook.json,new-wsl-handbook.md},adoption/new-wsl-profile.{json,md},evidence/artifacts/new-wsl-definitive-defaults-20261001/definitive-manifest.json,evidence/artifacts/new-wsl-layer-consensus-20261002/consensus.json,docs/decisions/2026-10-04-codex-rtk-hook-qualified.md,adoption/platforms/linux-wsl2-new-distro.md,tools/adoption/codex_hook_trust.py, the tests, andmanifests/evidence.json(last commit,registry:). Nothing is installed or trusted on any host by this change.SOTA sources
e001f773f80b22b7dc4c7a79521b30e35aaef026,README.mdL133 (rtk init -g --codex), the installedrtk init --help(--codex: "uses PreToolUse hook + AGENTS.md + RTK.md";--hook-only,--no-patchand--auto-patchrefused with it),rtk init --show --codexandrtk-init-codex-probe.json.01fc69f4026735edfdf6789820549727a4867b11,codex-rs/tui/src/hooks_rpc.rsL58-L91 (write_hook_trusts: the/hooksreview persists trust withconfig/batchWriteofhooks.state) andcodex-rs/hooks/src/engine/discovery.rsL775-L815 (hash and status), whichcodex_hook_trust.pyreproduces.01fc69f40267and rust-v0.160.0a956835d0207:codex-rs/core/src/tools/registry.rsL603-L660 (PreToolUse hook,invocation = updated_invocationL632, handler L689),codex-rs/core/src/exec_policy.rsL327-L420 and L770-L850 (rules matched on the command words; unmatched fallback),codex-rs/shell-command/src/command_safety/is_dangerous_command.rsL133-L143 (forcedrm, unwrappingsudoandenv),codex-rs/hooks/src/events/pre_tool_use.rsL357 and L388-L405, andcodex-rs/exec/src/exec_events.rsL151-L166 (CommandExecutionItem:exit_code,status);codex execpolicy check, Codex's own rule evaluator.a956835d0207:codex-rs/core/src/exec_policy.rsL1121-L1170 (collect_policy_files: only opening the directory may report it missing, errors on the iteration and on an entry's file type propagate, every entry's type is asked before its extension, symlinks are not loaded), L645-L660 (load_exec_policy_with_warning: a parse error in any rules file makes Codex load no file rules),codex-rs/execpolicy/src/amend.rs(blocking_append_allow_prefix_rule: the format of the allow-onlydefault.rules),codex-rs/execpolicy/README.md(prefix_ruleandhost_executablebuiltins, strictest decision wins). The 705f counterexamples rest on:codex-rs/execpolicy/src/parser.rsL64 and facebook/starlark-ruststarlark_syntax/src/lexer.rsL415 at0c8d107ab963(a raw CR inside a string is dropped),codex-rs/shell-command/src/bash.rsL492,codex-rs/core/src/exec_policy.rsL876 andcodex-rs/core/src/shell.rsL22 (assignment-prefixed scripts fall back to the whole shell argv); rtk v0.51.0e001f773f80b:src/discover/registry.rsL393-L418 and L1811 (PHP tool normalization),src/core/toml_filter.rsL199-L227 and L456-L495 (filters load only while trusted; trusted user filters keep the complete pattern, alternative branches allowed),src/hooks/trust.rsL51-L166 andrun_trust(the global trust store,rtk trust --list, and theRTK_TRUST_PROJECT_FILTERS+ CI override),src/discover/registry.rsL1743-L1763 (exclude_commandsis applied before the TOML-filter rewrite),src/filters/gcc.tomlL3 and the rust-lang/regex word-class contract (Unicode\b),src/discover/rules.rs(94RULESpatterns, each^-anchored),src/discover/registry.rsL64 (ENV_PREFIX), L194-L215 (classify_commandnormalization), L438 and L568 (global options, absolute paths), L1386-L1498 (PROCESS_WRAPPERS, shell keywords,uv run), L1743-L1760 (the TOML filters are a second rewrite source),src/filters/*.toml(62 builtin filters),src/core/config.rsL119-L145 (transparent_prefixes),src/main.rsL3072-L3100 (rtk hook check: exit 0 with the rewrite, exit 1 withNo rewrite for:) andrtk config's output (show_config). hcom's own rule file (aannoo/hcom7151660a3):src/hooks/codex.rsbuild_codex_rulesL1508-L1534 andHCOM_TOOL_NAMESL578-L585,src/hooks/common.rsSAFE_HCOM_COMMANDSL52-L72.e001f773f80b:hooks/codex/README.mdL14-L24 (the rewrite precedes Codex's approval and sandbox checks),src/hooks/permissions.rsL64-L72 (no Codex rule source),src/core/config.rsL119-L123 andsrc/discover/registry.rsL1548-L1582 (exclude_commandsis exclusion-only),rtk hook check --agent codex.@reference inAGENTS.md:docs/token-efficiency-stack.md, citingcodex-rs/codex-home/src/instructions/mod.rsat rust-v0.157.1.check_plan.py(commands, acceptance and scripts agree), the hot-file protocol ofdocs/lanes.md, and WSL recipes: run Windows-side steps through PowerShell 7 (pwsh.exe) instead of Windows PowerShell 5.1 #694's re-pin of the recipe-freezing convergence record.Evidence-class table
install-plan.jsonand run in scratch HOMEs with rtk 0.51.0 and codex app-server 0.159.3:--checkexit 4 before the hook exists;rtk init -g --codex0 (the hook lands atpre_tool_use:1:0, after a memory hook's group);--check5 before the trust; the trust 0 ("read back from hooks/list by key and hash"); the post_install program 0; and nineteen homes for the rule review: #713'shcom-deny.rulesby its exact bytes lets the trust proceed, and agit pushrule added after the grant makes--checkexit 6 and the trust refuse; the same bytes plus one comment line, a configured rtk transparent prefix, a user TOML filter beside the reviewed file, a trusted project filter and the CI override variableRTK_TRUST_PROJECT_FILTERS(the last two each make the real rtk rewritehcom kill luna, recorded before and after, and with rtk exclusions forhcomanduvx hcomin its config the same filters leave both commands alone) are each refused; Codex'sdefault.rulesformat and hcom'shcom.rulesformat let the trust proceed; agit pushforbid rule is refused (exit 2, nothing written;--check5), accepted with--allow-exec-rules, after which--checkexits 6; the same rule with itsrtk git pushtwin is still refused; the counterexamples of 705e (git -C ., broaduvandnpx, the nestedhost_executablefile, under which the real codex evaluator forbidsgit push origin main) and of 705f (a raw CR in a token, abash -lcscript rule,phpunit.exe,g++plus a combining mark, each of which the real rtk rewrites or the real evaluator reads differently), an allow rule that holdsrtk(the evaluator allowsrtk git push origin mainunder["rtk"]and the script tokenFOO=1 rtk git push origin mainunder abash -lcrule, and gives no decision for the originals; the real hook produces the second fromFOO=1 git push origin main) and an unreadable rules directory are refused (79 steps, all as expected)local_integration: one run, one hostplan_row_scratch_run.py;plan-row-scratch-run.json(the trust command carries--codex-process-name no-such-process-namebecause other codex processes ran on the host; recorded in the file)rtk git status, exit 0, completed) ends 0, and five negative fixtures (exit 127, completed with exit 1, declined, no rtk prefix, no command item) end 1syntheticcodex execand a signed-in launchercodex_hook_qual.pyshowed the same prefix through the gateway route--checkand the review, with local stand-ins for the app-server and forrtk --versionandrtk config(FakeRtk):--check0 when trusted and no rule file is exposed, 5 untrusted or modified, 4 none matches, 6 trusted beside an exposure; no edit and no backup;--applyrefused with exit 2 before the app-server starts (noAppServercall, no backup, no write) for every counterexample above, a reviewed file with one changed byte, another rtk version, a failing rtk, config or trust-list command, a configured prefix, a trusted filter, the override variable or a user filter, a missing or malformed reviewed list, an unreadable file, and 29 near-misses of the allow-only grammar (a prompt line, CRLF, a tab, an escape, a non-ASCII byte, a justification, alternatives, a second statement, ...); accepted: the reviewed bytes under another name, Codex's and hcom's allow-only files (hcom's rebuilt from its installer's source lists), empty and comment-only files, tokens that merely contain the lettersrtk; a listing in which an entry vanished, an iteration or an open raised, or a path that is a file is refused, while a symlink, directory or named pipe is not loaded (the pipe is never opened)synthetic(fake app-server, fake rtk, fakescandir)tests/test_codex_hook_trust.py(81 tests)rtk-rewrite-heads.json, 142 from the 94 RULES patterns and 62 builtin TOML filters, the wrappers and the env prefix) agree with the binary: a positive control for each of the 94 patterns, 13,041 scanned commands (1,449 names, 9 argument shapes) with 623 rewrites and none outside the heads, 67 wrapper prefixes in front ofgit status(24 rewritten, all led by a head), 8,884 spellings of the 101 literal heads with 480 rewrites and none outside the heads; and the entry's own first tokenshcomanduvxin 22 spellings and 8 shapes (352 commands) are never rewritten. The derivation had 101 gaps in the first scan (ther#"..."#sbt rule, the TOML filters,\bcontinuations such asgcc-13), now 0. Review evidence, not a gate: the tool reads neither filelocal_integration(the scan can falsify the review, not prove it)derive_rtk_rewrite_heads.py,check_rtk_rewrite_heads.py;rtk-rewrite-heads-check.jsonFileNotFoundErroron an entry or the iteration or an open error read as no rules, the extension before the file type, a followed symlink, a named pipe loaded, any name ending inrules, an unsorted listing; grammar: a prompt rule, a quote, a backslash, a tab or CR in a token or comment, trailing text,anyforall, no empty lines, any comment, spacing, an empty pattern, an allow rule that holdsrtkin four variants (a token after a wrapper, whole-token only, inside a shell-script token, only a leading token); the reviewed list: a malformed, uppercase or over-long hash, a malformed list read as empty or not blocking, the list read with no rule file; the decision: every file reviewed, every file allow-only, an unreadable file not blocking, rtk asked for allow-only files; rtk conditions: the version gate, exit statuses, theConfig:line, transparent prefixes, the trust list (ignored, exit status ignored, matched loosely), the override variable (ignored, only the value 1), user filters, the schema line, comments, an unreadable or non-UTF-8 filters file, no rtk, no PATH lookup, telemetry, a terminal, no time limit; the flow:--applynot refusing, the flag accepting nothing or not accepting,--checkignoring an exposure or answering 6 before 5,--rtknot passed, no dry-run note) each fail at least one test; the tests were written after the code, so this is the check that they are not vacuouslocal_integrationrule_review_mutation_check.py;rule-review-mutation-check.txtgit pushand one promptinggit commit,git pushisforbiddenandgit commitisprompt, whilertk git pushandrtk git commitget no decision (each answer needs exit 0 and a valid response)local_integration(Codex's own evaluator, codex-cli 0.159.3) andsource_reviewfor the dispatch order at both pinsplan-row-scratch-run.json,execpolicy_check; the decision record's addendumgit push,git commit,gh pr merge,docker run,pip install,rsync --delete; 19 are not (git reset --hard,rm -rf,npm publish,terraform applyand others); the fiveexclude_commandschange none of theselocal_integration: one run, one hostrtk_behaviour_probe.py;rtk-behaviour-probe.json,codex_hook_checkRTK_TRUST_PROJECT_FILTERSis checked in the tool's own environment, not in the one Codex runs the hook in, and a filter trusted after the review shows at the next--check(705g P1-2: a point-in-time check cannot establish what a global hook does in every working directory; the exclusions of alternative (j) are the enforced hardening and are not enforced here); the reviewed list covers rtk's default hook configuration of one version; hcom's installer itself was not run (its file is rebuilt from its source)install-plan.json,install.shandaccept.shagreelocal_integrationcheck_plan.py: 80 rows, 163 commands, 101 acceptance entries (with #704's rows)local_integrationbuild_new_wsl_handbook.py --check0;test_new_wsl_handbookOK;validate_convergence.py --all-recorded0Local commands run
Decision record
docs/decisions/2026-10-04-codex-rtk-hook-qualified.mdgains the 2026-10-05 addendum (the relayed answer, its effect, and the one-command undo:rtk init -g --codex --uninstallremoves the hook,RTK.mdand the pointer together), its Residuals sentence now says the user approved the pointer edit, and a second addendum, "approval and execution rules": five sourced findings (item 5 corrected: approvals off do not switch execution rules off, and NativeStack2604 has no user-layerrulesdirectory), the decision (the hash-list rule above, why three analysing versions failed, the reviewed list and its conditions, the pin-move rule: a move of the rtk pin re-reviews the list, tied to the RTK row ofdocs/token-efficiency-stack.json), the evidence, the limits and what would overturn it, the review rounds, and ten alternatives (anexclude_commandsread-only limit, whose probe showsgit -C /tmp pushstill rewritten; a never-rewrites-mutating proof; holding the hook out; shippingrtkrules; refusing on any rules file; the probe-and-sample review; a wrapper hook; derived heads with a parser; a purpose-written parser; (j) enforcedexclude_commandsentries forhcomanduvx hcom, measured and not enforced, with why).Review threads
Three Codex-connector threads, each answered with its fix and source in the thread and resolved at head 4739ea8: after_sign_in exit status (
accept.sh), the profile's "never runsrtk init" statement (install.shL446), and approval classification against the rewrite (install.shL448).Cross-family reads of the guard, four versions: 4739ea8 (refuse on any rules file) was read by 705d (Sol, through 5f: P1 a failed listing of the rules directory read as no rules, P2 the refusal came after the app-server started, P2 the scratch run accepted a failed evaluator) and job-071 (through the command center: P2 the same listing hole, P2 rules reported only for a hook still to be trusted, P3 the claim that approvals-off hosts consult no rules).
e6321c0b8(a behavioural review withrtk hook checkandcodex execpolicy check) was read by 705e: three P1s that sampling cannot close (an entry-levelFileNotFoundError, aprefix_rulenested in ahost_executableargument, extensions of a prefix rtk leaves alone).c771da9eb(heads derived from rtk's source and a literal-onlyastreader) was read by 705f: five P1s (a raw CR in a Starlark string, a rule on the whole shell argv, PHP tool suffix spellings, user filter regexes with a second branch, Unicode word boundaries) and a P2 (DirEntry.is_file()swallows a missing entry).3a2bb97ba(content2d052a659) replaced the analysis with the hash list on 5f's recommendation and added one exclusion found while checking the design against the real evaluator: an allow rule that namesrtk. 705g (Sol, through 5f, at3a2bb97ba) found two P1s and no P2 in it: (P1-1) the exclusion refused only a whole tokenrtk, but Codex evaluates an assignment-prefixed script as one token of the shell argv and the hook insertsrtkinside it, so["/bin/bash", "-lc", "FOO=1 rtk git push origin main"]allowed the rewritten script and not the original; (P1-2) project filters, which rtk loads from the hook's working directory and whichrtk trust --yesorRTK_TRUST_PROJECT_FILTERS=1with a CI variable activate, rewrotehcom kill lunaout of the reviewed forbid rules while the reviewed hash still passed. This head's repair (b7f758768, registry1b8d4c074; merge of main9080bc324) repairs both in one bounded round:rtkis refused anywhere in an allow rule (regression cases, a whole-token mutant, a scratch home); the reviewed-file conditions also need an emptyrtk trust --listand noRTK_TRUST_PROJECT_FILTERS(the reviewer's second option: classify the exposure so that it needs--allow-exec-rules), with rtk's exclusions measured as the enforced alternative and recorded, not enforced. It also follows #713's repair round 2 (the entry holdsac6254ee…, the 7fbe586 bytes; only comments and justification strings differ from 5f295f2).705h (Sol, through 5f, at
14a8b119f; verdictverdict-705h.json) ACCEPTed: no P1 and no P2. Both 705g P1s were verified fixed against the real binaries (a lowercasertkanywhere in an allow line is refused, and the whole-token mutant dies with 36 test failures; the trust list and the override variable classify both project-filter activation routes,--applyexit 2 and--checkexit 6, with the default and the XDG layouts, andrtk trust --listdetected the filter from another directory), and no additional bypass was found in the pinned rewrite paths and inputs. Two boundaries stay not verified and are recorded as residuals: runtime coverage (codex-cli 0.159.3 and rtk 0.51.0 were probed, rust-v0.160.0 was read from source, no fresh model session) and the point-in-time and environment limits (the classification observes the current user-layer rule bytes and the tool process's RTK environment and trust store; no atomic snapshot across listing, loading and the grant, and no enforcement after a later change of rules, filters, HOME or XDG paths or the hook's environment; project and managed Codex policies are outside its scope).Merge of main
9080bc324merges main4af7417b7(#720 re-pin to v2026.10.05.1, #712, #696, #724) into the branch. Conflicts were only in the generated and hot files (docs/new-wsl-handbook.md, the handbook receipt,manifests/evidence.json), resolved by the hot-file protocol ofdocs/lanes.md: main's copies, the branch's 44 registry entries re-registered from the pre-merge snapshot, the handbook regenerated with main's generator (#724), the receipt digests refreshed. Carry check: of every file this PR changes against its old base, onlydocs/new-wsl-handbook.{json,md}, the receipt andmanifests/evidence.jsondiffer between the pre-merge head1b8d4c074and the merge head (git diff 1b8d4c074 <merge head> -- <the PR's files>); the 705g repairs are3a2bb97ba..1b8d4c074. The merged tree failed two tests of main's new rules, fixed ina7990f56a(registry14a8b119f): the F9 unit saystools/adoption/exec_rules_reviewed.jsonwas added afterv2026.10.05.1(main's unreleased-path marker rule, #720), and the receipt's frozen profile digest is the branch's (the merge took main's receipt); the handbook and the receipt follow.Host evidence
No files under
evidence/hosts/change. The scratch run used a scratch HOME; the live~/.codexand rtk configuration were neither read nor written.Checklist
🤖 Generated with Claude Code