Subchapter 25.8
references/design-refs/database.mdMarkdown12 KBView on GitHub
Pass-2 rubric for every database type index.md routes here. Loaded only when the
inventory contains one.
Outcome is confidence: inferred, or measured when observed utilization backed the
sizing.
For Postgres and MySQL Flexible Server, the availability answer selects the family, and
it overrides whatever the rubric would have chosen. Read it from
preferences.json → data.availability — not design_constraints.availability,
which is where gcp-to-aws keeps it and where this file wrongly looked until 2026-09-07.
clarify-database.md writes it under data, and schema-preferences.md § data documents
it there.
Why that typo was dangerous rather than annoying. Looking in the wrong place finds nothing, and § the absent case below then says to default to RDS single-AZ — which is the same answer the corpus produces, so every test stayed green. On an estate where the customer answers
multi-az-hait silently produces RDS where Aurora was chosen, and the artifact records the customer’s answer faithfully next to a target that ignores it. Capability run 4 found it by reading both files. This is a post-rubric override gate, not a criterion, and it is the cleanest lift in the whole port — gcp’s Q6 maps across unchanged.
data.availability | Target (match the engine from the source) |
|---|---|
single-az | RDS PostgreSQL / RDS MySQL |
multi-az | RDS … Multi-AZ |
multi-az-ha | Aurora PostgreSQL / MySQL, Multi-AZ |
multi-region | Aurora Global Database |
Clarify writes multi-region only when the availability answer is Catastrophic and
global.user_geography is global (canonical clarify-availability.md). If
availability is multi-az-ha and geography is global, do not upgrade the family
here — that would invent Aurora Global without the recorded availability value. If
geography is single-region / multi-region and availability is somehow multi-region,
still honor the recorded availability row (the user picked [D] on Q-D1) and say in the
rationale that global infrastructure was requested without global users.
Why an override rather than a criterion: availability is never inferable from
configuration. A source high_availability { mode = "ZoneRedundant" } tells you what
they bought, not what they need — plenty of estates carry zone-redundancy nobody asked for
because it was a default, and plenty of single-zone databases are load-bearing. Only the
customer can answer it, so a rubric that inferred it from the source would be
manufacturing a requirement.
If the answer is absent — Clarify has not run, or the question was skipped — do not default to Aurora. Default to RDS single-AZ, the dev-tier posture in SKILL.md § Philosophy, and record in the rationale that availability was not stated. Aurora costs materially more; inferring it from silence inflates the estimate and the customer has no way to see why.
Do not read the source’s
zone_redundant/high_availabilityas the answer. Surface it as a finding — “your source is zone-redundant; you selected single-AZ, which is a deliberate downgrade” — which is a genuinely useful thing to tell someone.
| Candidate | Eliminated when |
|---|---|
| Aurora Serverless v2 | the workload needs a fixed reserved capacity floor below its minimum ACU billing granularity — a permanently-busy database is cheaper provisioned |
| DynamoDB | the source uses joins, transactions across arbitrary keys, or ad-hoc query patterns. Cosmos Core → DynamoDB is a data-model migration; if the access pattern is relational, it is the wrong target regardless of the source being NoSQL |
| ElastiCache Redis | the source uses Redis modules (RediSearch, RedisJSON, RedisTimeSeries) — no ElastiCache equivalent. MemoryDB does not add them either; this is a feature-parity finding, and the honest output names the gap |
| Amazon Keyspaces | the source relies on Cassandra materialized views or UDFs |
| RDS SQL Server | the source is a Managed Instance — specialist gate, never a rubric outcome |
Applied after the eliminators; the availability gate in §1 then overrides the family for the two Flexible Server engines.
| Source | Target |
|---|---|
Microsoft.DBforPostgreSQL/flexibleServers | RDS or Aurora PostgreSQL — §1 selects |
Microsoft.DBforMySQL/flexibleServers | RDS or Aurora MySQL — §1 selects |
Microsoft.DBforPostgreSQL/servers, .../MySQL/servers (Single Server) | same as Flexible, plus a finding: Single Server is retired on Azure, so the migration is also an upgrade and the source version may be below RDS’s floor |
Microsoft.Sql/servers/databases | RDS SQL Server (owner decision 11.3). Carry the source tier — DTU or vCore — into aws_config as the sizing input |
Microsoft.Sql/servers | the RDS instance hosting its databases; usually a config source rather than its own entry |
Microsoft.DocumentDB/databaseAccounts (Core / SQL API) | DynamoDB — see §4 |
Microsoft.Cache/redisEnterprise | ElastiCache Redis, or MemoryDB when durability is required |
Microsoft.Search/searchServices | routed to analytics.md (OpenSearch), not here |
The four non-Core Cosmos APIs are fast-path rows, not rubric decisions — Mongo → DocumentDB, Cassandra → Keyspaces, Gremlin → Neptune, Table → DynamoDB. The wire protocol determines the only drop-in target, so they never reach this file.
The one Cosmos surface with real depth, and the one where the conversion is assumption-sensitive enough that the caveat matters more than the number.
RU/s → capacity. Convert with the divisors in
knowledge/design/cosmos-dynamodb-conversion.json, then apply the write-percentage and
consistency multipliers. State the assumed read/write split in the rationale, because
the result moves by multiples with it: a 50/50 split and a 95/5 split on the same RU/s
produce very different WCU/RCU, and the customer is the only one who knows which they are.
Serverless and autoscale sources. A serverless Cosmos account has no provisioned RU/s
to convert — use consumption data if present, otherwise say so and recommend DynamoDB
on-demand rather than inventing a throughput figure. An autoscale account’s max_throughput
is a ceiling, not a demand.
What does not convert. Cosmos’s five consistency levels do not map onto DynamoDB’s two. Session consistency in particular has no equivalent and is the most common source setting — record it as a finding rather than silently choosing eventually-consistent reads, because the application may depend on read-your-writes.
The remaining criteria, in order, and both are usually quiet for databases:
pattern_status is catalog_absent or unclassified.knowledge/design/flexible-server-rds-sizing.json, confidence: inferred. SKILL.md’s
db.t4g.micro-class posture applies — but note db.t4g is Graviton, and for RDS
SQL Server it is not available: use db.t3 there (graviton.md‘s escape path).knowledge/estimate/rightsizing-thresholds.json, confidence: measured, citing the
evidence.storage_mb across as allocated GiB and keep the source’s growth
headroom. Do not right-size storage down from utilization: shrinking allocated storage
is not an online operation on RDS, so a too-small guess is expensive to undo.backup_retention_days across verbatim. It is a stated
requirement, not a sizing knob.Per schema-design-aws.md § services[], with rubric_applied: "database.md" and a
rationale naming which criterion or gate fired. When the availability gate decided the
family, say so explicitly — “Aurora PostgreSQL, because you selected multi-az-ha”
tells the customer which of their own answers to revisit if the cost surprises them.
Implemented for Postgres/MySQL Flexible Server, Single Server, Azure SQL Database, Cosmos
Core, and Redis Enterprise. database-specialist-gate.md content lives in
specialist-gates.md. The sizing tables now exist:
knowledge/design/flexible-server-rds-sizing.json for Postgres and MySQL Flexible Server,
and knowledge/design/cosmos-dynamodb-conversion.json for the Cosmos Core API. Look the
SKU up and stamp sizing_provenance: "table"; for a SKU the table does not carry, stamp
model_prior, warn, and say the number is not sourced. The Cosmos conversion additionally
REFUSES to run without the read/write split, which is an ESSENTIAL Clarify answer with no
default — an absent split means the conversion is unavailable, not that it should be
guessed.