Skip to content

Phase 3 -- Corporate Updates -- Requirements

Numbered requirements that Phase 3 must satisfy. Each requirement is traceable to verification tests in verification.md and to tasks in specification.md.

Requirement-ID conventions:

  • REQ-CORP-NNN — direct deliverables of the Corporate instance group (zones, records, Postmark resources, 1Password items, cross-stack exports).
  • REQ-IAC-NNN — IaC-side hygiene (constructs, stacks, apps, instance configurations, reserved-words list, typed references).
  • REQ-CLI-NNN — Corporate CLI (tools/corporate-cli.ts) behavior, idempotency, and failure semantics.
  • REQ-OPS-NNN — operator prerequisites and post-deploy verification (mailbox provisioning, sandbox-to-live approval, smoke send).
  • REQ-CI-NNN — CI workflows for drift detection.
  • REQ-DOC-NNN — documentation deliverables.

REQ-CORP-001: arda.ardamails.com hosted zone exists in the Root account

Section titled “REQ-CORP-001: arda.ardamails.com hosted zone exists in the Root account”

The Corporate Email stack declares a Route53 PublicHostedZone with zoneName: "arda.ardamails.com" via the new DnsZone xgress construct. The zone is created in the same AWS account that hosts the parent ardamails.com zone (platformRoot for the foreseeable future, per architecture-overview § 6.4). The zone carries RemovalPolicy.RETAIN to defend against accidental cdk destroy.

Verifies: V-CORP-001

REQ-CORP-002: arda.ardamails.com zone ID is exported

Section titled “REQ-CORP-002: arda.ardamails.com zone ID is exported”

The Corporate Email stack publishes a CloudFormation export named arda-corporate-mail-zone whose value is the hosted zone ID. Future Corporate consumers (HubSpot, marketing) reference this export to add their own sending sub-domain records.

Verifies: V-CORP-002

REQ-CORP-003: NS-delegation record for arda is written into the parent zone

Section titled “REQ-CORP-003: NS-delegation record for arda is written into the parent zone”

The Corporate Email stack instantiates WriteNSRecordsToUpstreamDns with subdomain: "arda" and nameServers derived from the arda.ardamails.com zone’s hostedZoneNameServers token. The Lambda-backed Custom Resource assumes AllowCreatingNSRecordsRole (Phase 2 export arda-allow-create-ns-record-role) and writes the NS record set into the ardamails.com zone, even when both stacks deploy into the same AWS account (per DQ-R1-010).

Verifies: V-CORP-003

REQ-CORP-004: SPF record at arda.ardamails.com apex

Section titled “REQ-CORP-004: SPF record at arda.ardamails.com apex”

A TXT record at arda.ardamails.com apex has the value "v=spf1 include:spf.mtasv.net ~all" (Postmark’s SPF include with a soft-fail policy). The record is owned by the Corporate Email stack.

Verifies: V-CORP-004

REQ-CORP-005: DMARC record at _dmarc.arda.ardamails.com

Section titled “REQ-CORP-005: DMARC record at _dmarc.arda.ardamails.com”

A TXT record at _dmarc.arda.ardamails.com has the initial monitoring policy "v=DMARC1; p=quarantine; sp=quarantine; rua=mailto:dmarc-reports@arda.cards". Alignment is relaxed (DMARC’s default; tags adkim and aspf omitted). The policy hardens to p=reject (and possibly to strict alignment) after the Free Kanban Tool sending has bedded in — out of scope of this requirement; tracked as a post-deploy operator task. The reporting mailbox dmarc-reports@arda.cards is the address recorded in DQ-R1-015.

Verifies: V-CORP-005

REQ-CORP-006: Postmark Sender Signature exists for arda.ardamails.com

Section titled “REQ-CORP-006: Postmark Sender Signature exists for arda.ardamails.com”

A Postmark Sender Signature (sending-domain entry) exists in the PostmarkProd account for the domain arda.ardamails.com. It is created by Phase A of the Corporate CLI via the Postmark Account API using the PostmarkSendingDomain thin-wrapper. Verification target is the parent Corporate zone (per DQ-R1-009); leaf sub-domains do not get their own Sender Signature.

Verifies: V-CORP-006

REQ-CORP-007: Postmark Sender Signature is verified (DKIM and Return-Path)

Section titled “REQ-CORP-007: Postmark Sender Signature is verified (DKIM and Return-Path)”

