# Scenario Coverage Matrix

<!-- AUTO-GENERATED by scripts/build-scenario-coverage-matrix.ts. Do not hand-edit. -->

Run `vp run scenario-coverage` to regenerate.

**92 / 92 canonical scenarios** have at least one integ fixture exercising them. **194 / 287 integ fixtures** carry a `.scenarios.json` sidecar (with 0+ tags); the rest are un-annotated and contributor-reviewed below.

## How this is computed

Each `tests/integration/<fixture>/.scenarios.json` sidecar declares which canonical real-AWS regression patterns the fixture exercises. The canonical taxonomy lives in [scripts/build-scenario-coverage-matrix.ts](../scripts/build-scenario-coverage-matrix.ts) as `KNOWN_SCENARIOS` — sidecar tags outside the taxonomy are rejected at parse time so typos surface immediately.

**Sidecar shape**:

```json
{
  "scenarios": ["vpc-lambda-eni-release", "nat-gateway-cleanup"]
}
```

Empty `[]` means "intentionally no canonical scenario applies to this fixture" (per-service smoke tests). Absent file means "not yet annotated" — surfaced in the un-annotated section below.

This report is a visibility tool, not a commit-time gate. Many cdkd fixtures legitimately exercise no canonical scenario, and forcing per-commit annotation would add friction without proportional value. Contrast with the provider-coverage matrix ([docs/integ-coverage.md](integ-coverage.md)) which IS gated because the "is every registered SDK Provider exercised?" question has a structural answer.

## Orphan scenarios

_None._ Every canonical scenario has at least one integ fixture tagged with it.

## Per-scenario coverage (92 scenarios)

