ADR-0004: Per-Lambda PR preview deploys + promote-on-merge

Context

Vercel gives the Next.js app a preview deploy per PR, so reviewers can click a URL and see the change before it lands on main. Our Lambdas have no such workflow — the old lambda-deploy.yml only ran on push to main, which meant:

We have four Lambdas today:

Lambda Trigger Has :live alias
propflow-inbound-processor (Clara) SQS FIFO yes
propflow-tour-reminder EventBridge 1h no
propflow-outlook-subscription-renewer EventBridge 30m no
ses-email-forwarder SES rule no

propflow-inbox-poller was retired in ADR-0011.

Decision

Add a per-Lambda GitHub Actions workflow that runs in two stages:

  1. pr-preview job on pull_request whenever a file the Lambda bundles has changed:

    • Build the bundle, zip it.
    • Ensure a propflow-<name>-preview Lambda exists (clone config from the prod function on first run — same role / runtime / memory / env vars). The preview function has no trigger (no SQS, no EventBridge, no SES), so invoking it cannot touch production data paths.
    • aws lambda publish-version — captures an immutable preview version.
    • Smoke-invoke lambda/<name>/fixtures/*.json against the preview version.
    • Post a sticky PR comment with ARN, version, bundle size, and per-fixture smoke results.
  2. prod-promote job on push to main:

    • Rebuild (see Known gap below).
    • update-function-code on the prod function.
    • publish-version — immutable prod version.
    • Smoke-invoke the new version before flipping the alias.
    • If smoke passes AND a :live alias exists, flip it. If no alias, the update-function-code above is already "live" (the EventBridge / SES trigger targets $LATEST). This is a soft migration path for adding aliases to the other Lambdas later.
    • Post-promote smoke against the alias (or the new version).
    • On any failure, emit a workflow annotation and do NOT flip the alias.

Known gaps (post-Phase-3)

Consequences

Rollback plan

If the new workflows misbehave:

  1. Delete or disable the per-Lambda workflows (gh workflow disable).
  2. Re-enable the on: push trigger in lambda-deploy.yml.
  3. Manually run bash lambda/<name>/deploy.sh from a clean main checkout for the other Lambdas (these scripts still exist — we intentionally did not delete them in Phase 3).

References