The Sender Signature created under REQ-CORP-006 is marked verified for both DKIM and Return-Path. Verification is API-driven (verifyDkim and verifyReturnPath Account API calls invoked by the Corporate CLI) — no Postmark Console click-through is required for verification. The Postmark Console click-through is reserved for sandbox-to-live approval (REQ-OPS-002), which has no API equivalent.

Verifies: V-CORP-007

REQ-CORP-008: Free Kanban Tool DNS records published

Section titled “REQ-CORP-008: Free Kanban Tool DNS records published”

The Free Kanban Tool stack instantiates DnsEmailRecords against the Corporate zone with the Postmark-issued DKIM and Return-Path values surfaced via cdk.context.json (public values; per DQ-R1-014). Two records are emitted:

  • <selector>._domainkey.freekanban.arda.ardamails.com (DKIM TXT, TTL 300)
  • pm-bounces.freekanban.arda.ardamails.com (Return-Path CNAME → pm.mtasv.net, TTL 300)

DKIM signing for sub-domains under arda.ardamails.com is inherited from the parent Sender Signature (per DQ-R1-009); the leaf sub-domain does not register its own Sender Signature.

Verifies: V-CORP-008

REQ-CORP-009: Free Kanban Tool Postmark server exists in PostmarkProd

Section titled “REQ-CORP-009: Free Kanban Tool Postmark server exists in PostmarkProd”

A Postmark server named for the Free Kanban Tool exists in PostmarkProd, created by Phase A of the Corporate CLI. The server provides the per-asset isolation envelope for sending credentials and per-asset Postmark API quotas. Phase A is idempotent: re-running with an existing server returns the existing server’s metadata without creating a duplicate.

Verifies: V-CORP-009

REQ-CORP-010: Free Kanban Tool server token in Arda-CorporateOAM

Section titled “REQ-CORP-010: Free Kanban Tool server token in Arda-CorporateOAM”

The 1Password item Free-Kanban-Generator-Postmark-Server exists in the Arda-CorporateOAM vault with a credential field set to the Postmark Server API token. Canonical reference: op://Arda-CorporateOAM/Free-Kanban-Generator-Postmark-Server/credential. The item is created by Phase A of the Corporate CLI on first run; on subsequent runs the field is updated only if the token has changed.

The OP_SERVICE_ACCOUNT_TOKEN (CI’s 1Password auth) does not have read access to this vault, satisfying the bounded-blast-radius framing in DQ-R1-007.

Verifies: V-CORP-010

REQ-IAC-001: Postmark thin-wrapper constructs added

Section titled “REQ-IAC-001: Postmark thin-wrapper constructs added”

src/main/cdk/platform/constructs/postmark/server.ts (PostmarkServer) and src/main/cdk/platform/constructs/postmark/sending-domain.ts (PostmarkSendingDomain) exist. Each follows the construct-line shape:

  • Configuration interface declaring inputs.
  • Built interface declaring the public values exposed to consumers.
  • validateProps() static method covering input invariants.

The PostmarkServer.Built shape exposes serverId and the public DKIM / Return-Path metadata as structurally identical between the interim mechanism (Phase A imperative) and the eventual Custom-Resource Lambda target (per architecture-overview § 5.3). Caller code in stacks does not change at the future migration.

Verifies: V-IAC-001

REQ-IAC-002: route-53-hosted-zone.ts renamed to dns-zone.ts

Section titled “REQ-IAC-002: route-53-hosted-zone.ts renamed to dns-zone.ts”

The construct file src/main/cdk/constructs/xgress/route-53-hosted-zone.ts is renamed to dns-zone.ts; the class Route53HostedZone is renamed to DnsZone. The arda.cards default for overrideDomainName is removed; callers supply the zone name explicitly. All in-repo callers are migrated in the same PR (per DQ-R1-011).

Verifies: V-IAC-002

REQ-IAC-003: dns-email-records.ts construct added

Section titled “REQ-IAC-003: dns-email-records.ts construct added”

A new construct src/main/cdk/constructs/xgress/dns-email-records.ts (DnsEmailRecords) is added. Inputs (props only): hosted zone, DKIM selector, DKIM key (public), Return-Path target. Emits one DKIM TXT record and one Return-Path CNAME record at the configured sub-domain. No environment-variable bridge; no file-artifact channel.

Verifies: V-IAC-003

