Skip to content

docs(email-security): all three hunt routes return the typed not_implemented refusal - #388

Open
maximelb wants to merge 2 commits into
masterfrom
mailsec-hunts-refusal-doc
Open

docs(email-security): all three hunt routes return the typed not_implemented refusal#388
maximelb wants to merge 2 commits into
masterfrom
mailsec-hunts-refusal-doc

Conversation

@maximelb

@maximelb maximelb commented Sep 8, 2026

Copy link
Copy Markdown
Contributor

Why

The "Registered, but not implemented yet" section of the Email Security API reference told readers, in bold, not to branch on the refusal — because only GET /hunts/{hunt_id} returned the typed not_implemented, and the two POSTs returned a plain routing error instead. That caveat was accurate when it was written and is the kind of thing docs should say.

The underlying defect is fixed: all three routes are now addressed to the backend that registers the typed refusal, so all three answer the same body. The caveat comes out, and is replaced by the thing it was standing in for — the payload, and the field to branch on.

What changed

One section of docs/email-security/api-reference.md:

  • The "do not branch on the refusal" paragraph is replaced by the refusal itself, shown as JSON exactly as the API returns it.
  • Says to match on data.error_code rather than on the message text, since the text is for a human reading a log and the code is the contract.
  • Keeps the retry: false point, with the reason (an unimplemented route does not become implemented inside a retry budget), because that is now true of all three rather than one.
  • Do not build against them yet stays. Nothing is served; only the shape of the refusal changed.

docs/email-security/policy.md already described the hunt routes as answering a typed not_implemented without the per-route caveat, so it needed no change and is now consistent rather than optimistic.

Verified

  • The JSON example is the live payload, captured against the API rather than written from the source.
  • Anchors in the touched section checked by hand: automation.md#querying-mail-with-lcql resolves to the ## Querying mail with LCQL heading; remediation.md exists. No links were added or moved.

Sequencing — DO NOT MERGE YET

This PR must not land until the gateway fix is in production, not merely merged. The site publishes on every push to master, so merging early makes a claim public that is not yet true for a caller hitting the live API. Until then the paragraph this replaces is the accurate one.

The gateway change is merged to its own master and rides the ordinary API release; this PR follows it.

(Noted here rather than left implicit because an earlier draft of this body said the opposite.)

…emented refusal

The hunt section told readers not to branch on the refusal, because only
GET /hunts/{hunt_id} returned the typed not_implemented and the two POSTs
returned a plain routing error. That is fixed: all three now answer the same
typed, non-retryable refusal.

Replaces the caveat with the payload itself and says to match on
data.error_code rather than on the message text, which is the branch the
section promises a client can write.
lcbill
lcbill previously approved these changes Sep 8, 2026
…ng sameness

Independent review findings:
- The refusal arrives as HTTP 400 and the section never said so, in a file that
  is otherwise precise about status codes.
- 'All three answer the same' was stronger than the truth: rpc differs per route
  and needs differs on the remediation route, which names the remediation
  executor too. The example is now labelled with the route that produced it and
  the varying fields are called out, so nobody wires a check on rpc or needs.
- 'no change on either side' overclaimed: the branch condition survives, the
  client still has to handle the success body when the engine lands.
- Dropped the 'tripled its load' multiplier, which came from a retry budget that
  is not the client's.
- Said plainly that the milestone identifier and the section reference are
  internal build-order labels, not a published schedule.
- Comma splice.
@maximelb

maximelb commented Sep 8, 2026

Copy link
Copy Markdown
Contributor Author

Independent review — addressed, plus a hold

An independent review of this diff raised one blocking item and five smaller ones. All are addressed in f5f1bb5, except the blocking one, which is a sequencing constraint rather than a text change:

Blocking — held. This site publishes on every push to master, and the gateway fix is not in production yet. Merging now would make the new statement public before it is true for a caller hitting the live API, which is the same failure the paragraph being deleted existed to prevent. This PR is not to be merged until the gateway change has shipped to production. The PR body's Sequencing section said otherwise and has been corrected.

Addressed in the diff:

  • Status code. The refusal arrives as 400 and the section never said so, in a file that is otherwise precise about status codes and that sets up the contrast two paragraphs earlier ("a refusal rather than a 404"). Now stated.
  • "All three answer the same" was stronger than the truth. Same shape and same error_code, but rpc differs per route and needs differs on the remediation route, which names the remediation executor as well. The example is now labelled with the route that produced it, and the varying fields are called out, so nobody wires a check on rpc or needs.
  • "with no change on either side" overclaimed. The branch condition survives; the client still has to handle a success body when the engine lands. Reworded to the claim that is true.
  • "tripled its load" used a retry count that is not the client's. Dropped the multiplier.
  • Internal identifiers. The milestone label and the section reference appear in the payload and cannot be scrubbed from an honest example, but the prose presented them as self-explanatory. It now says plainly that they are internal build-order identifiers, not a published schedule or a date commitment.
  • Comma splice.

Also confirmed by the review: the JSON example is byte-exact against the captured payload; the anchor in this section resolves to a real heading; the one other page mentioning these routes already agrees with the new text and needs no edit; and the diff introduces no name or reference that does not belong on a public site — it in fact removes one, since the deleted text explained the bug in terms of the internal backend topology.

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