| Scenario | Description | Integ Fixture(s) |
|---|---|---|
| `apigateway-cors-preflight` | API Gateway CORS preflight (OPTIONS) handling — CDK auto-generates `Method` with both Integration.IntegrationResponses and MethodResponses arrays. | [`apigateway`](../tests/integration/apigateway/) |
| `auto-import-cfn-generated-name` | `cdkd import` AUTO mode (no `--resource`, no `--migrate-from-cloudformation`) adopting a resource whose physical name CloudFormation GENERATED, after an upstream `cdk deploy`. Pins issue #1128: auto mode resolves ids by the template name property, then an `aws:cdk:path` tag walk that CANNOT match on real AWS (AWS rejects `aws:`-prefixed tag writes; CloudFormation keeps the value in template `Metadata` without promoting it to a tag), so a CFn-generated name returned `not found` until auto mode learned to consult `DescribeStackResources`. The fixture deliberately sets NO explicit physical name and passes NO override flag — both pre-existing import integs pass one of those and therefore never exercised this path, which is why the defect survived four rounds of #1091 tag-walk work. | [`import-auto-mode`](../tests/integration/import-auto-mode/) |
| `auto-import-composite-physical-id` | `cdkd import` AUTO mode adopting a resource whose cdkd physicalId is a COMPOSITE (`<databaseName>|<tableName>`) while CloudFormation's is a single bare segment (the table name). Pins issue #1651, the sibling of #1128 one layer down: #1128 fixed the RESOLUTION of a CFn-generated id, this is the provider REJECTING an id auto mode had already resolved — `importTable` split the bare form on `|`, found no second segment, and returned `not found` without calling AWS, so every `cdk deploy`-managed `AWS::Glue::Table` was unadoptable while the error told the user to pass the id it had just refused. The fixture renders `DatabaseName` as a `Ref` to the sibling database (what CDK emits, and the reason a bare table name can be paired with a database at all — `AWS::Glue::Database`'s CFn physicalId IS the database name, so the overrides map resolves the Ref to a literal before `provider.import()` runs), asserts CloudFormation's reported id carries no `|` before relying on it, and asserts the ADOPTED id is the COMPOSITE — recording CFn's bare name would look like success while leaving a state row that update / delete / getAttribute / readCurrentState cannot split. | [`import-auto-mode`](../tests/integration/import-auto-mode/) |
| `cc-api-getatt-enrichment-elasticache-replicationgroup` | CC-API attribute enrichment for `AWS::ElastiCache::ReplicationGroup` (no SDK provider): `Fn::GetAtt(<RG>, PrimaryEndPoint.Address / ReaderEndPoint.* / ConfigurationEndPoint.* / ReadEndPoint.Addresses)` must resolve to the real Redis endpoint via DescribeReplicationGroups, not fall through to the physicalId (the RG id). | [`elasticache-replicationgroup-getatt`](../tests/integration/elasticache-replicationgroup-getatt/) |
| `cc-api-getatt-enrichment-opensearch-domain` | CC-API attribute enrichment for `AWS::OpenSearchService::Domain` (no SDK provider): `Fn::GetAtt(<Domain>, DomainEndpoint / Arn)` must resolve to the real `*.es.amazonaws.com` endpoint / `arn:aws:es:...:domain/...` ARN via DescribeDomain, not fall through to the physicalId (the domain name). | [`opensearch-domain-getatt`](../tests/integration/opensearch-domain-getatt/) |
| `cc-api-getatt-enrichment-redshift-cluster` | CC-API attribute enrichment for `AWS::Redshift::Cluster` (no SDK provider): `Fn::GetAtt(<Cluster>, Endpoint.Address / Endpoint.Port)` must resolve to the real Redshift endpoint via DescribeClusters, not fall through to the physicalId (the cluster id). | [`redshift-cluster-getatt`](../tests/integration/redshift-cluster-getatt/) |
| `cdk-defensive-vpc-deps-relax` | CDK-defensive route DependsOn relaxation for VPC Lambda parallelization. | [`bench-cdk-sample`](../tests/integration/bench-cdk-sample/) |
| `cdkd-asset-storage` | cdkd-owned asset storage lifecycle against real AWS: `cdkd bootstrap` creates the asset bucket + container repo + per-region marker (default or custom `--asset-bucket` / `--container-repo` names), deploy-time asset-mode detection + publish redirection into the marker-named storage, and `cdkd bootstrap --destroy` marker-driven teardown with zero residue (issues #1002 / #1007 / #1010 / #1011). | [`asset-auto-create`](../tests/integration/asset-auto-create/)<br>[`asset-bootstrap`](../tests/integration/asset-bootstrap/)<br>[`asset-migration`](../tests/integration/asset-migration/)<br>[`gc-custom-asset-names`](../tests/integration/gc-custom-asset-names/) |
| `cdkd-asset-storage-import` | Import-driven adoption into a cdkd-assets region against real AWS (issue #1652): a stack deployed by the UPSTREAM `cdk deploy` (so AWS holds `cdk-<qualifier>-assets-*` everywhere, including the `AWS::IAM::Policy` that `s3deploy.BucketDeployment` grants on the asset bucket) is adopted with `cdkd import --migrate-from-cloudformation`; state must record the PRE-rewrite `cdk-*` values, `cdkd diff` must report a real UPDATE on that policy (pre-fix it classified NO_CHANGE because the rewrite reached `state.properties`), and the post-import `cdkd deploy` must leave the LIVE policy document naming the cdkd asset bucket. | [`asset-migration`](../tests/integration/asset-migration/) |
| `cdkd-gc` | `cdkd gc` garbage-collection precision against real AWS: whole-bucket state-file reference scan keeps every referenced asset, an unreferenced seeded object plus an unreferenced seeded ECR image are the only deletion candidates, `--dry-run` deletes nothing, `--older-than` age guard honored (issue #1012). Since issues #1792 / #1793 the ECR half is DISCRIMINATING rather than a re-run of the plain path: two live images are referenced only through WIDENED host forms — an UPPER-cased host carrying an UPPER-cased digest (collected yet unmatchable against ECR lower-case digests before the insert-time fold, so the live image was deleted) and the dual-stack FIPS `<acct>.dkr-ecr-fips.<region>.on.aws` form the grammar had missed entirely — and both must SURVIVE the run, since a missed reference deletes irreversibly. | [`gc-custom-asset-names`](../tests/integration/gc-custom-asset-names/) |
| `cfn-fallback-cross-stack` | CloudFormation fallback for cross-stack references (issue #1697): a cdkd-deployed consumer references a producer stack managed by CloudFormation ONLY (no cdkd state record) — `Fn::ImportValue` via the `ListExports` fallback AND `Fn::GetStackOutput` via the `DescribeStacks` outputs fallback — plus the weak-reference contract (no imports[]/outputReads[] recorded) and the `--no-cfn-fallback` opt-out failing at resolve time. | [`cross-stack-cfn-fallback`](../tests/integration/cross-stack-cfn-fallback/) |
| `cfn-macro-expansion` | CloudFormation macro / `Fn::Transform` expansion via transient CFn changeset round-trip (SAM, AWS::Include, AWS::LanguageExtensions, custom macros). See `docs/design/463-cfn-macros.md`. | [`macro-expansion`](../tests/integration/macro-expansion/) |
| `cloudfront-oai-attribute-enrichment` | CloudFront OAI `S3CanonicalUserId` attribute enrichment (the attribute is not on `GetCloudFrontOriginAccessIdentity` directly). | [`s3-cloudfront`](../tests/integration/s3-cloudfront/) |
| `conditions-and-if` | CloudFormation Conditions section + resource-level `Condition:` key + `Fn::If` / `Fn::Equals` / `Fn::And` / `Fn::Or` / `Fn::Not` evaluated by cdkd itself. Two deploys flip a CDK-context-driven CfnParameter Default so the SAME stack is asserted in both settings: condition-gated resource creation (PRESENT vs ABSENT on AWS), `Fn::If` property + tag branch values reaching AWS, and `Fn::If` -> `AWS::NoValue` genuinely OMITTING a property. | [`conditions-and-if`](../tests/integration/conditions-and-if/) |
| `conditions-update-semantics` | Harder CloudFormation-Conditions-on-UPDATE semantics beyond the simple flip in `conditions-and-if` (which surfaced #840). A CDK-context phase flip (-c phase=a|b) redeploys the SAME stack in place and asserts: a resource that MOVES gating conditions (IsPhaseA-gated -> condition-false -> DELETED) and its reverse (IsPhaseB-gated absent -> CREATED); `Fn::If` -> `AWS::NoValue` REMOVING a nested property block (SQS RedrivePolicy) on an in-place UPDATE (same physical id, not a replacement); a condition-gated OUTPUT present vs absent in cdkd state outputs; a `DependsOn` to a condition-EXCLUDED resource being dropped (the depender still deploys); and a `Ref` to a condition-excluded resource living inside another condition-excluded resource (both pruned together, no dangling-ref crash). | [`conditions-update-2`](../tests/integration/conditions-update-2/) |
| `cross-cutting-deploy-destroy` | Broad real-AWS regression set (39+ resource VPC+NAT+CF+Lambda+SQS or comparable breadth). Refreshes the integ-broad gate. | [`bench-ccapi`](../tests/integration/bench-ccapi/)<br>[`bench-cdk-sample`](../tests/integration/bench-cdk-sample/)<br>[`bench-sdk`](../tests/integration/bench-sdk/)<br>[`full-stack-demo`](../tests/integration/full-stack-demo/)<br>[`lambda`](../tests/integration/lambda/)<br>[`microservices`](../tests/integration/microservices/)<br>[`multi-resource`](../tests/integration/multi-resource/) |
| `custom-resource-async-poll` | Custom Resource backed by Lambda + cfn-response via S3 pre-signed URL polling. | [`cloudfront-function-url`](../tests/integration/cloudfront-function-url/)<br>[`custom-resource-provider`](../tests/integration/custom-resource-provider/)<br>[`destroy-interrupt`](../tests/integration/destroy-interrupt/)<br>[`vpc-lambda-cr-race`](../tests/integration/vpc-lambda-cr-race/) |
| `custom-resource-getatt-data` | Custom Resource response `Data` consumed via `Fn::GetAtt(CR, 'Data.<key>')` / `Fn::GetAtt(CR, '<key>')` into ANOTHER resource's property (e.g. an SSM Parameter Value) — the fragile CR response-Data attribute path (#756 / #804: CR attributes only exist after the CR Lambda runs). Asserts the dependent's on-AWS value equals the value the CR handler returned, across multiple Data keys + an explicit dependent->CR dependency. A second custom resource carries the `NoEcho: true` arm (issue #2274) through the SIMPLE-HANDLER response shape, asserting both directions at once: the dependent's live SSM value is the real token, while the CR's `attributes`, the dependent's `properties`, `state.outputs` and the whole state blob hold none of it -- with the non-`NoEcho` resource above as the in-fixture negative control. | [`custom-resource-getatt-data`](../tests/integration/custom-resource-getatt-data/) |
| `deep-getatt-chain-resolution` | Long GetAtt chain where each resource POST-CREATE attribute (ARN / generated name only known after the AWS create call) feeds the next resource property, spanning a SDK + CC-API type mix. A wrong / late attribute resolution on either path (SDK `attributes` write or CC-API stored attributes + `constructAttribute` fallback) is pinpointed by the failing link. Critical hop: an unregistered CC-API type (`AWS::CloudWatch::CompositeAlarm`) whose `Arn` feeds downstream SDK-resource properties (issue: deep-getatt-chains fixture). | [`deep-getatt-chains`](../tests/integration/deep-getatt-chains/) |
| `deletion-policy-retain` | DeletionPolicy: Retain skip on destroy (schema v5 recorded value wins over template). | [`deletion-policy-retain`](../tests/integration/deletion-policy-retain/) |
| `deletion-policy-snapshot` | DeletionPolicy / UpdateReplacePolicy: Snapshot honored on delete (issues #1352 / #1354 / #1357): final EBS snapshot created + waited to completed on the deploy engine template-removal DELETE path, on the REPLACEMENT delete site (an immutable AvailabilityZone change under --force-stateful-recreation, unblocked by the #1356 EC2 Volume classification), and on the destroy-runner path; --skip-final-snapshot opt-out. | [`deletion-policy-snapshot`](../tests/integration/deletion-policy-snapshot/) |
| `deletion-policy-snapshot-heavy` | DeletionPolicy: Snapshot pre-delete machinery for the CC-routed name-keyed snapshot APIs (issue #1353): Redshift Cluster CreateClusterSnapshot + ElastiCache ReplicationGroup CreateSnapshot, both waited to available before the delete. | [`deletion-policy-snapshot-heavy`](../tests/integration/deletion-policy-snapshot-heavy/) |
| `deployment-events` | Structured deployment events to S3 + `cdkd events` command (issue #808): per-run `deployments/{runId}.jsonl` + `index.json` (separate key family from state.json, no schema bump), events survive `cdkd destroy`, and carry error + metadata ONLY (no resource properties / secrets). | [`deployment-events`](../tests/integration/deployment-events/) |
| `destroy-data-guard` | CloudFormation-parity refusal to force-clean contained data on destroy (issue #1340): a non-empty S3 bucket WITHOUT the auto-delete opt-in and an image-carrying ECR repository WITHOUT EmptyOnDelete both FAIL the destroy with the data intact, while the opted-in siblings (aws-cdk:auto-delete-objects tag / EmptyOnDelete: true) are force-cleaned in the same run; after AWS-native data cleanup a second destroy completes with zero orphans. | [`destroy-data-guard`](../tests/integration/destroy-data-guard/)<br>[`s3-directory-bucket`](../tests/integration/s3-directory-bucket/) |
| `destroy-interrupt` | Graceful SIGINT on destroy (#816 — first Ctrl-C drains in-flight deletes, flushes trimmed state, releases the lock, exits non-zero; no 30m stranded lock) + Custom Resource replay fail-fast on re-run (#804 — the CR delete does NOT stall ~10 minutes invoking GetFunction against the already-deleted backing Lambda; the re-run resumes cleanly and quickly). | [`destroy-interrupt`](../tests/integration/destroy-interrupt/) |
| `docker-image-asset-ecr-publish` | cdkd's deploy-time Docker ASSET pipeline (`DockerAssetPublisher`): `docker build` of a local Dockerfile -> ECR auth -> `docker push` to the CDK-managed container-assets repo, then an `AWS::Lambda::Function` with `PackageType=Image` pointing at the pushed image. Distinct from the local-emulation container scenarios (which never touch AWS) — this verifies the real build+push happens during `cdkd deploy`, the image runs (Lambda invoke), and the pushed image is gone after destroy. | [`docker-image-asset`](../tests/integration/docker-image-asset/) |
| `drift-revert-array-canonicalization` | cdkd drift no-false-positive on tag-list / resource-id / ARN array REORDER (issue #802 `drift-normalize.ts` canonicalization) and on an unordered OBJECT array at a provider-declared path (issue #1620 — ELBv2 `TargetGroup.Targets`, asserted by TWO consecutive clean drift runs, since one run cannot detect a reorder disagreement), while still detecting real value / Action / SG-rule / added-target drift. | [`drift-revert-arrays`](../tests/integration/drift-revert-arrays/) |
| `drift-revert-roundtrip` | cdkd drift detection + `--revert` round-trip via each provider.update(). | [`drift-revert`](../tests/integration/drift-revert/)<br>[`drift-revert-arrays`](../tests/integration/drift-revert-arrays/)<br>[`drift-revert-vpc`](../tests/integration/drift-revert-vpc/) |
| `dynamic-reference-resolution` | CloudFormation dynamic references (`{{resolve:secretsmanager:...}}` / `{{resolve:ssm:...}}`) resolved by cdkd itself (`resolveDynamicReferences`) BEFORE the property reaches the provider — JSON-key (`:SecretString:<key>`), whole-secret, and version-stage forms + plaintext SSM param; the deployed resource carries the RESOLVED value, never the literal token. Secret-bearing references are additionally REDACTED back to their expression in persisted state, decided by the parameter TYPE rather than the spelling: an `ssm:` reference to a SecureString parameter is redacted (issue #1901) while a String parameter beside it stays resolved. (`ssm-secure:` is NOT resolved by cdkd and is intentionally out of scope.) | [`cross-stack-secret-import`](../tests/integration/cross-stack-secret-import/)<br>[`dynamic-ref-cross-region`](../tests/integration/dynamic-ref-cross-region/)<br>[`nested-stack-secret`](../tests/integration/nested-stack-secret/)<br>[`rollback-cross-region-secret`](../tests/integration/rollback-cross-region-secret/)<br>[`secrets-array-nested`](../tests/integration/secrets-array-nested/)<br>[`secrets-dynamic-ref`](../tests/integration/secrets-dynamic-ref/) |
| `elbv2-listener-tg-lb-deletion-order` | ELBv2 destroy ordering web: Listener/ListenerRule before TargetGroup (ResourceInUse), TG + Listener before the LoadBalancer, and the LB hyperplane ENI + registered-target ENI release before Subnet/SecurityGroup delete (DependencyViolation). | [`deletion-ordering-complex`](../tests/integration/deletion-ordering-complex/) |
| `eventsourcemapping-fresh-source-race` | `AWS::Lambda::EventSourceMapping` created against a FRESH source (SQS/Kinesis/DynamoDB-stream) + a FRESH execution role in the SAME deploy: the ESM create races source-readiness + role/policy propagation (cdkd dispatches with no level barrier), AND the orphan-ESM-on-redeploy collision class (a killed mid-deploy leaves an out-of-state ESM that collides on the next CREATE). The fixture pre-flight-scans for orphan ESMs by stack name, asserts the ESM reaches Enabled + actually delivers a probe message to the Lambda, and asserts no orphan ESM survives destroy. | [`eventsourcemapping-race`](../tests/integration/eventsourcemapping-race/) |
| `export-to-cfn-handover` | cdkd → CloudFormation migration via 2-phase IMPORT changeset + phase-2 UPDATE. | [`export`](../tests/integration/export/) |
| `exports-index-region-resolve` | Exports index store (`Fn::ImportValue` tracking, `_index/{region}/exports.json`) auto-detects the bucket region via `GetBucketLocation` before its write/remove, so a cross-region state bucket no longer hits S3 301 PermanentRedirect (issue #819). | [`cross-region-state-bucket`](../tests/integration/cross-region-state-bucket/) |
| `failed-only-journal-retention-cycle` | Failed-only rollback-journal retention after a CLEAN automatic rollback (issue #1208): the journal survives as a SINGLE popped-and-re-recorded segment (reason=auto-rollback-clean / operations=[] / failedOperations=[<bad resource>], raw S3 read), the next deploy prints the --revert-failed note and its own clean auto-rollback PRESERVES the older failed-only segment (PR #1216, exactly 2 segments), `cdkd rollback --force --revert-failed` consumes it via the #1198 skip-with-warning for a physical-id-less failed CREATE (exit 2 accepted), and a NO-CHANGE fix-forward deploy (bad resource removed) clears the journal + note (the PR #1212 no-change gap). | [`rollback-sqs-cooldown`](../tests/integration/rollback-sqs-cooldown/) |
| `fresh-principal-consumer-race` | A consumer resource created moments after the fresh principal/resource it references in the SAME deploy: IAM InstanceProfile -> EC2 Instance (RunInstances validates the profile), Lambda::Permission granting a fresh S3 source (AddPermission validates SourceArn + function), S3 BucketPolicy referencing a fresh role principal ("Invalid principal in policy"), KMS key policy referencing a fresh role (CreateKey validates principals). Each is a distinct propagation-race edge from the original IAM-propagation-stress integ (Lambda exec role / SFN role / EventBridge target / SQS+SNS policy, #839). Pass condition = deploy SUCCEEDS, so the fixture is a race detector for missing transient-retry coverage in src/deployment/retryable-errors.ts. | [`propagation-races-2`](../tests/integration/propagation-races-2/) |
| `getstackoutput-cross-region` | Cross-REGION `Fn::GetStackOutput` (cdkd-specific): a CONSUMER stack deployed in region Y reads a PRODUCER stack output from region X via the `Region` argument. Works same-account because the cdkd state bucket is account-scoped (not region-scoped) — the resolver reads `cdkd/{Producer}/{regionX}/state.json` from the same bucket the consumer state lives in. No CFn equivalent (CFn Exports are region-scoped). | [`getstackoutput-crossregion`](../tests/integration/getstackoutput-crossregion/)<br>[`rollback-cross-region-secret`](../tests/integration/rollback-cross-region-secret/) |
| `globaltable-billing-flip-with-gsi` | DynamoDB GlobalTable `PAY_PER_REQUEST` -> `PROVISIONED` billing flip on a table that HAS GSIs (issue #1421). AWS requires per-index `ProvisionedThroughput` in the SAME `UpdateTable` call that changes `BillingMode`, and an index the deploy REMOVES is still live at flip time (its Delete is issued later), so it must carry throughput in that call too — both claims were previously asserted only against a mocked DynamoDB client. Also pins the surviving index + table onto their `SeedCapacity` rather than `MinCapacity`, the one context AWS documents the seed for (issue #1435). | [`dynamodb-globaltable`](../tests/integration/dynamodb-globaltable/) |
| `globaltable-cross-region-replica` | DynamoDB GlobalTable cross-region replica add/remove serialization (AWS rejects multiple ReplicaUpdates per UpdateTable call). | [`dynamodb-globaltable`](../tests/integration/dynamodb-globaltable/) |
| `iam-fresh-role-immediate-assume` | Race detector: SEVERAL brand-new IAM roles each consumed within ~1s by a DIFFERENT service in ONE deploy (Lambda exec role -> CreateFunction; SFN role -> CreateStateMachine; EventBridge target role -> PutTargets; fresh principal -> SQS QueuePolicy + SNS TopicPolicy). Deploy SUCCESS is the pass condition — a failure is an unprotected consumer racing IAM propagation (the narrow #794/#805/#756 fixes cover only a few consumers). | [`iam-propagation-stress`](../tests/integration/iam-propagation-stress/) |
| `iam-policy-propagation-retry` | CREATE retry with exponential backoff after IAM-EC2/Lambda eventual-consistency race. | [`lambda`](../tests/integration/lambda/)<br>[`microservices`](../tests/integration/microservices/)<br>[`propagation-races-2`](../tests/integration/propagation-races-2/)<br>[`stepfunctions-logging`](../tests/integration/stepfunctions-logging/) |
| `import-adopt-live-resource-roundtrip` | End-to-end `cdkd import` adoption of a LIVE AWS resource: drop the resource from cdkd state with `cdkd orphan` (AWS untouched), re-adopt it with `cdkd import --resource <logicalId>=<physicalId>`, then destroy THROUGH the re-adopted record. Exercises the provider `import()` + `readCurrentState()` pair (the `observedProperties` baseline seeded post-import) and the selective-mode merge that must preserve unlisted sibling rows. Distinct from `nested-stack-migrate-from-cfn`, which covers the `--migrate-from-cloudformation` path; NO fixture covered the plain adopt mode before (issue #1090). | [`emr-cluster`](../tests/integration/emr-cluster/) |
| `intrinsic-hard-arg-shapes` | Resolver correctness on the harder / less-common intrinsic arg shapes feeding real resource values: `Fn::Select` over a list-returning intrinsic (`Fn::GetAZs` / `Fn::Split`), `Fn::FindInMap` enhanced 4th-arg `{DefaultValue}` + `Ref`-driven top key, `Fn::GetAtt` with a `Ref`-valued attribute name, the `Fn::Sub` `${!Literal}` escape, `Fn::Base64` of an intrinsic, a triple-nested `Fn::If`-in-`Fn::Sub`-in-`Fn::Join`, and `Fn::Cidr` IPv6. Sibling of `intrinsics-torture` (which found bug #838). | [`intrinsics-torture-2`](../tests/integration/intrinsics-torture-2/) |
| `intrinsics-torture` | Stress-test of cdkd's hand-rolled intrinsic-function resolver (`src/deployment/intrinsic-function-resolver.ts`), which resolves EVERY intrinsic itself instead of deferring to CloudFormation. Each harder intrinsic computes an `AWS::SSM::Parameter` Value read back + asserted against an independently-computed expected value: `Fn::Cidr` (carve a /16 into eight /24s), `Fn::FindInMap` (Mappings region/env lookup), `Fn::GetAZs` + `Fn::Select`, `Fn::Base64`, nested `Fn::Split` + `Fn::Select` + `Fn::Join`, deeply-nested two-arg `Fn::Sub` (literal-map var via `Fn::Join` + `${AWS::Region}` + `${Resource.Arn}` GetAtt), and ALL pseudo-parameters (AccountId / Region / Partition / StackName / URLSuffix / NotificationARNs). Goes beyond the `intrinsic-functions` fixture (which covers only Ref / GetAtt / Join / Sub). | [`intrinsics-torture`](../tests/integration/intrinsics-torture/) |
| `lambda-vpc-subnet-sg-deletion-order` | Subnet/SecurityGroup must delete AFTER Lambda::Function to avoid ENI DependencyViolation. | [`bench-cdk-sample`](../tests/integration/bench-cdk-sample/)<br>[`lambda`](../tests/integration/lambda/)<br>[`vpc-lambda`](../tests/integration/vpc-lambda/) |
| `legacy-bucket-name-fallback` | New region-free `cdkd-state-{account}` vs legacy `cdkd-state-{account}-{region}` bucket fallback resolution. | [`legacy-bucket-name-fallback`](../tests/integration/legacy-bucket-name-fallback/) |
| `local-agentcore-from-state` | `cdkd local invoke-agentcore --from-state` end-to-end against a real-AWS deployed AgentCore Runtime — verifies the cdkd-port-specific 3-arg `createLocalStateProvider` shim resolves intrinsic-valued env vars (e.g. `Ref: <S3 bucket>`) against cdkd state after a real `cdkd deploy`. | [`local-invoke-agentcore-from-state`](../tests/integration/local-invoke-agentcore-from-state/) |
| `local-agentcore-runtime` | `cdkd local invoke-agentcore` Bedrock AgentCore Runtime: HTTP `/invocations` / MCP `/mcp` / A2A `/a2a` / AGUI / WebSocket `--ws` protocols + inbound JWT auth verification + container artifact + CodeConfiguration managed-runtime source build. | [`local-invoke-agentcore`](../tests/integration/local-invoke-agentcore/)<br>[`local-invoke-agentcore-from-state`](../tests/integration/local-invoke-agentcore-from-state/) |
| `local-apigateway-server` | `cdkd local start-api` HTTP server with route discovery + per-Lambda warm container pool. | [`local-start-api`](../tests/integration/local-start-api/)<br>[`local-start-api-container`](../tests/integration/local-start-api-container/)<br>[`local-start-api-rest-v1-non-proxy`](../tests/integration/local-start-api-rest-v1-non-proxy/) |
| `local-ecs-awsvpc` | `cdkd local run-task` ECS TaskDefinition declaring `NetworkMode: awsvpc` — accepted and mapped to a docker bridge network with a startup warn (#461; docker cannot emulate ENI-per-task). | [`local-run-task-awsvpc`](../tests/integration/local-run-task-awsvpc/) |
| `local-ecs-service` | `cdkd local start-service` long-running ECS Service emulator: replica pool, restart-on-exit, SIGINT teardown. | [`local-ecs-service-connect`](../tests/integration/local-ecs-service-connect/)<br>[`local-start-service`](../tests/integration/local-start-service/) |
| `local-ecs-service-connect` | `cdkd local start-service` Service Connect + Cloud Map peer discovery: ServiceConnectConfiguration + ServiceRegistries parsing, in-process Cloud Map registry, docker `--add-host` DNS overlay (Issue #460). | [`local-ecs-service-connect`](../tests/integration/local-ecs-service-connect/) |
| `local-ecs-task` | `cdkd local run-task` ECS TaskDefinition with docker network + AWS-published metadata sidecar. | [`local-run-task`](../tests/integration/local-run-task/)<br>[`local-run-task-from-state`](../tests/integration/local-run-task-from-state/)<br>[`local-run-task-multi-container`](../tests/integration/local-run-task-multi-container/) |
| `local-from-cfn-stack-substitution` | `cdkd local invoke|start-api|run-task|start-service --from-cfn-stack` substitutes intrinsic-valued env/secret/image references against a deployed CloudFormation stack via DescribeStackResources + ListExports — for CDK apps deployed via the upstream CDK CLI (`cdk deploy`). | [`local-invoke-from-cfn-stack`](../tests/integration/local-invoke-from-cfn-stack/)<br>[`local-invoke-from-cfn-stack-multi-stack`](../tests/integration/local-invoke-from-cfn-stack-multi-stack/) |
| `local-from-state-substitution` | `cdkd local invoke|run-task --from-state` substitutes intrinsic-valued env/secret/role references against deployed cdkd state + AWS pseudo parameters. | [`local-invoke-from-state`](../tests/integration/local-invoke-from-state/)<br>[`local-run-task-from-state`](../tests/integration/local-run-task-from-state/) |
| `local-lambda-rie-container` | `cdkd local invoke` container-Lambda (Code.ImageUri) against RIE — local-build OR ECR-pull asset resolution. | [`local-invoke-buildkit`](../tests/integration/local-invoke-buildkit/)<br>[`local-invoke-container`](../tests/integration/local-invoke-container/)<br>[`local-start-api-container`](../tests/integration/local-start-api-container/) |
| `local-lambda-rie-zip` | `cdkd local invoke` ZIP-runtime Lambda against the AWS Lambda Runtime Interface Emulator (RIE) container. | [`local-invoke`](../tests/integration/local-invoke/)<br>[`local-invoke-dotnet`](../tests/integration/local-invoke-dotnet/)<br>[`local-invoke-from-cfn-stack`](../tests/integration/local-invoke-from-cfn-stack/)<br>[`local-invoke-from-cfn-stack-multi-stack`](../tests/integration/local-invoke-from-cfn-stack-multi-stack/)<br>[`local-invoke-from-state`](../tests/integration/local-invoke-from-state/)<br>[`local-invoke-java`](../tests/integration/local-invoke-java/)<br>[`local-invoke-layers`](../tests/integration/local-invoke-layers/)<br>[`local-invoke-provided`](../tests/integration/local-invoke-provided/)<br>[`local-invoke-python`](../tests/integration/local-invoke-python/)<br>[`local-invoke-ruby`](../tests/integration/local-invoke-ruby/) |
| `local-region-case-fold` | Region CASE folding on the `cdkd local` path (issues #1795 / #1814 / #1836): an upper-cased region is structurally valid and nothing rejects it, while AWS SDK endpoint resolution, the partition table and cdkd's own state-record / marker-key comparisons are all case-SENSITIVE. Covers the two ends a Docker / real-AWS run can observe — the CONTAINER's own `AWS_REGION` (every SDK client the handler builds) must arrive canonical from an upper-cased shell, and an upper-cased `--stack-region` must still read the canonically-keyed `cdkd/{stack}/{region}/state.json` record instead of silently falling back to no state at all. | [`local-invoke`](../tests/integration/local-invoke/)<br>[`local-invoke-from-state`](../tests/integration/local-invoke-from-state/) |
| `local-websocket-api` | `cdkd local start-api` WebSocket API support: ws upgrade + $connect/$disconnect/$default/custom route dispatch + @connections data plane. | [`local-start-api-websocket`](../tests/integration/local-start-api-websocket/) |
| `migrate-from-bare-cfn` | `cdkd migrate --from-cfn-stack <name>` end-to-end: bare CFn → `cdk migrate` codegen → 2-pass resource mapping → cdkd state + optional retire. | [`migrate-from-bare-cfn`](../tests/integration/migrate-from-bare-cfn/) |
| `migrate-from-cfn-handover` | CloudFormation → cdkd migration via `--migrate-from-cloudformation` (UpdateStack with Retain + DeleteStack). | [`migrate-from-cfn`](../tests/integration/migrate-from-cfn/) |
| `multi-asset` | Asset-publishing layer under concurrency: MANY assets of TWO kinds publish in ONE `cdkd deploy` — 1 Docker image asset (`DockerAssetPublisher` -> ECR build+push, ARM_64-pinned) + 3 distinct multi-file directory assets (three distinct `FileAssetPublisher` S3 uploads, one per zip Lambda) + 1 generic `s3_assets.Asset` (a 4th S3 upload read back at runtime via cdkd-resolved bucket/key env). Exercises FileAssetPublisher + DockerAssetPublisher concurrency, ECR + S3 in one run, and asset-ref intrinsics. Each Lambda returns a DISTINCT marker so a cross-wired asset (wrong Code ref) fails the test — proving each distinct asset uploaded AND was wired to the correct Lambda. Clean destroy: all 4 Lambdas + OUR pushed ECR image (by tag) gone; the shared bootstrap container-assets repo + asset bucket objects persist by design. | [`multi-asset`](../tests/integration/multi-asset/) |
| `multi-region-state-key` | Same stackName + different regions = independent state files (`version: 2` region-prefixed key layout). | [`multi-region-same-stack`](../tests/integration/multi-region-same-stack/) |
| `multi-stack-getstackoutput` | Cross-stack `Fn::GetStackOutput` weak reference resolution (cdkd-specific, no CFn Export). | [`composite-stack`](../tests/integration/composite-stack/)<br>[`cross-stack-references`](../tests/integration/cross-stack-references/)<br>[`getstackoutput-crossregion`](../tests/integration/getstackoutput-crossregion/)<br>[`multi-stack-deps`](../tests/integration/multi-stack-deps/) |
| `multi-stack-importvalue-strong-ref` | Cross-stack `Fn::ImportValue` strong-reference + persistent exports index (schema v4 imports[]). | [`import-value-strong-ref`](../tests/integration/import-value-strong-ref/)<br>[`importvalue-chain`](../tests/integration/importvalue-chain/) |
| `multi-stack-outputs-only-export` | Outputs-only change on an already-deployed producer (issue #875): a downstream consumer starts referencing the producer, so CDK synth adds a new Output/Export to the producer WITHOUT changing any of its resources. The producer redeploy is a no-op at the resource level but must still persist the new export to state + the exports index, otherwise the consumer (deployed with --exclusively, so the producer is not redeployed to paper over the gap) fails to resolve its Fn::ImportValue. Also covers the PREVIEW half (issue #1921): `cdkd diff` must report the Outputs-only change — human Outputs section naming the `[export]` row, `--fail` exiting 1, and the entry in `--json` `outputChanges` — where it previously printed "No changes detected" and exited 0, steering the user away from the deploy that publishes the export; paired with a negative arm requiring the freshly-deployed producer to still diff clean. | [`outputs-only-export`](../tests/integration/outputs-only-export/) |
| `nat-gateway-cleanup` | NAT Gateway destroy + dependent route cleanup (unconditional `waitUntilNatGatewayDeleted` on destroy). | [`bench-cdk-sample`](../tests/integration/bench-cdk-sample/)<br>[`vpc-nat-gateway`](../tests/integration/vpc-nat-gateway/) |
| `nested-stack-deep-deploy-cascade` | Recursive `cdk.NestedStack` deploy + destroy at depth >= 3 (root → child → grandchild → great-grandchild): per-level `<parent>~<logicalId>` v6 state-key derivation with populated `parentStack` / `parentLogicalId`, bidirectional cross-level refs (bottom-up `Fn::GetAtt` outputs AND top-down `Parameters` forwarding), `state list --tree` hierarchy rendering, and the full reverse-DAG destroy cascade that removes every level's resources + state files. | [`nested-stack-3level`](../tests/integration/nested-stack-3level/) |
| `nested-stack-migrate-from-cfn` | CloudFormation → cdkd RECURSIVE nested-stack migration via `--migrate-from-cloudformation` (recursive DescribeStackResources walk, per-child v6 state writes, recursive DeletionPolicy: Retain injection, parent-side DeleteStack cascade). See #464 PR A. | [`import-nested-stack`](../tests/integration/import-nested-stack/) |
| `ordinary-create-name-cooldown` | An ORDINARY `cdkd deploy` (no --replace, no rollback, a fresh process that never deleted anything itself) creating a resource whose NAME is still held by a prior `cdkd destroy`'s asynchronous delete, and riding the cooldown out instead of failing the deploy (issue #2116). Distinct from `rollback-reverse-replacement-name-cooldown`, which covers the sites where cdkd ITSELF just deleted the name holder and therefore consults `isRecreateRetryableError`: this one covers the reachable destroy-then-redeploy dev loop, where the only thing that can absorb the window is the generic transient classifier plus the name-cooldown backoff grid. Pass condition = the redeploy exits 0 and prints `Deployment completed successfully`; coverage is confirmed separately from a --verbose retry line quoting the AWS cooldown message, since a fully-closed window produces the same exit code. CAVEAT on reading this row as coverage: the tag is claimed unconditionally by the fixture, but the arm is OPPORTUNISTIC -- the window is a ~23s real-AWS timing property that the fixture's preceding 200s bucket poll can outlast, so a given run reports either `OK: COVERED` or `INCONCLUSIVE`, and the latter is likely the common one. Nothing forces a re-run on INCONCLUSIVE. The standing backstop for the classifier and the 64s backoff grid is the unit suite (tests/unit/deployment/retryable-errors.test.ts + retry.test.ts), which runs every time; this row records that a real-AWS arm EXISTS, not that the last run exercised it. | [`custom-resource-provider`](../tests/integration/custom-resource-provider/) |
| `raw-cfn-template-diff-parity` | Raw CloudFormation template (CfnInclude) carrying Parameters w/ defaults + Mappings + Conditions on resources AND outputs: deploy resolves them, a no-op `cdkd diff --fail` must exit 0 (no phantom replacement / phantom create — #1027), an inlined-parameter change updates in place, and a condition-false Output is skipped without a `Failed to resolve output` warn (#1028). | [`raw-cfn-conditions-params`](../tests/integration/raw-cfn-conditions-params/) |
| `rds-aurora-cluster-instance` | RDS Aurora cluster + writer instance create/destroy with the 30-min wait budget + DBProxy/DBProxyTargetGroup family. | [`rds-aurora`](../tests/integration/rds-aurora/) |
| `rds-full-stack` | Realistic single-instance RDS deployment: L2 `rds.DatabaseInstance` (db.t3.micro, single-AZ, isolated subnets, no NAT) with an EXPLICIT DBSubnetGroup + DBParameterGroup + SecurityGroup + CDK-managed Secrets Manager credentials, plus an SSM Parameter consuming the DBInstance COMPUTED endpoint via `Fn::GetAtt(<DBInstance>, Endpoint.Address)`. Stresses event-driven DAG ordering (sub-groups before the instance), slow-create propagation (~5-10 min instance create), and intrinsic resolution of a computed attribute only known post-create (the SSM value must equal the live endpoint). A second SSM Parameter consumes `Fn::GetAtt(<DbSubnetGroup>, DBSubnetGroupArn)` (issue 1824) and must equal the live `describe-db-subnet-groups` ARN byte for byte — that ARN is read off the `CreateDBSubnetGroup` RESPONSE, a wire assumption every unit test hand-feeds to a mock, and pre-fix the reference HARD-FAILED the deploy on the resolver `*Arn` shape guard rather than resolving wrongly. | [`rds-full-stack`](../tests/integration/rds-full-stack/) |
| `remove-protection-bypass` | `--remove-protection` flag bypassing AWS-side deletion-protection on supported types. | [`remove-protection`](../tests/integration/remove-protection/) |
| `replacement-fanout-propagation` | Replacement propagation (#807) at FAN-OUT scale: ONE base resource (SNS Topic, TopicName change -> new ARN) referenced by MANY (10) dependents via Fn::Sub of its Ref (10 SSM Parameters + an SNS TopicPolicy). A second deploy with `-c phase=b` replaces the base; `promoteReplacementDependents` (src/analyzer/diff-calculator.ts) must propagate the new ARN to EVERY dependent so none keeps the stale phase-a ARN. Catches fan-out gaps the narrow ECS-only #807 case cannot. | [`replacement-fanout`](../tests/integration/replacement-fanout/) |
| `rollback-create-deletion-policy-snapshot` | DeletionPolicy: Snapshot on a ROLLED-BACK CREATE (issue #1358): a deploy whose second resource fails must snapshot the first one and DELETE it, not orphan it. verify.sh asserts the deploy fails, the old orphan log line is absent, a completed cdkd:final-snapshot-of EBS snapshot of the rolled-back volume exists, the volume is gone from AWS, and state.json is gone. | [`rollback-deletion-policy-snapshot`](../tests/integration/rollback-deletion-policy-snapshot/) |
| `rollback-failure-injection` | deploy-engine ROLLBACK path on a RICH multi-resource stack (VPC+SG+IAM Role+Lambda-in-VPC+SSM Parameter): a self-contained env-gated (`ROLLBACK_INTEG_FAIL`) failing SQS Queue (out-of-range messageRetentionPeriod) wired to depend on the fast siblings forces a deploy failure AFTER siblings complete; verify.sh asserts the completed siblings are rolled back (no orphan VPC/SG/ENI/Role/Lambda/SSM, state empty) and the #808 events captured RESOURCE_FAILED + ROLLBACK_* + RUN_FINISHED=FAILED. | [`rollback-failure-injection`](../tests/integration/rollback-failure-injection/) |
| `rollback-replay-effective-properties` | Reverse-replacement rollback records the replay-CREATE's `effectiveProperties` (issue #1682). Distinct from `rollback-failure-injection`, which rolls back CREATEs (a delete): here the resource is REPLACED before the failure, so rollback re-creates the OLD one from `previousState.properties` — a cdkd STATE record, which can carry a malformed block an older binary wrote and which the provider WARNS about and SUBSTITUTES (the #1544 replayWarn downgrade) rather than refusing. Pre-fix the engine typed that call's result as `{physicalId, attributes?}` and rebuilt the record from `prev.properties`, discarding the substitution. The vehicle is `AWS::EC2::Route` rather than the `AWS::S3::Bucket` #1682 names, because a bucket's reverse-replacement re-create must re-acquire a just-deleted GLOBALLY unique name whose release is not immediate (flaky for an unrelated reason), while a route's `<RouteTableId>|<Destination>` identity is stack-scoped and deterministic; `createRoute`'s multi-destination warn arm is gated on the same `CreateContext.replayingState` flag, so the engine path is identical. verify.sh deploys v1, injects a second destination key into the state record, flips the create-only destination with a failure wired AFTER the route (so rollback classifies reverse-replacement, asserted via the substitution warning), then asserts the post-rollback record restored the v1 destination and DROPPED the injected key, that two consecutive `cdkd drift` runs converge, and that destroy leaves 0 orphans. | [`rollback-replay-effective-props`](../tests/integration/rollback-replay-effective-props/) |
| `rollback-reverse-replacement-name-cooldown` | `cdkd rollback` reverse-replacement re-create through the SQS same-name ~60s deletion cooldown (issue #1206): a custom-named queue rename-replacement (create-only QueueName, --force-stateful-recreation) plus an injected failing resource under --no-rollback is reverted immediately — the reverse-replacement's initial re-create must hit `QueueDeletedRecently`, retry through the window (asserted via the --verbose retry lines), restore the old-named queue, delete the new one, and exit 0. | [`rollback-sqs-cooldown`](../tests/integration/rollback-sqs-cooldown/) |
| `s3-asset-deploy` | File/ZIP asset publishing during `cdkd deploy`: a multi-file local directory is zipped + uploaded to the CDK bootstrap asset bucket by `FileAssetPublisher` (content-addressed, skip-if-exists), the Lambda `Code.S3Bucket`/`Code.S3Key` ref is wired to the uploaded object (CodeSize proves it is NOT inline), AND a generic `s3_assets.Asset` upload is read back at runtime via cdkd-resolved bucket/key env vars. Bootstrap-bucket asset objects persist by design across destroy. | [`s3-asset-deploy`](../tests/integration/s3-asset-deploy/) |
| `sdk-ccapi-crossref-boundary` | Heterogeneous SDK-Provider <-> Cloud Control API routing in ONE stack (a silent-drop top-level property flips a resource to the CC path per #614) with `Fn::GetAtt` cross-references crossing the boundary in BOTH directions — SDK-routed consumer reads a CC-routed producer attribute AND CC-routed consumer reads an SDK-routed producer attribute. Exercises the constructAttribute fallback for CC-API physical-id shapes (memory `feedback_silent_drop_forces_cc_api_routing`) and the CC delete path bypassing the SDK provider delete() (memory `feedback_cc_api_routing_bypasses_sdk_delete_logic`). | [`sdk-ccapi-crossref`](../tests/integration/sdk-ccapi-crossref/) |
| `selective-import-attribute-persistence` | Selective `cdkd import --resource <LogicalId>=<physical>` adoption of an already-deployed resource whose provider `import()` returns a NON-EMPTY `attributes` map, asserting the map is persisted into the state row (issue #1098: `buildStackState` hardcoded `attributes: {}` and dropped it, leaving an adopted resource with no `Fn::GetAtt` backing while a deployed one had it). Uses `AWS::IAM::ManagedPolicy` (`import()` -> `{ PolicyArn }`) after a `cdkd state orphan` drops state while leaving the AWS resource live. Distinct from `migrate-from-cfn-handover`, which covers the CFn retirement path rather than the state-row shape. | [`import-attributes`](../tests/integration/import-attributes/) |
| `sg-circular-dependency` | Circular Security Group reference (SG-A ingress from SG-B AND SG-B ingress from SG-A) modeled via standalone AWS::EC2::SecurityGroupIngress resources. DAG builder must not raise a false cycle; destroy must revoke both ingress rules BEFORE deleting either SG (SecurityGroup-after-SecurityGroupIngress implicit-delete-dep) or AWS rejects DeleteSecurityGroup with DependencyViolation. | [`sg-circular-dependency`](../tests/integration/sg-circular-dependency/) |
| `stack-level-tag-propagation-multitype` | STACK-LEVEL tags (`cdk.Tags.of(app/stack).add(k, v)`) propagate to ALL taggable resources across MANY types on BOTH the SDK-provider path (S3 / SNS / SQS / SSM Parameter / IAM Role / Logs LogGroup / Lambda / DynamoDB) AND the Cloud Control API path (Athena WorkGroup, no SDK provider). Each AWS type accepts tags in a DIFFERENT wire shape ({Key,Value}[] list vs { k: v } map vs the CC-API forwarder) — notably `AWS::SSM::Parameter.Tags` is a CFn MAP (the historical `Tags.map()` deploy-crash type per feedback_ssm_parameter_tags_is_a_map). verify.sh reads live AWS tags per type via that type-specific list/describe API and asserts ALL stack-level tags landed with the right value; a dropped tag FAILs naming the type. Also asserts post-deploy `cdkd drift` is clean (no #802 tag-list-reorder false positive). | [`tags-propagation`](../tests/integration/tags-propagation/) |
| `state-bucket-region-resolve` | State-bucket S3 clients (state backend + lock manager) auto-detect bucket region via `GetBucketLocation` regardless of caller-profile region. | [`cross-region-state-bucket`](../tests/integration/cross-region-state-bucket/) |
| `state-schema-migration` | Legacy v1 / v2 state schema auto-migrates on next write; old binary fails clearly on a newer schema. | [`legacy-state-migration`](../tests/integration/legacy-state-migration/)<br>[`schema-v5-to-v6-migration`](../tests/integration/schema-v5-to-v6-migration/)<br>[`schema-v8-to-v9-migration`](../tests/integration/schema-v8-to-v9-migration/) |
| `undeletable-pending-resource-skip` | Destroy of a resource AWS itself refuses to delete until it expires server-side — the canonical case is an SNS subscription in PendingConfirmation, which rejects Unsubscribe from EVERY caller and only disappears via ~3-day auto-expiry or topic deletion. The provider must treat the rejection as delete-success (CloudFormation parity: the resource is removed from the stack without unsubscribing) instead of failing the resource and wedging destroy/state-destroy permanently (issue #1301). | [`sns-pending-subscription`](../tests/integration/sns-pending-subscription/) |
| `update-policy-mutations` | Second-deploy mutation of CloudFormation template-level ATTRIBUTES (not properties) across a CDK context flip (`-c phase=a|b`): (1) `UpdateReplacePolicy: Retain` orphan-on-replace — an S3 `BucketName` change forces replacement, the OLD physical bucket must be RETAINED on AWS (not deleted) while the new one is created; (2) `DeletionPolicy` flip DESTROY->RETAIN on an SSM Parameter — the final destroy must honor the CURRENT (Retain) policy and leave it on AWS; (3) `DependsOn` add/remove between SNS topics — a metadata-only change that must update successfully without replacing either topic; (4) metadata-only / no-op identical redeploy reporting `No changes detected`. Intentional orphans (Retain bucket + Retain param) are cleaned by captured physical id in the verify.sh trap. Regression net for `diff-calculator.ts` attribute diff + `deploy-engine.ts` Retain-on-replace / DeletionPolicy destroy-skip paths. | [`update-policy-mutations`](../tests/integration/update-policy-mutations/) |
| `update-replace-breadth` | Second-deploy property mutation exercising BOTH cdkd update paths in one stack: in-place provider.update() (S3 versioning toggle / Lambda env+memory / IAM inline-policy edit / SecurityGroup ingress add — physical id unchanged) AND replacement (S3 BucketName change per the replacement-rules registry — new physical id, old resource cleaned up). Regression net for provider update() paths + #807 replacement propagation + #809 Cloud Control write-only-property UPDATE on non-ECS types. | [`update-replace`](../tests/integration/update-replace/) |
| `vpc-lambda-cr-race` | Custom Resource invocation against a VPC Lambda mid-deploy (ENI-attach race window). | [`vpc-lambda-cr-race`](../tests/integration/vpc-lambda-cr-race/) |
| `vpc-lambda-eni-release` | Lambda hyperplane ENI cleanup after DeleteFunction (5-30 min eventually consistent). | [`bench-cdk-sample`](../tests/integration/bench-cdk-sample/)<br>[`destroy-interrupt`](../tests/integration/destroy-interrupt/)<br>[`lambda`](../tests/integration/lambda/)<br>[`vpc-lambda`](../tests/integration/vpc-lambda/) |
| `warn-arm-effective-properties` | A provider warn arm that SKIPS or SUBSTITUTES a malformed DECLARED value must record what it actually SENT (`effectiveProperties`), not the declared value. The deploy SUCCEEDS, so recording the declared bag makes state describe something AWS does not hold: `readCurrentState` can never match it, every later `cdkd drift` re-reports the same difference, and `drift --revert` re-issues the same skipped call (issues #1591 / #1612 / #1653 / #1654). Only a real deploy can produce the record and only a real read-side run can prove it converges, so a mocked client agrees with whatever wire assumption the author had. Covered arms: the DynamoDB GlobalTable `StreamSpecification` warn-and-SKIP (retains the PREVIOUS value; drops it when the previous side is malformed too) and the Lambda URL `AuthType` warn-and-SUBSTITUTE (records the previous value on the substituted arm, drops the key on the OMITTED arm) — each asserting the recorded value, the untouched LIVE resource, and that the corrected template then diffs clean against that record (a `cdkd drift` assertion would be vacuous here: drift prefers the `observedProperties` baseline, which is a live read and therefore matches AWS either way). The Lambda arm additionally asserts the security consequence directly (the URL is still IAM-guarded) and that a reverse-replacement replay of a record with no `AuthType` ANNOUNCES the PUBLIC default it falls back to. | [`dynamodb-globaltable`](../tests/integration/dynamodb-globaltable/)<br>[`lambda-url-authtype-replay`](../tests/integration/lambda-url-authtype-replay/) |
| `wide-dag-throttle-retry` | Wide (~100-resource: 80 SSM Parameters + 10 IAM Roles + 10 SNS Topics, 10-deep SSM Fn::Sub chain) single-stack burst deployed under a HIGH `--concurrency` to stress the concurrency limiter + event-driven DAG executor + throttle/retry classifier: a `TooManyRequests` / `Rate exceeded` / HTTP 429 during the burst must be RETRIED (deploy still succeeds) not fatal, the chained subset proves strict DAG ordering, and the destroy burst absorbs ~100 deletes with 0 orphans. | [`throttle-wide-dag`](../tests/integration/throttle-wide-dag/) |

## Un-annotated fixtures (93)

These integ fixtures have no `.scenarios.json` sidecar. They may or may not exercise a canonical scenario — contributor review needed. To opt out (per-service smoke tests with no canonical pattern), add a sidecar with `{ "scenarios": [] }`.

- [`acm-certificate`](../tests/integration/acm-certificate/)
- [`apigatewayv2-update-removal`](../tests/integration/apigatewayv2-update-removal/)
- [`apigw-stage-props`](../tests/integration/apigw-stage-props/)
- [`apigw-stage-throttling`](../tests/integration/apigw-stage-throttling/)
- [`apigw-usage-plan-key`](../tests/integration/apigw-usage-plan-key/)
- [`appconfig`](../tests/integration/appconfig/)
- [`aws-custom-resource`](../tests/integration/aws-custom-resource/)
- [`backup`](../tests/integration/backup/)
- [`bootstrap-free-region`](../tests/integration/bootstrap-free-region/)
- [`bucket-deployment`](../tests/integration/bucket-deployment/)
- [`cc-api-fallback`](../tests/integration/cc-api-fallback/)
- [`cc-api-fallback-transitions`](../tests/integration/cc-api-fallback-transitions/)
- [`cloudtrail-trail`](../tests/integration/cloudtrail-trail/)
- [`codebuild-project`](../tests/integration/codebuild-project/)
- [`codedeploy-lambda-deployment-group`](../tests/integration/codedeploy-lambda-deployment-group/)
- [`cognito-custom-attribute-add`](../tests/integration/cognito-custom-attribute-add/)
- [`cognito-identity-pool`](../tests/integration/cognito-identity-pool/)
- [`cognito-lambda-triggers`](../tests/integration/cognito-lambda-triggers/)
- [`cognito-userpool-user-ref`](../tests/integration/cognito-userpool-user-ref/)
- [`dynamodb-autoscaling`](../tests/integration/dynamodb-autoscaling/)
- [`dynamodb-gsi-update`](../tests/integration/dynamodb-gsi-update/)
- [`dynamodb-ondemand`](../tests/integration/dynamodb-ondemand/)
- [`dynamodb-sse`](../tests/integration/dynamodb-sse/)
- [`dynamodb-stream-filter`](../tests/integration/dynamodb-stream-filter/)
- [`dynamodb-tableclass-switch`](../tests/integration/dynamodb-tableclass-switch/)
- [`dynamodb-ttl-attr-change`](../tests/integration/dynamodb-ttl-attr-change/)
- [`ec2-instance-fanout`](../tests/integration/ec2-instance-fanout/)
- [`ec2-route-targets`](../tests/integration/ec2-route-targets/)
- [`ecr-scanning`](../tests/integration/ecr-scanning/)
- [`ecs-schedule-targets`](../tests/integration/ecs-schedule-targets/)
- [`efs-immutable-replacement`](../tests/integration/efs-immutable-replacement/)
- [`eventbridge-api-destination`](../tests/integration/eventbridge-api-destination/)
- [`eventbridge-input-transformer`](../tests/integration/eventbridge-input-transformer/)
- [`eventbridge-pipes`](../tests/integration/eventbridge-pipes/)
- [`eventbridge-scheduler`](../tests/integration/eventbridge-scheduler/)
- [`eventbus-policy`](../tests/integration/eventbus-policy/)
- [`export-nested-stack`](../tests/integration/export-nested-stack/)
- [`fifo-sqs-event-source`](../tests/integration/fifo-sqs-event-source/)
- [`getatt-fallback-guard`](../tests/integration/getatt-fallback-guard/)
- [`glue-securityconfig-replace`](../tests/integration/glue-securityconfig-replace/)
- [`iam-managed-policy`](../tests/integration/iam-managed-policy/)
- [`iam-role-policies-drift-clean`](../tests/integration/iam-role-policies-drift-clean/)
- [`iam-role-prefixed-name-update`](../tests/integration/iam-role-prefixed-name-update/)
- [`inplace-attr-propagation`](../tests/integration/inplace-attr-propagation/)
- [`kinesis-esm-filter`](../tests/integration/kinesis-esm-filter/)
- [`kinesis-stream-mode-switch`](../tests/integration/kinesis-stream-mode-switch/)
- [`lambda-alias-provisioned-concurrency`](../tests/integration/lambda-alias-provisioned-concurrency/)
- [`lambda-arch-switch`](../tests/integration/lambda-arch-switch/)
- [`lambda-config-field-removal`](../tests/integration/lambda-config-field-removal/)
- [`lambda-destinations`](../tests/integration/lambda-destinations/)
- [`lambda-env-removal`](../tests/integration/lambda-env-removal/)
- [`lambda-esm-self-managed-kafka`](../tests/integration/lambda-esm-self-managed-kafka/)
- [`lambda-event-invoke-config-update`](../tests/integration/lambda-event-invoke-config-update/)
- [`lambda-layer-version-update`](../tests/integration/lambda-layer-version-update/)
- [`lambda-log-retention`](../tests/integration/lambda-log-retention/)
- [`lambda-microvm-image`](../tests/integration/lambda-microvm-image/)
- [`lambda-reserved-concurrency`](../tests/integration/lambda-reserved-concurrency/)
- [`launchtemplate-asg-inplace`](../tests/integration/launchtemplate-asg-inplace/)
- [`local-start-agentcore`](../tests/integration/local-start-agentcore/)
- [`local-start-alb`](../tests/integration/local-start-alb/)
- [`local-start-alb-from-state`](../tests/integration/local-start-alb-from-state/)
- [`local-start-cloudfront`](../tests/integration/local-start-cloudfront/)
- [`local-start-service-watch-fast`](../tests/integration/local-start-service-watch-fast/)
- [`loggroup-class-guard`](../tests/integration/loggroup-class-guard/)
- [`loggroup-kms-associate`](../tests/integration/loggroup-kms-associate/)
- [`nested-stack`](../tests/integration/nested-stack/)
- [`nested-stack-deep`](../tests/integration/nested-stack-deep/)
- [`nodejs-function`](../tests/integration/nodejs-function/)
- [`rds-dbinstance-backfill`](../tests/integration/rds-dbinstance-backfill/)
- [`recreate-mixed-direction`](../tests/integration/recreate-mixed-direction/)
- [`recreate-via-cc-api`](../tests/integration/recreate-via-cc-api/)
- [`recreate-via-sdk-provider`](../tests/integration/recreate-via-sdk-provider/)
- [`rename-refactor`](../tests/integration/rename-refactor/)
- [`replacement-immutable-name`](../tests/integration/replacement-immutable-name/)
- [`rollback-command`](../tests/integration/rollback-command/)
- [`s3-analytics-inventory`](../tests/integration/s3-analytics-inventory/)
- [`s3-event-notification`](../tests/integration/s3-event-notification/)
- [`s3-lifecycle`](../tests/integration/s3-lifecycle/)
- [`s3-object-lock`](../tests/integration/s3-object-lock/)
- [`s3-replication-and-filter`](../tests/integration/s3-replication-and-filter/)
- [`scheduler-custom-group`](../tests/integration/scheduler-custom-group/)
- [`schema-v6-to-v7-migration`](../tests/integration/schema-v6-to-v7-migration/)
- [`schema-v7-to-v8-migration`](../tests/integration/schema-v7-to-v8-migration/)
- [`secrets-rotation-schedule`](../tests/integration/secrets-rotation-schedule/)
- [`servicediscovery`](../tests/integration/servicediscovery/)
- [`sns-event-source`](../tests/integration/sns-event-source/)
- [`sns-inline-subscription`](../tests/integration/sns-inline-subscription/)
- [`sns-subscription-filter`](../tests/integration/sns-subscription-filter/)
- [`sns-subscription-update`](../tests/integration/sns-subscription-update/)
- [`sqs-esm-max-concurrency`](../tests/integration/sqs-esm-max-concurrency/)
- [`stack-lock-renewal`](../tests/integration/stack-lock-renewal/)
- [`stepfunctions-s3-definition`](../tests/integration/stepfunctions-s3-definition/)
- [`synthetics-canary`](../tests/integration/synthetics-canary/)
