Skip to content

docs(email-security): bulk remediation, verdict revisions, link detonation and a troubleshooting page - #383

Merged
maximelb merged 11 commits into
masterfrom
mailsec-w11-docs
Sep 7, 2026
Merged

docs(email-security): bulk remediation, verdict revisions, link detonation and a troubleshooting page#383
maximelb merged 11 commits into
masterfrom
mailsec-w11-docs

Conversation

@maximelb

@maximelb maximelb commented Sep 7, 2026

Copy link
Copy Markdown
Contributor

Why

The Email Security section was written ahead of several features and behind
others. This closes the remaining gaps identified in the pre-GA docs sweep, and
corrects three sections that had become wrong rather than merely incomplete.

Everything here was verified against current origin/master of the gateway, the
CLI/SDK, the extension, the hive definitions and the backend before it was
written — several claims that "looked right" turned out not to be, and are
called out below.

What is new

Page
remediation.md (new) Bulk remediation end to end: preview → confirm → execute → status, the real field names (confirm, action, msg_uuids, reason, state, items[].result, all seven counts keys), why the confirmation is a derivation rather than a nonce, interrupted as a terminal state versus the stalled flag, the CLI's two-step --confirm grammar, and the exit codes
troubleshooting.md (new) The entitlement gate, the entitlement block on coverage, the silent-mailbox stall, EMAIL_INGEST_ERROR, connection handover during a platform update, installation keys, and the 30-day deletion clock
policy.md New managed_rules section — the record, the console switch, the two extension actions, absent-means-enabled, and the propagation bound
detections.md New Revising a verdict and Link detonation sections
custom-rules.md scope versus the ? path wildcard, and the two backtest refusals
pipeline.md The latency section rewritten around the real processing_latency_p95
api-reference.md The six routes that were missing, plus an honest note on the three that are registered and not served
cli.md, messages.md, user-reports.md, index.md The new commands and cross-links

Corrections to things that were wrong

  • policy.md claimed submit_to_triage and crawl_link "validate but do not
    execute".
    Both are implemented now. They are documented as the two asking
    actions — they touch no mailbox and promote nothing to the retained lane — with
    the load-bearing warning that a trigger rule on submit_to_triage must
    filter on result: ok, because an alert_only organization emits the action
    as audit and a rule matching the action alone would start paid work for exactly
    the organizations that opted out.
  • pipeline.md said we do not publish a latency figure. We do:
    overview.processing_latency_p95 reports p50/p95/p99 with its basis, its
    denominator, and — when there is no number — which of two honest reasons
    applies. Backfilled and re-driven mail is excluded, so a recovery cannot report
    a latency measured in days.
  • policy.md documented hunt_defaults as if something read it. Nothing
    does. The record still validates and composes, the server-side hunt routes are
    registered and answer a refusal, and the console's Hunt screen is an LCQL search
    that does not read this record. Said plainly, with the explicit instruction not
    to treat its dry_run: true as a safety control over anything.

What was deliberately not written

  • No hunt page. The three /hunts routes are registered and not served. They
    are documented as unavailable, in one short section, rather than as a feature.
    The section also warns not to branch on the refusal: only the GET returns the
    typed not_implemented; the two POSTs currently fail differently.
  • No commercial trial terms. The trial clock and the mailbox ceiling exist in
    code and are reported through the entitlement block, but they ship inert and
    there is no announced Email Security pricing. The troubleshooting page therefore
    documents the mechanism and every field, and states that limits are reported
    before they are enforced — mailbox_cap_enforced is the field that says which
    you are looking at — rather than publishing a duration and a cap as a promise.
    Assumption stated for review: if the intent is to announce the trial terms
    publicly, that is a one-paragraph follow-up, not a rewrite.
  • The AI triage page was not changed. The ticket said the lc-ai
    mailsec-triage bundle did not exist and the docs link 404s. It does exist on
    master and the link resolves — the ticket (and my first check) were reading a
    stale clone. Verified against the live repository; the page's claims about the
    bundle's three trigger rules match what is checked in.

Verification

  • .venv/bin/mkdocs build --strict — clean
  • markdownlint-cli2 — 0 issues across 388 files
  • scripts/check-release-note-headings.py, scripts/check-release-feeds.py,
    scripts/check-list-numbering.py — clean
  • pytest tests/ — 210 passed
  • Every internal link and anchor in the whole docs tree checked against the
    built HTML
    — 0 broken. The new API sections are linked by their generated
    anchors, so a heading rename would fail this check rather than silently 404.

Release note added under 2026-09-07 in the versionless announcement form, as
### Extensions: …, matching how the tenant-purge entry did it.

🤖 Generated with Claude Code