src/main/cdk/stacks/corporate/corporate-mail-dns.ts (CorporateMailDns) and src/main/cdk/stacks/corporate/free-kanban-tool-mail-dns.ts (FreeKanbanToolMailDns) exist. Composition:

  • CorporateMailDns owns the arda.ardamails.com zone (via DnsZone), the SPF record, the DMARC record, and the NS-delegation write (via WriteNSRecordsToUpstreamDns).
  • FreeKanbanToolMailDns composes DnsEmailRecords (against the Corporate zone) and PostmarkServer. The stack passes Built values from PostmarkServer (and PostmarkSendingDomain’s output via cdk.context.json) into DnsEmailRecords. Neither construct depends on the other.

Verifies: V-IAC-004

src/main/cdk/apps/Corporate/index.ts exports the reusable CorporateApp class that instantiates both Corporate stacks (CorporateMailDns, FreeKanbanToolMailDns) with names and configuration sourced from instances/Corporate/corporate.ts. The entry script src/main/cdk/tools/cdk-corporate.ts calls new cdk.App() and wires the stacks — it is the only file that calls new cdk.App() for this App. The CFN stack names are stable strings declared explicitly (the CFN-stack-name-immutability rule restated in ../phases.md § Phase 2 applies to all future updates of Corporate stacks).

Verifies: V-IAC-005

REQ-IAC-006: instances/Corporate/free-kanban-tool.ts declarative configuration

Section titled “REQ-IAC-006: instances/Corporate/free-kanban-tool.ts declarative configuration”

A new file src/main/cdk/instances/Corporate/free-kanban-tool.ts exports the typed configuration consumed by the Corporate App: Postmark account reference (from platform/postmark-service.ts), sending sub-domain (freekanban.arda.ardamails.com), 1Password item reference for the server token (from platform/one-password.ts), and Postmark plan attributes. Follows the rev1 instances/<InstanceGroup>/<asset>.ts convention.

Verifies: V-IAC-006

REQ-IAC-007: Reserved-words list extended for ardamails.com level

Section titled “REQ-IAC-007: Reserved-words list extended for ardamails.com level”

src/main/cdk/platform/ari-configuration.ts is extended with a constant (MAIL_RESERVED_SLUGS_AT_MAIL_ROOT or equivalent) that includes arda (and other reserved zone names at the ardamails.com level). Any partition-zone slug-validation that consumes the constant rejects the reserved values. The reserved-name registry at arda.ardamails.com itself is documentation-only (per DQ-R1-016) and is enforced by the Corporate CLI’s conflict-check (REQ-CLI-003).

Verifies: V-IAC-007

REQ-IAC-008: FREE_KANBAN_POSTMARK_ITEM typed reference reintroduced

Section titled “REQ-IAC-008: FREE_KANBAN_POSTMARK_ITEM typed reference reintroduced”

The typed reference FREE_KANBAN_POSTMARK_ITEM in src/main/cdk/platform/one-password.ts (removed in Phase 1 per DQ-R1-007) is reintroduced with the new vault, item title, and field:

export const FREE_KANBAN_POSTMARK_ITEM: OnePasswordItem = {
vault: "Arda-CorporateOAM",
title: "Free-Kanban-Generator-Postmark-Server",
primaryField: "credential",
reference: "op://Arda-CorporateOAM/Free-Kanban-Generator-Postmark-Server/credential",
};

tools/drift-check.ts’s ALL_OP_ITEMS is extended with this item; the Phase-1 test that asserts the item count moves from 3 to 4.

Verifies: V-IAC-008

tools/corporate-cli.ts exposes an entry point that runs in two conceptual phases:

  • Phase A (imperative): list-then-create the Postmark Sender Signature and server, write the 1Password item, write cdk.context.json. Idempotent.
  • Phase B: invoke cdk deploy apps/Corporate/. The CDK stacks read public values from cdk.context.json and emit the DNS records.

The two phases are exposed as separate CLI subcommands (e.g., corporate-cli prepare for Phase A, corporate-cli deploy for Phase B) so an operator can re-run either independently. Source comments name the phases explicitly so the eventual migration to a Lambda-backed Custom Resource is unambiguous.

Verifies: V-CLI-001

Each Phase A operation (Postmark sending-domain create, Postmark server create, 1Password item create, cdk.context.json write) is implemented as a list-then-create-or-update pattern. Re-running Phase A with the same inputs converges to the same external state without creating duplicates and without spurious updates.

