Skip to content

Phase 4 -- Runtime Platform Updates -- Analysis

A capability-oriented bridge between ../goal.md (project intent) and the downstream requirements.md / specification.md / verification.md / exports.md (the contract) and the ../plan/ tree (the run-level execution machinery — evaluation.md, choreography.md, per-run plans).

Phase 4 enables four Application Runtime partitions (prod, demo, dev, stage; kyle excluded per DQ-R1-021) to authoritatively send email on a per-partition mail sub-zone of ardamails.com, with the per-partition AWS infrastructure that Phase 5b’s Email module will consume at runtime.

  • Fan-out scope: 4 partition-email stacks across 2 AWS accounts. Alpha001 carries prod + demo; Alpha002 carries dev + stage. Each account hosts one Infrastructure and two Partitions per current-system/runtime/platform-structure.md.
  • Upstream dependencies: Phase 2 (ardamails.com zone + AllowCreatingNSRecordsRole) and Phase 3 (PostmarkSendingDomain thin-wrapper, DnsEmailRecords xgress construct, corporate-cli reusable utilities).
  • Downstream consumers: Phases 5a (consumes nothing from Phase 4) and 5b (consumes SM secret ARNs and IAM role ARNs via the STS chain).
  • Rollout order: devstagedemoprod, operator-enforced via amm.sh (DQ-R1-021).

Each Capability section (§4–§11) is self-contained: read one without paging through the others. Implementation Groups (§12) and the DAG (§13) are the execution view: read them when planning PR sequencing.

Looking for…Read
Goal-to-Capability traceability (which goal item is covered where)§3
What Phase 4 changes for DNS sub-zones / records§4 (C-DNS-Authority)
Postmark Sender Signature mechanics + token delivery (δ.1)§5 (C-Postmark-Sending)
Encryption-key SM secret (envelope design lives in email-server-key-encryption.md)§6 (C-EmailKey-At-Rest)
IAM role construct reuse + Root no-drift guard§7 (C-Runtime-DNS-Writes)
Fallback role for SM versions older than AWSPREVIOUS§8 (C-Fallback-Decryption)
Drift workflow shape and probe logic§9 (C-Drift-Detection)
amm.sh partition-mail steps + minimal corporate-cli extraction§10 (C-Operator-Surface)
Per-partition mail documentation pages§11 (C-Documentation)
Execution order, PR sequencing, DAG§12 + §13.1–§13.2
When amm.sh is ready and which invocations create which resources§13.3
Capability readiness criteria§13.4
Out-of-scope concerns§14
Decisions made and rationale§15 + ../../decision-log.md
Spec / verification carry-forwards§16

Each goal-item is owned by exactly one Capability. No goal-item is unowned.

Goal item (../goal.md)Capability
Success criterion #1 (sub-zones live and delegated)C-DNS-Authority
Success criterion #2 (deploy-time Postmark credential resolution)C-Postmark-Sending
Success criterion #3 (encryption-key secret + ESO)C-EmailKey-At-Rest
Success criterion #4, role (a) DNS-provisioningC-Runtime-DNS-Writes
Success criterion #4, role (b) SM-fallbackC-Fallback-Decryption
Success criterion #5 (arda-nonprod first Signature verified)C-Postmark-Sending (specifically G-POSTMARK-5)
Success criterion #6 (runtime-platform-drift covers partition surfaces)C-Drift-Detection
Scope bullet “Operator surfaces integrated into amm.sh” (DQ-R1-022)C-Operator-Surface
Deliverable rows 11 + 11b (documentation)C-Documentation
Success criteria #7 + #8 (decision-log + phases.md patches)Meta — this analysis + ../../decision-log.md

Each Capability section follows the same five-subsection structure: Purpose & linkage, Already in place, What Phase 4 adds (gap rows tagged → Group), What’s reused, Out-of-scope edges.

Each partition becomes a DNS authority for {partition}.ardamails.com — owning SPF and DMARC policy and the namespace under which Postmark will publish DKIM records. Supports goal success criterion #1.

FoundationSource
ardamails.com root zonePhase 2; exported arda-ardamails-zone
AllowCreatingNSRecordsRole (Root account)Phase 2; reused by Phase 4 for NS-delegation only (distinct from the per-partition DNS-records role in §7)
WriteNSRecordsToUpstreamDns constructPhase 2; constructs/xgress/write-ns-records-to-upstream-dns.ts
DnsZone xgress constructPhase 3 (renamed from Route53HostedZone); constructs/xgress/dns-zone.ts
GapDescription→ Group
G-DNS-1r53.PublicHostedZone per partition (prod.ardamails.com, demo.ardamails.com in Alpha001; dev.ardamails.com, stage.ardamails.com in Alpha002). RemovalPolicy.RETAIN. Exported as ${publishingPrefix}-API-PartitionMailZoneId and ${publishingPrefix}-API-PartitionMailZoneName (zone-name needed for SDK ListHostedZonesByName-style lookups and for record-set FQDN composition). The -API- marker is correct because the consumer is the operations Helm chart (non-CDK), per the convention in cdk-infrastructure.md § Export naming. Phase 3’s Corporate-I-MailZoneId used -I- because its consumer was a sibling CDK stack (FreeKanbanToolMailDns); Phase 4 has no such CDK consumer (operations is not CDK-deployed). Models image-storage.ts, where every export uses -API- for the same reason.G-B
G-DNS-2NS-delegation record per partition in ardamails.com via WriteNSRecordsToUpstreamDns. CR Lambda assumes AllowCreatingNSRecordsRole (Phase 2).G-B
G-DNS-3SPF v=spf1 include:spf.mtasv.net ~all TXT record at each partition apex.G-B
G-DNS-4DMARC p=quarantine; sp=quarantine; rua=mailto:dmarc-reports@arda.cards at _dmarc.{partition}.ardamails.com (per pre-design follow-up C2: reuse Corporate mailbox; no per-partition mailboxes).G-B
G-DNS-5Reserved-name list extension: prod, demo, dev, stage, kyle reserved at the ardamails.com level so future tenants cannot appropriate partition names as slugs (per pre-design follow-up B4: extend the Phase 3 mechanism used to reserve arda). Workspace-scoped (no per-partition fan-out) — landed in PR #1 (G-A) alongside the other workspace refactors.G-A

