roadmap: decisions of 2026-10-13 on the candidates
test / test (push) Canceled after 0s

Agreed with the owner, one question at a time; documents only, no code.

- csrf-tokens -> origin-strict (agreed): no tokens, the origin check
  refuses a request with neither header. security.md's ADR records the
  decision and when tokens are built after all.
- structured-logging, contributing: dropped, each with what brings it
  back (new roadmap section "Dropped, with the condition for return").
- template-data-typing: done by 2.0.0; its last map (healthChecks) is a
  step of the audit's stage 4.
- preflight -> health-setup-checks (certificate name, Postfix's greeting,
  trusted proxy as lines on Health) and test-email, both agreed. The port
  check is dropped with its reason; plans/preflight.md removed.
- password-reset: agreed; a reset link goes only to a confirmed e-mail,
  so the item builds confirmation first.
- phone-desktop-mode: agreed, after stages 1 and 2 of the audit.
- backup-reauth (agreed): the account password before a backup or a
  domain export, out of review-2026-08-followups.
- from-header-binding, Not done: the Delivery log box is required on a
  refused message's page, with the line Postfix wrote, for all three
  kinds of refusal (audit stage 1); the Outbound log gets a filter by
  status and by day (audit stage 4).

The audit's checklist is 48 lines (was 45).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
mix
2026-10-13 19:13:04 +03:00
co-authored by Claude Opus 5.5
parent b9353db507
commit c3d99b1f15
5 changed files with 233 additions and 195 deletions
+40 -2
View File
@@ -597,6 +597,25 @@ has already run is never edited — the next file is added; the published
grown for a tick and the new file has a line). Both are fixes to the
tailer's blindness and stay on the list whatever the sweep's fate; their
priority follows `tailer_blind_seconds`.
- [ ] **A refused message's page shows what Postfix wrote** (owner,
2026-10-13: "the log box is required" - the box is the reason
delivery-log-storage was built, and its absence from the picture he
approved for 2.4.0 was an oversight, not a decision). Today every
`rejected` row - `wrong From`, `wrong client`, `rate-limited` - has no
queue id, and its page shows the box with one sentence,
"This message never reached the queue, so Postfix wrote no delivery lines
for it" ([handlers_monitor.go](../internal/web/handlers/handlers_monitor.go)).
The sentence is untrue: Postfix wrote a line for each (`milter-reject:
END-OF-MESSAGE ... 5.7.1 From: ...` from cleanup, `NOQUEUE: reject: ...`
from smtpd). The tailer attaches that line to the row it belongs to, by
client address, time and the addresses in the line, and stores it in
`send_log_lines` like any other; the page shows it. First on the stand:
read `mail.log` for the three kinds of refusal and write down what
identifies each line. Then the mockup: the refused variant of `out-message`
gets the box with the line in it (`design:` commit), then the code. The
sentence stays only for a row whose line was truly never written or is
older than this change, and says that. Done when the e2e shows the stored
line on the page of each of the three refusals. - **Opus**
- [ ] **Anchor `deliveryRe`** at the head of the line like its two siblings;
test with the probed HELO and quoted-sender lines. — **Opus**
- [ ] **TLS re-copy** (H2): `postfix-cert-reload.sh` compares the mounted files
@@ -689,6 +708,24 @@ has already run is never edited — the next file is added; the published
the flash and the two comments say what it covers. — **Sonnet**
- [ ] `domain.Service.Delete`: say the domain is deleted when a later step fails,
and run `apps.Resync()` anyway. — **Opus**
- [ ] **A status filter and a day filter in the Outbound log** (owner, 2026-10-13, from the
Not done list of from-header-binding). The mockup `out-log` has drawn a
third list since the redesign and the built log never had it; the Inbound
log has its counterpart built (domain, decision, day). One list: *Any
status*, `queued`, `sent`, `deferred`, `bounced`, `rejected` - the statuses
of a row, and `rejected` shows all three kinds of refusal together. He was
shown the list with the refusals split by reason and chose it without the
split. The mockup's own list is wrong (it offers `rate-limited`, which is
a reason, and lacks `queued` and `rejected`): correct it first (`design:`
commit). And a filter by day, as the Inbound log has it (owner, the same
day): the same control, drawn in the mockup first. Both filters survive
paging and the rows' polling. - **Sonnet**
- [ ] **The last untyped page data** (owner, 2026-10-13): `healthChecks`
([handlers_status.go](../internal/web/handlers/handlers_status.go)) returns
a struct instead of `map[string]any`, so a mistyped key in `healthPage` /
`healthCards` is a compile error and not an empty card on Server › Health.
No template change. This closes what is left of the roadmap's former
`template-data-typing`. — **Sonnet**
- [ ] **Upstream TLS mode validated at save** (L5): saving an inbound domain
whose `[host]:port` is already used by another domain with a different
TLS mode is refused with the validator's text naming that domain and its
@@ -727,8 +764,9 @@ has already run is never edited — the next file is added; the published
### Stage 6 — documentation and roadmap sweep (no product code, no cut)
- [ ] Every item under *Doc drift* above, file by file. — **Sonnet**
- [ ] roadmap.md: strike `template-data-typing` (done by 2.0; one sampler map
left, typed before render); reword `structured-logging`; in
- [ ] roadmap.md: `template-data-typing` is struck already (owner, 2026-10-13;
its last map is a step of stage 4); `structured-logging` is dropped (owner,
2026-10-13, roadmap § Dropped) - nothing to reword; in
`review-2026-08-followups` mark `parsePage` and `secretfile` rows as
addressed by stages 3-4, keep the `offset.go` inode row (still open:
fingerprint of the first 512 bytes only), and the `dnscheck` fan-out row