Repository navigation
docs: confine every review pass to its worktree as CA-32, assigned to WP-4 - #28
Merged
constantin-jais merged 3 commits intoOct 26, 2026
Merged
Conversation
… WP-4 Owner decisions of 2026-10-24, verbatim: - R-13: "Linux netns + nftables (Recommandé)". - K1: "6e condition, deux pilotes (Recommandé)". The second-family reviews of WP-3 (Kimi K3, GLM 5.3, on #27) both rated as major a channel that the letter of INV-a does not cover. The pi `read` tool resolves absolute and `~` paths outside the pass directory (pi 1.4.0, dist/core/tools/path-utils.js:38-44), and the verdict, free text included, is published under docs/reviews/. A reviewed commit can therefore get a host file copied into a public artefact. No deterministic control over the verdict can tell a copied secret from a comment, so only a boundary enforced outside pi closes the channel. Requirements specification: - CA-32: the pass reads nothing outside its detached worktree, enforced by the R-13 mechanism, with no provider secret readable from inside the pass (neither a mounted file nor an environment variable that a process pseudo-file would expose). Both drivers refuse real passes until it holds. Red vector `pass-read-confined`, with a neutralisation. - R-16 records the channel and the decision. R-13 records the mechanism and the options rejected that day. - CA-26: the profile also carries --no-extensions and --no-approve, with their measured reason (an extension can replace a built-in tool by name, dist/core/agent-session.js:2893-2894). The validation command points at fanout-core.ts, because WP-2 moved the pi spawn out of fanout.ts. The "value at the commit read" now names 7644bfd and stays red there. - Threat table: one row for the channel. PRD: the WP-4 row now covers CA-32. Its scope gains tools/review/confinement/** (the R-13 mechanism) and tools/review/*.ts (both drivers must run their passes under it). The WP-4 issue will cite the commit of this change. Norm reader: RESULT: pass. Exempt: docs-only Signed-off-by: Constantin Jais <74049135+constantin-jais@users.noreply.github.com>
…acle Second-family review of #28 (GLM 5.3, ACCEPTABLE on 0f306b2). Each finding was checked against its source. - Major, applied. R-16 named a `pass-read-confined` condition at `satisfied: false` that no branch carries yet: the second round of #27 is not pushed. The detection column now reads "no true condition", which holds both before and after #27 merges. - Minor, applied. Network namespaces and nftables do not confine a file read. CA-32 now says that the container mounts confine the read, that the network namespace and its rules confine egress, and that the second does not replace the first. - Minor, applied. The vector now requires that the error returned for the sentinel is byte-identical to the error for a missing path inside the worktree, so a refusal cannot tell whether a host file exists. - Minor, rejected. The suggestion was to note in issue #20 that acceptance also runs check:review-tools. A work-package issue body must be exactly the form output (WORK-PACKAGES.md, "Nothing else is allowed in the body"). The full validation chain stays in the requirements specification. Exempt: docs-only Signed-off-by: Constantin Jais <74049135+constantin-jais@users.noreply.github.com>
Second round of the second-family review of #28 (GLM 5.3, ACCEPTABLE on 0a8a870). The reviewer accepted the four dispositions of round one and raised one new minor finding, checked here at its source. The round-one wording asked for a byte-identical error between the sentinel and a missing path inside the worktree. That cannot be met. pi returns error.message unchanged (pi 1.4.0, dist/core/tools/read.js:77, pi-agent-core dist/agent-loop.js:542-546), and the Node message embeds the path it read. Reproduced: accessSync on two missing paths gives two different strings, "ENOENT: no such file or directory, access '<path>'". An author who compared the full message could never turn the vector green, so the sixth activation condition could never be met. The requirement now compares the same path in two host states: a host file present at that path, and no file there. Equality there is exactly the "no existence oracle" property. Exempt: docs-only Signed-off-by: Constantin Jais <74049135+constantin-jais@users.noreply.github.com>
constantin-jais
added a commit
that referenced
this pull request
Oct 26, 2026
… by both drivers Review round 1 on 28dfe9c, finding F10: the owner's decision of 2026-10-24 on K1 (read is not confined to the worktree), verbatim "6e condition, deux pilotes (Recommandé)", written as CA-32 by #28. The activation table gains its sixth condition: id pass-read-confined, requirement "a review pass cannot read outside its detached worktree, enforced outside pi", source citing the owner decision of 2026-10-24 and CA-32, work package WP-4, satisfied false, evidence null. The LangGraph path applies all six: "3 of 6 activation condition(s) unmet". The default driver now refuses real passes itself, in runCampaignDirect and not only on the command line, while the conditions that bind it are unmet: pass-read-confined alone, since it loads no package (defaultDriverRefusal). The refusal comes before anything is printed or opened, names the condition, and leaves --dry-run available; a dry run, an empty run and a refused overwrite run no pass and need no activation. Both drivers throw ActivationRefusedError, which fanout.ts prints with exit 2. The canonical table check moves from fanout-graph.ts to fanout-activation.ts (assertCanonicalTable) and serves both drivers. The LangGraph refusal no longer suggests omitting --runtime, since the default path refuses too. Tests that run real passes with the stand-in pi hand both drivers the table reserved for tests (ALL_CONDITIONS_MET_FOR_TESTS), as the graph driver's already did. fanout-cli.test.ts: the command line now pins the refusal, that no flag or variable lifts it, and every path that runs no pass (dry run, recorded verdict skipped, forced overwrite refused, missing commit); what a real campaign records, a failing pass and a dirty tree are pinned in process through the default driver and printed as the command line prints. The CA-29 test with the package absent now shows a real run reaching the driver's own refusal, identical to the run with the package present and with no module resolution error. authority-boundary.test.ts covers the default driver: it takes its refusal from fanout-activation.ts and fanout.ts hands neither driver a table. Gate-integrity questions for the added and changed tests: 1. What makes them red (env -i PATH HOME, full review suite): - `if (false) throw new ActivationRefusedError(refusal ?? "");` in runCampaignDirect: 4 red (driver refusal, CLI refusal, no flag lifts it, CA-29 with the package absent); - DEFAULT_DRIVER_CONDITION_IDS emptied to `[]`: 5 red (the same 4 and "the default path is refused by the sixth condition alone"). 2. Would an equivalent refactor redden them: no for the behaviour cases, which read refusals, messages and what ran. The authority-boundary case pins two call shapes on purpose (the driver reads its table from the activation module; the command line passes none), as its neighbours do. Work-package: #19 WP-3 Signed-off-by: Constantin Jais <74049135+constantin-jais@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
The two second-family reviews of WP-3 (#27, Kimi K3 and GLM 5.3) rated as major a channel that the letter of INV-a does not cover:
readtool resolves absolute and~paths outside the directory of the pass. Source: pi 1.4.0,dist/core/tools/path-utils.js:38-44, "Handles ~ expansion and absolute paths". Thegrep,findandlstools do the same.docs/reviews/of this public repository.A reviewed commit can therefore get a host file copied into
detailand published. No deterministic control over the verdict can tell a copied secret from a comment, so only a boundary enforced outside pi closes the channel. The default driver has no activation table, so the channel is open on it today.Owner decisions of 2026-10-24, verbatim:
What changes
docs/cahier-des-charges.md:--dry-runstays available.pass-read-confined, with a neutralisation (mounting the sentinel directory must let the read through).--no-extensionsand--no-approve, with their measured reason: an extension can register a tool under a built-in name and replace it (dist/core/agent-session.js:2893-2894; the shippedexamples/extensions/ssh.ts:128-129routesreadover ssh).grepnow targetsfanout-core.ts, because WP-2 moved the pi spawn out offanout.ts.7644bfdand stays red there.CA-18 à CA-32,R-11 à R-16) and provenance are updated.docs/prd.md:WP-4row now coversCA-32. Its scope gains:tools/review/confinement/**, a new directory for the R-13 mechanism;tools/review/*.ts, because both drivers must spawn their passes under that mechanism.After this merges, issue #20 (WP-4) will be updated to cite the merge commit as its
PRD-ref. The work-package gate judges a package at the commit its issue cites.Ordering
This PR goes before WP-3 (#27). The second round of #27, not pushed when this was written, will add the sixth condition
pass-read-confinedto the activation table, withsatisfied: falseand source CA-32; #27 is not merged without it. CA-32 therefore exists before any code cites it. R-16 is worded to hold on both sides of that merge: no truepass-read-confinedcondition exists, whether it is absent or false.Verification
bun prd-read.ts <repo-root>, governancetools/quality/prd-model.ts):RESULT: pass. It warns thattools/review/confinement/**matches no tracked file; the PRD declares that directory as to be created by WP-4.Exempt: docs-only
🤖 Generated with Claude Code