Files

6.4 KiB

Filbert review: row 175 r1 (#1673), approve

Candidate manifest dc5c0361a3103e758b52e1b8e02a57bc348ce2797531f9c2e6d55ea7911a1410 on base d63cfca22 (candidate commits 84e350f99 and 7b27ab3f9). Brief docs/plans/2026-10-19_tester-read-checks.md (blob 41b6033da2).

Verdict: approve. I found no defects. There are three notes below. They aren't findings, and none of them blocks.

What I ran

  • Built ~/filbert-scratch/r175-r1/wt: d63cfca22, then git apply --index build.patch.
    • sha256sum -c on the manifest: 25/25 OK. The manifest file hashes to dc5c0361...1410.
    • The cached diff's patch-id 004191c61f78 equals that of git diff d63cfca22 7b27ab3f9.
    • Diffstat: 25 files, +653/-119.
  • Base drift: git log d63cfca22..HEAD on the 25 paths is empty.
  • Pins and path readers:
    • The only 64-hex pins in tests are on row 164's files (channel-proof.test.mjs:12 and the like), and none of those files is in the manifest.
    • host.test.mjs:826 reads packages/cli/README.md, but only for the unit file name, which no hunk touches.
    • stack-release.test.mjs reads a refusal string from docs/TOOLS.md. The only TOOLS hunk is at :280.
  • Stale text: outside the tests, no source or doc still requires the prefix. [mos test] survives only as message bodies in tests, which is still valid input.
  • Tests, one file at a time, scratch TMPDIR, no mutants. The slot was sage-1093's grant, after my /proc CLEAR. 23 files, 205/205 pass, 0 fail, 0 skip, every rc 0 (23:26:03Z-23:26:47Z). Counts are awk sums over the spec logs.
    • The 10 touched test files: bus tester-writes, tester, names, instances-verb, routes-verb and limits; cli tester-reads, names and tester; project tester-init.
    • Readers of the changed src and the scripts/mosaic case line: bus plugins-verb, project-files, messaging and launch-notice; cli app, instances, limits, usage, project, thread-cli and host; project project; queue dispatch.
  • I did not run any mutant. "24 of 25 killed" in round 1a and "m2b, m10a, m10b killed" in round 1b are Dewey's receipts.

Brief items against the code

  • Organization branch (broker.mjs:1238-1253):

    • The tester gate runs before human-required and before every keys() check.
    • Only TESTER_ORGANIZATION_VERBS pass. organization.set and organization.revision refuse there, so a tester never reaches the role grant check or the consume.
    • actor is tester.
  • Store path (:1286): TESTER_VERBS is 19 entries, the old 10 + 7 reads + name.set + project.create. Both lists are frozen and pinned by the test at tester-writes.test.mjs:17.

  • Writes:

    • name.set keeps every name check, skips consumeAuthority for a tester and writes by tester.
    • project.create and project.list skip #human for a tester only.
    • thread.list binds owner to b.human (:2329).
    • The broker prefix check, the CLI's early check and both TESTER_PREFIX constants are gone. unknown-role for human and tester, the corrects and decision key refusals and tester-reply-required stay.
  • Project file verbs: #requestProjectFile (:1413) refuses a tester with tester-refused before #human. These verbs dispatch before the store gate, so this is what makes brief test 9's project.file.save line hold.

  • W7 (cli/src/project.mjs:56-64) runs in the brief's order:

    1. testerProjectArea (exit 2).
    2. One agents read through the tester transport (exit 3).
    3. initProject(context, {author: 'tester'}).

    The only work before step 1 is loadSystem and loadBusiness, which read and write nothing. initProject runs author through checkedId, and tester-init.test.mjs:30 refuses a non-id author before any directory exists.

  • scripts/mosaic:38 adds plugins, name, names, follow, threads and thread. The seat usage that app.test.mjs pins doesn't change.

  • Brief tests 1-13 each map to a test:

    • 1, 3, 4, 9, 11 and 13: tester-writes.test.mjs:57, :70, :86, :112, :195 and :17.
    • 5 and 7: :167 and :184.
    • 6: bus tester.test.mjs, the "needs no prefix" test.
    • 2: tester-reads.test.mjs:59. It covers six reads plus business instances, checks that the tester transport was called and the human's wasn't, and checks that each read without --tester exits 3.
    • 8: tester-reads.test.mjs:159, :173 (with bus.tester off, so exit 2 proves the area check ran first) and :188.
    • 10: tester-reads.test.mjs:87. 12: :132.

Dewey's three design choices

  1. The tester gate before the argument checks: agreed. It matches the store-path gate, and a tester learns nothing about a verb's argument shape. The test at :112 pins it with bad-key calls.
  2. contains counts the area root as inside: see N1.
  3. The project file verbs refuse with tester-refused instead of human-required: agreed. Brief test 9 requires it.

Notes, not findings

  • N1 packages/project/src/paths.mjs:32: rel === '' lets a business entry whose repo is exactly <dataRoot>/projects/<business> pass testerProjectArea.
    • A repository there would contain the default repo path of every other project in the business (<area>/<project>). A later human project init would then nest a repository inside it, and the outer repository would show it as untracked.
    • It takes a human-authored business entry, and the human's own init already allows that path, so the tester gains nothing the human lacks.
    • No test exercises the root itself. The inside list at tester-init.test.mjs:38 has the default path, a child and a grandchild. So a mutant dropping rel === '' from the area check would survive there. projectRepo's overlap check uses the same function, though, so I haven't confirmed that.
    • Suggestion for a follow-up: refuse the area root for the tester, or pin the choice with a test.
  • N2 Brief test 10, "every other write form not in W1-W7": the list at tester-reads.test.mjs:87 covers every bus-calling write form. It doesn't include bus start and bus stop, which are host commands that make no bus call. Their parse() refuses --tester as an unknown option with exit 4 (cli.mjs:81), so the behavior holds. It just has no test.
  • N3 broker.mjs:1288: a tester's non-message verbs run with a {...s, reader: true} view, and that now includes the two writes name.set and project.create. Neither case reads s.reader, and the top-level read-only gate checks the unmodified session, so the writes land, as the tests show. A future check of s.reader inside those cases would refuse the tester without anyone intending it. A comment there would help.