Verifies: V-CLI-002

REQ-CLI-003: Phase A entry-time conflict-check

Section titled “REQ-CLI-003: Phase A entry-time conflict-check”

Before any state-mutating call, Phase A enumerates pre-existing Postmark Sender Signatures, Postmark servers, and 1Password items in Arda-CorporateOAM. If a name collision exists with the asset being created (and the existing entity is not the one this CLI invocation is reconciling), Phase A exits with a structured failure message identifying the colliding entity. This catches both intra-Corporate collisions and cross-instance-group collisions (per DQ-R1-016).

Verifies: V-CLI-003

REQ-CLI-004: Server-token write ordering and failure handling

Section titled “REQ-CLI-004: Server-token write ordering and failure handling”

Phase A captures the Postmark Server API token from the createServer response into a process-local secret-handling buffer. The token is written to 1Password with retries using the following policy (per DQ-R1-013):

  • Max attempts: 5 (1 initial + 4 retries).
  • Base delay: 1s.
  • Backoff: exponential, capped at 30s per individual delay.
  • Jitter: ±20% applied to each delay independently.
  • Total wall-clock cap: 5 minutes; if exceeded, the CLI exits the retry loop and treats the failure as permanent.
  • Retryable errors: HTTP 429, 5xx, and connection-level errors. 4xx (other than 429) are non-retryable.

On permanent 1P-write failure, the CLI exits with a redacted summary that allows the operator to either manually paste the token into 1Password (DesktopAuth) or invoke Postmark’s DELETE /servers/<id> API deliberately as recovery. The cdk.context.json write happens after the 1Password write succeeds; a 1P-write failure leaves cdk.context.json untouched. Per DQ-R1-013.

Verifies: V-CLI-004

REQ-CLI-005: Public values channel is cdk.context.json

Section titled “REQ-CLI-005: Public values channel is cdk.context.json”

Phase A writes the following public values into cdk.context.json:

  • postmark.free-kanban.serverId
  • postmark.free-kanban.dkimSelector
  • postmark.free-kanban.dkimKey
  • postmark.free-kanban.returnPathTarget

The file is committed to the repository per DQ-R1-014. The Postmark server token is not written to cdk.context.json, environment variables, file artifacts in the deploy pipeline, or CI context; the token lives only in 1Password (REQ-CORP-010).

Verifies: V-CLI-005

Where the Postmark Account API offers a verification endpoint (verifyDkim, verifyReturnPath, list / get for Sender Signatures), the CLI uses it. The Postmark Console click-through is reserved for steps that have no API equivalent (REQ-OPS-002).

Verifies: V-CLI-006

REQ-CLI-007: Structured logging with token redaction

Section titled “REQ-CLI-007: Structured logging with token redaction”

CLI output is structured (JSON-line per event); secret-bearing fields are redacted at the logging boundary. Operators run with --verbose for full trace; the default output is a compact human-readable summary. Token shapes (Postmark, 1Password service-account, GitHub PAT) are recognized by the redaction layer regardless of which field they appear in.

Verifies: V-CLI-007

tools/corporate-cli.ts exposes a verify <asset> subcommand that re-invokes the Postmark Account API verification endpoints (verifyDkim, verifyReturnPath) for the asset’s Sender Signature and reports the result. The subcommand is idempotent and is the operator path for Task O3 step 1. prepare invokes the same verification logic at the end of its run; verify exists as a standalone re-runnable entry point so the operator can re-verify after DNS propagation without re-running the full Phase A pipeline.

Verifies: V-CLI-008

tools/corporate-cli.ts may additionally expose convenience subcommands — list (enumerate assets in instances/Corporate/) and check <asset> (run the Phase A conflict-check without state mutation). These are not required deliverables; they are not subject to a formal acceptance gate in this phase. If implemented, they follow the same redaction and structured-output rules (REQ-CLI-007).

REQ-OPS-001: dmarc-reports@arda.cards mailbox provisioned

Section titled “REQ-OPS-001: dmarc-reports@arda.cards mailbox provisioned”

Satisfied — the mailbox was provisioned on 2026-05-09 in Arda’s Google Workspace and confirmed reachable (see V-OPS-001).

