CloudFormation Resource Update Behavior Validator
Creates test stacks, analyzes CloudFormation events, compares actual vs documented update behavior, then confirms whether a resource property change triggers replacement rather than an in-place update. Use when: testing if a CFN property change causes resource replacement; investigating stack update behavior, "Update requires" documentation accuracy; validating whether a workaround (e.g. hash-based logical IDs) is actually necessary; questioning UpdateRequiresReplacement behavior for immutable properties; needing empirical evidence before an architectural decision involving CDK/CloudFormation stack updates.
npx skills add github:pantheon-org/tekhne --skill infrastructure--cfn--behavior-validatorPurpose
Empirically validate how CloudFormation handles specific resource property changes by deploying a controlled test stack, making a targeted change, and observing actual CFN events — then deciding whether workarounds are justified.
Mindset
Documentation is a hypothesis, not a fact: the “Update requires” value is maintained by hand and drifts from actual resource-provider behavior, and it never encodes interaction effects between properties on the same resource. Treat every rating as unverified until real CFN events back it up — never carry a workaround, or its removal, into production on a documentation read alone. A change CloudFormation applies in-place can still be disruptive underneath: a Lambda VPC change is rated “some interruption” but always forces ENI churn that shows up only in the ELASTIC_NETWORK_INTERFACE events, never on the Lambda resource’s own status line.
Decision framework:
- State the hypothesis before touching a stack — a test with no falsifiable prediction is not a test.
- Isolate the property. Every other variable must be held constant, or the result cannot be attributed to the one change under test.
- Watch the events, not the exit code. A successful
cdk deploydoes not tell you whether the result was an in-place update or a replacement; always read theResourceStatustransitions. - Repeat before trusting an ambiguous result. A handful of resource types are genuinely non-deterministic across runs; one clean result is a data point, not proof — a classic gotcha is treating a single successful in-place update as confirmation when the resource actually replaces on every third deploy.
When to use this skill:
- A CDK/CFN property change’s actual update behavior needs verification before shipping.
- A workaround (hash-suffixed logical IDs,
UpdateReplacePolicyoverrides, forced replacement) is proposed and its necessity is unconfirmed. - The team is deciding whether “Update requires: Replacement” for a property is still accurate on the current CloudFormation resource-provider version.
When NOT to use this skill:
- The property’s replacement behavior is already confirmed by a recent, repeatable test result documented for this exact resource type and CFN provider version — re-run only if the provider version changed.
- The change is trivial and reversible with no state to lose (e.g. adding a tag), where the cost of being wrong does not justify a dedicated test stack.
- Testing would touch a stateful production resource that cannot be safely replaced — route that decision through change management instead of an ad hoc validation stack.
Workflow
1. Research
- Find the resource’s CloudFormation reference page; note “Update requires” for the target property.
- Search GitHub (AWS CDK repo), Stack Overflow, and AWS re:Post for community reports of discrepancies.
- State a hypothesis: “Docs say Replacement — does CFN actually replace the resource?”
2. Design Minimal Test Stack
- Use a non-production, disposable environment.
- Isolate the single property under test; remove unrelated resources.
- Define observable success criteria (e.g. DELETE + CREATE events for the resource type).
// Example: minimal CDK stack parameterised via context
export class BehaviorTestStack extends cdk.Stack {
constructor(scope: Construct, id: string, props?: cdk.StackProps) {
super(scope, id, props);
// Add only the resource under test, driven by this.node.tryGetContext(...)
}
}
3. Execute Test
# 1. Deploy initial state
cdk deploy --require-approval never
# 2. Record resource ARNs / IDs, confirm any required manual steps (e.g. email confirmation)
# 3. Make the single property change, then redeploy
cdk deploy --require-approval never
# 4. Inspect CFN events — stop and debug if deployment fails before proceeding
aws cloudformation describe-stack-events \
--stack-name <stack-name> \
--query 'StackEvents[?ResourceType==`<ResourceType>`].[Timestamp,ResourceStatus,ResourceStatusReason]' \
--output table
Validation gates:
- If initial deployment fails → stop and fix before making any changes.
- If events show unexpected behavior → document immediately and abort further changes.
- If behavior is ambiguous → repeat the test to confirm repeatability.
4. Document Findings & Decide
## CloudFormation Behavior Test Results
- **Date / Region / CDK Version:**
- **Resource Type & Property Changed:**
- **AWS Docs Say:** "Update requires: ..."
- **What Actually Happened:** [UPDATE_IN_PLACE | REPLACEMENT | NO-OP | error]
- **CFN Events:** [paste relevant rows]
- **Matches Docs:** Yes / No
- **Workaround Needed:** Yes / No — Reasoning: ...
- **Code Changes:** [commit/PR link]
Update the code: implement or remove the workaround and add a comment citing this test.
Related Skills
cfn-template-compare— Compare deployed vs local templatesaws-cdk— General AWS CDK developmentterraform-validator— Similar testing for Terraform
Anti-Patterns
NEVER assume UPDATE_REQUIRES_REPLACEMENT from documentation without testing
- WHY: AWS documentation for resource property behavior is sometimes incorrect or lags behind API changes; only testing against an actual stack confirms actual replacement behavior.
- BAD: Trust the CloudFormation docs that say a property change is “No interruption” and skip testing.
- GOOD: Create a test stack and apply the change to observe actual behavior via stack events.
NEVER test behavior-changing updates on production stacks
- WHY: Replacement validation creates and deletes resources; testing on production risks unintended downtime or data loss.
- BAD: Test property change behavior directly on a prod stack to “save time”.
- GOOD: Use a dedicated test stack in a non-production account with realistic (but non-sensitive) configuration.
NEVER ignore UPDATE_ROLLBACK_FAILED stack status
- WHY: A stack in this state cannot be updated or deleted without manual intervention; document the recovery procedure whenever behavior testing triggers a rollback.
- BAD: Treat
UPDATE_ROLLBACK_FAILEDas a transient error and retry. - GOOD: Resolve the failed resource, then skip it explicitly so the rollback can complete:
aws cloudformation continue-update-rollback \
--stack-name <stack-name> \
--resources-to-skip <LogicalResourceId>
NEVER compare template drift without accounting for CDK synthesizer metadata
- WHY: CDK-synthesized templates include
aws:cdk:pathmetadata and synthesizer version fields that differ between environments but are not functional differences; filter these before comparing. - BAD: Flag every metadata field difference as drift.
- GOOD: Normalize templates by stripping CDK-specific metadata keys before comparison:
jq 'del(.Metadata."aws:cdk:path", .Metadata."aws:asset:path")' template.json > template.normalized.json
NEVER run a replacement test on a stateful resource without DeletionPolicy: Retain
- WHY: replacement deletes the original resource once the new one is
CREATE_COMPLETE; for RDS, DynamoDB, EFS, or any resource holding real data, that deletion is permanent. SetDeletionPolicy: Retain(andUpdateReplacePolicy: Retain) before the change, never after. - BAD: Trigger the property change on a stateful test resource with default deletion behavior.
- GOOD:
MyTestTable:
Type: AWS::DynamoDB::Table
DeletionPolicy: Retain
UpdateReplacePolicy: Retain
Properties:
# property under test goes here
NEVER treat a “No interruption” rating as proof of zero operational impact
- WHY: the interruption rating describes the stack update, not the infrastructure underneath. A Lambda VPC change is rated “some interruption” but always forces ENI churn that briefly leaves the function uninvokable — visible only as separate
ENIevents, never on the Lambda resource’s own status line. - BAD: Conclude “no interruption” means safe to deploy at any time.
- GOOD: Check the full event stream for auxiliary resources (ENIs, DNS records, target-group registrations) that carry impact the top-level rating hides.
References
| Script | Location | Purpose |
|---|---|---|
watch-cfn-events.sh |
./scripts/watch-cfn-events.sh |
Stream CFN events in real-time during deployment |
compare-resources.sh |
./scripts/compare-resources.sh |
Diff resource properties before and after deployment |
See EXAMPLES.md in this skill directory for a full walkthrough of an SNS email subscription endpoint change test.
Explicit NEVER/WHY/consequence triplets with side-by-side bad/good examples. Generic warnings score low — concrete failure modes with real impact (security, correctness, performance) score high.
Runtime validation via eval scenarios proving the skill actually changes agent behaviour. Requires evals/ directory, instructions.json, ≥3 scenarios, and ≥80% instruction coverage in summary.json.
Appropriate rigidity for the skill type: strict rules for critical/security skills, balanced steps for process skills, flexible options for tool skills. Mismatched calibration (too rigid or too loose) reduces score.
Expert-only knowledge the AI couldn't derive on its own — domain-specific patterns, production gotchas, decision frameworks, and non-obvious tool behaviour. High scores mean <5% redundancy with what the model already knows.
A clear philosophy plus numbered step-by-step workflows with explicit entry/exit points. Should answer: what is the core principle, how to execute it, and when (and when not) to apply it.
Rich activation keywords and trigger scenarios in the description so the skill fires when needed. Best descriptions read like an exhaustive list of the tasks and concepts that should invoke this skill.
Copy-paste-ready code, complete runnable examples, real file paths and commands. Pseudocode and abstract descriptions score low — concrete, executable content scores high.
SKILL.md as a <100-line navigation hub pointing to focused references/ files. Content should be lazy-loaded on demand, not front-loaded. Includes actionable 'When to Use' conditions per reference.
Proper frontmatter, single-task focus, activation keywords, and cross-harness portability. Skills must work across 40+ agentic harnesses without hardcoded paths or agent-specific references.
Explicit NEVER/WHY/consequence triplets with side-by-side bad/good examples. Generic warnings score low — concrete failure modes with real impact (security, correctness, performance) score high.
Runtime validation via eval scenarios proving the skill actually changes agent behaviour. Requires evals/ directory, instructions.json, ≥3 scenarios, and ≥80% instruction coverage in summary.json.
Appropriate rigidity for the skill type: strict rules for critical/security skills, balanced steps for process skills, flexible options for tool skills. Mismatched calibration (too rigid or too loose) reduces score.
Expert-only knowledge the AI couldn't derive on its own — domain-specific patterns, production gotchas, decision frameworks, and non-obvious tool behaviour. High scores mean <5% redundancy with what the model already knows.
A clear philosophy plus numbered step-by-step workflows with explicit entry/exit points. Should answer: what is the core principle, how to execute it, and when (and when not) to apply it.
Rich activation keywords and trigger scenarios in the description so the skill fires when needed. Best descriptions read like an exhaustive list of the tasks and concepts that should invoke this skill.
Copy-paste-ready code, complete runnable examples, real file paths and commands. Pseudocode and abstract descriptions score low — concrete, executable content scores high.
SKILL.md as a <100-line navigation hub pointing to focused references/ files. Content should be lazy-loaded on demand, not front-loaded. Includes actionable 'When to Use' conditions per reference.
Proper frontmatter, single-task focus, activation keywords, and cross-harness portability. Skills must work across 40+ agentic harnesses without hardcoded paths or agent-specific references.
Expert-only knowledge the AI couldn't derive on its own — domain-specific patterns, production gotchas, decision frameworks, and non-obvious tool behaviour. High scores mean <5% redundancy with what the model already knows.
A clear philosophy plus numbered step-by-step workflows with explicit entry/exit points. Should answer: what is the core principle, how to execute it, and when (and when not) to apply it.
Explicit NEVER/WHY/consequence triplets with side-by-side bad/good examples. Generic warnings score low — concrete failure modes with real impact (security, correctness, performance) score high.
Proper frontmatter, single-task focus, activation keywords, and cross-harness portability. Skills must work across 40+ agentic harnesses without hardcoded paths or agent-specific references.
SKILL.md as a <100-line navigation hub pointing to focused references/ files. Content should be lazy-loaded on demand, not front-loaded. Includes actionable 'When to Use' conditions per reference.
Appropriate rigidity for the skill type: strict rules for critical/security skills, balanced steps for process skills, flexible options for tool skills. Mismatched calibration (too rigid or too loose) reduces score.
Rich activation keywords and trigger scenarios in the description so the skill fires when needed. Best descriptions read like an exhaustive list of the tasks and concepts that should invoke this skill.
Copy-paste-ready code, complete runnable examples, real file paths and commands. Pseudocode and abstract descriptions score low — concrete, executable content scores high.
No eval scenarios available.
CloudFormation Behavior Validator - Testing Guide
Quick Start
Testing SNS Email Subscription Updates
This guide walks through testing whether CloudFormation properly handles SNS email subscription endpoint changes.
Prerequisites
- AWS CLI configured with appropriate credentials
- Access to non-production AWS environment
- Two email addresses you can access for testing
- CloudFormation stack deployed with SNS email subscription
Step-by-Step Testing Procedure
1. Capture Initial State
Before making any changes, capture the current resource state:
./scripts/compare-resources.sh \
<your-stack-name> \
<logical-resource-id>
Example:
./scripts/compare-resources.sh \
MyAppStack-Dev \
AlertEmailSubscription
This creates a snapshot in .context/cfn-resource-snapshots/
2. Start Event Monitoring
In a separate terminal, start watching CloudFormation events:
./scripts/watch-cfn-events.sh \
<your-stack-name> \
5
Example:
./scripts/watch-cfn-events.sh \
MyAppStack-Dev \
5
This will display events in real-time as they occur.
3. Make the Change
Update the email address in your configuration using your project’s method:
Option A: CDK Context Parameter
cdk deploy --context alertEmail="new-email@example.com"
Option B: Environment Variable
export ALERT_EMAIL="new-email@example.com"
cdk deploy
Option C: Update Configuration File
Edit your stack configuration file (e.g., cdk.json, .env, or stack properties):
{
"context": {
"alertEmail": "new-email@example.com"
}
}
Then deploy using your project’s deployment method:
cdk deploy
# OR
make deploy
# OR
npm run deploy
This creates a snapshot in .context/cfn-resource-snapshots/
2. Start Event Monitoring
In a separate terminal, start watching CloudFormation events:
./scripts/watch-cfn-events.sh \
ExampleMonitoringStack-ST \
5
This will display events in real-time as they occur.
3. Make the Change
Update the email address in your configuration:
Option A: Environment variable
export PROCESS_EMAIL="new-email@example.com"
make deploy
Option B: Update env file
Edit .env or relevant configuration file:
PROCESS_EMAIL=new-email@example.com
Then deploy:
make deploy
4. Observe CloudFormation Behavior
Watch the event monitor terminal. Look for:
✅ Expected (Replacement):
DELETE_IN_PROGRESS <YourSubscriptionLogicalId> AWS::SNS::Subscription
DELETE_COMPLETE <YourSubscriptionLogicalId> AWS::SNS::Subscription
CREATE_IN_PROGRESS <YourSubscriptionLogicalId> AWS::SNS::Subscription
CREATE_COMPLETE <YourSubscriptionLogicalId> AWS::SNS::Subscription
❌ Unexpected (No Change):
UPDATE_COMPLETE <YourSubscriptionLogicalId> AWS::SNS::Subscription
or no events at all for the subscription.
5. Verify Resource Changes
After deployment completes, capture the new state:
./scripts/compare-resources.sh \
<your-stack-name> \
<logical-resource-id>
Example:
./scripts/compare-resources.sh \
MyAppStack-Dev \
AlertEmailSubscription
DELETE_IN_PROGRESS ProcessAlertEmailSubscription AWS::SNS::Subscription DELETE_COMPLETE ProcessAlertEmailSubscription AWS::SNS::Subscription CREATE_IN_PROGRESS ProcessAlertEmailSubscription AWS::SNS::Subscription CREATE_COMPLETE ProcessAlertEmailSubscription AWS::SNS::Subscription
❌ **Unexpected (No Change):**
UPDATE_COMPLETE ProcessAlertEmailSubscription AWS::SNS::Subscription
or no events at all for the subscription.
### 5. Verify Resource Changes
After deployment completes, capture the new state:
```bash
./scripts/compare-resources.sh \
ExampleMonitoringStack-ST \
ProcessAlertEmailSubscription
The script will automatically compare with the previous snapshot and show:
- Whether Physical Resource ID changed (indicates replacement)
- Timestamp differences
- Full property diff
6. Verify Functional Behavior
Check email:
- New email address should receive confirmation request
- Click confirmation link
- Trigger an alert to verify emails arrive at new address
Check AWS Console:
- Navigate to SNS → Topics → Select the topic
- Check subscriptions list
- Verify old email is gone and new email is present
7. Document Results
Create a test results document:
mkdir -p .context/cfn-test-results
cat > .context/cfn-test-results/sns-subscription-endpoint-test-$(date +%Y%m%d).md << 'EOF'
# SNS Subscription Endpoint Change Test Results
## Test Details
- Date: $(date +%Y-%m-%d)
- Stack: <your-stack-name>
- Resource: <logical-resource-id>
- Change: Email endpoint from old@example.com to new@example.com
## CloudFormation Behavior
[Describe what happened - replacement/update/no-op]
## Physical Resource ID
- Before: [paste from snapshot]
- After: [paste from snapshot]
- Changed: Yes/No
## Functional Verification
- Confirmation email received: Yes/No
- Old email still receives alerts: Yes/No
- New email receives alerts after confirmation: Yes/No
## Conclusion
[Does the hash pattern provide value or is CloudFormation behavior sufficient?]
## Decision
[Keep hash pattern / Remove hash pattern / Not applicable]
## Artifacts
- Before snapshot: [filename]
- After snapshot: [filename]
- CloudFormation events: [paste key events]
EOF
Interpreting Results
Scenario A: CloudFormation Replaced the Subscription
Observations:
- Physical Resource ID changed
- DELETE and CREATE events in CloudFormation
- New confirmation email sent
Conclusion: CloudFormation correctly handles endpoint changes via replacement. Hash pattern is NOT needed.
Action: Remove hash from subscription IDs to simplify code.
Scenario B: CloudFormation Updated In-Place
Observations:
- Physical Resource ID stayed the same
- UPDATE event (or no event) in CloudFormation
- No new confirmation email
Conclusion: CloudFormation doesn’t properly handle email changes. Hash pattern IS needed.
Action: Fix hash implementation to use correct email per subscription.
Scenario C: CloudFormation Did Nothing
Observations:
- No events for the subscription resource
- Physical Resource ID unchanged
- No confirmation email
Conclusion: CloudFormation failed to detect the change. Hash pattern IS needed.
Action: Fix hash implementation to use correct email per subscription.
Troubleshooting
“Stack not found” error
- Verify stack name is correct (check CloudFormation console)
- Ensure you’re in the correct AWS region (check AWS_REGION or –region flag)
- Check AWS CLI credentials (
aws sts get-caller-identity)
Events not appearing
- Increase watch interval (try 10 seconds)
- Check if deployment actually started (
aws cloudformation describe-stacks --stack-name <name>) - Verify IAM permissions to describe stack events
Can’t see resource details
- Resource might not exist yet (first deployment)
- Check logical resource ID spelling (case-sensitive)
- Verify resource type is correct in CloudFormation template
Cleanup
After testing, clean up snapshots:
rm -rf .context/cfn-resource-snapshots/
rm -rf .context/cfn-test-results/
Or keep them for reference and version control them.
Related Documentation
- SKILL.md - Full skill documentation
- AWS CloudFormation Update Behaviors
- AWS::SNS::Subscription Reference