Add a shared `svc/spam` service Issue open
Keymail accepts authenticated first-contact email into its Screener, where the mailbox owner chooses Let in or Block. Obvious bulk spam can still fill that view. Keymail needs a spam score so it can separate ordinary first contacts from Likely spam without rejecting mail.
Proposed service
Add a synchronous svc/spam service backed initially by Rspamd. It accepts a bounded raw RFC 822 email and returns a versioned response:
{
"score": 8.4,
"threshold": 6.0,
"disposition": "likely_spam",
"signals": [
{"name": "bulk_sender_pattern", "score": 2.1},
{"name": "suspicious_links", "score": 1.7}
],
"engine_version": "…",
"ruleset_version": "…"
}The contract should define the message-size limit, score and threshold semantics, allowed dispositions, bounded signal list, response versions, and errors for invalid input, resource limits, timeouts, and service failure.
Platform fit
svc/spam is a seeing service: it processes plaintext and retains neither messages nor content-derived history. Start without Redis, a shared Bayesian corpus, scan histories containing message content, or automatic learning. Carlos should give it no database binding, bucket write access, or persistent volume.
This matches Carlos's platform-owned antivirus scanning and the shared seeing-service design. Calls carry tenant identity, and Carlos applies per-tenant rate limits, request-size limits, and strict timeouts.
Consumers declare the dependency as required or degradable. Keymail will use degradable:
- A successful scan routes the message to the ordinary Screener or Likely spam.
- A timeout or service failure routes it to the ordinary Screener.
- Scanner failure never rejects, delays, or loses mail.
Arbitrary app-declared sidecars are out of scope. If Carlos lacks generic support for service declarations, endpoint binding, tenant identity, limits, or isolated service canaries, include that platform work without assuming it already exists.
Deployment and testing
Deploy the service and Keymail consumer independently through isolated canaries. Do not experiment on the flagship.
Use public corpora of legitimate email and spam, plus adversarial fixtures. Contract tests should cover the response fields, absence of message retention, bounded memory and execution time, tenant isolation, per-tenant limits, and Keymail's behavior when the service is unavailable.
Acceptance checklist
- [ ]
svc/spamhas a documented, versioned request and response contract. - [ ] It accepts only bounded raw RFC 822 messages.
- [ ] Responses include the score, threshold, disposition, bounded signals, engine version, and ruleset version.
- [ ] Carlos supplies tenant identity and enforces rate, size, and time limits.
- [ ] The seeing service has no persistent storage.
- [ ] Keymail treats it as degradable and falls back to the ordinary Screener.
- [ ] Keymail can route successful high-scoring results to Likely spam.
- [ ] Service and consumer have independent isolated canaries.
- [ ] Contract and failure tests pass without manual testing on the flagship.
- [ ] Any missing generic
svc/*support is identified as platform implementation work.