DnsZone, WriteNSRecordsToUpstreamDns, AllowCreatingNSRecordsRole (Root account, NS-delegation path only). Reserved-name mechanism from Phase 3.

  • DKIM TXT and Return-Path CNAME records under partition sub-zones → C-Postmark-Sending (their values are produced by the Postmark API at deploy time).
  • Per-tenant DNS records → Phase 5b.
  • Apex SPF/DMARC on the root ardamails.com zone → out of project.
  • kyle.ardamails.com sub-zone → deferred (DQ-R1-021).

Each partition can authoritatively send email from its own Postmark Sender Signature with a distinct DKIM signing key. Supports goal success criteria #2 (deploy-time credential resolution) and #5 (arda-nonprod unlock).

FoundationSource
PostmarkSendingDomain thin-wrapperPhase 3; platform/constructs/postmark/sending-domain.ts
sendingDomainPlacement() typed FQDN composerPhase 3
DnsEmailRecords xgress construct (DKIM TXT + Return-Path CNAME emitter)Phase 3
POSTMARK_PROD_ACCOUNT + POSTMARK_NONPROD_ACCOUNT typed referencesPhase 1; platform/postmark-service.ts
arda-prod Postmark account approvalExternal (Postmark Support ticket #11236087, approved 2026-05-11). prod + demo rollouts have no external prerequisite.
arda-nonprod Postmark account approvalPending (ticket #11236089). Unlocked by G-POSTMARK-5 (dev partition’s first non-prod Sender Signature).
GapDescription→ Group
G-POSTMARK-1postmarkCredentialOpReference(partition: PartitionId): string in platform/postmark-service.ts returning the op://Arda-{Env}OAM/Postmark/credential reference. Consumed by amm.sh (via op read); CDK has no 1Password dependency.G-A
G-POSTMARK-2Partition Postmark Sender Signature per partition (PostmarkSendingDomain instantiated per partition; one Signature per partition sub-zone — DQ-R1-017). Created via Postmark Account API in amm.sh’s Phase A step (before cdk deploy) — the API call returns the DKIM selector / Return-Path target which tools/register-partition-mail-signature.ts writes into cdk.context.json, and cdk deploy (Phase B) reads that context at synth time. See § 10.3 G-OP-2 and § 13.3 for the operator-level sequencing.G-C
G-POSTMARK-3DKIM TXT + Return-Path CNAME records per partition (via DnsEmailRecords). Values come from Postmark API at deploy time, written to cdk.context.json (Phase 3 pattern).G-C
G-POSTMARK-4Per-partition Postmark account-token SM secret {fqn}-I-EmailPostmarkAccountToken declared in partition-email stack via SecretValue.cfnParameter() (δ.1 pattern; amm.sh reads from 1Password and passes as NoEcho parameter). RemovalPolicy.RETAIN. Exported as ${publishingPrefix}-API-EmailPostmarkAccountTokenArn for the operations Helm chart’s ESO ExternalSecret. The {fqn}-I-… in the SM resource name is a separate concern from the CFN export name: the resource name’s -I- marker indicates intra-partition AWS scope (per the existing partitionSecrets.cfn.yaml convention); the CFN export’s -API- marker indicates non-CDK consumption.G-C
G-POSTMARK-5arda-nonprod unlock: the dev partition’s Sender Signature registration (a special case of G-POSTMARK-2 applied to PostmarkNonProd). Operator replies to Postmark Compliance (#11236089) with verified-domain evidence.G-C-for-dev

PostmarkSendingDomain, DnsEmailRecords, sendingDomainPlacement(), partitionSecrets.cfn.yaml NoEcho-parameter pattern (5 secrets already use it — ArdaApiKey, HubspotPAT, AmazonCreatorsApi, etc.), amm.sh GHA ::add-mask:: hygiene.

  • Per-tenant Sender Signatures and per-tenant DNS records → deferred to Phase 5b (DQ-R1-017). The current Phase 4 design (one Signature per partition + DMARC relaxed alignment) lets all tenants in a partition send from {config}.{tenant}.{partition}.ardamails.com while DKIM-signed by the partition’s key. This works because receivers accept relaxed-aligned DKIM, but the trade-off is that all tenants share the partition’s DKIM-domain reputation. If Phase 5b decides per-tenant reputation isolation is required (whole-population from v1, opt-in for sensitive tenants, or as a remediation path for tenants generating bounce/spam issues), each affected tenant will need (a) its own Sender Signature registered via the Postmark Account API and (b) per-tenant DKIM TXT + Return-Path CNAME records written into the partition mail sub-zone. Phase 4’s EmailDnsProvisioningRole (G-IAM-3) is provisioned specifically to enable (b) — it is the explicit Phase-4 deliverable that unlocks per-tenant Signatures whenever Phase 5b chooses to introduce them. Phase 5b’s decision does not require any Phase 4 re-work. Tracked in DQ-R1-023 as a Phase 5b open question.
  • PostmarkServer resources (per-tenant servers; independent of the Signature decision) → Phase 5b.
  • Inbound webhook handling → Phase 5b.
  • Bulk / broadcast Message Stream → out of project (transactional-only per cross-cutting-design.md § 7a).

The encryption material that Phase 5b’s TokenCipher will use to encrypt per-tenant Postmark server tokens before persistence exists in AWS Secrets Manager, ready for ESO projection. Supports goal success criterion #3.

FoundationSource
AWS Secrets Manager per-accountStanding infrastructure
ESO ClusterSecretStore per partition clusterPre-Phase-4 entry criterion
Two-axis envelope and dispatch design (DQ-R1-019)email-server-key-encryption.md
GapDescription→ Group
G-KEY-1Per-partition encryption-key SM secret {fqn}-I-EmailEncryptionKey (passwordLength: 64, RemovalPolicy.RETAIN). Versioning delegated to AWS SM native (AWSCURRENT / AWSPREVIOUS). Exported as ${publishingPrefix}-API-EmailEncryptionKeyArn for the operations Helm chart’s two ESO ExternalSecret mounts (AWSCURRENT + AWSPREVIOUS — both reference the same secret ARN with different versionStage selectors). CDK generateSecretString is “generate-if-missing” semantics: subsequent cdk deploy runs (and amm.sh re-runs that drive them) are no-ops on this secret. Rotation is exclusively operator-driven via aws secretsmanager update-secret (runbook in G-OP-5). The generateSecretString configuration must be treated as immutable post-launch — changing fields like passwordLength could trigger silent regeneration. Full lifecycle invariants in email-server-key-encryption.md § CDK lifecycle invariants.G-C

AWS SM native versioning (no Phase 4 code for envelope dispatch — that machinery is Phase 5b consuming this Phase 4 secret).

  • TokenCipher class (HKDF + AES-256-GCM + envelope codec) → Phase 5a (common-module, general-purpose per B1).
  • ESO ExternalSecret Helm definitions (AWSCURRENT + AWSPREVIOUS mounts) → Phase 5b.
  • Lazy + coroutine migration → Phase 5b.
  • SDK-fallback consumer wiring → Phase 5b (uses C-Fallback-Decryption).
  • Rotation procedure (operator-driven via aws secretsmanager update-secret) → documented in email-server-key-encryption.md § Sub-decision 3; runbook deliverable in G-OP-5.
  • CDK lifecycle invariants (generateSecretString is “generate-if-missing”; amm.sh re-runs are no-ops; config must be treated as immutable post-launch) → email-server-key-encryption.md § CDK lifecycle invariants.

The operations component running in a partition can write DKIM/Return-Path DNS records into the partition’s mail sub-zone at runtime. Supports goal success criterion #4 (DNS-provisioning role). Whether Phase 5b actually exercises this role — and on what frequency — depends on the per-tenant Sender Signature decision tracked as DQ-R1-023. If Phase 5b adopts per-tenant Sender Signatures (options β / γ / δ in DQ-R1-023), the role is exercised at tenant onboarding (and at remediation events for option δ) to register the per-tenant DKIM TXT + Return-Path CNAME records into the partition mail sub-zone. If Phase 5b stays with the partition Signature (option α), the role is provisioned but not exercised in v1 — it remains available for future per-tenant Signature introduction without re-doing Phase 4 IAM work.

FoundationSource
AllowCreatingNSRecordsRole constructPhase 2; constructs/oam/allow-creating-ns-records-role.ts. Permissions are already generic Route53 record-set CRUD (ChangeResourceRecordSets, ListResourceRecordSets, ListHostedZonesByName) with allowedParentHostedZoneIds scope-tightening — the “NSRecords” name is misleading.
Per-partition pod IRSA roleeks-stack.ts:250, exported as ${publishingPrefix}-EksPodRoleArn
STS-chain precedentinfrastructure/src/main/cdk/constructs/storage/image-asset-bucket.ts ImageUploadPreSigningRole pattern
GapDescription→ Group
G-IAM-1Generalize AllowCreatingNSRecordsRole construct + rename to AllowCreatingDnsRecordsRole (mechanical). Parameterize the trust principal so callers can choose between (a) Lambda + OrgID (Root use case, default for backwards compatibility) and (b) iam.AccountPrincipal(account).withConditions({ ArnLike: ... }) (Phase 4 STS-chain use case). The class rename lands in the same PR — the CDK construct ID at the Root call site is preserved (new AllowCreatingDnsRecordsRole(this, "AllowCreatingNSRecordsRole", …)), so the synthesized CloudFormation logical IDs are unchanged. T-I2’s byte-equality test catches any regression regardless. (See DQ-R1-020 update for the override of the original “defer the rename” guidance.)G-A
G-IAM-2CDK Template.fromStack() snapshot-equality unit test in root-dns-stack.test.ts (or in the construct’s own test) asserting the Root-account synthesis output is byte-identical before and after G-IAM-1. Fails closed on any Root regression.G-A
G-IAM-3Per-partition DNS-records role instantiation in partition-email stack: one role per partition’s stack, trust principal = iam.AccountPrincipal(account).withConditions({ ArnLike: { "aws:PrincipalArn": ${fqn}-* } }); resource scoping via allowedParentHostedZoneIds: [zone.hostedZoneId] to just that partition’s mail sub-zone (single-zone scope; per-partition least-privilege isolation — a dev pod cannot assume into the stage partition’s role, and the dev role cannot write to stage.ardamails.com). Permissions inherited from the construct: route53:ChangeResourceRecordSets, route53:ListResourceRecordSets, route53:ListHostedZonesByName. route53:GetChange intentionally omitted (requires arn:aws:route53:::change/* resource scope; Postmark verification is API-driven, no Route53 propagation wait needed). Exported as ${publishingPrefix}-API-EmailDnsProvisioningRoleArn for the operations Helm chart (-API- because the consumer is non-CDK; matches the image-storage.ts precedent where imagePresignRoleArnAPI is exported the same way).G-D

AllowCreatingNSRecordsRole construct (generalized — same construct serves Root and Phase 4 use cases). STS-chain pattern from image-asset-bucket.ts.

  • Runtime DNS-write code in the Email module → Phase 5b. The shape and frequency of these writes depend on DQ-R1-023 (per-tenant Sender Signature decision; pending Phase 5b planning).
  • route53:GetChange permission → omitted by design (see G-IAM-3 note).
  • Tightening allowedParentHostedZoneIds on the existing Root-account instantiation → future security-hardening project (out of project per goal.md).

The operations pod can decrypt rare ciphertexts whose k{versionId} predates AWSPREVIOUS (SDK cache-miss path per DQ-R1-019). Supports goal success criterion #4 (SM-fallback role).

FoundationSource
Per-partition pod IRSA role${publishingPrefix}-EksPodRoleArn
STS-chain trust-policy shapeSame as C-Runtime-DNS-Writes; mirrors image-asset-bucket.ts
GapDescription→ Group
G-IAM-4Per-partition EmailEncryptionKeyFallbackRole declared fresh in partition-email stack. Trust principal = account principal + ArnLike on {fqn}-*. Permission: secretsmanager:GetSecretValue on ${encryptionKeySecret.secretArn}* (full SM-secret ARN; the trailing wildcard tolerates the SM-appended random 6-character suffix — SM versions are selected at API call time via VersionId/VersionStage, not encoded in the resource ARN). Exported as ${publishingPrefix}-API-EmailEncryptionKeyFallbackRoleArn for the operations Helm chart.G-D

Trust-policy shape from C-Runtime-DNS-Writes; STS-chain pattern.

  • SDK-fallback consumer code in TokenCipher → Phase 5b.
  • Custom-stage SM version mounting (preemptive AWSPREVIOUS-1 retention) → out-of-project hardening.

Partition-mail state divergence between declared and observed (Postmark, DNS, AWS SM) is detected automatically and surfaced as a labelled GitHub issue. Supports goal success criterion #6.

FoundationSource
corporate-drift.yml workflowPhase 3; .github/workflows/corporate-drift.yml
tools/corporate-drift.ts driverPhase 3
Issue-on-failure pattern with labelsPhase 1 / Phase 3 conventions
Postmark + DNS probe helpersPhase 3’s corporate-drift driver
GapDescription→ Group
G-DRIFT-1New .github/workflows/runtime-platform-drift.yml. Daily cron. Failure-issue labels: drift + runtime-platform (per pre-design follow-up C3).G-E
G-DRIFT-2Driver script enumerating instances/Alpha001/{prod,demo}.ts + instances/Alpha002/{dev,stage}.ts. Asserts Postmark + DNS + cross-seam state for every partition Signature.G-E
G-DRIFT-3Minimal shared utility extraction from corporate-drift (per DQ-R1-018 — corporate-drift is not renamed). Both workflows source the extracted helpers.G-E

corporate-drift workflow shape; issue-creation pattern; Postmark + DNS probe logic (extracted to shared utilities).

  • 1Password vault-scope expansion → unnecessary (drift uses Postmark API + AWS SDK probes per pre-design follow-up B5 resolution; no per-partition 1P read needed).
  • Per-tenant drift → Phase 5b (extends runtime-platform-drift later).
  • corporate-drift rename → rejected (DQ-R1-018 keeps it; future runtime-platform drift unrelated to email plugs into runtime-platform-drift).

Operators provision and rotate partition mail through the existing amm.sh entry point, following its idempotency / security / pre-flight rules. Supports DQ-R1-022 and the scope bullet “Operator surfaces integrated into amm.sh.”

FoundationSource
amm.sh partition deploy scriptPre-Phase-4; already does op read + GHA ::add-mask:: + CFN NoEcho-parameter for 5 partition-scoped secrets
partitionSecrets.cfn.yaml deploy stepPre-Phase-4 canonical δ pattern
corporate-cli.tsPhase 3; includes idempotency, retry, redaction, conflict-check utilities
GapDescription→ Group
G-OP-1amm.sh partition-mail step (bash side, three direct calls in order): (i) op read 'op://Arda-{Env}OAM/Postmark/credential' to obtain the Postmark account-level token; (ii) npx ts-node tools/register-partition-mail-signature.ts <infrastructure> <partition> (Phase A; see G-OP-2); (iii) cdk deploy ${infrastructure}-${partition}-Email --parameters PostmarkAccountToken=... (Phase B). SecretValue.cfnParameter() lifecycle: amm.sh re-runs with an unchanged 1Password value are no-ops on the Postmark SM secret (CFN sees the parameter resolves to the same value). Rotation happens only when the 1Password item is updated first — never via out-of-band aws secretsmanager put-secret-value, which CDK would revert on the next deploy (intentional, per B2 — 1Password is the source of truth).G-C
G-OP-2tools/register-partition-mail-signature.ts — new TypeScript entry script (the Phase A imperative step, mirroring Phase 3’s corporate-cli Phase A pattern). Composes the extracted helpers from G-OP-4 to: register the {partition}.ardamails.com Postmark Sender Signature via the Account API (idempotent: list-then-create); capture the Postmark-issued DKIM selector / public key / Return-Path target; write them into cdk.context.json (committed). Runs before the cdk deploy of step G-OP-1.iii, not after — CDK reads context at synth time, so the Postmark API call must precede deploy. The script is invoked only by amm.sh; it is not a standalone operator-facing CLI (per DQ-R1-022’s “no partition-mail-cli” framing).G-C
G-OP-3GHA ::add-mask:: hygiene for the Postmark token (token from op read is not auto-masked; explicit mask required). Applied in amm.sh immediately after step G-OP-1.i, before either G-OP-1.ii or G-OP-1.iii.G-C
G-OP-4TypeScript helpers under tools/lib/ (or equivalent shared location) — extracted from corporate-cli per pre-design follow-up B3 (minimal cut: only what register-partition-mail-signature.ts actually needs). Candidates: 1Password SDK resolution wrapper, Postmark Account API client with retry / backoff, idempotent list-then-create helpers, output redaction, conflict-check. Consumed by both corporate-cli and register-partition-mail-signature.ts; not invoked directly from bash. amm.sh stays a thin orchestrator — there is no bash reimplementation of Postmark or 1P logic. Workspace-scoped — landed in PR #1 (G-A) so the helpers are available when G-OP-2’s register-partition-mail-signature.ts lands in PR #2. (DQ-R1-022 implementation route.)G-A
G-OP-5Encryption-key rotation operator runbook: aws secretsmanager update-secret against {fqn}-I-EmailEncryptionKey → ESO refreshes → operations pod’s TokenCipher reloads → lazy + coroutine migration mops up. Forward-pointer to email-server-key-encryption.md for the full mechanism.G-F

amm.sh’s op-read + GHA-masking pattern (existing for 5 secrets); corporate-cli’s idempotency / retry / redaction / conflict-check helpers (extracted, not reimplemented).

  • Standalone partition-mail-cli → rejected (DQ-R1-022).
  • Full corporate-cli refactor → rejected (B3 minimal cut).
  • Operator UI / dashboard → out of project (Postmark Console is the OAM surface).

Operators, Phase 5b authors, and future maintainers can understand the partition mail capability without re-deriving it from code or DQ-R1-NNN entries. Supports goal deliverable rows 11 + 11b.

FoundationSource
secret-delivery-pattern.md stubCommitted 2026-05-11 in this branch (current-system/oam/security/secret-delivery-pattern.md)
secrets-vault.md cross-linkWired to secret-delivery-pattern.md
operator-runbook.md (Phase 1)Updated 2026-05-11 with the Message Stream Discipline section
sending-email-via-free-kanban-tool.md (Phase 3)Updated 2026-05-11 (arda-prod approval status; maturity: review)
GapDescription→ Group
G-DOC-1Fill secret-delivery-pattern.md content with two worked examples: partitionSecrets.cfn.yaml (existing) and the Phase 4 Postmark token (δ.1). Upgrade frontmatter maturity: draftreview.G-F
G-DOC-2Per-partition mail pages in current-system/runtime/ (topology, partition zone structure, NS-delegation chain).G-F
G-DOC-3Multi-partition / multi-Signature updates in current-system/oam/postmark-service/ (account-to-partition mapping; the post-Phase-4 Sender Signature inventory).G-F
G-DOC-4V-PART-NNN verification entry in verification.md for the Root no-drift check (see §16).G-A (entry authored alongside the unit test)
G-DOC-5Current-system retrofit at project completion: reconcile new Phase-4 pages with the broader current-system/ trees once Phase 5b lands.Post-Phase-4 (project closeout)

Phase 3 OAM page conventions; Phase 3 operator-runbook structure.

  • Phase 5b docs (Email module, TokenCipher implementation pages) → Phase 5b.
  • Documentation site infrastructure changes → out of project.

Six Groups. Each Group has a self-contained test surface for isolated verification; the DAG (§13) is the only inter-Group sequencing constraint.

12.1 G-A — Workspace refactors + accessor

Section titled “12.1 G-A — Workspace refactors + accessor”
FieldValue
ScopeWorkspace-only (no per-partition fan-out)
ContainsG-IAM-1 (construct generalization + rename), G-IAM-2 (byte-equality unit test), G-POSTMARK-1 (accessor), G-DNS-5 (reserved-words list extension — workspace-scoped), G-OP-4 (TypeScript helpers under tools/lib/ — workspace-scoped, prerequisite for PR #2’s register-partition-mail-signature.ts), G-DOC-4 (verification entry)
Completes CapabilityNone directly. Unblocks G-D (construct generalized; Root no-drift gated) and G-C-for-dev (helpers + accessor in place so PR #2’s register-partition-mail-signature.ts can compile against them).
Test surface (isolated)(a) CDK Template.fromStack() snapshot-equality unit test for RootDnsStack synthesis output — fails closed on any Root regression. (b) Unit test for postmarkCredentialOpReference(partition) returning the four expected op://Arda-{Env}OAM/Postmark/credential references. (c) Reserved-words list test asserts prod, demo, dev, stage, kyle are reserved (plus arda baseline from Phase 3). (d) tools/lib/*.test.ts covers each extracted helper (Postmark client retry/backoff, op-resolver, redaction).
Acceptance criteria• Construct generalized with backwards-compatible default principal shape.
• Class renamed; file moved; import sites updated (compilation gate).
• Byte-equality unit test green.
• Accessor function shipped with unit test.
• Reserved-words list extended; tenant-slug validator rejects partition names.
tools/lib/ helpers extracted from corporate-cli (minimal cut per B3); both corporate-cli and the future register-partition-mail-signature.ts import from there; corporate-drift continues to function unchanged.
make pr-checks passes.
• Zero AWS changes (Synth-only PR).
AWS impactSynth-only
Deploy unitSingle PR; merge to main. No cdk deploy.
FieldValue
ScopePer-partition (fan-out begins)
ContainsG-DNS-1 through G-DNS-4 (per-partition resources). G-DNS-5 (reserved-words list extension) is workspace-scoped and lands in G-A — see § 12.1.
Completes CapabilityC-DNS-Authority (per partition; together with G-DNS-5 in G-A which provides the registry extension)
Test surface (isolated)Stack-level CDK Template assertions: zone declared with correct name; NS-write CR present; SPF + DMARC TXT contents match agreed strings. (The reserved-words assertion is in G-A’s test surface, not here.)
Acceptance criteriadig NS {partition}.ardamails.com @8.8.8.8 returns the partition zone’s nameservers via root delegation.
dig TXT {partition}.ardamails.com returns the SPF record.
dig TXT _dmarc.{partition}.ardamails.com returns the DMARC record.
AWS impactResource-touching (per partition)
Deploy unitBundled into the per-partition PR (see §13.2).

12.3 G-C — Per-partition Postmark + secrets + operator step

Section titled “12.3 G-C — Per-partition Postmark + secrets + operator step”
FieldValue
ScopePer-partition
ContainsG-POSTMARK-2, 3, 4 (and G-POSTMARK-5 for dev); G-KEY-1; G-OP-1, 2, 3 (G-OP-4 — TypeScript helper extraction — is workspace-scoped and lands in G-A)
Completes CapabilityC-Postmark-Sending (per partition; fully completed at dev rollout via G-POSTMARK-5 unlocking arda-nonprod). C-EmailKey-At-Rest (per partition). C-Operator-Surface deploy-time path.
Test surface (isolated)• Postmark Account API client mocks for Sender Signature idempotency (list-then-create).
• CDK Template assertions for both SM secrets (resource shape, names, RemovalPolicy.RETAIN).
• DKIM TXT + Return-Path CNAME shape assertions.
amm.sh dependency-injectable tests for op read + cdk deploy --parameters, with mocks for op CLI, Postmark client, AWS SDK.
Acceptance criteria• Sender Signature verified in Postmark Console (DKIM, Return-Path) for the partition.
aws secretsmanager describe-secret --secret-id {fqn}-I-EmailPostmarkAccountToken returns secret with DeletionPolicy: Retain.
aws secretsmanager describe-secret --secret-id {fqn}-I-EmailEncryptionKey returns secret with DeletionPolicy: Retain.
amm.sh partition-mail step re-runs idempotently (second run is a no-op).
• (dev partition only) Reply sent to Postmark Compliance #11236089 with verified-domain evidence.
AWS impactResource-touching (per partition; Postmark side also creates non-AWS state)
Deploy unitBundled into the per-partition PR (see §13.2).
FieldValue
ScopePer-partition
ContainsG-IAM-3, G-IAM-4
Completes CapabilityC-Runtime-DNS-Writes (per partition — four partitions = four completions). C-Fallback-Decryption (per partition).
Test surface (isolated)CDK Template assertions: each role’s trust-policy condition (ArnLike on {fqn}-*); each role’s Action + Resource statements. DNS-records role uses the generalized construct from G-A with partition-scoped allowedParentHostedZoneIds.
Acceptance criteria• Both roles exist in each partition’s Infrastructure account (aws iam get-role).
• Trust-policy condition matches the partition pod-role name prefix.
• Resource scoping verified: DNS-records role’s ChangeResourceRecordSets resources are limited to the partition’s mail hosted zone ARN; fallback role’s GetSecretValue resource is limited to {fqn}-I-EmailEncryptionKey*.
• Root no-drift verification (V-PART-NNN) passes — re-run after G-A merges, before any G-D deploy.
AWS impactResource-touching (per partition for both roles — each partition-email stack declares its own DNS-records role + fallback role)
Deploy unitBundled into the per-partition PR (see §13.2).
FieldValue
ScopeWorkspace-only
ContainsG-DRIFT-1, 2, 3
Completes CapabilityC-Drift-Detection
Test surface (isolated)Workflow YAML lints; driver script exercises a fixture asset list and produces the expected report shape; shared-utility unit tests (extracted helpers work for both workflows).
Acceptance criteria• Workflow runs on a scheduled cron tick (manual workflow_dispatch for the first verification).
• Fails closed: creates GitHub issue with drift + runtime-platform labels on a synthetic drift fixture.
corporate-drift continues to work unchanged after shared-utility extraction (regression check).
AWS impactNone
Deploy unitSingle PR; merge to main.
FieldValue
ScopeWorkspace-only
ContainsG-DOC-1, 2, 3; G-OP-5 (rotation runbook)
Completes CapabilityC-Documentation. C-Operator-Surface rotation path.
Test surface (isolated)make pr-checks passes (link integrity, lint, smoke tests). All page slugs resolve.
Acceptance criteriasecret-delivery-pattern.md upgraded from maturity: draft to maturity: review.
• At least one new page in current-system/runtime/ describing partition mail topology.
current-system/oam/postmark-service/ reflects multi-partition Signature inventory.
• Encryption-key rotation runbook exists and is linked from operator-runbook.md.
AWS impactNone
Deploy unitSingle PR; merge to main.

The diagram below shows the Phase 4 Implementation Groups and the dependencies between them. G-A (workspace refactors) is a hard prerequisite for the per-partition Groups G-C and G-D — the generalized IAM construct, the partition-aware accessor, and the extracted tools/lib/ helpers all originate there. The per-partition Groups G-B, G-C, G-D are bundled per partition and land sequentially via PRs #2–#5 (dev → stage → demo → prod per DQ-R1-021). G-E (drift workflow) and G-F (documentation) are soft-dependent on the partition Groups and land last.

PlantUML diagram

Edges:

EdgeTypeReason
G-A → G-BSoftamm.sh references the new accessor (G-POSTMARK-1), but amm.sh doesn’t run until G-C. G-A can land before or alongside G-B.
G-A → G-CHardG-C’s register-partition-mail-signature.ts (G-OP-2) imports the tools/lib/* helpers extracted in G-A (G-OP-4); G-C also calls postmarkCredentialOpReference() (G-POSTMARK-1). G-A must merge before G-C can compile.
G-A → G-DHardG-D’s DNS-records role instantiation uses the generalized construct from G-A. G-A must merge and Root no-drift must pass before any G-D deploy.
G-B → G-CHardG-C composes additional resources onto the partition-email stack G-B authors.
G-B → G-DHardG-D composes IAM resources onto G-B’s stack and references G-B’s hosted zone ARN for resource-scoping.
G-C ‖ G-DIndependentSame stack, different resource families; can be PR’d together or separately. Per §13.2, they are bundled.
G-C → G-ESoftDrift workflow probes the SM secrets and Postmark state landed in G-C. G-E can be authored alongside G-C; verification happens once G-C is live for at least one partition.
all → G-FSoftDocs cite all the implementations. G-F lands last.
#PRGroup(s)ScopeSequencing
1phase-4-G-AG-AWorkspaceLands first. Must merge before #3-#6. Root no-drift verification runs after merge, before #3 starts.
2phase-4-G-B-C-D-devG-B + G-C + G-DPartition: devPer DQ-R1-021, dev is first. Per-partition bundling: one PR carries DNS authority + Postmark/secrets + IAM for the partition. amm.sh rolls the partition forward post-merge. G-POSTMARK-5 (arda-nonprod unlock) lands here.
3phase-4-G-B-C-D-stageG-B + G-C + G-DPartition: stageAfter PR #2’s deploy is verified live.
4phase-4-G-B-C-D-demoG-B + G-C + G-DPartition: demoAfter PR #3.
5phase-4-G-B-C-D-prodG-B + G-C + G-DPartition: prodAfter PR #4.
6phase-4-G-EG-EWorkspaceCan land anywhere after PR #2 is live (dev provides enough state for drift to probe). Recommended after PR #2 to start exercising the workflow early.
7phase-4-G-FG-FWorkspaceLast. Documentation reflects what’s actually been built.

Total: 7 PRs. Per-partition rollback semantics: PR #N’s failure is contained — partitions deployed under PR #M (M < N) remain operational; partitions later in the rollout simply haven’t started.

Per-partition cdk diff discipline: Each per-partition PR (#2–#5) carries the cdk diff summary for that partition only. The diff is refreshed before merge if upstream PRs land between authoring and merge.

amm.sh is the only mechanism that creates Phase 4’s partition-mail resources end-to-end (CDK deploy + Postmark Account API calls + 1Password reads). The script gains its Phase 4 partition-mail step in G-C (G-OP-1..4); the code change lands as part of PR #2 alongside the dev deploy. Once PR #2 merges, amm.sh is ready to execute against any of the four active partitions; PRs #3–#5 do not modify the script — they only add the per-partition instance config and trigger another invocation.

EventTriggered byEffect
amm.sh partition-mail code lands on mainPR #2 merge (G-C-for-dev)The script now contains the new partition-mail step, three bash calls in order: (i) op read the Postmark account-level token (+ GHA ::add-mask::); (ii) npx ts-node tools/register-partition-mail-signature.ts <infrastructure> <partition> — Phase A: calls Postmark Account API to register the Sender Signature, writes the returned DKIM selector / Return-Path target into cdk.context.json; (iii) cdk deploy ${infrastructure}-${partition}-Email --parameters PostmarkAccountToken=… — Phase B: declarative deploy that reads context and emits DNS records + SM secrets + IAM roles. The code is partition-agnostic; the partition is the operator’s invocation argument. (Phase A precedes Phase B because CDK synth reads cdk.context.json — the Postmark API call must complete before deploy.)
First executionamm.sh for devOperator-initiated after PR #2 merges (or run from the PR branch before merge as a pre-merge verification)Creates dev.ardamails.com zone + NS-delegation + SPF/DMARC; populates both SM secrets; declares both IAM roles; registers the dev.ardamails.com Sender Signature on PostmarkNonProd. G-POSTMARK-5 fires here — the registration unlocks arda-nonprod account approval (Postmark ticket #11236089).
Subsequent executionsamm.sh for stage, demo, prodOperator-initiated after PRs #3, #4, #5 merge respectivelyEach invocation creates the equivalent resources for its partition. The amm.sh code is unchanged from PR #2; only the partition argument and the per-partition instance config differ. prod and demo (on PostmarkProd) have no external-approval prerequisite (the account is already approved per K-10 / 2026-05-11).
Rotation invocations (post-Phase 4)Operator-initiated whenever a 1Password Postmark-token value is updated or an encryption-key rotation runsThe same amm.sh step re-runs; the Postmark token’s SM secret is updated to match the new 1P value (CFN sees a different NoEcho parameter resolution); encryption-key rotation goes through the separate aws secretsmanager update-secret path documented in G-OP-5 (not amm.sh).

Readiness preconditions — all must hold before any partition amm.sh invocation:

PreconditionVerified by
PR #1 (G-A) mergedpostmarkCredentialOpReference(partition) accessor unit test green; generalized AllowCreatingNSRecordsRole construct unit test green
Root no-drift verification passedV-PART-NNN in verification.md (operator step; runs after PR #1 merge, before any partition deploy)
Per-partition PR (#2–#5) merged for the target partitionStack code + instance config on main
Partition’s Arda-{Env}OAM 1P vault contains Postmark/credential item with a valid account-level tokenOperator pre-flight: op read "$(postmarkCredentialOpReference dev)" returns a non-empty value
Operator has AWS SSO credentials for the partition’s Infrastructure accountaws sts get-caller-identity --profile <profile> matches Alpha001 (for prod / demo) or Alpha002 (for dev / stage)

amm.sh is not invoked during G-A (PR #1, code-only), G-E (PR #6, workflow YAML and driver scripts only), or G-F (PR #7, documentation only).

Each row is an evaluable, observable condition. A Capability is “ready” only when the criterion holds.

CapabilityReadiness criterion (evaluable)Met at end of
C-DNS-Authoritydig NS {partition}.ardamails.com @8.8.8.8 returns the partition zone’s nameservers via root delegation, for each of prod, demo, dev, stage.G-B-for-each-partition (full readiness after PRs #2–#5 deployed)
C-Postmark-SendingPostmark Console shows each {partition}.ardamails.com Sender Signature with DKIM verified and Return-Path verified, for both arda-prod and arda-nonprod. arda-nonprod account is approved by Postmark Support.G-C-for-dev (arda-nonprod unlock) + G-C-for-each-partition (per-partition completion)
C-EmailKey-At-Restaws secretsmanager describe-secret --secret-id {fqn}-I-EmailEncryptionKey returns secret with AWSCURRENT versionId and DeletionPolicy: Retain, for each partition. ESO ClusterSecretStore resolves the secret on a probe pod (Phase 4 verifies projection works; Phase 5b consumes the projected secret). Re-running amm.sh for a deployed partition with no code or 1P changes does not create a new SM versionId on {fqn}-I-EmailEncryptionKey (verifiable via describe-secret versionId comparison before/after a no-op amm.sh run; catches accidental generateSecretString config drift in future PRs).G-C-for-each-partition
C-Runtime-DNS-Writesaws iam get-role --role-name <DnsRecordsRoleName> returns the role with the expected trust policy (account principal + ArnLike on {fqn}-*) and resource-scoped Route53 permissions (single zone — that partition’s mail sub-zone only), for each partition (dev, stage in Alpha002; demo, prod in Alpha001).G-D for each partition (PRs #2–#5 — full readiness after PR #5)
C-Fallback-Decryptionaws iam get-role --role-name <EmailEncryptionKeyFallbackRoleName> returns the role with secretsmanager:GetSecretValue on {fqn}-I-EmailEncryptionKey*, for each partition.G-D-for-each-partition
C-Drift-Detectionruntime-platform-drift workflow has completed a successful scheduled run; a synthetic drift fixture produces a labelled GitHub issue.G-E (full readiness after at least one partition is live for the probes to find state)
C-Operator-Surfaceamm.sh partition-mail step runs idempotently for at least one partition; encryption-key rotation runbook exists at the documented path and is linked from operator-runbook.md.G-C-for-dev (deploy-time path) + G-F (rotation path)
C-Documentationsecret-delivery-pattern.md maturity: review; new pages in current-system/runtime/ describe partition mail topology; make pr-checks passes on the documentation repo.G-F

IDConcernWhere it belongs
O-1Per-tenant Postmark Sender SignaturesPhase 5b
O-2TokenCipher primitive (HKDF, AES-256-GCM, envelope codec)Phase 5a (common-module, general-purpose per B1)
O-3Backend ShopAccess/Email module in operationsPhase 5b
O-4Tightening allowedParentHostedZoneIds on the Root-account instantiationFuture security-hardening project (out of project per goal.md)
O-5kyle partition mail capabilityDeferred until partition resumes (DQ-R1-021)
O-6Apex SPF/DMARC on ardamails.comOut of project
O-7Automated AWS SM rotation via Rotation LambdaFuture operator decision; design accommodates per DQ-R1-019
O-8Standalone partition-mail-cliRejected (DQ-R1-022; amm.sh integration is the operator surface)

All design questions are resolved. Full text in ../../decision-log.md.

IDTopicOne-line resolution
DQ-R1-017Postmark Sender Signature granularityOne Signature per partition sub-zone; leaves inherit DKIM; per-tenant Signatures deferred to Phase 5b
DQ-R1-018corporate-drift rename and scopeKeep corporate-drift; add parallel runtime-platform-drift; share via reusable scripts / composite actions
DQ-R1-019Per-partition encryption-key derivationSingle SM secret per partition with native versioning; two-axis envelope a{N}.k{SM-VERSION-ID}; lazy + coroutine migration; SDK fallback (full design in email-server-key-encryption.md)
DQ-R1-020DNS-provisioning + SM-fallback IAM rolesTwo per-purpose roles; DNS-records via reuse of the existing AllowCreatingNSRecordsRole construct (generalized) with Root no-drift guard; fallback role fresh; both STS-chained
DQ-R1-021Order of partition rolloutdevstagedemoprod; kyle excluded
DQ-R1-022Operator CLI shapeIntegrate into amm.sh; share utilities with corporate-cli; no standalone partition-mail-cli
B1Phase 5a TokenCipher locationcommon-module, general-purpose encrypted-field utility (not email-specific)
B2Postmark account-token deploy-time deliveryδ.1 — NoEcho CFN parameter
B3amm.sh extraction scope from corporate-cliMinimal cut: only what amm.sh’s partition-mail step needs
B4kyle reservation registry mechanismExtend the Phase 3 mechanism used to reserve arda at the ardamails.com level
B5Cross-partition deploy gating in CIOperator-enforced via amm.sh; no tools/cdk-runner.js matrix change
C1CDK stack name${infrastructure}-${partition}-Email; immutable, locked at first deploy
C2DMARC reporting mailboxReuse dmarc-reports@arda.cards for all partitions
C3runtime-platform-drift cron + labelsDaily; labels drift + runtime-platform

16. Forward-references to specification.md and verification.md

Section titled “16. Forward-references to specification.md and verification.md”
ConcernCarries toNotes
NS-delegation TTL during rolloutverification.md (V-PART-NNN)Operator wait time between NS write and DKIM probe; depends on existing TTL settings in ardamails.com
Wrong-token failure mode in amm.shspecification.md + verification.mdDeploy-time serverinfo call to verify token authenticates against the right Postmark account before continuing
Cross-stack synthesis ordering (G-B → G-C/G-D wiring)specification.mdConcrete CDK plumbing — Fn.importValue vs addDependency
runtime-platform-drift scope pin (B5 / G-16 option a confirmed)specification.mdPostmark API + AWS SDK probe path; no 1P vault-scope change
Root no-drift verification (V-PART-NNN)verification.mdOperator-driven; runs after G-A merges, before any G-D deploy
Per-partition cdk diff surfacing patternspecification.md (operator workflow)Per partition, refresh PR description
Helm-values-injection path for -API- exportsspecification.mdHow the operations Helm chart (or amm.sh driving Helm) reads the six -API- exports per partition (PartitionMailZoneId, PartitionMailZoneName, EmailPostmarkAccountTokenArn, EmailEncryptionKeyArn, EmailDnsProvisioningRoleArn, EmailEncryptionKeyFallbackRoleArn) and threads them into chart values / ESO ExternalSecret definitions. Must be concrete: which script reads aws cloudformation list-exports, where the values land in values.yaml.

Copyright: (c) Arda Systems 2025-2026, All rights reserved