Skip to content

Phase 3: human-in-the-loop at scale, secrets rotation, reputation monitoring#9

Merged
Aakash1337 merged 1 commit into
mainfrom
claude/relay-phase-3
Jul 5, 2026
Merged

Phase 3: human-in-the-loop at scale, secrets rotation, reputation monitoring#9
Aakash1337 merged 1 commit into
mainfrom
claude/relay-phase-3

Conversation

@Aakash1337

@Aakash1337 Aakash1337 commented Jul 5, 2026

Copy link
Copy Markdown
Owner

Why

Completes the code-buildable remainder of Phase 3 — Production Readiness (on the phase's own branch, per the new per-phase branching rule). With pacing/warmup and one-click unsubscribe already merged, the roadmap's remaining code items were: human-in-the-loop at scale, secrets rotation, and reputation monitoring. What code cannot close — production sending posture, legal/DPA documents, the human security review, and the three parked decisions — is now recorded explicitly in docs/phase3-readiness.md.

What changed

Human-in-the-loop at scale

  • Confidence-ordered review queue: /outreach-drafts/pending sorts by fit_score (highest first, FIFO within a score) and carries the score — the top of the queue is the batchable tail, the bottom is where reviewer attention belongs.
  • Batch review: POST /outreach-drafts/batch-review takes up to 100 rubric decisions per call through the same domain review path as the single endpoint. Each item runs in its own transaction, so one stale or bogus item fails alone while the rest land. Like every review surface, it never sends.
  • Edits-as-signal: the approved_with_edits share of window reviews is now a first-class edit_rate metric — the number that steers prompt iteration.

Secrets rotation

  • POST /internal/tenants/{id}/rotate-key (admin token): issues a new tenant API key, the old key dies the moment the rotation commits (rotation is for suspected exposure — a grace overlap would defeat the point), the action is audited, and the key is returned exactly once.
  • RELAY_MASTER_KEY_PREVIOUS: a verify-only rotation window for the master key. Unsubscribe tokens already sitting in delivered mail keep verifying across a rotation — a dead unsubscribe link is a compliance failure. New tokens always sign with the current key.

Reputation monitoring

  • Tenant metrics now include 24h suppressions-by-reason and reviews-by-decision, with derived bounce_rate, complaint_rate, and edit_rate — wired through /metrics JSON and the Prometheus export.
  • New bounce_rate_high critical alert (RELAY_ALERT_BOUNCE_RATE, default 5%) with a min-sends floor (RELAY_ALERT_BOUNCE_RATE_MIN_SENDS, default 5) so a 1-of-1 bounce never pages. It fires before the eligibility threshold silently pauses sending.

docs/phase3-readiness.md (new)

Maps each exit-gate concern to its mechanism and tests; lists the operator/legal deliverables code must not invent (production posture per the §6 revisit, region-specific lawful-basis rules pending the legal artifact, DPA/incident-response, KMS swap, human review); records the three parked decisions (email-hash pepper, global-suppression asymmetry, sequence_step generalization).

Tests (+7, suite now 299)

  • Batch review: item isolation (bogus id fails alone), terminal lead states, sent: false.
  • Queue confidence ordering with scores in the payload.
  • Key rotation: old key 401s immediately, new key works; 422/403/404 auth edges.
  • Master-key rotation: old token dies without the previous key, lives with it, new tokens use the new key.
  • Reputation + edit-signal metrics end to end (JSON + Prometheus).
  • Bounce alert: quiet under the min-sends floor, critical past it.

Verification

  • Full suite: 299 passed against real Postgres.
  • ruff check + format clean.
  • All new alert/pacing knobs documented in .env.example; no default-behavior change except the two new metrics fields (additive) and the alert (needs ≥5 sends/24h to ever fire).

🤖 Generated with Claude Code

https://claude.ai/code/session_01ASAVj4XgJCH3UcHkZZaYzM


Generated by Claude Code

Summary by CodeRabbit

  • New Features

    • Added tenant key rotation support and a new batch review flow for handling multiple drafts at once.
    • Expanded review queues and metrics to show fit scores, reputation signals, and additional rolling-window counts.
  • Bug Fixes

    • One-click unsubscribe tokens now remain valid during key rotation when the previous key is configured.
    • Bounce-rate alerts now wait for enough sends before triggering.
  • Documentation

    • Updated release readiness docs and setup examples with the latest production-readiness settings.

…itoring

Completes the code-buildable remainder of Phase 3 (production
readiness); docs/phase3-readiness.md records what code provides vs the
operator/legal deliverables and the three parked decisions.

Human-in-the-loop at scale:
- The review queue is confidence-ordered (highest fit_score first,
  FIFO within a score) and carries fit_score, so reviewers batch the
  confident tail and spend attention on the uncertain bottom.
- POST /outreach-drafts/batch-review: up to 100 rubric decisions per
  call through the same domain review path, each item in its own
  transaction - one stale/bogus item fails alone, the rest land.
  Never sends, like every review surface.
- Edit rate (approved_with_edits share of window reviews) is a
  first-class metric: edits-as-signal for prompt iteration.

Secrets rotation:
- POST /internal/tenants/{id}/rotate-key (admin token): issues a new
  tenant API key, old key dies at commit, rotation audited, key
  returned exactly once.
- RELAY_MASTER_KEY_PREVIOUS: verify-only rotation window for the
  master key, so signed unsubscribe tokens already sitting in
  delivered mail keep working across a rotation - a dead unsubscribe
  link is a compliance failure. New tokens always sign with the
  current key.

Reputation monitoring:
- 24h suppressions-by-reason and reviews-by-decision in tenant
  metrics; bounce_rate / complaint_rate / edit_rate properties wired
  through /metrics and the Prometheus export.
- bounce_rate_high critical alert (RELAY_ALERT_BOUNCE_RATE, default
  5%) with a min-sends floor (RELAY_ALERT_BOUNCE_RATE_MIN_SENDS) so a
  1-of-1 bounce never pages - it fires BEFORE the eligibility
  threshold silently pauses sending.

Tests (+7, suite now 299): batch review item isolation and terminal
states, confidence ordering, key rotation kills the old key instantly
(and 422/403/404 edges), master-key rotation keeps old tokens alive,
reputation + edit-signal metrics end to end, bounce alert honors the
min-sends floor then fires critical.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ASAVj4XgJCH3UcHkZZaYzM
@coderabbitai

coderabbitai Bot commented Jul 5, 2026

Copy link
Copy Markdown

Review Change Stack

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 8d731809-8bb3-48cd-b0ff-bb66213136e2

📥 Commits

Reviewing files that changed from the base of the PR and between 27862b4 and 7c10529.

📒 Files selected for processing (10)
  • .env.example
  • README.md
  • docs/phase3-readiness.md
  • src/relay/api/routes.py
  • src/relay/api/schemas.py
  • src/relay/config.py
  • src/relay/ingest/unsubscribe.py
  • src/relay/observability/alerts.py
  • src/relay/observability/metrics.py
  • tests/test_phase3_scale.py

📝 Walkthrough

Walkthrough

This PR adds three Phase 3 production-readiness capabilities: confidence-ordered batch human review of outreach drafts, tenant/master API key rotation with backward-compatible unsubscribe token verification, and bounce-rate reputation monitoring with alerting. Metrics, schemas, configuration, documentation, and tests are extended accordingly.

Changes

Phase 3 Production Readiness

Layer / File(s) Summary
Batch review and confidence-ordered queue
src/relay/api/routes.py, src/relay/api/schemas.py, tests/test_phase3_scale.py
Adds fit_score to pending draft items, orders the pending queue by score descending, and introduces a /outreach-drafts/batch-review endpoint processing items independently with aggregate results; tested for ordering and independence.
Tenant and master key rotation
src/relay/api/routes.py, src/relay/api/schemas.py, src/relay/config.py, src/relay/ingest/unsubscribe.py, .env.example, tests/test_phase3_scale.py
Adds an admin-only tenant key rotation endpoint, master_key_previous config, and unsubscribe token verification against current or previous master keys; tested for immediate invalidation, authorization, and rotation continuity.
Reputation monitoring and extended metrics
src/relay/observability/alerts.py, src/relay/observability/metrics.py, src/relay/api/schemas.py, src/relay/api/routes.py, src/relay/config.py, .env.example, tests/test_phase3_scale.py
Adds bounce-rate alert configuration and evaluation, new suppression/review window metrics with bounce/complaint/edit rate properties, Prometheus exposition, and metrics API fields; tested for threshold gating and signal exposure.
Phase 3 readiness documentation
README.md, docs/phase3-readiness.md
Adds README rows for new capabilities and a new document detailing exit-gate mechanisms, operator/legal deliverables, and parked decisions.

Estimated code review effort: 4 (Complex) | ~60 minutes

Possibly related PRs

  • Aakash1337/Relay#2: Extends the same pending-draft/review endpoints and review_draft logic that this PR builds on for batch review and queue ordering.
  • Aakash1337/Relay#4: Directly modifies the same observability files (alerts.py, metrics.py, routes/schemas) that this PR extends with bounce-rate alerts and window metrics.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch claude/relay-phase-3

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@Aakash1337 Aakash1337 marked this pull request as ready for review July 5, 2026 07:59
@Aakash1337 Aakash1337 merged commit b32cf9b into main Jul 5, 2026
3 checks passed
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