feat(coord): announce across accounts, not just the local CCD instance - #1149
wshallwshall wants to merge 1 commit into
Conversation
announce-session.ps1 could only reach peers the model's ccd_session_mgmt send_message tool can address, which is one login and one surface. Measured on this repo 2026-09-14: 10 live peers, 3 reachable, list_sessions returning exactly the 3 on this login, so 7 sessions learned nothing. mail.ps1 was built for exactly those two cases and names them both in its own header, and this hook contained zero references to it. Section 16b mails the unreachable half directly, and runs BEFORE the NO_PEERS exit so an all-cross-login fleet is not silent: the new-peer set is computed from messageable peers alone, so that exit would otherwise fire having announced nothing. Coverage goes from 3 of 10 to 10 of 10. - Shells out to mail.ps1 rather than writing the inbox file. mail.ps1:324 says its caps are advisory because anyone who can write the file never runs that code, and the enforcing copy in mail-drain.ps1:216-236 TRUNCATES where mail.ps1 REFUSES. Bypassing the sender trades a visible refusal for a silent mid-sentence cut at the far end. - Wraps the body to 90 columns and hard-cuts unbreakable tokens. The receiver refuses any line over 240 chars, and an ordinary 370-char intent line was measured refusing all 7 of a peer's sends. Word wrapping alone is not enough: one long path or branch name breaches the cap by itself. - Intent comes from the claim note, never from the user's prompt. The hook has the prompt in its payload; delivery copies a body into a peer transcript that nothing here can delete, and mail.ps1 forbids message content outright. No note is reported as NOT DECLARED rather than filled in from the worktree name. - Three bounds: 3 sends per prompt, 12 per session, 6000 ms of wall clock. Only the clock survives disk contention from several sessions draining one directory; a count cap cannot bound time. UserPromptSubmit has a 15 s timeout and its failure mode is a blocked user prompt, not degraded coordination. One send costs 0.76-1.32 s, mean 0.98 over three timed spawns. - 120-minute TTL, not mail.ps1's 4320-minute default. A stale announce is worth nothing and would hold a drain slot for three days against a 5-per-injection cap. - Unattended peers are excluded. Their filter is flagged UNEXERCISED at the top of the hook, and mail's own staleness argument cuts against waking a scheduled run with an announce it cannot act on. Adds -AsLogin so a hand-run can exercise the login filter. Without it -SelfTest cannot resolve its own login, so the filter goes off and the diagnostic reports an upper bound as a measurement: the same live roster read reachable=9 without it and reachable=3 with it, and only the second matches list_sessions. Receipts go to v=2 and carry a mail= field beside msg=, so a reader can tell a v1 receipt's absent mail count from a v2 receipt's zero. New outcome code ANNOUNCED_MAIL covers a successful cross-account announce with no messageable peer in the fleet, which a bare NO_PEERS reported as nothing happening. 14 tests drive the lane through an injected stub, and they exist because the suite went green without them. $MailScript defaults to the real mail.ps1, which refuses the fixtures' fake D:\t\... recipient paths, so every send failed, every mailable peer fell back to SKIP, and the existing SKIP assertions kept passing while the new feature did nothing at all. Two of the new tests form a controlled pair on one peer, differing only in the mail script, and the verb flips MAILED against SKIP. Verified: 82 passed (test_announce_hook.py + test_announce_wiring.py), ruff check and format clean, hook source still ASCII-only. windows-service-smoke and the rest of CI run only on a hosted runner and have not been read.
|
LANDER review: BLOCKING on one line, and I am deliberately escalating it above the severity my reviewer gave it. Read against head 155cf1e. THE GUARD BETWEEN A USER PROMPT AND AN UNDELETABLE TRANSCRIPT PASSES WHEN NOTHING WAS SENT. If the stub log does not exist, WHY I AM RAISING IT FROM A NOTE. Its own docstring states the stakes better than I can: "mail.ps1's header forbids message content in a body, and delivery copies the body into the recipient's transcript, which nothing in this repo can delete. The hook HAS the prompt in its payload and must never mail it." Three properties compound here and any one alone would only be a note: The failure is IRREVERSIBLE. A prompt that reaches a peer's transcript cannot be recalled by anything in this repository. The payload is arbitrary user text, which in this product routinely includes pasted HL7. That makes it a PHI path, not merely a privacy one. And this is the ONLY guard. Nothing else in the suite stands between the payload and the wire. A vacuous assertion on a reversible property is a note. A vacuous assertion that is the sole control on an irreversible PHI path is the control failing silently, which is the defect this repository has spent the night finding in other people's code. THE FIX IS ONE LINE, asserting the instrument fired before asserting what it saw: That makes a hook that mails nothing fail the test loudly instead of passing it quietly, and costs nothing when the hook is working. THE REST OF THE DIFF IS SOUND AND I WANT TO BE CLEAR ABOUT THAT. The second delivery lane is well built: it runs before the NO_PEERS exit so an all-cross-login fleet is no longer silent, bounds the fan-out three ways, versions the receipt, and marks mailed peers in the roster. Two larger concerns were raised against it -- that a queue accept is recorded as delivery, and that a dead mail lane is indistinguishable on stdout from a healthy one -- and BOTH were refuted 3 of 3 on adversarial verification. I am recording them as considered and dismissed so they are not rediscovered as new. THREE NOTES, none blocking: The
docs/WORKTREES.md:938 says the receiver refuses lines over 240 characters; the receiver truncates and the SENDER refuses. Line 936 states it correctly, so the section contradicts itself. Lift the block on the one-line test fix and this is a merge. |
What was wrong
announce-session.ps1could only reach peers the model'sccd_session_mgmt send_messagetool can address, which is one login and one surface. Everything else rendered asSKIPand got nothing.Measured on this repo 2026-09-14:
list_sessionsreturned exactly these)scripts/coord/mail.ps1was built for exactly those two cases and names them both in its own header. The hook contained zero references to it. The two components shipped separately and were never wired.What this does
Section 16b mails the unreachable half directly, so coverage goes from 3 of 10 to 10 of 10. The split is by what each lane can reach: a prompt for peers the model can address, an action for peers it cannot, because no instruction can conjure a session id outside the caller's namespace.
It runs before the
NO_PEERSexit. The new-peer set is computed from messageable peers alone, so an all-cross-login fleet would otherwise take that exit having announced nothing.Design points, each paid for by a measurement:
mail.ps1, never writes the inbox file.mail.ps1:324says its caps are advisory because anyone who can write the file never runs that code; the enforcing copy atmail-drain.ps1:216-236truncates wheremail.ps1refuses. Bypassing the sender trades a visible refusal for a silent mid-sentence cut.mail.ps1forbids message content outright.UserPromptSubmithas a 15 s timeout and its failure mode is a blocked user prompt. One send costs 0.76-1.32 s, mean 0.98 over three timed spawns, and the peer lookup has already spent ~1.0 s.-AsLoginis added so a hand-run can exercise the login filter. Without it-SelfTestcannot resolve its own login, the filter goes off, and it reports an upper bound as a measurement: the same live roster readreachable=9without it andreachable=3with it.Why the tests are the interesting part
The suite went green without them.
$MailScriptdefaults to the realmail.ps1, which refuses the fixtures' fakeD:\t\...recipients, so every send failed, every mailable peer fell back toSKIP, and the existingSKIPassertions kept passing while the feature did nothing at all.14 tests now drive the lane through an injected stub. Two form a controlled pair on one peer, differing only in the mail script, and the verb flips
MAILEDagainstSKIP— so a green result discriminates a working lane from an inert one.Checks
pytest tests/test_announce_hook.py tests/test_announce_wiring.pyruff check/ruff formatmypymessagefoundry/changedCI has since been read, and this paragraph originally named the wrong leg. Corrected here rather than in a comment, so the retraction sits at the claim.
windows service smokeis skipped for this change by thedetect server-DB + docker changespath filter. It was never going to produce a result, because nothing here touches server, DB, or docker paths. Naming it as a leg to read was wrong.repo harness tests (windows-2025).tests/test_announce_hook.pyis intests/tooling_manifest.txt, and thetestlegs deselect that tier with-m 'not tooling'. Result: 3225 passed, 17 skipped, 8 xfailed in 933 s, and the tier's own "Prove the tier actually ran" step reportedtooling tests EXECUTED: 3225.tests/test_announce_hook.py::tests, so the module was not skipped by itspwsh/os.namegate. That gate is module-level, so the 14 new tests ran under it and the leg is green.PR state at head
155cf1eb4:mergeable=MERGEABLE,mergeStateStatus=CLEAN, 7 workflow runs success and 1 correctly skipped.One operational note
The installed shim resolves the hook from the git common dir's parent first and breaks on that hit, so every session in every worktree runs the primary checkout's copy. Nothing picks this up from a branch, which is correct but means the only real-fleet test is post-merge.