mosaic thread create|open|read and threads take --tester and run as the tester through
tester-cli.mjs. talk --thread and follow --thread take --tester too, and the row 177 refusal of
--thread with --tester is gone. The bus already checks thread ownership (thread-not-owned), so
the CLI adds no rule of its own, and every verb it sends as the tester is in TESTER_VERBS. follow
already receives with message.receive, so a tester reply arrives without polling inbox.
docs/TOOLS.md and packages/cli/README.md list the new flags.
The new tester-threads.test.mjs runs an in-process Broker. It covers create, list, open, send,
read and follow on a tester thread; thread-not-owned on a human thread both ways; and the human
forms unchanged with no tester transport call. A real-process test runs scripts/mosaic as the
tester. thread-cli.test.mjs and tester-reads.test.mjs drop the argvs that pinned the old
refusal. Brief mutants (talk sent as the human, follow without the thread filter) are killed.
Filbert approved round 1 in #1682 comment 29396 with no findings or notes. Their run on 3da362982,
with row 182 in the broker, added one more mutant (no thread read before the first receive in
follow), and it was killed.
Sweeps lines the seats appended but didn't commit: Darkwing's SESSIONS lines for rows 180, 181
and 182, and Rocko's SESSIONS and BUILD-LOG lines for rows 138, 164, 171, 176 and 178. Additions
only, as the seats wrote them. No existing line changes.
#threadFor puts a message to a threaded instance in the thread found up its in_reply_to chain. It
checked the thread's instance but not its owner, so a tester reply to a message in a human's thread
landed in the human's thread. A new #testerOwns check refuses thread-not-owned when the sender is the
tester and the thread's owner isn't. It runs on both the thread branch and the row 143 spec-notice
branch. A role's reply into a tester's thread is unchanged, since that's how the answer comes back.
The bus README says so in its row 177 paragraph.
tester-threads.test.mjs adds four T9 tests: a tester reply into the human's thread refuses and
stores nothing, one into its own thread lands, the chief's reply into a tester thread lands, and a
tester reply to a spec notice refuses while the chief's relay still lands. messaging.test.mjs:203
used to send as the tester into a human thread. It now sends from a tester-owned thread.
Filbert approved round 1 in #1680 comment 29388. Their notes N1 (thread-instance-mismatch is
checked first, as before) and N2 (BUILD.md missed project-runtime.test.mjs:13 as a text reader of
broker.mjs, now corrected) need no change.
webui serve takes --proof-header NAME --proof-file PATH, only with the --public-host preview flags.
Before listen it reads the file once through O_NOFOLLOW and fstat: a regular file owned by the
Console uid, mode 0400 or 0600, at least 32 base64url bytes with one optional final LF. Any file
problem gives one fixed refusal that names neither the path nor the contents. The header name can't
collide with Host, Origin, auth or tester names.
On a public Host the guard runs before any auth header is read. It needs exactly one proof header
and compares equal-length buffers with timingSafeEqual. Missing, wrong and repeated proofs get the
same fixed 401. A proof header on another Host or on the tester listener gets 403. The existing
auth, Origin, Fetch Metadata and human write checks are unchanged.
webui-service.sh renders both flags and checks the file's metadata and canonical location without
opening it, and the send-status regex accepts the proof pair. stack-release.sh only gains a comment:
it already carries Console flags through re-pin and rollback, and new tests pin that.
This is a partial fix. Same-uid seats can still read the proof file. Activation (middleware, unit
flags, restart, smoke) is a separate Mos-checked window and isn't part of this commit.
Dewey approved round 2 in #1676 comment 29386, candidate 9300a670. Round 1 changes were in 29374.
The chat.mjs header comment now says the seam takes the bus transport it is given: the human one
from the signed-in listener, the tester one from the row 176 listener (row 177). The TypeError for a
missing or non-function call says 'chat needs a bus transport function' and no longer says human.
No behavior changes. The webui README doesn't repeat either phrase and is unchanged.
A new chat.test.mjs test passes undefined, null, a string, a number, an object, an array and no call,
and reads the new TypeError text. Putting the old text back fails it.
Dewey approved round 1 in #1681 comment 29376. Their notes (the tester line names no file, and the
test title says both transports pass when only a stand-in function does) need no change.
COUNTED, next to STORE_JS, lists the 11 tables a bus writer fills without an event in the same
transaction (role_claims through usage_records, in schema order). STORE_JS count and heldcount
return events after STAMP plus each listed table after STAMP from the same open as before. A
listed table the store lacks counts 0, and one that exists but can't be read refuses
restore-mismatch.
rollback --restore refuses post-backup-events unless the total is 0 or --events equals it, and
the message names each table with rows. The in-run recount compares the same total. An
events-only store prints the old text. T46 reads every table in schema.sql and fails on a table
in no list or in two.
Filbert approved round 1 in #1679 comment 29372. Follow-ups F1 (task_comment_cursors) and F2
(the refusal text at stack-release.sh:909) are recorded in agents/darkwing/work/queue-181/BUILD.md.
next_activation() takes the UTC second once and tries the base id, then -1 through -9, against
stack-rollback/, backups/stack/ and the post-attempt store, all under the lock. ACT and POST share
the suffix, and with all ten taken it refuses capture-failed with nothing stopped. Adopt uses the
same helper. --restore takes the old and the suffixed form.
Under --plan, a bad --tester-port reports tester-port-invalid through check_refuse and
tester-port-target goes through check_refuse in both modes, so the plan lists every refusal.
Without --plan the output is the usage block, byte for byte as before. webui-service.sh counts the
tester port's digits as written before stripping zeros, so 007333 refuses as serve does.
Round 2 adds subtests C1 (adopt takes the next free id) and C2 (a bad port is usage before any
pointer read) for Dewey's round 1 (#1678 comment 29352). Dewey approved round 2 in comment 29361.
The tester gets threads of its own: thread.create, thread.open, thread.send, thread.messages and
assistant.stop join TESTER_VERBS, with owner `tester`, and neither the tester nor the human reaches
or lists the other's threads. A tester thread.send is from tester-cli with no human.input; in a
tester thread the lists read the tester as the human, the run answers at `tester`, and its send to
`human` refuses tester-thread-human. The tester stop revokes only tester threads, by `tester`. A
business whose human is `tester` refuses invalid-business at start.
The tester listener (7333) serves chat through the TESTER_CLI caller, its fence admitting only the
four chat write routes, with the listener's own Origin required; 7332's chat is unchanged. The
Console composer is enabled for the tester. READMEs state calls (a)-(c), N1, N2 and where a tester
reads replies (sage-1148).
Design 99ce5780 approved in sage-1146 (#1675 comment 29333).
Evidence for the STATE report Sage checked and filed in 88f3253d9 (sage-1151). The skills-enabled
tar stays out of git; it is the W0b restore point under $WIN only. No credential or Environment
values: unit reads record ExecStart only, and the P3 credential files were fake placeholders.
serve --tester-port N starts a second listener on 127.0.0.1:N in the same
process, with a bus caller through TESTER_CLI. N is 1024..65535, not
--port and never 7332, and the flag needs the bus configured. The tester
listener takes only instances.set, routes.set and name.set; settings
save, project-file save, assistant stop, bus message and chat writes
refuse 403 with no bus call. It refuses the main listener's auth header,
and every other listener refuses any request carrying x-mosaic-tester.
/api/config answers tester: true and the page shows a tester banner with
the routes, instances and seat name editors only. tester-off and
tester-required map to 403 in a serve.mjs coreBusStatus wrapper, so
bus.mjs stays pinned (row 164).
The broker lets a tester read credentials (with #secretCheck), routes,
project.files and project.file; project.file.save stays human-only.
webui-service.sh takes --tester-port with serve's checks. stack-release
activate --tester-port N writes the flag to the pointer and the unit,
refuses tester-port-target when the target copy's Console lacks it, and
activate or rollback to such a copy drops the flag and says so in --plan.
docs/TOOLS.md rewords the stale row 175 two-phase step (#1673 F1).
Built by Rocko on 473258a51 (manifest a4c728fc...52c9), approved by Dewey
in round 2 (#1674 comment 29322) after round 1 changes (29309), Sage's
gate green on 473258a51 plus the patch in run 2. Run 1 failed T34's
failed-pm_launched subtest with capture-failed: activate and pm-on name
the activation by the second, so the two ran in one second and collided
on the rollback set. That race is row 169's (the base fails the same way
with the id pinned), and a follow-up row fixes it (Vikunja P19 391).