Before Phase B deploy, the operator provisions dmarc-reports@arda.cards in Arda’s Google Workspace as a real, reachable mailbox (or distribution list whose subscribers receive the mail). The mailbox is the destination for the DMARC aggregate-report rua address declared in REQ-CORP-005. Captured in the operator runbook (REQ-OPS-003) authored post-deploy.

Verifies: V-OPS-001

REQ-OPS-002: Sandbox-to-live approval (only Postmark Console step)

Section titled “REQ-OPS-002: Sandbox-to-live approval (only Postmark Console step)”

If the Free Kanban Tool Postmark server is in sandbox at the time of Phase A, the operator submits the approval request via the Postmark Console (the only step in Phase 3 that lacks an API equivalent and therefore requires a UI click-through). The CLI reads DeliveryType from GET /servers/{id} after server creation (Phase A, step after server creation) and emits a warn-level log event if DeliveryType is Sandbox or unknown, so the operator knows before proceeding to Phase B.

Note: Postmark’s API has no account-level sandbox endpoint. GET / 302-redirects to the marketing site; GET /account returns HTTP 404. DeliveryType is a per-server property; it is the correct API signal for live-sending readiness and is only available after the server is created.

Verifies: V-OPS-002

REQ-OPS-003: Operator runbook authoring is gated on the deploy experience

Section titled “REQ-OPS-003: Operator runbook authoring is gated on the deploy experience”

The operator runbook (the long-lived deliverable defined in REQ-DOC-004) is authored after the Phase C deploy completes, not before. This is a constraint on REQ-DOC-004’s timing, not a separate deliverable: the same physical artifact satisfies both requirements. The constraint exists so the runbook reflects deploy-time discoveries, observed Postmark-API quirks, and the actual operator experience — not the implementer’s pre-deploy guess at the procedure.

Verifies: V-OPS-003

After Phase B, the operator runs an end-to-end smoke send: one test message from the Free Kanban Tool through Postmark to a non-owner recipient. The recipient’s Authentication-Results header shows dkim=pass aligned with arda.ardamails.com, spf=pass, and dmarc=pass.

Verifies: V-OPS-004

REQ-CI-001: corporate-drift.yml workflow exists

Section titled “REQ-CI-001: corporate-drift.yml workflow exists”

infrastructure/.github/workflows/corporate-drift.yml exists. Schedule: monthly (cron: "0 9 1 * *" matching the Phase 1 cadence). Manual trigger: workflow_dispatch enabled. Authentication uses OP_SERVICE_ACCOUNT_TOKEN. Per DQ-R1-012.

Verifies: V-CI-001

REQ-CI-002: Drift driver is data-driven over instances/Corporate/

Section titled “REQ-CI-002: Drift driver is data-driven over instances/Corporate/”

