Merge pull request 'Design 59: no grant split (ADR 0472), and milestone 2's issues as split at its prepare step' (#446) from design-59-no-grant-split into main

This commit was merged in pull request #446.
This commit is contained in:
2026-10-20 21:43:16 +00:00
2 changed files with 33 additions and 30 deletions
+3 -3
View File
@@ -779,7 +779,7 @@ operator granted, note each mail for the operator and tell them of the mail that
the operator's Approve. **Recorded by** `mesh-mail` (its index database and attachment bucket, ADR 0359 §3; its
account buckets, ADR 0439) and `mesh-mail-reader` (its database of mail entries, mail groups and reading lessons,
ADR 0459). **Downstream of** Identity and access and Operator and conversation; **upstream of** nothing.
**Decided by** ADR 0359, 0361, 0378, 0439, 0440, 0458, 0459, 0460, 0461, 0462.
**Decided by** ADR 0359, 0361, 0378, 0439, 0440, 0458, 0459, 0461, 0462, 0472.
**Uses:** operator, person, module, seat; grant, identity (Identity and access); ask, warrant, operator channel,
content rule, untrusted input (Operator and conversation). A *judgement* is one call of the model with no tools
and no session (ADR 0278), in its plain sense.
@@ -791,8 +791,8 @@ and no session (ADR 0278), in its plain sense.
- **mail event** — what `mesh-mail` publishes on its stream `MAIL` for a new, changed or removed mail: headers,
flags and attachment references, never a body (ADR 0359 §2).
- **mail send** — a mail the mesh sends, which goes out only on the operator's warrant for that one mail (ADR 0361
§2), with the states `mail_send_status` answers (ADR 0440 §7). Only a caller granted asking to send for that
account may ask for one (ADR 0460).
§2), with the states `mail_send_status` answers (ADR 0440 §7). Any caller `mesh-mail`'s `grants` names for that
account may ask for one (ADR 0472).
- **mail web client** — the module `mesh-mail-web`, holder of `mail-webclient`: the operator's mail in a browser on
the private network (ADR 0440 §1). The page it serves is the mail page.
- **mail notice** — `mesh-mail-notifier`'s desktop pop-up for a new inbox mail (ADR 0378 §7, §9). It retires when
+30 -27
View File
@@ -16,7 +16,7 @@ decisions:
- "ADR 0436"
- "ADR 0458"
- "ADR 0459"
- "ADR 0460"
- "ADR 0472"
- "ADR 0461"
- "ADR 0462"
- "ADR 0278"
@@ -35,7 +35,7 @@ operator's Approve, as every mail the mesh sends does.**
`mail-reading`: it reads each new mail in batches, keeps a mail entry for it (its mail group, one line, its mark),
tells the operator on Telegram of the mail that matters in a mail signal, shows a scam warning on the page only, and
learns from the operator's corrections as reading lessons; it never changes the mailbox and keeps no mail text.
Reading and asking to send are granted apart first, and the pop-up for every new mail retires once mail signals
The pop-up for every new mail retires once mail signals
work. Later, once the mesh's threads exist, the operator asks questions about their mail in a mail conversation, a
thread with a mail context. Betterbird is removed once mail reading works on the laptop and the workstation.
(Research 066; ADR 0458 to 0462. The words are the glossary's Mail domain.)
@@ -119,22 +119,21 @@ account through the page and get around `grants`.
- **The seat's verbs** (ADR 0378 §5): `open` answers the page's address, and with an account and a mail that mail's
page; `status` answers whether it serves and which accounts it is granted.
## 5. Reading and asking to send, granted apart (ADR 0460)
## 5. One list per account, reading and asking to send alike (ADR 0472)
`mesh-mail`'s trusted setting `grants` gives a caller, per account, **reading** (that account's `MAIL` events,
`mail_accounts`, `mail_search`, `mail_read`) and **asking to send** (`mail_send`, `mail_send_status`), each on its own,
set as `grants` is today. A caller granted reading only is refused by both send tools, with the missing grant named;
one granted asking to send only is refused every read. When the split is delivered every caller in today's `grants`
keeps both for each account it has, so nothing stops; narrowing one afterwards is the operator's choice.
`mesh-mail-reader` is granted reading only, for every account, and nothing before the split is delivered. This is
issue 1227.
`mesh-mail`'s trusted setting `grants` stays one list of callers per account, giving both reading (that account's
`MAIL` events, `mail_accounts`, `mail_search`, `mail_read`) and asking to send (`mail_send`, `mail_send_status`):
the operator's Approve on every send is the guard (ADR 0472 §1, §2, which supersedes ADR 0460's split; issue 1227
will not be done). `mesh-mail-reader` is named in `grants` for every account after its delivery, on the operator's
Approve, and asks to send nothing: its manifest invokes no send verb (ADR 0472 §3). Who may call `mail-reading`'s
own verbs is its own trusted setting `callers`, `mesh-mail-web` by default (ADR 0459 §2).
## 6. Mail reading (ADR 0459)
```
mail-store (mesh-mail) ── MAIL: mail.<account>.message.added ──▶ mesh-mail-reader (seat mail-reading, once for the mesh)
▲ │ its own database: mail entries, mail groups,
└──────────── mail_read (reading grant only) ─────────────┤ reading lessons; never a body
└──────────── mail_read (named in grants) ────────────────┤ reading lessons; never a body
│ batches of ≤ 10 mails ──▶ claude_code_judge (within ≤ 40 s)
│ claude_code_judged
├──▶ operator-channel.tell (a mail signal, §7)
@@ -197,8 +196,8 @@ mail-store (mesh-mail) ── MAIL: mail.<account>.message.added ──▶ mesh-
## 8. The mail conversation (ADR 0462)
A mail conversation is a thread (ADR 0383), run by the thread handler (ADR 0384), with a mail context: the framing
that a mail is data, the tools `mail_search` and `mail_read` only under a caller of the thread's own granted reading
only (issue 1419), the operator's real senders and folder names, and the reading lessons. The operator writes a mail
that a mail is data, the tools `mail_search` and `mail_read` only, under a caller of the thread's own named in `grants`
(ADR 0472 §4; issue 1419), the operator's real senders and folder names, and the reading lessons. The operator writes a mail
question on the mail page; each answer names the mails it found, and a question with no answer says so.
`mesh-mail-web` creates and follows the thread over the bus on its server side; the page loads one script from its
own origin and talks only to it (content security policy: script from that origin, `connect-src 'self'`), so the
@@ -242,7 +241,7 @@ Tests 1 to 9 are milestone 1's; tests 10 to 17 are research 066's eight, in its
10. A new mail on each account has a mail entry, in a mail group, within 5 minutes of its mail event; a test searches
`mesh-mail-reader`'s database for a known body line and finds none.
11. The reader's caller is refused by `mail_send` for every account, and no mail is moved, flagged or deleted by it.
11. The reader asks no `mail_send` for any account, and no mail is moved, flagged or deleted by it.
12. (Milestone 4.) On the mail page, a mail question by a person, by a time range and by "what needs a reply" finds
its target mails, research 066's three failed kinds included; a question with no answer says so; the conversation
is a thread readable through the thread seat; and the browser makes no request but to the mail page's own origin.
@@ -263,8 +262,8 @@ Tests 1 to 4 are one integration test that starts the module whole against the r
tests 5 and 7 are `mesh-mail`'s own and test 8 `mesh-mail-web`'s, unit tests; test 6 is read before the module is
assigned; test 9 is proven live after the delivery.
Tests 11, 13 (with a stand-in router), 16 and the grant split's refusals are one integration test that starts
`mesh-mail` and `mesh-mail-reader` whole against the real bus and store; the batch's budget, the seat's verbs and the
Tests 10's and 11's checks, 13 (with a stand-in router) and 16 are integration tests that start
`mesh-mail-reader` whole against the real bus and store, with stand-ins for the seats it asks (issues 1431, 1524); the batch's budget, the seat's verbs and the
mail signal's words are unit tests; tests 10, 13, 14, 15 and 17 are proven live after milestone 2's delivery, test 13
before `mesh-mail-notifier` is unassigned; test 12 with milestone 4.
@@ -273,9 +272,9 @@ before `mesh-mail-notifier` is unassigned; test 12 with milestone 4.
| # | Outcome, in one sentence | Proves | Repositories and their parts | Depends on |
|---|---|---|---|---|
| 1 | In a browser on the laptop and the workstation, the operator signs in and browses, searches and reads every account's mail with its attachments, and writes a mail that goes out on their Approve | tests 1 to 9 | mesh-catalog: `mesh-mail`'s account bucket (issue 1255, ADR 0439 §2); the module `mesh-mail-web` (manifest, sign-in, the pages, the send, the seat's verbs, the integration test) | — |
| 2 | Each new mail is read into a mail group on the mail page; the mail that matters reaches the operator's phone as one mail signal, a scam warning shows on the page only, the operator's corrections become reading lessons, and the pop-up for every new mail is gone | tests 10, 11, 13 to 17 | mesh-catalog: `mesh-mail`'s grants split (issue 1227) and the seat `mail-reading` declared; the module `mesh-mail-reader` (batches, mail entries, reading lessons, mail signals, health, the integration test); `mesh-mail-web`'s mail groups, mail signals, scam warnings and reading lessons; `mesh-mail-notifier` unassigned (issue 1418) | 1 |
| 2 | Each new mail is read into a mail group on the mail page; the mail that matters reaches the operator's phone as one mail signal, a scam warning shows on the page only, the operator's corrections become reading lessons, and the pop-up for every new mail is gone | tests 10, 11, 13 to 17 | mesh-catalog: the seat `mail-reading` declared in `mesh-mail`'s manifest; the module `mesh-mail-reader` (batches, mail entries, reading lessons, mail signals, health, the integration test); `mesh-mail-web`'s mail groups, mail signals, scam warnings and reading lessons; `mesh-mail-notifier` unassigned (issue 1418) | 1 |
| 3 | Betterbird is gone from the laptop and the workstation, its profile and mail kept in the home | ADR 0379 §2 | mesh-catalog: Betterbird unassigned on the operator's Approve, then the `betterbird` module removed from the catalogue (issue 806) | 2 |
| 4 | On the mail page the operator asks questions about their mail and gets the mails that answer them, in a mail conversation kept as a thread | test 12 | mesh-catalog: `mesh-mail-web`'s mail conversation as a client of the thread seat; the thread's mail tools under a caller of their own granted reading only (issue 1419); `mesh-mail`'s folder case and `-any` switches | 2 (the grant split and the reading lessons); design 58's milestone 3 (issue 880) |
| 4 | On the mail page the operator asks questions about their mail and gets the mails that answer them, in a mail conversation kept as a thread | test 12 | mesh-catalog: `mesh-mail-web`'s mail conversation as a client of the thread seat; the thread's mail tools under a caller of their own (issue 1419); `mesh-mail`'s folder case and `-any` switches | 2 (the reading lessons); design 58's milestone 3 (issue 880) |
**Milestone 1, confirmed by the operator on 2026-10-19, is delivered;** its live proof on the laptop and the
workstation (a search, an attachment, one send on the Approve) is still the operator's. Its issues, one repository
@@ -288,18 +287,22 @@ the operator's Approve: `mesh-mail-web`'s `reach` on its machine (`internal`), i
**Milestones 2 to 4, confirmed by the operator on 2026-10-20.** Their issues, one repository part each, in their
order (each depends on the one before unless said):
- Milestone 2: 1227 (`mesh-mail`'s grants split), 1426 (the seat `mail-reading` and the module `mesh-mail-reader`),
1427 (batches, mail entries and mail groups), 1428 (reading lessons and the seat's verbs; with 1427 after 1426),
1429 (mail signals; after 1427), 1430 (the mail page; after 1428 and 1429), 1431 (the integration test; after
1430 and 1227), 1418 (`mesh-mail-notifier` unassigned; after 1431 and test 13 live).
- Milestone 2 (its order is said for each): 1426 (the seat `mail-reading` and the module `mesh-mail-reader`), 1517
(its database; after 1426), 1518 (hearing new mail, catching up in arrival order; after 1517), 1519 (its health;
after 1517), 1427 (a batch's question within its bounds; after 1426), 1520 (running batches; after 1427, 1518 and
1519), 1521 (the verbs `entries`, `groups`, `status`; after 1520), 1428 (`correct`, `lessons`, `undo`; after 1521),
1429 (a mail signal's words; after 1427), 1522 (sending it; after 1429 and 1520), 1430 (what the mail page shows;
after 1428, 1521 and 1522), 1523 (corrections and reading lessons on the page; after 1430 and 1428), 1431 (the
reader's integration test; after 1430 and 1522), 1524 (the integration test of failing loudly; after 1431 and
1523), 1418 (`mesh-mail-notifier` unassigned; after 1524, the delivery and test 13 live). Issues 1517 to 1524 were
split from 1426 to 1431 at the prepare step; issue 1227 (the grants split) will not be done (ADR 0472).
- Milestone 3: 806 (Betterbird removed; after 1418).
- Milestone 4: 1433 (`mail_search`'s folder case and `-any` switches; depends on none), 1419 (the thread's
reading-only caller; a decision first, after 1227 and design 58's milestone 3, issue 880), 1432 (the mail conversation;
caller; a decision first, after design 58's milestone 3, issue 880), 1432 (the mail conversation;
after 1431, 1419 and issue 880).
Milestone 2 is one release of `mesh-catalog`: the grant split, the new seat, the new
module and the page change ship together, and `mesh-mail-reader` is granted reading only after that delivery, on the
operator's Approve; `mesh-mail-notifier` is unassigned only after test 13 passes live. Milestone 3 is issue 806.
Milestone 2 is one release of `mesh-catalog`: the new seat, the new module and the page change ship together, and
`mesh-mail-reader` is named in `grants` after that delivery, on the operator's Approve; `mesh-mail-notifier` is unassigned only after test 13 passes live. Milestone 3 is issue 806.
ADR 0379 §2's bar for removing Betterbird is milestone 1's; keeping Betterbird until mail reading (milestone 2) works,
and not until the mail conversation, is the lead's proposal, for the operator to confirm with the milestones
(playbook 04, step 5). Milestone 4 waits for threads and for the decision that names its thread's reading-only caller (issue 1419, which needs a decision first).
(playbook 04, step 5). Milestone 4 waits for threads and for the decision that names its thread's caller (issue 1419, which needs a decision first).