# Belief Registry

## Claims

### access-analyzer-start-resource-scan-empty-response [IN] OBSERVATION
`StartResourceScan` returns HTTP 200 with no body on success — scan results must be retrieved separately via findings APIs (`ListFindings`/`GetFinding`).

### access-analyzer-start-resource-scan-external-only [IN] OBSERVATION
The `StartResourceScan` API action in IAM Access Analyzer works only with external access analyzers — not unused access analyzers or other analyzer types.

### access-analyzer-throttle-retry-after-seconds [IN] OBSERVATION
IAM Access Analyzer throttling (429) and internal server (500) errors include a `retryAfterSeconds` field for backoff guidance.

### acm-certificates-are-regional [IN] OBSERVATION
ACM certificates are regional resources — you cannot copy a certificate between regions.

### acm-cloudfront-requires-us-east-1 [IN] OBSERVATION
For CloudFront, ACM certificates must be requested or imported in the us-east-1 (N. Virginia) region.

### acm-elb-separate-cert-per-region [IN] OBSERVATION
For ELB across multiple regions, you must request or import a separate ACM certificate per region.

### acm-imported-certs-support-self-signed [IN] OBSERVATION
Self-signed certificates are supported in ACM through the import mechanism.

### acm-no-additional-charge [IN] OBSERVATION
ACM itself is free — there is no additional charge for SSL/TLS certificate management; you only pay for underlying AWS resources.

### acm-not-for-standalone-ec2 [IN] OBSERVATION
ACM certificates cannot be used directly on standalone EC2 web servers — only with integrated AWS services (ELB, CloudFront, etc.).

### acm-private-ca-certs-exportable [IN] OBSERVATION
Certificates signed by AWS Private CA can be exported for use in internal PKI.

### acm-private-ca-cross-account-sharing [IN] OBSERVATION
AWS Private CA supports cross-account sharing of certificate authorities.

### acm-private-ca-not-trusted-by-default [IN] OBSERVATION
Certificates signed by AWS Private CA are not publicly trusted by default — administrators must install them in client trust stores.

### acm-public-cert-ec2-requires-nitro-enclave [IN] OBSERVATION
Public ACM certificates can only be installed on EC2 instances connected to a Nitro Enclave, or exported for use on any EC2 instance.

### acm-supports-ipv4-and-ipv6 [IN] OBSERVATION
ACM supports both IPv4 and IPv6 on public endpoints.

### acm-supports-multiple-domain-types [IN] OBSERVATION
ACM certificates can secure singular domain names, multiple specific domains, wildcard domains, or combinations of these on a single certificate.

### acm-supports-wildcard-certificates [IN] OBSERVATION
ACM wildcard certificates protect an unlimited number of subdomains.

### acm-three-certificate-types [IN] OBSERVATION
ACM manages three certificate types: public (issued by ACM), private (signed by AWS Private CA), and imported (third-party or self-signed).

### administrator-access-policy-never-updated-v1 [IN] OBSERVATION
The AdministratorAccess managed policy is version v1 and has never been modified since its creation on February 6, 2015.

### administrator-access-policy-wildcard-action-resource [IN] OBSERVATION
The AdministratorAccess managed policy uses `"Action": "*"` and `"Resource": "*"` in a single Allow statement, granting unrestricted access to every AWS API on every resource.

### amazon-chime-end-of-support-feb-2026 [IN] OBSERVATION
Amazon Chime (the service, not the SDK) reached end of support on February 20, 2026; the Amazon Chime SDK is unaffected.

### amazon-mq-cloudtrail-control-plane-only [IN] OBSERVATION
Amazon MQ CloudTrail integration logs only control-plane API calls; ActiveMQ data-plane operations (message send/receive) and the ActiveMQ Web Console are NOT logged by CloudTrail.

### amazon-mq-cloudtrail-get-responses-redacted [IN] OBSERVATION
Amazon MQ GET/Describe/List API responses are redacted in CloudTrail logs; only request parameters are recorded.

### amazon-mq-cloudtrail-passwords-masked [IN] OBSERVATION
Amazon MQ masks `data` and `password` fields (replaced with `***`) in CloudTrail logs for CreateBroker, CreateUser, UpdateConfiguration, and UpdateUser operations.

### amazon-mq-cloudwatch-for-data-plane-logging [IN] OBSERVATION
Amazon MQ data-plane and ActiveMQ operation logging requires CloudWatch Logs (general and audit logs), not CloudTrail.

### amazon-mq-for-legacy-broker-migration [IN] OBSERVATION
Amazon MQ is recommended for migrating legacy broker-based applications (ActiveMQ, RabbitMQ); SQS and SNS are recommended for new cloud-native applications.

### amazon-mq-reboot-logging-manual-only [IN] OBSERVATION
Amazon MQ RebootBroker events are logged in CloudTrail only for manual reboots, not for automatic maintenance window reboots.

### amazonq-developer-event-source [IN] OBSERVATION
Amazon Q Developer Pro uses `q.amazonaws.com` as the CloudTrail event source; Amazon Q Business uses `qbusiness.amazonaws.com`.

### amazonq-dryrun-calls-logged-cloudtrail [IN] OBSERVATION
Amazon Q makes API calls with `dryRun: true` to verify permissions without executing — these are logged in CloudTrail and distinguishable from actual actions.

### amazonq-passrequest-invokedby-masks-user-ip [IN] OBSERVATION
When Amazon Q calls other AWS APIs on behalf of a user (PassRequest), the CloudTrail event shows both `sourceIPAddress` and `invokedBy` as `q.amazonaws.com`, not the user's IP.

### ami-block-device-mapping [IN] OBSERVATION
The block device mapping in an AMI determines what storage volumes are attached to the instance at launch.

### ami-boot-mode-uefi-or-legacy-bios [IN] OBSERVATION
AMIs specify a boot mode of either UEFI or Legacy BIOS.

### ami-create-from-running-instance [IN] OBSERVATION
A custom AMI can be created from an existing EC2 instance to capture its configuration as a reusable image.

### ami-cross-region-copy [IN] OBSERVATION
AMIs can be copied across AWS Regions to support multi-region deployments.

### ami-ebs-backed-vs-instance-store-backed [IN] OBSERVATION
AMIs can be EBS-backed or instance-store-backed, referring to the root volume type — this distinction affects instance behavior (persistence, stop/start capability).

### ami-five-scoping-attributes [IN] OBSERVATION
An AMI is scoped by five attributes: Region, Operating System, Processor Architecture, Root Volume Type, and Virtualization Type.

### ami-must-match-instance-type [IN] OBSERVATION
The AMI used to launch an instance must be compatible with the chosen instance type (architecture and virtualization type must match).

### ami-one-to-many-instances [IN] OBSERVATION
A single AMI can be used to launch multiple identical EC2 instances.

### ami-preconfigured-template-os-and-software [IN] OBSERVATION
An Amazon Machine Image (AMI) is a preconfigured template containing the OS and software needed to launch an EC2 instance.

### ami-region-specific [IN] OBSERVATION
AMIs are region-specific — an AMI must be copied to another region before it can be used to launch instances there.

### ami-sharing-across-accounts-and-marketplace [IN] OBSERVATION
AMIs can be shared with other AWS accounts or sold via AWS Marketplace; sources include AWS-provided, public community, shared (from other accounts), and AWS Marketplace AMIs.

### amplify-three-event-sources [IN] OBSERVATION
AWS Amplify logs to CloudTrail via three API surfaces with different event sources: `amplify.amazonaws.com` (Console API), `amplifybackend.amazonaws.com` (Admin UI API), and UI Builder API.

### amplify-v6-recommended-appsync-client [IN] OBSERVATION
Amplify v6 is the AWS-recommended client library for connecting to AppSync GraphQL APIs.

### apigateway-account-resource-one-per-region [IN] OBSERVATION
The `AWS::ApiGateway::Account` CloudFormation resource configures the IAM role API Gateway uses to write CloudWatch logs, and is configured once per region.

### apigateway-account-throttle-10k-rps-5k-burst [IN] OBSERVATION
API Gateway account-level throttling defaults are 10,000 requests per second steady-state and 5,000 concurrent burst.

### apigateway-body-transform-in-integration-not-method [IN] OBSERVATION
API Gateway body transformations happen in Integration Request/Response, not in Method Request/Response — the MethodResponse cannot modify the response body.

### apigateway-cache-metrics-hitcount-misscount [IN] OBSERVATION
API Gateway CacheHitCount and CacheMissCount CloudWatch metrics are used to evaluate cache effectiveness.

### apigateway-client-certificate-backend-mtls [IN] OBSERVATION
API Gateway ClientCertificate is used for mutual TLS authentication between API Gateway and the backend, not for client-facing TLS.

### apigateway-cloudwatch-metrics-one-minute-15-month-retention [IN] OBSERVATION
API Gateway sends metrics to CloudWatch automatically in one-minute periods, retained for 15 months.

### apigateway-custom-domain-requires-acm-cert [IN] OBSERVATION
API Gateway custom domain names require an ACM certificate (or imported certificate if ACM is unavailable in the Region).

### apigateway-custom-domain-unique-per-region-all-accounts [IN] OBSERVATION
API Gateway custom domain names must be unique per Region across all AWS accounts.

### apigateway-default-endpoint-disable-returns-403 [IN] OBSERVATION
The API Gateway default endpoint (`api-id.execute-api.region.amazonaws.com`) can be disabled, which returns 403 Forbidden (not a connection refusal).

### apigateway-http-api-endpoint-type-regional-only [IN] OBSERVATION
HTTP APIs support only regional endpoint types; REST APIs support edge-optimized, regional, and private endpoints.

### apigateway-http-api-only-features [IN] OBSERVATION
HTTP API exclusive features include: native JWT authorizers, automatic deployments, AWS Cloud Map private integrations, and built-in CORS support.

### apigateway-lambda-core-serverless-pattern [IN] OBSERVATION
API Gateway combined with AWS Lambda forms the app-facing part of the AWS serverless infrastructure — this is the core AWS serverless API pattern.

### apigateway-latency-vs-integration-latency [IN] OBSERVATION
API Gateway Latency metric measures full round-trip time; IntegrationLatency measures backend-only time. The delta reveals API Gateway overhead.

### apigateway-mtls-rest-and-http-apis [IN] OBSERVATION
API Gateway supports mutual TLS (mTLS) for both REST APIs and HTTP APIs.

### apigateway-multi-level-mappings-require-regional-tls12 [IN] OBSERVATION
API Gateway multi-level API mappings require a Regional custom domain name with TLS 1.2 security policy.

### apigateway-proxy-vs-nonproxy-integration [IN] OBSERVATION
In API Gateway proxy integration, requests/responses pass through unchanged; in non-proxy integration, mapping templates transform requests in Integration Request and responses in Integration Response.

### apigateway-rest-api-caching-get-methods-default [IN] OBSERVATION
When API Gateway stage caching is enabled, only GET methods have caching enabled by default.

### apigateway-rest-api-minimum-five-resources [IN] OBSERVATION
A CloudFormation REST API deployment requires at minimum five resource types: RestApi, Resource, Method, Deployment, and Stage.

### apigateway-rest-api-only-features [IN] OBSERVATION
REST APIs exclusively support: API keys, per-client throttling, request validation, WAF integration, caching, canary releases, private endpoints, edge-optimized endpoints, mock integrations, X-Ray tracing, execution logs, and resource policies.

### apigateway-rest-api-synchronous-only [IN] OBSERVATION
API Gateway REST API interactions are all synchronous — there is no async invocation pattern at the API Gateway level.

### apigateway-rest-api-v1-deployment-model [IN] OBSERVATION
API Gateway REST API (v1) changes don't take effect until a Deployment is created and associated with a Stage — the deployment is an immutable snapshot.

### apigateway-rest-api-vs-v2-http-websocket [IN] OBSERVATION
API Gateway REST API (v1) uses the `apigateway` service namespace; HTTP APIs and WebSocket APIs use API Gateway V2 (`apigatewayv2`) with a different, smaller API surface.

### apigateway-streaming-8-null-byte-delimiter [IN] OBSERVATION
API Gateway Lambda streaming output format requires metadata JSON followed by exactly 8 null bytes as a delimiter before the streamed payload, and the metadata must appear within the first 16KB of stream data.

### apigateway-streaming-requires-mode-and-format [IN] OBSERVATION
API Gateway Lambda response streaming requires both the response transfer mode set to `Stream` and function code adhering to the required metadata+delimiter format — mismatched combinations return a 500 error or missing response body.

### apigateway-streaming-uses-invoke-with-response-stream [IN] OBSERVATION
API Gateway Lambda response streaming uses the `InvokeWithResponseStream` Lambda API instead of the standard `Invoke` API.

### apigateway-supports-canary-release-deployments [IN] OBSERVATION
API Gateway supports canary release deployments for safe rollout of API changes.

### apigateway-three-api-types [IN] OBSERVATION
API Gateway supports three API types: REST APIs, HTTP APIs, and WebSocket APIs.

### apigateway-three-auth-mechanisms [IN] OBSERVATION
API Gateway REST APIs support three authorization mechanisms: IAM permissions, Lambda authorizers, and Amazon Cognito user pools.

### apigateway-tls-1-3-regional-rest-http-websocket [IN] OBSERVATION
API Gateway supports TLS 1.3 for Regional REST APIs, HTTP APIs, and WebSocket APIs (added February 2024).

### apigateway-usage-plan-apikey-three-resources [IN] OBSERVATION
API Gateway throttling and quota control uses three resources together: UsagePlan (throttle/quota limits), ApiKey (credential), and UsagePlanKey (association between them).

### apigateway-usage-plans-throttle-meter-api-keys [IN] OBSERVATION
API Gateway usage plans provide throttling and metering of API requests, associated with API keys and stages.

### apigateway-v1-rest-v2-http-websocket [IN] OBSERVATION
API Gateway V1 (`AWS::ApiGateway::*`) handles REST APIs; API Gateway V2 (`AWS::ApiGatewayV2::*`) handles HTTP APIs and WebSocket APIs — they use different CloudFormation namespaces.

### apigateway-v1-rest-websocket-v2-http [IN] OBSERVATION
API Gateway V1 API covers REST and WebSocket APIs (`apigateway` namespace); V2 API covers HTTP and WebSocket APIs (`apigatewayv2` namespace). CloudFormation uses `AWS::ApiGateway` for V1 and `AWS::ApiGatewayV2` for V2.

### apigateway-v2-http-api-lower-cost-lower-latency [IN] OBSERVATION
HTTP APIs (API Gateway V2) are lower-cost and lower-latency than REST APIs (V1) but have fewer features.

### apigateway-v2-stages-support-auto-deploy [IN] OBSERVATION
API Gateway V2 stages support auto-deploy, unlike V1 REST APIs which require explicit deployments.

### apigateway-vpclink-required-for-private-integrations [IN] OBSERVATION
API Gateway VpcLink is required for private integrations connecting API Gateway to backend services inside a VPC (ALB, NLB, ECS).

### apigateway-vpclink-requires-nlb [IN] OBSERVATION
API Gateway VpcLink connects REST APIs to private VPC resources via Network Load Balancers (NLB) — required for private integrations.

### apigateway-websocket-apis-launched-dec-2018 [IN] OBSERVATION
API Gateway WebSocket APIs launched December 2018; HTTP APIs launched December 2019 (beta) and March 2020 (GA).

### apigw-apigateway-vs-execute-api-planes [IN] OBSERVATION
API Gateway has two service components: `apigateway` (management plane for API creation) and `execute-api` (data plane for API invocation) — this distinction matters for IAM policy actions.

### apigw-aws-config-four-resource-types [IN] OBSERVATION
AWS Config supports four API Gateway resource types: `AWS::ApiGateway::RestApi`, `AWS::ApiGateway::Stage`, `AWS::ApiGatewayV2::Api`, and `AWS::ApiGatewayV2::Stage`.

### apigw-canary-blocks-stage-redeployment [IN] OBSERVATION
A stage with an active canary cannot be reassociated with a different deployment until the canary is disabled and its settings removed.

### apigw-canary-cache-separate-when-different-versions [IN] OBSERVATION
API Gateway canary and production use separate cache keys when pointing to different deployment versions, but share a single cache key when pointing to the same version.

### apigw-canary-separate-cloudwatch-logs [IN] OBSERVATION
API Gateway canary releases produce separate CloudWatch log groups from production, with `/Canary` appended to the standard log group name.

### apigw-canary-traffic-percentage-0-to-100 [IN] OBSERVATION
API Gateway canary release traffic percentage is configurable between 0.0 and 100.0 inclusive.

### apigw-cleanup-four-resources [IN] OBSERVATION
Cleaning up a Lambda-backed API Gateway setup requires deleting four separate resources: the API, the Lambda function, the CloudWatch log group, and the IAM execution role.

### apigw-client-ssl-verifies-backend-not-client [IN] OBSERVATION
API Gateway client-side SSL certificates verify that HTTP requests to the backend originate from API Gateway — they do not verify client-to-API-Gateway connections.

### apigw-cloudtrail-event-source [IN] OBSERVATION
The CloudTrail eventSource for API Gateway events is `apigateway.amazonaws.com`.

### apigw-cloudtrail-excludes-testinvoke [IN] OBSERVATION
API Gateway's TestInvokeAuthorizer and TestInvokeMethod operations are not logged in CloudTrail.

### apigw-config-changes-require-redeployment [IN] OBSERVATION
Changing `binaryMediaTypes`, `minimumCompressionSize`, or `apiKeySource` on a REST API (or `apiKeySelectionExpression` on V2) requires redeployment — AWS Config shows the change immediately but runtime behavior is unchanged until redeployed.

### apigw-default-endpoint-type-regional [IN] OBSERVATION
The default API Gateway REST API endpoint type is Regional.

### apigw-deployment-must-associate-stage [IN] OBSERVATION
An API Gateway deployment must be associated with a stage to be invocable by clients; a deployment is a point-in-time snapshot of the API.

### apigw-edge-optimized-default-endpoint [IN] OBSERVATION
Edge-optimized is the default API Gateway endpoint type; it routes through a CloudFront distribution even for same-region clients.

### apigw-endpoint-hostname-format [IN] OBSERVATION
API Gateway endpoint hostname format is `{api-id}.execute-api.{region}.amazonaws.com`.

### apigw-http-api-cheaper-lower-latency-fewer-features [IN] OBSERVATION
HTTP APIs are cheaper and lower latency than REST APIs but have fewer features (no SDK generation, no API documentation, limited request validation and usage plans).

### apigw-http-api-integration-targets [IN] OBSERVATION
HTTP APIs support integrations with Lambda, HTTP endpoints, private VPC resources, and AWS services (SQS, Step Functions, Kinesis).

### apigw-http-api-lower-cost-fewer-features [IN] OBSERVATION
API Gateway HTTP APIs are lower cost than REST APIs but support fewer features.

### apigw-invoke-url-format [IN] OBSERVATION
API Gateway invoke URL format is `https://{api-id}.execute-api.{region}.amazonaws.com/{stage-or-route}`.

### apigw-lambda-authorizer-two-modes [IN] OBSERVATION
API Gateway Lambda authorizers support two authorization modes: token-based (bearer token) and request-parameter-based (headers, paths, query strings, stage variables, context variables).

### apigw-lambda-proxy-no-transformation [IN] OBSERVATION
Lambda proxy integration passes incoming client requests directly to the Lambda function without request/response transformation by API Gateway.

### apigw-lambda-proxy-response-format [IN] OBSERVATION
Lambda functions used with API Gateway proxy integration must return a response object containing `statusCode` and `body` fields.

### apigw-mapping-templates-use-vtl [IN] OBSERVATION
API Gateway mapping templates use VTL (Velocity Template Language) to transform request/response bodies between frontend and backend formats.

### apigw-models-use-json-schema [IN] OBSERVATION
API Gateway models use JSON Schema to define request/response payload structure; models are required for strongly typed SDK generation but optional for mapping templates.

### apigw-proxy-integration-default-content-type-json [IN] OBSERVATION
When using API Gateway proxy integration with passthrough and no content type specified, the default `Content-Type` returned is `application/json`.

### apigw-proxy-resource-greedy-path-any-method [IN] OBSERVATION
A proxy resource uses a greedy path variable `{proxy+}` with the `ANY` method to catch all sub-paths and HTTP verbs with a single integration; `HTTP_PROXY` passes through without transformation, `AWS_PROXY` uses a default mapping template for Lambda.

### apigw-quick-create-http-api-only [IN] OBSERVATION
Quick create is an HTTP API-only shortcut that creates an API with integration, catch-all route, and auto-deploy default stage.

### apigw-rest-api-requires-stage-deployment [IN] OBSERVATION
REST APIs require explicit deployment to a stage before they are accessible to clients.

### apigw-rest-api-six-access-control-mechanisms [IN] OBSERVATION
API Gateway REST APIs support six access control mechanisms: resource policies, IAM roles/policies, IAM tags, Lambda authorizers, Cognito user pools, and VPC endpoint policies.

### apigw-rest-api-synchronous-request-response [IN] OBSERVATION
API Gateway REST APIs use a synchronous request/response model with three backend integration types: HTTP endpoints, Lambda functions, and AWS services.

### apigw-three-api-types [IN] OBSERVATION
API Gateway supports three API types: REST API (resources + methods), HTTP API (routes + methods, simpler/cheaper), and WebSocket API (routes + route keys, persistent connections).

### apigw-three-endpoint-types [IN] OBSERVATION
API Gateway has three endpoint types: edge-optimized (default, uses CloudFront), regional (direct in-region, no CloudFront), and private (VPC interface endpoints only).

### apigw-usage-plans-api-keys-throttle-quota [IN] OBSERVATION
API Gateway usage plans configure throttling and quota limits enforced per API key on REST and WebSocket APIs.

### apigw-usage-plans-paired-with-api-keys [IN] OBSERVATION
API Gateway usage plans are paired with API keys for throttling and quota enforcement on API stages and methods per customer.

### apigw-vpc-endpoint-policies-private-apis-only [IN] OBSERVATION
VPC endpoint policies in API Gateway apply specifically to private APIs, not to edge-optimized or regional API types.

### apigw-waf-associated-per-stage [IN] OBSERVATION
WAF web ACL association with API Gateway is per API stage, not per API — different stages can have different web ACLs, and only Regional web ACLs (not CloudFront-scoped) work with API Gateway.

### apigw-waf-body-inspection-first-64kb [IN] OBSERVATION
AWS WAF request body inspection for API Gateway is limited to the first 64 KB of the request body.

### apigw-waf-evaluated-first-before-all-auth [IN] OBSERVATION
AWS WAF is evaluated first in the API Gateway access control chain — before resource policies, IAM policies, Lambda authorizers, and Cognito authorizers; if WAF blocks, nothing else is evaluated.

### apigw-waf-rate-based-rules-5min-window [IN] OBSERVATION
AWS WAF rate-based rules limit requests per client IP using a trailing 5-minute window.

### apigw-websocket-at-connections-api-push [IN] OBSERVATION
The `@connections` API allows backend services to send POST requests to push data to specific connected WebSocket API clients.

### apigw-websocket-backend-invoked-per-message [IN] OBSERVATION
WebSocket API connections are persistent between client and API Gateway only; backend integrations (e.g., Lambda) are invoked on-demand per message, not persistently connected.

### apigw-websocket-bidirectional-push [IN] OBSERVATION
API Gateway WebSocket APIs support bidirectional communication — backends can push messages to connected clients without a client request, unlike REST/HTTP APIs.

### apigw-websocket-client-error-vs-integration-error [IN] OBSERVATION
In API Gateway WebSocket APIs, ClientError counts 4XX responses generated by API Gateway before reaching the integration, while IntegrationError counts 4XX/5XX responses from the backend integration.

### apigw-websocket-detailed-metrics-not-default [IN] OBSERVATION
API Gateway WebSocket API detailed per-route metrics are not enabled by default — they require explicit opt-in via `detailedMetricsEnabled` and incur additional CloudWatch charges.

### apigw-websocket-max-2-hours-idle-10-minutes [IN] OBSERVATION
API Gateway WebSocket connections have a maximum lifetime of 2 hours and a 10-minute idle timeout (close status 1001).

### apigw-websocket-no-binary-frames [IN] OBSERVATION
API Gateway WebSocket APIs do not support binary media types — only JSON/text messages are supported (status code 1003 returned for binary frames).

### apigw-websocket-route-selection-expression-api-level [IN] OBSERVATION
The WebSocket API route selection expression is defined at the API level (not per-route) and specifies which JSON property in the message payload determines routing (e.g., `${request.body.action}`).

### apigw-websocket-three-predefined-routes [IN] OBSERVATION
API Gateway WebSocket APIs have three predefined routes: `$connect` (connection initiation/auth), `$disconnect` (disconnection), and `$default` (fallback for unmatched routes and non-JSON messages).

### apigw-xray-rest-api-only [IN] OBSERVATION
API Gateway X-Ray tracing integration applies to REST APIs only — not HTTP APIs or WebSocket APIs.

### apigw-xray-trace-passthrough-without-enablement [IN] OBSERVATION
API Gateway passes through X-Ray traces from upstream callers automatically, even when X-Ray tracing is not explicitly enabled on the API stage.

### apigw-xray-tracing-enabled-per-stage [IN] OBSERVATION
AWS X-Ray tracing for API Gateway is enabled at the stage level, not the API level.

### app-autoscaling-custom-resources-supported [IN] OBSERVATION
Application Auto Scaling can scale custom resources via the `aws-auto-scaling-custom-resource` GitHub framework.

### app-autoscaling-four-scaling-policies [IN] OBSERVATION
Application Auto Scaling supports four scaling policy types: target tracking (metric-driven), step scaling (alarm-breach-driven), scheduled scaling (time-driven), and predictive scaling (ML on historical data).

### app-autoscaling-lambda-provisioned-concurrency-only [IN] OBSERVATION
Application Auto Scaling manages Lambda provisioned concurrency (not regular concurrency).

### app-autoscaling-logs-management-events-only [IN] OBSERVATION
Application Auto Scaling logs all control plane operations as management events (not data events) in CloudTrail.

### app-autoscaling-not-for-ec2-instances [IN] OBSERVATION
Application Auto Scaling handles non-EC2 resources (DynamoDB, ECS, Lambda, Aurora, ElastiCache, etc.); EC2 Auto Scaling handles EC2 instance fleets via Auto Scaling groups.

### app-mesh-eol-september-2026 [IN] OBSERVATION
AWS App Mesh reaches end of support on September 30, 2026, with AWS recommending migration to Amazon ECS Service Connect.

### appconfig-data-event-resource-type [IN] OBSERVATION
AppConfig data events use `AWS::AppConfig::Configuration` as the `resources.type` value in CloudTrail advanced event selectors.

### appconfig-data-events-require-explicit-enablement [IN] OBSERVATION
AppConfig data plane operations (GetLatestConfiguration, StartConfigurationSession) are not logged by CloudTrail by default — they must be explicitly enabled and incur additional charges.

### appflow-response-elements-not-logged [IN] OBSERVATION
Amazon AppFlow intentionally omits response elements from CloudTrail log entries because they may contain sensitive data.

### application-discovery-service-deprecated [IN] OBSERVATION
AWS Application Discovery Service is no longer open to new customers; AWS Transform is the recommended replacement.

### apprunner-cloudtrail-event-source [IN] OBSERVATION
The `eventSource` for AWS App Runner in CloudTrail logs is `apprunner.amazonaws.com`.

### apprunner-cloudtrail-redacts-sensitive-values [IN] OBSERVATION
App Runner redacts sensitive property values (build commands, start commands, environment variables) in CloudTrail logs, replacing them with `HIDDEN_DUE_TO_SECURITY_REASONS`.

### appsync-aurora-integration-via-data-api [IN] OBSERVATION
AppSync integrates with Aurora Serverless (PostgreSQL) specifically via the RDS Data API, not via direct database connections.

### appsync-auth-failures-not-billed [IN] OBSERVATION
AWS AppSync does not charge for authentication/authorization failures or invalid API key calls.

### appsync-auto-provision-dynamodb-from-schema [IN] OBSERVATION
AppSync supports automatic provisioning of DynamoDB tables from a GraphQL schema, as well as importing existing DynamoDB tables with auto-generated schema and resolvers.

### appsync-cloudtrail-data-event-resource-type [IN] OBSERVATION
The CloudTrail resource type for AppSync data event filtering is `AWS::AppSync::GraphQLApi`.

### appsync-cloudtrail-field-authorization-results [IN] OBSERVATION
AppSync CloudTrail data events include field-level authorization results in `additionalEventData.fieldAuthorizationResults`, showing `allowedFields` and `deniedFields`.

### appsync-cloudtrail-request-id-unreliable [IN] OBSERVATION
The `requestID` field in AppSync CloudTrail logs is not authoritative — it can be overwritten by the client and should not be relied upon for unique identification.

### appsync-cloudtrail-websocket-connect-only [IN] OBSERVATION
For AppSync real-time endpoints, only the WebSocket connect operation is logged as a CloudTrail data event — messages sent over the WebSocket are not logged.

### appsync-context-object-carries-resolver-state [IN] OBSERVATION
The AppSync resolver context object (`ctx`) carries `arguments`, `source`, `identity`, `stash`, and `result` — it is central to all resolver logic.

### appsync-data-events-not-logged-by-default [IN] OBSERVATION
AppSync GraphQL data events (query/mutation/subscription operations) are not logged by CloudTrail by default — they must be explicitly enabled and incur additional charges.

### appsync-dynamodb-three-resolver-patterns [IN] OBSERVATION
AppSync DynamoDB resolvers have three distinct patterns: standard CRUD, transactions, and batch operations.

### appsync-events-no-subscription-required-to-publish [IN] OBSERVATION
Publishing to an AppSync Events channel does not require subscribing to that channel first.

### appsync-events-websocket-batch-limit-5 [IN] OBSERVATION
AppSync Events WebSocket publish requests support a maximum of 5 events per batch.

### appsync-events-websocket-subprotocol [IN] OBSERVATION
AppSync Events uses the WebSocket subprotocol `aws-appsync-event-ws` and connects via `wss://WS_DOMAIN/event/realtime`.

### appsync-four-non-console-provisioning-methods [IN] OBSERVATION
AppSync APIs can be provisioned outside the console using four methods: AWS Amplify, AWS SAM, CloudFormation, and CDK.

### appsync-graphql-api-three-components [IN] OBSERVATION
An AWS AppSync GraphQL API requires three core components: a schema, data sources, and resolvers.

### appsync-introspection-schema-via-aws-cli [IN] OBSERVATION
The AppSync schema is downloaded using the AWS CLI command `aws appsync get-introspection-schema` with `--format SDL`, not the Amplify CLI.

### appsync-js-resolver-eight-data-sources [IN] OBSERVATION
APPSYNC_JS resolvers support eight data source types: DynamoDB, OpenSearch, Lambda, EventBridge, None, HTTP, RDS, and Bedrock.

### appsync-js-runtime-preferred-over-vtl [IN] OBSERVATION
AWS recommends the APPSYNC_JS (JavaScript) runtime over VTL for new AppSync resolver development; VTL is considered legacy.

### appsync-merged-api-combines-source-apis [IN] OBSERVATION
AppSync Merged API is a feature that combines multiple source APIs into a single endpoint for multi-team or federated API architectures.

### appsync-merged-apis-federated-graphql [IN] OBSERVATION
AppSync Merged APIs combine multiple source GraphQL APIs into a single federated API, enabling multi-team GraphQL architectures.

### appsync-none-data-source-local-resolvers [IN] OBSERVATION
The AppSync None data source is used for local resolvers that don't call an external service, commonly used for pub/sub subscriptions and pass-through operations.

### appsync-pipeline-resolvers-chain-operations [IN] OBSERVATION
AppSync pipeline resolvers allow chaining multiple resolver functions sequentially in a single field resolution.

### appsync-pure-websockets-only-since-2022 [IN] OBSERVATION
AWS AppSync supports only pure WebSockets for real-time subscriptions since January 1, 2022 (MQTT over WebSockets was fully deprecated).

### appsync-resolver-runtimes-js-and-vtl [IN] OBSERVATION
AppSync resolvers support JavaScript/TypeScript (modern path) and VTL (Velocity Template Language, legacy but still supported) as resolver runtimes.

### appsync-resolvers-two-languages [IN] OBSERVATION
AWS AppSync resolvers support two languages: JavaScript (APPSYNC_JS runtime) and VTL (Velocity Template Language).

### appsync-serverless-graphql-pubsub-service [IN] OBSERVATION
AWS AppSync is a managed serverless service that provides GraphQL and Pub/Sub APIs through a single endpoint, supporting real-time data updates via WebSockets.

### appsync-six-authorization-modes [IN] OBSERVATION
AWS AppSync supports six authorization modes: API key, IAM, Amazon Cognito User Pools, OpenID Connect (OIDC), Lambda custom authorizers, and multiple auth on a single API.

### appsync-subscribe-directive-accepts-mutation-array [IN] OBSERVATION
The `@aws_subscribe(mutations: ["..."])` directive accepts an array, allowing a single subscription to listen to multiple mutations.

### appsync-subscription-null-vs-omitted-argument [IN] OBSERVATION
In AppSync subscriptions, passing `null` as an argument filters for records where the field is unset, while omitting the argument entirely means no filtering on that field.

### appsync-subscriptions-triggered-only-by-mutations [IN] OBSERVATION
AWS AppSync subscriptions are triggered only by mutations — not by queries or direct invocations.

### appsync-websocket-max-payload-240kb [IN] OBSERVATION
AWS AppSync pure WebSocket subscriptions support a maximum payload size of 240 KB.

### artifact-cloudtrail-event-source [IN] OBSERVATION
The CloudTrail `eventSource` for AWS Artifact events is `artifact.amazonaws.com`.

### athena-can-query-its-own-cloudtrail-logs [IN] OBSERVATION
Athena can query its own CloudTrail logs stored in S3 — a circular relationship useful for usage analysis and cost optimization.

### athena-cloudtrail-querystring-always-omitted [IN] OBSERVATION
In CloudTrail logs, the `queryString` field for Athena `StartQueryExecution` and `CreateNamedQuery` events is always `***OMITTED***`; use `GetQueryExecution` API with the `queryExecutionId` to retrieve actual SQL text.

### athena-queries-cloudtrail-logs-directly-from-s3 [IN] OBSERVATION
Amazon Athena can query CloudTrail logs directly from S3 using standard SQL, without ETL or data loading.

### audit-architecture-simultaneously-fragile-and-quota-constrained [IN] OBSERVATION
Building real-time security audit infrastructure requires a fragile multi-service integration chain (CloudTrail → CloudWatch Logs → metric filters → alarms, each requiring its own IAM and configuration) AND faces hard quota limits (5 trails per region) with incremental costs for additional management event copies — the architecture needed for real-time alerting is both brittle and bounded.

### audit-infrastructure-must-be-proactively-built-within-hard-constraints [IN] OBSERVATION
Real-time audit infrastructure must be proactively built (Lake requires irrevocable KMS decisions, Insights needs up to 7 days for first delivery) within hard quota constraints (5 trails per region, incremental cost per coverage dimension) using fragile multi-service chains (CloudTrail → CloudWatch Logs → metric filters → alarms) — there is no fast path to audit readiness at incident time.

### audit-manager-delegated-admin-cross-account-evidence-search [IN] OBSERVATION
Audit Manager delegated administrators can search evidence across all member accounts in an AWS Organization using evidence finder.

### audit-manager-eventsource-cloudtrail [IN] OBSERVATION
The CloudTrail `eventSource` for AWS Audit Manager API calls is `auditmanager.amazonaws.com`.

### audit-manager-evidence-finder-not-enabled-by-default [IN] OBSERVATION
AWS Audit Manager's evidence finder must be explicitly enabled from Audit Manager settings before use; it is not enabled by default.

### audit-manager-evidence-finder-retention-2yr-default-7yr-max [IN] OBSERVATION
Audit Manager evidence finder has a default retention of 2 years, configurable up to 7 years (2,555 days); it backfills 2 years of historical evidence upon enablement.

### audit-manager-evidence-finder-uses-cloudtrail-lake [IN] OBSERVATION
Audit Manager's evidence finder uses CloudTrail Lake as its backend, automatically creating an event data store when enabled.

### audit-proactive-investment-still-blind-to-automated-cost-mutations [IN] OBSERVATION
Even proactively built audit infrastructure (requiring irrevocable KMS decisions and multi-day cold-start delays) cannot observe DynamoDB automated operations that simultaneously create cost mutations and audit blind spots — the observability ceiling is structural, not a configuration gap

### aurora-continuous-backup-snapshots-free-within-retention [IN] OBSERVATION
Aurora continuous backup snapshots within the configured retention period (up to 35 days) incur no storage charge; snapshots kept beyond that window are charged as full backups.

### aurora-dsql-active-active-no-failover [IN] OBSERVATION
Aurora DSQL clusters are active-active by default with automatic failure recovery — no traditional primary-secondary failover configuration is needed.

### aurora-dsql-fis-connection-error-injection [IN] OBSERVATION
AWS FIS can inject elevated connection error rates into Aurora DSQL clusters for chaos engineering testing.

### aurora-dsql-multi-az-by-default-three-azs [IN] OBSERVATION
Aurora DSQL single-Region clusters automatically have Multi-AZ availability across three AZs with no manual configuration required.

### aurora-dsql-multi-region-same-continent-only [IN] OBSERVATION
Aurora DSQL multi-Region clusters cannot span continents — they must stay within a single Region set (US, APAC, or Europe).

### aurora-dsql-serverless-postgresql-16-compatible [IN] OBSERVATION
Aurora DSQL is a serverless distributed relational database compatible with PostgreSQL version 16, working with standard PostgreSQL drivers, ORMs, and `psql`.

### aurora-dsql-sla-single-multi-region [IN] OBSERVATION
Aurora DSQL provides 99.99% availability for single-Region clusters and 99.999% availability for multi-Region clusters.

### aurora-dsql-snapshot-isolation [IN] OBSERVATION
Aurora DSQL uses snapshot isolation for ACID transactions with strong consistency, even in multi-Region configurations.

### aurora-dsql-synchronous-replication-no-lag [IN] OBSERVATION
Aurora DSQL uses synchronous replication for all write transactions, eliminating data loss risk from replication lag or async failover.

### aurora-dsql-witness-region-logs-only [IN] OBSERVATION
In Aurora DSQL multi-Region clusters, the witness Region stores only encrypted transaction logs, has no user-accessible endpoint, and its impairment causes slight latency increase but no availability impact.

### aurora-eventsource-rds-amazonaws-com [IN] OBSERVATION
Aurora's CloudTrail `eventSource` is `rds.amazonaws.com` because Aurora shares the RDS API surface — there is no Aurora-specific event source.

### aurora-zero-etl-global-db-failover-breaks-integration [IN] OBSERVATION
Aurora Global Database failover makes zero-ETL integrations inactive — they must be deleted and recreated.

### aurora-zero-etl-mysql-innodb-only [IN] OBSERVATION
Aurora zero-ETL integrations with Aurora MySQL only support the InnoDB storage engine; foreign keys with CASCADE/SET NULL/SET DEFAULT cause table failure.

### aurora-zero-etl-postgresql-primary-keys-required [IN] OBSERVATION
Aurora zero-ETL integrations with Aurora PostgreSQL require primary keys on all filtered tables, at least one data filter, and UTF-8 encoding.

### aurora-zero-etl-quotas-100-per-account-50-per-target-5-per-source [IN] OBSERVATION
Aurora zero-ETL integration quotas per Region: 100 integrations per account, 50 per target, 5 per source cluster.

### aurora-zero-etl-source-target-same-region [IN] OBSERVATION
Aurora zero-ETL integrations require the source Aurora cluster and target (Redshift or SageMaker lakehouse) to be in the same Region.

### aws-account-closure-10pct-rolling-limit [IN] OBSERVATION
Organizations have a 10% rolling 30-day limit on closing member accounts (minimum 10, maximum 1000 closures per period).

### aws-account-closure-90-day-post-closure-period [IN] OBSERVATION
After closing an AWS account, there is a 90-day post-closure period during which the account can be reopened; after 90 days, AWS permanently closes the account and deletes all content/resources.

### aws-account-closure-hardware-mfa-locked [IN] OBSERVATION
Hardware TOTP tokens are not automatically removed on AWS account closure and become permanently locked to the closed account unless deactivated beforehand.

### aws-account-closure-root-user-only-standalone [IN] OBSERVATION
Only the root user can close standalone and management AWS accounts — IAM users and roles cannot perform this action; there is no CLI/API support for closing these account types.

### aws-account-id-never-reused [IN] OBSERVATION
After permanent closure, an AWS account ID can never be reused.

### aws-account-reopen-60-day-limit [IN] OBSERVATION
Reopening a closed AWS account requires contacting AWS Support and paying the outstanding balance within 60 days of closure.

### aws-alternate-contact-types-three [IN] OBSERVATION
AWS accounts support three alternate contact types: SECURITY, BILLING, and OPERATIONS.

### aws-autoscaling-plans-distinct-api-from-ec2-autoscaling [IN] OBSERVATION
AWS Auto Scaling scaling plans use a distinct API namespace (`autoscaling-plans`) from EC2 Auto Scaling, though both share the eventSource `autoscaling.amazonaws.com`.

### aws-backup-dynamodb-cross-account-cross-region [IN] OBSERVATION
AWS Backup enables cross-account and cross-Region backup copying for DynamoDB — native DynamoDB on-demand backups do not support this.

### aws-backup-dynamodb-opt-in-per-account-region [IN] OBSERVATION
AWS Backup requires explicit opt-in per account and per Region before it can manage DynamoDB backups.

### aws-backup-first-backup-full-subsequent-incremental [IN] OBSERVATION
AWS Backup performs a full copy for the first backup of a resource; subsequent backups are incremental (changes only), reducing storage costs.

### aws-backup-plan-defines-schedule-lifecycle-retention [IN] OBSERVATION
An AWS Backup backup plan is a policy expression that defines backup schedule, lifecycle transitions, and retention for assigned AWS resources.

### aws-backup-scheduled-backups-not-native-dynamodb [IN] OBSERVATION
Scheduled automatic backups of DynamoDB tables require AWS Backup — this capability is not available natively in DynamoDB.

### aws-backup-vault-independent-kms-key [IN] OBSERVATION
Backups stored in AWS Backup vaults can use a KMS key independent from the source resource's (e.g., DynamoDB table's) encryption key.

### aws-backup-vault-lock-worm-immutability [IN] OBSERVATION
AWS Backup Vault Lock provides WORM (write-once-read-many) immutability, protecting backups against both accidental and malicious deletion, recovery period changes, or lifecycle modifications.

### aws-backup-window-optimized-by-default [IN] OBSERVATION
AWS Backup optimizes the backup window by default; it can be customized via the console or programmatically.

### aws-cli-command-structure-options-command-subcommand [IN] OBSERVATION
The AWS CLI command structure follows: `aws [options] <command> <subcommand> [parameters]`

### aws-cli-default-timeout-60-seconds [IN] OBSERVATION
The AWS CLI default socket read and connect timeouts are both 60 seconds; set to 0 for blocking (no timeout)

### aws-cli-fileb-always-binary-file-respects-setting [IN] OBSERVATION
The `fileb://` prefix always treats content as raw binary regardless of `--cli-binary-format` setting; `file://` behavior depends on the `--cli-binary-format` setting

### aws-cli-no-sign-request-public-resources [IN] OBSERVATION
The AWS CLI `--no-sign-request` flag skips request signing, allowing access to public resources (e.g., public S3 buckets) without credentials

### aws-cli-output-formats-six-types [IN] OBSERVATION
The AWS CLI supports six output formats: json, text, table, yaml, yaml-stream, and off

### aws-cli-query-uses-jmespath [IN] OBSERVATION
The AWS CLI `--query` parameter uses JMESPath syntax (not SQL or JSONPath) for filtering response data

### aws-config-dedicated-host-license-tracking [IN] OBSERVATION
AWS Config is the service used for tracking Dedicated Host configuration changes for license compliance (per-socket, per-core BYOL), not CloudTrail or CloudWatch.

### aws-config-dedicated-host-resource-type [IN] OBSERVATION
The AWS Config resource type for EC2 Dedicated Hosts is `AWS::EC2::Host`.

### aws-config-s3-bucket-policy-source-account-condition [IN] OBSERVATION
When granting AWS Config access to an S3 bucket, the bucket policy should use the `AWS:SourceAccount` condition key to prevent confused deputy attacks by ensuring access is only on behalf of expected accounts.

### aws-config-three-recording-conditions-dedicated-hosts [IN] OBSERVATION
AWS Config requires all three recording conditions enabled for Dedicated Host tracking: Config recording status, host recording status, and instance recording status.

### aws-console-cli-defaults-diverge-creating-drift-risk [IN] OBSERVATION
AWS automation defaults differ between console and CLI/API interfaces — auto-scaling enabled by default in console but not CLI — creating configuration drift when teams mix interfaces.

### aws-cost-explorer-13-months-history-12-months-forecast [IN] OBSERVATION
AWS Cost Explorer shows up to 13 months of historical cost data and forecasts up to 12 months ahead.

### aws-database-services-hide-billing-complexity-behind-simple-interfaces [IN] OBSERVATION
AWS database services systematically hide billing complexity behind simple provisioning interfaces — RDS abstracts EBS volume striping and three storage types behind instance selection while DynamoDB hides per-item indexing overhead, KB rounding penalties, and GSI storage costs behind capacity unit pricing — creating a structural gap between perceived and actual cost across the data tier.

### aws-default-regions-pre-march-2019-cannot-disable [IN] OBSERVATION
AWS Regions launched before March 20, 2019 are default Regions — always enabled and cannot be disabled; Regions launched after that date are opt-in and must be explicitly enabled.

### aws-deletion-safety-semantics-inconsistent-across-services [IN] OBSERVATION
AWS deletion safety semantics are inconsistent across services — DynamoDB table deletion is permanent and irreversible with no default protection, CloudTrail Lake enables termination protection by default, and DynamoDB global table deletion protection must be configured independently per replica region — organizations cannot rely on uniform deletion safety behavior.

### aws-disable-region-does-not-delete-resources [IN] OBSERVATION
Disabling an opt-in AWS Region deactivates IAM access but does not delete resources — charges continue for any resources remaining in the disabled Region.

### aws-managed-policy-arn-empty-account-field [IN] OBSERVATION
AWS managed policy ARNs use an empty account field: `arn:aws:iam::aws:policy/PolicyName`.

### aws-managed-policy-max-five-versions [IN] OBSERVATION
AWS managed policies can have up to 5 versions with one designated as the default.

### aws-partitions-hard-iam-boundaries [IN] OBSERVATION
AWS partitions (`aws`, `aws-cn`, `aws-us-gov`) are hard IAM boundaries — credentials and IAM data do not cross partition boundaries.

### aws-recommends-cognito-over-direct-sts-for-mobile [IN] OBSERVATION
For mobile apps, AWS recommends Amazon Cognito over direct STS web identity federation.

### aws-recommends-savings-plans-over-reserved-instances [IN] OBSERVATION
AWS officially recommends Savings Plans over Reserved Instances for new commitments due to greater flexibility.

### aws-region-enable-disable-cli-commands [IN] OBSERVATION
Opt-in Regions are managed via `aws account enable-region --region-name <region>` and `aws account disable-region --region-name <region>`; status checked with `aws account get-region-opt-status`.

### aws-resilience-defaults-suboptimal-at-every-geographic-scope [IN] OBSERVATION
AWS resilience defaults are suboptimal at both AZ scope (single-AZ default for EBS volumes and DAX clusters) and region scope (eventual consistency default for DynamoDB global tables and RDS cross-region replication), requiring explicit opt-in at every geographic level for production-grade resilience.

### aws-resource-properties-split-into-creation-immutable-and-runtime-mutable [IN] OBSERVATION
AWS resource properties consistently divide into creation-time immutable (DynamoDB LSI/consistency mode, CloudTrail Lake KMS keys, SLR names) and runtime-mutable (DynamoDB GSI/table class) categories.

### aws-support-all-api-calls-logged-by-cloudtrail [IN] OBSERVATION
All AWS Support API operations are logged by CloudTrail comprehensively — this is not selective logging.

### az-code-to-physical-zone-mapping-is-per-account [IN] OBSERVATION
Availability Zone code-to-physical-zone mapping is account-specific — the same AZ code (e.g., us-east-1a) can represent different physical zones in different AWS accounts.

### az-failure-protection-requires-explicit-multi-az-for-all-data-tiers [IN] OBSERVATION
Single-AZ is the default scope for EBS volumes and DAX clusters; surviving AZ failure requires explicit multi-AZ configuration across every data tier (EBS, DAX, RDS).

### b2bi-cloudtrail-redacts-sensitive-fields [IN] OBSERVATION
AWS B2B Data Interchange redacts sensitive fields (S3 bucket names, keys, EDI transaction details) in CloudTrail logs, marking them `HIDDEN_DUE_TO_SECURITY_REASONS`.

### b2bi-events-management-events-in-cloudtrail [IN] OBSERVATION
AWS B2B Data Interchange events are classified as management events (not data events) in CloudTrail, with event source `b2bi.amazonaws.com`.

### backup-air-gapped-vault-all-charges-to-backup [IN] OBSERVATION
AWS Backup Logically Air-Gapped Vaults shift all backup charges to the AWS Backup bill regardless of whether the resource supports full AWS Backup management.

### backup-aurora-neptune-documentdb-always-require-opt-in [IN] OBSERVATION
Aurora, Neptune, and Amazon DocumentDB always require explicit AWS Backup service opt-in — they are exceptions to the rule that explicitly assigned resource types bypass opt-in settings.

### backup-cloudtrail-service-events-not-api-calls [IN] OBSERVATION
AWS Backup generates CloudTrail events that are not tied to public API calls (e.g., `BackupJobCompleted` has eventType `AwsServiceEvent`, not `AwsApiCall`).

### backup-cloudwatch-namespace-aws-backup [IN] OBSERVATION
AWS Backup publishes metrics to CloudWatch under the `AWS/Backup` namespace with a 5-minute update interval.

### backup-cold-storage-90-day-minimum-immutable [IN] OBSERVATION
AWS Backup cold storage has a minimum retention of 90 days, which cannot be changed after transition; the total retention period must exceed the cold storage transition value by more than 90 days.

### backup-cold-storage-minimum-90-days-beyond-warm [IN] OBSERVATION
AWS Backup cold storage requires a minimum 90-day retention beyond the warm-to-cold transition point; `DeleteAfterDays` must be at least `MoveToColdStorageAfterDays + 90`.

### backup-completed-with-issues-console-only [IN] OBSERVATION
The "Completed with issues" backup job status exists only in the AWS Backup console and is not trackable via CloudWatch metrics.

### backup-continuous-pitr-retention-1-to-35-days [IN] OBSERVATION
AWS Backup continuous backups (PITR) have a retention limit of 1–35 days and cannot be scheduled with cron expressions.

### backup-copy-job-uses-destination-vault-dimension [IN] OBSERVATION
AWS Backup copy job CloudWatch metrics use the destination vault name (not source) as their vault dimension.

### backup-cross-account-aws-managed-key-not-supported [IN] OBSERVATION
Cross-account AWS Backup copies require customer managed KMS keys for resources not fully managed by AWS Backup — AWS managed keys cannot be used because their key policies are immutable and cannot be shared.

### backup-cross-account-copy-billing-differs-by-management [IN] OBSERVATION
For AWS Backup cross-account/cross-Region copies, fully managed resources bill data transfer to the source account, while non-fully managed resources bill to the destination account.

### backup-cross-account-copy-into-vault-action [IN] OBSERVATION
The `backup:CopyIntoBackupVault` action must be explicitly allowed on the destination vault via resource-based policy for cross-account backup copies.

### backup-cross-account-dest-vault-requires-cmk [IN] OBSERVATION
The destination vault for cross-account backup must use a customer managed KMS key — the default vault (with AWS managed key) cannot be used because its key cannot be shared across accounts.

### backup-cross-account-disable-15min-eventual-consistency [IN] OBSERVATION
After disabling cross-account backup in AWS Backup, jobs may still run for up to 15 minutes due to eventual consistency.

### backup-cross-account-no-cold-tier [IN] OBSERVATION
AWS Backup cross-account copies do not support cold tier storage.

### backup-cross-account-no-direct-restore [IN] OBSERVATION
AWS Backup does not support restoring directly across accounts — backups must be copied to the target account first, then restored locally.

### backup-cross-account-requires-organizations [IN] OBSERVATION
AWS Backup cross-account backup requires AWS Organizations to be configured first.

### backup-cross-account-requires-same-org [IN] OBSERVATION
AWS Backup cross-account backup requires all accounts to belong to the same AWS Organizations organization.

### backup-cross-region-copy-reencrypts-destination-key [IN] OBSERVATION
AWS Backup cross-Region copies are re-encrypted using the destination vault's customer managed KMS key.

### backup-delegated-admin-cannot-override-opt-in [IN] OBSERVATION
AWS Backup delegated administrator accounts can manage backup policies and monitor cross-account jobs but cannot override service opt-in settings of other member accounts — only the management account can.

### backup-ebs-encryption-change-forces-full-copy [IN] OBSERVATION
Changing the encryption status during an Amazon EBS snapshot copy forces a full (non-incremental) copy.

### backup-ebs-incremental-becomes-full-in-cold [IN] OBSERVATION
EBS incremental backups become full backups when transitioned to cold storage in AWS Backup.

### backup-ec2-restore-requires-passrole-instance-profile [IN] OBSERVATION
EC2 restores via AWS Backup require an additional `iam:PassRole` statement for the EC2 instance profile role, not the Backup service role.

### backup-encrypted-restore-needs-kms-permissions [IN] OBSERVATION
Restoring encrypted AWS Backup recovery points requires either KMS key policy allowlisting or explicit KMS permissions (`KMSDescribePermissions`, `KMSPermissions`, `KMSCreateGrantPermissions`) on the restore role.

### backup-event-source-aws-backup [IN] OBSERVATION
All AWS Backup EventBridge events use `"source": "aws.backup"` and all CloudTrail events use `eventSource: backup.amazonaws.com`.

### backup-eventbridge-best-effort-5-minutes [IN] OBSERVATION
AWS Backup emits events to Amazon EventBridge on a best-effort basis every 5 minutes — not real-time delivery.

### backup-eventbridge-more-event-types-than-sns [IN] OBSERVATION
AWS Backup EventBridge integration covers more event types than the SNS notification API, including vault changes, copy jobs, region settings, and cold/warm recovery point counts.

### backup-expired-recovery-points-still-billed [IN] OBSERVATION
Expired AWS Backup recovery points that couldn't be automatically deleted still incur storage charges and must be manually deleted.

### backup-expired-state-concurrent-job-conflict [IN] OBSERVATION
AWS Backup job EXPIRED state occurs when a job couldn't start because another backup job for the same resource was already running.

### backup-failed-copy-jobs-not-charged [IN] OBSERVATION
Failed AWS Backup copy jobs incur no charge — billing only occurs when a recovery point is successfully created in the destination vault.

### backup-first-cross-region-copy-always-full [IN] OBSERVATION
The first AWS Backup cross-Region copy is always a full copy; subsequent copies are incremental for services that support it.

### backup-full-management-own-arn-independent-kms [IN] OBSERVATION
Full AWS Backup management gives backups their own `arn:aws:backup` ARNs (enabling backup-specific IAM policies) and independent KMS encryption using the vault key rather than the source resource key.

### backup-fullaccess-vs-operatoraccess [IN] OBSERVATION
AWSBackupOperatorAccess can assign resources to plans and create on-demand backups but cannot create/edit backup plans or delete scheduled backups; AWSBackupFullAccess can do all of these.

### backup-fully-managed-incremental-same-vault [IN] OBSERVATION
For fully-managed AWS Backup resource types, incremental backups require an earlier backup in the same vault; non-fully-managed types only need one in the same Region.

### backup-incremental-allows-full-restore-after-base-deleted [IN] OBSERVATION
AWS Backup incremental backups retain enough reference data to perform a full restore even after the original full backup has been deleted.

### backup-independent-encryption-fully-managed-only [IN] OBSERVATION
AWS Backup independent encryption (using vault's KMS key instead of source resource's key) is only available for fully-managed resource types: S3, VMware VMs, DynamoDB (Advanced), EFS, Timestream, CloudFormation, and SAP HANA on EC2.

### backup-job-created-to-expired-start-window [IN] OBSERVATION
AWS Backup jobs transition from CREATED to EXPIRED if the backup cannot begin within the configured start window.

### backup-job-nine-statuses [IN] OBSERVATION
AWS Backup jobs have 9 possible statuses: CREATED, PENDING, RUNNING, ABORTING, ABORTED, COMPLETED, FAILED, EXPIRED, and PARTIAL.

### backup-kms-three-minimum-permissions [IN] OBSERVATION
The three minimum KMS key policy permissions required for AWS Backup operations are `kms:CreateGrant`, `kms:GenerateDataKey`, and `kms:Decrypt`.

### backup-maintenance-window-block-1hr-fsx-4hr-aurora-exempt [IN] OBSERVATION
AWS database services cannot start backups 1 hour before or during maintenance windows; FSx blocks 4 hours before/during; Aurora is exempt from this restriction.

### backup-max-5-delegated-admins [IN] OBSERVATION
Up to 5 delegated administrator accounts can be registered for AWS Backup via the console.

### backup-new-services-not-auto-opted-in [IN] OBSERVATION
When AWS Backup adds support for new services in a Region after initial account setup, those services are not automatically opted in — manual opt-in is required.

### backup-on-demand-cannot-use-pitr [IN] OBSERVATION
On-demand AWS Backup backups cannot be used with Point-in-Time Recovery (PITR) — PITR requires continuous backups.

### backup-only-governs-backups-created-through-service [IN] OBSERVATION
AWS Backup only governs backups created through AWS Backup — native service snapshots created independently are not centralized or managed by AWS Backup.

### backup-opt-in-per-account-per-region [IN] OBSERVATION
AWS Backup service opt-in is configured per account and per Region — not globally.

### backup-org-policy-mgmt-account-opt-in-overrides [IN] OBSERVATION
For backup plans created by AWS Organizations-level policies, the management account's opt-in settings override member account settings; locally-created backup plans follow the member account's own opt-in settings.

### backup-overlapping-rules-longer-retention-wins [IN] OBSERVATION
When two AWS Backup plan rules have overlapping start windows, AWS Backup keeps only the backup with the longer retention period.

### backup-plan-name-max-50-chars [IN] OBSERVATION
AWS Backup plan names have a maximum of 50 characters, allowing alphanumeric characters, dashes, underscores, and periods.

### backup-retention-semantics-conflict-across-storage-tiers [IN] OBSERVATION
AWS Backup cold storage requires a minimum 90-day retention beyond the warm-to-cold transition while continuous PITR backups max out at 35 days — organizations must plan for fundamentally different retention windows across backup tiers, and cannot unify continuous and archival retention into a single policy

### backup-s3-always-encrypted [IN] OBSERVATION
S3 backups created by AWS Backup are always encrypted, even if the source bucket is unencrypted.

### backup-s3-dedicated-iam-policies [IN] OBSERVATION
AWS Backup S3 backup and restore have dedicated IAM policies (`AWSBackupServiceRolePolicyForS3Backup` and `AWSBackupServiceRolePolicyForS3Restore`) separate from the general backup/restore service role policies.

### backup-snapshot-retention-1-day-to-100-years [IN] OBSERVATION
AWS Backup snapshot retention ranges from 1 day to 100 years (or indefinite).

### backup-strategy-faces-conflicting-retention-and-state-reset [IN] OBSERVATION
AWS backup strategy faces compounding structural conflicts: cold storage demands 90+ day retention while PITR maxes at 35 days, AND recovery restores do not preserve PITR configuration — organizations must bridge a retention gap while manually re-enabling the very protection that would cover it.

### backup-tag-based-respects-opt-in-explicit-does-not [IN] OBSERVATION
AWS Backup tag-based resource assignments respect service opt-in settings, while explicitly assigned resource types are backed up regardless of opt-in (except Aurora, Neptune, and DocumentDB).

### backup-unencrypted-aurora-docdb-neptune-stays-unencrypted [IN] OBSERVATION
Copies of unencrypted Aurora, DocumentDB, and Neptune clusters remain unencrypted even when copied by AWS Backup.

### backup-vault-content-immutable [IN] OBSERVATION
AWS Backup vault content is immutable — no one can alter the content of backups stored in a vault.

### backup-vault-lock-governance-vs-compliance-mode [IN] OBSERVATION
AWS Backup Vault Lock has two modes: Governance (removable by users with sufficient IAM permissions) and Compliance (immutable after grace time expires); the `ChangeableForDays` parameter creates Compliance mode, omitting it creates Governance mode.

### backup-vault-lock-grace-time-3-to-36500-days [IN] OBSERVATION
AWS Backup Vault Lock Compliance mode grace time (cooling-off period) ranges from a minimum of 3 days to a maximum of 36,500 days (~100 years); after it expires, the lock is permanently immutable.

### backup-vault-lock-not-glacier-vault-lock [IN] OBSERVATION
AWS Backup Vault Lock is a different feature from Amazon S3 Glacier Vault Lock — they have different scope and functionality.

### backup-vault-lock-retention-only-new-jobs [IN] OBSERVATION
AWS Backup Vault Lock retention period enforcement (min/max days) only affects new backup/copy jobs; existing recovery points are not affected retroactively.

### backup-vault-lock-root-cannot-override [IN] OBSERVATION
AWS Backup Vault Lock prevents recovery point deletion by any user including the AWS account root user; however, account closure overrides vault lock after the 90-day suspension period.

### backup-vault-lock-sec-17a4-cftc-finra [IN] OBSERVATION
AWS Backup Vault Lock is assessed for compliance with SEC 17a-4, CFTC, and FINRA regulations.

### backup-vault-requires-kms-key [IN] OBSERVATION
Each AWS Backup vault requires an AWS KMS encryption key at creation time; some backups are encrypted by the vault's KMS key while others are encrypted by their source AWS service.

### backup-warm-storage-minimum-one-week [IN] OBSERVATION
AWS Backup warm storage retention of less than one week can force daily full backups instead of incremental, significantly increasing costs.

### batch-cloudtrail-event-history-without-trail [IN] OBSERVATION
AWS Batch events are visible in CloudTrail Event History without creating a trail; a trail is required only for continuous persistent delivery to S3.

### batch-cloudtrail-logs-all-api-calls [IN] OBSERVATION
AWS Batch integrates with CloudTrail to log all API calls as events, including calls from the console and programmatic API/SDK calls.

### bedrock-cloudtrail-data-event-resource-types [IN] OBSERVATION
Amazon Bedrock supports eight CloudTrail data event resource types: AgentAlias, KnowledgeBase, FlowAlias, Guardrail, Model, AsyncInvoke, InlineAgent, and Prompt.

### bedrock-data-events-require-advanced-selectors [IN] OBSERVATION
Amazon Bedrock data events (InvokeAgent, Retrieve, RetrieveAndGenerate, InvokeFlow, etc.) require advanced event selectors to enable and incur additional CloudTrail charges.

### bedrock-eventsource-bedrock-amazonaws-com [IN] OBSERVATION
The CloudTrail `eventSource` for Amazon Bedrock is `bedrock.amazonaws.com`.

### bedrock-guardduty-monitors-management-events [IN] OBSERVATION
Amazon GuardDuty automatically analyzes CloudTrail management events for suspicious Bedrock API activity, such as removing Guardrails or changing training data S3 buckets.

### bedrock-invokemodel-converse-are-management-events [IN] OBSERVATION
Amazon Bedrock's `InvokeModel`, `InvokeModelWithResponseStream`, `Converse`, and `ConverseStream` are logged as CloudTrail management events (logged by default), not data events.

### billing-cloudtrail-events-logged-in-us-east-1 [IN] OBSERVATION
AWS Billing CloudTrail events are logged in us-east-1 because billing is a global service routed through that region.

### billing-cloudtrail-payment-data-auto-redacted [IN] OBSERVATION
Sensitive payment instrument details (card numbers, CVV, addresses) are automatically redacted as `HIDDEN_DUE_TO_SECURITY_REASONS` in billing-related CloudTrail logs — no configuration required.

### billing-conductor-all-management-events [IN] OBSERVATION
All AWS Billing Conductor API calls are logged by CloudTrail as management events (not data events).

### billing-conductor-auto-events-awsserviceevent-type [IN] OBSERVATION
AWS Billing Conductor automatic operations (e.g., AutoAssociateAccount) appear in CloudTrail as `eventType: AwsServiceEvent` with `invokedBy: billingconductor.amazonaws.com`, while user-initiated calls appear as `AwsApiCall`.

### billing-conductor-does-not-change-actual-bill [IN] OBSERVATION
AWS Billing Conductor generates an alternative billing view for showback/chargeback workflows — it does not modify the actual AWS bill.

### billing-conductor-sensitive-parameter-masking [IN] OBSERVATION
AWS Billing Conductor redacts sensitive parameters (e.g., the `Name` field in CreateBillingGroup appears as `"***"`) in CloudTrail log entries.

### billing-console-iam-access-must-be-activated [IN] OBSERVATION
By default, IAM users and roles cannot access the AWS Billing console — the **Activate IAM Access** setting must be enabled by the root user first.

### braket-cloudtrail-logs-all-api-actions [IN] OBSERVATION
All Amazon Braket API actions are logged by CloudTrail with no opt-in required; the `eventSource` is `braket.amazonaws.com`.

### budgets-actions-can-apply-iam-deny-policies [IN] OBSERVATION
AWS Budget actions can automatically enforce IAM policies (e.g., deny resource provisioning) when budget thresholds are crossed.

### budgets-six-types [IN] OBSERVATION
AWS Budgets supports six budget types: Cost, Usage, RI utilization, RI coverage, Savings Plans utilization, and Savings Plans coverage.

### budgets-support-forecasted-alerts [IN] OBSERVATION
AWS Budgets supports forecasted alerts (triggered before costs actually accrue), not just actual-spend alerts.

### budgets-update-frequency-three-times-per-day [IN] OBSERVATION
AWS Budgets updates up to 3 times per day (typically 8–12 hours between updates) — notifications are not real-time and costs may exceed thresholds before alerts arrive.

### byoip-aws-checks-ip-reputation [IN] OBSERVATION
AWS checks IP reputation for BYOIP ranges and may reject ranges with poor history.

### byoip-limit-5-ranges-per-region [IN] OBSERVATION
BYOIP has a limit of 5 address ranges per Region (IPv4 + IPv6 combined); increases require AWS Support.

### byoip-most-specific-ipv4-slash-24-ipv6-slash-48 [IN] OBSERVATION
BYOIP most specific address range is /24 for IPv4 and /48 for publicly advertisable IPv6 (/60 for non-publicly advertisable IPv6).

### byoip-not-wavelength-or-outposts [IN] OBSERVATION
BYOIP is not supported in Wavelength Zones or AWS Outposts; BYOIPv6 is also not supported in Local Zones.

### byoip-one-region-at-a-time [IN] OBSERVATION
Each BYOIP address range can only be brought to one AWS Region at a time.

### byoip-requires-business-entity-registration [IN] OBSERVATION
BYOIP address ranges must be registered to a business or institutional entity, not an individual person.

### capacity-block-expiration-warning-40-minutes [IN] OBSERVATION
EC2 Capacity Block reservations emit an expiration warning event 40 minutes before reservation end; instances begin terminating 30 minutes before end (10 minutes after the warning).

### capacity-block-instance-lifecycle-field [IN] OBSERVATION
Capacity Block instance interruption events use `instance-lifecycle: capacity-block` and `instance-action: terminate` — distinguishing them from Spot Instance interruption events.

### cdk-construct-three-arguments [IN] OBSERVATION
Every CDK construct takes three arguments: scope (parent, typically `this`/`self`), id (logical name), and props (configuration object, may be optional).

### cdk-constructs-base-class-separate-library [IN] OBSERVATION
The `Construct` base class is in a separate `constructs` library, not bundled within `aws-cdk-lib`.

### cdk-constructs-three-positional-args [IN] OBSERVATION
All CDK constructs take three arguments: scope (parent), id (identifier), and props (keyword arguments); scope and id must be positional arguments, never keyword arguments.

### cdk-interface-prefix-i-for-external-resources [IN] OBSERVATION
CDK interfaces prefixed with `I` (e.g., `IBucket`) represent minimum functionality for a resource type; use concrete classes when creating resources, interfaces when accepting external resources (imported via `fromBucketArn()` etc.).

### cdk-l1-l2-l3-construct-levels [IN] OBSERVATION
CDK L1 constructs (Cfn-prefixed) map 1:1 to CloudFormation resources and are auto-generated; L2 constructs are curated higher-level abstractions with defaults; L3 constructs (patterns) compose multiple resources into common architectures.

### cdk-python-jsii-implements-decorator [IN] OBSERVATION
Python CDK apps use the `@jsii.implements()` decorator to implement CDK interfaces since Python lacks native interface syntax.

### cdk-python-lambda-alias-trailing-underscore [IN] OBSERVATION
In CDK Python, the `aws_cdk.aws_lambda` module must be aliased with a trailing underscore (`lambda_`) because `lambda` is a Python reserved word.

### cdk-requires-nodejs-runtime [IN] OBSERVATION
AWS CDK requires Node.js as a runtime dependency even when using Python, because the CDK Toolkit is built on Node.js.

### cdk-v1-end-of-support-june-2023 [IN] OBSERVATION
AWS CDK v1 ended support on June 1, 2023; CDK v2 is the current version.

### cdk-v2-main-package-aws-cdk-lib [IN] OBSERVATION
AWS CDK v2 consolidates most constructs into the `aws-cdk-lib` package; experimental modules use separate packages with the `.alpha` suffix (e.g., `aws-cdk.<SERVICE-NAME>.alpha`).

### cdk-v2-python-requires-3-9-plus [IN] OBSERVATION
AWS CDK v2 requires Python 3.9 or later for Python applications.

### cdk-v2-single-package-aws-cdk-lib [IN] OBSERVATION
AWS CDK v2 uses a single consolidated package (`aws-cdk-lib`) instead of CDK v1's per-service packages; experimental constructs ship as separate modules.

### cfn-adding-removing-replacement-property-triggers-replacement [IN] OBSERVATION
Adding or removing a CloudFormation property that requires replacement triggers replacement even if the effective value doesn't change.

### cfn-auto-resolves-resource-dependencies [IN] OBSERVATION
CloudFormation automatically resolves resource dependencies and determines creation order — users do not manually sequence resource creation.

### cfn-capability-named-iam-for-custom-names [IN] OBSERVATION
`CAPABILITY_NAMED_IAM` is required when CloudFormation templates include custom names for IAM resources; `CAPABILITY_IAM` suffices for IAM resources without custom names.

### cfn-change-set-execute-deletes-all-change-sets [IN] OBSERVATION
After executing a CloudFormation change set, all change sets associated with that stack are automatically deleted.

### cfn-change-set-no-stack-modification-until-execute [IN] OBSERVATION
CloudFormation does not modify the stack when creating a change set — changes only happen on explicit execution.

### cfn-change-set-no-success-guarantee [IN] OBSERVATION
CloudFormation change sets do not validate whether an update will succeed — they only preview changes, not check permissions, quotas, or resource update support.

### cfn-change-sets-do-not-validate-success [IN] OBSERVATION
CloudFormation change sets do not validate whether an update will succeed — they don't check account quotas, permissions, or whether a resource supports the proposed update.

### cfn-change-sets-preview-before-execute [IN] OBSERVATION
CloudFormation change sets let you preview proposed changes before executing them; the `deploy` command automatically creates and executes change sets

### cfn-cloudtrail-parameter-values-never-logged [IN] OBSERVATION
CloudFormation parameter values are never logged in CloudTrail — only parameter key names appear in log entries (security measure to protect secrets).

### cfn-console-requires-create-upload-bucket-s3 [IN] OBSERVATION
CloudFormation console users need `cloudformation:CreateUploadBucket` plus `s3:PutObject`, `s3:ListBucket`, `s3:GetObject`, and `s3:CreateBucket` permissions for template uploads.

### cfn-continue-update-rollback-resumes-failed [IN] OBSERVATION
CloudFormation `continue-update-rollback` resumes a stack update rollback that has previously failed

### cfn-create-failed-rolls-back-by-default [IN] OBSERVATION
On `CREATE_FAILED`, CloudFormation rolls back by default and deletes created resources.

### cfn-custom-named-iam-globally-unique-no-reuse [IN] OBSERVATION
Custom-named IAM resources in CloudFormation templates are globally unique — do not reuse the same template with custom-named IAM resources across multiple stacks or regions.

### cfn-default-2000-stacks-per-account [IN] OBSERVATION
The default CloudFormation limit is 2,000 stacks per account (soft limit, can be increased via Service Quotas).

### cfn-delegated-admin-requires-call-as-flag [IN] OBSERVATION
Delegated administrators must pass `--call-as DELEGATED_ADMIN` in CLI commands for CloudFormation StackSet operations.

### cfn-delete-stack-does-not-delete-template-s3-bucket [IN] OBSERVATION
Deleting a CloudFormation stack deletes its resources but does not delete the S3 bucket storing the template — that requires separate cleanup.

### cfn-deleted-stackset-shows-deleted-status [IN] OBSERVATION
Deleted CloudFormation StackSets appear with a `DELETED` status in `list-stack-sets` output rather than being immediately purged.

### cfn-deleting-stack-deletes-all-resources [IN] OBSERVATION
Deleting a CloudFormation stack deletes all resources within it, unless deletion policies are configured to retain specific resources.

### cfn-dual-layer-permissions-required [IN] OBSERVATION
CloudFormation users need permissions for both CloudFormation actions (e.g., `cloudformation:CreateStack`) AND permissions for the underlying AWS services referenced in templates (e.g., `sqs:*` for SQS queues).

### cfn-get-federation-token-cannot-use-iam [IN] OBSERVATION
Temporary credentials from STS `GetFederationToken` cannot be used to work with IAM — use role-based temporary credentials instead.

### cfn-get-template-retrieves-existing-template [IN] OBSERVATION
The `aws cloudformation get-template --stack-name <name>` command retrieves the current template of an existing stack.

### cfn-helper-scripts-four-tools [IN] OBSERVATION
CloudFormation helper scripts consist of four Python-based tools: `cfn-init` (apply configuration), `cfn-signal` (report completion), `cfn-get-metadata` (retrieve metadata), and `cfn-hup` (detect metadata updates).

### cfn-iac-generator-uses-cloud-control-api [IN] OBSERVATION
CloudFormation IaC generator creates templates from existing unmanaged resources using the Cloud Control API.

### cfn-infrastructure-composer-lambda-not-in-console-mode [IN] OBSERVATION
Lambda-related cards and local sync are not available in Infrastructure Composer's CloudFormation console mode — they require the standalone Infrastructure Composer console or VS Code Toolkit.

### cfn-infrastructure-composer-replaces-designer [IN] OBSERVATION
AWS Infrastructure Composer (formerly Application Composer) is the recommended visual tool for CloudFormation templates, replacing the deprecated CloudFormation Designer.

### cfn-init-fixed-processing-order [IN] OBSERVATION
`cfn-init` processes metadata sections in a fixed order: packages → groups → users → sources → files → commands → services, regardless of template ordering.

### cfn-init-metadata-key-aws-cloudformation-init [IN] OBSERVATION
`cfn-init` reads configuration from the `AWS::CloudFormation::Init` metadata key, placed in the resource's `Metadata` section (not `Properties`).

### cfn-local-templates-auto-uploaded-to-s3 [IN] OBSERVATION
Local CloudFormation template files are automatically uploaded to a per-region S3 bucket in the user's account when creating or updating stacks.

### cfn-marketing-names-differ-from-namespaces [IN] OBSERVATION
Some CloudFormation namespaces differ from AWS marketing names: Cloud Map = `AWS::ServiceDiscovery`, IAM Identity Center = `AWS::SSO`, Data Firehose = `AWS::KinesisFirehose`.

### cfn-max-200-parameters-outputs-mappings [IN] OBSERVATION
CloudFormation templates are limited to 200 parameters, 200 outputs, and 200 mappings each per template.

### cfn-max-500-resources-per-template [IN] OBSERVATION
CloudFormation templates support a maximum of 500 resources; nested stacks are the standard workaround for exceeding this limit.

### cfn-max-60-dynamic-references-per-template [IN] OBSERVATION
CloudFormation templates support a maximum of 60 dynamic references (SSM Parameter Store, Secrets Manager) per template.

### cfn-nested-stack-update-always-initiated [IN] OBSERVATION
CloudFormation nested stacks always get an update initiated to check for changes during a parent stack update, but only modified resources within them are actually updated.

### cfn-ref-returns-physical-id-getatt-returns-attributes [IN] OBSERVATION
`!Ref` on a CloudFormation resource returns its physical ID; `!GetAtt` retrieves specific attributes (e.g., `PublicDnsName`).

### cfn-renaming-logical-name-causes-replacement [IN] OBSERVATION
Changing a resource's logical name in a CloudFormation template is equivalent to deleting and replacing that resource, and cascades to dependent resources.

### cfn-replacement-creates-before-delete [IN] OBSERVATION
CloudFormation replacement creates the new resource first, updates references from dependent resources to the new physical ID, then deletes the old resource (create-before-delete).

### cfn-replacement-only-behavior-new-physical-id [IN] OBSERVATION
Only the Replacement update behavior produces a new physical resource ID; No Interruption and Some Interruption updates preserve the existing physical ID.

### cfn-resource-type-triple-colon-format [IN] OBSERVATION
CloudFormation resource type identifiers follow the format `service-provider::service-name::data-type-name` (e.g., `AWS::EC2::Instance`, `AWS::Lambda::Function`).

### cfn-rollback-on-creation-and-update-failure [IN] OBSERVATION
CloudFormation automatically rolls back on failure for both stack creation (deletes created resources) and stack update operations.

### cfn-self-managed-stackset-two-iam-roles [IN] OBSERVATION
Self-managed CloudFormation StackSets require two pre-created IAM roles: `AWSCloudFormationStackSetAdministrationRole` (administrator account) and `AWSCloudFormationStackSetExecutionRole` (target accounts).

### cfn-service-is-free [IN] OBSERVATION
CloudFormation itself is a free service — you pay only for the AWS resources it creates and manages.

### cfn-service-itself-no-cost [IN] OBSERVATION
CloudFormation itself has no cost — charges apply only to the AWS resources it provisions (EC2, S3, etc.).

### cfn-service-managed-stackset-role-naming [IN] OBSERVATION
Service-managed StackSet roles follow a naming convention: `CloudFormationStackSetsOrgAdmin` (management account) and `CloudFormationStackSetsOrgMember` (target accounts).

### cfn-source-ip-condition-does-not-work [IN] OBSERVATION
The `aws:SourceIp` condition key does not work with CloudFormation — CloudFormation uses its own IP address to provision resources, not the caller's IP.

### cfn-ssm-parameter-value-resolves-at-creation [IN] OBSERVATION
`AWS::SSM::Parameter::Value<AWS::EC2::Image::Id>` resolves SSM Parameter Store values at stack creation time, not at template authoring time.

### cfn-sso-abac-separate-resource [IN] OBSERVATION
IAM Identity Center ABAC configuration is managed through a dedicated CloudFormation resource (`AWS::SSO::InstanceAccessControlAttributeConfiguration`), not as a property of the `AWS::SSO::Instance` resource.

### cfn-sso-assignment-account-vs-application [IN] OBSERVATION
`AWS::SSO::Assignment` maps users/groups to AWS accounts with a permission set (account-level access), while `AWS::SSO::ApplicationAssignment` maps users/groups to an application (application-level access).

### cfn-sso-namespace-six-resource-types [IN] OBSERVATION
AWS CloudFormation provides exactly 6 resource types under the `AWS::SSO::` namespace for IAM Identity Center: Application, ApplicationAssignment, Assignment, Instance, InstanceAccessControlAttributeConfiguration, and PermissionSet.

### cfn-stack-atomic-rollback-on-create-failure [IN] OBSERVATION
If any resource fails to create in a CloudFormation stack, CloudFormation rolls back and deletes all resources that were created.

### cfn-stack-belongs-to-one-stackset-only [IN] OBSERVATION
A CloudFormation stack can belong to only one StackSet at a time.

### cfn-stack-failed-delete-retains-remaining-resources [IN] OBSERVATION
If a CloudFormation resource fails to delete, remaining resources are retained until the stack can be successfully deleted.

### cfn-stack-is-unit-of-management [IN] OBSERVATION
A CloudFormation stack is the unit of management — resources are created, updated, and deleted together as a single unit from a template.

### cfn-stack-name-max-128-chars [IN] OBSERVATION
CloudFormation stack names have a maximum length of 128 characters, shorter than the 255-character limit for resource, parameter, output, and mapping names.

### cfn-stack-resources-charged-while-existing [IN] OBSERVATION
CloudFormation stack resources are billed for the time they exist, even if the stack is deleted immediately after creation.

### cfn-stack-updates-only-changed-resources [IN] OBSERVATION
CloudFormation only updates changed resources during a stack update — it compares submitted changes against the current stack state.

### cfn-stackset-account-gate-lambda-name [IN] OBSERVATION
StackSet account gate Lambda functions must be named exactly `AWSCloudFormationStackSetAccountGate`.

### cfn-stackset-account-gate-skipped-without-permission [IN] OBSERVATION
If the StackSet execution role lacks `lambda:InvokeFunction` permission, CloudFormation silently skips the account gate check rather than failing.

### cfn-stackset-default-strict-failure-tolerance [IN] OBSERVATION
CloudFormation StackSet operations default to Strict Failure Tolerance mode, where concurrency decreases proportionally with failures; Soft Failure Tolerance maintains full concurrency regardless of failures but may result in more total failures.

### cfn-stackset-delegated-admin-call-as-flag [IN] OBSERVATION
Delegated administrators must include `--call-as DELEGATED_ADMIN` when running StackSet CLI commands.

### cfn-stackset-delete-instances-not-stackset [IN] OBSERVATION
Deleting stack instances from a StackSet removes provisioned stacks from target accounts/regions but does not delete the StackSet itself.

### cfn-stackset-delete-requires-empty-stackset [IN] OBSERVATION
A CloudFormation StackSet cannot be deleted until all stack instances have been removed from it first.

### cfn-stackset-delete-requires-zero-instances [IN] OBSERVATION
A StackSet cannot be deleted until all of its stack instances have been removed.

### cfn-stackset-drift-detects-out-of-band-only [IN] OBSERVATION
CloudFormation StackSet drift detection only identifies changes made outside CloudFormation; changes made via CloudFormation directly to a stack (not at StackSet level) are not considered drift.

### cfn-stackset-drift-respects-parameter-overrides [IN] OBSERVATION
CloudFormation StackSet drift detection respects parameter overrides — each stack instance is evaluated against its own effective parameters.

### cfn-stackset-drift-status-values [IN] OBSERVATION
CloudFormation StackSet drift status values are `DRIFTED`, `IN_SYNC`, and `NOT_CHECKED`; resource-level drift statuses include `MODIFIED` and `DELETED`.

### cfn-stackset-failed-gate-counts-against-failure-tolerance [IN] OBSERVATION
A failed account gate check counts against the StackSet operation's failure tolerance threshold.

### cfn-stackset-failure-tolerance-per-region [IN] OBSERVATION
StackSet failure tolerance is evaluated per Region; exceeding it in any Region sets the overall operation to FAILED and cancels remaining Regions.

### cfn-stackset-global-resources-naming-conflicts [IN] OBSERVATION
IAM roles and S3 buckets (global resources) can cause naming conflicts when deployed via StackSets to multiple regions in the same account — names must be unique.

### cfn-stackset-import-limits-10-inline-200-s3 [IN] OBSERVATION
CloudFormation StackSet import supports up to 10 stacks via inline stack IDs or up to 200 stacks via S3 object.

### cfn-stackset-imported-params-require-override [IN] OBSERVATION
Imported stack instance parameters in a CloudFormation StackSet can only be changed via parameter overrides, not via editing the StackSet directly.

### cfn-stackset-inoperable-fix-delete-retain-then-manual [IN] OBSERVATION
To fix an INOPERABLE stack instance, call `DeleteStackInstances` with `RetainStacks=true`, then delete the stack manually in the target account.

### cfn-stackset-is-regional-resource [IN] OBSERVATION
A StackSet is a regional resource — it can only be viewed and modified from the AWS Region where it was created.

### cfn-stackset-management-region-independent-of-targets [IN] OBSERVATION
The Region from which a CloudFormation StackSet is managed does not affect which Regions can be targeted for deployment.

### cfn-stackset-max-10-dependencies [IN] OBSERVATION
Service-managed CloudFormation StackSets support a maximum of 10 dependencies (dependent StackSet ARNs).

### cfn-stackset-max-concurrent-lte-failure-tolerance-plus-one [IN] OBSERVATION
In StackSet operations, `MaxConcurrentCount` must not exceed `FailureToleranceCount` + 1.

### cfn-stackset-noecho-blocks-new-import [IN] OBSERVATION
The `NoEcho` property blocks importing a stack into a new CloudFormation StackSet (but does not block import into an existing StackSet).

### cfn-stackset-one-drift-operation-at-a-time [IN] OBSERVATION
Only one drift detection operation can run on a given CloudFormation StackSet at a time.

### cfn-stackset-one-operation-at-a-time [IN] OBSERVATION
Only one operation is permitted on a StackSet at a time — concurrent operations on the same StackSet are not allowed.

### cfn-stackset-org-overrides-current-members-only [IN] OBSERVATION
For Organizations-managed StackSets, parameter overrides only affect accounts currently in the target OU — new accounts added later receive StackSet defaults, not overridden values.

### cfn-stackset-overrides-survive-updates [IN] OBSERVATION
Overridden StackSet parameter values are sticky — StackSet updates do not revert them; they must be explicitly reset to StackSet values.

### cfn-stackset-overrides-via-update-stack-instances [IN] OBSERVATION
StackSet parameter overrides are applied via `update-stack-instances`, not `update-stack-set`.

### cfn-stackset-percentage-settings-round-down [IN] OBSERVATION
Percentage-based StackSet operation settings (failure tolerance, max concurrent accounts) round down to the nearest whole number.

### cfn-stackset-retain-stacks-disassociates [IN] OBSERVATION
Using `--retain-stacks` when deleting stack instances keeps the stacks and resources in the account but disassociates them from the StackSet; `--no-retain-stacks` fully deletes stacks and resources.

### cfn-stackset-self-vs-service-managed-permissions [IN] OBSERVATION
Self-managed StackSet permissions require manually creating IAM roles for cross-account trust; service-managed permissions leverage AWS Organizations to create IAM roles automatically.

### cfn-stackset-service-managed-cascades-child-ous [IN] OBSERVATION
With service-managed permissions, deleting stack instances from a parent OU automatically cascades deletion to all child OUs.

### cfn-stackset-strict-initial-concurrency-formula [IN] OBSERVATION
In Strict Failure Tolerance mode, initial StackSet concurrency equals the lower of `MaxConcurrentAccounts` or `FailureTolerance + 1`, not simply `MaxConcurrentAccounts`.

### cfn-stackset-strict-vs-soft-failure-tolerance [IN] OBSERVATION
CloudFormation StackSet strict failure tolerance reduces concurrency when failures occur (staying within FailureToleranceCount + 1), while soft failure tolerance maintains the specified concurrency level regardless of failures.

### cfn-stackset-template-updates-affect-all-stacks [IN] OBSERVATION
Template updates to a StackSet always affect all stacks in the StackSet — you cannot selectively update only some stack instances.

### cfn-stackset-updates-sequential-by-region-default [IN] OBSERVATION
CloudFormation StackSet updates proceed Region by Region sequentially by default; parallel Region concurrency must be explicitly chosen.

### cfn-stacksets-account-move-triggers-delete-and-create [IN] OBSERVATION
When an account moves between OUs, CloudFormation StackSets automatic deployment deletes the old OU's StackSet stack and creates the new OU's StackSet stack.

### cfn-stacksets-auto-deploy-ignores-account-filters [IN] OBSERVATION
Automatic deployments in CloudFormation StackSets ignore account-level targeting filters — new accounts added to the organization still receive deployments.

### cfn-stacksets-auto-deploy-new-org-accounts [IN] OBSERVATION
Service-managed CloudFormation StackSets support automatic deployments — stacks are automatically provisioned when new accounts are added to an organizational unit.

### cfn-stacksets-auto-deploy-uses-stackset-defaults-not-overrides [IN] OBSERVATION
When automatic deployment adds stacks for new accounts joining a target OU, the stacks receive StackSet default parameter values — overridden parameter values do not propagate.

### cfn-stacksets-create-stack-instances-cli-command [IN] OBSERVATION
The CLI command to add stack instances to a StackSet is `create-stack-instances`; self-managed uses `--accounts`, service-managed uses `--deployment-targets OrganizationalUnitIds=...`.

### cfn-stacksets-delegated-admin-call-as-flag [IN] OBSERVATION
Delegated administrators must use `--call-as DELEGATED_ADMIN` when managing CloudFormation StackSets.

### cfn-stacksets-delegated-admin-cannot-be-restricted-to-specific-ous [IN] OBSERVATION
Delegated administrators for CloudFormation StackSets have full permissions to deploy to any account in the organization; the management account cannot restrict them to specific OUs.

### cfn-stacksets-dependency-limits-10-per-stackset-100-per-account [IN] OBSERVATION
CloudFormation StackSets dependency limits are 10 per StackSet and 100 per account (the per-account limit is increasable via Service Quotas).

### cfn-stacksets-failed-instance-status-outdated [IN] OBSERVATION
A failed CloudFormation StackSet instance shows status `OUTDATED`; the underlying stack shows `DELETED` (failed create) or `FAILED` (failed update).

### cfn-stacksets-four-account-filter-types [IN] OBSERVATION
CloudFormation StackSets support four account filter types for deployment targeting: None (default, all accounts), Intersection (only specified accounts), Difference (exclude specified accounts), and Union (OU accounts plus additional accounts).

### cfn-stacksets-import-existing-stacks [IN] OBSERVATION
Existing CloudFormation stacks can be imported into a StackSet.

### cfn-stacksets-max-10-dependencies [IN] OBSERVATION
CloudFormation StackSets support a maximum of 10 StackSet dependencies per StackSet.

### cfn-stacksets-max-concurrency-lte-failure-tolerance-plus-one [IN] OBSERVATION
In CloudFormation StackSets, `MaxConcurrentCount` must not exceed `FailureToleranceCount` + 1.

### cfn-stacksets-multi-account-multi-region [IN] OBSERVATION
CloudFormation StackSets enable creating, updating, or deleting stacks across multiple AWS accounts and Regions in a single operation from an administrator account.

### cfn-stacksets-no-macros-with-service-managed [IN] OBSERVATION
CloudFormation StackSets do not support macros/transforms when using service-managed permissions (AWS Organizations).

### cfn-stacksets-ou-includes-child-ous [IN] OBSERVATION
Selecting an OU for a CloudFormation StackSet automatically includes all child OUs.

### cfn-stacksets-parameter-overrides-per-instance [IN] OBSERVATION
CloudFormation StackSets allow parameter overrides on individual stack instances, enabling customization within a single StackSet deployment.

### cfn-stacksets-parent-ou-includes-child-ous [IN] OBSERVATION
Targeting a parent OU in a CloudFormation StackSet automatically includes all child OUs.

### cfn-stacksets-revert-failed-import-retain-then-retry [IN] OBSERVATION
To revert a failed CloudFormation StackSet import, delete stack instances with `RetainStacks` enabled, then fix the issue and retry the import.

### cfn-stacksets-sample-templates-governance-baseline [IN] OBSERVATION
AWS provides sample CloudFormation StackSet templates for enterprise governance baselines including enabling CloudTrail, enabling AWS Config, AWS Config rules (CloudTrail enabled, root MFA, EIP attachment, EBS encryption), and Data Lifecycle Manager default policies.

### cfn-stacksets-self-managed-requires-two-named-roles [IN] OBSERVATION
Self-managed CloudFormation StackSets require two IAM roles: `AWSCloudFormationStackSetAdministrationRole` in the admin account and `AWSCloudFormationStackSetExecutionRole` in each target account, with a trust relationship between them.

### cfn-stacksets-service-is-free [IN] OBSERVATION
CloudFormation StackSets itself is free; charges apply only for the AWS resources created by the stacks.

### cfn-stacksets-service-managed-no-deploy-to-management-account [IN] OBSERVATION
CloudFormation StackSets with service-managed permissions never deploy stacks to the AWS Organizations management account, even if it is in the target OU.

### cfn-stacksets-service-managed-no-nested-stacks-no-macros [IN] OBSERVATION
CloudFormation StackSets with service-managed permissions do not support nested stacks or macros/transforms.

### cfn-stacksets-strict-vs-soft-failure-tolerance [IN] OBSERVATION
CloudFormation StackSets concurrency mode has two options: strict failure tolerance (reduces concurrency when failures occur) and soft failure tolerance (maintains configured concurrency regardless of failures).

### cfn-stacksets-termination-protection-blocks-instance-deletion [IN] OBSERVATION
If termination protection is enabled on a CloudFormation stack, it blocks stack instance deletion from a StackSet; termination protection must be disabled first.

### cfn-stacksets-two-permission-models [IN] OBSERVATION
CloudFormation StackSets has two permission models: self-managed (manually create IAM roles in each target account) and service-managed (AWS auto-creates roles via AWS Organizations trusted access).

### cfn-template-only-resources-section-required [IN] OBSERVATION
The only required section in a CloudFormation template is the Resources section (must declare at least one resource).

### cfn-template-s3-required-over-51200-bytes [IN] OBSERVATION
CloudFormation templates larger than 51,200 bytes must be uploaded to S3 rather than passed inline

### cfn-template-size-51200-inline-1mb-s3 [IN] OBSERVATION
CloudFormation templates have a maximum size of 51,200 bytes when passed inline in API requests, or up to 1 MB when stored in and referenced from S3.

### cfn-templates-support-yaml-and-json [IN] OBSERVATION
CloudFormation templates can be written in either YAML or JSON format, with any file extension (`.yaml`, `.json`, `.template`, `.txt`).

### cfn-templates-yaml-or-json [IN] OBSERVATION
CloudFormation templates can be written in YAML or JSON — both are fully supported.

### cfn-three-update-behavior-types [IN] OBSERVATION
Each CloudFormation resource property has an update behavior: No interruption (no disruption), Some interruptions (partial disruption), or Replacement (resource deleted and recreated).

### cfn-three-update-behaviors [IN] OBSERVATION
CloudFormation resource updates have three behaviors: Update with No Interruption (in-place, no downtime), Update with Some Interruption (partial disruption), and Replacement (new physical ID, old resource deleted after).

### cfn-update-behavior-per-property-not-resource [IN] OBSERVATION
CloudFormation update behavior is per-property, not per-resource type — different properties on the same resource type can have different update behaviors (No Interruption, Some Interruption, or Replacement).

### cfn-userdata-must-be-base64-encoded [IN] OBSERVATION
EC2 `UserData` in CloudFormation templates must be Base64-encoded using `!Base64`.

### cfn-validate-template-syntax-only [IN] OBSERVATION
The `aws cloudformation validate-template` command checks template syntax only, not property value correctness; use cfn-lint for deeper validation.

### cfn-vpc-cidr-change-requires-replacement [IN] OBSERVATION
Changing the `CidrBlock` or `Ipv4IpamPoolId` on an `AWS::EC2::VPC` resource requires replacement — a new VPC is created.

### cfn-vpc-ipv6-requires-separate-cidr-resource [IN] OBSERVATION
IPv6 is not a direct property of `AWS::EC2::VPC` — it requires a separate `AWS::EC2::VPCCidrBlock` resource with `AmazonProvidedIpv6CidrBlock: true`.

### chatbot-permanently-blocked-operations [IN] OBSERVATION
Amazon Q Developer in chat applications permanently blocks sensitive operations (IAM, KMS, STS, SSO, Secrets Manager, S3 Get/PutObject, and others) regardless of any role configuration.

### chatbot-permissions-intersection-not-union [IN] OBSERVATION
In Amazon Q Developer chat applications (formerly AWS Chatbot), effective permissions equal the intersection of channel guardrail policies and the user's role permissions — guardrail policies always take precedence.

### chatbot-renamed-from-aws-chatbot [IN] OBSERVATION
AWS Chatbot was renamed to Amazon Q Developer in chat applications.

### chatbot-sns-notification-mechanism [IN] OBSERVATION
Amazon Q Developer in chat applications (formerly AWS Chatbot) uses Amazon SNS topics as the mechanism to deliver AWS service notifications to chat channels (Slack, Microsoft Teams, Amazon Chime).

### chatbot-three-supported-platforms [IN] OBSERVATION
Amazon Q Developer in chat applications supports three platforms: Amazon Chime (webhooks only), Microsoft Teams (channels), and Slack (channels).

### chatbot-user-role-account-level-enforcement [IN] OBSERVATION
Amazon Q Developer chat application user role requirements can be enforced at the account level; individual channels cannot override an account-level requirement.

### clean-rooms-events-are-management-events [IN] OBSERVATION
AWS Clean Rooms CloudTrail events are classified as management events, not data events.

### clean-rooms-sql-redacted-in-cloudtrail [IN] OBSERVATION
AWS Clean Rooms SQL query parameters are redacted (shown as `"***"`) in CloudTrail logs, protecting query content from exposure in audit logs.

### cli-control-plane-data-plane-split-namespaces [IN] OBSERVATION
Some AWS services split CLI commands into separate control-plane and data-plane namespaces (e.g., `bedrock` vs `bedrock-runtime`, `iot` vs `iot-data`, `mediastore` vs `mediastore-data`).

### cli-default-output-format-json [IN] OBSERVATION
The AWS CLI default output format is `json`; six formats are supported: `json`, `text`, `table`, `yaml`, `yaml-stream`, and `off`.

### cli-default-socket-timeout-60-seconds [IN] OBSERVATION
AWS CLI default socket read and connect timeouts are both 60 seconds; setting to 0 enables blocking (no timeout).

### cli-endpoint-url-for-local-development [IN] OBSERVATION
The AWS CLI `--endpoint-url` flag enables pointing commands at custom/local endpoints such as LocalStack or DynamoDB Local for local development.

### cli-error-output-format-default-enhanced [IN] OBSERVATION
The AWS CLI error output format defaults to `enhanced`; alternatives include `legacy`, `json`, `yaml`, `text`, and `table`.

### cli-fileb-always-binary-file-respects-format [IN] OBSERVATION
The `fileb://` prefix always treats content as raw binary regardless of `--cli-binary-format` setting; `file://` respects the `--cli-binary-format` setting (default: `base64`).

### cli-no-paginate-returns-first-page-only [IN] OBSERVATION
The AWS CLI `--no-paginate` flag returns only the first page of results; without it, the CLI automatically paginates through all results.

### cli-no-sign-request-for-public-resources [IN] OBSERVATION
The AWS CLI `--no-sign-request` flag skips authentication entirely, allowing access to public resources (e.g., public S3 buckets) without credentials.

### cli-query-uses-jmespath-syntax [IN] OBSERVATION
The AWS CLI `--query` option uses JMESPath expression syntax for client-side filtering and transformation of JSON response data.

### cli-s3-vs-s3api-high-vs-low-level [IN] OBSERVATION
The AWS CLI has separate `s3` (high-level commands like `cp`, `sync`, `ls`) and `s3api` (low-level API calls like `put-object`) service namespaces for S3.

### cli-some-services-have-versioned-namespaces [IN] OBSERVATION
Some AWS CLI services have versioned command namespaces where v2 supersedes v1: `waf`→`wafv2`, `kinesisanalytics`→`kinesisanalyticsv2`, `lex-models`→`lexv2-models`, `ses`→`sesv2`.

### cloud-financial-management-organizational-practice [IN] OBSERVATION
Cloud Financial Management is an organizational practice requiring culture, processes, and dedicated ownership — not just a technical exercise.

### cloudfront-acm-cert-must-be-us-east-1 [IN] OBSERVATION
ACM certificates used with CloudFront must be requested or imported in the US East (N. Virginia) / us-east-1 region.

### cloudfront-anycast-static-ips [IN] OBSERVATION
CloudFront anycast static IPs can be requested for allowlisting use cases.

### cloudfront-auto-configures-based-on-origin-type [IN] OBSERVATION
CloudFront auto-configures most distribution settings based on the selected origin type; manual editing is optional.

### cloudfront-cache-key-identifies-cached-files [IN] OBSERVATION
The CloudFront cache key uniquely identifies each file in the cache for a given distribution; its composition (headers, cookies, query strings) affects cache behavior.

### cloudfront-cloudtrail-events-us-east-1-only [IN] OBSERVATION
CloudFront is a global service whose CloudTrail events are always recorded in the US East (N. Virginia / us-east-1) region, regardless of where the action originated.

### cloudfront-concurrent-invalidation-limit [IN] OBSERVATION
There is a maximum number of concurrent invalidation requests per CloudFront distribution.

### cloudfront-continuous-deployment-support [IN] OBSERVATION
CloudFront supports continuous deployment for safely testing configuration changes before full rollout.

### cloudfront-ddos-resilient-architecture-component [IN] OBSERVATION
CloudFront is a key component in AWS DDoS-resilient architectures, working alongside AWS Shield and AWS WAF.

### cloudfront-default-ttl-24-hours [IN] OBSERVATION
CloudFront default cache expiration is 24 hours per file; minimum TTL is 0 seconds with no maximum limit.

### cloudfront-distribution-configurable-settings [IN] OBSERVATION
CloudFront distribution configurable settings include: origin, access (public/restricted), security (WAF, HTTPS), cache key, origin request settings, geographic restrictions, and logging (standard or real-time).

### cloudfront-do-not-delete-cert-while-associated [IN] OBSERVATION
An ACM or IAM certificate must not be deleted until it is removed from all CloudFront distributions and those distributions are fully deployed.

### cloudfront-domain-format [IN] OBSERVATION
CloudFront assigns each distribution a domain in the format `d111111abcdef8.cloudfront.net`; alternate domain names (CNAMEs) can be configured for custom URLs.

### cloudfront-edge-layer-provides-simultaneous-security-cost-performance-benefit [IN] OBSERVATION
CloudFront simultaneously provides DDoS protection (Shield/WAF integration), cost elimination (free data transfer from AWS origins), and latency optimization (lowest-latency edge routing) — the edge layer is a structural improvement across three independent operational dimensions rather than a single-purpose CDN

### cloudfront-field-level-encryption-at-edge [IN] OBSERVATION
CloudFront field-level encryption encrypts specific form fields at the edge, and data stays encrypted through to the application, providing protection beyond standard HTTPS.

### cloudfront-free-data-transfer-from-aws-origins [IN] OBSERVATION
Data transfer from AWS origins (S3, ELB, API Gateway) to CloudFront is free; you pay only for edge-to-viewer transfer.

### cloudfront-http-redirect-double-charges [IN] OBSERVATION
CloudFront HTTP-to-HTTPS redirects incur double charges: one for the HTTP request and one for the subsequent HTTPS request.

### cloudfront-https-enforcement-has-method-dependent-gaps [IN] OBSERVATION
CloudFront's two HTTPS enforcement options both have method-dependent behavior gaps: "Redirect HTTP to HTTPS" returns 301 only for GET/HEAD (other methods like POST get different handling), and "HTTPS Only" returns 403 for all HTTP requests — neither option provides clean HTTPS migration for API traffic using non-GET methods.

### cloudfront-https-only-returns-403 [IN] OBSERVATION
CloudFront's "HTTPS Only" viewer protocol policy returns 403 Forbidden for any HTTP request.

### cloudfront-iam-cert-path-must-start-with-cloudfront [IN] OBSERVATION
When uploading a third-party certificate to the IAM certificate store for CloudFront, the --path must start with /cloudfront/ and end with /.

### cloudfront-invalidation-does-not-clear-browser-cache [IN] OBSERVATION
CloudFront cache invalidation does not clear files cached in a user's browser or behind corporate caching proxies.

### cloudfront-invalidation-has-cost [IN] OBSERVATION
CloudFront cache invalidation has an associated cost; file versioning avoids invalidation fees.

### cloudfront-invalidation-triggers-origin-fetch [IN] OBSERVATION
After cache invalidation, CloudFront returns to the origin server on the next viewer request to fetch the latest version of the file.

### cloudfront-keyvaluestore-data-events-resource-type [IN] OBSERVATION
CloudFront KeyValueStore is the only CloudFront resource type supporting CloudTrail data events, using resource type `AWS::CloudFront::KeyValueStore` with operations DeleteKeys, DescribeKeyValueStore, GetKey, ListKeys, PutKeys, UpdateKeys.

### cloudfront-live-streaming-via-cloudformation [IN] OBSERVATION
CloudFront live streaming distributions can be provisioned via CloudFormation stacks using AWS Media Services.

### cloudfront-max-100-certs-console-dropdown [IN] OBSERVATION
CloudFront console dropdown supports associating up to 100 certificates; beyond that, the certificate ARN must be specified directly.

### cloudfront-max-25-origins-per-distribution [IN] OBSERVATION
A CloudFront distribution supports up to 25 origins.

### cloudfront-mtls-both-directions [IN] OBSERVATION
CloudFront supports mutual TLS (mTLS) in both directions: viewer-to-CloudFront and CloudFront-to-origin.

### cloudfront-multi-tenant-waf-v2-only [IN] OBSERVATION
Multi-tenant CloudFront distributions only support WAF V2 web ACLs (not V1) and do not support Smooth Streaming.

### cloudfront-no-file-limit-per-distribution [IN] OBSERVATION
There is no maximum number of files per CloudFront distribution, but there are account-level limits on number of distributions.

### cloudfront-origin-access-restriction-s3-alb [IN] OBSERVATION
CloudFront origin access can be restricted for both S3 origins (OAC/OAI) and ALB origins, preventing direct access to the origin.

### cloudfront-pricing-varies-by-region-usage-feature [IN] OBSERVATION
CloudFront pricing varies by usage type, geographic region, and feature selection.

### cloudfront-private-content-signed-urls-cookies [IN] OBSERVATION
CloudFront private content access is controlled via signed URLs and signed cookies.

### cloudfront-redirect-http-returns-301-get-head-only [IN] OBSERVATION
CloudFront's "Redirect HTTP to HTTPS" viewer protocol policy returns 301 Moved Permanently only for GET/HEAD requests; DELETE, OPTIONS, PATCH, POST, and PUT return 403 Forbidden.

### cloudfront-routes-to-lowest-latency-edge [IN] OBSERVATION
CloudFront delivers content from the lowest-latency edge location, not necessarily the geographically closest one.

### cloudfront-signed-urls-vs-cookies [IN] OBSERVATION
CloudFront signed URLs are for individual file access control; signed cookies are for multiple files or when URLs should not change.

### cloudfront-six-security-mechanisms [IN] OBSERVATION
CloudFront offers six primary security mechanisms: HTTPS, geo-restriction, signed URLs/cookies, field-level encryption, AWS WAF integration, and origin access restriction.

### cloudfront-supported-origin-types [IN] OBSERVATION
CloudFront supports five origin types: S3 bucket, MediaPackage channel, MediaStore container, ELB load balancer, and HTTP server (custom origin).

### cloudfront-supports-static-and-dynamic-content [IN] OBSERVATION
CloudFront supports both static content (HTML, CSS, JS, images) and dynamic web content, as well as video on demand (HLS, Smooth Streaming) and live streaming.

### cloudfront-supports-websockets-grpc-ipv6 [IN] OBSERVATION
CloudFront distributions support WebSocket, gRPC, and IPv6 protocols.

### cloudfront-two-distribution-types [IN] OBSERVATION
CloudFront has two distribution types: Standard (single site) and Multi-tenant/CloudFront SaaS Manager (multi-customer).

### cloudfront-uses-aws-backbone-network [IN] OBSERVATION
CloudFront routes requests through AWS's own backbone network, reducing hops and improving latency compared to the public internet.

### cloudfront-versioning-five-advantages-over-invalidation [IN] OBSERVATION
File versioning has five advantages over cache invalidation: bypasses local/corporate caches, easier log analysis, supports per-user file versions, enables easy rollback, and avoids invalidation costs.

### cloudfront-versioning-preferred-over-invalidation [IN] OBSERVATION
AWS recommends file versioning over cache invalidation for frequently updated CloudFront content.

### cloudfront-viewer-protocol-policy-two-options [IN] OBSERVATION
CloudFront Viewer Protocol Policy has two HTTPS enforcement options: "Redirect HTTP to HTTPS" (returns 301 for GET/HEAD) and "HTTPS Only" (returns 403 for all HTTP).

### cloudfront-waf-integration-request-filtering [IN] OBSERVATION
AWS WAF integrates directly with CloudFront for request filtering, rate limiting, and access control based on IP, geo, and request patterns.

### cloudsearch-document-limit-1mb-batch-5mb [IN] OBSERVATION
Amazon CloudSearch individual documents are limited to 1 MB and document batch uploads are limited to 5 MB total

### cloudsearch-upload-endpoint-domain-specific [IN] OBSERVATION
The CloudSearch document upload endpoint is unique per domain and must be retrieved via `DescribeDomains` or the console dashboard

### cloudtrail-additional-management-event-copies-cost [IN] OBSERVATION
Only the first copy of management events per Region is free; additional trails delivering the same management events incur extra CloudTrail charges.

### cloudtrail-admin-permissions-separate-from-log-delivery [IN] OBSERVATION
CloudTrail administrator IAM permissions are separate from the permissions CloudTrail needs to deliver logs to S3 or send SNS notifications (which require separate bucket/topic policies).

### cloudtrail-advanced-basic-selectors-mutually-exclusive [IN] OBSERVATION
Advanced and basic event selectors are mutually exclusive on a trail — applying advanced event selectors overwrites any existing basic event selectors.

### cloudtrail-advanced-event-selectors-max-500-values [IN] OBSERVATION
Advanced event selectors support a maximum of 500 values across all conditions on a trail.

### cloudtrail-advanced-event-selectors-required-fields [IN] OBSERVATION
Advanced event selectors require exactly two fields: `eventCategory` (e.g., `"Data"`) and `resources.type` (e.g., `AWS::S3::Object`); all other fields are optional.

### cloudtrail-advanced-features-have-cold-start-penalties [IN] OBSERVATION
CloudTrail Insights may take up to 7 days for first delivery and re-enabling resets the timer; Lake highlights refresh every 6 hours — advanced observability features trade immediacy for analytical depth.

### cloudtrail-advanced-observability-cannot-be-activated-reactively [IN] OBSERVATION
CloudTrail advanced observability requires proactive investment: Lake demands irrevocable upfront decisions (KMS keys, pricing tier) and Insights has up to 7-day cold-start delays, meaning the full advanced observability stack cannot be spun up reactively during an incident.

### cloudtrail-advanced-selectors-deselect-precedence [IN] OBSERVATION
In CloudTrail advanced event selectors, DESELECT operators (NotEquals, NotStartsWith, NotEndsWith) are AND'd and take precedence over SELECT operators (Equals, StartsWith, EndsWith) which are OR'd.

### cloudtrail-advanced-selectors-no-wildcards [IN] OBSERVATION
CloudTrail advanced event selectors do not support wildcards (`*`); use `StartsWith`, `EndsWith`, `NotStartsWith`, `NotEndsWith` operators instead.

### cloudtrail-all-iam-sts-actions-logged [IN] OBSERVATION
All IAM and AWS STS API actions are logged by CloudTrail — there are no unlogged IAM/STS API operations.

### cloudtrail-assume-role-readonly-true [IN] OBSERVATION
AssumeRole, AssumeRoleWithSAML, and AssumeRoleWithWebIdentity are logged as `readOnly: true` in CloudTrail despite generating credentials; GetSessionToken and GetFederationToken are `readOnly: false`.

### cloudtrail-audit-blind-spots-exist-for-automated-operations [IN] OBSERVATION
Certain automated and system-initiated operations create audit gaps: DynamoDB TTL deletions produce no CloudTrail records, and API Gateway test invocations are excluded from CloudTrail logging.

### cloudtrail-audit-completeness-requires-both-scope-and-fidelity [IN] OBSERVATION
Complete CloudTrail audit coverage requires addressing two independent dimensions: scope (cross-account event linking via sharedEventID, multi-region awareness for root sign-ins, delegated admin configuration) AND fidelity (inconsistent sensitive data redaction across services means investigation may encounter redacted fields in B2BI/Clean Rooms but full values elsewhere) — closing either gap alone leaves the other open.

### cloudtrail-basic-event-selectors-three-types [IN] OBSERVATION
CloudTrail basic event selectors support only three resource types for data events: S3 objects (general purpose buckets), Lambda functions, and DynamoDB tables; advanced event selectors are required for all other resource types.

### cloudtrail-captures-api-calls-not-performance-metrics [IN] OBSERVATION
CloudTrail captures EC2 API calls (who, what, when, source IP) and stores them in S3; it does not capture performance metrics (that is CloudWatch's role).

### cloudtrail-channel-custom-source-for-non-aws [IN] OBSERVATION
The CloudTrail Lake channel source value `Custom` is used for all non-AWS event sources; named partner sources are used for specific integration partners.

### cloudtrail-channel-for-lake-integrations-only [IN] OBSERVATION
CloudTrail channels are specific to CloudTrail Lake integrations (partner or custom external sources), not traditional trails.

### cloudtrail-channel-max-200-destinations [IN] OBSERVATION
A CloudTrail Lake channel supports up to 200 destinations per channel.

### cloudtrail-channel-one-per-source [IN] OBSERVATION
Only one CloudTrail Lake channel is allowed per source (partner or custom).

### cloudtrail-channel-policy-action-putauditevents [IN] OBSERVATION
CloudTrail Lake channel resource-based policies only allow one action: `cloudtrail-data:PutAuditEvents` (note the `cloudtrail-data` service prefix, not `cloudtrail`).

### cloudtrail-channel-policy-limits-20-statements-50-principals [IN] OBSERVATION
CloudTrail Lake channel resource-based policies support a maximum of 20 statements and 50 principals per statement.

### cloudtrail-channel-source-immutable-after-creation [IN] OBSERVATION
A CloudTrail Lake channel's source cannot be changed after creation — it is immutable.

### cloudtrail-cloudwatch-default-role-name [IN] OBSERVATION
The default IAM role for CloudTrail-to-CloudWatch Logs integration is named `CloudTrail_CloudWatchLogs_Role`.

### cloudtrail-cloudwatch-logs-near-real-time-alerting [IN] OBSERVATION
CloudTrail can send log events to CloudWatch Logs for near real-time monitoring and alerting via metric filters, CloudWatch metrics, and CloudWatch alarms — unlike S3 delivery which has higher latency.

### cloudtrail-cloudwatch-logs-org-trail-management-account-console [IN] OBSERVATION
CloudWatch Logs log group configuration for organization trails can only be done via the console by the management account; delegated administrators must use CLI/API.

### cloudtrail-cloudwatch-logs-requires-iam-role [IN] OBSERVATION
Integrating CloudTrail with CloudWatch Logs requires a specific IAM role policy granting CloudTrail permission to write to the CloudWatch log group.

### cloudtrail-cloudwatch-role-two-permissions [IN] OBSERVATION
CloudTrail requires only two CloudWatch Logs permissions to deliver events: `logs:CreateLogStream` and `logs:PutLogEvents` — notably not `logs:CreateLogGroup`.

### cloudtrail-console-trail-all-regions-default [IN] OBSERVATION
Trails created in the CloudTrail console apply to all AWS regions by default.

### cloudtrail-console-trail-multi-region-default [IN] OBSERVATION
CloudTrail trails created via the AWS console are multi-Region by default; one free copy of management events is delivered to S3 (S3 storage charges still apply).

### cloudtrail-console-trails-all-regions-default [IN] OBSERVATION
CloudTrail trails created via the AWS Console apply to all AWS Regions by default; CLI-created trails can be single-Region.

### cloudtrail-console-trails-always-multi-region [IN] OBSERVATION
CloudTrail trails created via the console are always multi-Region; single-Region trails can only be created via the CLI.

### cloudtrail-console-trails-default-multi-region [IN] OBSERVATION
Trails created in the AWS Console default to multi-region logging.

### cloudtrail-console-trails-multi-region-by-default [IN] OBSERVATION
CloudTrail trails created via the console are multi-Region by default; CLI-created trails can be single-Region.

### cloudtrail-console-trails-multi-region-default [IN] OBSERVATION
Trails created via the AWS Console default to multi-region logging (all AWS Regions).

### cloudtrail-control-tower-auto-creates-org-trail [IN] OBSERVATION
Control Tower automatically creates an organization trail on landing zone setup; existing organization trails may cause duplicate billing.

### cloudtrail-copy-ignores-destination-selectors [IN] OBSERVATION
CloudTrail copies all trail events regardless of the destination event data store's event type configuration, advanced event selectors, or region settings.

### cloudtrail-copy-only-gzip-compressed-logs [IN] OBSERVATION
CloudTrail trail-to-Lake copy only processes gzip-compressed log files; uncompressed or other compression formats are skipped.

### cloudtrail-copy-retention-formula [IN] OBSERVATION
CloudTrail Lake event data store retention period for copied events must be set to: oldest_event_age_in_days + desired_retention_days.

### cloudtrail-copy-trail-management-account-only-for-org [IN] OBSERVATION
Only the management account can copy trail events to an organization event data store — delegated administrator accounts cannot perform this operation.

### cloudtrail-copy-trail-uncompressed-10x-s3-size [IN] OBSERVATION
Copying trail events to CloudTrail Lake charges based on uncompressed data size, which is approximately 10x the compressed S3 log storage size.

### cloudtrail-cross-account-audit-requires-multi-region-awareness [IN] OBSERVATION
CloudTrail cross-account audit requires multi-region awareness: AssumeRole events are linked via sharedEventID across accounts, root sign-ins always appear in us-east-1 regardless of location, delegated admins can manage org-wide resources, but Lake dashboards are limited to same-account event data stores.

### cloudtrail-cross-account-denied-not-logged-target [IN] OBSERVATION
Cross-account AssumeRole denied requests are NOT logged in the target account's CloudTrail — only the source (caller's) account sees the denial.

### cloudtrail-custom-dashboard-max-50-tags [IN] OBSERVATION
CloudTrail Lake custom dashboards support up to 50 tags.

### cloudtrail-cwl-delivery-approximately-5-minutes [IN] OBSERVATION
CloudTrail delivers events to CloudWatch Logs within approximately 5 minutes of an API call; delivery is not real-time and not guaranteed.

### cloudtrail-cwl-log-group-same-account-only [IN] OBSERVATION
CloudWatch Logs log groups for CloudTrail must exist in the same account as the trail — unlike S3 buckets and SNS topics which support cross-account delivery.

### cloudtrail-cwl-max-event-size-256kb [IN] OBSERVATION
CloudTrail does not send events larger than 256 KB to CloudWatch Logs or EventBridge; starting with event version 1.05, events are capped at 256 KB.

### cloudtrail-cwl-role-two-permissions [IN] OBSERVATION
The IAM role for CloudTrail-to-CloudWatch Logs integration requires exactly two permissions: `logs:CreateLogStream` and `logs:PutLogEvents`, with a trust policy for `cloudtrail.amazonaws.com`.

### cloudtrail-dashboard-auto-refresh-two-policies-required [IN] OBSERVATION
For CloudTrail Lake dashboard auto-refresh, two resource-based policies are needed: one on the event data store (allowing `StartQuery`) and one on the dashboard (allowing `StartDashboardRefresh`), both with principal `cloudtrail.amazonaws.com`.

### cloudtrail-dashboard-max-10-widgets [IN] OBSERVATION
CloudTrail Lake custom dashboards support a maximum of 10 query widgets.

### cloudtrail-dashboard-refresh-frequency-values [IN] OBSERVATION
CloudTrail Lake dashboard refresh schedule supports HOURS (1, 6, 12, 24) or DAYS (1); the Highlights dashboard is fixed at 6 hours.

### cloudtrail-dashboard-resource-policies-required [IN] OBSERVATION
CloudTrail Lake dashboards with scheduled refresh require resource-based policies granting `StartQuery` on each event data store and `StartDashboardRefresh` on the dashboard itself.

### cloudtrail-data-events-available-in-eventbridge [IN] OBSERVATION
Data events logged by CloudTrail trails are also available as events in Amazon EventBridge.

### cloudtrail-data-events-go-to-lake-not-trails [IN] OBSERVATION
Events ingested via the CloudTrail Data Service `PutAuditEvents` API go to CloudTrail Lake event data stores, not to standard trails or S3 delivery.

### cloudtrail-data-events-insights-trail-only [IN] OBSERVATION
CloudTrail Data events Insights are only supported on trails, not on event data stores.

### cloudtrail-data-events-not-in-event-history [IN] OBSERVATION
CloudTrail data events do not appear in the CloudTrail Event History console — only management events are shown there.

### cloudtrail-data-events-off-by-default [IN] OBSERVATION
CloudTrail data events (data plane operations) are not logged by default in trails or event data stores and incur additional charges when enabled.

### cloudtrail-data-events-over-150-resource-types [IN] OBSERVATION
CloudTrail supports data event logging for over 150 resource types across dozens of AWS services, using the `resources.type` field in advanced event selectors.

### cloudtrail-data-events-queried-via-lake-not-event-history [IN] OBSERVATION
Events ingested via `cloudtrail-data` are searchable only through CloudTrail Lake queries, not through standard CloudTrail event history.

### cloudtrail-data-events-require-advanced-event-selectors [IN] OBSERVATION
Logging CloudTrail data events requires advanced event selectors (not basic event selectors), with filtering available on `eventCategory`, `resources.type`, `eventName`, and `resources.ARN`.

### cloudtrail-data-ingestion-uses-lake-channels [IN] OBSERVATION
External events are ingested into CloudTrail Lake through channel resources configured for external sources.

### cloudtrail-data-only-command-put-audit-events [IN] OBSERVATION
The `cloudtrail-data` service exposes only a single command: `put-audit-events`.

### cloudtrail-data-putauditevents-ingests-non-aws-events [IN] OBSERVATION
The CloudTrail Data Service API `PutAuditEvents` is the only way to ingest non-AWS events (from on-premises, SaaS, VMs, containers) into CloudTrail Lake.

### cloudtrail-data-requires-put-audit-events-permission [IN] OBSERVATION
Ingesting external events via `cloudtrail-data` requires the `cloudtrail-data:PutAuditEvents` IAM permission.

### cloudtrail-data-separate-endpoint-from-control-plane [IN] OBSERVATION
The CloudTrail Data Service uses a separate service endpoint (`cloudtrail-data`) from the main CloudTrail control-plane API.

### cloudtrail-data-service-ingests-external-events [IN] OBSERVATION
The `cloudtrail-data` CLI namespace is a separate service from `cloudtrail` that enables ingestion of events from non-AWS external sources (on-premises apps, SaaS, VMs, containers) into CloudTrail Lake.

### cloudtrail-default-posture-sufficient-for-basic-operational-visibility [IN] OBSERVATION
CloudTrail's default configuration (management events across all regions with 90-day retention) provides sufficient operational visibility for basic incident awareness when comprehensive audit coverage is not a regulatory or security requirement.

### cloudtrail-default-trail-scope-all-regions [IN] OBSERVATION
When a CloudTrail trail is created via the console, the default scope is all Regions.

### cloudtrail-delegated-admin-can-manage-org-resources [IN] OBSERVATION
A delegated administrator can manage CloudTrail resources for an organization, not just the management account.

### cloudtrail-delegated-admin-policy-auto-generated [IN] OBSERVATION
Delegated administrator accounts in AWS Organizations get an automatically generated resource policy for CloudTrail Lake resources that is evaluated alongside any user-submitted policy and cannot be overridden.

### cloudtrail-delegated-admin-slr-creation-difference [IN] OBSERVATION
Adding a CloudTrail delegated administrator via CloudTrail console/CLI/API auto-creates service-linked roles (AWSServiceRoleForCloudTrail, AWSServiceRoleForCloudTrailEventContext), but adding via Organizations CLI/API does not.

### cloudtrail-delete-channel-accepts-arn-or-uuid [IN] OBSERVATION
The `aws cloudtrail delete-channel` command's `--channel` parameter accepts either an ARN or a UUID to identify the channel.

### cloudtrail-delete-channel-does-not-delete-event-data-store [IN] OBSERVATION
Deleting a CloudTrail channel stops external event ingestion but does not delete the associated event data store.

### cloudtrail-delete-channel-no-output-on-success [IN] OBSERVATION
The `aws cloudtrail delete-channel` command returns no output on success.

### cloudtrail-delete-trail-keeps-s3-bucket [IN] OBSERVATION
Deleting a CloudTrail trail does not delete the associated S3 bucket or its log files.

### cloudtrail-dynamodb-streams-included-in-table-data-events [IN] OBSERVATION
When DynamoDB Streams is enabled, specifying `AWS::DynamoDB::Table` for CloudTrail data events logs both table and stream events by default; use `eventName` filter to separate them.

### cloudtrail-eds-default-billing-mode-extendable [IN] OBSERVATION
The default billing mode for a CloudTrail Lake event data store is EXTENDABLE_RETENTION_PRICING with a 366-day default retention period.

### cloudtrail-eds-event-categories-five-types [IN] OBSERVATION
CloudTrail Lake advanced event selectors support five `eventCategory` values: `Management`, `Data`, `ConfigurationItem`, `NetworkActivity`, and `Insight`.

### cloudtrail-eds-kms-key-irrevocable [IN] OBSERVATION
Once a KMS key is associated with a CloudTrail Lake event data store, it cannot be changed or removed; disabling/deleting the key blocks logging and querying.

### cloudtrail-eds-max-5-advanced-event-selectors [IN] OBSERVATION
A CloudTrail Lake event data store supports a maximum of 5 advanced event selectors, with no wildcard support (use StartsWith/EndsWith instead).

### cloudtrail-eds-multi-region-enabled-by-default [IN] OBSERVATION
CloudTrail Lake event data stores have multi-region enabled by default; use `--no-multi-region-enabled` to disable.

### cloudtrail-eds-only-name-required [IN] OBSERVATION
The only required parameter for `create-event-data-store` is `--name`; all others are optional with defaults.

### cloudtrail-eds-retention-limits-by-billing-mode [IN] OBSERVATION
CloudTrail Lake EDS retention limits differ by billing mode: EXTENDABLE_RETENTION_PRICING allows up to 3653 days (default 366), FIXED_RETENTION_PRICING allows up to 2557 days (default 2557, recommended for >25 TB/month).

### cloudtrail-eds-two-billing-modes [IN] OBSERVATION
CloudTrail Lake event data stores have two billing modes: `EXTENDABLE_RETENTION_PRICING` (default, ≤25 TB/month, up to 3653 days/~10 years) and `FIXED_RETENTION_PRICING` (>25 TB/month, up to 2557 days/~7 years).

### cloudtrail-enabled-by-default-90-days-free [IN] OBSERVATION
CloudTrail is enabled by default on all AWS accounts and provides 90 days of management event history at no charge.

### cloudtrail-enabled-by-default-all-accounts [IN] OBSERVATION
AWS CloudTrail is automatically enabled when you create an AWS account.

### cloudtrail-enabled-by-default-on-account-creation [IN] OBSERVATION
CloudTrail is automatically enabled when an AWS account is created — no manual setup is required to start capturing events.

### cloudtrail-enabled-by-default-on-all-accounts [IN] OBSERVATION
CloudTrail is enabled by default on every AWS account at creation time; recent events are viewable in Event history without creating a trail.

### cloudtrail-event-history-90-day-default [IN] OBSERVATION
CloudTrail Event History retains events for only 90 days without a trail configured.

### cloudtrail-event-history-90-days-free [IN] OBSERVATION
CloudTrail Event history provides 90 days of management events at no charge — viewable, searchable, downloadable, and immutable.

### cloudtrail-event-history-90-days-free-no-trail [IN] OBSERVATION
CloudTrail Event history is automatic, free, and provides 90 days of searchable management events per Region without creating a trail.

### cloudtrail-event-history-90-days-no-trail [IN] OBSERVATION
CloudTrail Event History retains the last 90 days of API activity per Region without any trail configuration.

### cloudtrail-event-history-90-days-no-trail-required [IN] OBSERVATION
CloudTrail Event History is available by default without creating a trail, capturing 90 days of management events per Region.

### cloudtrail-event-history-cannot-exclude-kms-rds-data-api [IN] OBSERVATION
KMS and RDS Data API events cannot be excluded from CloudTrail event history — exclusion settings on trails/event data stores do not apply to event history.

### cloudtrail-event-history-default-filter-write-only [IN] OBSERVATION
The CloudTrail console Event history default filter is Read only = false, showing only write events by default.

### cloudtrail-event-history-doubly-scoped-per-account-and-region [IN] OBSERVATION
CloudTrail event history is doubly scoped (per-account AND per-region), requiring accounts × regions combinatorial queries for comprehensive cross-account incident investigation — a 10-account, 5-region organization needs 50 independent lookups.

### cloudtrail-event-history-download-limit-200k [IN] OBSERVATION
CloudTrail event history console downloads are capped at 200,000 events per file in CSV or JSON format.

### cloudtrail-event-history-free-90-days [IN] OBSERVATION
CloudTrail Event history provides a free, searchable record of the past 90 days of management events per Region with no trail required.

### cloudtrail-event-history-free-90-days-management-only [IN] OBSERVATION
CloudTrail Event history is free, automatic, covers the past 90 days, and records management events only — no trail or event data store configuration required.

### cloudtrail-event-history-free-automatic-immutable [IN] OBSERVATION
CloudTrail event history is free, automatic, enabled by default for every AWS account, and immutable — it provides 90 days of management events per Region with no setup required.

### cloudtrail-event-history-independent-of-trails [IN] OBSERVATION
CloudTrail event history is independent of any trails or event data stores — changes to trails or event data stores do not affect what appears in event history.

### cloudtrail-event-history-no-trail-needed [IN] OBSERVATION
CloudTrail Event History shows recent events without creating a trail; a trail is required for long-term delivery to S3.

### cloudtrail-event-history-per-account [IN] OBSERVATION
CloudTrail Event history is per-account — the management account cannot see member account events in Event history; you must sign into each account.

### cloudtrail-event-history-region-scoped [IN] OBSERVATION
CloudTrail event history records and returns events per-Region — you must query each Region separately; for cross-Region queries use CloudTrail Lake.

### cloudtrail-eventbridge-requires-active-trail [IN] OBSERVATION
EventBridge integration with CloudTrail requires an active trail logging the appropriate event type (management, data, or Insights) for matching rules to trigger.

### cloudtrail-failed-signin-username-hidden [IN] OBSERVATION
CloudTrail masks incorrect usernames in sign-in failure events as `HIDDEN_DUE_TO_SECURITY_REASONS` to prevent sensitive data leakage.

### cloudtrail-federated-user-mfa-always-false [IN] OBSERVATION
Federated user sign-in events always show `mfaAuthenticated: "false"` and `MFAUsed: "No"` because MFA is evaluated at the federation/STS level, not at console sign-in.

### cloudtrail-first-management-event-copy-free [IN] OBSERVATION
The first copy of management events delivered to S3 via a CloudTrail trail is free (S3 storage charges still apply).

### cloudtrail-first-management-event-trail-free [IN] OBSERVATION
One copy of ongoing management events delivered to S3 via a CloudTrail trail is free; S3 storage charges still apply separately.

### cloudtrail-four-event-types [IN] OBSERVATION
CloudTrail logs four event types: management events (control plane), data events (data plane), network activity events (VPC endpoint calls), and Insights events (anomaly detection).

### cloudtrail-fullaccess-admin-only [IN] OBSERVATION
The `AWSCloudTrail_FullAccess` managed policy should only be granted to account administrators because it can disable or reconfigure auditing.

### cloudtrail-fullaccess-lambda-dynamodb-list-only [IN] OBSERVATION
The `AWSCloudTrail_FullAccess` policy grants only list permissions for Lambda and DynamoDB, enabling the CloudTrail console to display resources available for data event logging.

### cloudtrail-fullaccess-passrole-conditioned [IN] OBSERVATION
The `AWSCloudTrail_FullAccess` policy restricts `iam:PassRole` with condition `iam:PassedToService: cloudtrail.amazonaws.com`, preventing role passing to other services.

### cloudtrail-fullaccess-policy-arn [IN] OBSERVATION
The `AWSCloudTrail_FullAccess` managed policy ARN is `arn:aws:iam::aws:policy/AWSCloudTrail_FullAccess` and grants `cloudtrail:*` on all resources.

### cloudtrail-fullaccess-s3-sns-scoped-to-prefix [IN] OBSERVATION
The `AWSCloudTrail_FullAccess` policy scopes S3 and SNS write permissions to resources matching `aws-cloudtrail-logs*` — not all buckets/topics.

### cloudtrail-highlights-auto-enables-termination-protection [IN] OBSERVATION
Enabling the CloudTrail Lake Highlights dashboard automatically enables termination protection on it; termination protection must be disabled before the Highlights dashboard can be disabled.

### cloudtrail-highlights-dashboard-6hr-refresh-24hr-data [IN] OBSERVATION
The CloudTrail Lake Highlights dashboard refreshes automatically every 6 hours (not configurable) and displays the last 24 hours of data from the most recent update.

### cloudtrail-highlights-dashboard-exact-name [IN] OBSERVATION
The CloudTrail Lake Highlights dashboard must be named exactly `AWSCloudTrail-Highlights` — no other name is accepted.

### cloudtrail-highlights-widgets-managed-not-customizable [IN] OBSERVATION
CloudTrail Highlights dashboard widgets are unique per account and managed entirely by CloudTrail — users cannot add, remove, or modify them.

### cloudtrail-insights-analyzes-per-region-not-globally [IN] OBSERVATION
CloudTrail Insights analyzes events per-region, not globally; for organizations, analysis is per-member-account, not aggregated.

### cloudtrail-insights-api-call-rate-write-only-mgmt [IN] OBSERVATION
CloudTrail API call rate Insights only analyzes write management events (not read), while API error rate Insights analyzes both read and write management events.

### cloudtrail-insights-baseline-28-days-free [IN] OBSERVATION
CloudTrail Insights analyzes the past 28 days of events to establish a baseline at no charge; the baseline is recalculated daily.

### cloudtrail-insights-billed-per-events-analyzed [IN] OBSERVATION
CloudTrail Insights charges are based on the number of events analyzed, not the number of Insights events generated.

### cloudtrail-insights-call-rate-requires-write-error-rate-requires-read-or-write [IN] OBSERVATION
CloudTrail Insights API call rate analysis requires the trail to log write events, while API error rate analysis requires the trail to log read or write events.

### cloudtrail-insights-call-rate-write-mgmt-only [IN] OBSERVATION
CloudTrail Insights API call rate analysis for management events only analyzes write management events; API error rate analysis can use read, write, or both.

### cloudtrail-insights-call-rate-write-only-error-rate-read-write [IN] OBSERVATION
CloudTrail Insights on API call rate monitors write management APIs only; Insights on API error rate monitors both read and write management APIs.

### cloudtrail-insights-dashboard-max-30-days [IN] OBSERVATION
The CloudTrail Lake Insights events dashboard displays up to 30 days of Insights events.

### cloudtrail-insights-data-events-trail-only [IN] OBSERVATION
CloudTrail Insights on data events is only supported on trails, not on event data stores.

### cloudtrail-insights-delay-36h-trails-7d-lake [IN] OBSERVATION
CloudTrail Insights events have an initial delivery delay of up to 36 hours for trails and up to 7 days for CloudTrail Lake event data stores after first enablement.

### cloudtrail-insights-detects-unusual-api-activity [IN] OBSERVATION
CloudTrail Insights detects unusual API activity by analyzing CloudTrail events to establish baseline patterns, then generating Insights events when API call rates or error rates deviate significantly from those baselines.

### cloudtrail-insights-different-api-management-vs-data [IN] OBSERVATION
CloudTrail Insights events for management events use `LookupEvents` API, while Insights events for data events use `ListInsightsData` API — different APIs for different event types.

### cloudtrail-insights-double-counting-both-types [IN] OBSERVATION
When both Insights types (API call rate and API error rate) are enabled, write management events are analyzed twice and data events are always analyzed twice.

### cloudtrail-insights-eds-delivery-delay-7-days [IN] OBSERVATION
After first enabling Insights on an event data store, delivery of Insights events may take up to 7 days to begin.

### cloudtrail-insights-management-events-only [IN] OBSERVATION
CloudTrail Insights events are generated only for management API events, not data events; they detect anomalous API call rates and error rates.

### cloudtrail-insights-re-enable-resets-delay [IN] OBSERVATION
Re-enabling Insights or restarting logging/ingestion resets the delivery delay timer (36 hours for trails, 7 days for event data stores).

### cloudtrail-insights-region-scoped [IN] OBSERVATION
CloudTrail Insights events are generated per-Region, in the same Region as the source event that triggered them.

### cloudtrail-insights-requires-source-destination-eds-pair [IN] OBSERVATION
CloudTrail Lake Insights requires two event data stores (a source for management events and a destination for Insight events) linked via `put-insight-selectors`.

### cloudtrail-insights-requires-two-event-data-stores [IN] OBSERVATION
CloudTrail Insights in Lake requires two event data stores: a source (management events with Insights enabled) and a separate destination (receives Insights events).

### cloudtrail-insights-s3-delivery-folder [IN] OBSERVATION
CloudTrail Insights events from trails are delivered to a `/CloudTrail-Insight` folder in the trail's destination S3 bucket.

### cloudtrail-insights-trail-delivery-delay-36-hours [IN] OBSERVATION
After first enabling Insights on a trail, delivery of Insights events may take up to 36 hours to begin.

### cloudtrail-insights-two-event-types [IN] OBSERVATION
CloudTrail Insights has two event types: `ApiCallRateInsight` (detects unusual API call volume) and `ApiErrorRateInsight` (detects unusual API error volume).

### cloudtrail-insights-two-types [IN] OBSERVATION
CloudTrail Insights has two event types: `ApiCallRateInsight` (unusual API call volume) and `ApiErrorRateInsight` (unusual error rates).

### cloudtrail-insights-up-to-7-days-first-delivery [IN] OBSERVATION
After first enabling CloudTrail Insights, it may take up to 7 days before Insights events begin being delivered (if unusual activity is detected).

### cloudtrail-integration-eds-single-region-only [IN] OBSERVATION
CloudTrail Lake integration event data stores (for external sources) must be single-Region only.

### cloudtrail-internal-getmetricdata-no-cw-charge [IN] OBSERVATION
Internal CloudWatch GetMetricData calls (from dashboards, cross-account observability) appear in CloudTrail and count toward CloudTrail event charges but do not incur CloudWatch charges.

### cloudtrail-kms-encrypt-decrypt-over-99pct-volume [IN] OBSERVATION
AWS KMS actions (Encrypt, Decrypt, GenerateDataKey) account for over 99% of KMS event volume in CloudTrail and are classified as Read management events.

### cloudtrail-kms-events-over-99-percent [IN] OBSERVATION
KMS events (Encrypt, Decrypt, GenerateDataKey) typically generate over 99% of CloudTrail events; filtering these via advanced event selectors is a key cost optimization.

### cloudtrail-lake-14-managed-dashboards [IN] OBSERVATION
CloudTrail Lake provides 14 pre-built managed dashboards that are read-only with manual refresh.

### cloudtrail-lake-25tb-pricing-threshold [IN] OBSERVATION
The 25 TB/month ingestion threshold is the decision point between one-year extendable pricing (<25 TB) and seven-year fixed retention pricing (>25 TB) for CloudTrail Lake.

### cloudtrail-lake-advanced-selectors-no-wildcards [IN] OBSERVATION
CloudTrail Lake advanced event selectors do not support wildcards — use `StartsWith`, `EndsWith`, `NotStartsWith`, `NotEndsWith` operators instead, with a maximum of 500 values across all selector conditions per event data store.

### cloudtrail-lake-apache-orc-columnar-format [IN] OBSERVATION
CloudTrail Lake stores events in Apache ORC columnar format in event data stores, supporting SQL-based querying with configurable retention and ingestion/storage costs.

### cloudtrail-lake-apache-orc-sql-queries [IN] OBSERVATION
CloudTrail Lake stores events in Apache ORC columnar format and supports SQL-based queries with advanced event selectors for filtering.

### cloudtrail-lake-billing-mode-change-one-way [IN] OBSERVATION
CloudTrail Lake event data store billing mode can only be changed from FIXED_RETENTION_PRICING to EXTENDABLE_RETENTION_PRICING, not the reverse; reverting requires stopping ingestion and creating a new event data store.

### cloudtrail-lake-billing-mode-one-way [IN] OBSERVATION
CloudTrail Lake event data store billing mode cannot be switched from `EXTENDABLE_RETENTION_PRICING` to `FIXED_RETENTION_PRICING` — you must create a new event data store instead.

### cloudtrail-lake-cancel-query-queued-or-running-only [IN] OBSERVATION
CloudTrail Lake queries can only be cancelled when in QUEUED or RUNNING state; terminal states (CANCELLED, FAILED, TIMED_OUT, FINISHED) cannot be cancelled

### cloudtrail-lake-channels-one-per-source [IN] OBSERVATION
CloudTrail Lake channels (for external non-AWS event integration) allow a maximum of one channel per source; events are delivered via the `PutAuditEvents` API with `eventCategory="ActivityAuditLog"`.

### cloudtrail-lake-config-items-forward-only [IN] OBSERVATION
CloudTrail Lake event data stores for AWS Config configuration items only capture events going forward — no backfill of historical configuration items that occurred before creation.

### cloudtrail-lake-config-requires-recording-enabled [IN] OBSERVATION
Creating a CloudTrail Lake event data store for AWS Config configuration items requires that AWS Config recording is already enabled as a prerequisite.

### cloudtrail-lake-copy-trail-events-while-stopped [IN] OBSERVATION
Trail events can still be copied to a stopped CloudTrail Lake event data store, provided it contains only CloudTrail events.

### cloudtrail-lake-cross-account-cross-region-no-athena [IN] OBSERVATION
CloudTrail Lake aggregates events into an event data store (not S3) supporting cross-account, cross-region SQL queries directly in the CloudTrail console without requiring Athena.

### cloudtrail-lake-custom-dashboard-max-10-widgets [IN] OBSERVATION
CloudTrail Lake custom dashboards support a maximum of 10 widgets each.

### cloudtrail-lake-custom-dashboards-max-10-widgets [IN] OBSERVATION
CloudTrail Lake custom dashboards support up to 10 widgets, each backed by a SQL query.

### cloudtrail-lake-dashboard-auto-attaches-resource-policies [IN] OBSERVATION
When creating a CloudTrail Lake custom dashboard via the console, CloudTrail automatically attaches resource-based policies to selected event data stores to authorize dashboard queries.

### cloudtrail-lake-dashboard-max-50-tags [IN] OBSERVATION
CloudTrail Lake dashboards support up to 50 tag key pairs for identification and sorting.

### cloudtrail-lake-dashboard-queries-incur-charges [IN] OBSERVATION
CloudTrail Lake dashboard queries (both managed and Highlights) incur standard CloudTrail Lake query charges based on the amount of data scanned.

### cloudtrail-lake-dashboard-refresh-incurs-query-costs [IN] OBSERVATION
Each CloudTrail Lake dashboard refresh runs queries against event data stores and incurs standard Lake query costs.

### cloudtrail-lake-dashboard-refresh-intervals [IN] OBSERVATION
CloudTrail Lake custom dashboard automatic refresh intervals are limited to 1, 6, 12, or 24 hours — arbitrary cron expressions are not supported.

### cloudtrail-lake-dashboard-refresh-resource-policy [IN] OBSERVATION
CloudTrail automatically attaches a resource-based policy to a custom dashboard when an automatic refresh schedule is configured, granting CloudTrail permission to refresh on the user's behalf.

### cloudtrail-lake-dashboard-resource-policies-both-required [IN] OBSERVATION
CloudTrail Lake dashboard scheduled refresh requires resource-based policies on both the dashboard itself (for `StartDashboardRefresh`) and every associated event data store (for `StartQuery`).

### cloudtrail-lake-dashboard-termination-protection-blocks-delete [IN] OBSERVATION
CloudTrail Lake custom dashboards cannot be deleted until termination protection is explicitly disabled first.

### cloudtrail-lake-dashboard-two-types-custom-managed [IN] OBSERVATION
CloudTrail Lake dashboards have two types: CUSTOM (user-created) and MANAGED (configured by CloudTrail).

### cloudtrail-lake-dashboard-update-widgets-must-include-all [IN] OBSERVATION
When updating CloudTrail Lake dashboard widgets via CLI, the complete widgets array (existing plus new) must be passed — not just the new widget.

### cloudtrail-lake-dashboards-same-account-event-data-stores-only [IN] OBSERVATION
CloudTrail Lake dashboards (including Highlights and managed) can only query event data stores within the same AWS account.

### cloudtrail-lake-dashboards-same-account-only [IN] OBSERVATION
CloudTrail Lake dashboards only operate on event data stores within the same AWS account; delegated administrators cannot view or manage dashboards owned by the management account.

### cloudtrail-lake-dashboards-use-resource-based-policies [IN] OBSERVATION
CloudTrail Lake attaches resource-based policies (not identity-based policies) to event data stores and dashboards to grant itself permission to run automated queries and refreshes.

### cloudtrail-lake-eds-event-source-type-immutable [IN] OBSERVATION
A CloudTrail Lake event data store's event source type (AWS events vs. external events) cannot be changed after creation.

### cloudtrail-lake-eds-termination-protection-default-enabled [IN] OBSERVATION
CloudTrail Lake event data store termination protection is enabled by default and must be explicitly disabled (`--no-termination-protection-enabled`) before the event data store can be deleted.

### cloudtrail-lake-eds-two-pricing-options [IN] OBSERVATION
CloudTrail Lake event data stores have two pricing options: one-year extendable retention (default 366 days, max 3,653 days, best for <25 TB/month) and seven-year retention (default/max 2,557 days, best for >25 TB/month).

### cloudtrail-lake-enrichment-expands-event-size-to-1mb [IN] OBSERVATION
CloudTrail Lake event enrichment allows adding up to 50 resource tag keys and 50 IAM global condition keys to events (in the `eventContext` field), automatically expanding maximum event size from 256 KB to 1 MB.

### cloudtrail-lake-event-data-stores-immutable [IN] OBSERVATION
CloudTrail Lake event data stores are immutable collections of events filtered by advanced event selectors.

### cloudtrail-lake-event-delivery-latency-5-minutes [IN] OBSERVATION
CloudTrail Lake average event delivery latency is approximately 5 minutes from the API call, but delivery timing is not guaranteed.

### cloudtrail-lake-eventcategory-discriminator-values [IN] OBSERVATION
CloudTrail Lake event categories distinguish schema types: Management/Data for CloudTrail events, `Insight` for Insights, `ConfigurationItem` for Config items, `Evidence` for Audit Manager, and `ActivityAuditLog` for non-AWS events.

### cloudtrail-lake-events-immutably-stored [IN] OBSERVATION
Events stored in CloudTrail Lake are immutably stored, supporting audit and compliance use cases.

### cloudtrail-lake-eventtime-reduces-query-cost [IN] OBSERVATION
Including `eventTime` constraints in CloudTrail Lake queries directly reduces query costs by limiting the amount of compressed data scanned.

### cloudtrail-lake-eventtime-scope-controls-cost [IN] OBSERVATION
Constraining CloudTrail Lake queries with `eventTime` bounds is recommended to control query costs.

### cloudtrail-lake-extendable-retention-max-3653-days [IN] OBSERVATION
CloudTrail Lake EXTENDABLE_RETENTION_PRICING supports retention up to 3653 days and is recommended when ingesting less than 25 TB/month.

### cloudtrail-lake-external-events-putauditevents-api [IN] OBSERVATION
External (non-AWS) events are ingested into CloudTrail Lake via the PutAuditEvents API, with two integration types: direct (partner calls API) and solution (app runs in your account).

### cloudtrail-lake-external-events-via-putauditevents [IN] OBSERVATION
External (non-AWS) events are ingested into CloudTrail Lake via the PutAuditEvents API through channels that target event data stores logging `eventCategory="ActivityAuditLog"`.

### cloudtrail-lake-external-integration-direct-vs-solution [IN] OBSERVATION
CloudTrail Lake has two integration types for external events: direct (partner calls `PutAuditEvents` from outside your account) and solution (application runs in your AWS account and calls `PutAuditEvents` on your behalf).

### cloudtrail-lake-federation-athena-requires-lakeformation-getdataaccess [IN] OBSERVATION
Athena users querying federated CloudTrail Lake data must have the `lakeformation:GetDataAccess` permission (included in `AmazonAthenaFullAccess`).

### cloudtrail-lake-federation-glue-lakeformation-athena [IN] OBSERVATION
CloudTrail Lake federation enables Athena queries over event data stores by registering metadata in AWS Glue Data Catalog and AWS Lake Formation.

### cloudtrail-lake-federation-managed-glue-database [IN] OBSERVATION
CloudTrail Lake federation creates a managed AWS Glue database named `aws:cloudtrail` with a federated table named after the event data store ID; views cannot be created in this managed database.

### cloudtrail-lake-federation-must-disable-before-delete [IN] OBSERVATION
A federated CloudTrail Lake event data store cannot be deleted until federation (and termination protection) are disabled first; disabling federation does not delete any CloudTrail Lake data.

### cloudtrail-lake-federation-no-cloudtrail-charges [IN] OBSERVATION
CloudTrail Lake federation to Athena incurs no CloudTrail charges; only Athena query costs apply.

### cloudtrail-lake-federation-role-trust-lakeformation [IN] OBSERVATION
The CloudTrail Lake federation IAM role trust policy must allow `lakeformation.amazonaws.com` to assume it via `sts:AssumeRole`.

### cloudtrail-lake-federation-to-glue-athena [IN] OBSERVATION
CloudTrail Lake event data stores can be federated to AWS Glue Data Catalog, enabling querying via Amazon Athena.

### cloudtrail-lake-federation-uses-glue-athena [IN] OBSERVATION
CloudTrail Lake query federation enables querying event data stores via Amazon Athena by registering metadata in AWS Glue Data Catalog; disabling federation does not delete CloudTrail Lake data.

### cloudtrail-lake-five-schema-types [IN] OBSERVATION
CloudTrail Lake has five distinct event data store schema types: CloudTrail events, Insights events, AWS Config configuration items, AWS Audit Manager evidence, and non-AWS (partner/integration) events.

### cloudtrail-lake-from-clause-uses-eds-id [IN] OBSERVATION
CloudTrail Lake SQL FROM clause references the event data store ID (the ID portion of the EDS ARN), not a table name or full ARN.

### cloudtrail-lake-highlights-dashboard-6-hour-updates [IN] OBSERVATION
CloudTrail Lake Highlights dashboards auto-update every 6 hours and show the last 24 hours of data, surfacing anomalies.

### cloudtrail-lake-highlights-dashboard-every-6-hours [IN] OBSERVATION
The CloudTrail Lake Highlights dashboard auto-updates every 6 hours and shows the last 24 hours of data, surfacing anomalies like abnormal cross-account access.

### cloudtrail-lake-ingestion-uncompressed-queries-compressed [IN] OBSERVATION
CloudTrail Lake charges for ingestion based on uncompressed data size, but charges for queries based on optimized and compressed (ORC) data scanned.

### cloudtrail-lake-ingests-aws-config-items [IN] OBSERVATION
AWS Config configuration items can be ingested into CloudTrail Lake event data stores for unified querying using `eventCategory: ConfigurationItem`.

### cloudtrail-lake-insights-requires-two-event-data-stores [IN] OBSERVATION
CloudTrail Lake Insights requires two separate event data stores: a source (logs management events) and a destination (receives Insights events with `eventCategory` set to `Insight`).

### cloudtrail-lake-integrations-ingest-external-events [IN] OBSERVATION
CloudTrail Lake can ingest events from outside AWS (on-premises apps, SaaS, VMs, containers) via integration channels and the `PutAuditEvents` API from the `cloudtrail-data` service.

### cloudtrail-lake-kms-decrypt-for-encrypted-eds [IN] OBSERVATION
If CloudTrail Lake event data stores are KMS-encrypted, the KMS key policy must grant `kms:Decrypt` to the `cloudtrail.amazonaws.com` service principal for dashboards to function.

### cloudtrail-lake-kms-key-cannot-be-removed-or-changed [IN] OBSERVATION
Once a KMS key is associated with a CloudTrail Lake event data store, it cannot be removed or changed.

### cloudtrail-lake-kms-key-cannot-change-or-remove [IN] OBSERVATION
Once a customer-managed KMS key is associated with a CloudTrail Lake event data store, it cannot be removed or changed.

### cloudtrail-lake-kms-key-irreversible [IN] OBSERVATION
Once a KMS key is associated with a CloudTrail Lake event data store, it cannot be removed or changed.

### cloudtrail-lake-kms-key-irrevocable [IN] OBSERVATION
Once a KMS key is associated with a CloudTrail Lake event data store, it cannot be removed or changed; disabling or deleting the key prevents both logging and querying.

### cloudtrail-lake-managed-dashboard-requires-eds-id-param [IN] OBSERVATION
Managed dashboard refreshes require passing `$EventDataStoreId$` in query parameters; custom dashboard refreshes do not.

### cloudtrail-lake-managed-dashboards-not-modifiable [IN] OBSERVATION
CloudTrail Lake managed dashboards cannot be modified (no adding, removing, or editing widgets) — they must be saved as custom dashboards for customization.

### cloudtrail-lake-managed-dashboards-read-only [IN] OBSERVATION
CloudTrail Lake managed dashboards cannot be modified — they must be saved as a custom dashboard to edit widgets.

### cloudtrail-lake-max-5-advanced-event-selectors [IN] OBSERVATION
CloudTrail Lake event data stores support up to 5 advanced event selectors with a maximum of 500 total condition values across all selectors.

### cloudtrail-lake-max-retention-10-years [IN] OBSERVATION
CloudTrail Lake event data stores support up to 3,653 days (~10 years) retention with one-year extendable pricing, or up to 2,557 days (~7 years) with seven-year pricing.

### cloudtrail-lake-metrics-namespace-aws-cloudtrail [IN] OBSERVATION
CloudTrail Lake publishes metrics to CloudWatch under the `AWS/CloudTrail` namespace, including HourlyDataIngested (hourly), TotalDataRetained (nightly), TotalStorageBytes, TotalPaidStorageBytes, and HourlyEventsAnalyzed.

### cloudtrail-lake-one-event-category-per-eds [IN] OBSERVATION
Each CloudTrail Lake event data store holds only one event category (management events, data events, network activity events, Insights events, Config items, Audit Manager evidence, or external events).

### cloudtrail-lake-operational-readiness-requires-upfront-planning [IN] OBSERVATION
CloudTrail Lake demands careful upfront planning: KMS keys are irrevocable once set, pricing tier changes are one-way only (seven-year to one-year but not reverse), retention is based on eventTime not ingestion, and saved queries are browser-local — operational missteps in any of these are permanent or lossy.

### cloudtrail-lake-orc-columnar-format [IN] OBSERVATION
CloudTrail Lake converts events from row-based JSON to Apache ORC columnar format for optimized storage and retrieval (not Parquet, not JSON at rest).

### cloudtrail-lake-orc-format [IN] OBSERVATION
CloudTrail Lake stores event data in Apache ORC columnar format for SQL-based querying.

### cloudtrail-lake-orc-format-not-json [IN] OBSERVATION
CloudTrail Lake converts JSON events to Apache ORC columnar format for storage and fast retrieval; queries are charged by data scanned.

### cloudtrail-lake-orc-format-sql-queries [IN] OBSERVATION
CloudTrail Lake stores events in Apache ORC columnar format in immutable event data stores and supports SQL-based queries.

### cloudtrail-lake-orc-sql-queryable [IN] OBSERVATION
CloudTrail Lake stores event data in Apache ORC columnar format and supports SQL queries with advanced event selectors.

### cloudtrail-lake-org-eds-defaults [IN] OBSERVATION
Organization event data stores default to: MultiRegionEnabled=true, TerminationProtectionEnabled=true, RetentionPeriod=366, BillingMode=EXTENDABLE_RETENTION_PRICING.

### cloudtrail-lake-org-eds-management-only-actions [IN] OBSERVATION
Only the management account can: convert between account-level and organization-level event data stores, enable Insights, copy trail events, view managed dashboards, and enable Highlights dashboards on organization event data stores.

### cloudtrail-lake-org-eds-members-cannot-see-or-query [IN] OBSERVATION
Member accounts cannot see, modify, delete, or query organization event data stores by default in CloudTrail Lake.

### cloudtrail-lake-org-eds-requires-existing-kms-key [IN] OBSERVATION
Organization event data stores in CloudTrail Lake must use an existing KMS key from the management account — a new key cannot be created during setup.

### cloudtrail-lake-org-eds-resides-in-management-account [IN] OBSERVATION
Organization event data stores in CloudTrail Lake always reside in the management account, even when created by a delegated administrator.

### cloudtrail-lake-partner-events-activity-audit-log [IN] OBSERVATION
Partner events ingested into CloudTrail Lake use `eventCategory: ActivityAuditLog`, distinct from AWS management and data events.

### cloudtrail-lake-partner-two-integration-types [IN] OBSERVATION
CloudTrail Lake partner integrations have two types: direct integration (partner calls `PutAuditEvents` from their own infrastructure) and solution integration (partner app runs inside the customer's AWS account).

### cloudtrail-lake-pricing-change-one-way-only [IN] OBSERVATION
CloudTrail Lake event data store pricing can be changed from seven-year to one-year extendable, but not the reverse — switching to seven-year requires stopping ingestion and creating a new event data store.

### cloudtrail-lake-queries-billed-by-data-scanned [IN] OBSERVATION
CloudTrail Lake queries are billed based on data scanned; using `eventTime` filters reduces costs.

### cloudtrail-lake-queries-charged-by-data-scanned [IN] OBSERVATION
CloudTrail Lake queries are charged based on the amount of data scanned, not the number of queries; using eventTime filters reduces costs.

### cloudtrail-lake-queries-use-trino-sql [IN] OBSERVATION
CloudTrail Lake queries use Trino-compatible SQL SELECT statements, not standard MySQL or PostgreSQL syntax.

### cloudtrail-lake-query-async-three-step-workflow [IN] OBSERVATION
CloudTrail Lake query workflow is asynchronous: `start-query` → `describe-query` (check status) → `get-query-results` (retrieve results).

### cloudtrail-lake-query-engine-trino-sql [IN] OBSERVATION
CloudTrail Lake queries use Trino-compatible SQL (not standard MySQL/PostgreSQL), supporting all valid Trino SELECT statements and functions including cross-event-data-store JOINs.

### cloudtrail-lake-query-generator-english-only [IN] OBSERVATION
CloudTrail Lake natural language query generator only supports English-language prompts (3–500 characters).

### cloudtrail-lake-query-generator-free-generation [IN] OBSERVATION
CloudTrail Lake query generation from natural language prompts is free; charges only apply when running the generated queries, based on compressed data scanned.

### cloudtrail-lake-query-generator-opt-out-deny-action [IN] OBSERVATION
Users can opt out of CloudTrail Lake query generation by denying the `cloudtrail:GenerateQuery` IAM action.

### cloudtrail-lake-query-generator-seven-regions [IN] OBSERVATION
CloudTrail Lake query generator is available in 7 regions: ap-south-1, ap-southeast-2, ap-northeast-1, ca-central-1, eu-west-2, us-east-1, us-west-2.

### cloudtrail-lake-query-results-retained-7-days [IN] OBSERVATION
CloudTrail Lake query results are viewable for up to 7 days and can be saved to S3.

### cloudtrail-lake-query-select-only-trino-sql [IN] OBSERVATION
CloudTrail Lake queries are read-only (SELECT only, no mutations) and use Trino-compatible SQL.

### cloudtrail-lake-reduce-retention-deletes-immediately [IN] OBSERVATION
Reducing a CloudTrail Lake event data store's retention period immediately removes events with `eventTime` older than the new retention period.

### cloudtrail-lake-retention-based-on-event-time [IN] OBSERVATION
CloudTrail Lake retention period is based on `eventTime`, not ingestion time.

### cloudtrail-lake-retention-based-on-eventtime [IN] OBSERVATION
CloudTrail Lake event data store retention is determined by the event's `eventTime` field, not ingestion time — events are removed when their `eventTime` exceeds the retention period.

### cloudtrail-lake-retention-by-event-time-not-ingestion [IN] OBSERVATION
CloudTrail Lake event data store retention is based on the event's `eventTime`, not when the event was ingested.

### cloudtrail-lake-retention-limits-by-billing-mode [IN] OBSERVATION
CloudTrail Lake retention limits differ by billing mode: 7–3,653 days (~10 years) for extendable retention pricing vs. 7–2,557 days (~7 years) for fixed retention pricing.

### cloudtrail-lake-retention-reduction-deletes-immediately [IN] OBSERVATION
Reducing a CloudTrail Lake event data store's retention period immediately and irreversibly deletes events with eventTime older than the new retention period.

### cloudtrail-lake-saved-queries-browser-local [IN] OBSERVATION
CloudTrail Lake saved queries are stored in the browser only (browser-local) — they do not persist across browsers or devices.

### cloudtrail-lake-search-sample-queries-iam-action [IN] OBSERVATION
The `cloudtrail:SearchSampleQueries` IAM action is required for enhanced search functionality on the CloudTrail Lake sample queries page; it is included in the `AWSCloudTrail_FullAccess` managed policy.

### cloudtrail-lake-seven-to-one-year-in-place-not-reverse [IN] OBSERVATION
CloudTrail Lake pricing can be changed from seven-year to one-year extendable in-place, but switching from one-year to seven-year requires stopping ingestion and creating a new event data store.

### cloudtrail-lake-sql-dot-notation-nested-fields [IN] OBSERVATION
CloudTrail Lake uses SQL syntax with dot-notation for nested fields (e.g., `userIdentity.arn`) and queries run against event data stores identified by their ARN-derived ID.

### cloudtrail-lake-sql-queries-additional-charges [IN] OBSERVATION
CloudTrail Lake provides SQL-based querying of events and incurs separate charges beyond standard CloudTrail pricing.

### cloudtrail-lake-stop-ingestion-cloudtrail-config-only [IN] OBSERVATION
Stop/Start ingestion is only available for event data stores containing CloudTrail events (management, data, network activity) or AWS Config configuration items — not for integration event data stores.

### cloudtrail-lake-stop-ingestion-queries-still-work [IN] OBSERVATION
Stopping ingestion on a CloudTrail Lake event data store (state `STOPPED_INGESTION`) does not affect read access — queries continue to work on existing events.

### cloudtrail-lake-storage-free-first-366-days [IN] OBSERVATION
Under CloudTrail Lake one-year extendable retention pricing, storage for the first 366 days is included at no extra cost with ingestion pricing; storage beyond 366 days is pay-as-you-go.

### cloudtrail-lake-supported-31-regions-including-govcloud [IN] OBSERVATION
CloudTrail Lake is available in 31 AWS regions including both GovCloud (US) regions, but China regions are not supported.

### cloudtrail-lake-termination-protection-before-delete [IN] OBSERVATION
Termination protection must be disabled on a CloudTrail Lake dashboard before it can be deleted; it applies to both custom and Highlights dashboards.

### cloudtrail-lake-termination-protection-default-on [IN] OBSERVATION
Termination protection is enabled by default on CloudTrail Lake event data stores and must be explicitly disabled before deletion.

### cloudtrail-lake-termination-protection-on-by-default [IN] OBSERVATION
CloudTrail Lake event data store termination protection is enabled by default.

### cloudtrail-lake-three-dashboard-types [IN] OBSERVATION
CloudTrail Lake has three dashboard types: managed (14 pre-built, read-only), custom (up to 10 widgets, optional scheduled refresh), and Highlights (auto-updated every 6 hours, surfaces anomalies).

### cloudtrail-lake-three-resource-types-support-resource-policies [IN] OBSERVATION
Three CloudTrail Lake resource types support resource-based policies: channels, event data stores, and dashboards.

### cloudtrail-lake-two-pricing-options [IN] OBSERVATION
CloudTrail Lake offers two pricing options: one-year extendable retention (default, up to 3,653 days/~10 years, storage included first 366 days) and seven-year fixed retention (up to 2,557 days/~7 years, storage included at no additional cost).

### cloudtrail-lake-two-pricing-tiers [IN] OBSERVATION
CloudTrail Lake has two pricing options: one-year extendable retention (max ~10 years, recommended for <25 TB/month) and seven-year retention (max ~7 years, recommended for >25 TB/month).

### cloudtrail-lake-uncompressed-10x-s3-gzip [IN] OBSERVATION
Uncompressed CloudTrail trail data is approximately 10x the S3 gzip-compressed size, which is critical for cost estimation when copying trail events to Lake.

### cloudtrail-limit-5-trails-per-region [IN] OBSERVATION
CloudTrail has a limit of 5 trails per AWS Region; a multi-Region trail counts as one trail in each Region it covers.

### cloudtrail-log-delivery-approx-5-minutes [IN] OBSERVATION
CloudTrail delivers log files within approximately 5 minutes on average, not in real-time, and delivery time is not guaranteed.

### cloudtrail-log-delivery-within-15-minutes [IN] OBSERVATION
CloudTrail typically delivers log files to S3 within 15 minutes of API activity.

### cloudtrail-log-entry-captures-identity-time-ip-params-response [IN] OBSERVATION
Each CloudTrail log entry captures caller identity, call start time, source IP address, request parameters, and response elements.

### cloudtrail-log-files-not-ordered [IN] OBSERVATION
CloudTrail log files are not ordered — they do not form a sequential stack trace of events.

### cloudtrail-log-files-published-every-5-minutes [IN] OBSERVATION
CloudTrail publishes log files to S3 approximately every 5 minutes (not guaranteed per SLA).

### cloudtrail-log-files-unordered [IN] OBSERVATION
CloudTrail log files are not ordered — they are not a sequential stack trace.

### cloudtrail-log-group-name-max-512-chars [IN] OBSERVATION
CloudWatch log group names for CloudTrail must be unique per Region per account, with a maximum length of 512 characters and allowed characters `a-z, A-Z, 0-9, _ - / . #`.

### cloudtrail-log-stream-naming-format [IN] OBSERVATION
CloudTrail CloudWatch log streams are automatically named `{account_ID}_CloudTrail_{region}`, with a numeric suffix appended for high-volume trails.

### cloudtrail-logs-all-cfn-api-calls-automatically [IN] OBSERVATION
CloudTrail logs all CloudFormation API calls automatically with no additional configuration required; the eventSource is `cloudformation.amazonaws.com`.

### cloudtrail-logs-delivered-to-s3 [IN] OBSERVATION
CloudTrail records AWS API calls and delivers log files to Amazon S3 as its primary storage target.

### cloudtrail-logs-itself [IN] OBSERVATION
CloudTrail logs its own API calls — all CloudTrail API operations are recorded by CloudTrail.

### cloudtrail-logs-multi-account-multi-region-single-bucket [IN] OBSERVATION
CloudTrail logs can be aggregated from multiple AWS Regions and multiple accounts into a single S3 bucket.

### cloudtrail-logs-request-params-not-responses [IN] OBSERVATION
CloudTrail logs capture request parameters but not response data for Account Management API calls (`responseElements: null` for read operations).

### cloudtrail-lookup-events-90-days-management-only [IN] OBSERVATION
The `lookup-events` CLI command only accesses management events from the last 90 days; older events require CloudTrail Lake or S3 log archives.

### cloudtrail-lookup-events-rate-limit-2-per-second [IN] OBSERVATION
CloudTrail `lookup-events` requests are rate-limited to 2 per second, per account, per Region.

### cloudtrail-lookup-events-single-attribute-filter [IN] OBSERVATION
Only one AttributeKey/AttributeValue pair can be specified per `lookup-events` call; valid keys are AccessKeyId, EventId, EventName, EventSource, ReadOnly, ResourceName, ResourceType, and Username.

### cloudtrail-lookupevents-90-day-limit [IN] OBSERVATION
`LookupEvents` API retrieves management events or CloudTrail Insights events within a single Region, limited to the last 90 days.

### cloudtrail-lookupevents-insight-requires-explicit-category [IN] OBSERVATION
To retrieve Insights events via `LookupEvents`, `EventCategory` must be explicitly set to `"insight"`; otherwise only management events are returned.

### cloudtrail-lookupevents-max-50-results-per-page [IN] OBSERVATION
`LookupEvents` returns a default and maximum of 50 results per page; pagination requires `NextToken`.

### cloudtrail-lookupevents-no-data-events [IN] OBSERVATION
`LookupEvents` does not return data events — it only supports management events and Insights events.

### cloudtrail-lookupevents-one-attribute-per-request [IN] OBSERVATION
`LookupEvents` accepts only one lookup attribute per request — multiple filters cannot be combined in a single call.

### cloudtrail-lookupevents-rate-limit-2-per-second [IN] OBSERVATION
`LookupEvents` has a rate limit of 2 requests per second, per account, per Region.

### cloudtrail-management-account-owns-org-resources [IN] OBSERVATION
The management account always owns all CloudTrail organization resources (trails, event data stores) regardless of which delegated administrator created them.

### cloudtrail-management-events-default-data-events-not [IN] OBSERVATION
CloudTrail logs management events (control plane) by default; data events (data plane) are NOT logged by default and require explicit configuration via advanced event selectors, incurring additional charges.

### cloudtrail-masks-sensitive-fields [IN] OBSERVATION
CloudTrail automatically redacts sensitive fields (e.g., `masterUserPassword` appears as `"****"`) in log entries.

### cloudtrail-max-3-delegated-admins [IN] OBSERVATION
A maximum of 3 CloudTrail delegated administrators can be registered per AWS Organization.

### cloudtrail-max-50-tags-per-resource [IN] OBSERVATION
CloudTrail resources (trails, event data stores, dashboards, channels) support a maximum of 50 tags per resource

### cloudtrail-mfa-status-in-session-context [IN] OBSERVATION
MFA authentication status is recorded in CloudTrail logs at `sessionContext.attributes.mfaAuthenticated` (true/false).

### cloudtrail-misconfigured-trail-30-day-redelivery [IN] OBSERVATION
CloudTrail attempts redelivery for 30 days if a trail's S3 bucket is unreachable, incurring standard charges; the trail must be deleted to stop charges.

### cloudtrail-misconfigured-trail-retries-30-days-incurs-charges [IN] OBSERVATION
A misconfigured CloudTrail trail (e.g., unreachable S3 bucket) retries delivery for 30 days and still incurs charges; the trail must be deleted to stop costs.

### cloudtrail-misconfigured-trail-retries-30-days-with-charges [IN] OBSERVATION
A misconfigured CloudTrail trail retries log delivery for 30 days and still incurs charges; the trail must be deleted to stop billing.

### cloudtrail-multi-region-tags-from-home-region [IN] OBSERVATION
Multi-region CloudTrail trails and event data stores can only be tagged from the Region where they were created (home Region)

### cloudtrail-multi-region-trail-modify-home-region-only [IN] OBSERVATION
Multi-Region CloudTrail trails can only be modified in their home Region (the Region where they were created), though they are visible in all enabled Regions.

### cloudtrail-multi-trail-strategy-constrained-by-limits-and-costs [IN] OBSERVATION
Multi-trail audit architectures (separate trails for security, compliance, and operations) face both a hard quota (5 trails per region) and incremental costs (only first management event copy is free), forcing organizations to choose between audit separation and cost/quota efficiency.

### cloudtrail-network-activity-events-vpc-endpoints [IN] OBSERVATION
CloudTrail network activity events record API calls made through VPC endpoints from private VPCs, filterable by eventName, errorCode (VpceAccessDenied), and vpcEndpointId.

### cloudtrail-network-events-no-s3-multi-region-access-points [IN] OBSERVATION
Amazon S3 Multi-Region Access Points are not supported for CloudTrail network activity events.

### cloudtrail-network-events-not-default-extra-charge [IN] OBSERVATION
CloudTrail network activity events are not logged by default and incur additional charges beyond standard CloudTrail pricing.

### cloudtrail-network-events-only-vpceaccessdenied-error [IN] OBSERVATION
The only supported `errorCode` filter for CloudTrail network activity events is `VpceAccessDenied`.

### cloudtrail-network-events-require-advanced-selectors [IN] OBSERVATION
CloudTrail network activity events require advanced event selectors — basic event selectors cannot log them; each event source needs its own separate field selector.

### cloudtrail-no-logs-for-vpc-endpoint-denied-requests [IN] OBSERVATION
CloudTrail does not deliver log entries for S3 requests denied by a VPC endpoint policy.

### cloudtrail-no-service-specific-condition-keys [IN] OBSERVATION
CloudTrail does not have service-specific context keys for use in IAM policy Condition elements.

### cloudtrail-oidc-verification-method-logged [IN] OBSERVATION
CloudTrail logs the OIDC provider verification method in `additionalEventData.identityProviderConnectionVerificationMethod` — value is either `IAMTrustStore` or `Thumbprint`.

### cloudtrail-one-free-copy-management-events-to-s3 [IN] OBSERVATION
One copy of ongoing management events is delivered to S3 at no CloudTrail charge (S3 storage charges still apply).

### cloudtrail-opt-in-region-auto-replicates-trails [IN] OBSERVATION
When an opt-in Region is enabled, CloudTrail automatically creates copies of existing multi-Region trails there; when disabled, it continues attempting to deliver events until trails are deleted.

### cloudtrail-org-eds-policy-auto-managed [IN] OBSERVATION
Organization event data store resource-based policies are automatically managed by CloudTrail based on AWS Organizations delegated administrator settings and auto-updated on organization changes.

### cloudtrail-org-governance-delegation-incomplete [IN] OBSERVATION
CloudTrail organization trails support delegated administrator management but trail-to-Lake event copying requires the management account — governance delegation breaks at the analytics boundary, forcing the management account back into the operational path for long-term audit storage

### cloudtrail-org-trail-created-despite-validation-failures [IN] OBSERVATION
Organization trail copies are created in member accounts even if resource validation fails (S3 policy, SNS policy, CloudWatch Logs, KMS permissions).

### cloudtrail-org-trail-cwl-console-management-account-only [IN] OBSERVATION
Organization trail CloudWatch Logs configuration via the console is restricted to the management account; delegated administrators must use the AWS CLI or CreateTrail/UpdateTrail API.

### cloudtrail-org-trail-log-stream-org-id-prefix [IN] OBSERVATION
Organization trail CloudWatch log stream resource ARNs use the `o-<orgid>_*` prefix pattern, requiring separate resource entries in the IAM policy alongside the standard account-based entries.

### cloudtrail-org-trail-management-account-or-delegated-admin-only [IN] OBSERVATION
Only the management account or a delegated administrator can create, modify, or delete organization trails; member accounts have read-only visibility of trail copies.

### cloudtrail-org-trail-management-or-delegated-admin [IN] OBSERVATION
Only the management account or a delegated administrator can create organization trails in CloudTrail.

### cloudtrail-org-trail-requires-management-or-delegated [IN] OBSERVATION
CloudTrail organization trails require the caller to be the management account or a delegated administrator.

### cloudtrail-org-trail-service-linked-role-auto-managed [IN] OBSERVATION
Organization trails automatically create a service-linked role `AWSServiceRoleForCloudTrail` in member accounts; the role is removed if the account leaves the organization.

### cloudtrail-removed-member-logs-persist-in-s3 [IN] OBSERVATION
When an account is removed from an organization, CloudTrail logging stops and the trail/SLR are deleted, but existing log files remain in S3.

### cloudtrail-resource-policy-max-8192-chars [IN] OBSERVATION
CloudTrail resource-based policies have a maximum size of 8,192 characters.

### cloudtrail-resource-policy-three-resource-types [IN] OBSERVATION
CloudTrail resource-based policies can be attached to event data stores, dashboards, and channels — not trails.

### cloudtrail-root-signin-always-us-east-1 [IN] OBSERVATION
Root user ConsoleLogin events are always logged in us-east-1 regardless of the user's location.

### cloudtrail-security-lake-requires-multi-region-org-trail [IN] OBSERVATION
Security Lake requires a multi-Region organization trail collecting both read and write management events to ingest CloudTrail management events.

### cloudtrail-sensitive-data-masked-in-logs [IN] OBSERVATION
CloudTrail masks sensitive data (user utterances, conversation tokens, response bodies) with `***` in log entries for services like Amazon Q.

### cloudtrail-sensitive-data-redaction-inconsistent-across-services [IN] OBSERVATION
Sensitive data handling in CloudTrail logs varies by service — some redact fields (B2BI, Clean Rooms), some never log values (CFN parameters) — with no platform-wide redaction policy.

### cloudtrail-shared-event-id-cross-account [IN] OBSERVATION
Cross-account AssumeRole events are linked across both accounts' CloudTrail logs using a `sharedEventID` field.

### cloudtrail-signin-event-source-signin-amazonaws [IN] OBSERVATION
Console sign-in events use event source `signin.amazonaws.com` with event name `ConsoleLogin` and event type `AwsConsoleSignIn`.

### cloudtrail-signin-events-are-management-events [IN] OBSERVATION
Console sign-in events are management events (`managementEvent: true`, `eventCategory: "Management"`).

### cloudtrail-sns-notification-per-log-file-not-event [IN] OBSERVATION
CloudTrail SNS notifications are sent per log file delivery, not per individual event.

### cloudtrail-sse-kms-enabled-by-default [IN] OBSERVATION
CloudTrail trail log file encryption uses SSE-KMS by default (not SSE-S3) when creating a trail.

### cloudtrail-start-logging-required-after-creation [IN] OBSERVATION
A CloudTrail trail must have `start-logging` called to begin capturing events after creation via CLI.

### cloudtrail-tag-key-max-128-value-max-256 [IN] OBSERVATION
CloudTrail tag keys have a maximum length of 128 Unicode characters and tag values have a maximum of 256 Unicode characters

### cloudtrail-trail-all-regions-by-default [IN] OBSERVATION
A CloudTrail trail created via the console applies to all AWS Regions by default.

### cloudtrail-trail-delivers-events-to-s3 [IN] OBSERVATION
A CloudTrail trail delivers API activity events as log files to a specified S3 bucket, extending retention beyond the default 90-day Event History.

### cloudtrail-trail-log-validation-disabled-by-default [IN] OBSERVATION
CloudTrail log file integrity validation is disabled by default and must be explicitly enabled with `--enable-log-file-validation`; disabling it breaks the digest chain after one hour.

### cloudtrail-trail-required-beyond-90-days [IN] OBSERVATION
A CloudTrail trail is required to retain event records beyond 90 days; trails deliver log files to S3 (first copy of management events is free from CloudTrail, S3 storage charges apply).

### cloudtrail-trail-required-for-continuous-s3-delivery [IN] OBSERVATION
A CloudTrail trail is required for continuous, long-term delivery of events to S3; without one, only recent events are viewable via Event History.

### cloudtrail-trail-required-for-persistent-logging [IN] OBSERVATION
Without creating a CloudTrail trail, only recent events are viewable in Event History; a trail must be created for persistent log delivery to S3.

### cloudtrail-trail-required-for-persistent-logs [IN] OBSERVATION
Without a configured trail, CloudTrail only provides access to recent events via Event History (90-day retention); a trail must be configured for persistent long-term delivery of events to S3.

### cloudtrail-trail-requires-start-logging [IN] OBSERVATION
A CloudTrail trail only delivers logs after `start-logging` is called — creating a trail does not automatically start log delivery.

### cloudtrail-trail-single-region-by-default [IN] OBSERVATION
A CloudTrail trail is single-region by default; `--is-multi-region-trail` must be explicitly set for all-region logging.

### cloudtrail-trails-all-regions-by-default [IN] OBSERVATION
CloudTrail trails created in the console apply to all AWS Regions by default.

### cloudtrail-trails-cross-region-s3-delivery [IN] OBSERVATION
CloudTrail trails can deliver log files to S3 buckets in a different Region from where the trail is created, and multiple trails can share the same S3 bucket.

### cloudtrail-trails-default-all-regions-console [IN] OBSERVATION
CloudTrail trails created via the AWS Console apply to all AWS Regions by default.

### cloudtrail-trails-deliver-s3-cloudwatch-eventbridge [IN] OBSERVATION
CloudTrail trails can deliver events simultaneously to S3, CloudWatch Logs, and EventBridge.

### cloudtrail-trails-survive-account-closure [IN] OBSERVATION
CloudTrail trails can persist even after AWS account closure unless explicitly deleted beforehand.

### cloudtrail-useridentity-identifies-credential-type [IN] OBSERVATION
The CloudTrail `userIdentity` element reveals whether a request used root credentials, IAM user credentials, temporary role/federated credentials, or was made by another AWS service.

### cloudtrail-vpc-api-logged-as-ec2-subset [IN] OBSERVATION
Amazon VPC API calls are logged in CloudTrail as a subset of EC2 API calls (supported since 11/13/2013).

### cloudwatch-agent-required-for-os-level-metrics [IN] OBSERVATION
The CloudWatch agent is required for OS-level metrics (memory, disk usage) and log collection; default EC2 monitoring provides only hypervisor-level metrics (CPU, network, disk I/O).

### cloudwatch-agent-required-for-os-metrics [IN] OBSERVATION
The CloudWatch Agent is required for detailed OS-level metrics (memory, disk, processes) on EC2 — these are not sent automatically.

### cloudwatch-agent-supports-on-premises-servers [IN] OBSERVATION
The CloudWatch agent can collect system-level metrics and logs from both EC2 instances and on-premises servers.

### cloudwatch-alarm-actions-five-targets [IN] OBSERVATION
CloudWatch metric alarms can trigger five types of actions: SNS notifications, EC2 actions (stop/terminate/reboot/recover), Auto Scaling policies, Systems Manager OpsItems/incidents, and CloudWatch Investigations.

### cloudwatch-alarm-actions-on-state-change-only [IN] OBSERVATION
CloudWatch alarms invoke actions only on state change, except Auto Scaling actions which continue invoking once per minute while in the new state.

### cloudwatch-alarm-can-precede-custom-metric [IN] OBSERVATION
A CloudWatch alarm can be created for a custom metric before the metric exists, provided all dimensions, namespace, and metric name are specified.

### cloudwatch-alarm-eval-period-max-7-days [IN] OBSERVATION
CloudWatch alarm evaluation period maximum is 7 days (for period ≥ 1 hour) or 1 day (for shorter periods or Lambda data source).

### cloudwatch-alarm-history-30-days [IN] OBSERVATION
CloudWatch alarm history is retained for 30 days.

### cloudwatch-alarm-missing-data-configurable [IN] OBSERVATION
When resources stop sending metric data (e.g., unattached EBS volumes), CloudWatch alarms enter INSUFFICIENT_DATA state; behavior is configurable via missing data treatment settings.

### cloudwatch-alarm-no-action-validation [IN] OBSERVATION
CloudWatch does not validate that alarm action targets (SNS topics, Auto Scaling groups) actually exist; nonexistent targets will silently fail.

### cloudwatch-alarm-three-states [IN] OBSERVATION
A CloudWatch alarm has exactly three possible states: OK, ALARM, and INSUFFICIENT_DATA.

### cloudwatch-alarms-trigger-on-sustained-state-changes [IN] OBSERVATION
CloudWatch alarms act only on sustained state changes, not momentary spikes — the threshold must be breached for the configured number of evaluation periods before an action triggers.

### cloudwatch-application-signals-no-instrumentation [IN] OBSERVATION
CloudWatch Application Signals provides automatic APM (latency, error rates, request rates) without manual instrumentation or code changes.

### cloudwatch-composite-alarm-no-ec2-autoscaling-actions [IN] OBSERVATION
CloudWatch composite alarms cannot perform EC2 or Auto Scaling actions; they support only SNS notifications, OpsItems, incidents, and investigations.

### cloudwatch-container-insights-ecs-eks-k8s [IN] OBSERVATION
CloudWatch Container Insights works with ECS, EKS, and self-managed Kubernetes on EC2.

### cloudwatch-cross-account-composite-alarms-not-supported [IN] OBSERVATION
Cross-account composite alarms are not supported in CloudWatch; cross-account metric alarms are supported.

### cloudwatch-cross-account-math-no-anomaly-insight-quota [IN] OBSERVATION
Cross-account CloudWatch math expression alarms do not support ANOMALY_DETECTION_BAND, INSIGHT_RULE, or SERVICE_QUOTA functions.

### cloudwatch-cross-account-observability-central-monitoring [IN] OBSERVATION
CloudWatch cross-account observability uses a central monitoring account with linked source accounts; can be automated via AWS Organizations.

### cloudwatch-custom-metrics-via-putmetricdata [IN] OBSERVATION
Custom application metrics are published to CloudWatch via the PutMetricData API and are treated the same as AWS resource metrics.

### cloudwatch-dashboard-accountid-metric-overrides-widget [IN] OBSERVATION
In CloudWatch dashboard JSON, the `accountId` parameter can be set at widget level or individual metric level, with metric-level overriding widget-level.

### cloudwatch-dashboard-putdashboard-api [IN] OBSERVATION
CloudWatch dashboards are created or modified programmatically using the `PutDashboard` API with a JSON-based dashboard body definition.

### cloudwatch-dashboard-three-iam-permissions [IN] OBSERVATION
CloudWatch dashboard access requires three specific IAM permissions: `GetDashboard`/`ListDashboards` (view), `PutDashboard` (create/modify), and `DeleteDashboards` (delete).

### cloudwatch-dashboards-cross-account-cross-region [IN] OBSERVATION
CloudWatch dashboards can be shared across accounts and Regions.

### cloudwatch-data-events-not-logged-by-default [IN] OBSERVATION
CloudWatch data plane operations (GetMetricData, PutMetricData, GetMetricWidgetImage, GetMetricStatistics, ListMetrics) are CloudTrail data events not logged by default; enabling them incurs additional charges.

### cloudwatch-internet-monitor-uses-aws-global-network-data [IN] OBSERVATION
CloudWatch Internet Monitor analyzes internet performance using AWS global networking data and VPC flow logs.

### cloudwatch-log-outlier-detection [IN] OBSERVATION
CloudWatch provides Log Outlier Detection to find unusual patterns in log events.

### cloudwatch-logs-1-active-export-task-limit [IN] OBSERVATION
CloudWatch Logs allows only 1 active export task at a time — this limit is not adjustable.

### cloudwatch-logs-1-million-log-groups-per-account-region [IN] OBSERVATION
CloudWatch Logs allows up to 1,000,000 log groups per account per region (adjustable).

### cloudwatch-logs-10-resource-policies-per-account-region [IN] OBSERVATION
CloudWatch Logs allows a maximum of 10 resource policies per account per region — this limit is not adjustable.

### cloudwatch-logs-cloudtrail-management-events-only [IN] OBSERVATION
CloudWatch Logs records only management events (not data events like PutLogEvents) in CloudTrail.

### cloudwatch-logs-data-protection-masks-sensitive-data [IN] OBSERVATION
CloudWatch Logs data protection policies audit and mask sensitive data in logs using configurable data identifiers; data is masked by default when the policy is enabled.

### cloudwatch-logs-default-retention-indefinite [IN] OBSERVATION
CloudWatch Logs default retention is indefinite (never expires); retention is configurable from 1 day to 10 years per log group.

### cloudwatch-logs-encrypted-in-transit-and-at-rest [IN] OBSERVATION
CloudWatch Logs data is encrypted both in transit and at rest.

### cloudwatch-logs-eventsource-logs-amazonaws-com [IN] OBSERVATION
CloudWatch Logs standard API calls use `logs.amazonaws.com` as the CloudTrail eventSource; Query Generator console events use `monitoring.amazonaws.com`.

### cloudwatch-logs-insights-cross-account-multi-log-group-query [IN] OBSERVATION
A single CloudWatch Logs Insights query in a monitoring account can query multiple log groups across multiple source accounts simultaneously.

### cloudwatch-logs-insights-sql-ppl [IN] OBSERVATION
CloudWatch Logs Insights supports SQL and PPL query languages in addition to its native syntax.

### cloudwatch-logs-max-100-metric-filters-per-group [IN] OBSERVATION
CloudWatch Logs allows a maximum of 100 metric filters per log group — this limit is not adjustable.

### cloudwatch-logs-max-2-subscription-filters-per-group [IN] OBSERVATION
CloudWatch Logs allows a maximum of 2 subscription filters per log group — this limit is not adjustable.

### cloudwatch-logs-max-event-size-1mb [IN] OBSERVATION
CloudWatch Logs maximum log event size is 1,024 KB (1 MB), and the PutLogEvents batch size limit is also 1 MB.

### cloudwatch-logs-putlogevents-5000-tps-adjustable [IN] OBSERVATION
CloudWatch Logs PutLogEvents has a default throttle limit of 5,000 TPS (adjustable) — the highest default API throttle limit for CloudWatch Logs.

### cloudwatch-logs-two-classes-standard-infrequent-access [IN] OBSERVATION
CloudWatch Logs has two log classes: Standard (full features, higher cost) and Infrequent Access (lower ingestion cost, subset of features).

### cloudwatch-many-aws-services-free-basic-metrics [IN] OBSERVATION
Many AWS services (EC2, EBS, RDS, etc.) provide free basic CloudWatch metrics by default; detailed monitoring is available at additional cost.

### cloudwatch-metric-filters-extract-metrics-from-logs [IN] OBSERVATION
CloudWatch metric filters extract numerical values from log data to generate CloudWatch metrics for alerting and dashboards.

### cloudwatch-metric-retention-15-months [IN] OBSERVATION
CloudWatch metric data is retained for 15 months.

### cloudwatch-metric-streams-continuous-export [IN] OBSERVATION
CloudWatch Metric Streams provide continuous streaming of metrics to external destinations (e.g., S3, Datadog via Firehose).

### cloudwatch-metrics-insights-max-2-weeks [IN] OBSERVATION
CloudWatch Metrics Insights queries support up to 2 weeks of historical data, not the full 15-month retention period.

### cloudwatch-network-flow-monitor-nhi [IN] OBSERVATION
CloudWatch Network Flow Monitor uses lightweight agents on instances and produces a Network Health Indicator (NHI).

### cloudwatch-network-synthetic-monitor-direct-connect [IN] OBSERVATION
CloudWatch Network Synthetic Monitor is specifically for testing Direct Connect connectivity.

### cloudwatch-no-limit-alarms-per-account [IN] OBSERVATION
There is no limit on the number of CloudWatch alarms per AWS account.

### cloudwatch-set-alarm-state-testing-only [IN] OBSERVATION
CloudWatch SetAlarmState is for testing only; the state change is temporary until the next evaluation cycle.

### cloudwatch-slo-error-budgets [IN] OBSERVATION
CloudWatch supports defining Service Level Objectives (SLOs) with reliability targets, error budgets, and compliance monitoring over time.

### cloudwatch-solutions-catalog-prebuilt-configs [IN] OBSERVATION
CloudWatch Solutions Catalog provides pre-built monitoring configurations for common workloads including JVM, NVIDIA GPU, Kafka, Tomcat, and NGINX.

### cloudwatch-synthetics-vs-rum [IN] OBSERVATION
CloudWatch Synthetics (canaries) proactively test endpoints with configurable scripts simulating user behavior; CloudWatch RUM gathers performance data from actual user sessions.

### cloudwatch-tag-based-alarms-metrics-insights [IN] OBSERVATION
CloudWatch supports tag-based alarms using Metrics Insights queries with resource tags for context-aware monitoring.

### cognito-identity-pools-use-assume-role-with-web-identity [IN] OBSERVATION
Amazon Cognito identity pools use the STS `AssumeRoleWithWebIdentity` API under the hood to acquire temporary IAM credentials for mobile/web app users.

### consolidated-billing-combines-usage-for-volume-discounts [IN] OBSERVATION
AWS Organizations consolidated billing combines usage across all member accounts for volume pricing discounts, RI discounts, and Savings Plans benefits at no additional fee.

### cost-allocation-tags-24-hour-propagation [IN] OBSERVATION
Cost allocation tags can take up to 24 hours to appear in the Billing and Cost Management console after activation.

### cost-allocation-tags-management-account-only [IN] OBSERVATION
Only the management account in an AWS Organization (or a standalone account) can manage cost allocation tags.

### cost-allocation-tags-two-types-both-require-activation [IN] OBSERVATION
AWS cost allocation tags come in two types: AWS-generated (prefixed `aws:`) and user-defined (prefixed `user`), and both must be separately activated before appearing in cost reports.

### cost-anomaly-detection-automated-vs-budgets-threshold [IN] OBSERVATION
AWS Cost Anomaly Detection provides automated alerting for unexpected cost spikes, distinct from AWS Budgets which uses user-defined thresholds.

### cost-optimization-five-focus-areas [IN] OBSERVATION
The Cost Optimization pillar has five focus areas: Practice Cloud Financial Management, Expenditure and usage awareness, Cost-effective resources, Manage demand and supply resources, and Optimize over time.

### cost-optimization-not-minimizing-spend [IN] OBSERVATION
Cost optimization does not mean minimizing spend at all costs — it means achieving the best price for the required outcome while meeting functional requirements.

### creation-time-immutability-has-permanent-cost-and-dr-implications [IN] OBSERVATION
Creation-time immutable decisions (consistency mode, LSI structure, KMS keys) permanently affect both capacity costs and disaster recovery options — incorrect choices require full resource recreation.

### cross-account-dynamodb-cost-attribution-structurally-incomplete [IN] OBSERVATION
Cross-account DynamoDB deployments have structurally incomplete cost attribution: resource owners pay for operations initiated by other accounts (billing-audit asymmetry) AND automated operations like TTL create dual blind spots invisible to both cost monitoring and CloudTrail audit — cross-account billing cannot be reconciled against operational audit records.

### cross-region-replication-defaults-eventual-consistency-across-services [IN] OBSERVATION
Cross-region data replication defaults to eventual consistency across AWS's major data services — DynamoDB global tables default to MREC, RDS cross-region replicas are asynchronous, and Aurora DSQL requires same-continent for multi-region — making strong cross-region consistency an opt-in exception rather than the norm.

### cross-service-kms-irrevocability-creates-permanent-operational-constraints [IN] OBSERVATION
Multiple AWS services make KMS key decisions irrevocable through different mechanisms — DynamoDB archives data after 7 days if a CMK is disabled, CloudTrail Lake KMS keys cannot be changed or removed — creating a cross-cutting pattern where encryption key management permanently constrains operational flexibility across unrelated service tiers

### dax-actions-use-dax-prefix-not-dynamodb [IN] OBSERVATION
DAX IAM actions use the `dax:` prefix (e.g., `dax:GetItem`, `dax:PutItem`) not the `dynamodb:` prefix, and the resource ARN format is `arn:aws:dax:<region>:<account-id>:cache/<cluster-name>`.

### dax-attribute-name-metadata-retained-indefinitely [IN] OBSERVATION
DAX retains attribute name metadata indefinitely in the cluster even after items expire or are evicted — using unbounded unique values as top-level attribute names (timestamps, UUIDs) causes memory exhaustion.

### dax-best-cache-hit-rate-above-90-percent [IN] OBSERVATION
DAX performs best when cache hit rates exceed 90%; it is ideal for read-heavy, hot-key, or bursty workloads.

### dax-bypassing-writes-causes-stale-reads [IN] OBSERVATION
Writing directly to DynamoDB (bypassing DAX) causes DAX to serve stale data until TTL expiry or LRU eviction — there is no automatic cache invalidation from DynamoDB-side writes.

### dax-cannot-manage-tables [IN] OBSERVATION
DAX cannot perform table management operations (CreateTable, UpdateTable, etc.) — applications must call DynamoDB directly for these.

### dax-cannot-warm-item-cache-with-scan [IN] OBSERVATION
You cannot warm the DAX item cache with a Scan operation — Scan results go only to the query cache, not the item cache.

### dax-client-drop-in-replacement-same-vpc [IN] OBSERVATION
The DAX client SDK is a drop-in replacement for the standard DynamoDB client requiring minimal code changes, and the client must be in the same VPC as the DAX cluster (DAX is not accessible over the public internet).

### dax-cluster-same-region-as-tables [IN] OBSERVATION
A DAX cluster can only interact with DynamoDB tables in the same AWS Region.

### dax-console-auto-creates-service-role-cli-does-not [IN] OBSERVATION
The AWS Console automatically detects and creates a DAX service role if none exists; the CLI requires you to create the service role manually before cluster creation.

### dax-consumed-rcu-only-counts-cache-misses [IN] OBSERVATION
When DAX is in front of DynamoDB, the `ConsumedReadCapacityUnits` CloudWatch metric only reflects cache misses; divide by (1 - hit rate) to estimate total DAX read throughput.

### dax-cross-account-client-only-not-dynamodb [IN] OBSERVATION
DAX cannot access a DynamoDB table in a different account — cross-account access only applies to clients accessing a DAX cluster, not DAX accessing DynamoDB cross-account.

### dax-cross-account-requires-iam-and-vpc-peering [IN] OBSERVATION
Cross-account DAX access requires both IAM role chaining (STS AssumeRole) and VPC peering with non-overlapping CIDRs — neither alone is sufficient.

### dax-daxs-scheme-indicates-encryption-in-transit [IN] OBSERVATION
DAX cluster endpoints use `dax://` for unencrypted connections and `daxs://` for encryption-in-transit connections.

### dax-describe-table-required-in-service-role [IN] OBSERVATION
The `dynamodb:DescribeTable` action must be included in the DAX service role policy for DAX to maintain table metadata.

### dax-does-not-enforce-user-level-permissions [IN] OBSERVATION
DAX does not enforce user-level permissions on DynamoDB data — all users of a DAX cluster inherit the cluster's IAM service role permissions, which can subvert existing DynamoDB IAM policies.

### dax-dynamodb-compatible-drop-in-client [IN] OBSERVATION
DAX is DynamoDB-compatible — applications use a DAX client that is a drop-in replacement for the standard DynamoDB client.

### dax-encryption-at-rest-aes-256-aws-managed-key-only [IN] OBSERVATION
DAX encryption at rest uses AES-256 encryption with the AWS KMS managed service default key; customer-managed KMS keys are not supported.

### dax-encryption-at-rest-aws-managed-key-only [IN] OBSERVATION
DAX clusters with encryption at rest always use an AWS managed key — customer managed keys and AWS owned keys are not supported for DAX.

### dax-encryption-cannot-change-after-creation [IN] OBSERVATION
DAX encryption at rest and encryption in transit cannot be enabled or disabled after cluster creation — the cluster must be recreated.

### dax-encryption-in-transit-tls-all-or-nothing [IN] OBSERVATION
DAX encryption in transit uses TLS with x509 certificate verification; once enabled, unencrypted traffic is rejected (no mixed-mode support).

### dax-fault-tolerant-cluster-minimum-3-nodes-3-azs [IN] OBSERVATION
A fault-tolerant DAX cluster requires at least 3 nodes distributed across 3 Availability Zones.

### dax-iam-role-creation-excluded-from-managed-policies [IN] OBSERVATION
The four IAM permissions needed to create a DAX service role (iam:CreateRole, iam:CreatePolicy, iam:AttachRolePolicy, iam:PassRole) are intentionally excluded from AWS managed DynamoDB policies to prevent privilege escalation.

### dax-is-inmemory-cache-not-database [IN] OBSERVATION
DAX (DynamoDB Accelerator) is an in-memory caching layer for DynamoDB, not a separate database.

### dax-isolation-requires-separate-clusters [IN] OBSERVATION
To isolate user-level access to specific DynamoDB tables through DAX, separate DAX clusters with different service roles scoped to specific tables must be created.

### dax-item-cache-default-ttl-5-minutes [IN] OBSERVATION
The DAX item cache has a default TTL of 5 minutes, configurable at cluster creation time; with TTL=0, items are only refreshed via LRU eviction or write-through operations.

### dax-item-cache-query-cache-independent [IN] OBSERVATION
DAX's item cache (GetItem/BatchGetItem) and query cache (Query/Scan) are completely independent — writing an item does not invalidate query cache results containing that item.

### dax-kms-key-used-only-at-cluster-launch [IN] OBSERVATION
DAX uses the KMS encryption key only at cluster launch, not per-operation; revoking KMS access does not immediately cut off data access until the cluster is shut down.

### dax-management-api-cannot-scope-to-resource [IN] OBSERVATION
DAX management API actions (e.g., `DescribeClusters`, `CreateCluster`) cannot be scoped to specific cluster ARNs — the IAM `Resource` element must be `"*"`; data plane actions can be scoped to specific cluster ARNs.

### dax-max-10-read-replicas-per-cluster [IN] OBSERVATION
A DAX cluster supports up to 10 read replicas (11 nodes total: 1 primary + 10 replicas), and the `--new-replication-factor` parameter specifies total nodes including the primary.

### dax-max-500-tables-per-cluster [IN] OBSERVATION
A DAX cluster supports a maximum of 500 DynamoDB tables; exceeding this degrades availability and performance.

### dax-microsecond-latency-eventually-consistent [IN] OBSERVATION
DAX delivers microsecond latency for eventually consistent reads, compared to single-digit milliseconds for standard DynamoDB reads.

### dax-microsecond-read-latency [IN] OBSERVATION
DAX (DynamoDB Accelerator) provides microsecond response times for read-heavy workloads, compared to single-digit millisecond latency for standard DynamoDB reads.

### dax-minimum-3-nodes-multi-az-for-ha [IN] OBSERVATION
The recommended DAX high-availability configuration is a minimum of 3 nodes deployed across multiple Availability Zones.

### dax-monitoring-cloudwatch-and-cloudtrail [IN] OBSERVATION
DAX monitoring uses two primary AWS tools: CloudWatch for real-time metrics/alarms and CloudTrail for API call logging/auditing.

### dax-negative-caching-empty-results [IN] OBSERVATION
DAX caches negative results (empty/missing items) which persist until TTL expires, LRU evicts them, or the item is modified via DAX.

### dax-only-caches-eventually-consistent-reads [IN] OBSERVATION
DAX only caches eventually consistent reads; strongly consistent reads (ConsistentRead=true) always pass through to DynamoDB and are never cached.

### dax-parameter-group-change-affects-new-entries-only [IN] OBSERVATION
Modifying a DAX parameter group on a running cluster only affects newly written cache entries — existing cached items retain their original TTL values.

### dax-port-8111 [IN] OBSERVATION
DAX uses TCP port 8111 for client connections — this port must be opened in security groups for cross-account or any DAX access.

### dax-production-minimum-3-nodes-3-azs [IN] OBSERVATION
DAX production best practice requires at least 3 nodes deployed across 3 different Availability Zones; 1–2 node clusters are not fault-tolerant and are suitable only for dev/test.

### dax-query-cache-ttl-zero-means-no-caching [IN] OBSERVATION
DAX query cache with TTL=0 means query responses are not cached at all, unlike item cache TTL=0 which retains items until LRU eviction or write-through.

### dax-r3-no-encryption-at-rest [IN] OBSERVATION
DAX `dax.r3.*` node types do not support encryption at rest.

### dax-read-replicas-do-not-write-to-dynamodb [IN] OBSERVATION
DAX read replicas handle reads and cache eviction only — they do not write to DynamoDB; only the primary node writes to DynamoDB.

### dax-requires-aws-provided-client [IN] OBSERVATION
DAX requires AWS-provided DAX client SDKs (Go, Java, Node.js, Python, .NET) — the standard DynamoDB SDK client cannot be used with DAX.

### dax-runs-exclusively-within-vpc [IN] OBSERVATION
DAX clusters run exclusively within a VPC — there is no public endpoint option, and access is controlled via VPC security groups, subnets, and routing tables.

### dax-service-linked-role-auto-created [IN] OBSERVATION
The AWSServiceRoleForDAX service-linked role is auto-created when you create a DAX cluster and cannot be deleted while any DAX clusters exist.

### dax-service-linked-role-ec2-not-dynamodb [IN] OBSERVATION
The DAX service-linked role (AWSServiceRoleForDAX) grants EC2 networking permissions (security groups, network interfaces, VPCs, subnets), not DynamoDB permissions — DynamoDB access must be configured separately.

### dax-service-role-trusts-dax-service [IN] OBSERVATION
The DAX service role must include a trust relationship allowing `dax.amazonaws.com` to call `sts:AssumeRole`.

### dax-t2-nodes-not-suitable-sustained-workloads [IN] OBSERVATION
DAX T2 node types use burstable CPU and are not suitable for sustained workloads due to CPU credit depletion.

### dax-t2-standard-t3-unlimited-burst-modes [IN] OBSERVATION
DAX T2 instances use standard burst mode (CPU capped at baseline when credits exhausted), while T3 instances use unlimited mode (can burst beyond baseline at extra cost).

### dax-t3-burst-free-if-average-below-baseline-24h [IN] OBSERVATION
DAX T3 bursting is free if average CPU usage stays at or below the baseline over a 24-hour window; surplus usage is billed per vCPU-hour.

### dax-traffic-stays-within-vpc [IN] OBSERVATION
DAX traffic between the application and cluster always stays within the VPC via ENIs with private IPs, regardless of whether encryption in transit is enabled.

### dax-transactgetitems-not-cached [IN] OBSERVATION
TransactGetItems are not cached by DAX — they are passed through to DynamoDB like strongly consistent reads.

### dax-transactwriteitems-async-cache-population [IN] OBSERVATION
DAX handles TransactWriteItems by forwarding the transaction to DynamoDB, returning success, then asynchronously issuing TransactGetItems for each item to populate the item cache with serializable isolation.

### dax-two-caches-default-ttl-5-minutes [IN] OBSERVATION
DAX has two separate caches — item cache (`GetItem`/`BatchGetItem`) and query cache (`Query`/`Scan`) — both with a default TTL of 5 minutes, configured via parameter group settings `record-ttl-millis` and `query-ttl-millis` in milliseconds.

### dax-two-policies-govern-access [IN] OBSERVATION
Two IAM policies govern DAX access: a user access policy controlling `dax:*` actions on the cluster ARN, and a DAX service role policy controlling `dynamodb:*` actions on DynamoDB table ARNs.

### dax-typical-cache-hit-rate-85-95-percent [IN] OBSERVATION
Typical cache hit rates for DAX applications are 85–95%.

### dax-vertical-scaling-requires-new-cluster [IN] OBSERVATION
DAX vertical scaling (changing node type) requires creating a new cluster — node types cannot be changed on a running cluster, and all nodes must be the same type.

### dax-vertical-vs-horizontal-scaling [IN] OBSERVATION
DAX vertical scaling (larger node type) addresses high CPU, high eviction, and high memory usage; horizontal scaling (more nodes) addresses read-heavy workloads with high cache hit rates.

### dax-vpc-only-port-8111 [IN] OBSERVATION
DAX runs inside a VPC and requires an inbound security group rule on TCP port 8111; it is only accessible from resources within the VPC.

### dax-write-through-dynamodb-first [IN] OBSERVATION
DAX uses a write-through model where writes go to DynamoDB first, then to the DAX item cache; the operation succeeds only if both succeed, and failed DynamoDB writes are never cached.

### dedicated-host-cannot-mix-virtualized-and-metal [IN] OBSERVATION
You cannot mix virtualized and `.metal` instance types on the same allocated Dedicated Host.

### dedicated-host-no-capacity-reservations [IN] OBSERVATION
Capacity Reservations are NOT supported on Dedicated Hosts; they are only supported on Dedicated Instances.

### dedicated-host-no-placement-groups [IN] OBSERVATION
Dedicated Hosts cannot be launched into placement groups.

### dedicated-host-reservation-up-to-70pct-discount [IN] OBSERVATION
Dedicated Host Reservations offer up to 70% discount vs On-Demand pricing, available in 1-year or 3-year terms.

### dedicated-instance-ebs-not-single-tenant [IN] OBSERVATION
EBS volumes attached to Dedicated Instances do NOT run on single-tenant hardware; the isolation boundary is compute only.

### dedicated-instance-may-share-host-same-account [IN] OBSERVATION
Dedicated Instances are isolated at the account level — instances from the same AWS account (including non-dedicated instances) can share the same physical host.

### dedicated-vpc-tenancy-forces-all-instances-dedicated [IN] OBSERVATION
Setting VPC tenancy to `dedicated` forces all instances in that VPC to run as Dedicated Instances.

### default-nacl-allows-all-custom-nacl-denies-all [IN] OBSERVATION
The default VPC Network ACL allows all inbound and outbound traffic; custom NACLs deny all traffic by default until rules are added.

### default-subnets-auto-assign-public-ipv4 [IN] OBSERVATION
Default subnets auto-assign public IPv4 addresses to launched instances; nondefault subnets do not.

### default-vpc-has-igw-ipv4-route-not-ipv6 [IN] OBSERVATION
The default VPC comes with an internet gateway and a route table entry for IPv4 (0.0.0.0/0) but not for IPv6 (::/0).

### default-vpc-per-region [IN] OBSERVATION
Every AWS account includes a default VPC in each Region with default subnets already configured.

### default-vpc-security-group-used-when-none-specified [IN] OBSERVATION
If no security group is specified at instance launch, the default security group for the VPC is used.

### dynamodb-100-byte-per-item-storage-overhead [IN] OBSERVATION
DynamoDB billing includes a 100-byte per-item storage overhead not reflected in DescribeTable or capacity calculations.

### dynamodb-10000-table-hard-limit-per-account [IN] OBSERVATION
DynamoDB has a hard cap of 10,000 tables per account that cannot be increased; exceeding this requires distributing tables across multiple AWS accounts.

### dynamodb-2500-tables-per-account-soft-limit [IN] OBSERVATION
DynamoDB has a soft quota of 2,500 tables per account.

### dynamodb-2500-tables-soft-quota [IN] OBSERVATION
DynamoDB has a soft account quota of 2,500 tables per account.

### dynamodb-500-concurrent-table-operations-limit [IN] OBSERVATION
DynamoDB has a soft limit of 500 simultaneous table operations per account (shared across CreateTable, UpdateTable, DeleteTable, UpdateTimeToLive, RestoreTableFromBackup, RestoreTableToPointInTime), reduced to 250 when creating tables with secondary indexes.

### dynamodb-500-simultaneous-table-operations-limit [IN] OBSERVATION
DynamoDB allows up to 500 simultaneous table operations (CreateTable, UpdateTable, DeleteTable, UpdateTimeToLive, RestoreTableFromBackup, RestoreTableToPointInTime) per account, reduced to 250 when creating tables with secondary indexes.

### dynamodb-account-deletion-overrides-deletion-protection [IN] OBSERVATION
AWS account deletion overrides DynamoDB deletion protection — all data is removed within 90 days.

### dynamodb-account-limit-2500-tables-500-concurrent-ops [IN] OBSERVATION
DynamoDB has a soft limit of 2,500 tables per account and up to 500 simultaneous table operations (reduced to 250 when creating tables with secondary indexes).

### dynamodb-account-limit-2500-tables-500-ops [IN] OBSERVATION
DynamoDB soft account quotas: 2,500 tables per account; 500 simultaneous table operations (CreateTable, UpdateTable, DeleteTable, UpdateTimeToLive, restore operations), reduced to 250 when creating tables with secondary indexes.

### dynamodb-add-action-number-and-set-only [IN] OBSERVATION
The `ADD` action in DynamoDB UpdateExpression only supports Number and Set types; it initializes a non-existent numeric attribute to 0 before adding.

### dynamodb-adjacency-list-many-to-many [IN] OBSERVATION
The adjacency list pattern is DynamoDB's recommended approach for modeling many-to-many relationships: partition key holds entity IDs, sort key holds related entity IDs, and a GSI on the sort key enables reverse lookups.

### dynamodb-api-three-categories [IN] OBSERVATION
DynamoDB's low-level API is organized into three categories: table/index management, data CRUD operations, and DynamoDB Streams record processing.

### dynamodb-ats-certificate-migration-december-2017 [IN] OBSERVATION
In December 2017, DynamoDB endpoints migrated to Amazon Trust Services (ATS) certificates for SSL/TLS; legacy clients may need certificate store updates.

### dynamodb-automated-operations-have-dual-cost-and-audit-blind-spots [IN] OBSERVATION
DynamoDB automated operations (TTL deletions) are simultaneously invisible to both cost monitoring (no local WCU consumed, but WCU charged on replicas) and audit logging (no CloudTrail entries for TTL or noop writes) — creating a dual blind spot where the same class of operations evades both financial and security observability.

### dynamodb-autoscaling-8-alarms-per-event [IN] OBSERVATION
A full DynamoDB auto scaling event creates 8 CloudWatch alarms total (4 for read capacity, 4 for write capacity) and 8 AWS Config configuration items.

### dynamodb-autoscaling-default-console-not-cli [IN] OBSERVATION
DynamoDB auto scaling is enabled by default when creating tables via the AWS Management Console, but not when using CLI or SDK.

### dynamodb-autoscaling-delete-table-no-cleanup [IN] OBSERVATION
Deleting a DynamoDB table does not automatically delete associated auto scaling resources (scalable targets, scaling policies, or CloudWatch alarms).

### dynamodb-autoscaling-four-independent-failure-modes [IN] OBSERVATION
DynamoDB auto-scaling has four independent failure modes: a 2-minute reaction delay with request throttling during the breach window, throttling during the capacity change itself, new GSIs not inheriting scaling configuration, and orphaned scaling resources on table deletion — each failure operates independently and can compound during routine operations.

### dynamodb-autoscaling-new-gsi-no-auto-scaling [IN] OBSERVATION
Creating a GSI on an existing DynamoDB table does not auto-enable scaling on the GSI; capacity must be managed manually until the GSI backfill completes and reaches active status.

### dynamodb-autoscaling-scale-up-2-scale-down-15-datapoints [IN] OBSERVATION
DynamoDB auto scaling triggers scale-up after 2 consecutive one-minute data points breaching target utilization, and scale-down after 15 consecutive data points below target.

### dynamodb-autoscaling-target-tracking-only [IN] OBSERVATION
DynamoDB auto-scaling uses target tracking scaling policies exclusively — step scaling is not supported.

### dynamodb-autoscaling-target-utilization-20-to-90 [IN] OBSERVATION
DynamoDB auto scaling target utilization percentage must be between 20% and 90%.

### dynamodb-autoscaling-throttles-during-update [IN] OBSERVATION
During DynamoDB auto scaling capacity changes, requests exceeding the previous provisioned capacity are throttled while the UpdateTable operation takes effect.

### dynamodb-autoscaling-trigger-2min-scaledown-15min [IN] OBSERVATION
DynamoDB auto scaling triggers scale-up after consumed capacity breaches target utilization for 2 consecutive minutes; scale-down requires 15 consecutive data points below target.

### dynamodb-autoscaling-triggers-after-2min-breach [IN] OBSERVATION
DynamoDB auto scaling triggers when consumed capacity breaches the target utilization for two consecutive minutes; recommended target utilization is 70%.

### dynamodb-autoscaling-uses-application-auto-scaling [IN] OBSERVATION
DynamoDB auto scaling is implemented via Application Auto Scaling with target tracking scaling policies, using a dedicated IAM role (`AutoScalingRoleArn`).

### dynamodb-aws-owned-key-free-no-kms-quota [IN] OBSERVATION
DynamoDB AWS owned encryption keys have zero cost and do not count against KMS request quotas.

### dynamodb-backup-billing-spike-1st-normal [IN] OBSERVATION
The DynamoDB `TimedBackupStorage-ByteHrs` metric spike on the 1st of each month is normal behavior — it reflects front-loaded full-month charges for all carried-over backups, which decrease as backups expire or are deleted.

### dynamodb-backup-consistency-window-1-minute [IN] OBSERVATION
DynamoDB on-demand backup consistency window: data committed up to 1 minute before the request is guaranteed included; data committed more than 1 minute after is excluded; data within ~2 minutes of the request may or may not be included (no causal consistency).

### dynamodb-backup-cross-account-requires-same-org [IN] OBSERVATION
AWS Backup cross-account backup/restore for DynamoDB requires both accounts to be in the same AWS Organization.

### dynamodb-backup-encrypted-with-key-at-creation [IN] OBSERVATION
DynamoDB on-demand backups are encrypted with the key that was active when the backup was created; changing the table key does not re-encrypt existing backups, and the original key is needed to restore.

### dynamodb-backup-includes-table-data-indexes-streams-config [IN] OBSERVATION
DynamoDB on-demand backups include table data, GSIs, LSIs, Streams configuration, and provisioned capacity settings.

### dynamodb-backup-tags-not-preserved [IN] OBSERVATION
Tags are not preserved on restored DynamoDB tables — they must be re-added manually after restore.

### dynamodb-batch-execute-http-200-not-full-success [IN] OBSERVATION
DynamoDB `BatchExecuteStatement` HTTP 200 does not guarantee all statements succeeded — individual statement errors must be checked in each `BatchStatementResponse.Error` field.

### dynamodb-batch-execute-select-equality-all-keys [IN] OBSERVATION
DynamoDB `BatchExecuteStatement` SELECT statements must specify equality conditions on all key attributes (partition key + sort key if present), returning at most one item per statement.

### dynamodb-batch-execute-statement-max-25-same-type [IN] OBSERVATION
DynamoDB `BatchExecuteStatement` supports 1–25 PartiQL statements per batch, but all must be the same type (all reads or all writes — no mixing).

### dynamodb-batch-get-item-max-100-items-16mb [IN] OBSERVATION
DynamoDB `BatchGetItem` supports a maximum of 100 items and 16 MB per request; partial results are returned via `UnprocessedKeys` when limits are exceeded.

### dynamodb-batch-get-nonexistent-items-consume-rcu [IN] OBSERVATION
DynamoDB `BatchGetItem` silently omits nonexistent items from results but still consumes minimum read capacity units for each.

### dynamodb-batch-operations-require-dual-defensive-handling [IN] OBSERVATION
DynamoDB batch operations impose both size constraints (25 items per BatchWriteItem, put/delete only) and partial failure semantics (HTTP 200 does not guarantee all statements succeeded) — clients must implement capacity-limit pagination AND per-item error checking simultaneously.

### dynamodb-batch-write-max-25-items-put-delete-only [IN] OBSERVATION
DynamoDB `BatchWriteItem` supports up to 25 put or delete operations per call (max 16 MB total, max 400 KB per item) — it cannot update items and does not support condition expressions.

### dynamodb-batch-write-no-duplicate-keys-in-batch [IN] OBSERVATION
DynamoDB `BatchWriteItem` rejects the entire batch if it contains multiple operations on the same item or two puts with identical hash and range keys.

### dynamodb-batch-write-not-atomic-as-whole [IN] OBSERVATION
DynamoDB `BatchWriteItem` is not atomic as a whole — individual operations are atomic but partial failures are possible; failed operations are returned in `UnprocessedItems` for retry with exponential backoff.

### dynamodb-batchgetitem-rounds-each-item-individually [IN] OBSERVATION
`BatchGetItem` rounds each item individually to the next 4 KB boundary then sums, while `Query` sums all returned items first then rounds the total to 4 KB.

### dynamodb-batchwriteitem-25-items-no-auto-retry [IN] OBSERVATION
DynamoDB BatchWriteItem supports up to 25 items per call and does not include automatic SDK retries — you must handle UnprocessedItems yourself.

### dynamodb-batchwriteitem-25-items-no-update [IN] OBSERVATION
`BatchWriteItem` supports up to 25 `PutItem` and `DeleteItem` requests per call but does not support `UpdateItem`.

### dynamodb-batchwriteitem-puts-deletes-no-updates [IN] OBSERVATION
BatchWriteItem supports PutItem and DeleteItem operations (up to 25 per call) but does not support UpdateItem.

### dynamodb-billing-mode-switch-auto-estimates-capacity [IN] OBSERVATION
When switching DynamoDB billing mode to provisioned, initial capacity values are auto-estimated from the last 30 minutes of consumption.

### dynamodb-billing-modes-provisioned-vs-on-demand [IN] OBSERVATION
DynamoDB has two billing modes: PROVISIONED (specify ReadCapacityUnits/WriteCapacityUnits) and PAY_PER_REQUEST (on-demand, no capacity planning needed); PAY_PER_REQUEST sets capacity units to 0 in the response.

### dynamodb-billingmode-provisioned-or-pay-per-request [IN] OBSERVATION
DynamoDB supports two billing modes: `PAY_PER_REQUEST` (on-demand, recommended for most workloads) and `PROVISIONED` (for steady, predictable workloads); `ProvisionedThroughput` is required for `PROVISIONED` and must not be specified for `PAY_PER_REQUEST`.

### dynamodb-binary-size-raw-bytes-not-base64 [IN] OBSERVATION
DynamoDB binary attribute size is calculated using raw byte length, not the base64-encoded length used for transmission.

### dynamodb-bpa-15-trusted-condition-keys [IN] OBSERVATION
There are 15 trusted condition keys (e.g., `aws:PrincipalAccount`, `aws:SourceVpc`, `aws:PrincipalOrgID`) that can make a `Principal: "*"` DynamoDB resource-based policy non-public; values must not contain wildcards or variables.

### dynamodb-bpa-blocks-public-resource-policies [IN] OBSERVATION
DynamoDB Block Public Access (BPA) uses automated reasoning to analyze resource-based policies at creation/modification time and blocks policies that would grant public access to tables, indexes, or streams.

### dynamodb-bpa-does-not-cover-identity-policies [IN] OBSERVATION
DynamoDB BPA only analyzes resource-based policies directly attached to DynamoDB resources — it does not cover identity-based policies or policies on associated resources like KMS keys.

### dynamodb-bulk-data-round-trip-requires-table-recreation [IN] OBSERVATION
DynamoDB bulk data operations have an asymmetric round-trip: export to S3 efficiently extracts data without consuming table capacity, but import from S3 can only create new tables — bulk transformation workflows (export → process → reload) require full table recreation with re-provisioning of all settings rather than in-place updates.

### dynamodb-cannot-delete-source-table-within-24h-of-replica-creation [IN] OBSERVATION
A DynamoDB source table used to create a global table replica cannot be deleted until 24 hours after creation.

### dynamodb-capacity-billing-has-hidden-overhead-multipliers [IN] OBSERVATION
DynamoDB capacity billing includes hidden overhead beyond raw item size: 100 bytes of indexing overhead per item, rounding up to 4 KB for reads and 1 KB for writes, and a minimum 200-byte storage cost per GSI-projected item — small items pay disproportionately more per byte than large items.

### dynamodb-capacity-billing-penalizes-small-items-disproportionately [IN] OBSERVATION
DynamoDB capacity billing includes three hidden overhead mechanisms beyond raw item size: 100 bytes of indexing overhead per item, rounding up to 4 KB for reads and 1 KB for writes, and a minimum 200-byte storage cost per GSI-projected item — collectively making small-item workloads (e.g., IoT telemetry, session tokens) pay dramatically more per byte than large-item workloads.

### dynamodb-capacity-metrics-1min-others-5min [IN] OBSERVATION
DynamoDB capacity consumption metrics are aggregated at 1-minute intervals; most other DynamoDB CloudWatch metrics are aggregated at 5-minute intervals.

### dynamodb-capacity-mode-switch-limit-4-per-24h [IN] OBSERVATION
DynamoDB tables can switch from provisioned to on-demand capacity mode up to 4 times per 24-hour rolling window; switching from on-demand to provisioned has no limit.

### dynamodb-capacity-pre-warming-survives-mode-transitions [IN] OBSERVATION
DynamoDB has two independent capacity memory mechanisms — pre-warming survives capacity mode changes without requiring a mode switch, and on-demand mode remembers historical peak provisioned capacity even after capacity reductions — making capacity transitions less disruptive than expected.

### dynamodb-cdc-fragile-across-both-streams-and-kinesis-paths [IN] OBSERVATION
Both DynamoDB CDC paths are independently fragile: Streams requires a multi-step client protocol with expiring iterators and rate limits, while Kinesis has four independent reliability hazards (out-of-order, duplication, 1MB skip, 168-hour auto-disable) — no CDC path offers inherently reliable change data capture.

### dynamodb-cdc-not-on-views [IN] OBSERVATION
Change Data Capture (CDC) does not work on SQL VIEWs — online migrations combining relational tables into DynamoDB require a physical staging table with triggers or stored procedures.

### dynamodb-cdc-unit-1kb-larger-image [IN] OBSERVATION
DynamoDB change data capture billing uses 1 KB change data capture units, sized from the larger of the before/after item images, with no provisioned throughput required.

### dynamodb-cfn-no-drift-detection-resource-policies [IN] OBSERVATION
CloudFormation does not detect drift on DynamoDB resource-based policies and does not reconcile out-of-band policy changes unless the template itself contains a policy change.

### dynamodb-cfn-table-to-globaltable-type-change-deletes [IN] OBSERVATION
Changing a CloudFormation resource type from `AWS::DynamoDB::Table` to `AWS::DynamoDB::GlobalTable` can delete the table — a safe migration requires Retain deletion policy, stack removal, console conversion, then import.

### dynamodb-client-complexity-compounds-across-pagination-and-filtering [IN] OBSERVATION
DynamoDB clients must simultaneously implement defensive multi-page iteration (checking LastEvaluatedKey, handling parallel scan segments) AND capacity-aware query design (avoiding post-read filtering), with filter expressions reducing useful items per page while consuming the same RCU per page.

### dynamodb-cloudtrail-audits-control-and-data-plane [IN] OBSERVATION
CloudTrail can audit both DynamoDB control plane and data plane operations.

### dynamodb-cloudtrail-table-resource-type-includes-streams [IN] OBSERVATION
When filtering DynamoDB data plane events by resource type `AWS::DynamoDB::Table`, CloudTrail logs both table and stream events for tables with streams enabled; use `AWS::DynamoDB::Stream` to capture only stream API calls.

### dynamodb-cmk-disabled-streams-24h-ttl-30m [IN] OBSERVATION
When a DynamoDB CMK is disabled, streams data has a 24-hour lifetime and TTL deletes continue for 30 minutes.

### dynamodb-cmk-inaccessible-7-day-archive [IN] OBSERVATION
If a DynamoDB customer managed key is disabled or scheduled for deletion, the table becomes inaccessible; after 7 days, DynamoDB creates an on-demand backup and archives the table.

### dynamodb-cmk-not-supported-global-table-v2017 [IN] OBSERVATION
Customer managed KMS keys are not supported on DynamoDB Global Table Version 2017 — must use Version 2019 or later.

### dynamodb-cmk-not-supported-with-dax [IN] OBSERVATION
Customer managed KMS keys cannot be used with DynamoDB Accelerator (DAX) clusters.

### dynamodb-complex-graph-queries-use-neptune [IN] OBSERVATION
For real-time multi-hop queries, complex edge traversals, or second/third-level relationship aggregations, Amazon Neptune should be used instead of DynamoDB.

### dynamodb-composite-sort-key-delimiter-hierarchy [IN] OBSERVATION
DynamoDB composite sort keys use a delimiter-separated structure (e.g., `[country]#[region]#[state]#[county]#[city]#[neighborhood]`) to define hierarchical relationships queryable at any level via `begins_with`.

### dynamodb-compressed-attributes-binary-no-filter [IN] OBSERVATION
Compressed DynamoDB attributes are stored as Binary type and cannot be used for filtering.

### dynamodb-concurrent-table-operations-limit-500 [IN] OBSERVATION
DynamoDB has a 500 concurrent table operations limit shared across `CreateTable`, `UpdateTable`, `DeleteTable`, `UpdateTimeToLive`, `RestoreTableFromBackup`, and `RestoreTableToPointInTime` (reduced to 250 when creating tables with secondary indexes).

### dynamodb-conditional-check-failed-exception [IN] OBSERVATION
A failed condition expression on PutItem, UpdateItem, or DeleteItem throws `ConditionalCheckFailedException`.

### dynamodb-conditional-check-failed-not-user-errors [IN] OBSERVATION
DynamoDB ConditionalCheckFailedRequests return HTTP 400 but are NOT counted in the UserErrors CloudWatch metric.

### dynamodb-conditioncheck-read-only-validation [IN] OBSERVATION
ConditionCheck is a read-only action within TransactWriteItems that validates a condition without modifying data — used to assert preconditions in a transaction.

### dynamodb-conditioncheckitem-only-transaction-specific-action [IN] OBSERVATION
`dynamodb:ConditionCheckItem` is the only transaction-specific IAM action in DynamoDB.

### dynamodb-consistency-mode-immutable-after-creation [IN] OBSERVATION
DynamoDB global table consistency mode (MREC or MRSC) cannot be changed after table creation; modes cannot be mixed within a table.

### dynamodb-console-deletes-autoscaling-on-demand-switch [IN] OBSERVATION
When switching a DynamoDB table to on-demand mode via the console, auto scaling settings are deleted; switching via CLI/SDK preserves them.

### dynamodb-console-to-code-output-formats [IN] OBSERVATION
Console-to-Code generates CDK (TypeScript, Python, Java) and CloudFormation (YAML, JSON) templates from DynamoDB console actions.

### dynamodb-consumed-capacity-use-sum-divide-60 [IN] OBSERVATION
For DynamoDB ConsumedReadCapacityUnits and ConsumedWriteCapacityUnits, Sum is the most useful statistic — divide Sum by 60 to get per-second average; Average is skewed by periods of inactivity.

### dynamodb-contains-filter-only-not-key-condition [IN] OBSERVATION
The `contains` function is available only in DynamoDB filter expressions, not in key condition expressions; `begins_with` is available in both.

### dynamodb-continuous-backups-always-enabled [IN] OBSERVATION
Continuous backups are enabled on all DynamoDB tables at creation automatically and cannot be disabled; only PITR is an optional separate setting.

### dynamodb-contributor-insights-exposes-keys-plaintext [IN] OBSERVATION
DynamoDB Contributor Insights displays partition and sort key values in plaintext — it should not be enabled on tables where KMS encryption of key data is required.

### dynamodb-contributor-insights-identifies-hot-throttled-keys [IN] OBSERVATION
DynamoDB Contributor Insights integrates with CloudWatch Contributor Insights to identify the most accessed or throttled partition keys in a table or GSI, with two modes: `ACCESSED_AND_THROTTLED_KEYS` and `THROTTLED_KEYS`.

### dynamodb-contributor-insights-per-table-and-gsi [IN] OBSERVATION
DynamoDB Contributor Insights tracks hot keys independently for both the base table and each global secondary index.

### dynamodb-contributor-insights-two-modes [IN] OBSERVATION
DynamoDB Contributor Insights has two tracking modes: `ACCESSED_AND_THROTTLED_KEYS` (all access plus throttles) and `THROTTLED_KEYS` (throttled events only); it can target a table or a specific GSI.

### dynamodb-contributor-insights-uses-cloudwatch [IN] OBSERVATION
DynamoDB Contributor Insights uses CloudWatch Contributor Insights rules under the hood to identify the most accessed (hot) keys and items.

### dynamodb-control-plane-cache-results [IN] OBSERVATION
DynamoDB best practice: cache control plane results (e.g., DescribeTable) rather than polling repeatedly, and do not mix control plane and data plane calls in the same code path.

### dynamodb-control-plane-logged-by-default [IN] OBSERVATION
DynamoDB control plane events (CreateTable, DeleteTable, UpdateTable) are logged by CloudTrail by default; data plane events (GetItem, PutItem, Query, Scan) require explicit enablement.

### dynamodb-control-plane-throttle-2500-rps [IN] OBSERVATION
DynamoDB enforces a control plane throttle limit of 2,500 requests per second.

### dynamodb-control-plane-throttled-across-three-independent-dimensions [IN] OBSERVATION
DynamoDB control plane enforces three independent throttle limits — 2,500 RPS general, 500 TPS cross-account, and 500 simultaneous table operations — that compound in multi-account architectures managing large table estates.

### dynamodb-cost-compounds-across-three-independent-dimensions [IN] OBSERVATION
DynamoDB costs multiply across three independent dimensions — consistency choice (4x between eventual and transactional), query efficiency (wasted RCU from filter expressions on unindexed access patterns), and extraction method (scan vs export for analytics) — and optimizing only one dimension leaves the other multipliers in place.

### dynamodb-cost-model-adversarial-to-resilience-best-practices [IN] OBSERVATION
DynamoDB's cost optimization mechanism (reserved capacity) is structurally incompatible with its resilience mechanism (global tables/on-demand), while costs simultaneously compound across three independent dimensions (consistency, query efficiency, extraction method) — the cost model actively penalizes the architectures recommended for production resilience.

### dynamodb-cost-multiplicative-and-structurally-unoptimizable [IN] OBSERVATION
DynamoDB cost compounds across multiple dimensions (consistency, transactions, GSI projections, small item overhead) and the primary optimization path — reserved capacity — is unavailable in on-demand mode, limiting cost management options for on-demand workloads.

### dynamodb-cost-optimization-incompatible-with-global-availability [IN] OBSERVATION
DynamoDB's primary cost optimization mechanism (reserved capacity) is structurally incompatible with its primary availability mechanism (global tables) — reserved capacity excludes replicated write capacity units, on-demand mode, and Standard-IA, while global tables charge rWCUs in every replica region, making the dominant write cost in multi-region architectures ineligible for reservation discounts.

### dynamodb-create-table-policy-no-consistency-delay [IN] OBSERVATION
Resource-based policies attached via `CreateTable` are guaranteed to apply to all requests immediately with no eventual consistency delay for authorization.

### dynamodb-createbackup-rate-limit-50-per-second [IN] OBSERVATION
The DynamoDB `CreateBackup` API is rate-limited to 50 calls per second.

### dynamodb-createtable-async-poll-describetable [IN] OBSERVATION
DynamoDB `CreateTable` is asynchronous — it returns immediately with `TableStatus: CREATING` and the table is usable only when status reaches `ACTIVE`; poll with `DescribeTable`.

### dynamodb-cross-account-billing-audit-asymmetry [IN] OBSERVATION
DynamoDB cross-account operations create a billing-audit asymmetry: the resource owner pays for all operations (including those initiated by other accounts) while CloudTrail logs appear in both accounts — billing responsibility concentrates on the resource owner but audit visibility is distributed

### dynamodb-cross-account-cloudtrail-both-accounts [IN] OBSERVATION
DynamoDB cross-account requests are logged in CloudTrail in both the resource owner's and the requestor's accounts.

### dynamodb-cross-account-control-plane-500-tps [IN] OBSERVATION
Cross-account access of DynamoDB control plane APIs has a lower TPS limit of 500 requests per second.

### dynamodb-cross-account-lambda-stream-four-actions [IN] OBSERVATION
Cross-account Lambda triggers on DynamoDB Streams require four stream actions in the resource-based policy: `DescribeStream`, `GetRecords`, `GetShardIterator`, and `ListShards`.

### dynamodb-cross-account-migration-two-methods [IN] OBSERVATION
DynamoDB tables can be migrated between AWS accounts using two methods: AWS Backup cross-account backup/restore, and DynamoDB Export/Import via S3.

### dynamodb-cross-account-requires-customer-managed-kms [IN] OBSERVATION
Cross-account access to DynamoDB tables via resource-based policies does not work with AWS managed KMS keys — customer-managed KMS keys are required because AWS managed key policies cannot grant cross-account access.

### dynamodb-cross-account-requires-full-table-arn [IN] OBSERVATION
DynamoDB cross-account API calls require the full table ARN in the `TableName` parameter; if only a table name is provided, the operation targets the caller's own account.

### dynamodb-cross-account-resource-owner-pays [IN] OBSERVATION
The resource owner's account is billed for all DynamoDB operations, including those from cross-account principals.

### dynamodb-csv-empty-columns-omitted [IN] OBSERVATION
Empty CSV columns in DynamoDB imports are omitted from the item entirely, not stored as empty strings.

### dynamodb-csv-import-non-key-columns-as-strings [IN] OBSERVATION
CSV imports into DynamoDB store all non-key, non-index columns as DynamoDB strings — no automatic type inference for numbers, booleans, or other types.

### dynamodb-cur-no-region-prefix-means-us-east-1 [IN] OBSERVATION
In AWS Cost and Usage Reports, an absent region prefix in DynamoDB UsageType codes means `us-east-1`.

### dynamodb-dax-cloudwatch-backup-separate-product-codes [IN] OBSERVATION
DAX charges appear under `AmazonDAX`, CloudWatch Contributor Insights under `AmazonCloudWatch`, and managed backups under `AWSBackup` — not under the `AmazonDynamoDB` product code in CUR.

### dynamodb-dax-ipv6-resource-policy-exemption [IN] OBSERVATION
In IPv6-only environments with IP-based DynamoDB resource policies, an `ArnNotEquals` condition must exempt the DAX cluster's IAM role.

### dynamodb-dax-microsecond-latency [IN] OBSERVATION
DynamoDB Accelerator (DAX) provides microsecond response times, up to 10x improvement over base DynamoDB single-digit millisecond latency.

### dynamodb-default-20-gsi-5-lsi-per-table [IN] OBSERVATION
DynamoDB defaults to a maximum of 20 GSIs (adjustable) and 5 LSIs (hard limit) per table.

### dynamodb-default-encryption-aws-owned-cmk [IN] OBSERVATION
DynamoDB tables are encrypted at rest by default using an AWS-owned CMK at no extra charge; customer-managed KMS keys can optionally be specified via `--sse-specification`.

### dynamodb-default-provisioned-quota-20000-rcu-wcu [IN] OBSERVATION
DynamoDB default provisioned capacity quotas are 20,000 RCU/WCU at the account level and 10,000 RCU/WCU per table per Region.

### dynamodb-default-table-throughput-limit-40k [IN] OBSERVATION
DynamoDB's default table-level throughput limit is 40,000 RCUs and 40,000 WCUs per table (can request increase).

### dynamodb-delete-resource-policy-api [IN] OBSERVATION
The `DeleteResourcePolicy` API removes a resource-based policy from a DynamoDB table; the only required parameter is `--resource-arn`.

### dynamodb-delete-resource-policy-async [IN] OBSERVATION
`DeleteResourcePolicy` is asynchronous — a `GetResourcePolicy` call immediately after deletion may still return the old policy.

### dynamodb-delete-resource-policy-idempotent [IN] OBSERVATION
`DeleteResourcePolicy` is idempotent — repeated calls on the same resource produce no error unless `ExpectedRevisionId` is specified.

### dynamodb-delete-table-async-deleting-status [IN] OBSERVATION
DynamoDB table deletion is asynchronous — the `DeleteTable` API returns immediately with `TableStatus: "DELETING"`.

### dynamodb-delete-table-cli-only-requires-table-name [IN] OBSERVATION
The `aws dynamodb delete-table` CLI command only requires `--table-name` as a parameter.

### dynamodb-delete-table-irreversible [IN] OBSERVATION
DynamoDB DeleteTable is irreversible — there is no undo or recovery mechanism.

### dynamodb-delete-table-removes-all-data-permanently [IN] OBSERVATION
Deleting a DynamoDB table removes the table and all of its data permanently; the operation is irreversible.

### dynamodb-delete-table-requires-active-state [IN] OBSERVATION
A DynamoDB table must be in `ACTIVE` state to be deleted; tables in `CREATING` or `UPDATING` state return `ResourceInUseException`.

### dynamodb-deletebackup-rate-limit-10-per-second [IN] OBSERVATION
The DynamoDB `DeleteBackup` API is rate-limited to 10 calls per second.

### dynamodb-deleteitem-idempotent-without-conditions [IN] OBSERVATION
DynamoDB `DeleteItem` is idempotent without conditions — deleting a non-existent item succeeds silently without error.

### dynamodb-deleteitem-returnvalues-none-or-all-old-only [IN] OBSERVATION
DynamoDB `DeleteItem` only supports `NONE` and `ALL_OLD` for `ReturnValues`; returning old values does not consume additional read capacity units.

### dynamodb-deletion-protection-enabled-setting [IN] OBSERVATION
DynamoDB tables have a `DeletionProtectionEnabled` boolean setting that safeguards against accidental table deletion.

### dynamodb-deletion-protection-off-by-default [IN] OBSERVATION
DynamoDB deletion protection is off by default for all tables, including global replicas and restored tables; when enabled, no one can delete the table regardless of IAM permissions.

### dynamodb-deletion-protection-toggle [IN] OBSERVATION
DynamoDB `DeletionProtectionEnabled` is a table-level toggle set via `UpdateTable` that prevents accidental table deletion.

### dynamodb-denormalization-eliminates-joins [IN] OBSERVATION
DynamoDB's core modeling principle is denormalization to eliminate JOINs, storing data so queries are answered in a single request with constant runtime complexity regardless of data size.

### dynamodb-describe-backup-rate-limit-10-per-second [IN] OBSERVATION
The DynamoDB `DescribeBackup` API is rate-limited to 10 calls per second.

### dynamodb-describe-endpoints-no-parameters [IN] OBSERVATION
The DynamoDB `DescribeEndpoints` API takes no input parameters and returns regional endpoint information including address and cache duration.

### dynamodb-describe-kinesis-streaming-table-scoped [IN] OBSERVATION
The `DescribeKinesisStreamingDestination` API is table-scoped — it queries one table at a time and requires only `TableName` (or table ARN) as input.

### dynamodb-describe-table-eventually-consistent [IN] OBSERVATION
DynamoDB DescribeTable is eventually consistent and may throw ResourceNotFoundException immediately after CreateTable.

### dynamodb-describelimits-four-values [IN] OBSERVATION
`DescribeLimits` returns four values: `AccountMaxReadCapacityUnits`, `AccountMaxWriteCapacityUnits`, `TableMaxReadCapacityUnits`, and `TableMaxWriteCapacityUnits`.

### dynamodb-describelimits-throttle-once-per-minute [IN] OBSERVATION
`DescribeLimits` should be called at most once per minute; more frequent calls will be throttled.

### dynamodb-describetable-eventually-consistent [IN] OBSERVATION
`DescribeTable` is eventually consistent — calling it immediately after `CreateTable` may throw `ResourceNotFoundException`; retry after a few seconds.

### dynamodb-design-philosophy-inverts-rdbms-normalization [IN] OBSERVATION
DynamoDB's core design philosophy is the inverse of RDBMS: start from access patterns (not entities), denormalize to eliminate joins, and optimize for locality of reference — violating any one principle (normalizing data, designing schema-first, or scattering related items) undermines the entire model.

### dynamodb-disable-kinesis-streaming-preserves-resources [IN] OBSERVATION
DisableKinesisStreamingDestination stops replication from a DynamoDB table to a Kinesis Data Stream without deleting either resource.

### dynamodb-dual-stack-endpoints-use-api-aws-domain [IN] OBSERVATION
DynamoDB dual-stack endpoints (IPv4/IPv6) use the `api.aws` domain suffix (e.g., `dynamodb.<region>.api.aws`), not `amazonaws.com`.

### dynamodb-eight-cost-optimization-dimensions [IN] OBSERVATION
DynamoDB has eight cost optimization dimensions: table-level cost analysis, capacity mode, auto scaling settings, table class selection, unused resources, usage patterns, streams usage, and right-sized provisioning.

### dynamodb-encryption-aes-256 [IN] OBSERVATION
DynamoDB encryption at rest uses AES-256 encryption standard with envelope encryption via AWS KMS key hierarchy.

### dynamodb-encryption-at-rest-always-enabled [IN] OBSERVATION
DynamoDB encryption at rest is always enabled and cannot be disabled — you choose which key type, not whether to encrypt.

### dynamodb-encryption-at-rest-always-on [IN] OBSERVATION
DynamoDB encryption at rest is always enabled and cannot be disabled; you can only choose between AWS owned key (free), AWS managed key, or customer managed key.

### dynamodb-encryption-at-rest-default-aws-owned-key [IN] OBSERVATION
DynamoDB encryption at rest is enabled by default using AWS-owned keys at no extra charge; also supports AWS managed keys and customer managed KMS keys.

### dynamodb-encryption-context-table-name-account-id [IN] OBSERVATION
DynamoDB encryption context includes `aws:dynamodb:tableName` (table name) and `aws:dynamodb:subscriberId` (account ID), usable for audit and policy conditions.

### dynamodb-encryption-defense-in-depth-with-zero-cost-baseline [IN] OBSERVATION
DynamoDB encryption provides defense-in-depth with a zero-cost baseline: AWS owned keys are free with no KMS quota impact, customer-managed keys add audit trails via encryption context (table name + account ID), and KMS key caching with 5-minute refresh limits operational overhead.

### dynamodb-encryption-key-switchable-no-downtime [IN] OBSERVATION
DynamoDB encryption key type can be changed on existing tables at any time with no downtime or service degradation.

### dynamodb-encryption-key-type-switchable-anytime [IN] OBSERVATION
DynamoDB allows switching between encryption key types (AWS owned, AWS managed, customer managed) at any time on an existing table without downtime or code changes.

### dynamodb-endpoint-cache-period-in-minutes [IN] OBSERVATION
DynamoDB `DescribeEndpoints` returns a `CachePeriodInMinutes` field (e.g., 1440) indicating how long clients should cache the endpoint before re-querying.

### dynamodb-event-processing-simultaneously-constrained-and-unreliable [IN] OBSERVATION
DynamoDB event processing faces simultaneous capacity and reliability failures: stream fan-out is constrained by ordering requirements (parent-before-child) and consumer limits (max 2 Lambda consumers), while Kinesis CDC pipelines independently face four reliability hazards (out-of-order, duplication, size limits, auto-disable) — addressing capacity constraints by moving to Kinesis introduces reliability hazards, and neither path is sufficient alone.

### dynamodb-eventually-consistent-reads-half-cost [IN] OBSERVATION
DynamoDB eventually consistent reads consume half the RCUs of strongly consistent reads.

### dynamodb-executestatement-singleton-writes-only [IN] OBSERVATION
DynamoDB ExecuteStatement supports reads and singleton writes only (one item at a time); use BatchExecuteStatement for batch operations.

### dynamodb-executetransaction-max-100-statements [IN] OBSERVATION
DynamoDB ExecuteTransaction supports a maximum of 100 PartiQL statements per transaction, and all statements must be either reads or writes (cannot mix).

### dynamodb-export-billed-size-and-item-count [IN] OBSERVATION
DynamoDB export metadata includes both `BilledSizeBytes` (what you pay for) and `ItemCount` as separate metrics.

### dynamodb-export-cross-account-requires-s3bucketowner [IN] OBSERVATION
DynamoDB cross-account exports to S3 require the S3BucketOwner parameter (12-digit account ID).

### dynamodb-export-formats-dynamodb-json-and-ion [IN] OBSERVATION
DynamoDB table exports support two formats: DYNAMODB_JSON and ION, with two export types: FULL_EXPORT (default) and INCREMENTAL_EXPORT.

### dynamodb-export-kms-key-same-region-as-s3 [IN] OBSERVATION
When using KMS encryption for DynamoDB exports, the KMS key must be in the same Region as the destination S3 bucket.

### dynamodb-export-limit-500-tables-50-imports [IN] OBSERVATION
DynamoDB `LimitExceededException` covers: up to 500 simultaneous table operations, 250 with secondary indexes, 50 simultaneous imports, and a soft limit of 2,500 tables.

### dynamodb-export-metadata-retained-90-days [IN] OBSERVATION
DynamoDB export task metadata is retained for 90 days; S3 objects persist according to bucket policies and are never deleted by DynamoDB.

### dynamodb-export-no-requester-pays-buckets [IN] OBSERVATION
DynamoDB exports to S3 do not support requester pays buckets as the destination.

### dynamodb-export-no-table-read-capacity-consumed [IN] OBSERVATION
DynamoDB ExportTableToPointInTime does not consume table read capacity — it works from PITR snapshots.

### dynamodb-export-not-found-returns-400 [IN] OBSERVATION
DynamoDB `ExportNotFoundException` returns HTTP 400 (client error), not 404.

### dynamodb-export-not-transactionally-consistent [IN] OBSERVATION
DynamoDB exports to S3 are not transactionally consistent (transactions can be torn across exports), but contiguous exports are eventually consistent and capture all changes without duplicates.

### dynamodb-export-preferred-over-scan-for-analytics [IN] OBSERVATION
DynamoDB export to S3 is strictly superior to Scan for bulk data extraction — exports consume zero table read capacity while scans consume RCUs for full 1 MB pages including filtered items.

### dynamodb-export-requires-pitr-enabled [IN] OBSERVATION
DynamoDB ExportTableToPointInTime requires Point-in-Time Recovery (PITR) to be enabled on the source table; otherwise PointInTimeRecoveryUnavailableException is thrown.

### dynamodb-export-two-formats-json-ion [IN] OBSERVATION
DynamoDB table exports to S3 support two formats: DynamoDB JSON and Amazon Ion; both are gzip-compressed and use newline-delimited items.

### dynamodb-export-uses-pitr-no-read-capacity [IN] OBSERVATION
ExportTableToPointInTime exports DynamoDB data to S3 without consuming read capacity units — it uses PITR snapshots.

### dynamodb-failed-conditional-writes-consume-wcus [IN] OBSERVATION
DynamoDB conditional writes that fail (condition evaluates to false) still consume WCUs based on the larger of the existing or new item size.

### dynamodb-fgac-attribute-level-condition-keys [IN] OBSERVATION
DynamoDB supports attribute-level access control using the `dynamodb:Attributes` condition key with `ForAllValues:StringEquals` to restrict which attributes can be read or written, and `dynamodb:Select` set to `SPECIFIC_ATTRIBUTES` to prevent leaking disallowed attributes through index projections.

### dynamodb-fgac-attributes-checks-request-not-response [IN] OBSERVATION
The `dynamodb:Attributes` IAM condition key evaluates only request parameters (e.g., ProjectionExpression), not response attributes — omitting ProjectionExpression returns all attributes regardless of the policy.

### dynamodb-fgac-incompatible-global-tables-replication [IN] OBSERVATION
DynamoDB fine-grained access control conditions must not be applied to global tables replication service-linked roles, as it may break replication.

### dynamodb-fgac-leadingkeys-requires-forallvalues [IN] OBSERVATION
The `dynamodb:LeadingKeys` IAM condition key requires the `ForAllValues` set operator even for single-item actions.

### dynamodb-fgac-putitem-deleteitem-bypass-attribute-restrictions [IN] OBSERVATION
`PutItem` and `DeleteItem` replace entire items, so they bypass attribute-level restrictions — `UpdateItem` should be used instead for attribute-restricted writes.

### dynamodb-fgac-three-conditions-for-attribute-security [IN] OBSERVATION
To properly restrict DynamoDB attribute-level access, you must combine all three condition keys: `dynamodb:Attributes`, `dynamodb:Select`, and `dynamodb:ReturnValues`.

### dynamodb-filter-cannot-contain-key-attributes [IN] OBSERVATION
DynamoDB filter expressions cannot contain partition key or sort key attributes — those must be specified in the key condition expression.

### dynamodb-filter-expression-does-not-reduce-capacity [IN] OBSERVATION
DynamoDB filter expressions are applied after the read operation completes, so they do not reduce read capacity consumption.

### dynamodb-filter-expression-does-not-reduce-consumed-capacity [IN] OBSERVATION
Filter expressions are applied after items are read and do not reduce ScannedCount or ConsumedCapacity.

### dynamodb-filter-expression-does-not-reduce-rcu [IN] OBSERVATION
DynamoDB filter expressions are applied after the Query completes and do not reduce read capacity unit (RCU) consumption — you pay for all items read regardless of filtering.

### dynamodb-filter-expressions-waste-capacity-on-filtered-items [IN] OBSERVATION
DynamoDB queries using filter expressions pay full RCU cost for all scanned data (up to 1 MB per page) even when most items are filtered out post-read.

### dynamodb-free-tier-25gb-25rcu-25wcu-always-free [IN] OBSERVATION
DynamoDB free tier includes 25 GB storage + 25 RCU/25 WCU (~200M requests/month) and is always free (not 12-month limited).

### dynamodb-free-tier-25gb-25wcu-25rcu [IN] OBSERVATION
DynamoDB AWS Free Tier includes 25 GB storage, 25 WCU, and 25 RCU of provisioned capacity.

### dynamodb-full-access-arn [IN] OBSERVATION
The ARN for the AmazonDynamoDBFullAccess managed policy is `arn:aws:iam::aws:policy/AmazonDynamoDBFullAccess`.

### dynamodb-full-access-excludes-s3-glue-export-import [IN] OBSERVATION
The `AmazonDynamoDBFullAccess` policy does not include S3, Glue, or other export/import-related permissions — features like Export to S3 or Import from S3 require separate grants.

### dynamodb-full-access-iam-passrole-condition-restricted [IN] OBSERVATION
The `AmazonDynamoDBFullAccess` policy restricts `iam:PassRole` with the `iam:PassedToService` condition, allowing roles to be passed only to `application-autoscaling.amazonaws.com` and `dax.amazonaws.com`.

### dynamodb-full-access-policy-includes-cross-service-permissions [IN] OBSERVATION
The `AmazonDynamoDBFullAccess` managed policy grants permissions beyond DynamoDB — it includes `dax:*`, Application Auto Scaling, CloudWatch, Data Pipeline, EC2 (VPC describe), IAM (read roles), KMS, SNS, Lambda, Resource Groups, Tagging, and Kinesis.

### dynamodb-gateway-free-interface-billed [IN] OBSERVATION
DynamoDB gateway VPC endpoints are free but don't support on-premises or cross-region access; interface endpoints are billed but support both — both can coexist in the same VPC.

### dynamodb-getitem-eventually-consistent-by-default [IN] OBSERVATION
GetItem defaults to eventually consistent reads (0.5 RCU for items ≤ 4 KB); use `--consistent-read` for strongly consistent reads (1.0 RCU for items ≤ 4 KB).

### dynamodb-getitem-eventually-consistent-default [IN] OBSERVATION
DynamoDB `GetItem` defaults to eventually consistent reads; set `ConsistentRead: true` for strongly consistent reads.

### dynamodb-getitem-missing-item-not-error [IN] OBSERVATION
When `GetItem` finds no matching item, the HTTP response is still 200 but the `Item` element is omitted — it is not an error.

### dynamodb-getitem-no-secondary-index-access [IN] OBSERVATION
`GetItem` does not access secondary indexes — specifying `INDEXES` for `ReturnConsumedCapacity` still only returns table-level capacity.

### dynamodb-getitem-rcu-cost [IN] OBSERVATION
A strongly consistent `GetItem` read consumes 1 RCU per 4 KB; an eventually consistent read consumes 0.5 RCU per 4 KB.

### dynamodb-getitem-requires-full-primary-key [IN] OBSERVATION
`GetItem` requires all primary key components — partition key alone for simple keys, both partition key and sort key for composite keys; omitting the sort key is an error.

### dynamodb-getitem-returns-empty-if-not-found [IN] OBSERVATION
If no matching item exists, GetItem returns an empty result — no error is thrown.

### dynamodb-global-table-99999-availability-sla [IN] OBSERVATION
DynamoDB global tables offer 99.999% availability SLA (five nines) compared to 99.99% for single-Region tables.

### dynamodb-global-table-cfn-single-stack-all-replicas [IN] OBSERVATION
All DynamoDB global table replicas must be defined in a single Region's CloudFormation stack; using separate Regional stacks causes drift errors.

### dynamodb-global-table-cmk-inaccessible-20-hours [IN] OBSERVATION
DynamoDB global table replicas are removed from the replication group after 20 hours of inaccessible CMK.

### dynamodb-global-table-deletion-protection-per-replica [IN] OBSERVATION
DynamoDB global table deletion protection must be enabled individually on each replica — it is not inherited across replicas.

### dynamodb-global-table-equal-write-capacity-without-autoscaling [IN] OBSERVATION
For DynamoDB global tables without auto scaling, equal replicated write capacity units must be provisioned across all replicas and matching secondary indexes.

### dynamodb-global-table-gsi-updates-use-standard-write-units [IN] OBSERVATION
GSI updates on DynamoDB global table replicas are always billed as standard WRUs/WCUs, not replicated write units (rWRUs/rWCUs).

### dynamodb-global-table-not-found-returns-400 [IN] OBSERVATION
DynamoDB `GlobalTableNotFoundException` returns HTTP 400 (client error), not 404.

### dynamodb-global-table-one-replica-per-region [IN] OBSERVATION
Only one replica per AWS Region is allowed in a DynamoDB global table.

### dynamodb-global-table-per-replica-read-capacity-override [IN] OBSERVATION
DynamoDB global tables allow per-replica throughput overrides, enabling different read capacity settings in each region.

### dynamodb-global-table-replication-sub-second [IN] OBSERVATION
DynamoDB Global Tables replicate changes across regions typically within one second using eventual consistency.

### dynamodb-global-table-requires-streams-new-and-old-images [IN] OBSERVATION
DynamoDB global tables require DynamoDB Streams enabled with both new and old images on all replica tables.

### dynamodb-global-table-resource-policies-per-replica [IN] OBSERVATION
For DynamoDB Global Tables, resource-based policies are configured per-replica (each replica region can have its own policy), not globally across all replicas.

### dynamodb-global-table-rwcu-gsi-standard-wcu [IN] OBSERVATION
DynamoDB global table writes use replicated write units (rWCU for provisioned, rWRU for on-demand), but GSI writes on global tables use standard WCU/WRU.

### dynamodb-global-table-security-governance-fragmented-by-design [IN] OBSERVATION
DynamoDB global table security governance is fragmented by design: resource-based policies must be independently configured per replica region AND fine-grained access control conditions must explicitly exclude replication service-linked roles — security administration scales linearly with replica count and carries replication-specific exclusion requirements that are easy to miss.

### dynamodb-global-table-small-item-cost-triply-penalized [IN] OBSERVATION
DynamoDB global tables with small items face compounding cost penalties across three independent dimensions: per-item overhead is disproportionately large relative to item size, writes replicate to every region multiplying cost, and transactional writes double it again.

### dynamodb-global-table-version-2019-current [IN] OBSERVATION
DynamoDB global tables have two versions: 2019.11.21 (Current) and 2017.11.29 (Legacy); the Current version should always be used.

### dynamodb-global-table-warm-throughput-propagates [IN] OBSERVATION
For DynamoDB global tables (version 2019.11.21/Current), warm throughput settings automatically propagate to all replicas.

### dynamodb-global-table-witness-replicas-free [IN] OBSERVATION
Witness replicas in DynamoDB global tables (MRSC mode) do not incur replicated write unit costs, storage costs, or data transfer costs.

### dynamodb-global-table-write-costs-multiply-across-regions-and-transactions [IN] OBSERVATION
DynamoDB global table write costs are subject to triple multiplication: replicated write units charge in every replica region, transactions double the per-item cost, and GSI writes on global tables use standard (non-replicated) WCUs billed separately — making global transactional workloads with GSIs dramatically more expensive than single-region equivalents.

### dynamodb-global-table-write-global-read-per-replica [IN] OBSERVATION
In DynamoDB Global Tables (legacy 2017.11.29), write capacity is set globally across all replicas while read capacity is configured per-replica — an asymmetric design.

### dynamodb-global-table-writes-charged-every-replica-region [IN] OBSERVATION
Writes to DynamoDB global tables are charged in every region containing a replica using replicated write units (rWRU/rWCU), which are priced identically to standard write units — the cost increase comes from per-region charging, not higher per-unit price.

### dynamodb-global-tables-48-bytes-per-item-overhead [IN] OBSERVATION
DynamoDB Global Tables add 48 bytes per item in system-created attributes.

### dynamodb-global-tables-99999-sla [IN] OBSERVATION
DynamoDB global tables offer 99.999% availability SLA compared to 99.99% for single-Region tables.

### dynamodb-global-tables-consistency-mode-immutable [IN] OBSERVATION
DynamoDB Global Tables consistency mode (MREC or MRSC) is set at creation and cannot be changed afterward.

### dynamodb-global-tables-current-half-rwru-cost [IN] OBSERVATION
DynamoDB global tables Current version consumes 1 rWRU per replicated write vs Legacy's 2 rWRUs for PutItem, yielding up to 50% cost savings.

### dynamodb-global-tables-current-vs-legacy-version [IN] OBSERVATION
DynamoDB global tables have two versions: 2019.11.21 (Current, recommended) and 2017.11.29 (Legacy); Current uses standard UpdateTable API, produces 1 stream record per write, and synchronizes settings across replicas; Legacy uses dedicated APIs, produces 2 stream records per write, and does not sync settings.

### dynamodb-global-tables-dax-cache-staleness [IN] OBSERVATION
DynamoDB global table writes bypass DAX cache, causing cache staleness until DAX TTL expires.

### dynamodb-global-tables-last-writer-wins [IN] OBSERVATION
DynamoDB Global Tables use "last writer wins" reconciliation — optimistic locking with version numbers does not work across Regions because a write in one Region can overwrite a concurrent write in another without a version check.

### dynamodb-global-tables-legacy-v2017-vs-current-v2019 [IN] OBSERVATION
DynamoDB has two global tables versions: legacy (v2017.11.29) and current (v2019.11.21); AWS strongly recommends using the current version for greater flexibility, higher efficiency, and lower write capacity consumption.

### dynamodb-global-tables-mrec-default [IN] OBSERVATION
DynamoDB Global Tables default consistency mode is MREC (Multi-Region Eventual Consistency); MRSC (Multi-Region Strong Consistency) is restricted to same-account configurations only.

### dynamodb-global-tables-mrec-default-mrsc-optional [IN] OBSERVATION
DynamoDB global tables default to MREC (multi-Region eventually consistent) with async replication and last-writer-wins conflict resolution; MRSC (multi-Region strongly consistent) provides synchronous replication with RPO=0 but requires exactly 3 Regions from the same Region set.

### dynamodb-global-tables-mrsc-constraints [IN] OBSERVATION
DynamoDB MRSC global tables require exactly 3 Regions from the same set, table must be empty at creation, and do not support TTL, LSIs, or transactions.

### dynamodb-global-tables-multi-account-requires-current-version [IN] OBSERVATION
DynamoDB multi-account global tables require version 2019.11.21 (current); legacy version 2017.11.29 supports same-account only.

### dynamodb-global-tables-multi-active-no-primary [IN] OBSERVATION
DynamoDB global tables use multi-active replication across AWS Regions with no primary table concept and no failover delay.

### dynamodb-global-tables-multi-active-replication [IN] OBSERVATION
DynamoDB Global Tables use multi-active replication — every replica can accept both reads and writes (not primary/secondary).

### dynamodb-global-tables-never-synced-settings [IN] OBSERVATION
DynamoDB global table settings that never synchronize between replicas: deletion protection, point-in-time recovery, tags, resource policies, and Kinesis Data Streams configuration.

### dynamodb-global-tables-prefer-2019-version [IN] OBSERVATION
AWS strongly recommends using Global Tables version 2019.11.21 (Current) instead of the legacy 2017.11.29 version; the `UpdateGlobalTableSettings` API is for the legacy version only.

### dynamodb-global-tables-sla-99999 [IN] OBSERVATION
DynamoDB with global tables provides an availability SLA of up to 99.999%.

### dynamodb-global-tables-transactions-local-only [IN] OBSERVATION
DynamoDB global table transactions (MREC) are atomic only within the invoking Region — partial results may be visible in other Regions during replication. MRSC does not support transactions at all.

### dynamodb-global-tables-two-versions [IN] OBSERVATION
DynamoDB has two versions of global tables: v2017.11.29 (Legacy) and v2019.11.21 (Current); the current version consumes less write capacity and should be preferred.

### dynamodb-gsi-100-bytes-overhead-per-item [IN] OBSERVATION
Each item stored in a GSI includes 100 bytes of storage overhead in addition to the key and projected attribute sizes.

### dynamodb-gsi-autoscaling-independent-from-base-table [IN] OBSERVATION
DynamoDB GSI auto scaling is configured independently from the base table's auto scaling on each replica.

### dynamodb-gsi-backfill-no-read-charges [IN] OBSERVATION
During GSI backfill on an existing table, base table reads use internal system capacity and do not incur read charges.

### dynamodb-gsi-can-add-remove-after-creation [IN] OBSERVATION
Global Secondary Indexes can be added to or removed from a DynamoDB table after table creation.

### dynamodb-gsi-during-import-no-write-charges [IN] OBSERVATION
Creating a GSI during a DynamoDB S3 import incurs no write charges, whereas adding a GSI after import does incur write charges.

### dynamodb-gsi-eventual-consistency-only [IN] OBSERVATION
Global Secondary Indexes (GSIs) in DynamoDB support only eventual consistency for read operations; strong consistency is not available.

### dynamodb-gsi-eventually-consistent-only [IN] OBSERVATION
GSI reads are always eventually consistent; strongly consistent reads are not supported on Global Secondary Indexes.

### dynamodb-gsi-independent-provisioned-throughput [IN] OBSERVATION
Each GSI has its own independent provisioned throughput (RCUs and WCUs) separate from the base table; GSI write capacity should be ≥ base table write capacity to prevent throttling.

### dynamodb-gsi-key-change-costs-two-wcus [IN] OBSERVATION
Changing an indexed key attribute on a GSI costs 2 WCUs (one delete of the old item + one put of the new item in the index).

### dynamodb-gsi-keys-must-be-scalar-types [IN] OBSERVATION
GSI key attributes must be top-level scalar types: String, Number, or Binary only — document and set types are not allowed.

### dynamodb-gsi-max-20-per-table [IN] OBSERVATION
DynamoDB supports up to 20 Global Secondary Indexes per table (default quota).

### dynamodb-gsi-multi-attribute-keys-max-8 [IN] OBSERVATION
GSI partition keys can be composed from up to 4 attributes and sort keys from up to 4 attributes (max 8 total), eliminating the need for manually concatenated synthetic keys.

### dynamodb-gsi-no-getitem-batchgetitem [IN] OBSERVATION
GetItem and BatchGetItem operations cannot be used on Global Secondary Indexes — only Query and Scan are supported.

### dynamodb-gsi-no-strongly-consistent-reads [IN] OBSERVATION
DynamoDB GSIs do not support strongly consistent reads — setting ConsistentRead=true on a GSI query causes ValidationException.

### dynamodb-gsi-no-table-fetch-lsi-auto-fetches [IN] OBSERVATION
GSI queries can only return projected attributes (no fetching from base table), while LSI queries can request non-projected attributes and DynamoDB auto-fetches them from the base table.

### dynamodb-gsi-nonunique-partition-key-sort-key-disambiguates [IN] OBSERVATION
When a DynamoDB GSI partition key is non-unique (e.g., same URL bookmarked by multiple customers), the sort key is used to disambiguate — as demonstrated by the Bookmarks model's ByUrl index using customerId as sort key.

### dynamodb-gsi-one-add-or-delete-per-update-table [IN] OBSERVATION
Only one GSI can be added or deleted per `UpdateTable` operation in DynamoDB.

### dynamodb-gsi-overloading-multiple-attributes [IN] OBSERVATION
DynamoDB GSI overloading allows a single GSI to index multiple different attribute types (e.g., Dates, Names, Places, Skills) by storing different attribute values in the same indexed attribute.

### dynamodb-gsi-overloading-single-table-pattern [IN] OBSERVATION
GSI overloading uses a single GSI to serve multiple access patterns by storing different entity types with the same index key attribute names but different semantic meanings — a core technique in single-table design.

### dynamodb-gsi-own-throughput-lsi-base-table [IN] OBSERVATION
GSI reads and writes consume capacity from the index's own provisioned throughput, while LSI operations consume capacity from the base table.

### dynamodb-gsi-query-projected-attributes-only [IN] OBSERVATION
Querying a DynamoDB GSI can only return projected attributes; querying an LSI can fetch non-projected attributes from the base table at additional cost.

### dynamodb-gsi-quota-20-lsi-quota-5 [IN] OBSERVATION
DynamoDB default quota is 20 Global Secondary Indexes (GSIs) and 5 Local Secondary Indexes (LSIs) per table.

### dynamodb-gsi-sparse-index-missing-keys-omitted [IN] OBSERVATION
Items missing the GSI key attributes are not propagated to the index, enabling sparse index patterns.

### dynamodb-gsi-storage-overhead-200-bytes-minimum-per-projected-item [IN] OBSERVATION
Each item projected into a DynamoDB GSI incurs at least 200 bytes of storage overhead (100 bytes base table + 100 bytes GSI), making GSIs disproportionately expensive for small items.

### dynamodb-gsi-throttling-back-pressures-base-table [IN] OBSERVATION
DynamoDB GSI throttling can back-pressure the base table, causing writes to the base table to be throttled even if the base table has available capacity.

### dynamodb-hash-partition-range-sort-key-types [IN] OBSERVATION
In DynamoDB key schema, KeyType=HASH designates the partition key and KeyType=RANGE designates the sort key.

### dynamodb-iam-policy-version-2012-for-variables [IN] OBSERVATION
IAM policy version must be `2012-10-17` (not the default `2008-10-17`) when using policy variables such as web identity federation substitutions.

### dynamodb-if-not-exists-list-append-set-only [IN] OBSERVATION
DynamoDB `if_not_exists()` and `list_append()` are functions available only within the `SET` action of UpdateExpression.

### dynamodb-import-csv-configurable-delimiter-headers [IN] OBSERVATION
DynamoDB import supports CSV input with configurable delimiters and header lists via `InputFormatOptions`.

### dynamodb-import-from-s3-new-table-only [IN] OBSERVATION
DynamoDB Import from S3 creates a new table only — it cannot load into an existing table and performs no data transformations.

### dynamodb-import-not-found-returns-400 [IN] OBSERVATION
DynamoDB `ImportNotFoundException` returns HTTP 400 (client error), not 404.

### dynamodb-import-source-always-s3 [IN] OBSERVATION
DynamoDB table imports always use S3 as the source; cross-account imports are possible by specifying `S3BucketOwner`.

### dynamodb-import-tracks-processed-vs-imported-count [IN] OBSERVATION
DynamoDB import tracks both `ProcessedItemCount` (attempted) and `ImportedItemCount` (succeeded), plus `ErrorCount` for monitoring progress and failures.

### dynamodb-importtable-creates-new-table [IN] OBSERVATION
The `ImportTable` API creates a new DynamoDB table as part of the import — you cannot import into an existing table.

### dynamodb-importtable-creates-new-table-only [IN] OBSERVATION
DynamoDB ImportTable creates a new table from S3 data — it cannot import into an existing table.

### dynamodb-importtable-formats-csv-json-ion [IN] OBSERVATION
`ImportTable` supports three input formats: `CSV`, `DYNAMODB_JSON`, and `ION`, with optional `GZIP`, `ZSTD`, or `NONE` compression.

### dynamodb-importtable-idempotency-8-hours [IN] OBSERVATION
`ImportTable` client token idempotency window is 8 hours; resubmitting with the same token and changed parameters raises `IdempotentParameterMismatch`.

### dynamodb-importtable-max-50-concurrent [IN] OBSERVATION
DynamoDB allows a maximum of 50 concurrent `ImportTable` operations per account.

### dynamodb-incremental-export-insert-delete-same-window-no-output [IN] OBSERVATION
In DynamoDB incremental exports, an item inserted and deleted within the same export window produces no output.

### dynamodb-incremental-export-min-15min-max-24hr [IN] OBSERVATION
DynamoDB incremental export period has a minimum duration of 15 minutes and a maximum of 24 hours.

### dynamodb-incremental-export-shared-data-folder [IN] OBSERVATION
DynamoDB incremental exports store data files in a shared `AWSDynamoDB/data/` folder (not under each ExportId), unlike full exports which store data under `ExportId/data/`.

### dynamodb-index-key-must-be-scalar [IN] OBSERVATION
DynamoDB secondary index key attributes must be top-level scalar types (String, Number, or Binary) — document types and sets are not allowed as index keys.

### dynamodb-index-storage-refresh-every-6-hours [IN] OBSERVATION
DynamoDB secondary index storage size and item counts (returned by DescribeTable) refresh approximately every 6 hours, not in real time.

### dynamodb-indexes-streams-backups-same-key [IN] OBSERVATION
DynamoDB indexes (LSI/GSI), streams, and backups are all encrypted with the same key as the base table.

### dynamodb-individual-writes-atomic [IN] OBSERVATION
Individual DynamoDB write operations (e.g., UpdateItem) are atomic and always operate on the most recent item version — concurrency control is only needed for read-modify-write cycles.

### dynamodb-interface-endpoint-50k-rps-limit [IN] OBSERVATION
DynamoDB PrivateLink interface endpoints have a throughput limit of 50,000 requests per second per endpoint.

### dynamodb-interface-endpoint-min-3-azs [IN] OBSERVATION
DynamoDB PrivateLink interface endpoints should be deployed across a minimum of 3 AZs for optimal reliability.

### dynamodb-ion-set-annotations-required [IN] OBSERVATION
Amazon Ion lists require type annotations (`$dynamodb_SS`, `$dynamodb_NS`, `$dynamodb_BS`) to import as DynamoDB Sets; without annotations, Ion lists become DynamoDB Lists.

### dynamodb-ip-ranges-exclude-streams-and-dax [IN] OBSERVATION
DynamoDB IP address ranges published in `ip-ranges.json` (filtered by `"service": "DYNAMODB"`) apply to tables/indexes only — they do not cover DynamoDB Streams or DAX.

### dynamodb-item-100-bytes-indexing-overhead [IN] OBSERVATION
Every DynamoDB item has 100 bytes of indexing overhead added for storage billing purposes.

### dynamodb-item-collection-10gb-lsi-only [IN] OBSERVATION
`ItemCollectionSizeLimitExceededException` only applies to DynamoDB tables with local secondary indexes, enforcing a 10 GB limit per partition key collection.

### dynamodb-item-collection-one-to-many-mechanism [IN] OBSERVATION
Item collections are the primary mechanism for modeling one-to-many relationships in DynamoDB.

### dynamodb-item-collection-requires-composite-key [IN] OBSERVATION
DynamoDB item collections (groups of items sharing the same partition key value) only exist on tables or indexes with composite primary keys (partition key + sort key), not on tables with only a partition key.

### dynamodb-item-collection-size-limit-10gb-lsi [IN] OBSERVATION
DynamoDB item collection size limit is 10 GB, enforced only on tables with local secondary indexes (ItemCollectionSizeLimitExceededException).

### dynamodb-item-size-limit-400kb [IN] OBSERVATION
DynamoDB items have a maximum size limit of 400 KB; exceeding it during a transaction causes TransactionCanceledException.

### dynamodb-itemcount-tablesize-approximate-6-hour-update [IN] OBSERVATION
DynamoDB `ItemCount` and `TableSizeBytes` from `DescribeTable` are approximate values updated approximately every 6 hours, not in real time.

### dynamodb-kds-168-hour-auto-disable [IN] OBSERVATION
If `AgeOfOldestUnreplicatedRecord` exceeds 168 hours (7 days), DynamoDB-to-Kinesis replication is automatically disabled.

### dynamodb-kds-1mb-record-limit-skip [IN] OBSERVATION
Items larger than ~34 KB may exceed the 1 MB Kinesis record limit due to serialization expansion (Boolean/empty attributes: 1 byte in DynamoDB → up to 5 bytes in JSON) and are silently skipped (not retried).

### dynamodb-kds-binary-double-base64-encoding [IN] OBSERVATION
Binary values in DynamoDB CDC records are double base64-encoded (DynamoDB encodes once, Kinesis encodes again) — consumers must decode twice.

### dynamodb-kds-enable-requires-cross-service-permissions [IN] OBSERVATION
Enabling KDS for DynamoDB requires both DynamoDB permissions (`EnableKinesisStreamingDestination`) and Kinesis permissions (`ListStreams`, `PutRecords`, `DescribeStream`) plus `iam:CreateServiceLinkedRole`.

### dynamodb-kds-records-may-be-out-of-order-or-duplicated [IN] OBSERVATION
DynamoDB CDC records in Kinesis may arrive out of order or duplicated; consumers should use `ApproximateCreationDateTime` for ordering and deduplication.

### dynamodb-kds-same-account-region-one-stream [IN] OBSERVATION
A DynamoDB table can stream to only one Kinesis data stream, and both must be in the same AWS account and Region.

### dynamodb-kds-service-linked-role-auto-created [IN] OBSERVATION
The service-linked role `AWSServiceRoleForDynamoDBKinesisDataStreamsReplication` is automatically created on first KDS enable and is assumed by `kinesisreplication.dynamodb.amazonaws.com`.

### dynamodb-kds-three-cloudwatch-metrics [IN] OBSERVATION
The three key CloudWatch metrics for DynamoDB-to-KDS replication health are `ThrottledPutRecordCount`, `AgeOfOldestUnreplicatedRecord`, and `FailedToReplicateRecordCount`.

### dynamodb-kds-timestamp-precision-configurable [IN] OBSERVATION
DynamoDB Kinesis Data Streams `ApproximateCreationDateTimePrecision` is configurable to millisecond (default) or microsecond granularity, and can be changed on an active streaming destination.

### dynamodb-kds-update-takes-5-minutes [IN] OBSERVATION
Updating DynamoDB Kinesis streaming configuration (e.g., timestamp precision) transitions through `UPDATING` status and typically takes up to 5 minutes.

### dynamodb-kinesis-and-streams-can-coexist [IN] OBSERVATION
DynamoDB Kinesis streaming destination and DynamoDB Streams are separate CDC mechanisms that can both be active simultaneously on the same table.

### dynamodb-kinesis-cdc-has-four-independent-reliability-hazards [IN] OBSERVATION
DynamoDB-to-Kinesis CDC pipelines face four independent reliability hazards: records may arrive out of order or duplicated, binary values are double base64-encoded requiring consumer-side correction, items over ~34 KB may silently skip the 1 MB record limit, and replication auto-disables after 168 hours of lag — each requiring separate mitigation.

### dynamodb-kinesis-streaming-destination-status-lifecycle [IN] OBSERVATION
The DynamoDB Kinesis streaming destination status follows the lifecycle: ENABLING → ACTIVE → DISABLING → DISABLED, with additional states ENABLE_FAILED and UPDATING (six total states).

### dynamodb-kinesis-streaming-enable-is-async [IN] OBSERVATION
EnableKinesisStreamingDestination is asynchronous — it returns immediately but streaming may not be active; poll with DescribeKinesisStreamingDestination until status is ACTIVE.

### dynamodb-kinesis-streaming-newer-than-streams [IN] OBSERVATION
DynamoDB Kinesis streaming is the newer, higher-throughput change-data-capture option compared to DynamoDB Streams.

### dynamodb-kinesis-timestamp-precision-setting [IN] OBSERVATION
DynamoDB's `ApproximateCreationDateTimePrecision` setting controls whether timestamps on Kinesis streaming records are at second or millisecond granularity.

### dynamodb-kms-cache-refresh-5-minutes [IN] OBSERVATION
DynamoDB caches the plaintext table key from KMS and refreshes it every 5 minutes per caller with active traffic, not per operation.

### dynamodb-lambda-stream-consumer-no-getrecords-charge [IN] OBSERVATION
Using Lambda (not KCL) as a DynamoDB Streams consumer avoids `GetRecords` API charges.

### dynamodb-large-item-three-strategies [IN] OBSERVATION
Three strategies for handling large DynamoDB items: compress attributes (stored as Binary type), vertical partition (split across sort keys), or offload to Amazon S3.

### dynamodb-leading-keys-condition-row-level-security [IN] OBSERVATION
The `dynamodb:LeadingKeys` condition key in resource-based policies restricts access to specific partition key values, enabling row-level security.

### dynamodb-legacy-global-table-more-write-capacity [IN] OBSERVATION
Legacy global tables (version 2017.11.29) consume more write capacity than the current version (2019.11.21).

### dynamodb-legacy-global-table-replicas-must-be-empty [IN] OBSERVATION
In legacy DynamoDB global tables (v2017.11.29), replica tables must be empty before being added to a global table.

### dynamodb-legacy-global-tables-no-resource-policies [IN] OBSERVATION
DynamoDB legacy global tables (version 2017.11.29) do not support resource-based policies.

### dynamodb-legacy-global-tables-separate-apis [IN] OBSERVATION
Legacy global tables (v2017.11.29) use separate APIs (`DescribeGlobalTable`, `DescribeGlobalTableSettings`, `UpdateGlobalTable`, `UpdateGlobalTableSettings`); the current version (v2019.11.21) folds this into standard table APIs like `DescribeTable`.

### dynamodb-limit-caps-items-read-not-returned [IN] OBSERVATION
The DynamoDB Query `Limit` parameter caps the number of items read (before filtering), not the number of items returned — a query with a filter may return fewer items than the limit value.

### dynamodb-list-exports-90-day-window [IN] OBSERVATION
The DynamoDB `ListExports` API only returns exports completed within the last 90 days.

### dynamodb-list-exports-max-25-per-page [IN] OBSERVATION
The DynamoDB `ListExports` API returns a maximum of 25 results per page.

### dynamodb-list-global-tables-legacy-api [IN] OBSERVATION
The `ListGlobalTables` API is a legacy API (version 2017.11.29); new global tables should use version 2019.11.21 which relies on standard table APIs like `DescribeTable`.

### dynamodb-list-imports-90-day-window-max-50-concurrent [IN] OBSERVATION
The DynamoDB `ListImports` API only returns imports from the last 90 days; accounts support up to 50 simultaneous import operations.

### dynamodb-list-map-3-bytes-plus-1-per-element [IN] OBSERVATION
DynamoDB List and Map attributes have 3 bytes of overhead (even if empty) plus 1 byte per nested element.

### dynamodb-list-tables-cursor-based-pagination [IN] OBSERVATION
DynamoDB `ListTables` uses cursor-based pagination via `ExclusiveStartTableName`/`LastEvaluatedTableName` (actual table names, not opaque tokens).

### dynamodb-list-tables-max-100-per-page [IN] OBSERVATION
The DynamoDB `ListTables` API returns a maximum of 100 table names per page, scoped to the current account and region endpoint.

### dynamodb-list-tags-rate-limit-10-tps [IN] OBSERVATION
The DynamoDB `ListTagsOfResource` API is rate-limited to 10 requests per second per account.

### dynamodb-listbackups-5-tps-limit [IN] OBSERVATION
`ListBackups` has a rate limit of 5 calls per second.

### dynamodb-listbackups-excludes-aws-backup-by-default [IN] OBSERVATION
`ListBackups` does not include AWS Backup-created backups by default (default type is `USER`); use `BackupType: AWS_BACKUP` or the AWS Backup `ListBackupJobs` API to list them.

### dynamodb-liststreams-no-resource-based-policy [IN] OBSERVATION
`ListStreams` is the only DynamoDB Streams API that does not support resource-based policies; the other three (`DescribeStream`, `GetRecords`, `GetShardIterator`) support both resource-based policies and cross-account access.

### dynamodb-local-dev-only-endpoint-swap-to-production [IN] OBSERVATION
DynamoDB Local is for development and testing only; migrating to production requires only changing the endpoint configuration.

### dynamodb-local-dev-testing-only [IN] OBSERVATION
DynamoDB Local is a downloadable version for development and testing only — not a production deployment option — and uses the same API as the web service.

### dynamodb-local-offline-development [IN] OBSERVATION
DynamoDB Local is a downloadable version that enables offline development and testing without AWS credentials or network access.

### dynamodb-local-requires-endpoint-url-every-command [IN] OBSERVATION
DynamoDB Local requires `--endpoint-url http://localhost:8000` on every CLI command; there is no way to set it as a default endpoint override.

### dynamodb-local-requires-jre-17 [IN] OBSERVATION
DynamoDB Local (bundled with NoSQL Workbench) requires JRE 17.x or newer to run.

### dynamodb-local-three-distribution-methods [IN] OBSERVATION
DynamoDB Local is available as a downloadable JAR (requires JRE), an Apache Maven dependency, or a Docker image.

### dynamodb-locality-of-reference-top-performance-factor [IN] OBSERVATION
Keeping related data together (locality of reference) is the single most important performance factor in DynamoDB design.

### dynamodb-lock-client-dedicated-table-lease-heartbeat [IN] OBSERVATION
DynamoDB pessimistic locking via a lock client uses a dedicated lock table with lease duration and heartbeat mechanisms for long-running distributed coordination, with automatic lock expiry for process failure handling.

### dynamodb-lsi-10gb-item-collection-limit [IN] OBSERVATION
Tables with LSIs have a 10 GB item collection size limit per partition key value (includes base table items + all LSI items for that partition key).

### dynamodb-lsi-10gb-limit-per-partition-key [IN] OBSERVATION
DynamoDB Local Secondary Indexes have a 10 GB size limit per partition key value; GSIs do not have this limit.

### dynamodb-lsi-10gb-per-partition-key [IN] OBSERVATION
Local Secondary Indexes have a 10 GB size limit per partition key value.

### dynamodb-lsi-item-collection-10gb-limit [IN] OBSERVATION
DynamoDB tables with local secondary indexes (LSIs) have a 10 GB limit per item collection; exceeding it raises ItemCollectionSizeLimitExceededException.

### dynamodb-lsi-must-be-created-at-table-creation [IN] OBSERVATION
Local Secondary Indexes (LSIs) must be created at table creation time and cannot be added later; Global Secondary Indexes (GSIs) can be added after table creation.

### dynamodb-lsi-must-be-created-with-table [IN] OBSERVATION
Local Secondary Indexes must be defined at table creation time and cannot be added or removed after the table is created.

### dynamodb-lsi-must-create-at-table-creation [IN] OBSERVATION
DynamoDB local secondary indexes (LSIs) must be created at table creation time — they cannot be added or removed later.

### dynamodb-lsi-no-getitem-batchgetitem [IN] OBSERVATION
GetItem and BatchGetItem operations cannot be used on DynamoDB local secondary indexes — only Query and Scan are supported.

### dynamodb-lsi-queries-consume-base-table-capacity [IN] OBSERVATION
DynamoDB LSI queries consume the base table's read capacity, while GSI queries consume the index's own provisioned capacity.

### dynamodb-lsi-supports-strong-consistency [IN] OBSERVATION
Local Secondary Indexes (LSIs) in DynamoDB support both eventual and strong consistency for read operations.

### dynamodb-lsi-supports-strongly-consistent-reads [IN] OBSERVATION
DynamoDB LSIs support both strongly consistent and eventually consistent reads (unlike GSIs which only support eventually consistent).

### dynamodb-lsi-triggers-itemcollectionsizelimitexceeded [IN] OBSERVATION
`ItemCollectionSizeLimitExceededException` only applies to DynamoDB tables with Local Secondary Indexes (triggered by the 10 GB per partition key limit).

### dynamodb-max-20-gsi-5-lsi-per-table [IN] OBSERVATION
DynamoDB tables support a maximum of 20 Global Secondary Indexes and 5 Local Secondary Indexes per table.

### dynamodb-max-20-gsi-per-table [IN] OBSERVATION
DynamoDB supports a maximum of 20 Global Secondary Indexes per table.

### dynamodb-max-5-lsis-per-table [IN] OBSERVATION
DynamoDB supports a maximum of 5 local secondary indexes per table.

### dynamodb-max-500-simultaneous-table-operations [IN] OBSERVATION
DynamoDB allows up to 500 simultaneous table operations (CreateTable, UpdateTable, DeleteTable, etc.) per account, dropping to 250 when creating tables with secondary indexes.

### dynamodb-max-tables-2500-per-account-region [IN] OBSERVATION
The default maximum number of DynamoDB tables per account per Region is 2,500 (can be increased to 10,000; beyond that requires multiple accounts).

### dynamodb-mrec-last-writer-wins-silent [IN] OBSERVATION
DynamoDB global tables MREC (default mode) uses last-writer-wins conflict resolution based on write timestamp; conflicts are not logged in CloudWatch or CloudTrail.

### dynamodb-mrec-vs-mrsc-feature-differences [IN] OBSERVATION
DynamoDB global table MREC uses Streams for replication, supports TTL, supports transactions (region-local atomicity only), and publishes ReplicationLatency metric; MRSC does not use Streams for replication, does not support TTL, does not support transactions, and has no ReplicationLatency metric.

### dynamodb-mrsc-exactly-3-regions-same-set [IN] OBSERVATION
DynamoDB MRSC (Multi-Region Strong Consistency) requires exactly 3 Regions from the same Region set (US, EU, or AP); cannot span sets. Supports 3 replicas or 2 replicas + 1 witness.

### dynamodb-mrsc-no-transactions-ttl-lsi [IN] OBSERVATION
DynamoDB MRSC does not support transaction APIs, TTL, or local secondary indexes (LSIs).

### dynamodb-mrsc-rpo-zero-mrec-rpo-seconds [IN] OBSERVATION
DynamoDB MRSC provides RPO of zero (no data loss on Region failure); MREC RPO equals replication delay (typically seconds).

### dynamodb-mrsc-witnesses-cheaper-than-replicas [IN] OBSERVATION
MRSC (multi-region strong consistency) global tables support witnesses as a cheaper alternative to full replicas — witnesses maintain replicated change data but do not support read/write operations.

### dynamodb-multi-account-global-tables-mrec-only [IN] OBSERVATION
DynamoDB multi-account global tables support only MREC (Multi-Region Eventual Consistency); MRSC is not supported for multi-account configurations.

### dynamodb-multi-account-global-tables-per-account-billing [IN] OBSERVATION
Each replica in a DynamoDB multi-account global table is billed to its respective AWS account, simplifying cost attribution.

### dynamodb-native-backup-no-abac [IN] OBSERVATION
Attribute-based access control (ABAC) is not supported with DynamoDB-native backups; AWS Backup must be used if ABAC is needed.

### dynamodb-nested-attributes-32-levels-deep [IN] OBSERVATION
DynamoDB document types (List, Map) can be nested up to 32 levels deep.

### dynamodb-no-global-endpoint-regional-only [IN] OBSERVATION
DynamoDB has no global endpoint; all requests go to Regional endpoints accessing the local replica.

### dynamodb-no-item-count-limit-per-table [IN] OBSERVATION
There is no limit on the number of items in a DynamoDB table.

### dynamodb-no-native-date-type [IN] OBSERVATION
DynamoDB has no native date/time data type — use epoch time (Number) or ISO 8601 (String) instead.

### dynamodb-no-scan-index-forward-descending-order [IN] OBSERVATION
The `--no-scan-index-forward` flag on Query reverses traversal to descending sort key order.

### dynamodb-no-separate-transact-iam-action [IN] OBSERVATION
There is no separate `TransactWriteItems` or `TransactGetItems` IAM action — transactions are controlled via underlying item-level actions (`PutItem`, `UpdateItem`, `DeleteItem`, `GetItem`) plus the `dynamodb:EnclosingOperation` condition key.

### dynamodb-no-tag-based-iam-conditions [IN] OBSERVATION
DynamoDB does not support tag-based conditions for IAM policies.

### dynamodb-nonkeyattributes-max-100-across-indexes [IN] OBSERVATION
The total number of `NonKeyAttributes` across all secondary indexes on a DynamoDB table must not exceed 100 (applies to `INCLUDE` projection type).

### dynamodb-nosql-workbench-no-2fa-support [IN] OBSERVATION
NoSQL Workbench does not support AWS logins with two-factor authentication (2FA).

### dynamodb-nosql-workbench-three-functions [IN] OBSERVATION
NoSQL Workbench is the unified visual tool for DynamoDB supporting three functions: data modeling, visualization, and query development.

### dynamodb-number-precision-38-digits [IN] OBSERVATION
DynamoDB Number type supports up to 38 digits of precision with a range of 1E-130 to ~1E+125.

### dynamodb-numbers-sent-as-strings-in-json [IN] OBSERVATION
DynamoDB numbers are passed as strings in the JSON wire format (e.g., `"N": "10"`, not `"N": 10`) but stored as numbers.

### dynamodb-on-demand-backup-captures-feature-config [IN] OBSERVATION
DynamoDB on-demand backups capture table data and feature configuration including GSIs, LSIs, SSE settings, Streams config, and TTL settings.

### dynamodb-on-demand-backup-no-limit-no-throughput [IN] OBSERVATION
On-demand DynamoDB backups have no limit on count and do not consume any provisioned read/write capacity.

### dynamodb-on-demand-default-mode [IN] OBSERVATION
On-demand is the default and recommended throughput capacity mode for DynamoDB tables.

### dynamodb-on-demand-default-throughput-mode [IN] OBSERVATION
DynamoDB on-demand mode is the default and recommended throughput option for most workloads.

### dynamodb-on-demand-describe-shows-zero-rcu-wcu [IN] OBSERVATION
On-demand DynamoDB tables report RCU/WCU as 0 in DescribeTable output — this is expected behavior, not an error.

### dynamodb-on-demand-floor-4000wcu-12000rcu [IN] OBSERVATION
When switching to on-demand mode, DynamoDB tables below 4,000 WCU / 12,000 RCU are scaled up to at least those minimums as the initial throughput floor.

### dynamodb-on-demand-no-account-level-quota [IN] OBSERVATION
DynamoDB on-demand mode has no account-level throughput quota — only per-table limits of 40,000 RRU/WRU apply.

### dynamodb-on-demand-not-immune-to-throttling [IN] OBSERVATION
DynamoDB on-demand mode is not immune to throttling — it has both account-level service quotas and configurable maximum throughput limits that can cause throttling.

### dynamodb-on-demand-pay-per-request [IN] OBSERVATION
DynamoDB on-demand mode uses pay-per-request pricing with no capacity planning; provisioned mode bills hourly for specified RCUs/WCUs regardless of usage.

### dynamodb-on-demand-remembers-historical-peak [IN] OBSERVATION
DynamoDB remembers the historical peak provisioned capacity when switching to on-demand — even if capacity was reduced before switching, the previous peak is used as the on-demand baseline.

### dynamodb-ondemand-backup-billing-monthly-prorated [IN] OBSERVATION
DynamoDB on-demand backup charges are applied on the day of creation (prorated for remaining month) and on the 1st of each subsequent month (full month assumed), with retroactive adjustment when backups are deleted.

### dynamodb-ondemand-backup-full-not-incremental [IN] OBSERVATION
DynamoDB on-demand backups are full table backups, not incremental.

### dynamodb-ondemand-backup-zero-performance-impact [IN] OBSERVATION
DynamoDB on-demand backups have zero impact on table performance or availability during backup and restore operations.

### dynamodb-ondemand-default-quota-40000-per-table [IN] OBSERVATION
The default account-level on-demand throughput quota for DynamoDB is 40,000 RRU/WRU per table, increasable via service quota request.

### dynamodb-ondemand-doubles-previous-peak [IN] OBSERVATION
DynamoDB on-demand mode instantly accommodates up to double the previous peak traffic without throttling; exceeding double the peak within 30 minutes can cause throttling.

### dynamodb-ondemand-exceeding-max-throttling-exception [IN] OBSERVATION
Exceeding the configured on-demand max throughput returns a ThrottlingException (not ProvisionedThroughputExceededException).

### dynamodb-ondemand-max-throughput-best-effort [IN] OBSERVATION
DynamoDB on-demand maximum throughput setting is best-effort, not a hard ceiling — burst capacity can temporarily allow traffic above the configured maximum.

### dynamodb-ondemand-max-throughput-global-table-propagation [IN] OBSERVATION
Setting max on-demand throughput on one DynamoDB global table replica automatically applies to all replicas.

### dynamodb-ondemand-new-table-initial-capacity [IN] OBSERVATION
New DynamoDB on-demand tables can sustain up to 4,000 writes/sec and 12,000 reads/sec initially.

### dynamodb-one-table-with-indexes-creating-at-a-time [IN] OBSERVATION
Only one DynamoDB table with secondary indexes can be in `CREATING` state at a time.

### dynamodb-only-key-attributes-require-definition [IN] OBSERVATION
Only key attributes (partition key, sort key, and index keys) require AttributeDefinitions at table creation; DynamoDB is schemaless for non-key attributes.

### dynamodb-only-symmetric-kms-keys [IN] OBSERVATION
DynamoDB supports only symmetric KMS keys for encryption — asymmetric keys cannot be used.

### dynamodb-opensearch-zero-etl-no-table-throughput-impact [IN] OBSERVATION
The DynamoDB-to-OpenSearch zero-ETL integration does not consume table read/write throughput capacity.

### dynamodb-opensearch-zero-etl-requires-pitr-and-streams [IN] OBSERVATION
DynamoDB zero-ETL integration with OpenSearch requires both PITR and DynamoDB Streams (with new & old images) enabled on the table.

### dynamodb-operations-require-defensive-implementation-across-both-planes [IN] OBSERVATION
DynamoDB data plane operations require defensive client implementation (pagination, partial-failure handling in batch ops, filter-expression awareness), and control plane operations are subject to per-account, per-region, and per-table throttle limits that must be anticipated in automation.

### dynamodb-optimistic-locking-version-conditional-write [IN] OBSERVATION
DynamoDB optimistic locking uses a version attribute combined with conditional writes to detect conflicts at write time; on conflict the write fails and the application retries.

### dynamodb-pagination-lastevaluatedkey-mechanism [IN] OBSERVATION
DynamoDB pagination uses `LastEvaluatedKey` in the response and `ExclusiveStartKey` in the next request; absence of `LastEvaluatedKey` is the only reliable signal that all results have been retrieved.

### dynamodb-pagination-requires-defensive-client-implementation [IN] OBSERVATION
DynamoDB pagination across Query and Scan operations requires explicit defensive client implementation: checking LastEvaluatedKey presence, passing ExclusiveStartKey on subsequent requests, and coordinating parallel scan via Segment/TotalSegments — none of this is automatic.

### dynamodb-parallel-scan-1-segment-per-2gb [IN] OBSERVATION
DynamoDB parallel scan recommended starting ratio is 1 segment per 2 GB of data (e.g., 30 GB table → TotalSegments = 15), with TotalSegments between 1 and 1,000,000.

### dynamodb-parallel-scan-segment-and-total-segments [IN] OBSERVATION
DynamoDB parallel scan requires both `Segment` (0-based worker ID) and `TotalSegments` (1–1,000,000) parameters; each segment's pagination must use the same segment ID.

### dynamodb-partiql-executestatement-1mb-limit [IN] OBSERVATION
DynamoDB ExecuteStatement (PartiQL) results are subject to a 1 MB dataset size limit per response, applied to processed items before filtering.

### dynamodb-partiql-insert-fails-if-exists [IN] OBSERVATION
PartiQL INSERT fails if an item with the same primary key already exists, unlike PutItem which overwrites by default.

### dynamodb-partiql-no-cross-account-access [IN] OBSERVATION
DynamoDB PartiQL operations support resource-based policies but do not support cross-account access.

### dynamodb-partiql-statement-max-8192-chars [IN] OBSERVATION
DynamoDB PartiQL statement maximum length is 8,192 characters.

### dynamodb-partiql-via-executestatement [IN] OBSERVATION
ExecuteStatement and BatchExecuteStatement use PartiQL syntax as an alternative to the native DynamoDB JSON API.

### dynamodb-partition-key-equality-only [IN] OBSERVATION
DynamoDB Query key condition expressions require the partition key to be an equality condition (`=`); range operators (`<`, `<=`, `>`, `>=`, `BETWEEN`, `begins_with`) are only available for the sort key.

### dynamodb-partition-key-max-2048-sort-key-max-1024-bytes [IN] OBSERVATION
DynamoDB partition key maximum size is 2048 bytes; sort key maximum size is 1024 bytes.

### dynamodb-per-partition-3000-rcu-1000-wcu [IN] OBSERVATION
DynamoDB has per-partition throughput limits of 3,000 RCUs and 1,000 WCUs per second.

### dynamodb-per-table-quota-creation-only [IN] OBSERVATION
DynamoDB per-table provisioned capacity quotas apply only at table creation time (including GSIs); existing tables are constrained only by the account-level aggregate quota when scaling up.

### dynamodb-pitr-1-to-35-days-per-second-granularity [IN] OBSERVATION
DynamoDB point-in-time recovery (PITR) provides continuous backups with per-second granularity, configurable between 1–35 days, starting from 5 minutes before the current time.

### dynamodb-pitr-35-day-window-per-second-granularity [IN] OBSERVATION
DynamoDB PITR provides continuous backups with per-second granularity for a configurable recovery window of 1–35 days (default 35 days).

### dynamodb-pitr-cost-same-regardless-of-recovery-window [IN] OBSERVATION
DynamoDB PITR billing is based on table size (data + LSIs); changing the recovery window between 1 and 35 days does not change the price.

### dynamodb-pitr-decrease-window-immediately-loses-data [IN] OBSERVATION
Decreasing the DynamoDB PITR recovery period immediately shrinks `EarliestRestorePoint` and older backups become unrecoverable; increasing the period does not instantly extend the earliest restore point.

### dynamodb-pitr-delete-creates-system-backup-35-days [IN] OBSERVATION
When a PITR-enabled DynamoDB table is deleted, a system backup named `<tablename>$DeletedTableBackup` is automatically created and retained for 35 days at no extra cost (single snapshot, not continuous recovery).

### dynamodb-pitr-disable-reenable-resets-recovery-window [IN] OBSERVATION
Disabling and re-enabling DynamoDB PITR resets the recovery start time — the previous recovery window is lost.

### dynamodb-pitr-disable-reenable-resets-window [IN] OBSERVATION
Disabling and re-enabling DynamoDB PITR resets the `EarliestRestorableDateTime` — you can only restore from the re-enable point onward.

### dynamodb-pitr-export-reimportable [IN] OBSERVATION
DynamoDB point-in-time recovery exports (DynamoDB JSON format) are directly usable as import sources for round-trip compatibility.

### dynamodb-pitr-latest-restorable-5-minutes-before-current [IN] OBSERVATION
DynamoDB PITR `LatestRestorableDateTime` is typically 5 minutes before the current time.

### dynamodb-pitr-latest-restorable-5min-lag [IN] OBSERVATION
DynamoDB PITR `LatestRestorableDateTime` is typically 5 minutes before the current time — you cannot restore to the exact current moment.

### dynamodb-pitr-max-35-days-latest-5min-lag [IN] OBSERVATION
DynamoDB Point-in-Time Recovery supports restoring to any point within the last 35 days (configurable 1–35 days); `LatestRestorableDateTime` is typically ~5 minutes before the current time.

### dynamodb-pitr-max-35-days-recovery [IN] OBSERVATION
DynamoDB PITR recovery window is configurable between 1 and 35 days; `LatestRestorableDateTime` lags approximately 5 minutes behind the current time.

### dynamodb-pitr-must-be-explicitly-enabled [IN] OBSERVATION
DynamoDB continuous backups are automatically enabled on all tables, but point-in-time recovery (PITR) must be explicitly enabled via `UpdateContinuousBackups`; PITR is not on by default.

### dynamodb-pitr-must-reconfig-pitr-itself [IN] OBSERVATION
When restoring a table via PITR, Point-in-Time Recovery itself is not automatically enabled on the restored table and must be manually reconfigured.

### dynamodb-pitr-not-enabled-by-default [IN] OBSERVATION
DynamoDB Point-in-Time Recovery (PITR) is a best practice but is not enabled by default and incurs additional cost.

### dynamodb-pitr-recovery-period-1-to-35-days [IN] OBSERVATION
DynamoDB Point-in-Time Recovery (PITR) supports a configurable recovery period between 1 and 35 days via the `RecoveryPeriodInDays` parameter.

### dynamodb-pitr-recovery-window-1-to-35-days [IN] OBSERVATION
DynamoDB PITR recovery window is configurable between 1 and 35 days via `RecoveryPeriodInDays`, with 35 days as the default and maximum.

### dynamodb-pitr-restore-creates-independent-table [IN] OBSERVATION
DynamoDB PITR restores create an independent, standalone table — not part of any global table.

### dynamodb-pitr-restore-creates-new-table [IN] OBSERVATION
DynamoDB point-in-time recovery (PITR) and on-demand backup restores always create a new table — you cannot restore in-place to an existing table.

### dynamodb-pitr-restores-current-settings-not-point-in-time [IN] OBSERVATION
PITR restores use the source table's current settings (GSIs, LSIs, capacity, encryption) — not the settings as they existed at the restore point in time.

### dynamodb-pitr-restores-to-new-table-only [IN] OBSERVATION
DynamoDB PITR always restores to a new table — it never overwrites the existing table.

### dynamodb-pitr-shorter-retention-no-cost-savings [IN] OBSERVATION
Shortening the DynamoDB PITR RecoveryPeriodinDays does not reduce pricing — PITR pricing is based on table + LSI size, not retention duration.

### dynamodb-primary-key-types-string-number-binary [IN] OBSERVATION
DynamoDB primary key attributes (partition key and sort key) must be String, Number, or Binary — no other data types are allowed.

### dynamodb-projected-attributes-max-100-include-type [IN] OBSERVATION
The maximum number of projected attributes across all secondary indexes on a DynamoDB table is 100, applying only to INCLUDE projection type (not KEYS_ONLY or ALL).

### dynamodb-projection-expressions-no-capacity-reduction [IN] OBSERVATION
Using projection expressions to request a subset of attributes does not reduce DynamoDB capacity consumption — the full item size is always read internally.

### dynamodb-provisioned-account-level-80k-rcu-wcu [IN] OBSERVATION
DynamoDB provisioned mode has account-level throughput quotas of 80,000 RCU and 80,000 WCU across all tables and GSIs in a Region.

### dynamodb-provisioned-decrease-max-27-per-day [IN] OBSERVATION
DynamoDB provisioned capacity decreases are limited to 27 per day (4 available at start of day UTC, plus 1 earned per hour, max 4 banked).

### dynamodb-provisioned-to-ondemand-max-4-per-day [IN] OBSERVATION
Switching a DynamoDB table from provisioned to on-demand mode is limited to 4 times in a 24-hour rolling window; switching from on-demand to provisioned can be done at any time with no limit.

### dynamodb-put-resource-policy-optimistic-locking [IN] OBSERVATION
DynamoDB's `PutResourcePolicy` API supports optimistic concurrency control via the `--expected-revision-id` parameter — the update only succeeds if the current revision ID matches.

### dynamodb-putitem-1-wcu-per-1kb [IN] OBSERVATION
PutItem consumes 1 WCU per item up to 1 KB; larger items consume additional WCUs proportionally.

### dynamodb-putitem-full-replace-not-merge [IN] OBSERVATION
PutItem replaces the entire item if a matching primary key exists — non-specified attributes on the old item are lost; use UpdateItem for partial updates.

### dynamodb-putitem-prevent-overwrite-condition [IN] OBSERVATION
PutItem can prevent overwrites using `ConditionExpression: "attribute_not_exists(<partition_key>)"` to insert only if the item doesn't already exist.

### dynamodb-putitem-replaces-entire-item [IN] OBSERVATION
PutItem replaces the entire item if the primary key already exists — it does not merge attributes; use UpdateItem for partial updates.

### dynamodb-putitem-returnvalues-none-or-all-old [IN] OBSERVATION
PutItem only supports `NONE` (default) and `ALL_OLD` for ReturnValues — not UPDATED_OLD, ALL_NEW, or UPDATED_NEW.

### dynamodb-query-1mb-limit-before-filter [IN] OBSERVATION
The DynamoDB Query 1 MB result size limit applies before filter expressions and projection expressions are evaluated.

### dynamodb-query-1mb-page-limit [IN] OBSERVATION
A single DynamoDB Query call reads up to 1 MB of data; pagination is required via LastEvaluatedKey/ExclusiveStartKey for larger result sets.

### dynamodb-query-eventually-consistent-by-default [IN] OBSERVATION
DynamoDB Query operations are eventually consistent by default; set `ConsistentRead=true` for strongly consistent reads (which doubles RCU cost).

### dynamodb-query-filter-does-not-reduce-rcu [IN] OBSERVATION
DynamoDB Query FilterExpression is applied after data is read but before returning results — it does NOT reduce read capacity consumed.

### dynamodb-query-operation-for-item-collections [IN] OBSERVATION
The Query operation (not Scan) is used to efficiently retrieve items from an item collection in DynamoDB, supporting partition key lookup and sort key filtering.

### dynamodb-query-pagination-1mb-page-limit [IN] OBSERVATION
DynamoDB Query operation results are paginated in pages of 1 MB or less; this is a hard limit per response.

### dynamodb-query-pagination-last-evaluated-key [IN] OBSERVATION
Query results are paginated; the presence of `LastEvaluatedKey` in the response signals that more pages exist, and it should be passed as `ExclusiveStartKey` in the next request.

### dynamodb-query-requires-partition-key [IN] OBSERVATION
DynamoDB Query always requires a partition key value; it operates on a single partition key value, unlike Scan which reads the entire table.

### dynamodb-query-secondary-index-requires-table-name [IN] OBSERVATION
When querying a secondary index, both `--index-name` and `--table-name` must be specified.

### dynamodb-query-sort-ascending-default-scanindexforward [IN] OBSERVATION
DynamoDB Query results are automatically sorted by sort key value in ascending order by default; setting `ScanIndexForward=false` reverses the order.

### dynamodb-rcu-4kb-wcu-1kb [IN] OBSERVATION
One DynamoDB RCU provides one strongly consistent read/sec (or two eventually consistent reads/sec) for items up to 4 KB; one WCU provides one write/sec for items up to 1 KB.

### dynamodb-read-4kb-write-1kb-rounding [IN] OBSERVATION
DynamoDB rounds item sizes up to the next 4 KB boundary for reads and the next 1 KB boundary for writes when calculating capacity unit consumption.

### dynamodb-read-committed-isolation [IN] OBSERVATION
DynamoDB provides read-committed isolation — reads always return committed values and never return data from an unsuccessful write.

### dynamodb-read-consistency-costs [IN] OBSERVATION
DynamoDB read costs per 4 KB: eventually consistent = 0.5 RCU, strongly consistent = 1 RCU, transactional = 2 RCU.

### dynamodb-reading-nonexistent-item-consumes-rcus [IN] OBSERVATION
Reading a non-existent item in DynamoDB still consumes read capacity units.

### dynamodb-reads-writes-may-succeed-during-deleting-state [IN] OBSERVATION
DynamoDB may continue to accept read/write operations on a table in `DELETING` state until deletion fully completes.

### dynamodb-region-disable-converts-replicas-after-20-hours [IN] OBSERVATION
Disabling an AWS Region converts its DynamoDB global table replicas to single-Region tables after 20 hours.

### dynamodb-replica-autoscaling-independent-per-replica [IN] OBSERVATION
Each DynamoDB global table replica can have different auto scaling settings (different min/max capacity, target utilization values) configured independently.

### dynamodb-replicates-across-three-azs [IN] OBSERVATION
DynamoDB automatically replicates data across three Availability Zones, providing 99.99% SLA (99.999% with global tables).

### dynamodb-reserved-capacity-100-unit-minimum [IN] OBSERVATION
DynamoDB reserved capacity is purchased in minimum allocations of 100 WCUs or 100 RCUs.

### dynamodb-reserved-capacity-excludes-ondemand-ia-rwcu [IN] OBSERVATION
DynamoDB reserved capacity does not apply to on-demand capacity mode, Standard-IA table class, or replicated write capacity units (rWCUs).

### dynamodb-reserved-capacity-provisioned-standard-single-region-only [IN] OBSERVATION
DynamoDB reserved capacity applies only to provisioned capacity mode, standard table class, and single-region (not on-demand, Standard-IA, or global tables).

### dynamodb-reserved-capacity-region-scoped-non-transferable [IN] OBSERVATION
DynamoDB reserved capacity is region-specific and cannot be sold, cancelled, or transferred to another Region or account.

### dynamodb-reserved-capacity-savings-1yr-54-3yr-77 [IN] OBSERVATION
DynamoDB reserved capacity offers up to 54% savings on a one-year term and up to 77% savings on a three-year term.

### dynamodb-resource-based-policies-always-inline [IN] OBSERVATION
DynamoDB resource-based policies are always inline — there are no managed resource-based policies for DynamoDB.

### dynamodb-resource-based-policies-tables-and-streams-only [IN] OBSERVATION
DynamoDB resource-based policies can only be attached to tables and streams, not to backups, imports, or other resource types.

### dynamodb-resource-based-policy-cross-account-access [IN] OBSERVATION
Resource-based policies are the primary mechanism for granting cross-account DynamoDB table access, using `PutResourcePolicy` API with standard IAM policy syntax.

### dynamodb-resource-based-policy-max-20kb [IN] OBSERVATION
DynamoDB resource-based policies have a maximum size of 20 KB per resource and can be attached to tables, indexes, and streams.

### dynamodb-resource-policies-on-tables-indexes-streams [IN] OBSERVATION
DynamoDB resource-based policies can be attached to tables, indexes, and streams.

### dynamodb-resource-policy-15-second-update-cooldown [IN] OBSERVATION
After a successful DynamoDB resource-based policy update, subsequent updates to the same resource are blocked for 15 seconds.

### dynamodb-resource-policy-attachable-at-creation [IN] OBSERVATION
DynamoDB resource-based policies can be attached at table creation time via `--resource-policy` on `create-table` CLI, not only post-creation.

### dynamodb-resource-policy-covers-table-and-indexes [IN] OBSERVATION
A resource-based policy attached to a DynamoDB table also covers its associated indexes.

### dynamodb-resource-policy-eventually-consistent [IN] OBSERVATION
`GetResourcePolicy` is eventually consistent — it may return stale data or `PolicyNotFoundException` immediately after `PutResourcePolicy`, `DeleteResourcePolicy`, or `CreateTable`.

### dynamodb-resource-policy-max-20kb [IN] OBSERVATION
DynamoDB resource-based policies have a maximum size of 20 KB including whitespace.

### dynamodb-resource-policy-requires-createtable-and-putresourcepolicy [IN] OBSERVATION
Attaching a resource-based policy at DynamoDB table creation requires both `CreateTable` and `PutResourcePolicy` IAM actions.

### dynamodb-resource-policy-simplifies-cross-account [IN] OBSERVATION
DynamoDB resource-based policies are the simplest way to grant cross-account access to DynamoDB resources, without requiring IAM roles or assume-role patterns.

### dynamodb-resource-policy-tables-and-streams [IN] OBSERVATION
DynamoDB resource-based policies can be attached to tables and streams; index permissions are controlled through the base table's policy.

### dynamodb-restore-50-concurrent-limit [IN] OBSERVATION
DynamoDB allows up to 50 concurrent table restores (any type — on-demand backup or PITR) per account.

### dynamodb-restore-creates-new-table [IN] OBSERVATION
DynamoDB `RestoreTableFromBackup` and `RestoreTableToPointInTime` both create a new table — they cannot restore in-place, and `TableAlreadyExistsException` is thrown if the target table name already exists.

### dynamodb-restore-no-source-throughput-consumed [IN] OBSERVATION
DynamoDB restores do not consume provisioned throughput on the source table.

### dynamodb-restore-six-settings-not-carried-over [IN] OBSERVATION
DynamoDB restores do not carry over six settings that must be manually reconfigured: auto scaling policies, IAM policies, CloudWatch metrics/alarms, tags, stream settings, and TTL settings (plus PITR on the new table).

### dynamodb-restore-six-settings-not-preserved [IN] OBSERVATION
DynamoDB restores (both from backup and PITR) do not preserve six settings that must be manually reconfigured: auto scaling policies, IAM policies, CloudWatch metrics/alarms, tags, stream settings, and TTL settings.

### dynamodb-restore-uses-capacity-from-restore-point [IN] OBSERVATION
A full DynamoDB PITR restore uses the provisioned capacity settings from the point-in-time being restored, not the table's current settings.

### dynamodb-returnvalues-no-extra-rcu [IN] OBSERVATION
DynamoDB `ReturnValues` does not consume additional read capacity units; returned values are strongly consistent.

### dynamodb-root-can-always-delete-resource-policy [IN] OBSERVATION
The AWS account root principal can always call `DeleteResourcePolicy` on DynamoDB, even if the resource-based policy explicitly denies root access, preventing accidental lockout.

### dynamodb-rru-wru-sizing [IN] OBSERVATION
One DynamoDB Read Request Unit (RRU) = 1 strongly consistent read or 2 eventually consistent reads for items up to 4 KB; one Write Request Unit (WRU) = 1 write for items up to 1 KB.

### dynamodb-s3-import-50-concurrent-jobs-per-account [IN] OBSERVATION
DynamoDB supports up to 50 concurrent S3 import jobs per account across all regions.

### dynamodb-s3-import-billed-on-uncompressed-size [IN] OBSERVATION
DynamoDB S3 import pricing is based on uncompressed size of source data processed, including items that fail to load.

### dynamodb-s3-import-compression-zstd-gzip [IN] OBSERVATION
DynamoDB S3 import supports ZSTD, GZIP, or no compression.

### dynamodb-s3-import-constrained-to-clean-initial-loads [IN] OBSERVATION
DynamoDB S3 import is constrained to clean initial table loads: it only creates new tables (no merge into existing), silently overwrites duplicate keys in random order, and does not support tables with LSIs — making it unsuitable for incremental migration, data reconciliation, or tables requiring local secondary indexes.

### dynamodb-s3-import-creates-new-table-only [IN] OBSERVATION
DynamoDB S3 import always creates a new table — importing into an existing table is not supported.

### dynamodb-s3-import-cross-account-cross-region [IN] OBSERVATION
DynamoDB S3 import supports cross-account imports (with S3BucketOwner parameter and bucket policy) and cross-region imports (source bucket and target table in different regions).

### dynamodb-s3-import-csv-headers-case-sensitive [IN] OBSERVATION
CSV headers for DynamoDB S3 import are case-sensitive and must include the table's key attributes.

### dynamodb-s3-import-duplicate-keys-last-write-wins [IN] OBSERVATION
Duplicate primary keys in DynamoDB S3 imports cause overwrites — only one item per key survives, in random order; duplicates are not counted as errors.

### dynamodb-s3-import-error-logs-cloudwatch [IN] OBSERVATION
DynamoDB S3 import publishes error details to CloudWatch Logs under the `/aws-dynamodb/imports` log group with stream name `<import-id>/error`.

### dynamodb-s3-import-failure-before-processing-no-table [IN] OBSERVATION
When a DynamoDB S3 import fails before data processing begins (e.g., bucket doesn't exist), no table is created; when it fails after processing starts, a partially-filled table may remain.

### dynamodb-s3-import-file-extensions-ignored [IN] OBSERVATION
S3 object file extensions (.csv, .json, .gz) are ignored by DynamoDB import — the `InputFormat` API parameter controls format interpretation.

### dynamodb-s3-import-max-50000-objects [IN] OBSERVATION
Each DynamoDB S3 import job supports a maximum of 50,000 S3 objects.

### dynamodb-s3-import-metadata-retained-90-days [IN] OBSERVATION
DynamoDB import metadata is available via `list-imports` for 90 days after the import completes.

### dynamodb-s3-import-no-lsi-supports-gsi [IN] OBSERVATION
DynamoDB Import from S3 does not support tables with Local Secondary Indexes (LSIs), but does support Global Secondary Indexes (GSIs).

### dynamodb-s3-import-no-write-capacity-consumed [IN] OBSERVATION
DynamoDB S3 import does not consume write capacity on the target table.

### dynamodb-s3-import-regional-size-limits [IN] OBSERVATION
DynamoDB S3 import total source size limit is 15 TB in us-east-1, us-west-2, and eu-west-1; 1 TB in all other regions (based on raw S3 object size, not uncompressed).

### dynamodb-s3-import-sorted-data-hot-partition [IN] OBSERVATION
Sorted data in DynamoDB S3 imports causes rolling hot partitions (sequential writes hitting one partition at a time); randomizing item order avoids this.

### dynamodb-s3-import-sse-c-not-supported [IN] OBSERVATION
SSE-C encrypted S3 objects are not supported for DynamoDB S3 import; SSE-KMS and SSE-S3 are supported.

### dynamodb-s3-import-three-formats [IN] OBSERVATION
DynamoDB S3 import supports three data formats: CSV, DynamoDB JSON, and Amazon Ion.

### dynamodb-s3-offload-no-cross-service-transactions [IN] OBSERVATION
DynamoDB does not support transactions spanning S3 and DynamoDB; applications must handle orphaned S3 objects themselves.

### dynamodb-same-account-global-table-consistency-chosen-at-creation [IN] OBSERVATION
DynamoDB same-account global tables require choosing between MREC and MRSC consistency mode at creation time.

### dynamodb-scan-1mb-page-128-rcu-eventual-256-strong [IN] OBSERVATION
A 1 MB eventually consistent DynamoDB Scan of 4 KB items consumes 128 RCUs; strongly consistent consumes 256 RCUs.

### dynamodb-scan-1mb-page-limit [IN] OBSERVATION
Each DynamoDB Scan request reads up to 1 MB of data before returning; pagination via `LastEvaluatedKey`/`ExclusiveStartKey` is required for larger datasets.

### dynamodb-scan-charges-evaluated-not-returned [IN] OBSERVATION
DynamoDB `Scan` charges capacity based on items evaluated, not items returned after filtering.

### dynamodb-scan-consistent-read-not-on-gsi [IN] OBSERVATION
DynamoDB Scan supports `ConsistentRead=true` for strongly consistent reads on base tables and LSIs, but setting it on a GSI throws `ValidationException`.

### dynamodb-scan-filter-does-not-reduce-rcu [IN] OBSERVATION
DynamoDB Scan `FilterExpression` is applied after items are read — it does not reduce consumed read capacity units, only reduces data returned to the caller.

### dynamodb-scan-index-forward-false-descending [IN] OBSERVATION
Setting `ScanIndexForward=false` on a DynamoDB Query reverses the sort key order to descending.

### dynamodb-scan-limit-controls-evaluated-not-returned [IN] OBSERVATION
The DynamoDB Scan `Limit` parameter caps items evaluated, not items returned — fewer matching items may come back than the Limit value.

### dynamodb-scan-no-snapshot-isolation [IN] OBSERVATION
Even with `ConsistentRead=true`, a DynamoDB Scan does not guarantee a consistent snapshot across the entire table — consistency is at the item level only.

### dynamodb-scan-reads-entire-table-then-filters [IN] OBSERVATION
DynamoDB Scan always reads the entire table or secondary index then filters out unwanted results — you pay for reading everything, not just what matches.

### dynamodb-scan-same-pagination-as-query [IN] OBSERVATION
DynamoDB Scan operations use the same `LastEvaluatedKey`/`ExclusiveStartKey` pagination pattern as Query operations.

### dynamodb-scanindexforward-false-descending [IN] OBSERVATION
DynamoDB Query parameter ScanIndexForward defaults to true (ascending sort key order); setting it to false returns results in descending order.

### dynamodb-schema-design-access-pattern-driven [IN] OBSERVATION
DynamoDB schema design must start from known access patterns before designing the schema — the opposite of RDBMS where you normalize first and optimize later.

### dynamodb-schema-design-starts-with-access-patterns [IN] OBSERVATION
DynamoDB schema design requires identifying all access patterns before designing the table structure, unlike RDBMS where you normalize first — each access pattern should be servable by a single query.

### dynamodb-schemaless-beyond-primary-key [IN] OBSERVATION
DynamoDB is schemaless beyond the primary key — items in the same table can have different attributes and data types with no schema definition required.

### dynamodb-sdk-builtin-retry-logic [IN] OBSERVATION
AWS SDKs for DynamoDB provide built-in retry logic and error handling, handling request formatting and response parsing automatically.

### dynamodb-sdks-recommended-over-low-level-api [IN] OBSERVATION
AWS recommends using SDKs rather than calling the DynamoDB low-level API directly; SDKs handle authentication, serialization, and connection management automatically.

### dynamodb-secondary-indexes-inherit-table-class [IN] OBSERVATION
DynamoDB secondary indexes (GSI/LSI) inherit the table class of their parent table — you cannot set a different class per index.

### dynamodb-select-count-same-rcu-as-read [IN] OBSERVATION
DynamoDB `SELECT COUNT` in a Scan still consumes the same RCUs as reading the full items.

### dynamodb-sets-unique-same-type-no-empty [IN] OBSERVATION
DynamoDB Set types require all elements to be the same type with unique values; empty sets are not allowed.

### dynamodb-shorter-attribute-names-reduce-costs [IN] OBSERVATION
Shorter DynamoDB attribute names reduce both storage costs and RCU/WCU consumption because attribute name length is included in item size calculations.

### dynamodb-single-table-design-preferred [IN] OBSERVATION
DynamoDB best practice is to maintain as few tables as possible (single-table design preferred); exceptions include high-volume time series data or datasets with very different access patterns.

### dynamodb-single-table-design-recommended [IN] OBSERVATION
DynamoDB best practices recommend minimizing the number of tables, with single-table design as the default recommendation.

### dynamodb-slr-deny-breaks-global-table-replication [IN] OBSERVATION
Denying the DynamoDB service-linked role's replication action in a resource-based policy causes global table replica add/delete operations to fail.

### dynamodb-soft-limit-2500-tables [IN] OBSERVATION
DynamoDB has a soft account quota of 2,500 tables.

### dynamodb-soft-quota-2500-tables-per-account [IN] OBSERVATION
DynamoDB has a soft account quota of 2,500 tables.

### dynamodb-soft-table-quota-2500 [IN] OBSERVATION
DynamoDB has a soft account quota of 2,500 tables.

### dynamodb-sort-key-defines-physical-ordering [IN] OBSERVATION
DynamoDB sort keys define the physical ordering of items within a partition, making range queries on the sort key very efficient.

### dynamodb-sort-key-range-boundaries-plaintext [IN] OBSERVATION
Some DynamoDB sort key values marking range boundaries are stored in plaintext in table metadata, even with encryption at rest enabled.

### dynamodb-sort-key-range-operators [IN] OBSERVATION
DynamoDB sort keys support range queries using the operators `begins_with`, `between`, `>`, `<`, and `=` in Query key conditions.

### dynamodb-sparse-index-omits-items-without-key [IN] OBSERVATION
DynamoDB sparse indexes only contain items that have the index key attributes — items without those attributes are automatically omitted from the index.

### dynamodb-sse-false-means-aws-owned-key [IN] OBSERVATION
Setting `--sse-specification Enabled=false` on a DynamoDB table switches to the AWS owned key — it does not disable encryption.

### dynamodb-standard-ia-table-class-lower-storage-higher-rw [IN] OBSERVATION
DynamoDB Standard-IA table class lowers storage costs but has higher read/write costs compared to Standard, suitable for infrequently accessed tables.

### dynamodb-storage-in-cur-higher-than-describe-table [IN] OBSERVATION
DynamoDB storage values in Cost and Usage Reports are higher than those from `DescribeTable` because CUR includes per-item storage overhead.

### dynamodb-stream-arn-includes-timestamp [IN] OBSERVATION
DynamoDB stream ARNs include a timestamp component in the format `arn:aws:dynamodb:<region>:<account-id>:table/<TableName>/stream/<timestamp>`.

### dynamodb-stream-fan-out-constrained-by-ordering-and-capacity [IN] OBSERVATION
DynamoDB Streams impose simultaneous ordering constraints (parent shards must be processed before child shards) and capacity constraints (maximum 2 Lambda consumers per stream before throttling), limiting event-driven architectures that require both high fan-out and strictly ordered processing to at most 2 ordered consumers.

### dynamodb-stream-filter-numeric-comparison-broken [IN] OBSERVATION
Numeric comparison operators do not work for DynamoDB stream event filters because DynamoDB stores numbers as strings (e.g., `"quantity": {"N": "50"}`).

### dynamodb-stream-filter-requires-new-and-old-images [IN] OBSERVATION
StreamViewType `NEW_AND_OLD_IMAGES` is required to filter on `NewImage` or `OldImage` data properties in Lambda event source mapping filters.

### dynamodb-stream-lambda-four-iam-permissions [IN] OBSERVATION
Lambda functions consuming DynamoDB Streams require four specific permissions: `dynamodb:DescribeStream`, `dynamodb:GetRecords`, `dynamodb:GetShardIterator`, and `dynamodb:ListStreams`.

### dynamodb-stream-max-2-lambda-consumers [IN] OBSERVATION
A maximum of 2 Lambda functions can subscribe to a single DynamoDB stream before read throttling occurs.

### dynamodb-stream-policy-cannot-attach-at-creation [IN] OBSERVATION
Resource-based policies cannot be attached to a DynamoDB stream during `CreateTable` or `UpdateTable` — only after the stream exists via `PutResourcePolicy`.

### dynamodb-stream-policy-persists-after-table-deletion [IN] OBSERVATION
DynamoDB stream resource-based policies persist and can be modified or deleted even after the parent table is deleted or the stream is disabled.

### dynamodb-streams-24-hour-data-retention [IN] OBSERVATION
DynamoDB Streams retains stream records for 24 hours only; accessing data older than 24 hours raises `TrimmedDataAccessException`.

### dynamodb-streams-24-hour-retention [IN] OBSERVATION
DynamoDB Streams retains stream records for exactly 24 hours with no configurable retention and no manual deletion mechanism.

### dynamodb-streams-apache-flink-connector [IN] OBSERVATION
DynamoDB Streams can be consumed by Apache Flink via a dedicated connector, using Amazon Managed Service for Apache Flink (formerly Kinesis Data Analytics for Apache Flink).

### dynamodb-streams-api-separate-endpoint [IN] OBSERVATION
DynamoDB Streams uses a separate API with its own endpoint (`streams.dynamodb.<region>.amazonaws.com`) and service name (`dynamodbstreams`), distinct from the main DynamoDB API.

### dynamodb-streams-api-similar-not-identical-to-kinesis [IN] OBSERVATION
The DynamoDB Streams API is intentionally similar but not 100% identical to the Kinesis Data Streams API — both have ListStreams, DescribeStream, GetShards, and GetShardIterator.

### dynamodb-streams-auto-delete-24h-after-table-deletion [IN] OBSERVATION
When a DynamoDB table is deleted, associated streams enter `DISABLED` state and are automatically deleted after 24 hours.

### dynamodb-streams-consumption-requires-fragile-client-protocol [IN] OBSERVATION
DynamoDB Streams consumption requires implementing a fragile multi-step client protocol: obtain shard iterators (which expire after 15 minutes of inactivity), issue GetRecords calls (bounded by 1 MB or 1,000 records), and respect API rate limits (DescribeStream at 10 TPS) — each constraint independently causes data loss or processing stalls if not handled defensively.

### dynamodb-streams-data-plane-requires-explicit-logging [IN] OBSERVATION
DynamoDB Streams control plane operations (DescribeStream, ListStreams) are logged by default; data plane operations (GetRecords, GetShardIterator) require explicit data event logging in CloudTrail.

### dynamodb-streams-describe-stream-rate-limit-10tps [IN] OBSERVATION
The DynamoDB Streams `DescribeStream` API is rate-limited to 10 calls per second.

### dynamodb-streams-disable-reenable-new-arn [IN] OBSERVATION
Disabling and re-enabling a DynamoDB stream creates a completely new stream with a different ARN.

### dynamodb-streams-exactly-four-actions [IN] OBSERVATION
The DynamoDB Streams API has exactly four actions: DescribeStream, GetRecords, GetShardIterator, and ListStreams.

### dynamodb-streams-four-iterator-types [IN] OBSERVATION
`GetShardIterator` supports four iterator types: `TRIM_HORIZON` (oldest untrimmed), `LATEST` (only new), `AT_SEQUENCE_NUMBER` (exact), and `AFTER_SEQUENCE_NUMBER` (immediately after).

### dynamodb-streams-four-view-types [IN] OBSERVATION
DynamoDB Streams `StreamViewType` controls captured data: `KEYS_ONLY`, `NEW_IMAGE`, `OLD_IMAGE`, or `NEW_AND_OLD_IMAGES`.

### dynamodb-streams-getrecords-max-1mb-or-1000 [IN] OBSERVATION
`GetRecords` returns up to 1 MB of data or 1,000 stream records per call, whichever limit is reached first.

### dynamodb-streams-kcl-recommended-consumer [IN] OBSERVATION
The recommended way to consume DynamoDB Streams is via the Kinesis Adapter + KCL, not raw API calls.

### dynamodb-streams-kcl-recommended-over-low-level [IN] OBSERVATION
AWS recommends using the Kinesis Client Library (KCL) adapter instead of the low-level DynamoDB Streams API for production use, as KCL handles shard management, checkpointing, and failover automatically.

### dynamodb-streams-kinesis-adapter-redirects-to-streams-endpoint [IN] OBSERVATION
The DynamoDB Streams Kinesis Adapter implements the Kinesis Data Streams interface, redirecting KCL API calls to the DynamoDB Streams endpoint transparently.

### dynamodb-streams-lambda-and-replication-reads-free [IN] OBSERVATION
DynamoDB Streams `GetRecords` calls invoked by Lambda triggers or global table replication are not charged.

### dynamodb-streams-lambda-not-exactly-once [IN] OBSERVATION
DynamoDB Streams + Lambda does not guarantee exactly-once delivery — duplicate records are possible, so Lambda function code must be idempotent.

### dynamodb-streams-list-streams-rate-limit-5tps [IN] OBSERVATION
The DynamoDB Streams `ListStreams` API is rate-limited to 5 calls per second, returning up to 100 streams per response.

### dynamodb-streams-low-level-api-separate-client [IN] OBSERVATION
DynamoDB Streams requires a separate `DynamoDbStreamsClient` from the standard `DynamoDbClient`, connecting to a different endpoint.

### dynamodb-streams-max-2-concurrent-readers-per-shard [IN] OBSERVATION
DynamoDB Streams supports a maximum of 2 concurrent readers per shard before throttling occurs.

### dynamodb-streams-max-2-concurrent-shard-readers [IN] OBSERVATION
DynamoDB Streams allows a maximum of 2 processes reading from the same shard concurrently; exceeding this causes throttling.

### dynamodb-streams-max-2-readers-per-shard [IN] OBSERVATION
DynamoDB Streams supports a maximum of 2 simultaneous readers per shard (1 for global tables).

### dynamodb-streams-noop-writes-skipped [IN] OBSERVATION
DynamoDB PutItem/UpdateItem operations that don't change data produce no stream record.

### dynamodb-streams-null-iterator-shard-sealed [IN] OBSERVATION
A DynamoDB Streams shard iterator becomes null when the shard is sealed (READ_ONLY); child shards must be fetched to continue reading.

### dynamodb-streams-parent-before-child-ordering [IN] OBSERVATION
DynamoDB Streams parent shards must be processed before child shards to preserve correct item-level ordering.

### dynamodb-streams-read-two-step-iterator-records [IN] OBSERVATION
Reading from DynamoDB Streams requires a two-step process: GetShardIterator to obtain an iterator, then GetRecords to retrieve stream records.

### dynamodb-streams-records-retained-24-hours [IN] OBSERVATION
DynamoDB Streams records are retained for 24 hours.

### dynamodb-streams-separate-api-endpoint [IN] OBSERVATION
DynamoDB Streams has its own API endpoint (`streams.dynamodb.<region>.amazonaws.com`) and service model (`DynamoDBStreams_20120810`), separate from the main DynamoDB API.

### dynamodb-streams-shard-iterator-expires-15-minutes [IN] OBSERVATION
DynamoDB Streams shard iterators expire after 15 minutes of inactivity and must be re-acquired via `GetShardIterator`.

### dynamodb-streams-shard-open-vs-closed [IN] OBSERVATION
A DynamoDB Streams shard with only a `StartingSequenceNumber` is open (still receiving records); a shard with both `StartingSequenceNumber` and `EndingSequenceNumber` is closed.

### dynamodb-streams-view-type-immutable [IN] OBSERVATION
DynamoDB StreamViewType (KEYS_ONLY, NEW_IMAGE, OLD_IMAGE, NEW_AND_OLD_IMAGES) cannot be changed after stream creation; the stream must be disabled and a new one created.

### dynamodb-strong-consistency-tables-and-lsis-only [IN] OBSERVATION
DynamoDB strongly consistent reads are supported on tables and Local Secondary Indexes (LSIs) only — not on GSIs or DynamoDB Streams.

### dynamodb-table-and-stream-policies-separate [IN] OBSERVATION
DynamoDB table and stream resource-based policies are separate — they must be attached independently as distinct policy documents.

### dynamodb-table-class-changeable-after-creation [IN] OBSERVATION
DynamoDB table class can be changed after table creation via Console, CLI, or SDK — it is not a permanent decision.

### dynamodb-table-multiple-kinesis-streaming-destinations [IN] OBSERVATION
A single DynamoDB table can have multiple Kinesis Data Streams streaming destinations simultaneously.

### dynamodb-table-name-3-255-chars-alphanumeric [IN] OBSERVATION
DynamoDB table names must be 3–255 characters matching the pattern `[a-zA-Z0-9_.-]+`.

### dynamodb-table-name-constraints-3-255-chars [IN] OBSERVATION
DynamoDB table names must be 3–255 characters matching the pattern `[a-zA-Z0-9_.-]+`.

### dynamodb-table-names-unique-per-account-region [IN] OBSERVATION
DynamoDB table names must be unique per AWS account and Region combination; identically named tables in different Regions are entirely separate.

### dynamodb-table-names-unique-per-region [IN] OBSERVATION
DynamoDB table names must be unique per Region but can be duplicated across Regions.

### dynamodb-table-policy-cascades-to-indexes [IN] OBSERVATION
Removing a DynamoDB table's resource-based policy also removes permissions for that table's indexes, since index permissions are defined within the table's policy.

### dynamodb-table-policy-covers-indexes [IN] OBSERVATION
A DynamoDB resource-based policy attached to a table also implicitly covers its indexes.

### dynamodb-table-size-unlimited [IN] OBSERVATION
DynamoDB tables have no practical size limit — table size is unlimited in terms of items and bytes.

### dynamodb-table-status-must-be-active-before-use [IN] OBSERVATION
DynamoDB tables transition from CREATING to ACTIVE status; the table must be ACTIVE before it can accept read/write operations.

### dynamodb-tablename-dimension-excludes-gsi [IN] OBSERVATION
The CloudWatch TableName dimension alone returns capacity metrics for the base table only, not GSIs — you must specify both TableName and GlobalSecondaryIndexName dimensions for GSI metrics.

### dynamodb-tag-resource-eventually-consistent-5tps [IN] OBSERVATION
DynamoDB `TagResource` is asynchronous and eventually consistent; it has a rate limit of 5 calls per second per account.

### dynamodb-tagging-eventually-consistent [IN] OBSERVATION
DynamoDB tagging operations (TagResource, UntagResource, ListTagsOfResource) are eventually consistent — tag changes may not be immediately reflected.

### dynamodb-tagging-rate-limit-5-per-second [IN] OBSERVATION
DynamoDB tagging operations (TagResource/UntagResource) are rate-limited to 5 calls per second per account.

### dynamodb-tags-for-cost-allocation-not-access-control [IN] OBSERVATION
DynamoDB tags are used for cost allocation tracking in the Billing and Cost Management console, not for access control (unlike IAM tags/ABAC).

### dynamodb-three-encryption-key-types [IN] OBSERVATION
DynamoDB supports three encryption key types: AWS owned keys (free, no audit), AWS managed keys (`aws/dynamodb`, auditable via CloudTrail), and customer managed keys (full control over policies, rotation, grants).

### dynamodb-three-table-design-approaches [IN] OBSERVATION
DynamoDB has three table design approaches: single-table design (composite sort keys, overloaded GSIs), multi-table design (separate tables for independent operational needs), and aggregate design (embed related data accessed together).

### dynamodb-throttling-four-scenarios [IN] OBSERVATION
DynamoDB has four throttling scenarios: (1) key range throughput exceeded (both modes), (2) provisioned throughput exceeded (provisioned only), (3) account-level service quotas exceeded (on-demand only), and (4) on-demand max throughput exceeded (on-demand only).

### dynamodb-time-series-special-table-design [IN] OBSERVATION
DynamoDB time-series data requires special table design to avoid hot partitions (e.g., separate tables per time period or sharded partition keys).

### dynamodb-time-series-table-per-period-pattern [IN] OBSERVATION
For time series data, DynamoDB recommends one table per time period (an exception to the single-table guideline), with prebuilt next-period tables, capacity scale-down on older tables (e.g., to 1 WCU), and eventual archival/deletion.

### dynamodb-total-cost-multiplies-across-six-independent-dimensions [IN] OBSERVATION
DynamoDB cost is affected by multiple billing factors — capacity overhead from rounding and GSI minimums, consistency mode choice, transaction multipliers, and item size calculations — that apply sequentially to the same operations, compounding the effective cost.

### dynamodb-transact-get-conflict-cancels-not-retries [IN] OBSERVATION
Concurrent write operations on items being read by `TransactGetItems` cause `TransactionCanceledException` — this is a hard failure, not an automatically retried error.

### dynamodb-transact-get-items-100-items-4mb [IN] OBSERVATION
`TransactGetItems` supports up to 100 items per request with a 4 MB aggregate size limit, across one or more tables within a single account and Region.

### dynamodb-transact-get-items-no-indexes [IN] OBSERVATION
`TransactGetItems` cannot read from indexes (GSI or LSI) — only base tables are supported.

### dynamodb-transaction-100-items-4mb-limit [IN] OBSERVATION
DynamoDB transactions (`TransactWriteItems` and `TransactGetItems`) support up to 100 actions targeting up to 100 distinct items with a 4 MB aggregate size limit.

### dynamodb-transaction-2x-capacity-cost [IN] OBSERVATION
Each item in a DynamoDB transaction consumes 2x capacity (one prepare phase + one commit phase) — 2 WCUs per write or 2 RCUs per read.

### dynamodb-transaction-all-or-nothing [IN] OBSERVATION
DynamoDB transactions are all-or-nothing — if any action's condition fails, the entire transaction is canceled with no partial execution.

### dynamodb-transaction-canceled-exception [IN] OBSERVATION
TransactionCanceledException is thrown when one or more conditions in a DynamoDB transaction are not met, canceling the entire transaction.

### dynamodb-transaction-cancellation-reasons-positional [IN] OBSERVATION
DynamoDB `CancellationReason` entries in `TransactionCanceledException` are positionally ordered to match the original request items; successful items show Null code/message (not omitted).

### dynamodb-transaction-cancelled-exception-no-auto-retry [IN] OBSERVATION
SDKs do not automatically retry `TransactionCanceledException` in DynamoDB.

### dynamodb-transaction-cannot-target-same-item-twice [IN] OBSERVATION
A single DynamoDB transaction cannot target the same item with multiple operations.

### dynamodb-transaction-four-action-types [IN] OBSERVATION
TransactWriteItems supports four action types: Put (write new item), Update (modify existing), Delete (remove item), and ConditionCheck (validate without modifying).

### dynamodb-transaction-idempotency-token-10-minutes [IN] OBSERVATION
TransactWriteItems supports idempotency via `ClientRequestToken` (1–36 chars), valid for 10 minutes; reusing a token with different parameters raises `IdempotentParameterMismatch`.

### dynamodb-transaction-max-100-actions [IN] OBSERVATION
DynamoDB transactions support up to 100 actions per request — both TransactWriteItems (100 write actions) and TransactGetItems (100 read actions).

### dynamodb-transaction-no-duplicate-items [IN] OBSERVATION
No two actions within a single DynamoDB transaction can target the same item.

### dynamodb-transaction-region-local-acid-only [IN] OBSERVATION
DynamoDB transaction ACID guarantees apply only within the Region where the write was invoked — cross-region replicas in global tables may show partial transactions during replication.

### dynamodb-transaction-same-account-region-only [IN] OBSERVATION
DynamoDB transactions (TransactWriteItems/TransactGetItems) can span multiple tables but are limited to the same AWS account and Region — no cross-account or cross-Region transactions.

### dynamodb-transaction-serializable-individual-read-committed-batch [IN] OBSERVATION
DynamoDB provides serializable isolation between transactions and individual standard operations (`GetItem`, `PutItem`, etc.), but only read-committed isolation between transactions and multi-item reads (`Query`, `Scan`, `BatchGetItem`).

### dynamodb-transaction-streams-not-atomic [IN] OBSERVATION
DynamoDB Streams does not preserve transaction atomicity — stream records from a transaction may appear at different times and interleave with other transactions.

### dynamodb-transactional-reads-quadruple-cost-vs-eventually-consistent [IN] OBSERVATION
DynamoDB transactional reads cost 4x more than eventually consistent reads (2 RCU vs 0.5 RCU per 4 KB), making consistency choice the single largest per-read cost lever.

### dynamodb-transactional-writes-2x-cost [IN] OBSERVATION
DynamoDB transactional writes cost 2 WCU per 1 KB (double the standard 1 WCU per 1 KB).

### dynamodb-transactions-100-item-limit-no-begin-end [IN] OBSERVATION
DynamoDB transactions (TransactWriteItems and TransactGetItems) are limited to 100 items per transaction call and have no begin/end semantics unlike RDBMS transactions.

### dynamodb-transactions-all-or-nothing [IN] OBSERVATION
DynamoDB transactions (`TransactWriteItems`/`TransactGetItems`) are all-or-nothing: if any item fails, the entire transaction is cancelled and all cancellation reasons are reported.

### dynamodb-transactions-bounded-atomicity-envelope [IN] OBSERVATION
DynamoDB transactions provide cross-table ACID guarantees within a fixed envelope: maximum 100 actions per transaction, 4 MB aggregate size, no duplicate item targeting, and exactly four action types — schema design must ensure all atomic business operations fit within these constraints or forfeit transactional guarantees.

### dynamodb-transactions-consume-read-and-write-capacity [IN] OBSERVATION
DynamoDB transactions consume both read and write capacity — reads for condition checks and writes for mutations.

### dynamodb-transactions-cross-table-support [IN] OBSERVATION
DynamoDB transactions can span multiple tables within a single atomic operation.

### dynamodb-transactions-no-cross-account-cross-region [IN] OBSERVATION
DynamoDB transactions do not support cross-account or cross-region operations — a table in a different account or region causes TransactionCanceledException.

### dynamodb-transactions-up-to-100-items-acid [IN] OBSERVATION
DynamoDB transactions (TransactGetItems, TransactWriteItems) provide ACID guarantees across up to 100 items.

### dynamodb-transactwriteitems-100-items [IN] OBSERVATION
`TransactWriteItems` supports up to 100 items per transaction and is all-or-nothing (transactional), unlike `BatchWriteItem` which allows partial failures.

### dynamodb-transactwriteitems-all-or-nothing [IN] OBSERVATION
TransactWriteItems provides multi-item atomic writes with all-or-nothing semantics, suited for moderate contention scenarios.

### dynamodb-transactwriteitems-four-action-types [IN] OBSERVATION
TransactWriteItems supports four action types: Put, Update, Delete, and ConditionCheck.

### dynamodb-transactwriteitems-max-100-actions-4mb [IN] OBSERVATION
TransactWriteItems supports up to 100 actions per transaction with a maximum aggregate size of 4 MB; individual items are limited to 400 KB.

### dynamodb-ttl-creates-invisible-asymmetric-cost-mutations [IN] OBSERVATION
DynamoDB TTL deletions appear free (no local WCU consumed, no CloudTrail log entries) but actually consume WCU on global table replicas, creating a category of mutations that is cost-free in one region, cost-bearing in all others, and audit-invisible everywhere — a hidden cost vector undetectable by either billing analysis or security audit.

### dynamodb-ttl-delete-no-wcu-local-but-wcu-on-replicas [IN] OBSERVATION
DynamoDB TTL deletes do not consume WCU in the region where the delete occurred, but do consume WCU on replicated replicas.

### dynamodb-ttl-deletes-at-no-cost [IN] OBSERVATION
DynamoDB TTL deletes aged-out items at no cost, relevant for both cost optimization and sustainability.

### dynamodb-ttl-deletion-within-48-hours [IN] OBSERVATION
DynamoDB TTL-expired items are deleted on a best-effort basis, typically within 48 hours of expiration; until deleted, expired items remain visible in reads, queries, and scans.

### dynamodb-ttl-deletions-generate-stream-records [IN] OBSERVATION
DynamoDB TTL deletions can generate stream records for downstream processing via DynamoDB Streams.

### dynamodb-ttl-deletions-not-logged-cloudtrail [IN] OBSERVATION
DynamoDB TTL data plane deletion actions are NOT logged by CloudTrail.

### dynamodb-ttl-epoch-seconds-format [IN] OBSERVATION
The DynamoDB TTL attribute must store values in epoch second format (seconds since 1970-01-01 00:00:00 UTC), not milliseconds.

### dynamodb-ttl-four-statuses [IN] OBSERVATION
DynamoDB TTL has four possible statuses: `ENABLED`, `DISABLED`, `ENABLING`, and `DISABLING` — it has transitional states, not just on/off.

### dynamodb-ttl-no-write-throughput-consumed [IN] OBSERVATION
DynamoDB TTL deletions do not consume write throughput — they are performed as a background, best-effort process.

### dynamodb-ttl-one-update-per-table-per-hour [IN] OBSERVATION
Only one `UpdateTimeToLive` call per DynamoDB table per hour is allowed; additional calls during the propagation window raise `ValidationException`.

### dynamodb-ttl-stream-useridentity-only-source-region [IN] OBSERVATION
In DynamoDB global tables, the `userIdentity` field on TTL stream records is set only in the region where the TTL deletion occurred — replicated deletes in other regions do not have this field.

### dynamodb-ttl-stream-useridentity-service-principal [IN] OBSERVATION
TTL-deleted items in DynamoDB Streams are identifiable by `userIdentity.type = "Service"` and `userIdentity.principalId = "dynamodb.amazonaws.com"`.

### dynamodb-two-cdc-options-streams-and-kinesis [IN] OBSERVATION
DynamoDB offers two change data capture (CDC) options: DynamoDB Streams and Kinesis Data Streams for DynamoDB.

### dynamodb-two-table-classes-standard-and-ia [IN] OBSERVATION
DynamoDB has two table classes: STANDARD (default) and STANDARD_INFREQUENT_ACCESS.

### dynamodb-two-table-classes-standard-and-standard-ia [IN] OBSERVATION
DynamoDB offers two table classes: Standard (default) and Standard-Infrequent Access (Standard-IA), where Standard-IA has lower storage costs but higher read/write costs.

### dynamodb-unconditional-allow-overrides-conditional-resource-policy [IN] OBSERVATION
An unconditional Allow in an identity-based policy overrides conditional Allow statements in a DynamoDB resource-based policy — use explicit Deny instead of conditional Allow to enforce restrictions like attribute-level access.

### dynamodb-update-capacity-based-on-larger-size [IN] OBSERVATION
Consumed capacity for an UpdateItem is based on the larger of the item size before or after the update, rounded up to 1 KB for standard tables.

### dynamodb-update-expression-four-actions [IN] OBSERVATION
Update expressions support four actions: SET, REMOVE, ADD, and DELETE.

### dynamodb-update-table-fully-available [IN] OBSERVATION
DynamoDB tables remain fully available during UpdateTable operations (UPDATING status does not block reads/writes).

### dynamodb-updateexpression-four-actions [IN] OBSERVATION
DynamoDB `UpdateExpression` supports four action types: `SET` (add/replace attributes), `REMOVE` (delete attributes), `ADD` (increment numbers or add to sets), and `DELETE` (remove elements from sets).

### dynamodb-updateglobaltable-legacy-2017-api [IN] OBSERVATION
`UpdateGlobalTable` is a legacy API (version 2017.11.29) for adding/removing replicas; current global tables (version 2019.11.21) use `UpdateTable` instead.

### dynamodb-updateitem-charges-larger-of-before-after [IN] OBSERVATION
DynamoDB `UpdateItem` consumes capacity based on the larger of the before or after item size, even if only updating one small attribute on a large item.

### dynamodb-updateitem-upsert-behavior [IN] OBSERVATION
DynamoDB `UpdateItem` creates the item if the primary key doesn't exist (upsert behavior); otherwise it modifies the existing item's attributes.

### dynamodb-updatetable-blocked-during-updating [IN] OBSERVATION
DynamoDB table is blocked from further `UpdateTable` calls while in `UPDATING` state (transitions ACTIVE → UPDATING → ACTIVE).

### dynamodb-updatetable-one-gsi-change-per-call [IN] OBSERVATION
DynamoDB `UpdateTable` allows only one GSI create or delete per call; throughput updates on existing GSIs can be batched in a single call.

### dynamodb-version-control-v0-prefix-pattern [IN] OBSERVATION
DynamoDB version control pattern maintains two copies per item: a `v0_` prefixed sort key (always overwritten with latest revision) and versioned copies (`v1_`, `v2_`, etc.) for history, enabling latest-version retrieval via `begins_with(SK, "v0_")`.

### dynamodb-vpc-endpoint-returns-private-address [IN] OBSERVATION
When using interface VPC endpoints for DynamoDB, `DescribeEndpoints` returns the private endpoint address instead of the public one.

### dynamodb-warm-throughput-cannot-decrease [IN] OBSERVATION
DynamoDB warm throughput values cannot be decreased once increased — pre-warming is irreversible.

### dynamodb-warm-throughput-default-free [IN] OBSERVATION
Default DynamoDB warm throughput (based on historical usage) is provided at no additional cost; only proactive pre-warming incurs charges.

### dynamodb-warm-throughput-no-capacity-mode-change [IN] OBSERVATION
DynamoDB pre-warming works with both on-demand and provisioned capacity modes without requiring a mode change.

### dynamodb-wcu-1kb-standard-2kb-transactional [IN] OBSERVATION
DynamoDB write capacity is based on item size: 1 WCU = 1 KB for standard writes, 2 WCUs per KB for transactional writes.

### dynamodb-write-cost-full-item-size [IN] OBSERVATION
DynamoDB write cost is proportional to the full item size, not just the changed attributes.

### dynamodb-zero-etl-no-aws-managed-key [IN] OBSERVATION
DynamoDB zero-ETL integration with Redshift requires the source table encryption to use an Amazon-owned key or customer-managed KMS key; AWS managed keys are not supported.

### dynamodb-zero-etl-redshift-15-30-min-sync [IN] OBSERVATION
DynamoDB zero-ETL integration with Redshift replicates incremental updates every 15–30 minutes using DynamoDB incremental exports, not in real-time.

### dynamodb-zero-etl-redshift-requires-pitr [IN] OBSERVATION
DynamoDB zero-ETL integration with Redshift requires Point-in-Time Recovery (PITR) to be enabled on the source table as a hard prerequisite.

### dynamodb-zero-etl-redshift-same-region-only [IN] OBSERVATION
DynamoDB zero-ETL integration with Redshift requires the source table and target Redshift database to be in the same AWS Region.

### ebs-accessed-via-ec2-console [IN] OBSERVATION
EBS is not a standalone service in the AWS console — it is accessed through the EC2 console.

### ebs-backed-spot-can-be-stopped-restarted [IN] OBSERVATION
EBS-backed Spot Instances can be stopped and restarted, not just terminated.

### ebs-data-lifecycle-manager-automates-snapshots [IN] OBSERVATION
Amazon Data Lifecycle Manager automates the creation, retention, and deletion of EBS snapshots and EBS-backed AMIs.

### ebs-direct-apis-snapshot-operations [IN] OBSERVATION
EBS Direct APIs allow creating snapshots, reading/writing snapshot data, and diffing two snapshots programmatically.

### ebs-elastic-volumes-live-resize [IN] OBSERVATION
Elastic Volumes allow live capacity increases and performance tuning of EBS volumes with no downtime.

### ebs-encryption-at-rest-and-transit [IN] OBSERVATION
EBS encryption covers data-at-rest on the volume, data-in-transit between the instance and the volume, and all subsequent snapshots.

### ebs-io2-durability-five-nines [IN] OBSERVATION
io2 Block Express volumes have 99.999% durability (0.001% annual failure rate), significantly higher than other EBS volume types at 99.8%–99.9%.

### ebs-other-volume-durability-99-8-to-99-9 [IN] OBSERVATION
Non-io2 EBS volume types have 99.8%–99.9% durability (0.1%–0.2% annual failure rate).

### ebs-pay-only-for-provisioned [IN] OBSERVATION
EBS billing is based on provisioned capacity — you pay only for what you provision, not what you consume.

### ebs-recycle-bin-recover-deleted-snapshots [IN] OBSERVATION
Recycle Bin can recover accidentally deleted EBS snapshots and EBS-backed AMIs.

### ebs-snapshot-archive-90-day-minimum [IN] OBSERVATION
EBS Snapshots Archive is a low-cost storage tier that requires a minimum 90-day retention period.

### ebs-snapshots-cross-region-account-az [IN] OBSERVATION
EBS snapshots can be used to migrate data across accounts, Regions, and Availability Zones.

### ebs-snapshots-persist-independently [IN] OBSERVATION
EBS snapshots persist independently from the source volume — the volume can be deleted and the snapshot remains.

### ebs-ssd-iops-hdd-throughput [IN] OBSERVATION
EBS volume types fall into two categories: SSD-backed (optimized for transactional workloads with high IOPS) and HDD-backed (optimized for throughput-intensive workloads).

### ebs-volumes-az-scoped [IN] OBSERVATION
EBS volumes are AZ-scoped — data is automatically replicated across multiple servers within a single Availability Zone, not across AZs.

### ec2-all-api-actions-management-events [IN] OBSERVATION
All EC2 API actions are logged as CloudTrail management events — there are no EC2-specific data events.

### ec2-api-query-based-not-restful [IN] OBSERVATION
The EC2 API is action-based (Query API) where each operation is a distinct named action invoked via HTTP query parameters, not RESTful resource paths.

### ec2-bare-metal-instances-longer-launch-time [IN] OBSERVATION
Bare metal EC2 instances take longer to launch than virtualized instances.

### ec2-basic-monitoring-5min-detailed-1min [IN] OBSERVATION
EC2 basic monitoring provides metrics at 5-minute intervals; detailed monitoring provides 1-minute intervals at additional cost.

### ec2-billing-starts-at-running-state [IN] OBSERVATION
EC2 billing starts when an instance enters the `running` state (not at launch request time) and stops at `stopped` state (for stop) or `shutting-down` state (for terminate).

### ec2-client-internal-error-means-kms-key-issue [IN] OBSERVATION
The termination reason `Client.InternalError: Client error on launch` indicates missing KMS key permissions on encrypted EBS volumes.

### ec2-create-snapshot-vs-create-snapshots [IN] OBSERVATION
EC2 `CreateSnapshot` creates one snapshot of one volume; `CreateSnapshots` (plural) creates multi-volume snapshots for point-in-time consistency across volumes.

### ec2-dedicated-hosts-for-byol [IN] OBSERVATION
EC2 Dedicated Hosts provide a physical server for compliance requirements and bring-your-own-license (BYOL) scenarios.

### ec2-force-stop-requires-fsck [IN] OBSERVATION
EC2 `StopInstances` with `Force=true` forcibly stops an instance stuck in the `stopping` state but requires subsequent file system check and repair.

### ec2-free-tier-differs-by-account-creation-date [IN] OBSERVATION
EC2 Free Tier depends on account creation date: before July 15, 2025 gets t2.micro for 12 months; on/after July 15, 2025 gets t3.micro, t3.small, t4g.micro, t4g.small, c7i-flex.large, m7i-flex.large for 6 months or until credits exhausted.

### ec2-graviton-arm-best-price-performance [IN] OBSERVATION
AWS Graviton instances (denoted by 'g' in the type name, e.g., M7g, C7g) are ARM-based processors designed for best price-performance.

### ec2-guardduty-threat-detection [IN] OBSERVATION
Amazon GuardDuty provides threat detection for EC2 instances.

### ec2-hibernate-preserves-ram-to-ebs [IN] OBSERVATION
EC2 hibernation (`Hibernate=true` on StopInstances) preserves RAM contents to the root EBS volume; normal stop does not preserve RAM. Requires pre-enabled hibernation and an encrypted root volume.

### ec2-hpc-series-dedicated-family [IN] OBSERVATION
Hpc-series is a dedicated EC2 instance family for high-performance computing workloads.

### ec2-hvm-preferred-over-pv [IN] OBSERVATION
HVM virtualization is always preferred over PV; HVM is required for enhanced networking and all current-generation instance types.

### ec2-imdsv2-enforcement-modify-instance-metadata-defaults [IN] OBSERVATION
Account-level IMDSv2 enforcement uses the `ModifyInstanceMetadataDefaults` API with `httpTokensEnforced`; instances must launch with `httpTokens=required` when enforcement is enabled.

### ec2-instance-connect-audit-via-cloudtrail [IN] OBSERVATION
EC2 Instance Connect SSH sessions can be audited by filtering CloudTrail events by source `ec2-instance-connect.amazonaws.com` and event name `SendSSHPublicKey`.

### ec2-instance-limit-exceeded-vs-insufficient-capacity [IN] OBSERVATION
`InstanceLimitExceeded` is an account-side per-region limit (fix: request quota increase); `InsufficientInstanceCapacity` is an AWS-side capacity shortage (fix: try different AZ, smaller batch, or different instance type).

### ec2-instance-naming-convention [IN] OBSERVATION
EC2 instance type naming encodes family + generation + processor suffix + capabilities + size (e.g., c7gn.2xlarge = Compute optimized, 7th gen, Graviton, network-optimized, 2xlarge).

### ec2-instance-roles-deliver-creds-via-metadata [IN] OBSERVATION
EC2 instances should use instance roles instead of embedded access keys — temporary credentials are delivered via the instance metadata service.

### ec2-instance-status-check-monitors-guest-os [IN] OBSERVATION
EC2 instance status checks monitor the instance's software and network configuration and require customer action (reboot, OS-level fixes) to resolve.

### ec2-instance-store-backed-cannot-stop [IN] OBSERVATION
Instance store-backed EC2 instances cannot be stopped — they can only be terminated. EBS-backed instances can be stopped, started, and terminated.

### ec2-instance-store-data-lost-on-stop-hibernate-terminate [IN] OBSERVATION
EC2 instance store volumes are ephemeral — data is deleted when you stop, hibernate, or terminate the instance. EBS volumes persist.

### ec2-instance-type-change-requires-stop [IN] OBSERVATION
EC2 instance type can be changed after launch but requires stopping and restarting the instance.

### ec2-instances-region-specific [IN] OBSERVATION
EC2 instances are Region-specific — they exist only in the Region where they were created and only appear in that Region's console view.

### ec2-key-pair-public-stored-private-user [IN] OBSERVATION
EC2 stores the public key; the user is responsible for the private key — EC2 has no way to recover a lost private key.

### ec2-key-pairs-asymmetric-aws-holds-public [IN] OBSERVATION
EC2 key pairs use asymmetric encryption for secure login — AWS stores the public key and the user retains the private key.

### ec2-key-pairs-aws-stores-public-key-only [IN] OBSERVATION
EC2 key pairs use public/private key cryptography — AWS stores the public key, the user stores the private key.

### ec2-launch-requires-runinstances-and-passrole [IN] OBSERVATION
Launching an EC2 instance requires both `ec2:RunInstances` (with wildcard resource) and `iam:PassRole` (scoped to the role ARN) IAM permissions.

### ec2-linux-public-key-authorized-keys [IN] OBSERVATION
On Linux instances, the public key is placed in ~/.ssh/authorized_keys at first boot.

### ec2-mac-billing-at-dedicated-host-level [IN] OBSERVATION
EC2 Mac instance billing is at the Dedicated Host level — instances running on the host incur no additional charge.

### ec2-mac-dedicated-host-24-hour-minimum [IN] OBSERVATION
EC2 Mac Dedicated Hosts have a minimum 24-hour allocation period before they can be released.

### ec2-mac-instances-bare-metal-dedicated-host-only [IN] OBSERVATION
EC2 Mac instances are bare-metal instances that run exclusively on Dedicated Hosts, with exactly one Mac instance per Dedicated Host.

### ec2-mac-no-filevault-use-ebs-encryption [IN] OBSERVATION
FileVault must never be enabled on EC2 Mac instances (causes boot failure); use EBS encryption instead.

### ec2-mac-no-spot-no-reserved-savings-plans-only [IN] OBSERVATION
EC2 Mac instances are not available as Spot or Reserved Instances; only On-Demand pricing with Savings Plans is supported.

### ec2-mac-system-monitor-not-on-apple-silicon [IN] OBSERVATION
EC2 System Monitor for macOS sends CPU metrics to CloudWatch every 1 minute but is not supported on Apple Silicon instances.

### ec2-managed-instances-cannot-modify [IN] OBSERVATION
EC2 managed instances (e.g., from EKS Auto Mode) are identified by `Managed = true` and cannot be directly modified by the user.

### ec2-mtu-1500-standard-9001-jumbo [IN] OBSERVATION
EC2 standard Ethernet frames support 1500 MTU; jumbo frames support 9001 MTU and are available on all current-generation instance types.

### ec2-nitro-current-gen-xen-previous [IN] OBSERVATION
Current-generation EC2 instances (5th gen+) use the Nitro hypervisor; previous generations (M1-M4, C1-C4, T1-T2, R3-R4, etc.) use Xen.

### ec2-on-demand-billing-per-second-60s-minimum [IN] OBSERVATION
EC2 On-Demand billing is per-second with a 60-second minimum.

### ec2-on-demand-capacity-reservations-no-term [IN] OBSERVATION
EC2 On-Demand Capacity Reservations reserve capacity in a specific Availability Zone without requiring a term commitment.

### ec2-p-series-gpu-training-g-series-graphics [IN] OBSERVATION
P-series instances (P4d, P5, P6) are GPU instances for ML training and HPC; G-series instances are GPU instances optimized for graphics and inference workloads.

### ec2-pay-per-instance-second [IN] OBSERVATION
EC2 billing is per instance-second.

### ec2-pci-dss-level-1-compliant [IN] OBSERVATION
Amazon EC2 is validated as PCI DSS Level 1 compliant.

### ec2-pending-to-terminated-four-causes [IN] OBSERVATION
An EC2 instance going directly from pending to terminated is caused by: EBS volume limit exceeded, corrupted EBS snapshot, missing KMS decrypt permissions on encrypted root/snapshot volumes, or missing instance-store-backed AMI parts in S3.

### ec2-per-second-billing-one-minute-minimum [IN] OBSERVATION
EC2 per-second billing applies with a one-minute minimum each time an instance is started.

### ec2-reboot-asynchronous-queued [IN] OBSERVATION
EC2 `RebootInstances` is asynchronous — it queues a reboot request and returns immediately; the API returning success does not mean the reboot is complete.

### ec2-reboot-hard-reboot-fallback [IN] OBSERVATION
EC2 performs a hard reboot automatically if an instance doesn't cleanly shut down within a few minutes of a reboot request — no separate API call is needed.

### ec2-reboot-preserves-instance-store [IN] OBSERVATION
EC2 reboot preserves instance store volumes, unlike stop/start which loses instance store data.

### ec2-reboot-terminated-silently-ignored [IN] OBSERVATION
Requests to reboot terminated EC2 instances are silently ignored — no error is returned.

### ec2-replace-public-key-on-running-instance [IN] OBSERVATION
A public key can be added or replaced on a running Linux instance without needing the original key pair.

### ec2-savings-plans-commit-dollar-per-hour [IN] OBSERVATION
EC2 Savings Plans commit to a USD/hour spend level for 1 or 3 years; Reserved Instances commit to a specific instance configuration for 1 or 3 years.

### ec2-security-groups-are-stateful-virtual-firewalls [IN] OBSERVATION
EC2 security groups act as stateful virtual firewalls at the instance level, controlling inbound and outbound traffic by protocol, port, and IP range.

### ec2-shared-vs-dedicated-resources [IN] OBSERVATION
EC2 dedicates CPU, memory, and instance storage to each instance; network and disk subsystem are shared among instances on the same host with equal-share fairness and burst capability.

### ec2-six-access-methods [IN] OBSERVATION
EC2 can be accessed via the EC2 Console, AWS CLI (`aws ec2`), CloudFormation templates, AWS SDKs, AWS Tools for PowerShell, and the Query API (direct HTTP GET/POST).

### ec2-six-instance-families [IN] OBSERVATION
EC2 instance families are grouped into six categories: General Purpose, Compute Optimized, Memory Optimized, Storage Optimized, Accelerated Computing, and High-Performance Computing.

### ec2-spot-instances-up-to-90-percent-savings [IN] OBSERVATION
EC2 Spot Instances can provide up to 90% cost savings compared to On-Demand pricing.

### ec2-ssm-session-manager-alternative [IN] OBSERVATION
AWS Systems Manager Session Manager is an alternative to key pairs for connecting to instances, eliminating the need to manage SSH keys or open port 22.

### ec2-statereason-field-reveals-termination-cause [IN] OBSERVATION
The `StateReason` field in `describe-instances` output contains `Message` and `Code` fields that reveal why an instance transitioned to terminated state (e.g., `Client.VolumeLimitExceeded`).

### ec2-stop-ebs-backed-only [IN] OBSERVATION
EC2 `StopInstances` works exclusively on EBS-backed instances; instance store-backed instances cannot be stopped.

### ec2-stop-start-may-change-host [IN] OBSERVATION
A stopped EC2 instance may be migrated to a different underlying physical host on restart, unlike a reboot which stays on the same host.

### ec2-stopped-no-compute-charge-ebs-continues [IN] OBSERVATION
Stopped EC2 instances are not charged for compute or data transfer, but attached EBS volumes continue to incur storage charges.

### ec2-system-status-check-monitors-aws-infrastructure [IN] OBSERVATION
EC2 system status checks monitor the underlying AWS infrastructure (physical host, network, power) and require AWS involvement or instance stop/start/terminate to resolve.

### ec2-t-series-burstable [IN] OBSERVATION
T-series instances (T3, T3a, T4g) are burstable with a CPU credit model; all other instance families provide fixed/dedicated CPU performance.

### ec2-terminate-deletes-launch-attached-ebs-by-default [IN] OBSERVATION
By default, EBS volumes attached at instance launch are deleted on termination (`DeleteOnTermination=true`), while EBS volumes attached after launch are preserved.

### ec2-terminate-idempotent [IN] OBSERVATION
The TerminateInstances API is idempotent — terminating an already-terminated instance succeeds without error.

### ec2-terminate-invalid-id-fails-entire-request [IN] OBSERVATION
If any single instance ID in a TerminateInstances request is invalid, the entire request fails and no instances are terminated.

### ec2-terminate-max-batch-1000 [IN] OBSERVATION
The TerminateInstances API accepts up to 1000 instance IDs per request.

### ec2-terminate-protection-per-az-partial-failure [IN] OBSERVATION
When terminating a batch of instances across AZs, termination protection causes per-AZ partial failure: AZs containing a protected instance fail entirely (even unprotected instances in that AZ are not terminated), while AZs with no protected instances succeed.

### ec2-terminated-instances-visible-one-hour [IN] OBSERVATION
Terminated EC2 instances remain visible in the console and API responses for approximately one hour after termination.

### ec2-trainium-training-inferentia-inference [IN] OBSERVATION
AWS Trainium (Trn1, Trn2) is for ML training; AWS Inferentia (Inf1, Inf2) is for ML inference — they are distinct chip families.

### ec2-u-series-high-memory-instances [IN] OBSERVATION
U-series instances (e.g., U-6tb1, U7i-12tb) are high-memory instance types designed for large in-memory workloads such as SAP HANA.

### ec2-windows-private-key-decrypts-password [IN] OBSERVATION
On Windows instances, the private key is used to decrypt the administrator password, not for direct login.

### ecr-cross-account-requires-region-enabled [IN] OBSERVATION
ECR cross-account image sharing requires the target account to have the repository's Region enabled, in addition to the repository policy granting access.

### ecr-get-authorization-token-prerequisite [IN] OBSERVATION
Users must have `ecr:GetAuthorizationToken` permission via IAM identity-based policy before they can authenticate to an ECR registry or push/pull images — repository policies alone are insufficient.

### ecr-getauthorizationtoken-iam-policy-only [IN] OBSERVATION
The `ecr:GetAuthorizationToken` permission must be granted via an IAM identity-based policy — it cannot be granted via an ECR repository policy.

### ecr-image-restore-from-archive-asynchronous [IN] OBSERVATION
ECR image restore from archive is asynchronous — initial status is `ACTIVATING` and completion is a separate service event.

### ecr-kms-encrypted-repo-two-creategrant-entries [IN] OBSERVATION
Creating a KMS-encrypted ECR repository generates two `CreateGrant` CloudTrail log entries (via `kms.amazonaws.com` event source).

### ecr-lifecycle-10plus-images-multiple-cloudtrail-events [IN] OBSERVATION
When ECR lifecycle policies expire 10 or more images, ECR sends multiple CloudTrail events due to event size limits (max 100 tags per image per event).

### ecr-repo-default-access-creating-account-only [IN] OBSERVATION
By default, only the AWS account that created an ECR repository has access to it.

### ecr-repo-policy-or-iam-policy-either-grants [IN] OBSERVATION
For ECR repository access, a user only needs to be allowed by one policy type (repository policy OR IAM policy), not both — but an explicit deny in either takes precedence.

### ecr-repository-resource-based-policies [IN] OBSERVATION
ECR private repositories support resource-based policies with multiple policy statements per repository, controlling which principals can perform which ECR API operations.

### ecr-set-repository-policy-cli-for-advanced [IN] OBSERVATION
The `aws ecr set-repository-policy` CLI command supports more complex repository policies than the ECR console UI.

### ecs-account-settings-per-region [IN] OBSERVATION
ECS account settings are per-Region, per-account and can be set for individual IAM users/roles or as account-wide defaults; federated users always inherit root user settings with no individual override.

### ecs-awsvpc-trunking-increases-task-density [IN] OBSERVATION
ECS `awsvpcTrunking` account setting increases ENI density on EC2 container instances via trunk ENI (e.g., c5.large goes from 2 tasks to 10 tasks).

### ecs-cloudtrail-data-events-container-instance-only [IN] OBSERVATION
The only ECS resource type supporting CloudTrail data events is `AWS::ECS::ContainerInstance` — not services, tasks, or clusters — and data events are not logged by default.

### ecs-cloudtrail-management-events-logged-by-default [IN] OBSERVATION
Amazon ECS control plane API calls (e.g., `CreateService`, `RunTask`, `DeleteCluster`) are logged as CloudTrail management events by default with no additional configuration.

### ecs-clusters-region-specific [IN] OBSERVATION
ECS clusters are Region-specific — `ClusterNotFoundException` indicates the wrong region or a nonexistent cluster.

### ecs-data-event-apis-poll-telemetry-syslog [IN] OBSERVATION
ECS CloudTrail data event APIs are agent-level operations: `ecs:Poll`, `ecs:StartTelemetrySession` (EC2 and ECS Managed Instances), and `ecs:PutSystemLogEvents` (ECS Managed Instances only).

### ecs-default-log-driver-mode-nonblocking [IN] OBSERVATION
ECS default log driver mode changed from `blocking` to `non-blocking` on June 25, 2025; non-blocking prioritizes task availability over logging completeness.

### ecs-draining-deployment-config-interaction [IN] OBSERVATION
During ECS container instance draining, `minimumHealthyPercent` and `maximumPercent` deployment configuration control whether replacement tasks must be healthy before draining tasks stop, governing the speed vs. availability tradeoff.

### ecs-draining-replaces-service-tasks-only [IN] OBSERVATION
When an ECS container instance is set to DRAINING, only service tasks are stopped and replaced on other instances; standalone (non-service) tasks are not drained automatically and must finish or be stopped manually.

### ecs-draining-requires-active-state [IN] OBSERVATION
An ECS container instance must be in ACTIVE state before it can transition to DRAINING; instances in REGISTERING, DEREGISTERING, or REGISTRATION_FAILED cannot be updated.

### ecs-fargate-task-retirement-default-7-days [IN] OBSERVATION
Fargate task retirement wait period defaults to 7 days, with options of 0, 7, or 14 days; shorter periods pick up patches sooner.

### ecs-fault-injection-custom-ami-tc-netem [IN] OBSERVATION
Custom (non-ECS-optimized) AMIs require manual installation of `tc` (traffic control) and `sch_netem` kernel module for ECS fault injection to work.

### ecs-fault-injection-opt-in-awsvpc-host-only [IN] OBSERVATION
ECS fault injection requires `enableFaultInjection: true` in the task definition (disabled by default), only works with `awsvpc` or `host` network modes, is not available on Windows, and works on both EC2 and Fargate launch types.

### ecs-fips-dualstack-api-cli-only [IN] OBSERVATION
ECS `fargateFIPSMode` and `dualStackIPv6` account settings can only be changed via API/CLI, not the AWS Console.

### ecs-guardduty-activate-read-only-aws-managed [IN] OBSERVATION
The ECS `guardDutyActivate` account setting is read-only and `aws-managed` type — it is controlled by GuardDuty Runtime Monitoring, not ECS directly.

### ecs-put-account-setting-vs-default [IN] OBSERVATION
`put-account-setting` applies to the calling user/role while `put-account-setting-default` sets account-wide defaults and requires root/admin privileges.

### ecs-stop-task-deletes-tags [IN] OBSERVATION
All tags associated with an ECS task are deleted when the task is stopped.

### ecs-stop-task-sigterm-30s-sigkill [IN] OBSERVATION
ECS `StopTask` sends SIGTERM (or custom STOPSIGNAL) to containers with a 30-second grace period, then SIGKILL if the container hasn't exited; the timeout is configurable via `ECS_CONTAINER_STOP_TIMEOUT` agent variable.

### ecs-tagging-authorization-mandatory-march-2024 [IN] OBSERVATION
ECS tagging authorization became mandatory on March 29, 2024 — `ecs:TagResource` permission is required when creating resources with tags.

### ecs-update-container-instances-state-batch-10 [IN] OBSERVATION
The `UpdateContainerInstancesState` API accepts up to 10 container instance IDs or ARNs per call.

### ecs-windows-containers-ctrl-shutdown-event [IN] OBSERVATION
ECS Windows containers receive `CTRL_SHUTDOWN_EVENT` instead of POSIX signals (SIGTERM/SIGKILL) when stopped.

### egress-only-igw-for-ipv6-outbound [IN] OBSERVATION
For outbound-only IPv6 internet access, use an egress-only internet gateway instead of a NAT gateway (unless using DNS64/NAT64).

### eip-account-scoped-until-released [IN] OBSERVATION
An Elastic IP belongs to an AWS account until explicitly released; a disassociated EIP remains allocated (and incurs charges) until released.

### eip-all-public-ipv4-charged [IN] OBSERVATION
All public IPv4 addresses are charged, including EIPs whether associated or not.

### eip-association-releases-original-public-ip [IN] OBSERVATION
Associating an EIP with an instance that already has a public IPv4 address permanently releases that original public IP back to Amazon's pool.

### eip-byoip-no-quota-count [IN] OBSERVATION
BYOIP-sourced Elastic IPs do not count toward the default EIP quota.

### eip-default-quota-5-per-region [IN] OBSERVATION
The default quota is 5 Elastic IP addresses per Region per account, increasable via the Service Quotas console.

### eip-dns-resolves-private-internally [IN] OBSERVATION
Public DNS for an EIP resolves to the EIP externally but to the private IPv4 address internally within the VPC.

### eip-dual-association-instance-and-eni [IN] OBSERVATION
Associating an EIP with an instance also associates it with the primary ENI, and vice versa.

### eip-ipv4-only [IN] OBSERVATION
Elastic IP addresses are IPv4 only — there is no Elastic IP concept for IPv6.

### eip-region-scoped [IN] OBSERVATION
Elastic IP addresses are Region-scoped and cannot be moved to another Region.

### eip-transferable-between-accounts [IN] OBSERVATION
Elastic IP addresses can be transferred between AWS accounts.

### eks-access-control-rbac-and-iam [IN] OBSERVATION
EKS access control uses both Kubernetes RBAC and AWS IAM.

### eks-add-subnets-after-creation [IN] OBSERVATION
Subnets can be added to an existing EKS cluster after creation, but they must be in the same VPC.

### eks-anywhere-on-premises-clusters [IN] OBSERVATION
EKS Anywhere allows running EKS clusters in your own data centers, separate from EKS Hybrid Nodes which connect on-premises nodes to cloud EKS clusters.

### eks-auto-mode-ebs-storage-classes [IN] OBSERVATION
EKS Auto Mode automatically creates EBS-backed storage classes; other storage types use CSI drivers.

### eks-capabilities-managed-controllers [IN] OBSERVATION
EKS Capabilities (Argo CD, ACK, kro) run as managed services in EKS infrastructure, not in the customer's cluster, with automated patching/scaling/monitoring.

### eks-certified-kubernetes-conformant [IN] OBSERVATION
EKS is certified Kubernetes-conformant; existing Kubernetes applications deploy without refactoring.

### eks-clusters-always-within-vpc [IN] OBSERVATION
EKS clusters are always created within a VPC; networking is not optional or separate.

### eks-fargate-serverless-compute [IN] OBSERVATION
EKS supports AWS Fargate for serverless container compute in addition to EC2 instances (including Nitro and Graviton instance types).

### eks-guardduty-threat-detection [IN] OBSERVATION
Amazon GuardDuty provides threat detection for EKS clusters as part of EKS security integrations.

### eks-hybrid-nodes-different-cni [IN] OBSERVATION
EKS hybrid nodes (on-premises infrastructure) require a different CNI configuration than standard AWS-hosted nodes.

### eks-management-interfaces [IN] OBSERVATION
EKS can be managed via AWS Console, AWS CLI, eksctl CLI, EKS API/SDKs, CDK, CloudFormation, and Terraform.

### eks-monitoring-cloudwatch-prometheus-cloudtrail [IN] OBSERVATION
EKS monitoring and observability integrates with Amazon CloudWatch, Amazon Managed Prometheus, AWS CloudTrail, ADOT Operator, and Metrics Server.

### eks-pricing-per-cluster [IN] OBSERVATION
EKS pricing is per-cluster based on Kubernetes version support tier, plus separate charges for compute (EC2/Fargate), storage (EBS), and networking (public IPv4).

### eks-requires-setup-prerequisites [IN] OBSERVATION
EKS requires completing setup prerequisites before cluster creation via either path.

### eks-savings-plans-apply-to-compute [IN] OBSERVATION
AWS Savings Plans can be applied to EKS compute costs.

### eks-shared-responsibility-model [IN] OBSERVATION
EKS follows the AWS shared responsibility model for security.

### eks-standard-and-extended-version-support [IN] OBSERVATION
EKS offers standard and extended Kubernetes version support tiers.

### eks-standard-vs-auto-mode [IN] OBSERVATION
EKS Standard: AWS manages the control plane only. EKS Auto Mode: AWS manages both control plane and data plane (node provisioning, scaling, patching, cost optimization).

### eks-storage-csi-drivers-ebs-s3-efs-fsx [IN] OBSERVATION
EKS integrates with Amazon EBS, S3, EFS, FSx, and Amazon File Cache for persistent storage via CSI drivers.

### eks-two-getting-started-paths [IN] OBSERVATION
EKS offers two getting started paths: eksctl (automated) and AWS Management Console + AWS CLI (manual resource creation).

### eks-vpc-cni-plugin-pod-networking [IN] OBSERVATION
EKS uses the Amazon VPC CNI plugin for pod networking, giving pods real VPC IP addresses (not overlay IPs).

### eksctl-simplest-eks-cluster-creation [IN] OBSERVATION
eksctl is the simplest and fastest CLI tool for creating and managing Amazon EKS clusters.

### elasticache-500-node-cluster-range [IN] OBSERVATION
A 500-node ElastiCache cluster can range from 83 shards (1 primary + 5 replicas each = 498 nodes) to 500 shards (primary only, no replicas).

### elasticache-500-shard-limit-version-5-0-6 [IN] OBSERVATION
The 500 node/shard limit is available for ElastiCache Valkey and Redis OSS version 5.0.6+; older versions are limited to 250.

### elasticache-cloudtrail-describe-response-null [IN] OBSERVATION
ElastiCache `Describe*` API calls have `responseElements` set to `null` in CloudTrail logs — only mutating actions include response details.

### elasticache-cloudtrail-event-source [IN] OBSERVATION
The `eventSource` for ElastiCache events in CloudTrail logs is `elasticache.amazonaws.com`.

### elasticache-cluster-mode-disabled-one-shard [IN] OBSERVATION
ElastiCache cluster mode disabled = exactly 1 shard; cluster mode enabled = up to 500 shards.

### elasticache-cluster-mode-horizontal-scaling [IN] OBSERVATION
ElastiCache cluster mode enables horizontal scaling (sharding); without cluster mode, only vertical scaling is available (applies to Valkey and Redis OSS).

### elasticache-connect-policy-requires-cache-and-user-arn [IN] OBSERVATION
The `elasticache:Connect` IAM policy must reference both the serverless cache ARN and the user ARN to grant IAM-based authentication access.

### elasticache-fully-managed-hardware-patching [IN] OBSERVATION
ElastiCache is fully managed: AWS handles hardware provisioning, monitoring, node replacement, and software patching in both Serverless and Node-based deployment models.

### elasticache-iam-auth-presigned-url-strip-https [IN] OBSERVATION
When using IAM authentication for ElastiCache, the presigned URL must have the `https://` prefix stripped before being used as the auth token password.

### elasticache-iam-auth-token-15-min-validity [IN] OBSERVATION
IAM auth tokens for ElastiCache are generated via SigV4 presigned URLs and are valid for 15 minutes; they should be cached (e.g., with `cachetools.TTLCache`) to avoid regeneration overhead.

### elasticache-iam-user-authentication-mode-type-iam [IN] OBSERVATION
IAM-enabled ElastiCache users are created with `--authentication-mode Type=iam` (not `Type=password` or `Type=no-password-required`).

### elasticache-max-90-nodes-per-cluster [IN] OBSERVATION
ElastiCache allows a maximum of 90 nodes per cluster (e.g., 90 shards × 0 replicas, or 15 shards × 5 replicas).

### elasticache-multi-az-automatic-failover [IN] OBSERVATION
ElastiCache Multi-AZ enables automatic failover from primary to a read replica; without it, primary failure requires manual intervention.

### elasticache-replication-asynchronous [IN] OBSERVATION
ElastiCache replication is asynchronous; some data loss is possible if the primary node fails before replication completes.

### elasticache-replication-group-max-6-nodes [IN] OBSERVATION
ElastiCache replication groups consist of 2–6 nodes per shard: 1 read/write primary + 1–5 read-only replicas.

### elasticache-serverless-cache-under-one-minute [IN] OBSERVATION
ElastiCache Serverless creates a cache in under a minute with a single endpoint, requiring only a cache name.

### elasticache-serverless-min-versions [IN] OBSERVATION
ElastiCache Serverless supports Valkey 7.2, Memcached 1.6.22+, and Redis OSS 7.1+.

### elasticache-serverless-patching-automatic [IN] OBSERVATION
In ElastiCache Serverless, software patching is fully automatic; in node-based clusters, users control when patches are applied.

### elasticache-shard-equals-node-group [IN] OBSERVATION
In the ElastiCache API/CLI, a shard is called a "node group."

### elasticache-single-node-all-data-lost [IN] OBSERVATION
A single-node ElastiCache cluster has no replication; all data is lost on node failure.

### elasticache-subnet-cidr-sizing-pitfall [IN] OBSERVATION
Subnet CIDR range must have sufficient IP addresses to accommodate ElastiCache node count increases; shared or small subnets are a common pitfall when scaling.

### elasticache-three-engines [IN] OBSERVATION
Amazon ElastiCache supports three engines: Valkey, Memcached, and Redis OSS.

### elasticache-two-deployment-models [IN] OBSERVATION
ElastiCache has two deployment models: Serverless (auto-scaling, no capacity planning) and Node-based (manual control over node type, count, and AZ placement).

### elasticache-user-group-requires-default-user [IN] OBSERVATION
Every ElastiCache user group must include a default user, even if that user is disabled (e.g., with access string `"off +get ~keys*"`).

### eni-eip-one-per-private-ipv4 [IN] OBSERVATION
An Elastic IP address is associated with a specific private IPv4 address on an ENI, with one EIP allowed per private IPv4 address.

### eni-is-foundational-network-primitive-across-services [IN] OBSERVATION
ENIs serve as the network attachment point for multiple VPC-integrated services including Lambda, DAX, and RDS Proxy, making ENI security group configuration important for service-level network controls.

### eni-max-count-varies-by-instance-type [IN] OBSERVATION
The maximum number of ENIs and IP addresses per ENI varies by EC2 instance type.

### eni-move-redirects-traffic-failover [IN] OBSERVATION
Moving an ENI between instances automatically redirects network traffic to the new instance, enabling failover patterns.

### eni-network-cards-multiple-over-100gbps [IN] OBSERVATION
Some large EC2 instance types support multiple network cards for over 100 Gbps bandwidth; the primary ENI must be on card index 0.

### eni-prefix-delegation-cidr-range-on-eni [IN] OBSERVATION
ENI prefix delegation assigns a CIDR range as a single prefix to an ENI, enabling faster service launches.

### eni-primary-cannot-be-detached [IN] OBSERVATION
Every EC2 instance has a primary network interface (ENI) that cannot be detached from the instance.

### eni-public-ipv4-released-on-stop [IN] OBSERVATION
An ENI's public IPv4 address is released on stop/hibernate/terminate and a new one is assigned on restart — use an Elastic IP for a persistent public address.

### eni-public-ipv4-setting-from-subnet-at-creation [IN] OBSERVATION
An ENI's public IPv4 auto-assign setting is determined at creation time from the subnet attribute and does not change if the subnet setting is later modified.

### eni-requester-managed-cannot-manage [IN] OBSERVATION
Requester-managed ENIs (created by AWS services like ELB, RDS, Lambda) appear in your account but cannot be managed by you directly.

### eni-same-az-only [IN] OBSERVATION
Elastic Network Interfaces can only be attached to EC2 instances in the same Availability Zone.

### eni-secondary-private-ip-reassignable-primary-not [IN] OBSERVATION
Secondary private IPv4 addresses on an ENI can be reassigned between instances; the primary private IPv4 cannot.

### eni-security-posture-cascades-across-vpc-integrated-services [IN] OBSERVATION
Since ENIs are the shared network primitive for PrivateLink endpoints, Lambda VPC integration, and instance failover, security group and NACL configurations on ENIs simultaneously affect all VPC-integrated services, making ENI misconfiguration a cross-service vulnerability vector.

### eni-source-dest-check-disable-for-nat [IN] OBSERVATION
Source/destination checking is enabled by default on ENIs and must be disabled for NAT instances, routers, and firewalls.

### event-driven-observability-gaps-at-source-and-audit-layers [IN] OBSERVATION
Event-driven AWS architectures face observability gaps at two independent layers: DynamoDB CDC pipelines have four reliability hazards (ordering, duplication, encoding, auto-disable), while CloudTrail has blind spots for automated operations — events may be lost or invisible at both the data change layer and the audit layer simultaneously.

### event-pipeline-ordering-fragile-at-both-source-and-destination [IN] OBSERVATION
Event-driven pipelines from DynamoDB through SQS face cascading ordering fragility — CDC sources produce out-of-order and duplicated records across both Streams and Kinesis paths AND SQS FIFO ordering holds only within message groups and breaks on DLQ routing — the full pipeline has no end-to-end ordering guarantee because both endpoints independently fail to maintain order.

### eventbridge-delivers-events-near-real-time [IN] OBSERVATION
Amazon EventBridge delivers AWS service events in near real time, enabling automated remediation workflows via rules.

### fis-ebs-all-volume-types-supported [IN] OBSERVATION
AWS FIS supports all EBS volume types (gp2, gp3, io1, io2, st1, sc1, standard) for fault injection experiments.

### fis-ebs-max-5-volumes-per-az [IN] OBSERVATION
AWS FIS can test a maximum of 5 EBS volumes simultaneously per AZ when specifying volume ARNs in the console.

### fis-ebs-multi-attach-affects-all-instances [IN] OBSERVATION
FIS experiments on Multi-Attach EBS volumes (io1/io2) affect all attached instances — per-attachment targeting is not supported.

### fis-ebs-not-local-zones-outposts-wavelength [IN] OBSERVATION
AWS FIS EBS experiments are not available in Local Zones, Outposts, or Wavelength Zones.

### fis-ebs-requires-nitro-instances [IN] OBSERVATION
AWS FIS EBS fault injection experiments require volumes to be attached to Nitro-based instances; non-Nitro instances are not supported.

### fis-ec2-kms-creategrant-for-encrypted-ebs [IN] OBSERVATION
The FIS EC2 access policy includes `kms:CreateGrant` conditioned on `kms:ViaService` and `kms:GrantIsForAWSResource` to handle stop/start of instances with encrypted EBS volumes.

### fis-ec2-policy-includes-spot-interruption-simulation [IN] OBSERVATION
The `AWSFaultInjectionSimulatorEC2Access` policy includes `ec2:SendSpotInstanceInterruptions`, enabling FIS to simulate Spot Instance interruptions for resilience testing.

### fis-ecs-destructive-actions-stop-task-drain-instance [IN] OBSERVATION
FIS ECS experiments can stop tasks (`ecs:StopTask`) and change container instance state to DRAINING (`ecs:UpdateContainerInstancesState`) as destructive fault injection actions.

### fis-ecs-ssm-sendcommand-os-level-faults [IN] OBSERVATION
FIS can inject OS-level faults on EC2-backed ECS container instances via `ssm:SendCommand` integration.

### fis-eks-terminates-ec2-not-k8s-api [IN] OBSERVATION
FIS EKS experiments operate by terminating the EC2 instances backing nodegroups, not by interacting with Kubernetes APIs directly; the EKS policy is read-only for EKS and destructive only at the EC2 layer.

### fis-network-disruption-nacl-route-table-swap [IN] OBSERVATION
FIS disrupts networking by creating replacement NACLs/route tables with deny rules, swapping them onto subnets, then restoring originals after the experiment completes.

### fis-network-managedbyfis-tag-safety-mechanism [IN] OBSERVATION
The FIS Network access policy uses the `managedByFIS=true` tag to track resources FIS creates, ensuring cleanup and mutation only affects FIS-managed resources.

### fis-rds-failover-targets-clusters-reboot-targets-instances [IN] OBSERVATION
FIS RDS failover targets Aurora clusters (`arn:aws:rds:*:*:cluster:*`) while reboot targets individual DB instances (`arn:aws:rds:*:*:db:*`) — different resource ARN patterns.

### fis-rds-policy-two-disruptive-actions [IN] OBSERVATION
The AWSFaultInjectionSimulatorRDSAccess managed policy permits exactly two disruptive RDS actions: `rds:FailoverDBCluster` (scoped to `cluster:*`) and `rds:RebootDBInstance` (scoped to `db:*`).

### fis-ssm-passrole-scoped-to-ssm-service [IN] OBSERVATION
The AWSFaultInjectionSimulatorSSMAccess policy scopes `iam:PassRole` with a condition restricting it to `"iam:PassedToService": "ssm.amazonaws.com"` only.

### fis-ssm-requires-ssm-agent-on-ec2 [IN] OBSERVATION
FIS requires SSM Agent running on target EC2 instances for SendCommand-based fault injection experiments to work.

### fis-ssm-two-execution-mechanisms [IN] OBSERVATION
FIS uses two SSM execution mechanisms: SSM Automation (start/stop/get automation execution) and SSM Run Command (send/list/cancel command).

### fis-tag-get-resources-required-for-target-resolution [IN] OBSERVATION
All FIS managed policies include `tag:GetResources` permission on `Resource: "*"` to enable tag-based target resolution during experiment execution.

### fis-tag-getresources-for-target-resolution [IN] OBSERVATION
FIS uses `tag:GetResources` from the Resource Groups Tagging API to resolve experiment targets by tag filters defined in experiment templates.

### fis-two-cloudformation-resource-types [IN] OBSERVATION
AWS FIS has two CloudFormation resource types: `AWS::FIS::ExperimentTemplate` (defines fault injection experiments) and `AWS::FIS::TargetAccountConfiguration` (configures cross-account targeting).

### fis-uses-service-role-policies [IN] OBSERVATION
FIS managed policies (EC2, ECS, EKS, Network, RDS, SSM) are service role policies attached to the FIS execution role, not directly to end-user IAM identities.

### gateway-route-tables-igw-and-vgw [IN] OBSERVATION
Gateway route tables can be associated with internet gateways and virtual private gateways, not just subnets.

### glacier-eventsource-glacier-amazonaws-com [IN] OBSERVATION
The CloudTrail eventSource for the legacy Amazon Glacier vault service is `glacier.amazonaws.com`, distinct from the S3 event source.

### glacier-standalone-deprecated-new-customers [IN] OBSERVATION
Amazon Glacier (the standalone vault-based archival service) is no longer accepting new customers — AWS recommends S3 Glacier storage classes (Instant Retrieval, Flexible Retrieval, Deep Archive) for all new workloads.

### iac-dynamodb-lifecycle-transitions-risk-data-loss [IN] OBSERVATION
Infrastructure-as-code operations on DynamoDB carry data-loss risk at two independent lifecycle transitions: changing a CloudFormation resource type from Table to GlobalTable can delete the table, AND stack creation rollback deletes all created resources including populated tables — both IaC lifecycle events threaten data persistence.

### iam-access-analyzer-control-tower-trails-not-supported [IN] OBSERVATION
AWS Control Tower trails are not supported for IAM Access Analyzer policy generation because logs are in the Log Archive account and S3 bucket permissions are restricted by SCPs.

### iam-access-analyzer-custom-policy-checks-paid [IN] OBSERVATION
IAM Access Analyzer custom policy checks (check-no-new-access, check-access-not-granted, check-no-public-access) are a paid feature with a per-invocation charge, unlike standard policy validation which is free.

### iam-access-analyzer-dashboard-two-views [IN] OBSERVATION
IAM Access Analyzer has two separate dashboard views: one for external/internal access findings, and one for unused access findings.

### iam-access-analyzer-error-findings-removed-not-resolved [IN] OBSERVATION
IAM Access Analyzer error findings are removed entirely when the underlying issue is fixed, not moved to Resolved status like resource findings.

### iam-access-analyzer-external-regional-unused-not [IN] OBSERVATION
External access analyzers are regional — one must be created in each Region with supported resources. Unused access analyzers are NOT regional — one analyzer suffices regardless of Region.

### iam-access-analyzer-internal-six-resource-types [IN] OBSERVATION
IAM Access Analyzer internal access analyzers support only 6 resource types: S3 buckets, S3 directory buckets, RDS DB snapshots, RDS DB cluster snapshots, DynamoDB streams, and DynamoDB tables.

### iam-access-analyzer-lambda-functions-layers-only [IN] OBSERVATION
IAM Access Analyzer generates findings for Lambda functions and layers only — not for aliases or specific versions via qualified ARN.

### iam-access-analyzer-max-one-external-one-internal-dashboard [IN] OBSERVATION
The IAM Access Analyzer dashboard allows selecting at most one external access analyzer and one internal access analyzer simultaneously.

### iam-access-analyzer-policy-gen-available-7-days [IN] OBSERVATION
Generated policies from IAM Access Analyzer are viewable in the IAM console for up to 7 days, with only one generated policy at a time per console session.

### iam-access-analyzer-policy-gen-includes-denied-actions [IN] OBSERVATION
IAM Access Analyzer policy generation reviews all CloudTrail events including denied actions, so generated policies may include actions that were attempted but denied.

### iam-access-analyzer-policy-gen-max-90-days [IN] OBSERVATION
IAM Access Analyzer policy generation analyzes up to 90 days of CloudTrail activity to create least-privilege policies.

### iam-access-analyzer-rcp-changes-24-hour-rescan [IN] OBSERVATION
RCP (resource control policy) changes without an accompanying bucket policy change don't trigger an IAM Access Analyzer rescan — the next periodic scan occurs within 24 hours.

### iam-access-analyzer-rescan-30min-full-24hr [IN] OBSERVATION
IAM Access Analyzer analyzes new or updated policies within approximately 30 minutes; a full periodic rescan occurs within 24 hours.

### iam-access-analyzer-resolved-findings-deleted-90-days [IN] OBSERVATION
IAM Access Analyzer resolved findings are automatically deleted after 90 days.

### iam-access-analyzer-s3-bpa-evaluation-6-hours [IN] OBSERVATION
IAM Access Analyzer evaluates account-level S3 Block Public Access changes only every 6 hours; multi-Region access point changes are also evaluated every 6 hours.

### iam-access-analyzer-six-capabilities [IN] OBSERVATION
IAM Access Analyzer provides six capabilities: external access findings, internal access analysis, unused access detection, policy validation, custom policy checks, and policy generation from CloudTrail activity.

### iam-access-analyzer-three-custom-check-types [IN] OBSERVATION
IAM Access Analyzer custom policy checks have three types: `CheckNoNewAccess` (compares updated vs existing policy), `CheckAccessNotGranted` (verifies specific access is prohibited), and `CheckNoPublicAccess` (detects public access for a resource type).

### iam-access-analyzer-three-functions [IN] OBSERVATION
IAM Access Analyzer has three distinct functions: (1) generate least-privilege policies from CloudTrail activity, (2) validate policy syntax and best practices (100+ checks), (3) detect and preview public/cross-account access.

### iam-access-analyzer-unused-access-is-paid [IN] OBSERVATION
IAM Access Analyzer unused access analysis is a paid feature, charged per IAM role and user analyzed per month.

### iam-access-analyzer-uses-formal-reasoning [IN] OBSERVATION
IAM Access Analyzer uses logic-based reasoning (automated reasoning / formal methods) to analyze policies, not sampling or heuristics.

### iam-access-analyzer-validate-policy-api-not-iam-api [IN] OBSERVATION
The `validate-policy` API belongs to the Access Analyzer service, not the IAM service.

### iam-access-analyzer-validation-not-inline-group-policies [IN] OBSERVATION
IAM Access Analyzer policy validation works for managed policies and inline user/role policies, but not inline group policies.

### iam-access-analyzer-zone-of-trust-org-requires-mgmt-or-delegated [IN] OBSERVATION
Setting IAM Access Analyzer zone of trust to Organization level requires the AWS Organizations management account or a delegated administrator.

### iam-access-key-id-akia-prefix [IN] OBSERVATION
Access key IDs starting with `AKIA` indicate long-term IAM user access keys.

### iam-access-key-secret-only-at-creation [IN] OBSERVATION
The secret access key can only be retrieved at the time of creation — if lost, the access key must be deleted and recreated.

### iam-access-key-two-parts [IN] OBSERVATION
An IAM access key consists of two parts: an access key ID (e.g., `AKIAIOSFODNN7EXAMPLE`) and a secret access key — both are required together to authenticate requests.

### iam-access-keys-do-not-expire [IN] OBSERVATION
IAM access keys are long-term credentials that do not expire automatically.

### iam-account-arn-root-means-entire-account [IN] OBSERVATION
An account principal ARN (`arn:aws:iam::123456789012:root`) delegates access to the entire account, not just the root user — any IAM identity in that account with appropriate permissions can assume the role.

### iam-account-settings-not-requiring-root [IN] OBSERVATION
Account name, contact info, alternate contacts, payment currency, and Region settings do not require root user — only email address, root password, and root access keys require root (for standalone accounts).

### iam-acls-only-non-json-cross-account-only [IN] OBSERVATION
ACLs are the only IAM policy type that does not use JSON format and only work for cross-account access (cannot grant to entities in the same account).

### iam-action-last-accessed-management-only [IN] OBSERVATION
Action last accessed information only covers management/control plane actions — no data plane events are tracked.

### iam-admin-user-is-not-root-user [IN] OBSERVATION
An IAM user with administrator permissions is not the same as the AWS account root user.

### iam-administrator-access-vs-power-user-access [IN] OBSERVATION
`AdministratorAccess` grants full access plus permissions delegation; `PowerUserAccess` grants full access except limited IAM and Organizations access.

### iam-arn-equals-and-arn-like-identical [IN] OBSERVATION
`ArnEquals` and `ArnLike` condition operators behave identically (both support wildcards); same for `ArnNotEquals` and `ArnNotLike`.

### iam-assume-role-max-12-hours [IN] OBSERVATION
Normal `AssumeRole` API calls support sessions up to 12 hours (43200 seconds) via the `DurationSeconds` parameter.

### iam-assumed-role-replaces-original-permissions [IN] OBSERVATION
While using an assumed role, the user's original permissions are not active — only one set of permissions is active at a time.

### iam-assuming-role-loses-own-permissions [IN] OBSERVATION
When a user assumes an IAM role, they temporarily give up their own permissions and take on the role's permissions.

### iam-authorization-paths-each-have-distinct-bypass-vectors [IN] OBSERVATION
IAM's multiple authorization evaluation paths (identity-based, resource-based, session, boundary) each have unique bypass mechanisms — resource policies bypass boundaries via user ARNs, PassRole bypasses CloudTrail visibility, and cross-account requires dual explicit controls — making single-path hardening insufficient.

### iam-aws-configure-no-session-token [IN] OBSERVATION
`aws configure` cannot capture session tokens; temporary credentials must be set via environment variables or manual config file edits.

### iam-aws-managed-policies-not-customer-editable [IN] OBSERVATION
AWS managed policies cannot be modified by customers — only AWS can update them, and updates automatically apply to all attached principals.

### iam-best-practice-managed-over-inline [IN] OBSERVATION
AWS best practice recommends managed policies over inline policies for reusability and central management.

### iam-canonical-user-principal-s3-specific [IN] OBSERVATION
The `CanonicalUser` principal type in IAM policy grammar is primarily an S3-specific construct used for S3 bucket policies and ACLs.

### iam-centralized-root-access-management-orgs [IN] OBSERVATION
Centralized root access management in AWS Organizations can remove and prevent long-term root credential recovery across member accounts.

### iam-centralized-root-privileged-tasks [IN] OBSERVATION
Centralized root access privileged tasks include: removing root credentials from member accounts, fixing deny-all S3 bucket policies, and fixing deny-all SQS queue policies.

### iam-cloudtrail-monitors-access-key-usage [IN] OBSERVATION
AWS CloudTrail is the service for monitoring and auditing IAM access key usage and detecting unauthorized access.

### iam-cognito-recommended-for-internet-federation [IN] OBSERVATION
Amazon Cognito is the AWS-recommended intermediary for internet identity federation (Login with Amazon, Facebook, Google, OIDC providers) in web and mobile applications.

### iam-condition-block-logical-and [IN] OBSERVATION
Multiple conditions within a single IAM policy `Condition` block are evaluated with logical AND — all conditions must be true for the statement to apply.

### iam-condition-key-names-case-insensitive [IN] OBSERVATION
IAM condition context key names are case-insensitive (`aws:SourceIP` equals `AWS:SourceIp`), but condition key values may be case-sensitive depending on the operator used.

### iam-condition-missing-key-false-negated-true [IN] OBSERVATION
When a condition key is not present in the request context, most operators evaluate to false (no match), but negated operators (`StringNotLike`, `ArnNotLike`) evaluate to true — a critical policy evaluation gotcha.

### iam-condition-multiple-operators-and-multiple-values [IN] OBSERVATION
Multiple condition operators within one Condition block are evaluated with logical AND; multiple values for a single key within one operator are evaluated with logical OR.

### iam-console-password-cli-login [IN] OBSERVATION
IAM console password credentials can also authenticate CLI/SDK access via `aws login` (requires `SignInLocalDevelopmentAccess` policy attached to the user).

### iam-create-policy-version-set-as-default [IN] OBSERVATION
`aws iam create-policy-version --set-as-default` updates a managed policy by creating a new version and making it the active version.

### iam-create-service-linked-role-cli-command [IN] OBSERVATION
Service-linked roles are created via CLI with `aws iam create-service-linked-role --aws-service-name SERVICE-NAME.amazonaws.com`.

### iam-credential-lifecycle-requires-entirely-proactive-management [IN] OBSERVATION
IAM access keys never expire automatically AND the secret access key can only be retrieved at creation time — credential lifecycle management must be entirely proactive with no forcing functions for rotation, and a lost secret key requires full credential replacement rather than recovery

### iam-credential-report-lists-users-and-status [IN] OBSERVATION
IAM credential reports can be generated and downloaded listing all IAM users and their credential status including password age, access key age, and MFA device status.

### iam-credentials-file-stores-plaintext [IN] OBSERVATION
The shared AWS credentials file stores access keys in plaintext.

### iam-cross-account-explicit-deny-needed-for-broad-permissions [IN] OBSERVATION
To prevent IAM users or groups with broad permissions (e.g., PowerUser) from assuming a cross-account role, an explicit Deny policy on `sts:AssumeRole` is required.

### iam-cross-account-needs-both-policies [IN] OBSERVATION
For cross-account access, both a resource-based policy on the resource and an identity-based policy on the principal are needed; for same-account access, a resource-based policy alone suffices.

### iam-cross-account-no-cross-partition [IN] OBSERVATION
Cross-account role delegation only works within a single AWS partition (e.g., `aws` and `aws-cn` cannot cross).

### iam-cross-account-passrole-requires-dual-controls [IN] OBSERVATION
Cross-account PassRole scenarios require both explicit deny policies for broad permissions and specific role ARN allow-lists — neither control alone is sufficient.

### iam-cross-account-requires-trust-and-identity-policy [IN] OBSERVATION
Cross-account role access requires both a trust policy on the role (in the trusting account) and an identity policy granting `sts:AssumeRole` (in the trusted account).

### iam-customer-managed-policy-copy-aws-managed [IN] OBSERVATION
Best practice for customer managed policies is to start by copying an AWS managed policy and then customizing it.

### iam-customer-managed-policy-preferred-for-least-privilege [IN] OBSERVATION
Customer managed policies are preferred over both inline policies (for reusability) and AWS managed policies (for least privilege granularity).

### iam-dangerous-permissions-equivalent-full-access [IN] OBSERVATION
Granting IAM permissions like `iam:CreatePolicy`, `iam:AttachRolePolicy`, `iam:PutUserPolicy`, or similar policy-management permissions effectively grants full account access — these must be tightly controlled.

### iam-delete-service-linked-role-requires-two-permissions [IN] OBSERVATION
Deleting a service-linked role requires both `iam:DeleteServiceLinkedRole` and `iam:GetServiceLinkedRoleDeletionStatus` permissions.

### iam-deny-with-condition-preferred-over-notprincipal [IN] OBSERVATION
The deny-with-condition pattern using `"Principal": "*"` with `ArnNotEquals` on `aws:PrincipalArn` is preferred over `NotPrincipal` for deny-all-except access patterns.

### iam-disable-console-password-keeps-programmatic-access [IN] OBSERVATION
Disabling an IAM user's console password does not revoke programmatic access or prevent assuming roles.

### iam-dynamodb-supports-all-six-iam-features [IN] OBSERVATION
DynamoDB supports all six IAM integration features: individual actions, resource-level permissions, resource-based policies, ABAC (tags), temporary credentials, and service-linked roles.

### iam-effective-permissions-combine-identity-and-resource [IN] OBSERVATION
A user's effective permissions are cumulative across identity-based policies (user/group/role) AND resource-based policies (S3, SQS, SNS, KMS) — both must be reviewed for a complete permission picture.

### iam-eventually-consistent [IN] OBSERVATION
IAM is eventually consistent — changes replicate globally across multiple data centers and may take time to propagate.

### iam-eventually-consistent-not-critical-path [IN] OBSERVATION
IAM changes should not be placed in critical, high-availability code paths due to eventual consistency — make IAM changes in initialization/setup routines and verify propagation before depending on them.

### iam-explicit-deny-always-wins [IN] OBSERVATION
An explicit deny in any applicable IAM policy type always overrides any allow from any other policy type.

### iam-external-id-for-cross-org-role-assumption [IN] OBSERVATION
ExternalId is an additional parameter used for secure cross-account role assumption between different organizations (confused deputy prevention).

### iam-external-id-no-console-switch [IN] OBSERVATION
Roles requiring ExternalId cannot be assumed via the AWS console; they must be assumed using the CLI or API.

### iam-federation-decision-matrix [IN] OBSERVATION
Federation decision matrix: IAM Identity Center for multi-account workforce access; IAM federation (direct SAML/OIDC) for single standalone accounts or machine identities; Amazon Cognito identity pools for mobile/web app end users.

### iam-federation-preferred-over-iam-users [IN] OBSERVATION
AWS best practice is for human users to access AWS through an identity provider (IdP) using temporary credentials via federation, not long-lived IAM user credentials.

### iam-fido-mfa-cannot-pass-to-sts [IN] OBSERVATION
FIDO security key MFA information cannot be passed to STS API operations for temporary credentials.

### iam-fido-security-key-console-only [IN] OBSERVATION
FIDO security keys (passkeys) can only be enabled via the AWS Console — not via CLI or API.

### iam-for-all-values-empty-key-returns-true [IN] OBSERVATION
`ForAllValues:` with an empty or missing key set evaluates to true — a `Null` condition check should be paired with it to prevent unintended access.

### iam-four-user-types [IN] OBSERVATION
AWS has four user types: root user (account owner, full access), IAM Identity Center users, federated principals (external IdP, temporary access), and IAM users (created within IAM).

### iam-generate-service-last-accessed-async [IN] OBSERVATION
`generate-service-last-accessed-details` is an asynchronous operation — you must poll with `get-service-last-accessed-details` until `JobStatus` is `COMPLETED`.

### iam-get-account-authorization-details-managed-policies [IN] OBSERVATION
The `GetAccountAuthorizationDetails` API identifies which AWS managed policies are currently in use (attached) in an account.

### iam-global-service-not-region-specific [IN] OBSERVATION
IAM is a global service that does not require Region selection — it is not tied to a specific AWS Region.

### iam-groups-cannot-be-nested [IN] OBSERVATION
IAM user groups cannot be nested — groups can only contain users, not other groups.

### iam-groups-identity-based-policies-only [IN] OBSERVATION
Only identity-based policies can be attached to IAM user groups — resource-based policies cannot reference groups.

### iam-groups-not-principals [IN] OBSERVATION
IAM user groups cannot be identified as a `Principal` in resource-based policies — they are not principals.

### iam-groups-permissions-not-authentication [IN] OBSERVATION
IAM user groups are a permissions management mechanism, not an authentication mechanism — groups are not authenticated entities.

### iam-hardware-totp-aws-approved-only [IN] OBSERVATION
Hardware TOTP tokens must be purchased from AWS-approved sources (token seeds must be shared with AWS at production); tokens from other sources will not work.

### iam-identity-center-coexists-with-iam-federation [IN] OBSERVATION
Existing IAM federation workflows continue to work alongside IAM Identity Center — migration is not required to adopt Identity Center for applications.

### iam-identity-center-multi-region-replication [IN] OBSERVATION
IAM Identity Center instances can be replicated to additional AWS Regions for resilience and regional application deployment.

### iam-identity-center-org-vs-account-instance [IN] OBSERVATION
IAM Identity Center has two instance types: organization instance (deployed in the AWS Organizations management account, required for multi-account access) and account instance (single account, limited to isolated app deployments).

### iam-identity-center-recommended-multi-account [IN] OBSERVATION
IAM Identity Center (formerly AWS SSO) is AWS's recommended approach for managing workforce access to multiple AWS accounts, over per-account IAM federation.

### iam-identity-center-recommended-over-iam-users-setup [IN] OBSERVATION
AWS recommends using IAM Identity Center (formerly AWS SSO) for creating administrative users instead of creating IAM users directly, with access assigned via groups following least-privilege principles.

### iam-identity-center-retains-sso-namespace [IN] OBSERVATION
Despite renaming from AWS SSO to IAM Identity Center, all API namespaces, CLI commands (`aws sso`, `aws sso-admin`), endpoints, and CloudFormation resources (`AWS::SSO`) retain the `sso`/`singlesignon` naming.

### iam-identity-center-single-federation-point [IN] OBSERVATION
IAM Identity Center provides a single point of federation — one SAML certificate to manage and one integration point with the identity provider.

### iam-identity-center-sts-free [IN] OBSERVATION
IAM, IAM Identity Center, and AWS STS have no charge; IAM Access Analyzer unused access analysis is paid.

### iam-identity-center-three-identity-sources [IN] OBSERVATION
IAM Identity Center supports three identity sources: its built-in directory, an external IdP via SAML 2.0, or Active Directory (via AWS Directory Service).

### iam-identity-center-trusted-identity-propagation [IN] OBSERVATION
IAM Identity Center's trusted identity propagation allows AWS managed applications (e.g., QuickSight → Redshift) to securely pass user identity between services, with CloudTrail logging the actual user identity.

### iam-identity-center-users-auto-assume-roles [IN] OBSERVATION
IAM Identity Center users automatically assume IAM roles on sign-in and receive temporary credentials; IAM users must explicitly switch roles to assume them.

### iam-identity-center-workforce-not-app-users [IN] OBSERVATION
IAM Identity Center is for workforce users (employees); Amazon Cognito is for application end-users.

### iam-if-exists-true-when-key-absent [IN] OBSERVATION
The `...IfExists` condition operator modifier evaluates to true (passes) when the condition key is absent from the request, and only evaluates the condition when the key is present.

### iam-inline-policy-one-to-one-deleted-with-identity [IN] OBSERVATION
Inline policies have a strict one-to-one relationship with an IAM identity and are deleted when the identity is deleted.

### iam-job-function-policies-auto-updated [IN] OBSERVATION
Job function policies (e.g., `AdministratorAccess`, `PowerUserAccess`) are AWS managed policies aligned to IT roles and are automatically maintained by AWS as services evolve.

### iam-lambda-partial-abac-partial-slr [IN] OBSERVATION
Lambda has "Partial" ABAC support and "Partial" service-linked role support, meaning not all resource types or features are covered.

### iam-last-accessed-4-hour-delay [IN] OBSERVATION
Recent IAM activity appears in last accessed reports within 4 hours; service-level tracking covers at least 400 days of history.

### iam-last-accessed-action-level-management-only [IN] OBSERVATION
Action-level last accessed information covers management (control plane) actions only — data plane events are not included.

### iam-last-accessed-activity-delay-4-hours [IN] OBSERVATION
Recent IAM activity takes up to 4 hours to appear in last accessed information in the IAM console.

### iam-last-accessed-includes-denied-attempts [IN] OBSERVATION
IAM last accessed data reports all API call attempts including denied ones — not just successful access.

### iam-last-accessed-information-cleanup [IN] OBSERVATION
IAM last accessed information identifies unused users, roles, permissions, policies, and credentials, enabling cleanup of unnecessary access.

### iam-last-accessed-only-identity-based-policies [IN] OBSERVATION
IAM last accessed reports only consider identity-based policies — resource-based policies, ACLs, SCPs, permissions boundaries, and session policies are excluded.

### iam-last-accessed-temp-creds-same-session [IN] OBSERVATION
For temporary/assumed-role credentials, the last accessed report must be generated and retrieved within the same session — only the principal that generated the report can view its details.

### iam-last-accessed-tracking-period-400-days [IN] OBSERVATION
IAM tracks service last accessed information for at least 400 days; action-level tracking started at different dates per service (S3: April 2020, EC2/IAM/Lambda: April 2021, all others: May 2023).

### iam-last-accessed-wait-90-days-before-reducing [IN] OBSERVATION
AWS recommends waiting a reporting period (e.g., 90 days) before using last accessed information to make permission reduction decisions.

### iam-legitimate-long-term-credential-use-cases [IN] OBSERVATION
Legitimate use cases for long-term IAM credentials include: workloads that can't use IAM roles (e.g., WordPress plugins), third-party clients without IAM Identity Center support, CodeCommit SSH/Git credentials, and Amazon Keyspaces service-specific credentials.

### iam-managed-policy-arn-pattern [IN] OBSERVATION
AWS managed policies have ARNs in the format `arn:aws:iam::aws:policy/<PolicyName>`.

### iam-managed-policy-attachable-to-multiple-principals [IN] OBSERVATION
A single AWS managed or customer managed policy can be attached to multiple principals; AWS managed policies can be attached across accounts.

### iam-management-account-exempt-from-scps [IN] OBSERVATION
The AWS Organizations management account is not limited by SCPs — its last accessed report lists all AWS services regardless of SCP restrictions.

### iam-max-two-access-keys-per-user [IN] OBSERVATION
Each IAM user can have a maximum of two access keys, enabling key rotation without downtime.

### iam-mfa-enforcement-cannot-be-fully-automated [IN] OBSERVATION
IAM MFA enforcement has structural automation gaps — FIDO security keys can only be configured via the console and root MFA can only be configured while signed in as root — preventing fully automated MFA lifecycle management across an organization.

### iam-mfa-max-8-devices-per-user [IN] OBSERVATION
Each IAM user or root user can register up to 8 MFA devices of any combination of types (passkeys, virtual MFA, hardware TOTP).

### iam-mfa-requires-existing-mfa-to-modify [IN] OBSERVATION
An IAM user must authenticate with an existing MFA device to enable or disable an additional MFA device.

### iam-mfa-setup-requires-two-consecutive-codes [IN] OBSERVATION
Setting up a virtual MFA device requires entering two consecutive TOTP codes (not just one) to validate time synchronization.

### iam-never-embed-access-keys-in-code [IN] OBSERVATION
AWS best practice: never embed access keys directly in application code — use SDK credential providers or known credential file locations instead.

### iam-never-embed-keys-in-code [IN] OBSERVATION
Access keys should never be embedded in application code or project files — this is a security anti-pattern.

### iam-never-use-root-access-keys [IN] OBSERVATION
AWS considers using root account access keys a critical security anti-pattern — root access keys should never be created or used.

### iam-new-user-zero-permissions-by-default [IN] OBSERVATION
A new IAM user has no permissions by default — all permissions must be explicitly granted (implicit deny).

### iam-no-default-all-users-group [IN] OBSERVATION
There is no default IAM group that includes all users — you must create and populate one manually.

### iam-no-default-roles-new-account [IN] OBSERVATION
No IAM roles are created by default when you first create an AWS account.

### iam-no-permissions-until-first-signin [IN] OBSERVATION
AWS recommends not granting permissions to new IAM users until after their first sign-in and password change, as a secure onboarding practice.

### iam-notaction-allow-grants-all-except-listed [IN] OBSERVATION
The `NotAction` element with `"Effect": "Allow"` grants access to all services except the listed ones — commonly used for power-user policies that exclude IAM/Organizations.

### iam-notprincipal-deny-boundary-conflict [IN] OBSERVATION
Using `NotPrincipal` with `Deny` in resource-based policies always denies principals with permissions boundaries attached — use `ArnNotEquals` with `aws:PrincipalArn` condition instead.

### iam-oidc-federated-principals-trust-policies-only [IN] OBSERVATION
OIDC federated principals (e.g., GitHub Actions, Cognito) can only be specified in IAM role trust policies, not in other resource-based policy types.

### iam-org-access-report-async-job-pattern [IN] OBSERVATION
Organization-level last accessed reports use an async job pattern: `generate-organizations-access-report` returns a job ID, then poll `get-organizations-access-report` for completion.

### iam-org-entity-path-format [IN] OBSERVATION
AWS Organizations entity paths use the format `o-orgId/r-rootId/ou-ouId/.../accountId/` — OU and root IDs are only unique within an organization, so the org ID must be included.

### iam-organizations-new-member-no-root-credentials [IN] OBSERVATION
New member accounts created in AWS Organizations with centralized root access enabled have no root credentials by default — no password, access keys, signing certificates, or MFA.

### iam-orgs-last-accessed-requires-mgmt-account-scps-enabled [IN] OBSERVATION
Organizations last accessed data requires signing in with management account credentials and SCPs must be enabled on the organization root.

### iam-orgs-mgmt-account-reports-all-services [IN] OBSERVATION
Organizations last accessed reports for the management account list all AWS services (not limited by SCPs); reports for other entities exclude management account activity.

### iam-orphaned-virtual-mfa-blocks-assignment [IN] OBSERVATION
Cancelling MFA assignment midway creates an orphaned virtual MFA device that blocks future assignment — it must be deleted via `aws iam delete-virtual-mfa-device`, not by editing policies.

### iam-ou-ids-not-globally-unique [IN] OBSERVATION
AWS Organizations OU IDs are only unique within an organization, not globally — `aws:PrincipalOrgPaths` conditions must always include the org ID.

### iam-passkeys-phishing-resistant [IN] OBSERVATION
Passkeys and FIDO2 security keys are phishing-resistant (using public key cryptography); TOTP-based MFA methods are not phishing-resistant.

### iam-passrole-not-in-cloudtrail-or-generated-policies [IN] OBSERVATION
`iam:PassRole` is not tracked by CloudTrail and is never included in IAM Access Analyzer generated policies.

### iam-passrole-not-tracked-in-last-accessed [IN] OBSERVATION
`iam:PassRole` is not tracked in last accessed information and is never included in IAM Access Analyzer generated policies.

### iam-passrole-not-tracked-last-accessed [IN] OBSERVATION
The `iam:PassRole` action is not tracked and is excluded from action last accessed information.

### iam-passrole-should-list-specific-roles [IN] OBSERVATION
The `iam:PassRole` permission should explicitly list allowed role ARNs — wildcards (`*`) in the Resource element for PassRole is a security anti-pattern.

### iam-permission-boundary-condition-key [IN] OBSERVATION
The `iam:PermissionsBoundary` condition key can enforce that delegated admins must attach a specific boundary when creating users; `iam:DeleteUserPermissionsBoundary` must be explicitly denied to prevent boundary removal.

### iam-permission-boundary-limits-not-grants [IN] OBSERVATION
Permissions boundaries limit but do not grant permissions — effective permissions are the intersection of identity-based policies and the permissions boundary.

### iam-permissions-boundaries-set-ceiling [IN] OBSERVATION
Permissions boundaries do not grant permissions on their own — they set a ceiling (maximum) on what identity-based policies can grant.

### iam-permissions-boundary-not-for-service-linked-roles [IN] OBSERVATION
Permissions boundaries cannot be applied to service-linked roles.

### iam-policies-attach-to-groups-not-users [IN] OBSERVATION
AWS best practice is to attach IAM policies to groups or roles, not directly to individual IAM users.

### iam-policy-evaluation-deny-order [IN] OBSERVATION
IAM policy evaluation order: explicit deny overrides all > SCP/RCP/permissions boundary/session policy implicit deny > explicit allow in identity-based or resource-based policy > default deny (all requests start denied).

### iam-policy-generation-max-90-days-cloudtrail [IN] OBSERVATION
IAM Access Analyzer policy generation analyzes up to 90 days of CloudTrail activity; generated policies are available for 7 days and only one can exist at a time.

### iam-policy-generation-no-control-tower-trails [IN] OBSERVATION
AWS Control Tower trails are not supported for IAM Access Analyzer policy generation because organization logs go to a separate Log Archive account with restricted S3 bucket permissions.

### iam-policy-generation-service-role-required [IN] OBSERVATION
IAM Access Analyzer policy generation requires a service role with trust to `access-analyzer.amazonaws.com` that has `cloudtrail:GetTrail`, `iam:GetServiceLastAccessedDetails`, `iam:GenerateServiceLastAccessedDetails`, and S3 read access to the trail bucket.

### iam-policy-size-limits-by-entity [IN] OBSERVATION
IAM policy size limits vary by entity type: 2,048 characters for user inline policies up to 10,240 characters for managed policies; whitespace is excluded from the character count.

### iam-policy-statements-evaluated-logical-or [IN] OBSERVATION
Multiple statements within an IAM policy are evaluated with logical OR; multiple policies attached to the same principal are also OR'd together (any allow counts, unless an explicit deny exists).

### iam-policy-version-must-be-2012-10-17 [IN] OBSERVATION
IAM policy documents should always use `"Version": "2012-10-17"` (the latest and current policy language version).

### iam-principal-arn-condition-survives-delete-recreate [IN] OBSERVATION
The `aws:PrincipalArn` condition key avoids the principal ID transformation problem — permissions persist through delete/recreate cycles of the referenced IAM entity.

### iam-principal-arn-returns-role-not-session [IN] OBSERVATION
The `aws:PrincipalArn` condition key returns the IAM role ARN, not the assumed-role session ARN — ARN operators (not string operators) should be used for comparisons.

### iam-principal-id-transformation-breaks-on-delete [IN] OBSERVATION
When a role or user ARN is saved in a trust policy, IAM converts it to a unique principal ID; if the entity is deleted and recreated with the same name, the old principal ID becomes orphaned and the trust policy must be re-edited.

### iam-principal-is-aws-service-only-direct-calls [IN] OBSERVATION
`aws:PrincipalIsAWSService` is `true` only when an AWS service principal (e.g., `cloudtrail.amazonaws.com`) makes a direct call — it is `false` when a service uses a service role or service-linked role.

### iam-principal-org-id-auto-includes-new-accounts [IN] OBSERVATION
The `aws:PrincipalOrgID` condition key automatically includes new accounts added to the AWS Organization without requiring manual policy updates.

### iam-principal-wildcard-and-aws-wildcard-equivalent [IN] OBSERVATION
`"Principal": "*"` and `"Principal": {"AWS": "*"}` are equivalent for granting anonymous/public access in resource-based policies.

### iam-request-evaluation-three-steps [IN] OBSERVATION
AWS evaluates principal requests in three steps: (1) authentication, (2) request context processing, (3) policy evaluation against context — some services like S3 can skip authentication for anonymous requests.

### iam-resource-based-policies-always-inline [IN] OBSERVATION
Resource-based policies are always inline (embedded in the resource) and never managed — unlike identity-based policies which can be AWS managed, customer managed, or inline.

### iam-resource-based-policies-not-universal [IN] OBSERVATION
Resource-based policies are only supported by select services (S3, Lambda, KMS, SNS, SQS, API Gateway, ECR, DynamoDB, Secrets Manager, CloudWatch Logs, etc.) — they are not universally available across all AWS services.

### iam-resource-level-permissions-vs-resource-based-policies [IN] OBSERVATION
Resource-level permissions (using ARNs to specify individual resources in any policy) are a different concept from resource-based policies (policies attached to a resource) — a common exam confusion point.

### iam-resource-policies-bypass-group-governance-and-permission-boundaries [IN] OBSERVATION
Resource-based policies targeting individual user ARNs can bypass both permission boundaries and group-based access governance, since groups cannot be principals in resource policies.

### iam-resource-policy-user-arn-bypasses-boundary [IN] OBSERVATION
Resource-based policies granting access to an IAM user ARN (same account) are not limited by implicit denies in permissions boundaries; grants to a role ARN are limited, but grants to a role session ARN are not.

### iam-resource-tag-key-matching-case-insensitive [IN] OBSERVATION
`aws:ResourceTag/tag-key` matching is case-insensitive on the tag key name — tags differing only by case (e.g., `TagKey1` vs `tagkey1`) match the same condition, which can cause unexpected policy behavior.

### iam-role-chaining-caps-session-at-1-hour [IN] OBSERVATION
Role chaining (assuming a second role from within an assumed role) limits the session to a maximum of 1 hour (3600 seconds), regardless of individual role max session duration settings.

### iam-role-path-plus-name-64-char-console-limit [IN] OBSERVATION
When using the AWS Console's "Switch Role" feature, the combined Path + RoleName must not exceed 64 characters, even though Path can be up to 512 chars and RoleName up to 64 chars when creating roles programmatically.

### iam-role-provides-temporary-credentials-not-long-term [IN] OBSERVATION
IAM roles provide temporary security credentials via STS — they do not have passwords or long-term access keys.

### iam-role-trust-policy-no-wildcard-in-principal-arn [IN] OBSERVATION
IAM role trust policies cannot use wildcard (*) as part of an ARN in the Principal element.

### iam-role-trust-policy-only-iam-resource-policy [IN] OBSERVATION
Role trust policies are the only resource-based policy type supported by IAM itself; all other resource-based policies are attached to non-IAM resources (S3 buckets, SQS queues, etc.).

### iam-role-trust-policy-required [IN] OBSERVATION
Every IAM role requires a trust policy — a resource-based JSON policy that defines which principals (users, roles, accounts, services) can assume it.

### iam-roles-anywhere-x509-certificates [IN] OBSERVATION
IAM Roles Anywhere enables external (non-AWS) workloads to obtain temporary AWS credentials using X.509 certificates from a PKI.

### iam-root-exclusive-tasks-list [IN] OBSERVATION
The root user is the only identity that can: change account email/password/access keys (standalone), close standalone accounts, restore revoked IAM admin permissions, activate IAM billing console access, register as Reserved Instance Marketplace seller, configure S3 MFA Delete, and sign up for GovCloud.

### iam-root-mfa-enforced-all-account-types [IN] OBSERVATION
MFA is enforced for root users across all AWS account types (standalone, management, and member accounts).

### iam-root-mfa-lost-contact-aws-support [IN] OBSERVATION
If all MFA devices for the root user are lost and no backup exists, the only recovery option is contacting AWS Support — there is no self-service recovery.

### iam-root-mfa-only-configurable-as-root [IN] OBSERVATION
Root user MFA can only be configured while signed in as the root user — no other principal can configure it.

### iam-root-mfa-requires-customer-action [IN] OBSERVATION
MFA is enforced for root users by default, but requires customer action to actually configure/add the MFA device during account creation or at the sign-in prompt.

### iam-root-no-identity-policies-or-boundaries [IN] OBSERVATION
The root user cannot have identity-based policies or permissions boundaries attached, but is affected by SCPs, RCPs, resource-based policies, and ACLs.

### iam-root-restricted-only-by-scps [IN] OBSERVATION
The root user cannot be restricted by IAM policies or permissions boundaries — only AWS Organizations SCPs can limit root user permissions.

### iam-root-user-cannot-assume-roles [IN] OBSERVATION
The root user cannot assume IAM roles via the console Switch Role feature.

### iam-root-user-not-entity-not-identity [IN] OBSERVATION
The root user is a principal but is neither an IAM entity nor an IAM identity — it cannot be restricted by identity-based or resource-based IAM policies.

### iam-same-account-identity-resource-union [IN] OBSERVATION
Within the same account, identity-based and resource-based policy permissions are combined as a union — if either allows, the action is allowed.

### iam-scp-rcp-identity-intersection [IN] OBSERVATION
When SCPs, RCPs, and identity-based policies all apply, effective permissions are the intersection of all three — the action must be allowed by all policy types.

### iam-scps-rcps-restrict-only-no-grant [IN] OBSERVATION
SCPs (Service Control Policies) and RCPs (Resource Control Policies) do not grant permissions — they only restrict; identity-based or resource-based policies are still required to grant access.

### iam-service-linked-role-can-exceed-account-limit [IN] OBSERVATION
Service-linked roles count toward the IAM roles-per-account quota but are the only role type that can exceed the limit.

### iam-service-linked-role-delete-requires-resource-cleanup [IN] OBSERVATION
Dependent resources must be deleted before a service-linked role can be deleted.

### iam-service-linked-role-indirect-permissions [IN] OBSERVATION
Users who invoke a service that uses a service-linked role gain indirect access to all other services that role can call (e.g., creating an RDS instance indirectly grants access to EC2, SNS, CloudWatch Logs, Kinesis).

### iam-service-linked-role-name-immutable [IN] OBSERVATION
Service-linked role names cannot be changed after creation.

### iam-service-linked-role-no-tags-at-creation [IN] OBSERVATION
Tags cannot be attached to service-linked roles during creation.

### iam-service-linked-role-permissions-not-editable [IN] OBSERVATION
Service-linked role permissions are defined by the owning AWS service and cannot be edited by IAM administrators.

### iam-service-linked-roles-excluded-unused-analysis [IN] OBSERVATION
Service-linked roles are excluded from IAM Access Analyzer unused access analysis.

### iam-service-principal-format [IN] OBSERVATION
AWS service principals follow the format `service-name.amazonaws.com`; opt-in region cross-region requests use regionalized format `service-name.{region}.amazonaws.com`, but role trust policies should use the non-regionalized form since IAM resources are global.

### iam-service-role-vs-service-linked-role [IN] OBSERVATION
A service role is an IAM role assumed by an AWS service that IAM admins can create/modify/delete; a service-linked role is a special service role owned by the AWS service where permissions cannot be edited by IAM admins.

### iam-session-policy-intersection [IN] OBSERVATION
Session policies (passed during AssumeRole or GetFederationToken) restrict permissions via intersection — effective permissions = identity-based policy ∩ permissions boundary ∩ session policy.

### iam-session-policy-resource-based-arn-distinction [IN] OBSERVATION
Resource-based policies referencing a session ARN bypass session policy limits and permissions boundary restrictions, while those referencing the entity (role/user) ARN do not bypass these limits.

### iam-session-tags-transitive-propagation [IN] OBSERVATION
When assuming an IAM role, session tags can be passed via `--tags` and `TransitiveTagKeys` can be set to propagate specific tags through role chains.

### iam-seven-policy-types [IN] OBSERVATION
AWS IAM supports seven policy types: identity-based, resource-based, permissions boundaries, SCPs, RCPs, ACLs, and session policies.

### iam-sid-alphanumeric-only [IN] OBSERVATION
The `Sid` element in IAM policies only allows alphanumeric characters (`A-Z`, `a-z`, `0-9`); other AWS services may allow different character sets in their policy Sid fields.

### iam-single-security-key-multiple-users [IN] OBSERVATION
A single FIDO security key can support multiple root and IAM users.

### iam-sms-mfa-discontinued [IN] OBSERVATION
SMS-based MFA has been discontinued in AWS — users must use passkeys, virtual MFA, or hardware TOTP tokens.

### iam-source-ip-not-through-vpc-endpoints [IN] OBSERVATION
The `aws:SourceIp` condition key does not work when requests are made through VPC endpoints or when a service calls another service on your behalf.

### iam-standalone-policy-has-own-arn [IN] OBSERVATION
A standalone policy (both AWS managed and customer managed) has its own ARN independent of any IAM identity, unlike inline policies which are embedded in an identity.

### iam-synced-passkeys-credential-managers [IN] OBSERVATION
Synced passkeys can be stored in credential managers (Google, Apple, 1Password, Dashlane, Bitwarden) and support biometric unlock and cross-device authentication (CDA).

### iam-temporary-credentials-minutes-to-hours [IN] OBSERVATION
Temporary security credentials (from STS/roles) can last from a few minutes to several hours, are generated dynamically, and cannot be reused after expiration.

### iam-three-identity-based-policy-types [IN] OBSERVATION
AWS IAM has three types of identity-based policies: AWS managed policies, customer managed policies, and inline policies.

### iam-transitive-session-tags-propagate-through-chain [IN] OBSERVATION
Transitive session tags propagate through all subsequent sessions in a role chain.

### iam-unassigned-virtual-mfa-auto-deleted [IN] OBSERVATION
Unassigned virtual MFA devices are automatically deleted when adding new virtual MFA devices.

### iam-user-arn-format [IN] OBSERVATION
IAM user ARN format is `arn:aws:iam::account-ID-without-hyphens:user/UserName`.

### iam-user-belongs-to-exactly-one-account [IN] OBSERVATION
Each IAM user is associated with one and only one AWS account.

### iam-user-cli-api-no-credentials-by-default [IN] OBSERVATION
IAM users created via CLI or API have no credentials by default; credentials must be explicitly created.

### iam-user-four-credential-types [IN] OBSERVATION
IAM users support four credential types: console password, access keys (CLI/SDK/API), SSH keys (for CodeCommit), and server certificates (SSL/TLS — use ACM instead unless region doesn't support it).

### iam-user-multiple-groups [IN] OBSERVATION
An IAM user can belong to multiple user groups simultaneously.

### iam-user-three-identifiers [IN] OBSERVATION
Each IAM user has three identifiers: a friendly name (human-readable, appears in ARNs), an ARN (globally unique), and a unique ID (returned only via API/CLI/PowerShell, not visible in console).

### iam-username-key-only-iam-users [IN] OBSERVATION
The `aws:username` condition key is only available for IAM users — it is not available for the root user, IAM roles, anonymous requests, or IAM Identity Center credentials.

### iam-users-only-for-edge-cases [IN] OBSERVATION
IAM users are only recommended for: workloads that can't use roles, third-party tools without IdP support, CodeCommit SSH access, Amazon Keyspaces compatibility testing, and emergency/break-glass access.

### iam-virtual-mfa-totp-rfc6238 [IN] OBSERVATION
Virtual MFA authenticator applications generate software-based TOTP codes per RFC 6238; each token must be unique per user but a single device can hold multiple tokens.

### igw-enforces-1500-mtu-limit [IN] OBSERVATION
The internet gateway enforces a 1500-byte MTU limit — jumbo frames do not work for internet-bound traffic.

### igw-horizontally-scaled-no-bottleneck [IN] OBSERVATION
An internet gateway is horizontally scaled, redundant, and highly available — it is not a bandwidth bottleneck or single point of failure.

### igw-instance-needs-public-ip-or-eip-for-internet [IN] OBSERVATION
Instances in a public subnet need a public IPv4 address or Elastic IP to communicate over the internet via the internet gateway.

### igw-no-additional-charge [IN] OBSERVATION
There is no charge for the internet gateway itself; only standard EC2 data transfer charges apply.

### igw-performs-one-to-one-nat-ipv4-only [IN] OBSERVATION
The internet gateway performs one-to-one NAT for IPv4 (translating between private and public/Elastic IP); IPv6 does not require NAT.

### instance-public-ip-private-subnet-no-internet [IN] OBSERVATION
An instance with a public IP in a private subnet (no IGW route) cannot reach the internet.

### ipv6-no-fragmentation-relies-on-pmtud [IN] OBSERVATION
IPv6 does not support packet fragmentation in the network; it relies entirely on Path MTU Discovery (PMTUD), and oversized packets are dropped with ICMPv6 Packet Too Big.

### ipv6-only-subnets-get-link-local-ipv4 [IN] OBSERVATION
IPv6-only subnets still receive link-local IPv4 addresses from 169.254.0.0/16 for VPC-internal service communication.

### irrevocable-decisions-span-both-data-and-observability-tiers [IN] OBSERVATION
Creation-time immutable decisions affect not only the data tier (DynamoDB consistency mode, LSIs, encryption) but also the observability tier (CloudTrail Lake KMS keys, pricing tier) — a wrong initial configuration can simultaneously lock in suboptimal performance AND inability to audit it.

### kafka-partitions-fixed-at-creation-sqs-groups-dynamic [IN] OBSERVATION
Kafka partition count is fixed at topic creation, whereas SQS FIFO message groups are dynamic and created on the fly — making dynamic parallel ordering harder to replicate with Kafka.

### kcl-1x-eol-january-30-2026 [IN] OBSERVATION
KCL version 1.x reaches end-of-support on January 30, 2026; the current recommendation is KCL 3.x with AWS SDK for Java v2.x.

### kcl-catchup-mode-default-disabled-1min-lag-3x [IN] OBSERVATION
KCL catch-up mode is disabled by default (`catchupEnabled=false`); when enabled, it scales GetRecords call rate by 3x when processing lag exceeds 1 minute.

### lambda-basic-execution-role-three-log-actions [IN] OBSERVATION
AWSLambdaBasicExecutionRole grants exactly three CloudWatch Logs actions: `logs:CreateLogGroup`, `logs:CreateLogStream`, and `logs:PutLogEvents` with `Resource: "*"`.

### lambda-container-reuse-not-guaranteed [IN] OBSERVATION
AWS Lambda may reuse execution containers across invocations, but this is not guaranteed and not controllable by the developer.

### lambda-db-connection-outside-handler-for-reuse [IN] OBSERVATION
Lambda database connections should be initialized outside the handler function (in initialization code) so the connection persists across invocations via execution context reuse.

### lambda-env-var-key-must-start-with-letter [IN] OBSERVATION
Lambda environment variable keys must match the pattern `[a-zA-Z][a-zA-Z0-9_]+` — they must start with a letter followed by alphanumeric characters or underscores.

### lambda-env-vars-version-specific [IN] OBSERVATION
Lambda environment variables are version-specific — each published function version captures its own set of environment variable values.

### lambda-event-filter-max-5-per-mapping [IN] OBSERVATION
A maximum of 5 filter patterns can be configured per Lambda event source mapping; multiple filters are evaluated as logical OR, and conditions within a single filter are evaluated as logical AND.

### lambda-event-source-mapping-batch-size-range [IN] OBSERVATION
The `--batch-size` parameter for Lambda event source mappings controls how many records Lambda receives per invocation, with a range of 1–10,000 and a default of 100.

### lambda-event-source-mapping-max-5-filters [IN] OBSERVATION
Lambda event source mappings support up to 5 filters to control which records invoke the function.

### lambda-init-code-runs-once-per-container [IN] OBSERVATION
Lambda initialization code (outside the handler) runs once after container creation but before the first handler invocation; the handler runs once per invocation.

### lambda-insights-deployed-as-extension-layer [IN] OBSERVATION
Lambda Insights must be explicitly installed as a Lambda extension layer on each function to collect metrics.

### lambda-insights-emf-logs-not-all-in-metrics [IN] OBSERVATION
Not all Lambda Insights metrics appear in CloudWatch Metrics — some non-aggregated metrics are only available as embedded metric format (EMF) log entries queryable via CloudWatch Logs Insights.

### lambda-no-logs-without-basic-execution-role [IN] OBSERVATION
Without AWSLambdaBasicExecutionRole or equivalent permissions, Lambda invocations succeed but produce no CloudWatch logs.

### lambda-polls-dynamodb-streams-4-per-second [IN] OBSERVATION
Lambda polls DynamoDB Streams 4 times per second for new records; invocation is synchronous.

### lambda-rds-eni-misconfiguration-cascades-across-vpc-services [IN] OBSERVATION
Lambda-RDS integration forces Lambda into a VPC where its ENIs become shared network primitives, meaning a security group misconfiguration in the Lambda-RDS path cascades beyond that pair to affect PrivateLink endpoints, instance failover, and any other VPC-integrated service sharing the same ENI security posture.

### lambda-rds-integration-requires-vpc-colocation-and-proxy [IN] OBSERVATION
Lambda accessing RDS requires VPC configuration with appropriate subnets and security groups, and RDS Proxy is recommended to manage connection pooling and prevent connection exhaustion from Lambda's concurrent execution model.

### lambda-rds-same-vpc-required [IN] OBSERVATION
Lambda functions accessing an RDS database must be deployed in the same VPC as the RDS instance.

### lambda-sqs-execution-role-two-managed-policies [IN] OBSERVATION
Lambda functions triggered by SQS in a VPC require two managed policies: `AWSLambdaSQSQueueExecutionRole` (poll SQS) and `AWSLambdaVPCAccessExecutionRole` (manage VPC ENIs).

### lambda-stream-error-retries-entire-batch [IN] OBSERVATION
On error, Lambda retries the entire batch from a DynamoDB stream until success or data expiration; configurable options include smaller batch size, retry limits, and discarding old records.

### lambda-vpc-access-role-nine-actions [IN] OBSERVATION
AWSLambdaVPCAccessExecutionRole grants nine actions: three `logs:` actions (same as basic) plus six `ec2:` actions (CreateNetworkInterface, DeleteNetworkInterface, DescribeNetworkInterfaces, DescribeSubnets, AssignPrivateIpAddresses, UnassignPrivateIpAddresses).

### lambda-vpc-creates-eni-per-combination [IN] OBSERVATION
When a Lambda function is VPC-connected, Lambda creates an elastic network interface (ENI) for every combination of security group and subnet specified in the VpcConfig.

### lambda-vpc-execution-role-needs-eni-permissions [IN] OBSERVATION
A VPC-connected Lambda function's execution role needs the `AWSLambdaVPCAccessExecutionRole` managed policy (or equivalent `ec2:CreateNetworkInterface`, `ec2:DescribeNetworkInterfaces`, `ec2:DeleteNetworkInterface` permissions).

### lambda-vpc-function-fails-without-eni-permissions [IN] OBSERVATION
A Lambda function configured with VPC access requires ENI permissions — without them, the function cannot start and will fail with an error.

### lambda-vpc-max-5-sg-16-subnets [IN] OBSERVATION
A VPC-connected Lambda function supports a maximum of 5 security groups and 16 subnets in its VpcConfig.

### lambda-vpc-role-superset-of-basic-role [IN] OBSERVATION
AWSLambdaVPCAccessExecutionRole is a superset of AWSLambdaBasicExecutionRole — it includes the same three `logs:` actions plus six `ec2:` actions for VPC networking.

### lambda-vpc-secrets-manager-requires-vpc-endpoint [IN] OBSERVATION
Accessing AWS Secrets Manager from a Lambda function deployed in a VPC requires a VPC endpoint for Secrets Manager.

### multi-az-deployment-fault-tolerance [IN] OBSERVATION
Launching resources across multiple Availability Zones provides fault tolerance against single-AZ failure.

### multi-region-dynamodb-achieves-five-nines-with-correct-initial-config [IN] OBSERVATION
DynamoDB global tables achieve 99.999% availability with multi-active replication when creation-time configuration errors that propagate permanently across all tiers and regions have been systematically prevented.

### nacl-cannot-filter-dns-dhcp-imds [IN] OBSERVATION
NACLs cannot filter DNS traffic to Route 53 Resolver, DHCP, instance metadata (IMDS), ECS task metadata, Windows license activation, Time Sync Service, or default VPC router reserved IPs.

### nacl-no-additional-charge [IN] OBSERVATION
Network ACLs are free to use with no additional charge.

### nacl-one-per-subnet-many-subnets-per-nacl [IN] OBSERVATION
Each subnet can have exactly one NACL at a time, but a single NACL can be associated with multiple subnets.

### nacl-rules-evaluated-lowest-number-first [IN] OBSERVATION
NACL rules are evaluated in order from lowest number first (1–32766); the first matching rule is applied and remaining rules are skipped.

### nacl-stateless-subnet-level-filtering [IN] OBSERVATION
Network ACLs are stateless — return traffic must be explicitly allowed by rules, unlike stateful security groups.

### nacl-supports-allow-and-deny-rules [IN] OBSERVATION
NACLs support both ALLOW and DENY rules, unlike security groups which only support allow rules.

### nat-gateway-connections-initiated-from-inside-only [IN] OBSERVATION
NAT gateways only allow connections initiated from inside the VPC — unsolicited inbound connections are blocked.

### nat-gateway-dns64-nat64-ipv6-to-ipv4 [IN] OBSERVATION
NAT gateways support DNS64/NAT64, enabling IPv6-only instances to communicate with IPv4 services through the NAT gateway.

### nat-gateway-managed-service-aws-scales [IN] OBSERVATION
NAT gateways are fully managed by AWS — AWS handles availability, scaling, and maintenance (in contrast to self-managed NAT instances).

### nat-gateway-no-security-groups [IN] OBSERVATION
NAT gateways do not have security groups, unlike self-managed NAT instances.

### nat-gateway-private-no-eip-no-igw [IN] OBSERVATION
A private NAT gateway cannot have an Elastic IP, and traffic from it to an internet gateway is dropped.

### nat-gateway-public-and-private-both-route-to-tgw-vgw [IN] OBSERVATION
Both public and private NAT gateways can route traffic to transit gateways and virtual private gateways for VPC-to-VPC or VPC-to-on-premises connectivity.

### nat-gateway-public-eip-source-only-via-igw [IN] OBSERVATION
A public NAT gateway uses its Elastic IP as source address only when routing through the internet gateway in the same VPC; when routing to transit gateway or virtual private gateway, the source is the NAT gateway's private IP.

### nat-gateway-public-requires-public-subnet-and-eip [IN] OBSERVATION
A public NAT gateway must be placed in a public subnet and must have an Elastic IP address.

### nondefault-vpc-no-igw-or-internet-routes [IN] OBSERVATION
Nondefault VPCs have neither an internet gateway nor internet routes by default; these must be created and configured manually.

### nosql-workbench-bundles-dynamodb-local [IN] OBSERVATION
NoSQL Workbench includes DynamoDB Local bundled with the installation — no separate download is needed for local offline development and testing.

### nosql-workbench-cloudformation-import-export [IN] OBSERVATION
NoSQL Workbench can import and export DynamoDB data models as CloudFormation JSON templates (since v3.0.0).

### nosql-workbench-commit-model-to-dynamodb [IN] OBSERVATION
NoSQL Workbench data models can be committed directly to a live DynamoDB instance from the workbench.

### nosql-workbench-cross-platform-gui [IN] OBSERVATION
NoSQL Workbench for DynamoDB is a cross-platform client-side GUI application available for Windows, macOS (Intel and Apple Silicon), and Linux — it is not an AWS managed service and consumes no cloud resources during modeling.

### nosql-workbench-default-capacity-on-demand [IN] OBSERVATION
As of NoSQL Workbench v3.13.5, the default table capacity mode for new tables changed from provisioned to on-demand.

### nosql-workbench-facets-single-table-design [IN] OBSERVATION
NoSQL Workbench facets help visualize single-table designs where multiple entity types share a DynamoDB table.

### nosql-workbench-operation-builder-50-saved-ops [IN] OBSERVATION
The NoSQL Workbench operation builder supports a maximum of 50 saved data operations per instance.

### nosql-workbench-platforms-windows-macos-linux [IN] OBSERVATION
NoSQL Workbench is available on Windows, macOS (including Apple silicon), and Linux.

### nosql-workbench-single-table-design-samples [IN] OBSERVATION
NoSQL Workbench ships with six sample data models demonstrating DynamoDB patterns including single-table design (Music Library, Ski Resort, Credit Card Offers), one-to-many (Employee), and many-to-many (Bookmarks) relationships.

### nosql-workbench-table-cloning-cross-account-region [IN] OBSERVATION
NoSQL Workbench can clone DynamoDB tables (key schema, optionally GSI schema and items) across AWS accounts, across regions, and between DynamoDB Local and cloud environments.

### nosql-workbench-three-components [IN] OBSERVATION
NoSQL Workbench for DynamoDB has three core components: Data Modeler, Visualizer, and Operation Builder.

### performance-efficiency-adapt-to-demand-and-technology [IN] OBSERVATION
Performance Efficiency requires using computing resources efficiently to meet system requirements and maintaining that efficiency as demand changes and technologies evolve.

### performance-efficiency-five-focus-areas [IN] OBSERVATION
The Performance Efficiency pillar has five focus areas: architecture selection, compute and hardware, data management, networking and content delivery, and process and culture.

### pitr-recovery-does-not-preserve-pitr-configuration [IN] OBSERVATION
Point-in-time recovery across DynamoDB (and RDS backup state requirements) does not automatically re-enable PITR on restored resources, and toggling PITR resets the recovery window.

### pmtud-requires-icmp-allowed-sg-and-nacl [IN] OBSERVATION
Path MTU Discovery (PMTUD) requires ICMP traffic to be allowed in both security groups and NACLs; NACLs can block ICMP even if security groups allow it.

### private-subnet-requires-nat-for-internet [IN] OBSERVATION
Private subnets require a NAT device (NAT gateway or NAT instance) for outbound internet access since they have no direct route to an internet gateway.

### privatelink-cloudformation-resources [IN] OBSERVATION
AWS PrivateLink CloudFormation support includes AWS::EC2::VPCEndpoint, AWS::EC2::VPCEndpointService, AWS::EC2::VPCEndpointServicePermissions, and AWS::EC2::VPCEndpointConnectionNotification.

### privatelink-enables-vpc-isolated-service-access-without-internet [IN] OBSERVATION
PrivateLink with interface endpoints (backed by ENIs) enables AWS service access from VPC-isolated workloads (Lambda, DAX) without internet gateway, NAT, or public IPs.

### privatelink-endpoint-service-requires-nlb-or-gwlb [IN] OBSERVATION
Creating a VPC endpoint service (provider side) requires a Network Load Balancer or Gateway Load Balancer.

### privatelink-has-hourly-and-data-charges [IN] OBSERVATION
AWS PrivateLink has its own pricing model with per-hour and per-GB data processed charges — it is not free.

### privatelink-interface-endpoints-use-enis [IN] OBSERVATION
Interface VPC endpoints are powered by Elastic Network Interfaces (ENIs) deployed in your subnets.

### privatelink-no-public-infrastructure-required [IN] OBSERVATION
AWS PrivateLink does not require an internet gateway, NAT device, public IP address, Direct Connect, or Site-to-Site VPN — traffic stays on the AWS network.

### privatelink-three-endpoint-types [IN] OBSERVATION
AWS PrivateLink supports three VPC endpoint types: interface endpoints (for AWS/third-party services), resource endpoints (for specific resources like databases), and service network endpoints (for VPC Lattice).

### public-ipv4-addresses-charged-all-types [IN] OBSERVATION
All public IPv4 addresses are now charged across all types (Elastic IP, auto-assigned, service-managed, BYOIP), with a free tier of 750 hours/month with EC2.

### public-subnet-defined-by-igw-route [IN] OBSERVATION
A public subnet is defined by its route table having a route to an internet gateway; a private subnet lacks this route.

### put-audit-events-checksum-base64-sha256 [IN] OBSERVATION
The `put-audit-events` integrity checksum is computed as base64-encoded SHA-256 of the event data (`printf %s $eventdata | openssl dgst -binary -sha256 | base64`).

### put-audit-events-max-100-events-1mb [IN] OBSERVATION
The `put-audit-events` API accepts a maximum of 100 events or 1 MB per request and uses a partial success model where some events can fail while others succeed.

### put-audit-events-only-cloudtrail-data-command [IN] OBSERVATION
`put-audit-events` is the only command in the `cloudtrail-data` service, used exclusively for ingesting external (non-AWS) events into CloudTrail Lake.

### rabbitmq-dlx-one-way-no-native-redrive [IN] OBSERVATION
RabbitMQ dead letter exchange (DLX) is one-way — there is no native redrive-to-source capability; redrive requires custom tooling or manual republishing.

### rdbms-global-dynamodb-migration-worst-case-across-all-dimensions [IN] OBSERVATION
Migrating RDBMS-normalized schemas to DynamoDB global tables produces the worst-case operational profile across all three dimensions: normalized entity tables create small items that trigger triple billing penalties locally, those penalties multiply across every replica region, and the resulting many-page filtered queries compound client implementation complexity.

### rdbms-normalization-maximizes-dynamodb-billing-penalties [IN] OBSERVATION
RDBMS normalization patterns applied to DynamoDB systematically maximize cost by producing many small entity-centric items that trigger all three billing overhead mechanisms (100-byte indexing, 1KB/4KB rounding, 200-byte GSI overhead) while generating filter-heavy queries that pay full RCU for discarded data.

### rdbms-trained-developers-waste-dynamodb-capacity-through-schema-mismatch [IN] OBSERVATION
Developers who design DynamoDB schemas using RDBMS normalization principles (entity-centric, normalized) will systematically produce queries that waste capacity through filter expressions, because normalized schemas require post-read filtering rather than single-shot access-pattern-driven queries.

### rds-additional-storage-volumes-oracle-sqlserver [IN] OBSERVATION
Oracle and SQL Server support up to 3 additional storage volumes (gp3 or io2), enabling scaling up to 256 TiB total storage.

### rds-all-api-actions-logged-by-cloudtrail [IN] OBSERVATION
All Amazon RDS API actions are automatically logged by CloudTrail as management events.

### rds-all-storage-uses-ebs [IN] OBSERVATION
All RDS storage is backed by Amazon EBS volumes.

### rds-aurora-separate-service [IN] OBSERVATION
Amazon Aurora is a separate service with its own user guide and is not covered by the standard RDS documentation, despite being a compatible engine.

### rds-automated-backup-blocked-by-concurrent-snapshot-copy [IN] OBSERVATION
RDS automated backups are blocked while a DB snapshot copy is running in the same Region for the same database.

### rds-automated-backup-requires-available-state [IN] OBSERVATION
RDS automated backups require the DB instance to be in the `available` state and do not occur during states like `storage_full`.

### rds-automated-backups-deleted-with-instance-unless-retained [IN] OBSERVATION
When deleting an RDS DB instance, automated backups are deleted unless you explicitly choose to retain them; deleted automated backups cannot be recovered.

### rds-automated-backups-snapshot-entire-instance [IN] OBSERVATION
RDS automated backups create storage volume snapshots of the entire DB instance, not individual databases.

### rds-backup-storage-not-per-second [IN] OBSERVATION
RDS backup storage is the exception to per-second billing — it is metered in GB-month.

### rds-backups-stored-in-s3 [IN] OBSERVATION
RDS backups (both automated and manual snapshots) are stored in Amazon S3, not EBS.

### rds-burst-credit-balances-relevant-to-burstable-classes [IN] OBSERVATION
Burst credit balances should be monitored for burstable RDS instance classes (e.g., `db.t3`).

### rds-can-copy-both-auto-and-manual-snapshots [IN] OBSERVATION
Both automated and manual RDS snapshots can be copied (including cross-Region), but only manual snapshots can be shared.

### rds-can-move-between-vpcs [IN] OBSERVATION
An RDS DB instance can be moved from one VPC to another, and non-VPC instances can be migrated into a VPC.

### rds-chained-replicas-mysql-mariadb-postgres-only [IN] OBSERVATION
Chained read replicas (replica of a replica) are supported for MariaDB, MySQL, and some PostgreSQL versions, but not for Db2, Oracle, or SQL Server.

### rds-cloudtrail-eventsource-rds-amazonaws-com [IN] OBSERVATION
The CloudTrail `eventSource` for Amazon RDS events is `rds.amazonaws.com`.

### rds-cloudwatch-metrics-every-minute [IN] OBSERVATION
Amazon RDS automatically sends metrics to CloudWatch every minute.

### rds-compute-billed-per-second-min-10-minutes [IN] OBSERVATION
RDS DB instance hours are billed in 1-second increments with a minimum charge of 10 minutes.

### rds-console-multi-az-instance-yes-cluster-3-zones [IN] OBSERVATION
In the RDS console, Multi-AZ DB instance deployments show Multi-AZ = "Yes" while cluster deployments show Multi-AZ = "3 Zones".

### rds-cross-region-replication-async-multi-az-sync [IN] OBSERVATION
RDS cross-region replication is asynchronous; within-region Multi-AZ replication is synchronous.

### rds-cross-region-snapshot-copy-increases-destination-storage-cost [IN] OBSERVATION
Copying an RDS snapshot to another Region increases backup storage costs in the destination Region.

### rds-data-transfer-billed-per-gb-internet-and-cross-region [IN] OBSERVATION
RDS data transfer is billed per GB for traffic to/from the internet and other AWS Regions.

### rds-db-parameter-groups-control-engine-behavior [IN] OBSERVATION
RDS DB parameter groups control engine-specific behavior and configuration settings.

### rds-db-r6g-graviton2-memory-optimized [IN] OBSERVATION
The `db.r6g` instance class type is memory-optimized and powered by AWS Graviton2 processors.

### rds-db-subnet-group-spans-multiple-azs [IN] OBSERVATION
RDS requires a DB subnet group spanning multiple Availability Zones within a VPC.

### rds-db2-byol-requires-custom-parameter-group-with-ibm-ids [IN] OBSERVATION
RDS for Db2 BYOL requires creating a custom DB parameter group with `rds.ibm_customer_id` and `rds.ibm_site_id` parameters before creating the DB instance.

### rds-db2-license-switch-requires-snapshot-restore [IN] OBSERVATION
Switching RDS for Db2 between BYOL and Marketplace licensing requires restoring from an automated backup or snapshot — it cannot be done as an in-place modification.

### rds-db2-multi-az-cold-standbys [IN] OBSERVATION
RDS for Db2 Multi-AZ standbys are cold — Db2 is installed but not running, not readable, and not serving requests.

### rds-db2-no-gp2-no-magnetic [IN] OBSERVATION
Db2 on RDS does not support gp2 or magnetic storage types.

### rds-db2-two-editions-se-ae [IN] OBSERVATION
RDS for Db2 supports two editions: Standard Edition (`db2-se`) and Advanced Edition (`db2-ae`), with parameter group families `db2-se-11.5` and `db2-ae-11.5`.

### rds-default-vpc-unless-specified [IN] OBSERVATION
All new RDS DB instances are created in the default VPC unless you explicitly choose another VPC.

### rds-delete-source-promotes-same-region-replicas [IN] OBSERVATION
Deleting a source DB instance automatically promotes all same-Region read replicas to standalone instances.

### rds-disk-space-85-percent-threshold [IN] OBSERVATION
RDS disk space consumption above 85% warrants investigation.

### rds-dlv-fixed-1024gib-3000iops-piops-only [IN] OBSERVATION
RDS Dedicated Log Volume (DLV) is a fixed 1,024 GiB / 3,000 IOPS volume that requires Provisioned IOPS storage and a reboot to enable.

### rds-dlv-supported-engines-versions [IN] OBSERVATION
DLV is supported on MariaDB 10.6.7+, MySQL 8.0.28+/8.4.3+, and PostgreSQL 13.10+/14.7+/15.2+/16.1+.

### rds-ebs-provisioned-storage-billed-per-second-min-10min [IN] OBSERVATION
RDS EBS provisioned storage is billed per second with a 10-minute minimum, matching the compute billing model.

### rds-encrypted-snapshots-cannot-be-public-max-20-accounts [IN] OBSERVATION
Encrypted RDS/RDS cluster snapshots cannot be shared publicly but can be shared with up to 20 AWS accounts; unencrypted snapshots can be made public.

### rds-encryption-at-rest-aes-256 [IN] OBSERVATION
RDS encryption at rest uses AES-256 and covers both DB instances and snapshots.

### rds-failover-aurora-vs-multi-az-different-mechanisms [IN] OBSERVATION
Aurora clusters fail over by promoting an Aurora Replica to primary, while Multi-AZ DB clusters fail over by terminating the primary and promoting a readable standby — different mechanisms, same `FailoverDBCluster` API.

### rds-failover-db-cluster-multi-az-under-35-seconds [IN] OBSERVATION
Failover for Multi-AZ DB clusters using the `FailoverDBCluster` API typically completes in less than 35 seconds.

### rds-failover-target-instance-optional [IN] OBSERVATION
The `TargetDBInstanceIdentifier` parameter in `FailoverDBCluster` is optional — if omitted, RDS chooses which replica/standby to promote; it is not supported for RDS for MySQL Multi-AZ DB clusters.

### rds-first-snapshot-full-subsequent-incremental [IN] OBSERVATION
The first RDS backup snapshot is a full backup; subsequent snapshots are incremental (only changed data).

### rds-free-tier-engines-t3-t4g-micro [IN] OBSERVATION
RDS Free Tier eligible engines are MariaDB, MySQL, PostgreSQL, and SQL Server Express Edition on db.t3.micro or db.t4g.micro (t4g.micro not available for SQL Server Express).

### rds-free-tier-single-az-only [IN] OBSERVATION
RDS Free Tier is restricted to Single-AZ deployments only.

### rds-gp2-iops-formula [IN] OBSERVATION
RDS gp2 storage provides 3 IOPS per GiB (minimum 100 IOPS), with burst to 3,000 IOPS for volumes under 1,000 GiB.

### rds-gp3-baseline-3000-iops-125-mibs [IN] OBSERVATION
RDS gp3 storage provides a baseline of 3,000 IOPS and 125 MiB/s per single volume; 12,000 IOPS and 500 MiB/s when striped above threshold.

### rds-iam-management-plane-sg-vpc-data-plane [IN] OBSERVATION
IAM governs management-plane access to RDS resources; security groups and VPC govern data-plane (network) access.

### rds-instance-class-availability-region-and-engine-dependent [IN] OBSERVATION
RDS instance class availability varies by AWS Region and supported DB engine.

### rds-instance-class-change-may-cause-downtime [IN] OBSERVATION
Changing an RDS DB instance class requires modifying the DB instance and can cause downtime depending on apply timing (immediately vs. next maintenance window).

### rds-instance-class-naming-convention [IN] OBSERVATION
RDS DB instance classes follow the naming convention `db.<type>.<size>` (e.g., `db.r6g.2xlarge`).

### rds-instance-class-prefixes [IN] OBSERVATION
RDS instance class prefixes: general purpose `db.m*`, memory optimized `db.z*`/`db.x*`/`db.r*`, compute optimized `db.c*`, burstable `db.t*`.

### rds-instance-level-iops-cap-overrides-volume [IN] OBSERVATION
EBS-optimized instance-level IOPS caps override volume-level provisioning — the instance class limits actual achievable IOPS.

### rds-instances-run-in-vpcs [IN] OBSERVATION
RDS DB instances run inside VPCs and are typically placed in private subnets.

### rds-io-request-charges-magnetic-only [IN] OBSERVATION
RDS I/O request charges (per 1 million requests) apply only to magnetic storage, not to SSD storage types.

### rds-io1-iops-to-gib-ratio-0point5-to-50 [IN] OBSERVATION
RDS io1 storage has an IOPS-to-GiB ratio of 0.5–50 (1–50 for SQL Server).

### rds-io2-block-express-up-to-256000-iops [IN] OBSERVATION
RDS io2 Block Express volumes support up to 256,000 IOPS with sub-millisecond latency and an IOPS-to-GiB ratio of 0.5–1,000 on Nitro instances.

### rds-io2-iops-to-gib-ratio-non-nitro-max-500 [IN] OBSERVATION
RDS io2 Block Express IOPS-to-GiB ratio is 0.5–500 on non-Nitro instances (vs 0.5–1,000 on Nitro).

### rds-iops-improves-when-working-set-fits-memory [IN] OBSERVATION
RDS IOPS performance improves when the working set fits into memory, minimizing disk I/O.

### rds-license-manager-tracks-by-vcpu [IN] OBSERVATION
AWS License Manager tracks RDS database licenses (Oracle, Db2) based on virtual cores (vCPUs), with resource discovery taking up to 24 hours.

### rds-magnetic-max-3tib-1000-iops [IN] OBSERVATION
RDS magnetic storage supports a maximum of 3 TiB and 1,000 IOPS, with no autoscaling and no elastic volumes support.

### rds-managed-processes-no-customer-security-config [IN] OBSERVATION
RDS-managed processes (backups, read replica replication) do not require customer-configured security.

### rds-manual-snapshot-limit-100-per-region [IN] OBSERVATION
RDS has a limit of 100 manual snapshots per Region.

### rds-manual-snapshots-never-auto-deleted [IN] OBSERVATION
RDS manual snapshots are never automatically deleted.

### rds-max-storage-64tib-most-256tib-oracle-sqlserver [IN] OBSERVATION
RDS max storage is 64 TiB for Db2/MariaDB/MySQL/PostgreSQL and 256 TiB for Oracle and SQL Server (with additional volumes).

### rds-monitoring-five-tools [IN] OBSERVATION
RDS monitoring integrates with five tools: CloudWatch (metrics), Performance Insights (DB load), Enhanced Monitoring (OS-level metrics), CloudWatch Database Insights, and DevOps Guru (anomaly detection).

### rds-multi-az-and-read-replicas-simultaneously [IN] OBSERVATION
An RDS DB instance can have both a synchronous Multi-AZ standby replica and asynchronous read replicas simultaneously.

### rds-multi-az-cluster-exactly-two-standby-readers [IN] OBSERVATION
A Multi-AZ DB cluster deployment has exactly one writer instance and two standby reader instances.

### rds-multi-az-cluster-spans-3-azs [IN] OBSERVATION
A Multi-AZ DB cluster deployment spans 3 Availability Zones.

### rds-multi-az-cluster-two-standbys-serve-reads [IN] OBSERVATION
In a Multi-AZ DB cluster deployment, there are two standby instances that provide failover support and can serve read traffic.

### rds-multi-az-instance-standby-no-reads [IN] OBSERVATION
In a Multi-AZ DB instance deployment, the single standby provides failover support only and does not serve read traffic.

### rds-multi-az-standby-sync-no-read [IN] OBSERVATION
RDS Multi-AZ standby replicas use synchronous replication and cannot serve read traffic.

### rds-multi-volume-snapshots-cover-all-volumes [IN] OBSERVATION
RDS multi-volume configurations are fully supported — snapshots, backups, and PITR cover all storage volumes (primary + additional).

### rds-no-circular-replication [IN] OBSERVATION
RDS does not support circular replication — a replica cannot replicate back to its source.

### rds-no-read-replica-autoscaling [IN] OBSERVATION
RDS does not auto-scale read replicas; they must be created and deleted manually.

### rds-only-manual-snapshots-can-be-shared [IN] OBSERVATION
Only manual RDS snapshots can be shared; automated snapshots cannot be shared.

### rds-oracle-byol-supports-ee-and-se2 [IN] OBSERVATION
RDS for Oracle Bring Your Own License (BYOL) supports both Enterprise Edition (EE) and Standard Edition 2 (SE2).

### rds-oracle-edition-migration-se2-to-ee-only [IN] OBSERVATION
RDS for Oracle edition migration only works SE2 → EE (via snapshot-and-restore); migrating from EE to other editions is not possible.

### rds-oracle-extra-encryption-options [IN] OBSERVATION
Oracle on RDS has two additional encryption options beyond standard RDS encryption: native network encryption and Transparent Data Encryption (TDE).

### rds-oracle-li-only-se2 [IN] OBSERVATION
RDS for Oracle License Included (LI) model is only available for Standard Edition 2 (SE2) — not for Enterprise Edition.

### rds-oracle-mounted-db2-standby-replicas-for-dr [IN] OBSERVATION
Oracle supports mounted-mode replicas and Db2 supports standby-mode replicas — neither accepts user connections and both are used for cross-Region disaster recovery.

### rds-oracle-multi-az-byol-requires-two-licenses [IN] OBSERVATION
Multi-AZ deployments with RDS for Oracle BYOL require licenses for both the primary and standby DB instances.

### rds-oracle-r5b-only-256000-iops-io1 [IN] OBSERVATION
Oracle on RDS r5b is the only instance type supporting the maximum 256,000 IOPS on io1 storage.

### rds-oracle-supports-processor-configuration [IN] OBSERVATION
Oracle on RDS supports processor configuration at the instance class level (CPU/threading options).

### rds-performance-baseline-under-varying-loads [IN] OBSERVATION
RDS performance baselines must be measured under different load conditions at various times, not just peak or average, to distinguish normal patterns from anomalies.

### rds-performance-insights-identifies-queries [IN] OBSERVATION
RDS Performance Insights assesses database load and identifies problematic queries.

### rds-pitr-any-point-within-retention-period [IN] OBSERVATION
RDS point-in-time recovery (PITR) allows restoring a DB instance to any point within the backup retention period.

### rds-promote-read-replica-to-standalone [IN] OBSERVATION
Promoting an RDS read replica converts it to a standalone read/write DB instance.

### rds-provisioned-iops-billed-regardless-of-use [IN] OBSERVATION
RDS Provisioned IOPS charges are incurred per IOPS per month regardless of actual IOPS consumed.

### rds-proxy-recommended-for-lambda-connection-pooling [IN] OBSERVATION
RDS Proxy is the recommended pattern for Lambda-to-RDS connectivity — it manages connection pooling and prevents connection exhaustion from concurrent Lambda invocations.

### rds-read-replica-async-replication [IN] OBSERVATION
RDS read replicas use asynchronous replication from the primary DB instance.

### rds-read-replica-billed-standard-rates [IN] OBSERVATION
RDS read replicas are billed at standard DB instance rates.

### rds-read-replica-can-differ-storage-type [IN] OBSERVATION
RDS read replicas can use a different storage type (Provisioned IOPS, General Purpose, or Magnetic) than their source, with constraints based on allocation size (minimum 100 GiB for Provisioned IOPS).

### rds-reboot-force-failover-requires-multi-az [IN] OBSERVATION
The `ForceFailover` parameter on `RebootDBInstance` can only be used when Multi-AZ is enabled; it triggers a Multi-AZ failover during the reboot.

### rds-reboot-not-rds-custom [IN] OBSERVATION
The `RebootDBInstance` API does not apply to RDS Custom instances; for Multi-AZ DB clusters, `RebootDBCluster` must be used instead.

### rds-reboot-required-for-parameter-group-changes [IN] OBSERVATION
A reboot of an RDS DB instance (via `RebootDBInstance`) is required to apply DB parameter group changes — they do not take effect automatically.

### rds-replica-storage-allocation-increase-min-10-percent [IN] OBSERVATION
Allocated storage increases on an RDS read replica must be at least 10%.

### rds-reserved-instance-benefit-across-instances-same-hour [IN] OBSERVATION
RDS Reserved Instance pricing benefit applies across multiple instances started and stopped within the same hour.

### rds-reserved-instances-1-or-3-year [IN] OBSERVATION
RDS Reserved Instances are available in 1-year or 3-year commitment terms for discounted pricing.

### rds-same-region-replication-no-data-transfer-charge [IN] OBSERVATION
RDS same-Region read replica replication incurs no data transfer charges; cross-Region replication does.

### rds-secrets-manager-password-rotation [IN] OBSERVATION
AWS Secrets Manager integrates with RDS for database password rotation and management.

### rds-security-group-pattern-ec2-to-rds [IN] OBSERVATION
The recommended RDS security group pattern places EC2 app servers in one security group and the RDS instance in another that references the EC2 security group as an allowed source — clients cannot directly access the DB.

### rds-security-groups-deny-all-by-default [IN] OBSERVATION
RDS security groups block all access by default until explicit rules are added.

### rds-shared-responsibility-customer-owns-query-tuning [IN] OBSERVATION
Under the RDS shared responsibility model, AWS handles infrastructure, patching, backups, and scaling; the customer is responsible for application optimization, query tuning, and schema design.

### rds-six-billing-components [IN] OBSERVATION
RDS has six billing components: compute hours, storage, I/O requests, provisioned IOPS, backup storage, and data transfer.

### rds-six-supported-engines [IN] OBSERVATION
Amazon RDS supports six database engines: IBM Db2, MariaDB, Microsoft SQL Server, MySQL, Oracle Database, and PostgreSQL.

### rds-sqlserver-lower-max-iops-gp3-io1 [IN] OBSERVATION
SQL Server on RDS has lower maximum IOPS than other engines: 16,000 IOPS on gp3 (vs 64,000) and 64,000 IOPS on io1 (vs 256,000), with a smaller max gp3 volume size of 16,384 GiB.

### rds-ssl-tls-all-major-engines [IN] OBSERVATION
SSL/TLS connections are supported for all major RDS engines: Db2, MySQL, MariaDB, PostgreSQL, Oracle, and SQL Server.

### rds-storage-architecture-complex-behind-simple-provisioning-interface [IN] OBSERVATION
RDS presents simple storage type selection (three types) but underneath all storage uses EBS volumes with automatic striping across four volumes above capacity thresholds — performance characteristics and failure modes depend on hidden infrastructure complexity that the provisioning interface does not surface

### rds-storage-billed-per-gib-per-month-prorated [IN] OBSERVATION
RDS storage is billed per GiB per month; scaling mid-month results in prorated charges.

### rds-storage-types-gp-ssd-piops-magnetic [IN] OBSERVATION
RDS offers three EBS-backed storage types: General Purpose (SSD) for dev/test, Provisioned IOPS (PIOPS) for production, and Magnetic (legacy, not recommended).

### rds-supports-dual-stack-ipv4-ipv6 [IN] OBSERVATION
RDS supports dual-stack mode (IPv4 and IPv6) within a VPC.

### rds-three-storage-types [IN] OBSERVATION
RDS offers three storage types: Provisioned IOPS SSD (io1/io2), General Purpose SSD (gp2/gp3), and Magnetic (standard/legacy).

### rds-typical-architecture-elb-ec2-public-rds-private [IN] OBSERVATION
Typical RDS architecture: ELB → EC2 app servers (public subnets) → RDS (private subnets).

### rds-user-connections-default-zero-unlimited [IN] OBSERVATION
The RDS `User Connections` parameter defaults to 0 (unlimited) and is controlled via parameter groups, not instance settings directly.

### rds-uses-ntp-for-time-sync [IN] OBSERVATION
Amazon RDS uses NTP to synchronize time on DB instances.

### rds-volume-modification-optimizing-lower-of-source-target [IN] OBSERVATION
During RDS volume modification in `optimizing` state, performance is at least the lower of source or target specifications.

### rds-volume-striping-4-volumes-above-threshold [IN] OBSERVATION
RDS automatically stripes across 4 EBS volumes above a threshold (400 GiB for most engines, 200 GiB for Oracle); SQL Server always uses 1 volume with no striping.

### rds-vpc-endpoints-privatelink-api-traffic [IN] OBSERVATION
AWS PrivateLink (interface VPC endpoints) can be used to keep RDS API traffic off the public internet.

### rds-vpc-no-extra-charge [IN] OBSERVATION
Running an RDS instance in a VPC incurs no additional charge beyond standard RDS pricing.

### rds-zero-etl-delete-before-blue-green-switchover [IN] OBSERVATION
Active zero-ETL integrations must be deleted before performing a blue/green deployment switchover, then recreated afterward.

### rds-zero-etl-no-read-replica-sources [IN] OBSERVATION
RDS read replicas cannot be used as sources for zero-ETL integrations (any engine).

### rds-zero-etl-quotas-100-per-account-region [IN] OBSERVATION
RDS zero-ETL integration quotas are 100 integrations per account per Region, 50 per target, and 5 per source instance.

### rds-zero-etl-same-region-required [IN] OBSERVATION
RDS zero-ETL integrations require the source database and target (Redshift or SageMaker lakehouse) to be in the same AWS Region.

### rds-zero-etl-targets-redshift-sagemaker-lakehouse [IN] OBSERVATION
RDS zero-ETL integrations replicate transactional data to Amazon Redshift (provisioned or serverless) or Amazon SageMaker AI lakehouse destinations.

### real-time-audit-alerting-requires-multi-service-integration-chain [IN] OBSERVATION
Real-time security alerting from CloudTrail requires configuring a multi-service chain — CloudTrail delivers to CloudWatch Logs (requiring a dedicated IAM role), metric filters extract patterns from log streams, and CloudWatch alarms trigger on the resulting metrics — where each link has independent failure and misconfiguration potential.

### rebalance-recommendation-best-effort [IN] OBSERVATION
EC2 rebalance recommendations are delivered on a best-effort basis — they are not guaranteed to arrive before the 2-minute Spot interruption notice.

### rebalance-recommendation-eventbridge-detail-type [IN] OBSERVATION
The EventBridge detail-type for Spot Instance rebalance recommendations is exactly `EC2 Instance Rebalance Recommendation` with source `aws.ec2`.

### rebalance-recommendation-metadata-path [IN] OBSERVATION
Rebalance recommendation signals are available via instance metadata at `events/recommendations/rebalance`; returns HTTP 404 if no signal has been emitted.

### reliability-failure-management-automatic-self-healing [IN] OBSERVATION
Failure Management in the Reliability Pillar emphasizes automatic failure detection and self-healing, not manual intervention.

### reliability-foundations-quotas-and-network [IN] OBSERVATION
The Foundations area of the Reliability Pillar focuses on ensuring service quotas and network topology can accommodate the workload.

### reliability-on-premises-three-challenges [IN] OBSERVATION
The three on-premises challenges AWS reliability practices address are: single points of failure, lack of automation, and lack of elasticity.

### reliability-pillar-four-key-areas [IN] OBSERVATION
The Reliability Pillar addresses four key areas: Foundations, Workload Architecture, Change Management, and Failure Management.

### resource-groups-cloudtrail-event-source [IN] OBSERVATION
Resource Groups API events use `resource-groups.amazonaws.com` as their CloudTrail event source; Tag Editor console actions use `resource-explorer` as their event source.

### ri-3-year-bigger-discount-than-1-year [IN] OBSERVATION
A 3-year Reserved Instance term offers a bigger discount than a 1-year term.

### ri-cannot-be-cancelled-after-purchase [IN] OBSERVATION
Reserved Instances cannot be cancelled after purchase — they can only be modified, exchanged (Convertible class only), or sold on the RI Marketplace.

### ri-discount-applies-immediately-on-match [IN] OBSERVATION
RI discounts apply immediately when a running On-Demand instance matches the RI attributes — no manual association is required.

### ri-do-not-auto-renew [IN] OBSERVATION
Reserved Instances do not auto-renew — when they expire, usage reverts to On-Demand rates.

### ri-must-match-type-region-tenancy-platform [IN] OBSERVATION
An RI must match instance type, Region, tenancy, and platform to apply the billing discount.

### ri-payment-options-all-partial-no-upfront [IN] OBSERVATION
RI payment options are All Upfront (most savings), Partial Upfront, and No Upfront (least savings); No Upfront requires a successful billing history.

### ri-sellable-on-marketplace [IN] OBSERVATION
Reserved Instances can be listed for sale to other AWS customers on the Reserved Instance Marketplace.

### ri-standard-vs-convertible-offering-classes [IN] OBSERVATION
Standard RIs offer higher discounts but can only be modified; Convertible RIs offer lower discounts but can be exchanged for different instance attributes.

### ris-are-billing-discounts-not-physical-instances [IN] OBSERVATION
EC2 Reserved Instances are billing constructs (discounts applied to matching On-Demand usage), not physical instances or capacity reservations.

### route53-100-percent-availability-sla [IN] OBSERVATION
Route 53 offers a 100% availability SLA for DNS queries — the only AWS service with this guarantee.

### route53-alias-records-for-aws-resources [IN] OBSERVATION
Alias records are Route 53-specific records that can route traffic to AWS resources (S3, CloudFront, ELB) and are distinct from standard CNAME records.

### route53-all-api-actions-logged-cloudtrail [IN] OBSERVATION
All Route 53 API actions are logged by CloudTrail with no exceptions, using three distinct event sources: `route53.amazonaws.com` (DNS), `route53domains.amazonaws.com` (registration), and `route53resolver.amazonaws.com` (Resolver).

### route53-auto-creates-hosted-zone-on-registration [IN] OBSERVATION
Route 53 automatically creates a public hosted zone when you register a domain name.

### route53-calculated-health-checks [IN] OBSERVATION
Calculated health checks aggregate multiple health checks for N-of-M monitoring scenarios (e.g., alert when 2 of 5 servers are down).

### route53-cloudtrail-excludes-domain-pii [IN] OBSERVATION
CloudTrail logs for Route 53 domain contact updates explicitly exclude personally-identifying information (PII).

### route53-dns-failover-requires-health-check-association [IN] OBSERVATION
DNS failover requires associating a health check with each resource record — Route 53 routes traffic only to resources whose health checks report healthy.

### route53-dns-firewall-filters-outbound [IN] OBSERVATION
Route 53 Resolver DNS Firewall filters outbound DNS traffic from VPC Resolver, not inbound.

### route53-dns-resolution-9-steps [IN] OBSERVATION
DNS resolution follows a 9-step flow: User → Browser → DNS Resolver → Root Name Server → TLD Name Server → Route 53 Name Server → back to resolver → browser → web server.

### route53-domain-events-lowercase-first-letter [IN] OBSERVATION
Route 53 domain registration event names use a lowercase first letter in CloudTrail logs (e.g., `updateDomainContact` instead of `UpdateDomainContact`) — a naming inconsistency from DNS management events.

### route53-edns-client-subnet-improves-location [IN] OBSERVATION
Route 53 geolocation, geoproximity, and latency routing policies use EDNS0 (edns-client-subnet) to improve location estimation of users.

### route53-eight-routing-policies [IN] OBSERVATION
Route 53 offers eight routing policies: simple, failover, geolocation, geoproximity, latency, IP-based, multivalue answer, and weighted.

### route53-event-history-requires-us-east-1 [IN] OBSERVATION
To view Route 53 events in CloudTrail Event History, you must select the US East (N. Virginia) region in the console.

### route53-failover-requires-two-records [IN] OBSERVATION
Failover routing requires exactly two records (primary + secondary) and a health check on the primary.

### route53-geolocation-vs-geoproximity-vs-latency [IN] OBSERVATION
Geolocation routes by where the user is; geoproximity routes by where resources are (with adjustable bias); latency routes by measured network latency to AWS Regions.

### route53-health-check-failure-count-resets [IN] OBSERVATION
The health check failure count resets to zero if the endpoint responds before reaching the failure threshold.

### route53-health-check-notification-chain [IN] OBSERVATION
Route 53 health check notification chain: health check → CloudWatch alarm → SNS notification.

### route53-health-check-protocols [IN] OBSERVATION
Route 53 health checks support three protocols: HTTP, HTTPS, and TCP.

### route53-health-checks-five-routing-policies [IN] OBSERVATION
Route 53 health checks integrate with failover, multivalue answer, weighted, latency, and geolocation routing policies to route only to healthy endpoints.

### route53-hosted-zone-shares-domain-name [IN] OBSERVATION
A hosted zone and its corresponding domain always share the same name.

### route53-ip-based-routing-cidr-client-mapping [IN] OBSERVATION
Route 53 IP-based routing routes based on source IP address of the client using CIDR-based mappings, useful when you have specific IP-to-location data (e.g., ISP data).

### route53-ip-based-routing-no-private-hosted-zone [IN] OBSERVATION
All routing policies except IP-based routing can be used in private hosted zones.

### route53-is-dns-service-not-content-host [IN] OBSERVATION
Route 53 is a DNS service that routes requests to where content lives (EC2, S3, etc.) — it does not host content itself.

### route53-multivalue-returns-up-to-8-records [IN] OBSERVATION
Multivalue answer routing returns up to 8 healthy records selected at random; it is not a substitute for ELB.

### route53-private-hosted-zone-tied-to-vpc [IN] OBSERVATION
Private hosted zones are explicitly scoped to one or more Amazon VPCs for internal DNS resolution.

### route53-profiles-cross-account-multi-vpc [IN] OBSERVATION
Route 53 Profiles enable cross-account, multi-VPC DNS configuration management.

### route53-public-vs-private-hosted-zones [IN] OBSERVATION
Public hosted zones route traffic on the public internet; private hosted zones route traffic within an Amazon VPC.

### route53-record-name-must-end-with-zone-name [IN] OBSERVATION
Route 53 record names must end with the hosted zone name.

### route53-resolver-outposts-hybrid-dns [IN] OBSERVATION
Route 53 Resolver on Outposts extends DNS resolution between Outpost racks and on-premises data centers via Resolver endpoints.

### route53-three-core-functions [IN] OBSERVATION
Route 53 provides three core functions: domain name registration, DNS routing, and health checking — usable in any combination.

### route53-three-health-check-types [IN] OBSERVATION
Route 53 supports three health check types: monitor an endpoint directly, monitor other health checks (calculated), and monitor a CloudWatch alarm state.

### route53-tld-cache-two-days [IN] OBSERVATION
TLD name server results are cached by DNS resolvers for approximately two days.

### route53-traffic-flow-combines-policies [IN] OBSERVATION
Route 53 Traffic Flow is a visual policy editor that can combine multiple routing policies into complex routing trees.

### route53-vpc-resolver-recursive-dns [IN] OBSERVATION
Route 53 VPC Resolver provides recursive DNS for VPCs in AWS Regions, Outposts racks, and on-premises networks, and supports conditional forwarding rules and Resolver endpoints.

### route53-weighted-zero-stops-traffic [IN] OBSERVATION
Weighted routing with weight 0 stops sending traffic to a resource; if all weights are 0, records are returned equally.

### s3-128kb-minimum-billable-size-ia-glacier-ir [IN] OBSERVATION
S3 Standard-IA, One Zone-IA, and Glacier Instant Retrieval have a 128 KB minimum billable object size — smaller objects are billed as 128 KB.

### s3-access-control-requires-three-layer-lockdown [IN] OBSERVATION
Fully securing S3 requires disabling legacy ACLs, enforcing bucket-owner Object Ownership, and enabling Block Public Access — each addresses a different legacy access vector.

### s3-access-grants-support-iam-identity-center [IN] OBSERVATION
S3 Access Grants support corporate directory identities (e.g., Active Directory users) via IAM Identity Center.

### s3-access-point-policies-evaluated-with-bucket-policy [IN] OBSERVATION
S3 Access Point policies are evaluated in conjunction with the underlying bucket policy — both must allow the request.

### s3-access-points-vpc-restriction [IN] OBSERVATION
S3 Access Points can be configured to accept requests only from a specific VPC.

### s3-account-owns-bucket-not-iam-user [IN] OBSERVATION
The AWS account that creates an S3 bucket owns it — not the IAM user that performed the creation.

### s3-acl-replacement-all-or-nothing [IN] OBSERVATION
S3 ACL updates require replacing the entire existing ACL — partial updates are not supported.

### s3-acls-are-legacy [IN] OBSERVATION
S3 ACLs are legacy; AWS recommends keeping them turned off and using policies instead.

### s3-acls-disabled-by-default [IN] OBSERVATION
S3 ACLs are disabled by default for new buckets via Object Ownership set to "Bucket owner enforced"; AWS recommends keeping them disabled.

### s3-all-classes-11-nines-except-rrs [IN] OBSERVATION
All S3 storage classes provide 99.999999999% (11 nines) durability except Reduced Redundancy Storage which provides only 99.99% durability.

### s3-atomic-single-key-reads [IN] OBSERVATION
S3 provides atomic single-key updates: a concurrent GET request never returns partial or corrupt data.

### s3-aws-config-no-directory-bucket-support [IN] OBSERVATION
AWS Config managed rules only evaluate general purpose S3 buckets; directory buckets are not supported.

### s3-batch-operations-billions-single-request [IN] OBSERVATION
S3 Batch Operations can process billions of objects with a single API request for bulk operations.

### s3-batch-replication-can-replicate-replicas [IN] OBSERVATION
S3 Batch Replication can replicate existing objects, previously failed objects, already-replicated objects, and replicas created by other replication rules (replicas of replicas).

### s3-batch-replication-retry-failed-and-rereplicate [IN] OBSERVATION
S3 Batch Replication can retry FAILED replications and re-replicate objects that were themselves replicas; live replication cannot re-replicate replicas.

### s3-bidirectional-replication-requires-replica-modification-sync [IN] OBSERVATION
S3 two-way (bi-directional) replication requires replica modification sync to be enabled on replication rules to keep objects and metadata in sync.

### s3-block-public-access-default-bucket-account-org [IN] OBSERVATION
S3 Block Public Access is enabled by default at the bucket level and can be enforced at the bucket, account, or organization level via AWS Organizations; it overrides any permissive ACLs or policies.

### s3-bucket-arn-patterns [IN] OBSERVATION
S3 ARN patterns: bucket-level is `arn:aws:s3:::bucket-name`, objects within a bucket use `arn:aws:s3:::bucket-name/*` — both are often needed in policies.

### s3-bucket-max-10000-access-points [IN] OBSERVATION
A single S3 bucket can have up to 10,000 access points.

### s3-bucket-must-be-emptied-before-deletion [IN] OBSERVATION
S3 buckets must be emptied of all objects before they can be deleted.

### s3-bucket-name-region-immutable [IN] OBSERVATION
S3 bucket name and region cannot be changed after creation.

### s3-bucket-name-squatting-risk [IN] OBSERVATION
Deleted S3 bucket names can be claimed by other AWS accounts; AWS recommends appending GUIDs to bucket names and avoiding bucket deletion.

### s3-bucket-names-globally-unique-per-partition [IN] OBSERVATION
S3 bucket names are globally unique within a partition (`aws`, `aws-cn`, `aws-us-gov`), not just per account or per Region; a name cannot be reused until the original bucket is deleted.

### s3-bucket-owner-can-always-delete-and-deny [IN] OBSERVATION
The S3 bucket owner can always delete objects and deny access regardless of object ownership.

### s3-bucket-owner-no-permission-on-cross-account-objects [IN] OBSERVATION
The S3 bucket owner has no permissions on objects uploaded by other AWS accounts — bucket policies do not apply to objects owned by other accounts.

### s3-bucket-policies-cannot-block-lifecycle [IN] OBSERVATION
Bucket policies cannot prevent S3 Lifecycle transitions or deletions — lifecycle actions operate independently of bucket policies.

### s3-bucket-policy-size-limit-20kb [IN] OBSERVATION
S3 bucket policies are limited to 20 KB in size.

### s3-buckets-block-public-access-since-april-2023 [IN] OBSERVATION
Buckets created since April 2023 block all public access by default.

### s3-concurrent-put-latest-timestamp-wins [IN] OBSERVATION
For concurrent PUT requests to the same S3 key, the latest-timestamp write wins; there is no built-in object locking for concurrent writers.

### s3-cross-account-object-acl-required [IN] OBSERVATION
When an S3 object owner differs from the bucket owner, the object owner must first grant permissions to the bucket owner via an object ACL before the bucket owner can delegate access.

### s3-cross-account-object-delegation-requires-role [IN] OBSERVATION
Cross-account delegation of S3 object permissions is not supported directly — an IAM role with AssumeRole must be used instead.

### s3-cross-account-permission-no-redelegation [IN] OBSERVATION
An AWS account receiving cross-account permissions cannot further delegate those permissions to a third account.

### s3-crr-requires-versioning-both-buckets [IN] OBSERVATION
S3 Cross-Region Replication (CRR) requires versioning to be enabled on both source and destination buckets.

### s3-default-bucket-quota-10000 [IN] OBSERVATION
The default S3 bucket quota is 10,000 buckets per AWS account.

### s3-default-object-ownership-bucket-owner-enforced [IN] OBSERVATION
The default Object Ownership setting is "Bucket owner enforced", which disables ACLs.

### s3-delete-creates-delete-marker [IN] OBSERVATION
Deleting a versioned S3 object inserts a delete marker as the current version rather than permanently removing the object.

### s3-directory-bucket-200k-read-100k-write-tps [IN] OBSERVATION
S3 directory buckets support up to 200,000 read TPS and 100,000 write TPS per bucket.

### s3-directory-bucket-90-day-inactivity-deactivation [IN] OBSERVATION
S3 directory buckets in Availability Zones become inactive after 90+ days without request activity, returning HTTP 503 during reactivation (typically minutes); Local Zone buckets are exempt.

### s3-directory-bucket-listobjectsv2-unsorted [IN] OBSERVATION
`ListObjectsV2` returns unsorted results in S3 directory buckets, unlike general purpose buckets which return lexicographically sorted results.

### s3-directory-bucket-naming-format [IN] OBSERVATION
S3 directory bucket names must follow the format `bucket-base-name--zone-id--x-s3`, embedding the Availability Zone or Local Zone ID in the name.

### s3-directory-bucket-quota-100-per-account-region [IN] OBSERVATION
S3 directory buckets are limited to 100 per account per Region (adjustable via AWS Support).

### s3-directory-bucket-requires-az-id-not-name [IN] OBSERVATION
When creating an S3 directory bucket (Express One Zone), you must specify the Availability Zone ID (e.g., `use1-az4`), not the AZ name (e.g., `us-east-1a`).

### s3-directory-bucket-security-locked-down [IN] OBSERVATION
S3 directory buckets have non-modifiable security: Block Public Access always on, ACLs always disabled, Object Ownership always bucket owner enforced.

### s3-directory-buckets-no-public-access [IN] OBSERVATION
S3 directory buckets have public access permanently disabled and cannot have it enabled.

### s3-directory-buckets-no-tagging [IN] OBSERVATION
S3 directory buckets do not support tagging and have prefix limitations compared to general purpose buckets.

### s3-do-not-pin-tls-certificates [IN] OBSERVATION
AWS rotates S3 TLS certificates automatically; users should not pin S3 TLS certificates.

### s3-each-version-full-object-not-diff [IN] OBSERVATION
Each S3 object version is stored as the entire object, not as a diff; storage costs apply per version.

### s3-enforce-https-secure-transport-condition [IN] OBSERVATION
HTTPS can be enforced on S3 buckets using the `aws:SecureTransport` condition key set to `false` in a Deny statement in bucket policies.

### s3-event-notification-destinations-must-grant-permission [IN] OBSERVATION
S3 event notification destination resources (SNS, SQS, Lambda) must grant S3 permission to publish or invoke via their resource policies.

### s3-event-notification-fifo-via-eventbridge [IN] OBSERVATION
To route S3 event notifications to an SQS FIFO queue, use Amazon EventBridge as an intermediary since FIFO queues cannot be direct destinations.

### s3-event-notification-four-destinations [IN] OBSERVATION
S3 event notifications support four destination types: Amazon SNS topics, Amazon SQS queues (standard only), AWS Lambda functions, and Amazon EventBridge.

### s3-event-notification-infinite-loop-risk [IN] OBSERVATION
If an S3 event notification triggers a Lambda that writes back to the same triggering bucket, it can create an infinite loop; mitigate with separate buckets or prefix-scoped triggers.

### s3-event-notification-supported-events [IN] OBSERVATION
S3 event notifications support events for: object created, object removal, object restore, RRS object lost, replication, lifecycle expiration/transition, Intelligent-Tiering archival, object tagging, and object ACL PUT.

### s3-event-notifications-at-least-once-delivery [IN] OBSERVATION
S3 Event Notifications are delivered at least once (not exactly once) — duplicates are possible.

### s3-event-notifications-no-fifo-queue-direct [IN] OBSERVATION
SQS FIFO queues cannot be direct S3 event notification destinations; use EventBridge as an intermediary.

### s3-express-one-zone-10x-faster-50pct-lower-cost [IN] OBSERVATION
S3 Express One Zone provides up to 10x faster access than S3 Standard with 50% lower request costs, using a single AZ with directory buckets.

### s3-express-one-zone-availability-sla-99-95 [IN] OBSERVATION
S3 Express One Zone is designed for 99.95% availability within a single AZ, lower than S3 Standard's 99.99% due to the single-AZ design.

### s3-four-bucket-types [IN] OBSERVATION
S3 supports four bucket types: general purpose, directory, table, and vector.

### s3-glacier-40kb-metadata-overhead [IN] OBSERVATION
S3 Glacier Flexible Retrieval and Glacier Deep Archive each add 40 KB of metadata per archived object (32 KB at the Glacier rate + 8 KB at the Standard rate).

### s3-glacier-flexible-deep-archive-require-restore [IN] OBSERVATION
S3 Glacier Flexible Retrieval and Glacier Deep Archive require a RestoreObject call before objects can be accessed; they do not provide real-time retrieval.

### s3-guardduty-monitors-cloudtrail-data-events [IN] OBSERVATION
Amazon GuardDuty S3 protection monitors CloudTrail S3 data events to detect threats such as anomalous API calls and suspicious access patterns.

### s3-iam-access-analyzer-external-access [IN] OBSERVATION
IAM Access Analyzer identifies S3 resources shared with external entities and validates policies for least-privilege access.

### s3-intelligent-tiering-128kb-threshold [IN] OBSERVATION
Objects smaller than 128 KB in S3 Intelligent-Tiering are not auto-tiered and remain in the Frequent Access tier permanently.

### s3-intelligent-tiering-five-tiers [IN] OBSERVATION
S3 Intelligent-Tiering has five access tiers: three automatic (Frequent Access, Infrequent Access at 30 days, Archive Instant Access at 90 days) and two optional asynchronous tiers (Archive Access at 90+ days, Deep Archive Access at 180+ days).

### s3-intelligent-tiering-no-retrieval-fees [IN] OBSERVATION
S3 Intelligent-Tiering has no retrieval fees; it charges a small per-object monitoring and automation fee instead.

### s3-lifecycle-billing-stops-at-eligibility [IN] OBSERVATION
S3 billing for the original storage class stops when an object becomes eligible for a lifecycle action, even before S3 performs it (exception: transitions to Intelligent-Tiering, where billing changes only after actual transition).

### s3-lifecycle-minimum-storage-duration-charges [IN] OBSERVATION
Expiring objects from storage classes with minimum storage duration requirements (e.g., Standard-IA 30 days, Glacier 90 days) may incur early deletion charges.

### s3-lifecycle-no-retrieval-charges [IN] OBSERVATION
S3 Lifecycle transitions do not incur data retrieval charges, but per-request ingestion charges (PUT/COPY) still apply.

### s3-lifecycle-rules-apply-retroactively [IN] OBSERVATION
S3 Lifecycle rules apply retroactively to existing objects already in the bucket, not just newly created ones.

### s3-lifecycle-single-rule-chains-transitions-and-expiration [IN] OBSERVATION
A single S3 Lifecycle rule can chain multiple transition actions and an expiration action to manage an object's complete lifecycle (e.g., Standard → Standard-IA at 30 days → Glacier at 90 days → delete at 365 days).

### s3-lifecycle-two-action-types [IN] OBSERVATION
S3 Lifecycle rules have two action types: transition actions (move objects to a cheaper storage class after a specified time) and expiration actions (automatically delete objects after a specified time).

### s3-live-replication-no-preexisting-objects [IN] OBSERVATION
S3 live replication does not replicate objects that existed before the replication rule was configured; Batch Replication is required for pre-existing objects.

### s3-macie-discovers-sensitive-data [IN] OBSERVATION
Amazon Macie discovers and protects sensitive data (PII, credentials) stored in S3 buckets.

### s3-max-object-size-5tb [IN] OBSERVATION
The maximum single S3 object size is 5 TB per AWS documentation convention.

### s3-minimum-storage-durations [IN] OBSERVATION
S3 minimum storage durations: Standard-IA/One Zone-IA = 30 days; Glacier IR/Glacier Flexible = 90 days; Glacier Deep Archive = 180 days; Standard/Express One Zone/Intelligent-Tiering = none.

### s3-multipart-upload-10000-parts-times-5gib [IN] OBSERVATION
S3 multipart upload supports up to 10,000 parts of up to 5 GiB each, yielding a theoretical maximum of 48.8 TiB (approximately 53.7 TB).

### s3-no-folder-hierarchy-prefixes-only [IN] OBSERVATION
S3 general purpose buckets have no actual folder hierarchy — prefixes are strings at the beginning of object key names used for organization.

### s3-object-lock-worm-compliance [IN] OBSERVATION
S3 Object Lock provides a WORM (Write Once Read Many) model to prevent accidental or malicious object deletion, useful for regulatory compliance and protecting audit logs.

### s3-object-metadata-two-types [IN] OBSERVATION
S3 object metadata consists of two types: user-defined metadata and system-defined (system-assigned) metadata, stored as name-value pairs.

### s3-object-ownership-three-settings [IN] OBSERVATION
S3 Object Ownership has three settings: bucket owner enforced (default, ACLs disabled), bucket owner preferred, and object writer.

### s3-object-unique-id-key-plus-version-id [IN] OBSERVATION
In a versioning-enabled bucket, a key plus version ID uniquely identifies an S3 object.

### s3-object-url-format [IN] OBSERVATION
S3 object URL format is `https://<bucket>.s3.<region>.amazonaws.com/<key>` (e.g., `https://amzn-s3-demo-bucket.s3.us-west-2.amazonaws.com/photos/puppy.jpg`).

### s3-objects-never-leave-region-unless-explicit [IN] OBSERVATION
S3 objects never leave their AWS Region unless explicitly transferred or replicated (e.g., via CRR or copy operations).

### s3-outposts-no-sse-kms [IN] OBSERVATION
S3 on Outposts does not support SSE-KMS encryption; only SSE-S3 and SSE-C are available.

### s3-preexisting-objects-null-version-id [IN] OBSERVATION
S3 objects that existed before versioning was enabled receive a version ID of `null`.

### s3-presigned-urls-share-private-objects [IN] OBSERVATION
S3 access to private objects can be shared via presigned URLs, which grant temporary access without requiring the recipient to have AWS credentials.

### s3-replication-owner-override [IN] OBSERVATION
S3 replication supports an owner override option that changes replica ownership to the destination bucket's AWS account, restricting access to replicas.

### s3-replication-preserves-metadata [IN] OBSERVATION
S3 replication preserves all metadata including original creation times and version IDs.

### s3-replication-target-different-storage-class [IN] OBSERVATION
S3 replication can replicate objects directly into a different storage class (e.g., Glacier Flexible Retrieval or Deep Archive) at the destination.

### s3-replication-without-rtc-24-48-hours [IN] OBSERVATION
Without S3 RTC, standard CRR/SRR replication timeframe is 24–48 hours and is not SLA-backed.

### s3-requester-pays-shifts-transfer-cost [IN] OBSERVATION
S3 Requester Pays shifts data transfer costs from the bucket owner to the requester.

### s3-resources-private-by-default [IN] OBSERVATION
All S3 resources (buckets, objects, access points, etc.) are private by default — only the root user of the creating account and authorized IAM identities can access them.

### s3-rrs-not-recommended [IN] OBSERVATION
Reduced Redundancy Storage (RRS) is not recommended by AWS; S3 Standard is more cost-effective and provides higher durability (11 nines vs 99.99%).

### s3-rtc-sla-15-minutes [IN] OBSERVATION
S3 Replication Time Control (S3 RTC) provides an SLA guaranteeing 99.99% of new objects are replicated within 15 minutes; S3 RTC does not apply to Batch Replication.

### s3-security-hub-aggregates-s3-findings [IN] OBSERVATION
AWS Security Hub aggregates S3 security findings from GuardDuty, Macie, IAM Access Analyzer, and other services into a single dashboard.

### s3-single-az-classes [IN] OBSERVATION
Only S3 One Zone-IA and S3 Express One Zone use a single Availability Zone; all other storage classes use three or more AZs.

### s3-sse-c-deprecated-april-2026 [IN] OBSERVATION
SSE-C will be disabled by default for all new buckets and existing buckets without SSE-C data starting April 2026; must explicitly enable via PutBucketEncryption API if needed.

### s3-sse-s3-default-encryption [IN] OBSERVATION
SSE-S3 is the default encryption for S3; all new objects are automatically encrypted at rest.

### s3-static-website-https-use-cloudfront-oac [IN] OBSERVATION
For S3 static website hosting with HTTPS and Block Public Access enabled, use CloudFront with Origin Access Control (OAC) rather than disabling Block Public Access.

### s3-storage-class-availability-slas [IN] OBSERVATION
S3 availability SLAs vary by storage class: Standard 99.99%, Standard-IA/Intelligent-Tiering/Glacier IR 99.9%, Express One Zone 99.95%, One Zone-IA 99.5%.

### s3-storage-lens-60-plus-metrics [IN] OBSERVATION
S3 Storage Lens provides organization-wide storage analytics with 60+ metrics covering usage, cost optimization, and security posture.

### s3-strong-read-after-write-consistency [IN] OBSERVATION
S3 provides strong read-after-write consistency for all PUT and DELETE operations in all regions, including new objects, overwrites, deletes, and metadata/ACL/tag reads.

### s3-suspending-versioning-keeps-existing-versions [IN] OBSERVATION
Suspending S3 versioning does not delete existing versions; it only changes behavior for future operations.

### s3-table-bucket-limits [IN] OBSERVATION
S3 table buckets are limited to 10 per account per region and 10,000 tables per bucket, using Apache Iceberg format.

### s3-three-permission-mechanisms [IN] OBSERVATION
S3 has three independent permission mechanisms: identity-based IAM policies, bucket policies (resource-based), and ACLs — each evaluated separately.

### s3-transfer-acceleration-uses-cloudfront-edges [IN] OBSERVATION
S3 Transfer Acceleration uses CloudFront edge locations to speed up file uploads to buckets.

### s3-two-bucket-types-general-and-directory [IN] OBSERVATION
S3 has two bucket types: general purpose buckets (standard, all storage classes except Express One Zone) and directory buckets (S3 Express One Zone, single-digit ms latency).

### s3-unlimited-objects-per-bucket [IN] OBSERVATION
There is no limit on the number of objects you can store in an S3 bucket.

### s3-unpredictable-bucket-names-guid [IN] OBSERVATION
AWS recommends appending a GUID to S3 bucket names to prevent name-squatting and avoiding bucket deletion since another account could reuse the name.

### s3-vector-buckets-for-embeddings [IN] OBSERVATION
S3 vector buckets are purpose-built for vector embeddings and similarity search, integrating with Amazon Bedrock and OpenSearch.

### s3-versioning-applies-all-objects [IN] OBSERVATION
S3 versioning applies to all objects in the bucket; there is no per-object versioning control.

### s3-versioning-cannot-revert-to-unversioned [IN] OBSERVATION
Once S3 versioning is enabled on a bucket, it can never return to the unversioned state — it can only be suspended.

### s3-versioning-disabled-by-default [IN] OBSERVATION
S3 versioning is disabled by default and must be explicitly enabled at the bucket level; buckets have three possible states: Unversioned (default), Versioning-enabled, and Versioning-suspended.

### s3-versioning-lifecycle-noncurrent-expiration-required [IN] OBSERVATION
When enabling S3 versioning on a bucket that already has an expiration lifecycle policy, you must add a noncurrent expiration configuration to maintain permanent delete behavior.

### s3-versioning-simultaneous-writes-all-stored [IN] OBSERVATION
Simultaneous write requests for the same S3 object in a versioned bucket are all stored as separate versions — there are no silent overwrites.

### s3-versioning-soap-api-not-supported [IN] OBSERVATION
The SOAP API does not support S3 Versioning.

### s3-vpc-endpoints-private-traffic [IN] OBSERVATION
S3 VPC endpoints keep S3 traffic off the public internet; bucket policies can reference VPC/endpoint conditions to restrict access, and VPCs without an internet gateway can use endpoints to prevent data exfiltration.

### security-attack-surface-multiplicative-across-network-and-identity-planes [IN] OBSERVATION
VPC network controls and IAM identity controls operate as independent security planes — a gap in either is exploitable regardless of the other — meaning both must be hardened to achieve defense in depth.

### security-controls-defined-as-code [IN] OBSERVATION
The Security Pillar recommends defining and managing security controls as code in version-controlled templates rather than manual processes.

### security-defense-in-depth-all-layers [IN] OBSERVATION
Defense in depth requires applying security controls at all layers: network edge, VPC, load balancing, compute, OS, application, and code.

### security-group-changes-apply-immediately [IN] OBSERVATION
Security group rule changes take effect immediately and are automatically applied to all associated instances.

### security-group-cross-vpc-same-region-association [IN] OBSERVATION
Security groups can be assigned to resources in other VPCs within the same Region via the Security Group VPC Association feature.

### security-group-name-cannot-start-with-sg-prefix [IN] OBSERVATION
Security group names must be unique within a VPC, are not case-sensitive, and cannot start with `sg-`.

### security-group-rules-can-reference-other-security-groups [IN] OBSERVATION
A security group rule can reference another security group as a source or destination, enabling group-to-group communication rules.

### security-groups-changeable-after-launch [IN] OBSERVATION
Security groups assigned to an EC2 instance can be changed after launch.

### security-groups-do-not-filter-dns-dhcp-metadata [IN] OBSERVATION
Security groups do not filter traffic to/from Amazon DNS, DHCP, EC2 instance metadata (169.254.169.254), ECS task metadata, Windows license activation, Time Sync Service, or default VPC router reserved IPs.

### security-groups-evaluate-all-rules-union [IN] OBSERVATION
When multiple security groups are associated with an instance, EC2 evaluates all rules from all associated security groups together as a union.

### security-groups-many-to-many-with-instances [IN] OBSERVATION
Security groups have a many-to-many relationship with instances — multiple security groups can be assigned to one instance, and one security group can be assigned to multiple instances.

### security-groups-no-additional-charge [IN] OBSERVATION
There is no additional charge for using EC2 security groups.

### security-groups-only-allow-rules-no-deny [IN] OBSERVATION
Security groups support only allow rules (no deny rules); traffic not explicitly allowed is denied by default.

### security-groups-resource-level-nacls-subnet-level [IN] OBSERVATION
Security groups operate at the resource/ENI level, while Network ACLs operate at the subnet level.

### security-groups-stateful-nacls-stateless [IN] OBSERVATION
Security groups are stateful (return traffic automatically allowed) while Network ACLs are stateless (return traffic must be explicitly allowed by rules).

### security-pillar-seven-areas [IN] OBSERVATION
The Security Pillar covers seven areas of cloud security: security foundations, IAM, detection, infrastructure protection, data protection, incident response, and application security.

### security-pillar-seven-design-principles [IN] OBSERVATION
The Security Pillar has seven design principles: strong identity foundation, traceability, security at all layers, automate security, protect data in transit and at rest, keep people away from data, and prepare for security events.

### serverless-relational-integration-inherits-full-vpc-security-complexity [IN] OBSERVATION
Serverless-to-relational database integration (Lambda → RDS) requires VPC colocation and connection proxy management, which in turn requires coordinating three independent VPC security control planes (NACLs, security groups, policy isolation via Block Public Access and PrivateLink) — the simplest serverless data-tier pattern inherits the full complexity of VPC defense-in-depth.

### ses-best-practice-one-recipient-per-call [IN] OBSERVATION
SES best practice is to send email to one recipient at a time to avoid total rejection on failure.

### ses-cloudtrail-logs-api-calls [IN] OBSERVATION
CloudTrail provides audit logging of SES API calls; CloudWatch publishes SES email sending events and metrics.

### ses-console-for-testing-smtp-for-bulk [IN] OBSERVATION
SES console is typically used for test emails, SMTP interface for bulk/integration sending, and SES API for raw HTTP requests.

### ses-easy-dkim-route53-integration [IN] OBSERVATION
SES Easy DKIM provides built-in email authentication and integrates with Route 53 for simplified DNS setup, but works with any DNS provider.

### ses-firehose-streaming-destinations [IN] OBSERVATION
SES can stream sending events via Amazon Data Firehose to Redshift, OpenSearch, or S3.

### ses-iam-controls-sending-access [IN] OBSERVATION
IAM controls user access to SES email sending capabilities.

### ses-multi-recipient-atomic-failure [IN] OBSERVATION
When sending to multiple recipients (To, CC, BCC) in a single SES API call, if the call fails the entire email is rejected — no recipients receive it.

### ses-pay-per-use-volume-pricing [IN] OBSERVATION
Amazon SES uses pay-per-use pricing based on volume of emails sent and received.

### ses-receipt-rule-targets-s3-sns-workmail [IN] OBSERVATION
SES receipt rules can deliver incoming email to S3 buckets, SNS topics, or Amazon WorkMail.

### ses-receipt-rules-vs-ip-filters [IN] OBSERVATION
SES inbound email has two control mechanisms: receipt rules (fine-grained, recipient-based) and IP address filters (broad, IP/CIDR-based block or allow).

### ses-received-email-s3-kms-lambda [IN] OBSERVATION
SES can store received emails in S3 (optionally encrypted with KMS) and trigger Lambda functions on receipt.

### ses-receiving-not-all-regions [IN] OBSERVATION
SES email receiving is only available in AWS Regions that have SES inbound endpoints, not all SES regions.

### ses-sns-bounce-complaint-delivery-notifications [IN] OBSERVATION
Amazon SNS provides bounce, complaint, and delivery notifications for SES email sending.

### ses-spam-virus-scanning-spamhaus [IN] OBSERVATION
SES automatically scans inbound email for spam and viruses and blocks mail from Spamhaus and SES block lists.

### ses-supports-sending-and-receiving [IN] OBSERVATION
Amazon SES supports both sending and receiving email, not just outbound.

### ses-three-sending-methods [IN] OBSERVATION
Amazon SES supports three methods for sending email: AWS SDK, SMTP interface, and SES API.

### sigv4-request-five-minute-replay-window [IN] OBSERVATION
AWS rejects SigV4-signed requests that arrive more than 5 minutes after the request timestamp as anti-replay protection.

### sigv4-scoped-to-service-region-date [IN] OBSERVATION
SigV4 signing keys are scoped to a specific service, region, and date — each signature is region-specific and cannot be reused across regions.

### sigv4a-ecdsa-multi-region-signing [IN] OBSERVATION
SigV4a uses ECDSA (asymmetric cryptography) to derive a public-private keypair, enabling a single signature to be valid across multiple regions — required for multi-region API requests like S3 Multi-Region Access Points.

### sns-fifo-topics-fan-out-to-sqs-fifo [IN] OBSERVATION
SNS FIFO topics can fan out to SQS FIFO queues while preserving message ordering.

### spot-capacity-pool-same-type-and-az [IN] OBSERVATION
A Spot capacity pool is a set of unused EC2 instances sharing the same instance type and Availability Zone.

### spot-group-constraints-terminate-together [IN] OBSERVATION
Spot Instances with launch group or Availability Zone group constraints are terminated together as a group when the constraints can no longer be met.

### spot-hibernate-interruption-immediate-no-2min [IN] OBSERVATION
When a Spot Instance's interruption behavior is set to hibernate, the interruption begins immediately with no 2-minute delay (unlike stop and terminate).

### spot-instances-2-minute-interruption-notice [IN] OBSERVATION
When AWS needs Spot capacity back, it interrupts the instance with a two-minute warning notice.

### spot-instances-not-covered-by-savings-plans [IN] OBSERVATION
Spot Instances are not covered by Savings Plans, and Spot spend does not count toward Compute Savings Plans commitments.

### spot-instances-up-to-90-percent-savings [IN] OBSERVATION
EC2 Spot Instances provide up to 90% savings over On-Demand pricing by using spare EC2 capacity.

### spot-interruption-actions-terminate-stop-hibernate [IN] OBSERVATION
When AWS reclaims Spot capacity, it can terminate, stop, or hibernate the Spot Instance (depending on configuration and backing store).

### spot-interruption-test-default-quota-5 [IN] OBSERVATION
The default quota for Spot Instance interruption experiments is 5 Spot Instances per experiment per region (adjustable via Service Quotas).

### spot-interruption-test-via-fis-console [IN] OBSERVATION
Spot Instance interruptions can be manually initiated for testing via the EC2 console, which uses AWS FIS under the hood with the action `aws:ec2:send-spot-instance-interruptions`.

### spot-interruption-three-reasons [IN] OBSERVATION
Spot Instances can be interrupted for three reasons: capacity (EC2 needs it back), price (Spot price exceeds max price), and constraints (launch group or AZ group constraints can't be met).

### spot-max-price-increases-interruption-frequency [IN] OBSERVATION
Specifying a maximum price for Spot Instances increases interruption frequency compared to not specifying one.

### spot-persistent-request-auto-resubmit [IN] OBSERVATION
Persistent Spot Instance requests are automatically resubmitted after interruption; one-time requests are not.

### spot-price-history-available-3-months [IN] OBSERVATION
Spot price history is available for the past 3 months via `aws ec2 describe-spot-price-history`; current prices update every 5 minutes on the console.

### spot-price-set-by-aws-long-term-supply-demand [IN] OBSERVATION
The Spot Instance price is set by Amazon EC2 and adjusted gradually based on long-term supply and demand trends, not by customer bidding.

### spot-rebalance-recommendation-before-interruption [IN] OBSERVATION
EC2 instance rebalance recommendation is a proactive signal indicating elevated interruption risk, delivered before the 2-minute interruption notice.

### sqs-cloudtrail-data-events-not-logged-by-default [IN] OBSERVATION
SQS data events (SendMessage, ReceiveMessage, etc.) are not logged by CloudTrail by default — they must be explicitly enabled via advanced event selectors using resource type `AWS::SQS::Queue`, and incur additional charges.

### sqs-cloudtrail-management-events-logged-by-default [IN] OBSERVATION
SQS management events (CreateQueue, DeleteQueue, SetQueueAttributes, PurgeQueue, etc.) are logged by CloudTrail by default at no additional charge.

### sqs-cloudtrail-message-body-hidden [IN] OBSERVATION
SQS message body content is never recorded in CloudTrail logs — it appears as `"HIDDEN_DUE_TO_SECURITY_REASONS"`.

### sqs-consumers-must-delete-messages [IN] OBSERVATION
SQS messages are not automatically deleted after consumption — consumers must explicitly delete them.

### sqs-cost-allocation-tags-supported [IN] OBSERVATION
SQS supports cost allocation tags for billing tracking.

### sqs-dead-letter-queues-failed-messages [IN] OBSERVATION
SQS dead-letter queues are available for handling messages that fail processing.

### sqs-default-retention-4-days-max-14-days [IN] OBSERVATION
SQS default message retention is 4 days; configurable from 60 seconds to 14 days (1,209,600 seconds).

### sqs-delay-queues-default-delay [IN] OBSERVATION
SQS delay queues allow setting a default delay on message delivery, postponing visibility of new messages.

### sqs-dlq-cloudwatch-alarm-monitoring [IN] OBSERVATION
CloudWatch alarms can be configured to alert on messages arriving in an SQS dead-letter queue; the `ApproximateAgeOfOldestMessage` metric behavior differs between standard and FIFO queues.

### sqs-dlq-default-redrive-allow-policy-allow-all [IN] OBSERVATION
The default SQS redrive allow policy is allowAll, meaning all source queues are allowed to use a dead-letter queue unless explicitly restricted.

### sqs-dlq-is-regular-queue-configured-as-dlq [IN] OBSERVATION
An SQS dead-letter queue must be created as a regular queue first, then configured as a DLQ via a redrive policy on the source queue.

### sqs-dlq-maxreceivecount-controls-transfer [IN] OBSERVATION
The SQS redrive policy's maxReceiveCount parameter controls how many times a message can be received before being moved to the dead-letter queue.

### sqs-dlq-redrive-allow-policy-max-10-arns [IN] OBSERVATION
SQS redrive allow policy in byQueue mode supports a maximum of 10 source queue ARNs.

### sqs-dlq-retention-should-exceed-source [IN] OBSERVATION
SQS DLQ retention period should be longer than the source queue's retention period to avoid premature message deletion.

### sqs-dlq-retention-timestamp-standard-vs-fifo [IN] OBSERVATION
Standard SQS queues retain the original enqueue timestamp when moving messages to the DLQ; FIFO queues reset the enqueue timestamp.

### sqs-dlq-same-account-and-region [IN] OBSERVATION
SQS source queue and its dead-letter queue should be in the same AWS account and Region.

### sqs-dlq-supports-redrive-to-source [IN] OBSERVATION
SQS dead-letter queues support redrive, which moves messages back to the source queue for reprocessing.

### sqs-extended-client-library-s3-over-1mib [IN] OBSERVATION
For SQS messages larger than 1 MiB, use the Amazon SQS Extended Client Library with S3, where SQS holds a pointer to the S3 object.

### sqs-fifo-batch-max-10-may-mix-groups [IN] OBSERVATION
SQS FIFO ReceiveMessage returns up to 10 messages (via MaxNumberOfMessages), preferring the same group ID but may mix groups if fewer than 10 are available in a single group.

### sqs-fifo-dedup-id-idempotent-retries [IN] OBSERVATION
Producer retries with the same SQS FIFO deduplication ID are idempotent — no duplicates are introduced and ordering is preserved.

### sqs-fifo-dlq-breaks-ordering [IN] OBSERVATION
Using a dead-letter queue with SQS FIFO queues can break strict message ordering.

### sqs-fifo-dlq-must-be-fifo [IN] OBSERVATION
A dead-letter queue used with an SQS FIFO queue must also be a FIFO queue.

### sqs-fifo-message-group-id-mandatory [IN] OBSERVATION
A message group ID is mandatory for every message sent to an SQS FIFO queue — the send fails without it.

### sqs-fifo-no-selective-consumption-by-group [IN] OBSERVATION
SQS FIFO consumers cannot selectively request messages from a specific message group ID.

### sqs-fifo-ordering-guarantees-fragile-across-two-dimensions [IN] OBSERVATION
SQS FIFO ordering guarantees are doubly fragile: ordering applies only within a single message group ID (cross-group messages may interleave) AND using a dead-letter queue breaks even intra-group ordering — applications requiring strict global ordering cannot rely on FIFO semantics alone.

### sqs-fifo-ordering-per-message-group-id [IN] OBSERVATION
SQS FIFO ordering guarantees apply per message group ID only; messages across different group IDs may be delivered out of order relative to each other.

### sqs-fifo-single-group-id-global-ordering-no-parallelism [IN] OBSERVATION
Using a single message group ID for all messages in an SQS FIFO queue enforces strict global ordering but eliminates parallelism.

### sqs-fifo-visibility-timeout-blocks-entire-group [IN] OBSERVATION
In SQS FIFO queues, while a message from a group is in-flight (received but not deleted), no additional messages from that same group are returned until the message is deleted or becomes visible again.

### sqs-fifo-vs-standard-tradeoff [IN] OBSERVATION
SQS FIFO queues provide strict ordering and exactly-once delivery but have lower throughput limits compared to standard queues.

### sqs-messages-larger-than-1mib-s3-or-dynamodb [IN] OBSERVATION
SQS messages larger than 1 MiB can be stored in S3 or DynamoDB, with SQS holding a pointer to the payload.

### sqs-scales-transparently-no-provisioning [IN] OBSERVATION
SQS scales transparently with no provisioning or capacity planning required.

### sqs-set-queue-attributes-api-configures-queue [IN] OBSERVATION
The SQS SetQueueAttributes API action is used to configure queue attributes such as message retention period.

### sqs-sns-async-amazon-mq-sync-and-async [IN] OBSERVATION
SNS and SQS support only asynchronous messaging; Amazon MQ supports both synchronous and asynchronous messaging.

### sqs-sns-fanout-pattern [IN] OBSERVATION
SQS + SNS fanout pattern delivers messages to multiple subscribers by having SNS push to multiple SQS queues.

### sqs-sse-default-sqs-managed-or-kms [IN] OBSERVATION
SQS supports server-side encryption via SQS-managed keys (default) or AWS KMS-managed keys.

### sqs-standard-at-least-once-delivery [IN] OBSERVATION
SQS standard queues provide at-least-once delivery semantics; duplicate delivery is possible.

### sqs-standard-at-least-once-fifo-exactly-once [IN] OBSERVATION
SQS standard queues guarantee at-least-once delivery; FIFO queues guarantee exactly-once processing.

### sqs-standard-best-effort-ordering [IN] OBSERVATION
SQS standard queues provide only best-effort ordering; messages may arrive out of order.

### sqs-standard-multi-az-redundancy [IN] OBSERVATION
SQS standard queue messages are stored redundantly across multiple Availability Zones before send acknowledgment is returned.

### sqs-standard-nearly-unlimited-throughput [IN] OBSERVATION
SQS standard queues support nearly unlimited API calls per second for SendMessage, ReceiveMessage, and DeleteMessage.

### sqs-standard-queue-back-of-queue-after-3-receives [IN] OBSERVATION
For SQS standard queues with maxReceiveCount greater than 3, messages received 3 or more times without deletion are moved to the back of the queue (separate from DLQ behavior).

### sqs-standard-queue-is-default-type [IN] OBSERVATION
SQS standard queues are the default queue type when creating an SQS queue.

### sqs-visibility-timeout-hides-during-processing [IN] OBSERVATION
SQS visibility timeout hides a message from other consumers while it is being processed; if not deleted before timeout expires, the message becomes visible again.

### sts-assume-role-returns-three-components [IN] OBSERVATION
`sts:AssumeRole` returns three components: AccessKeyId, SecretAccessKey, and SessionToken (with an expiration time).

### sts-credentials-expire-no-revocation-needed [IN] OBSERVATION
STS temporary credentials automatically expire and do not need explicit revocation; after expiration they cannot be reused.

### sts-custom-identity-broker-for-non-saml [IN] OBSERVATION
A custom identity broker can be built for organizations whose identity provider does not support SAML 2.0, to enable federation with AWS.

### sts-global-endpoint-url [IN] OBSERVATION
The global STS endpoint is `https://sts.amazonaws.com`; regional endpoints are also available, and credentials from any region work globally.

### sts-regional-endpoints-reduce-latency [IN] OBSERVATION
STS regional endpoints are available in all supported regions to reduce latency; credentials issued by any regional endpoint work globally.

### sts-source-identity-immutable-once-set [IN] OBSERVATION
Source identity (`sts:SourceIdentity`) is immutable once set during an STS call — it cannot be changed during role chaining, and attempts to change it are denied.

### sts-source-identity-tracks-original-caller [IN] OBSERVATION
The `SourceIdentity` attribute can be set during STS calls to trace the original caller through a chain of role assumptions.

### sts-temporary-credentials-three-components [IN] OBSERVATION
STS temporary credentials consist of three components: an access key ID, a secret access key, and a session token — all three are required for API calls.

### subnet-associated-with-exactly-one-route-table [IN] OBSERVATION
Each subnet is associated with exactly one route table; subnets not explicitly associated use the VPC's main route table.

### subnet-auto-assign-ip-overridable-per-instance [IN] OBSERVATION
The subnet auto-assign public IP setting can be overridden on a per-instance basis at launch time.

### subnet-cannot-span-availability-zones [IN] OBSERVATION
A VPC subnet must reside entirely within one Availability Zone — it cannot span multiple AZs.

### subnet-defaults-main-route-table-and-default-nacl [IN] OBSERVATION
Every subnet is automatically associated with the VPC's main route table and default NACL unless explicitly changed to a custom route table or NACL.

### subnet-four-types-public-private-vpn-isolated [IN] OBSERVATION
VPC subnets have four types based on routing: public (route to IGW), private (NAT for internet), VPN-only (route to virtual private gateway), and isolated (no routes outside the VPC).

### subnet-three-addressing-modes [IN] OBSERVATION
A VPC subnet supports three IP addressing modes: IPv4 only, dual stack (both IPv4 and IPv6), or IPv6 only.

### subnet-type-determined-by-route-table [IN] OBSERVATION
Subnet type (public, private, VPN-only, isolated) is determined by its route table configuration, not by an explicit subnet property — a public subnet simply has a route to an internet gateway.

### swf-data-events-resource-type-domain [IN] OBSERVATION
Amazon SWF data events use `AWS::SWF::Domain` as the CloudTrail resource type for advanced event selectors.

### swf-respond-decision-generates-n-plus-1-events [IN] OBSERVATION
SWF `RespondDecisionTaskCompleted` generates N+1 CloudTrail data events (one per decision plus one for the API call itself), all sharing the same request ID.

### target-tracking-auto-manages-cloudwatch-alarms [IN] OBSERVATION
Application Auto Scaling target tracking policies automatically create and manage CloudWatch alarms — no manual alarm configuration is needed.

### target-tracking-metric-inversely-proportional [IN] OBSERVATION
Application Auto Scaling target tracking requires the chosen metric to change inversely proportional to capacity (e.g., doubling capacity should halve the metric value) for correct scaling behavior.

### target-tracking-predefined-and-custom-metrics [IN] OBSERVATION
Application Auto Scaling target tracking supports both predefined metrics (e.g., average CPU utilization) and custom metrics including metric math combinations.

### tgw-hub-and-spoke-architecture [IN] OBSERVATION
AWS Transit Gateway uses a hub-and-spoke architecture to connect multiple VPCs and on-premises networks through a single gateway.

### tgw-mtu-8500-vpc-1500-vpn [IN] OBSERVATION
Transit Gateway supports an MTU of 8500 bytes for VPC attachments but only 1500 bytes for VPN attachments.

### tgw-route-propagation-static-or-bgp [IN] OBSERVATION
Transit Gateway route propagation uses static routes or BGP depending on the attachment type (VPN attachments support BGP).

### transit-gateway-flow-logs-separate-feature [IN] OBSERVATION
Transit Gateway Flow Logs are a separate feature from VPC Flow Logs.

### trusted-advisor-event-source-trustedadvisor [IN] OBSERVATION
The CloudTrail event source for Trusted Advisor console actions is `trustedadvisor.amazonaws.com`, while Trusted Advisor API operations use `support.amazonaws.com`.

### vpc-api-actions-use-ec2-namespace [IN] OBSERVATION
VPC API actions are part of the EC2 API namespace — there is no separate VPC service endpoint; IAM actions use the `ec2:` prefix (e.g., `ec2:CreateVpc`).

### vpc-block-public-access-feature [IN] OBSERVATION
VPC Block Public Access is a VPC-level feature that blocks internet access with exclusion mechanisms for specific resources.

### vpc-cross-account-resource-sharing-requires-ram [IN] OBSERVATION
Cross-account sharing of PrivateLink resource configurations and service networks requires AWS RAM.

### vpc-custom-dns-requires-dhcp-option-set [IN] OBSERVATION
Replacing the default Amazon DNS with a custom DNS server requires creating a new DHCP option set for the VPC.

### vpc-default-can-be-recreated [IN] OBSERVATION
The `CreateDefaultVpc` and `CreateDefaultSubnet` APIs can recreate default VPC resources if they were deleted.

### vpc-defense-requires-three-coordinated-control-planes [IN] OBSERVATION
Complete VPC security requires coordinating three independent control planes — network segmentation (NACLs + security groups), policy isolation (Block Public Access + resource policies), and service connectivity (PrivateLink + VPC endpoints) — a gap in any one plane undermines the others.

### vpc-dns-hostname-tied-to-public-and-private-ip [IN] OBSERVATION
EC2 instance DNS hostnames are tied to both the public and private IP addresses of the instance based on VPC DNS settings.

### vpc-dns-server-at-base-plus-two [IN] OBSERVATION
The Amazon-provided DNS server is available at `169.254.169.253` or at the VPC network range base address plus two.

### vpc-dns-support-enabled-hostnames-disabled-default [IN] OBSERVATION
For non-default VPCs, `EnableDnsSupport` is enabled by default but `EnableDnsHostnames` is disabled by default; DNS hostnames require DNS support to be enabled.

### vpc-endpoint-eni-ipv6-deny-all-igw-traffic [IN] OBSERVATION
VPC endpoint network interface IPv6 addresses have `denyAllIgwTraffic` enabled — they are unreachable from the internet.

### vpc-endpoint-eni-security-groups-supported [IN] OBSERVATION
Security groups can be applied to VPC endpoint network interfaces to control traffic.

### vpc-endpoint-policy-default-allow-all [IN] OBSERVATION
VPC endpoint policies are IAM resource policies that default to allowing all actions by all principals.

### vpc-endpoint-services-not-public-by-default [IN] OBSERVATION
VPC endpoint services are not publicly available by default — providers must explicitly grant permissions to consumers.

### vpc-endpoints-private-access-no-igw-nat [IN] OBSERVATION
VPC Endpoints allow private access to AWS services without requiring an internet gateway or NAT device.

### vpc-five-endpoint-types [IN] OBSERVATION
VPC supports five endpoint types: interface, GatewayLoadBalancer, resource, service network, and gateway (only gateway does not use AWS PrivateLink).

### vpc-flow-logs-capture-metadata-not-contents [IN] OBSERVATION
VPC Flow Logs capture IP traffic metadata (not packet contents) for network interfaces within a VPC.

### vpc-flow-logs-cost-allocation-tags [IN] OBSERVATION
Cost allocation tags can be applied to VPC Flow Log destination resources to track flow log costs.

### vpc-flow-logs-no-network-impact [IN] OBSERVATION
VPC Flow Logs are collected outside the network traffic path and have zero impact on network throughput or latency.

### vpc-flow-logs-three-destinations [IN] OBSERVATION
VPC Flow Logs can be published to three destinations: CloudWatch Logs, Amazon S3, or Amazon Data Firehose.

### vpc-flow-logs-vended-log-pricing [IN] OBSERVATION
VPC Flow Log charges fall under vended logs pricing (data ingestion and archival), not standard CloudWatch pricing.

### vpc-flow-logs-vpc-subnet-or-eni-level [IN] OBSERVATION
VPC Flow Logs can be created at the VPC, subnet, or network interface level.

### vpc-four-public-ipv4-address-types [IN] OBSERVATION
AWS has four public IPv4 address types: Elastic IP (EIP), EC2 auto-assigned, BYOIPv4 (bring your own), and service-managed (auto-provisioned by RDS, ECS, WorkSpaces, etc.).

### vpc-gateway-endpoints-s3-dynamodb-no-privatelink [IN] OBSERVATION
Gateway VPC endpoints (for S3 and DynamoDB only) do not use AWS PrivateLink — all other endpoint types do.

### vpc-interface-endpoints-use-dns-gwlb-use-route-tables [IN] OBSERVATION
Interface VPC endpoints use DNS resolution to direct traffic to endpoint services; Gateway Load Balancer endpoints use route table entries instead.

### vpc-isolation-creates-defense-in-depth-with-policy-controls [IN] OBSERVATION
VPC-only services (DAX, Lambda) combined with PrivateLink and S3 Block Public Access create layered defense where data access requires both network reachability AND policy authorization.

### vpc-itself-is-free [IN] OBSERVATION
The VPC itself is free; charges apply for NAT gateways, traffic mirroring, IPAM, public IPv4 addresses, and Reachability/Network Access Analyzer.

### vpc-local-route-cannot-be-deleted [IN] OBSERVATION
The local route for intra-VPC traffic is automatically included in every route table and cannot be deleted, but its target can be replaced.

### vpc-main-route-table-automatic [IN] OBSERVATION
Every VPC automatically gets a main route table; subnets not explicitly associated with a custom route table use the main route table.

### vpc-main-route-table-cannot-delete-while-main [IN] OBSERVATION
The main route table can be replaced with a custom route table but cannot be deleted while it is designated as the main route table.

### vpc-managed-prefix-lists-support-versioning [IN] OBSERVATION
Managed Prefix Lists are reusable sets of CIDR blocks that can be referenced in security groups and route tables, and support versioning with the ability to restore to previous versions.

### vpc-peering-cross-account-cross-region [IN] OBSERVATION
VPC peering connections can be established within the same account, across accounts, or across regions.

### vpc-peering-instances-communicate-as-same-network [IN] OBSERVATION
Instances in peered VPCs communicate as if they are on the same network, using private IPv4 or IPv6 addresses.

### vpc-peering-inter-region-encrypted-aws-backbone [IN] OBSERVATION
Inter-region VPC peering traffic is encrypted and stays on the AWS global backbone — it never traverses the public internet.

### vpc-peering-inter-region-mtu-8500 [IN] OBSERVATION
Inter-region VPC peering connections support up to 8500 MTU (not the full 9001 jumbo frame size).

### vpc-peering-no-creation-charge [IN] OBSERVATION
There is no charge to create a VPC peering connection; data transfer within the same AZ over peering is free (even cross-account), but cross-AZ and cross-region transfers incur charges.

### vpc-peering-non-transitive [IN] OBSERVATION
VPC peering connections are non-transitive — if VPC A peers with VPC B and VPC B peers with VPC C, VPC A cannot reach VPC C through VPC B.

### vpc-peering-not-gateway-vpn-or-hardware [IN] OBSERVATION
VPC peering is a distinct connection type — it is not a gateway, VPN, or physical hardware, and has no single point of failure or bandwidth bottleneck.

### vpc-privatelink-traffic-stays-on-aws-network [IN] OBSERVATION
Traffic over AWS PrivateLink stays on the AWS network and never traverses the public internet.

### vpc-resource-endpoints-no-load-balancer [IN] OBSERVATION
VPC resource endpoints provide direct access to shared resources in another VPC without requiring a load balancer; interface endpoint services require one (NLB or GWLB).

### vpc-route-table-destination-and-target [IN] OBSERVATION
Each route in a route table has a destination (CIDR block or prefix list matching traffic) and a target (where to send it, e.g., IGW, NAT gateway, peering connection).

### vpc-route53-resolver-default-dns [IN] OBSERVATION
Every VPC gets an Amazon-provided DNS server (Route 53 Resolver) by default.

### vpc-security-enforced-at-two-independent-layers [IN] OBSERVATION
VPC network security operates at both subnet level (NACLs, one-to-many mapping) and instance level (security groups), and FIS chaos testing validates both layers by swapping NACLs/route tables.

### vpc-split-horizon-dns-route53-privatelink [IN] OBSERVATION
Split-horizon DNS with Route 53 allows the same domain to resolve to private IPs inside the VPC (via PrivateLink) and public IPs outside.

### vpc-stale-security-groups-detect-deleted-peering [IN] OBSERVATION
The `DescribeStaleSecurityGroups` API detects security group rules that reference security groups in a deleted or detached VPC peering connection.

### vpc-subnet-single-az [IN] OBSERVATION
A VPC subnet resides in exactly one Availability Zone and cannot span multiple AZs.

### vpc-supports-ipv4-ipv6-and-byoip [IN] OBSERVATION
VPC supports both IPv4 and IPv6 addressing, and you can bring your own public IP addresses (BYOIP).

### vpc-tenancy-dedicated-to-default-no-replacement [IN] OBSERVATION
Changing VPC `InstanceTenancy` from `dedicated` to `default` requires no replacement, but changing from `default` to `dedicated` requires replacement (new VPC).

### vpc-traffic-mirroring-deep-packet-inspection [IN] OBSERVATION
VPC Traffic Mirroring copies network interface traffic to security and monitoring appliances for deep packet inspection.

### well-architected-framework-from-customer-reviews [IN] OBSERVATION
The AWS Well-Architected Framework distills lessons from thousands of real customer architecture reviews.

### well-architected-framework-six-pillars [IN] OBSERVATION
The AWS Well-Architected Framework has six pillars: Operational Excellence, Security, Reliability, Performance Efficiency, Cost Optimization, and Sustainability.

### well-architected-labs-hands-on-resource [IN] OBSERVATION
AWS Well-Architected Labs is a companion hands-on resource with code and documentation for implementing framework best practices.

### well-architected-not-audit-mechanism [IN] OBSERVATION
The AWS Well-Architected Framework is a best-practice guide and constructive conversation about design choices, not an audit mechanism.

### well-architected-reviews-produce-remediation-recommendations [IN] OBSERVATION
Well-Architected reviews produce remediation recommendations to achieve desired architectural qualities.

### well-architected-tool-is-free [IN] OBSERVATION
The AWS Well-Architected Tool (AWS WA Tool) is a free AWS service for reviewing and measuring architectures against the framework.

### well-architected-unit-is-workload [IN] OBSERVATION
The unit of evaluation in the AWS Well-Architected Framework is a workload, not an individual service.
