Subchapter 27.25
references/phases/design/design-infra.mdMarkdown19 KBView on GitHub
Loaded by
design.mdwhengcp-resource-inventory.jsonandgcp-resource-clusters.jsonexist.
Execute ALL steps in order. Do not skip or optimize.
Read preferences.json. If missing: STOP. Output: “Phase 2 (Clarify) not completed. Run Phase 2 first.”
Read gcp-resource-clusters.json.
Sort clusters by creation_order_depth (lowest first, representing foundational infrastructure).
For each cluster, process primary_resources first, then secondary_resources (as classified during discover phase — see gcp-resource-clusters.json).
For each PRIMARY resource in the cluster:
google_sql_database_instance)design-refs/fast-path.md → Direct Mappings table (not the Preferred Target table — that applies later in Pass 2).Always → conditions met.google_app_engine_application requires (compute_model absent or "managed_platform") and compute ≠ "eks"): read preferences.json → design_constraints.compute_model.value and design_constraints.compute.value. If the condition is NOT met (e.g., user chose "container_orchestration" or "serverless", or compute: "eks" from Q5 = multi-cloud), treat as not found — proceed to Pass 2. Under compute: "eks", the rubric routes App Engine to EKS (portability override, same as GKE); the EB fan-out below does not run.deterministic. Set human_expertise_required: false (no Direct Mapping row requires it).
App Engine fan-out (google_app_engine_application only; EB path only — skipped when compute: "eks" routed App Engine to EKS or when compute_model is "container_orchestration"/"serverless"): the parent resource carries no workload config — runtime, instance_class, env_variables, and scaling live on the google_app_engine_standard_app_version / google_app_engine_flexible_app_version resources. Execute these sub-steps in order:
project), so they are not reliably in the parent’s cluster or serves[]. Scan the entire gcp-resource-inventory.json across all clusters for app_version resources — do not rely on cluster membership.google_app_engine_application in the inventory, all app_version resources belong to it. If there are multiple parents, match each app_version to the parent with the same project; if project is absent on the resources (provider-level in Terraform) with multiple parents, you cannot attribute reliably — map each parent to a single EB environment, add a warnings entry naming the ambiguity, and skip sub-steps 4–6 for the ambiguous parents.warnings, and skip the remaining sub-steps.service. An app_version with no service argument belongs to service "default" (App Engine semantics). Multiple versions of the same service (e.g. v1 and v2, both service = "myapp") are one service → one EB environment. Pick the config-source version per service: prefer the version with serving_status = "SERVING"; if several (or none) are SERVING, pick the highest version_id by case-insensitive lexical order, and add a warnings entry noting the tie-break so the choice is reproducible.service, all under a single EB application named for the parent. Give each mapping a unique gcp_address of the form <parent gcp_address>#<service> — where <parent gcp_address> is the parent’s Terraform address (e.g. google_app_engine_application.example#default, google_app_engine_application.example#worker) — so per-service mappings don’t collide; keep gcp_type: "google_app_engine_application". These per-service mappings replace the parent’s single mapping — do not also emit a bare-parent-address mapping (no #service suffix); the parent is represented only by its per-service environments, so the output has exactly one resource per App Engine service, not N+1. Derive each field from that service’s own version config (see design-refs/elastic-beanstalk.md Sizing Defaults): runtime → EB platform; scaling block (automatic_scaling / basic_scaling / manual_scaling) → EB environment_type (multi-instance/autoscaled → LoadBalanced, single/manual-1 → SingleInstance) and both min_instances and max_instances so Generate can emit ASG MinSize/MaxSize. Read the min/max from the correct provider field for the scaling block present: Standard automatic_scaling.standard_scheduler_settings.{min_instances,max_instances}; Standard basic_scaling.max_instances (min 1); Standard/Flexible manual_scaling.instances (min = max = that count); Flexible automatic_scaling.{min_total_instances,max_total_instances}. Default max to min when the block declares no maximum. instance_class (Standard) or resources (Flexible) → instance_type (Graviton t4g.* default); env_variables → carry into aws_config.env_variables so Generate can emit the aws:elasticbeanstalk:application:environment settings. Do not use Q6 availability for EB sizing — that governs databases only.confidence: "deterministic", human_expertise_required: false, a non-empty rationale (e.g. "Direct Mapping: App Engine service <service> → Elastic Beanstalk environment"), and records the source service in aws_config. The *_app_version resources themselves are Skip Mappings — not emitted as separate output resources (config sources, no standalone cost). This step owns their warnings[] entry: add one per consumed version naming the version and the EB environment it fed (see fast-path.md → Skip Mappings + Secondary Behavior Lookups). Step 3 handles only versions this step did not consume, so there is no double-warning.gcp_type is google_sql_database_instance with PostgreSQL or MySQL engine: always proceed to Pass 2 (Cloud SQL is not in Direct Mappings — see fast-path.md). Confidence = inferred after rubric.inferred after rubric, or billing_inferred on the billing-only path).Definitions: See the top of design-refs/fast-path.md for deterministic vs inferred vs billing_inferred and the note that index.md “Typical AWS target” ≠ deterministic.
For resources not covered by fast-path:
0. BigQuery specialist gate (mandatory — before rubric): If gcp_type starts with google_bigquery_ (e.g. google_bigquery_dataset, google_bigquery_table, google_bigquery_routine, google_bigquery_data_transfer_config, google_bigquery_job, google_bigquery_ml_*):
Do not recommend a specific AWS analytics or warehouse service (Athena, Redshift, Glue, EMR, Lake Formation, or a prescribed “data lake on S3” architecture).
Set aws_service to Deferred — specialist engagement, human_expertise_required to true, confidence to inferred, and aws_config to include specialist_engagement (text: engage AWS account team and/or data analytics migration partner before choosing any AWS target) and no_automated_aws_target: true. Set rubric_applied to ["BigQuery specialist gate — no automated AWS service target"].
Skip rubric steps 1–6 and the Preferred AWS target check for this resource.
Determine service category (via design-refs/index.md):
google_compute_instance → computegoogle_cloudfunctions_function → computegoogle_sql_database_instance → databasegoogle_storage_bucket → storagegoogle_compute_network → networkingCatch-all for unknown types: If resource type not found in index.md:
Load rubric from corresponding design-refs/*.md file (e.g., compute.md, database.md)
Evaluate 6 criteria (1-sentence each):
preferences.json design_constraints (includes compute_model, kubernetes, cost_sensitivity)Select best-fit AWS service. Confidence = inferred
7b. Cloud SQL Q6 gate (mandatory — after rubric): For google_sql_database_instance (PostgreSQL or MySQL), read preferences.json → design_constraints.availability and enforce:
availability | Required aws_service |
|---|---|
single-az | RDS PostgreSQL or RDS MySQL (engine match) |
multi-az | RDS PostgreSQL or RDS MySQL + multi_az: true |
multi-az-ha | Aurora PostgreSQL or Aurora MySQL |
multi-region | Aurora PostgreSQL or Aurora MySQL Global Database |
| absent / null / missing | Do not proceed — Cloud SQL PostgreSQL/MySQL is present but Q6 was not answered. Return to Clarify to ask Q6 (or apply the documented Q6 default) before assigning RDS/Aurora topology. Do not infer Aurora from the rubric alone. |
IaC extraction note: Only single-az and multi-az can be auto-extracted from Terraform (ZONAL / REGIONAL). multi-az-ha and multi-region are never inferred from IaC — they require explicit user intent via Q6 (Mission-Critical / Catastrophic). Cloud SQL REGIONAL maps to multi-az (RDS Multi-AZ), not multi-az-ha (Aurora).
If rubric or fast-path would select Aurora when availability is single-az or multi-az, replace with RDS. If rubric would select RDS when availability is multi-az-ha or multi-region, replace with Aurora. Add "User Preference: availability=<value>" to rubric_applied. Q12/Q13 must not override this gate.
Set human_expertise_required: If the BigQuery specialist gate applied, already true. Otherwise set false unless another rubric explicitly requires it. This field is REQUIRED on every resource in the output.
Preferred AWS target check: Skip if aws_service is Deferred — specialist engagement. Skip Aurora substitution for Cloud SQL when Q6 availability is single-az or multi-az (RDS is correct). Skip EB substitution for App Engine when compute_model is "container_orchestration" or "serverless" (the eliminator’s Fargate/Lambda target is correct — the PaaS row’s condition is false, see fast-path.md enforcement exemption), or when compute is "eks" (Q5 = multi-cloud — the rubric’s EKS target is correct; the PaaS row’s compute ≠ "eks" condition is false, see fast-path.md multi-cloud enforcement exemption). Otherwise verify the selected aws_service aligns with the Preferred AWS Target Services table in design-refs/fast-path.md. If a non-preferred service is selected (e.g., App Runner for containerized workloads), substitute the preferred alternative (e.g., Fargate). Add a note to the rationale: “Preferred target: [alternative] selected for stronger ecosystem integration.”
For each SECONDARY resource:
google_app_engine_standard_app_version / google_app_engine_flexible_app_version): these are Skip Mappings — config sources for the App Engine → EB mapping with no standalone AWS target (see fast-path.md). If the App Engine fan-out (Pass 1 step 4) already consumed this version, it has already logged the warnings[] entry — do nothing here. Otherwise (the fan-out did not run — container_orchestration/serverless path, compute: "eks" multi-cloud path, ambiguous attribution, or no parent), skip it now: do not emit it to aws-design.json, do not send it through index.md/rubric, and add one warnings[] entry for it. Either way it never reaches the Pass 2 unknown-type catch-all — so no path STOPs on it, and each version is warned exactly once.design-refs/index.md for categorygcp_type starts with google_bigquery_; otherwise apply the same 6-criteria approach as Pass 2If aws_service is Deferred — specialist engagement, do not validate against concrete AWS analytics SKUs; add a warnings[] entry that specialist engagement is required.
Validation checks (if AWS MCP Server available):
For each mapped AWS service, verify:
Regional Availability: Is the service available in the target region (e.g., us-east-1)?
aws___get_regional_availability to check regional supportFeature Parity: Do required features exist in AWS service?
preferences.json design_constraintsaws___search_documentationService Compatibility: Are there known issues or constraints?
aws___search_documentationIf AWS MCP Server unavailable:
validation_status: "skipped" in outputIf validation succeeds:
validation_status: "completed" in outputFile 1: aws-design.json
{
"clusters": [
{
"cluster_id": "compute_instance_us-central1_001",
"gcp_region": "us-central1",
"aws_region": "us-east-1",
"resources": [
{
"gcp_address": "google_compute_instance.web",
"gcp_type": "google_compute_instance",
"gcp_config": {
"machine_type": "n2-standard-2",
"zone": "us-central1-a",
"boot_disk_size_gb": 100
},
"aws_service": "Fargate",
"aws_config": {
"cpu": "0.5",
"memory": "1024",
"region": "us-east-1"
},
"confidence": "inferred",
"human_expertise_required": false,
"rationale": "Rubric: Compute Engine → Fargate (example — not a Direct Mapping row; Cloud Run/Compute Engine use Pass 2)",
"rubric_applied": [
"Eliminators: PASS",
"Operational Model: Managed Fargate",
"User Preference: Speed (q2)",
"Feature Parity: Full (always-on compute)",
"Cluster Context: Standalone compute tier",
"Simplicity: Fargate (managed, no EC2)"
]
}
]
}
],
"warnings": [
"service X not fully supported in us-east-1; fallback to us-west-2"
]
}clusters array is non-emptycluster_id matching a cluster from gcp-resource-clusters.jsongcp_region and aws_regiongcp_address, gcp_type, gcp_config, aws_service, aws_confighuman_expertise_required (boolean) — true for all google_bigquery_* resources (specialist gate); false for others unless a rubric explicitly requires itgoogle_bigquery_* resource has aws_service exactly Deferred — specialist engagement (not Athena, Redshift, Glue, etc.)google_sql_database_instance resource has aws_service ∈ {RDS PostgreSQL, RDS MySQL, Aurora PostgreSQL, Aurora MySQL} with non-empty rationale citing Q6 availability value. If availability is single-az or multi-az, aws_service MUST be RDS (not Aurora). If multi-az-ha or multi-region, MUST be Aurora.confidence values are either "deterministic" or "inferred"rationale fields are non-emptygcp_address values across clustersBefore returning control to design.md, require:
aws-design.json exists and passes the Output Validation Checklist above.If this gate fails: STOP and output: “design-infra did not produce a valid aws-design.json; do not complete Phase 3.”
After writing aws-design.json, present a concise summary to the user:
design-refs/fast-path.md → User-facing vocabulary — Standard pairing (deterministic), Tailored to your setup (inferred), or Estimated from billing only (billing_inferred). Lead with the bold phrase; include the JSON value in parentheses only if the user is technical.Deferred — specialist engagement: state prominently that no AWS analytics target was chosen. Direct the user to their AWS account team and/or a data analytics migration partner. Do not recommend Athena, Redshift, Glue, or EMR in the chat summary.Keep it under 20 lines. The user can ask for details or re-read aws-design.json at any time.