Phase 2 -- Root Updates -- Specification
The contract for Phase 2 implementation. Each task lists its scope, file targets, and a STOP point where the implementer pauses for review before proceeding.
This specification is derived from requirements.md and analysis.md. The verification regime is in verification.md. The cross-phase exports Phase 2 produces are catalogued in exports.md.
1. Working agreements
Section titled “1. Working agreements”1.1 Skill set in scope
Section titled “1.1 Skill set in scope”typescript-codingskill — TypeScript style for the renamed stack and the newinstances/Root/dns.tsfile.cdk-infrastructureskill — CDK construct conventions and the CFN stack-name immutability rule.unit-tests-infraskill — CDKTemplate-matcher unit tests.
1.2 CFN stack-name immutability
Section titled “1.2 CFN stack-name immutability”The CDK id argument passed to the RootDnsStack constructor must remain the literal string "RootConfiguration". Any change to that argument forces CloudFormation to delete and recreate the stack, destroying the production hosted zones and the IAM role every partition’s NS-delegation pattern depends on. An inline source-code comment immediately above the constructor call documents the constraint. This rule is restated for emphasis in ../phases.md § Phase 2 and is the highest-risk concern in this phase.
1.3 Out of scope (restated)
Section titled “1.3 Out of scope (restated)”Per requirements.md § Out of scope of Phase 2:
- The NS-delegation entry for
arda.ardamails.com— written by Phase 3 (Corporate). - The
ardareserved-words update — belongs to Phase 3. - Per-partition mail sub-zones and their NS delegations — belong to Phase 4.
- Tightening of
AllowCreatingNSRecordsRole.allowedParentHostedZoneIds— not part of this project. - Extraction of the IAM role to a
RootSecurityStack— settled byDQ-013.
2. Tasks
Section titled “2. Tasks”Task 1: Rename apps/rootConfiguration/ to apps/Root/
Section titled “Task 1: Rename apps/rootConfiguration/ to apps/Root/”Goal: align the app folder name with the rev1 PascalCase instance-group convention without disturbing the deployed CFN stack.
Scope:
- Rename the folder
src/main/cdk/apps/rootConfiguration/tosrc/main/cdk/apps/Root/. Usegit mvso history is preserved. - Rewrite any in-repo imports that reference the old path. Since the files inside (
r53-zones.ts,live-url.ts) are CDK app entry points, expect zero or very few such imports; check exhaustively withgrep -rn "apps/rootConfiguration"before declaring done. - Do not edit the file contents of
r53-zones.tsorlive-url.tsin this task; that’s Task 2.
File targets:
- Move:
src/main/cdk/apps/rootConfiguration/{r53-zones,live-url}.ts→src/main/cdk/apps/Root/{r53-zones,live-url}.ts.
STOP — review after Task 1: confirm git status shows only the rename (no file-content modifications). npm run build should still succeed at this point because the stack class is still named RootConfigurationStack; only the entry-file path has moved.
Task 2: Rename RootConfigurationStack → RootDnsStack and update entry points
Section titled “Task 2: Rename RootConfigurationStack → RootDnsStack and update entry points”Goal: align the stack class with its actual concern (DNS) while preserving the published CFN stack name.
Scope:
-
Rename
src/main/cdk/stacks/root/root-configuration-stack.tstosrc/main/cdk/stacks/root/root-dns-stack.ts(usegit mv). -
Inside the file, rename the class
RootConfigurationStacktoRootDnsStack. Update the constructor’s docstring if it names the old class. -
Update
apps/Root/r53-zones.ts(andapps/Root/live-url.tsif it instantiates the stack):-
Update the import path to the new file name.
-
Update the type / class reference to
RootDnsStack. -
Leave the third positional argument as
"RootConfiguration"(this is the CDKidthat becomes the CFN stack name). Add an inline single-line comment immediately above the call that reads exactly:// CFN stack name MUST remain "RootConfiguration" -- changing it would// force CloudFormation to delete and recreate the stack.
-
-
Update any other in-repo imports of
RootConfigurationStackor the old file path.
File targets:
- Move + edit:
src/main/cdk/stacks/root/root-configuration-stack.ts→root-dns-stack.ts(with class rename). - Edit:
src/main/cdk/apps/Root/r53-zones.ts(import path, class name, inline comment). - Edit:
src/main/cdk/apps/Root/live-url.ts(only if it imports the stack class; review first).
STOP — review after Task 2: a fresh cdk synth of apps/Root/ against a non-prod environment must produce a CloudFormation template whose top-level StackName (or AWS metadata) reads RootConfiguration. npm run build and npm run lint must pass.
Task 3: Add instances/Root/dns.ts declarative configuration
Section titled “Task 3: Add instances/Root/dns.ts declarative configuration”Goal: crystallise the rev1 declarative instances/<InstanceGroup>/<asset>.ts convention for the Root instance group.
Scope:
- Create
src/main/cdk/instances/Root/directory. - Create
src/main/cdk/instances/Root/dns.tsexporting:- The set of zone-name constants the Root app declares (
app.arda.cards,io.arda.cards,auth.arda.cards,assets.arda.cards,ardamails.com). Reuse the prefixes fromplatform/ari-configuration.tsfor thearda.cardsfamily. - An
expectedExportsobject naming the CloudFormation export names this instance produces (matchingRootDnsStack.exportDefinition).
- The set of zone-name constants the Root app declares (
- Update
apps/Root/r53-zones.tsto import frominstances/Root/dns.tsinstead of using inline literals (where the declarative pattern dictates — this may be minimal in Phase 2 if the existing app file doesn’t have many literals to extract; do not refactor beyond what’s needed to makeinstances/Root/dns.tsthe source of truth for the newardamails.comzone).
File targets:
- New:
src/main/cdk/instances/Root/dns.ts. - Edit:
src/main/cdk/apps/Root/r53-zones.ts(limited; primarily to thread theardamails.comzone through from the declarative config).
STOP — review after Task 3: npm run build and npm test pass. cdk synth for apps/Root/ produces the expected resource set (existing zones + new ardamails.com zone).
Task 4: Add ardamails.com PublicHostedZone and its export
Section titled “Task 4: Add ardamails.com PublicHostedZone and its export”Goal: declare the mail-root hosted zone in the Root account and expose its zone ID to downstream stacks.
Scope:
- In
RootDnsStack, instantiate a newr53.PublicHostedZone(this, "ArdamailsZone", { zoneName: "ardamails.com" }). - Extend the stack’s
Builtinterface with a newardamailsZone: stringfield (the zone ID). - Extend the stack’s
exportDefinitionwith a newardamailsZoneentry whoseexportNameis"arda-ardamails-zone"and whose description is"The Hosted Zone Id for the ardamails.com mail-root zone". - Wire the new field into the
publish()method. - Confirm via
cdk synththat the resulting template includes aAWS::Route53::HostedZoneforardamails.com.and anAWS::CloudFormation::Outputforarda-ardamails-zone.
File targets:
- Edit:
src/main/cdk/stacks/root/root-dns-stack.ts.
STOP — review after Task 4: cdk diff against the deployed Root stack shows only an additive Outputs.ardaArdamailsZone and an additive Resources.ArdamailsZone. No deletions or replacements of existing resources.
Task 5: Update deploy-root.sh for the renamed app folder
Section titled “Task 5: Update deploy-root.sh for the renamed app folder”Goal: keep the deploy entry point working after the rename.
Scope:
- In
deploy-root.shline 56, changesrc/main/cdk/apps/rootConfiguration/r53-zones.tstosrc/main/cdk/apps/Root/r53-zones.ts. Path-only edit; no other change to the script.
File targets:
- Edit:
deploy-root.sh.
STOP — review after Task 5: a dry-run invocation (npx cdk synth ... substituting the same --app argument the script uses) succeeds.
Task 6: Patch phases.md and add DQ-R1-006
Section titled “Task 6: Patch phases.md and add DQ-R1-006”Goal: align the project-level documentation with the Phase 2 / Phase 3 ownership split for cross-zone NS delegations.
Scope:
- In
../phases.md:- Phase 2 deliverables table: remove the row “NS-delegation for
arda.ardamails.com”. Replace with a row “ardamails.comzone declaration” pointing atRootDnsStack. Drop the “gated to fire only when Phase 3 has provisioned the Corporate zone” language. - Phase 2 exit criteria: remove the parenthetical “(after Phase 3 lands the zone — this exit criterion gates the joint state, but Phase 2 itself only adds the forward declaration)”. The dig assertion belongs to Phase 3.
- Phase 3 deliverables table: add a new row “NS-delegation for
arda.ardamails.comwritten intoardamails.comviaWriteNSRecordsToUpstreamDns(Corporate stack)” so the ownership is explicit.
- Phase 2 deliverables table: remove the row “NS-delegation for
- In
../decision-log.md:- Add the row
DQ-R1-006to the decision table. - Add the section
### DQ-R1-006: Locus of Cross-Zone NS-Delegation Writesunder the Round R1-Phase1 heading (or a Round R1-Phase2 heading if cleaner — author’s discretion at write time, with a brief rationale in the section). - Add the entry to the Summary table at the bottom.
- Add the row
File targets:
- Edit:
documentation/src/content/docs/roadmap/in-progress/email-integration/phases.md. - Edit:
documentation/src/content/docs/roadmap/in-progress/email-integration/decision-log.md.
STOP — review after Task 6: make pr-checks passes.
Task 7: Add CHANGELOG entries
Section titled “Task 7: Add CHANGELOG entries”Goal: every PR to a protected branch carries a CHANGELOG.md entry.
Scope:
- Documentation repo: add an entry under a new
[0.30.0]heading with### Addedlisting the five Phase 2 planning artefacts, thephases.mdpatch, and theDQ-R1-006decision-log entry. - Infrastructure repo (when implementation lands): add an entry under a new
[2.29.0]heading with### Changedlisting the renames and### Addedlisting theardamails.comzone + new export. The infrastructure CHANGELOG entry is not part of the documentation PR; it lands with the Phase 2 implementation PR.
File targets:
- Edit:
documentation/CHANGELOG.md(this PR). - Edit (later):
infrastructure/CHANGELOG.md(Phase 2 implementation PR).
3. Execution sequence
Section titled “3. Execution sequence”Tasks 1 through 5 land on the infrastructure side and are executed in order. Each Task’s STOP point gates entry to the next. Task 6 lands on the documentation side; Task 6 may be performed in parallel with Tasks 1-5 because the patch is text-only and does not depend on the implementation. Task 7 (CHANGELOG) is the last action before opening either PR.
A single-engineer execution can complete the work; if the team chooses to parallelise, the natural split is along repository boundaries (one agent on infrastructure for Tasks 1-5, one on documentation for Task 6).
4. Out of scope of this specification
Section titled “4. Out of scope of this specification”Restated for clarity; identical to requirements.md § Out of scope of Phase 2.
- NS-delegation entry for
arda.ardamails.com. - Reserving
ardain the reserved-words list. - Per-partition mail sub-zones.
- Tightening
allowedParentHostedZoneIds. - Extraction of the IAM role.
5. Open Questions and Decisions
Section titled “5. Open Questions and Decisions”Phase 2 has no open questions on the date this specification is written. The decision that resolved the Phase 2 / Phase 3 ownership split is captured in DQ-R1-006.
If implementation surfaces an OQ, record it here with a recommendation, then resolve to a DQ-R1-NNN entry in decision-log.md per the convention introduced in architecture-overview.md § 10.
| # | Question | Options | Recommendation | Decision |
|---|---|---|---|---|
| (none open) | — | — | — | — |
6. References
Section titled “6. References”analysis.md— current-state assessment.requirements.md— numbered requirements.verification.md— test catalogue.exports.md— downstream contracts.../goal.md— project intent.../architecture-overview.md— system architecture.../phases.md— phase plan, with Phase 2 / Phase 3 patches in this round.../decision-log.md— decisions includingDQ-R1-006.
Copyright: © Arda Systems 2025-2026, All rights reserved