feat: send a deterministic email digest after each pipeline run - #59
Conversation
One fixed-template TL;DR email per completed watcher or publish run, rendered by the new email-digest control subcommand from retained run state only and delivered through Resend. The workflow skips quietly until the RESEND_API_KEY secret and the email variables exist.
Bugbot couldn't run - usage limit reachedBugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit. A user or team admin can review and increase usage limits in the Cursor dashboard. (requestId: serverGenReqId_50f9b20f-1422-47a8-b4cd-a72ca868e8fd) |
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (3)
🚧 Files skipped from review as they are similar to previous changes (3)
📝 WalkthroughWalkthroughAdds deterministic email digests for completed watcher and publish runs. The CLI renders validated fixed templates from retained state. A GitHub Actions workflow sends the digest through Resend when configuration is complete. ChangesEmail digest delivery
Estimated code review effort: 3 (Moderate) | ~20 minutes Sequence Diagram(s)sequenceDiagram
participant Run as Watcher or publish workflow
participant Email as autorelease-email workflow
participant CLI as email-digest
participant Resend as Resend API
Run->>Email: Complete with workflow metadata
Email->>Email: Retrieve retained state
Email->>CLI: Render fixed-template digest
CLI-->>Email: Return subject and body
Email->>Resend: Send email digest
Possibly related PRs
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches 💡 1📝 Generate docstrings 💡
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 4
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In @.github/workflows/autorelease-email.yml:
- Around line 104-108: Update the curl invocation that POSTs to
https://api.resend.com/emails to include bounded --connect-timeout and
--max-time options, ensuring stalled connections or requests fail promptly while
preserving the existing authentication, payload, and error-reporting flags.
In `@autorelease/_state.py`:
- Around line 236-248: In the decision handling around the report decision,
validate decision["modelCall"] with isinstance(..., bool) before the
quiet_day/template selection; reject missing or non-boolean values rather than
relying on truthiness, while preserving the existing behavior for explicit True
and False values.
- Around line 251-254: Update the plan validation around action and action_key
so each permitted action requires its corresponding actionKey prefix before
deriving version; do not rely solely on ACTION_KEY_RE.fullmatch. Preserve the
special original-action key contract for reconcile_partial, and reject
mismatched combinations such as new_patch with a repair key.
- Around line 195-225: Update the transaction-state handling around the
released/conclusion branches to require a non-null transaction when conclusion
is "success", validate that transaction["released"] is an exact boolean, and
require it to be True for successful runs. Reject inconsistent successful state
instead of falling through to the publish_failed email, while preserving the
existing handling for non-success conclusions.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 1b8a66c2-2c65-48cc-a2c0-3a911b1d4f2e
📒 Files selected for processing (6)
.github/workflows/autorelease-email.ymlAUTORELEASE.mdautorelease/_state.pyautorelease/control.pydocs/repository-settings.mdtests/test_autorelease.py
Run state that matches no template, including a corrupt retained artifact, now emails a fallback summary naming the exact rejection reason. Only revalidated values are interpolated; everything else is replaced with 'unknown'.
Bugbot couldn't run - usage limit reachedBugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit. A user or team admin can review and increase usage limits in the Cursor dashboard. (requestId: serverGenReqId_a05ca6d6-7cb0-4cb1-96ac-f7f25d73e0c7) |
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
autorelease/control.py (1)
185-195: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick winReject missing publish state as unexpected.
The state paths are optional for failed runs, but a successful publish run cannot be classified when
--transactionis absent or contains JSONnull. Lines 275-279 pass that case asNone;email_digestthen defaultsreleasedtoFalseand emitspublish_failed. The email can state that nothing was published although the state is unknown. Require a valid transaction and booleanreleasedfor successful publish runs, then raiseControlErrorsoemail_fallbackhandles the case.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@autorelease/control.py` around lines 185 - 195, Update email_digest to validate successful publish runs before classification: require a present, non-null transaction state containing a boolean released value, and raise ControlError when validation fails so email_fallback handles the unknown state. Preserve the existing optional-state behavior for failed runs and avoid defaulting missing released data to False.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@autorelease/control.py`:
- Around line 271-280: Update email_digest to validate decision.manifestDigest,
plan.actionKey, and transaction.version as strings before passing them to regex
fullmatch; raise ControlError for null or non-string values so the existing
handler emits the fallback JSON digest. Preserve normal matching behavior for
valid string fields.
---
Outside diff comments:
In `@autorelease/control.py`:
- Around line 185-195: Update email_digest to validate successful publish runs
before classification: require a present, non-null transaction state containing
a boolean released value, and raise ControlError when validation fails so
email_fallback handles the unknown state. Preserve the existing optional-state
behavior for failed runs and avoid defaulting missing released data to False.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: c998e06a-5311-474c-adfe-5cde13730f97
📒 Files selected for processing (4)
AUTORELEASE.mdautorelease/_state.pyautorelease/control.pytests/test_autorelease.py
🚧 Files skipped from review as they are similar to previous changes (1)
- AUTORELEASE.md
Reject a green publish run without released transaction state instead of emailing a false failure, require exact booleans for released and modelCall, pin each action to its action-key family, validate field types before regex matching so corrupt artifacts reach the fallback instead of raising TypeError, and bound the Resend call with connect and request timeouts.
Bugbot couldn't run - usage limit reachedBugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit. A user or team admin can review and increase usage limits in the Cursor dashboard. (requestId: serverGenReqId_4e051878-7902-4c99-9312-5eca687c8ad7) |
|
Review round complete. All five CodeRabbit findings were valid and are fixed in 194e274: bounded timeouts on the Resend call, a green publish run without released transaction state now rejects into the fallback digest instead of emailing a false failure, modelCall and released require exact booleans, each action is pinned to its action-key family, and malformed artifact fields raise ControlError so the fallback path survives corrupt state. All threads are replied to and resolved, Script checks is green, and the re-review reported nothing new. Protected controls stays red by design pending owner approval. |
What
Adds an end-of-pipeline TL;DR email: one fixed-template message per completed
PHP autorelease watcherorAutorelease publish transactionrun, delivered through Resend.autorelease/_state.py: new pureemail_digestfunction — a deterministic template table keyed on run conclusion, watch decision, admitted plan action, and release transaction state. Every interpolated value is validated against the existing shape rules (ACTION_KEY_RE,SHA256_RE,STABLE_VERSION_RE), so no model-authored prose can reach the outbound channel; an outcome with no template is rejected instead of guessed at.autorelease/control.py: exposes it as theemail-digestsubcommand..github/workflows/autorelease-email.yml: newworkflow_run-triggered workflow. Downloads the triggering run's retained artifact (investigation state or transaction state), renders the digest, and posts it to the Resend API. Skips quietly whileRESEND_API_KEY,AUTORELEASE_EMAIL_FROM, orAUTORELEASE_EMAIL_TOis unset, so it can merge ahead of provisioning.tests/test_autorelease.py: data-driven coverage of every template plus rejection of unroutable or unvalidated run state.AUTORELEASE.md,docs/repository-settings.md: document the channel and the required secret/variables.Why
Actions failure email and the deduplicated issues only speak up when something goes wrong. For an unattended system, silence is ambiguous between "healthy, no change" and "the schedule silently stopped" — the daily digest turns the quiet days into a positive heartbeat.
Verification
./scripts/test.shpasses locally (36 tests, public-language check included).no_change_reviewedwith the correct manifest digest and run link.Protected controls will be red by design (owner-authored protected-path change); judge by Script checks.
Summary by CodeRabbit
New Features
Documentation
Bug Fixes