The driver script invoked by corporate-drift.yml enumerates the assets declared in instances/Corporate/ and exercises each asset’s external-state invariants:

  • Postmark server reachable (the server’s account-API resolution succeeds).
  • DNS records resolve (dig returns the expected DKIM TXT and Return-Path CNAME for each leaf sub-domain).
  • 1Password item reachable (the op://... reference resolves under the CI service-account auth path — but the Free Kanban server-token itself is not read; only existence is asserted, since the token lives in Arda-CorporateOAM which is out of OP_SERVICE_ACCOUNT_TOKEN’s scope).

New Corporate assets added by future phases are picked up automatically by the same workflow.

Verifies: V-CI-002

REQ-CI-003: Drift workflow opens an issue on failure

Section titled “REQ-CI-003: Drift workflow opens an issue on failure”

On any drift detection failure, the workflow opens a GitHub issue in Arda-cards/infrastructure with a fixed label set (drift, phase-3, corporate, <asset>) and a structured body that names the failed assertion(s). The pattern mirrors the Phase 1 external-resources-drift.yml shape.

Verifies: V-CI-003

infrastructure/tools/drift-check.ts’s ALL_OP_ITEMS constant is extended with the Free-Kanban-Generator-Postmark-Server item; the test tools/drift-check.test.ts is updated to expect 4 items (was 3). Item resolution under OP_SERVICE_ACCOUNT_TOKEN is not asserted for this item (the token cannot read Arda-CorporateOAM); existence is asserted via the Corporate-OAM auth path inside the dedicated Corporate workflow.

Verifies: V-CI-004

REQ-DOC-001: Phase 3 planning artifacts published

Section titled “REQ-DOC-001: Phase 3 planning artifacts published”

The six planning artifacts (this file plus analysis.md, specification.md, verification.md, exports.md, and plan/task-plan.md) exist under roadmap/in-progress/email-integration/3-corporate-updates/. They are linked from phases.md. (Operator-side governance notes that reference these artifacts live in the workspace’s projects/email-integration-worktrees/ directory; that directory is outside the documentation repository and is not a published documentation home.)

Verifies: V-DOC-001

REQ-DOC-002: Decision-log Round R1-Phase3 published

Section titled “REQ-DOC-002: Decision-log Round R1-Phase3 published”

decision-log.md carries a Round R1-Phase3 section with eight entries (DQ-R1-009 through DQ-R1-016). The decision-table at the top and the Summary table at the bottom of decision-log.md are updated.

Verifies: V-DOC-002

REQ-DOC-003: Phase 3 documentation pages by content type

Section titled “REQ-DOC-003: Phase 3 documentation pages by content type”

New documentation pages are placed under current-system/ by content type (per 3-corporate-updates/analysis.md gap G-19):

  • OAM (current-system/oam/): a Postmark service overview for the Corporate consumer pattern; Corporate drift notes; a Free Kanban Tool service page.
  • Runtime architecture (current-system/runtime/): Corporate Resource Group structure; Free Kanban Tool component placement.

No new pages are placed under current-system/functional/ or current-system/data-model/ (Phase 3 is all IaC).

Verifies: V-DOC-003

The operator runbook is published at process/sre/runbooks/postmark-domain-verification.md (or a similarly scoped name finalized at write time). It generalizes beyond Free Kanban Tool: any future Corporate consumer or partition-level Postmark Sender Signature verification reuses it. The runbook covers only steps that lack an API equivalent (sandbox-to-live approval; the end-to-end smoke send to a non-owner address; any DMARC-mailbox-validation step). Steps the CLI automates do not appear in the runbook; they are documented inside the CLI’s --help and source comments. The Phase 1 stub at 3-corporate-updates/operator-domain-verification-checklist.md is left as a frozen Phase-1 artifact (per Phase D’s Task D2 disposition); the runbook does not depend on it.

Verifies: V-DOC-004

These items are either deferred to later phases or are explicit non-goals.

  • Per-partition mail sub-zones (prod.ardamails.com, dev.ardamails.com, …) and their NS delegations — belong to Phase 4.
  • Per-partition Postmark account-token + encryption-key Secrets Manager entries — belong to Phase 4.
  • Backend ShopAccess/Email module in operations — belongs to Phase 5b.
  • Apex-level SPF / DMARC at ardamails.com — out of scope of this project per project-level CLAUDE.md; revisit when org-wide DMARC reporting becomes a requirement.
  • Tightening AllowCreatingNSRecordsRole.allowedParentHostedZoneIds — out of scope of this project; current value preserved.
  • Migration of the PostmarkServer thin-wrapper internals to a Lambda-backed Custom Resource — deferred; the construct’s external surface is identical between interim and target so the migration is a future internals change only.
  • Helm-release equivalent of the IaC patterns — out of scope (deferred per the runtime-design review).
  • Free Kanban Tool runtime service — this project does not implement the Free Kanban Tool itself; it provisions the sending infrastructure the tool consumes.

Phase 3 is complete when:

  1. cdk diff of apps/Corporate/ against the Root account shows the additive zone, NS-delegation record, SPF / DMARC records, and Free Kanban DNS records (plus any non-functional logical-ID renames CDK assigns).
  2. dig confirms arda.ardamails.com is delegated, the SPF and DMARC records resolve, and the Free Kanban DKIM TXT + Return-Path CNAME records resolve.
  3. The Postmark Sender Signature for arda.ardamails.com is API-verified (DKIM and Return-Path).
  4. The Free Kanban Tool Postmark server is reachable via the token in op://Arda-CorporateOAM/Free-Kanban-Generator-Postmark-Server/credential.
  5. The end-to-end smoke send (REQ-OPS-004) passes DKIM / SPF / DMARC at the recipient.
  6. corporate-drift.yml runs successfully on its first scheduled trigger.
  7. The six planning artifacts in 3-corporate-updates/ are merged on the documentation side; phases.md and decision-log.md are patched.
  8. CHANGELOG entries: one in documentation under “Added”; one in infrastructure under “Added”.