Update: reconciled with #382, and an independent review

#382 landed the trial terms while this was open. This branch is merged with
it, and the overlap resolved in its favour: policy.md's deletion table and
notices section are master's, and the troubleshooting page now cross-links
[Plans, the free trial, and the mailbox cap] instead of hedging about whether
limits are enforced. The two pages no longer say different things.

Two links #382 introduced pointed at api-reference.md#get-coverage, an anchor
that does not exist — GET /coverage is a table row, not a heading. Fixed here,
because neither mkdocs build --strict nor the repo's check-links job
validates fragments.
This PR was checked with a per-anchor pass over the built
HTML instead; it also caught one of my own.

An independent reviewer read the whole diff against the backing repos and found
11 factual errors, all fixed
(commit 9e692a20). The two worth knowing about:

  • I wrote that reading and remediating still work while unsubscribed. They do
    not — mailsecGate runs the subscription check on every /v1/mailsec/*
    route including reads, so an unsubscribed organization gets 403 everywhere.
    That also made the page's own "run coverage and read gate_reason" advice
    unreachable. A lapsed trial is the case where reads do still work, and the
    page now distinguishes the two.
  • I wrote that rule validate checks a named lookup exists. It does not — the
    validate path passes no hive helpers, so the check runs on save only. That
    is the one exception to "valid here means savable there", and api-reference.md
    claimed that parity outright; both corrected.

The reviewer also caught the only internal detail that had leaked into this
public repo: a verbatim backtest-refusal quote naming a deployment component.
Paraphrased.

maximelb and others added 2 commits September 7, 2026 10:30
…reopen

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…wildcard and the release note

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@maximelb
maximelb marked this pull request as ready for review September 7, 2026 17:41
lcbill
lcbill previously approved these changes Sep 7, 2026
…propagation bound, safer installation-key advice

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
lcbill
lcbill previously approved these changes Sep 7, 2026
… path, in every list that enumerates them

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…tually co-occur on one link

is_ip and domain/root are mutually exclusive by construction, so the 'wrong'
example could never have matched a single link either — which made it a bad
demonstration of the trap it exists to show.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
lcbill
lcbill previously approved these changes Sep 7, 2026
…xt to the two that were listed

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
lcbill
lcbill previously approved these changes Sep 7, 2026
…ions

- troubleshooting: unsubscribing refuses the WHOLE API surface, reads included;
  the previous text claimed reading and remediating still work. A 403 on
  `coverage` is now called out as itself the answer.
- troubleshooting: `resolved: false` omits only plan/clock/cap, not every field;
  `gate_reason` is absent rather than empty; the trial note no longer asserts a
  posture that is per-deployment.
- custom-rules: `rule validate` does NOT check that a named lookup exists — that
  happens on save only. This is the one exception to validate/save parity, and
  api-reference now says so where it claimed parity outright. The verbatim
  refusal quote is paraphrased so it stops publishing a deployment detail.
- remediation: exit 0 is narrower than "something was acted on" — an all-skipped
  or all-alert_only batch exits 0. The SDK caveat is a version note, not a stale
  claim.
- policy: `banner_message` is a modification, not a placement change; only the
  extension stamps `lc:system`; the console replaces the switch with a badge
  rather than showing it read-only.
- detections: `disabled` is reserved and never stamped; the detonation block's
  `url` field was missing; omitempty means absent, not false; the mode
  allow-list also refuses an unknown prior mode.
- pipeline: `no_messages_emitted_in_window` also covers an all-backfill window.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
lcbill
lcbill previously approved these changes Sep 7, 2026
…overage is what 403s

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…annot read through the gated route

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
lcbill
lcbill previously approved these changes Sep 7, 2026
…phs above the box saying it may not

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
lcbill
lcbill previously approved these changes Sep 7, 2026
- policy.md: took master's 'It also happens without a request' table and its
  'You are told before it happens' section wholesale; they are strictly better
  than the version this branch had and cover cancellation non-interchangeability.
- policy.md: fixed two links to api-reference.md#get-coverage, an anchor that
  does not exist. They arrived on master with #382 and neither mkdocs --strict
  nor the repo's check-links job validates fragments.
- troubleshooting.md: dropped the hedge about trial limits now that the terms are
  published, and cross-linked the plans section instead. Added the three
  mailbox-cap fields the coverage layer adds on top of the entitlement RPC
  (mailboxes_active, mailboxes_over_cap, mailbox_cap_reached), and called out
  that a lapsed trial keeps the API while an unsubscribe does not.
@maximelb
maximelb merged commit b0343fa into master Sep 7, 2026
7 checks passed
@maximelb
maximelb deleted the mailsec-w11-docs branch September 7, 2026 18:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants