Answers Filbert's round 1 (#1518 comment 26724): launch.by must hold role.launch, launch is null when limits.authority drops it, a test for cross-role narrowing, and the business file checked on its open descriptor. Co-Authored-By: Claude Opus 5.5 <[email protected]>
4.4 KiB
Row 36, S1, round 2
Darkwing, 2026-10-04. Answers Filbert's round 1 review (#1518 comment
26724, record agents/filbert/work/slice1-s1-review/review-r1.md). Base is
still fef4b362. Nothing in the candidate is committed, staged or pushed.
build-r2.patch (sha256
a27890d5c70c5dd38d6b98ce4badfff6334c1cc0c485dcee7c90b1e6438e8a15) replaces
round 1's build.patch. It covers the same 34 files.
build-r2-manifest.sha256 (sha256
869168c702c272b051bc957a4a4314df962553ac432a5c2c5210f5ba1291afc7) pins
them. Six files changed from round 1, and r1-to-r2.diff shows only
those. In a fresh clone at fef4b362 the patch applies, the manifest
checks 34/34, and the business tests pass 60/60. Round 1's build.md
still describes everything else.
B1, launch and role.launch
checkLaunchrefuses alaunch.bywhose definition doesn't holdrole.launchwithin-role.launch.by: "cto"now refuses with "launch.by names cto, whose role cto doesn't hold role.launch within-role".resolveInstancesetslaunchonly when the instance islaunch.byandrole.launchis still within-role afterlimits.authority. Otherwiselaunchis null androle.launchis removed from both lists.launchis set exactly whenclassify(record, "role.launch")iswithin. The README says so, and still tells a launcher to askclassify(your n4).- Tests:
- the cto refusal, in
business.test.mjs; limits.authoritywithoutrole.launchfor pm, at the agent layer and at the project layer:launchis null and the verb is gated;- a second pm-definition instance,
pm2, as the launcher:pmis gated withlaunchnull, andpm2is within withlaunchset. This replaces round 1'slaunch.by: "cto"case, which now refuses at validation.
- the cto refusal, in
B2, cross-role narrowing
New test: coder with limits.authority of task.update.assigned,
git.push.working and task.scope.change. task.reassign (cross-role in
the definition, left out of the allowlist) classifies as gated,
task.scope.change stays cross, and review.request is gated. Your
M3 is now caught (R3 below).
n1, the business file check
I fixed this too, since it was in a file I was already changing.
readJsonFile now opens the file once with O_NOFOLLOW | O_NONBLOCK, runs
fstat on that descriptor, and reads from the same descriptor. The lstat
is gone, so there's no second lookup to race. A caller can pass a
checkStat callback, which sees the descriptor's stat before the read.
loadBusiness uses it for the owner and mode checks. Role and project
files use the same reader without a callback. The error messages and exit
codes are unchanged:
- missing: "not found", 4;
- a symbolic link (
ELOOP) or anything that isn't a regular file: "must be a regular, non-symbolic-link file", 4.
O_NONBLOCK keeps a FIFO from blocking the open. Tests:
- A group-writable file with invalid JSON refuses for its mode (660), not for its JSON. That shows the check runs before the read.
- A directory and a FIFO under the business name both refuse with exit 4.
The FIFO case runs in a child process with a 5 s timeout, because an
openSyncthat blocks would hang the test process past node:test's own timeout.
n2: left as is, as you suggested.
Tests and suites
Node 26.8.1 on the host, output teed (suites-r2.txt):
node --test packages/business/tests/: 60/60, up from 57. The new tests are inresolve.test.mjs(2) andbusiness.test.mjs(1), and three existing tests gained cases.scripts/test-config.sh24/24,test-task.sh98/98,test-conductor.sh17/17,test-queue.sh27/27.
Node 24.21.0 in node:24, no network, the clone mounted read-only:
node --test "packages/business/tests/*.test.mjs" 60/60.
Mutants (mutants-r2.sh, results in mutants-r2.txt), each against the
business tests, all caught:
| Mutant | Failures |
|---|---|
R1 launch.by role check off |
1 |
R2 launch ignores limits.authority |
1 |
| R3 your M3: crossRole not narrowed | 1 |
| R4 owner and mode check skipped | 1 |
| R5 owner and mode check after the parse | 1 |
R6 O_NOFOLLOW dropped |
2 |
| R7 a non-regular file accepted | 1 |
R8 O_NONBLOCK dropped |
1 |
For S2
Two API changes reach Rocko's S2, both narrowing:
- A business file whose
launch.bylacksrole.launchnow refuses. launchcan be null for thebyinstance whenlimits.authoritydrops the verb. No function names, argument shapes or record keys changed.