Subchapter 27.68
references/shared/schema-estimate-infra.mdMarkdown24 KBView on GitHub
projected_costs / cost_comparison)The fields aws_monthly_premium, aws_monthly_balanced, aws_monthly_optimized (under projected_costs) and option_a_premium, option_b_balanced, option_c_optimized (under cost_comparison) are three pricing scenarios for the same GCP->AWS mapping in aws-design.json. They are not three alternative Terraform roots.
scenario_deltas (required with three tiers): projected_costs.scenario_deltas itemizes, per non-Balanced scenario, what concretely differs from Balanced for this stack — the estimate engine already knows (it priced the differences); this field makes the reader see them instead of inferring from generic labels. Each entry names the change AND its consequence when the change is architectural, not just financial (e.g. dropping a NAT Gateway is a network-posture change, not merely savings):
"scenario_deltas": {
"premium": [
"RDS Multi-AZ instead of single-AZ (+$14/mo) — removes the single-AZ assumption",
"Provisioned compute headroom (+$X/mo)"
],
"optimized": [
"Drops NAT Gateway (-$33/mo) — tasks move to public subnets or VPC endpoints; security-posture change, not just savings",
"Assumes 1-year commitment pricing on compute (-$Y/mo) — requires an upfront commitment decision"
]
}Validation: when all three tiers are present, scenario_deltas.premium and scenario_deltas.optimized are non-empty string arrays; every architectural delta (resource added/removed vs the Balanced design) states its consequence, and commitment-based savings name the commitment. Readers of pre-extension artifacts must tolerate absence.
| Tier key | User-facing label | Subtitle (use in reports / MIGRATION_GUIDE) |
|---|---|---|
premium | Premium | Highest resilience / highest monthly estimate in this model |
balanced | Balanced | Default scenario; compare GCP to this first |
optimized | Optimized | Lower monthly estimate; reservations / Spot / storage trade-offs assumed |
How to read: Scenario order is highest -> middle -> lowest monthly AWS estimate for the modeled architecture. Balanced is the primary comparison row vs the GCP baseline. Premium and Optimized are bounds (HA vs cost-optimization skew).
Terraform: When the Generate phase produces terraform/, it implements one infrastructure baseline aligned with the Balanced scenario (aligned_with_estimate_tier in the migration_summary output). Premium and Optimized remain estimate-only unless the customer edits IaC. See references/phases/generate/generate-artifacts-infra.md (terraform/README.md, main.tf header comment).
{
"phase": "estimate",
"design_source": "infrastructure",
"timestamp": "2026-02-24T14:00:00Z",
"pricing_source": {
"status": "cached|cached_fallback|unavailable",
"message": "Using cached prices from 2026-03-04 (±5-10% accuracy)|Using cached prices from 2026-03-04, cache older than 30 days (±5-25% accuracy)|Pricing unavailable for [service]",
"fallback_staleness": {
"last_updated": "2026-02-24",
"days_old": 3,
"is_stale"
The recommendation block is the single source of truth for migrate/stay guidance. Consumed by Estimate chat output AND HTML migration report (Section 0). Do not duplicate this logic in the report template.
path value | path_label (display) |
|---|---|
"migrate_optimized" | "Migrate with Optimizations" |
"migrate_phased" | "Phased Migration" |
"stay" | "Stay on GCP" |
Decision outcome (additive — v2 fields): outcome expresses the decision, independent of the execution-path vocabulary above. path answers “how would we migrate”; outcome answers “should we, now”. Both are written; consumers that only read path keep working.
outcome value | outcome_label (display) | Meaning |
|---|---|---|
"go" | "Go" | Evidence supports migrating now; no unresolved material assumption |
"conditional_go" | "Go, with conditions" | Migrate, but named conditions (see conditions[]) must be confirmed or bounded first |
"defer_for_evidence" | "Defer — get evidence" | A hard trigger fired (see estimate-infra.md trigger table); decision needs one named piece of evidence. Expected rare — when in doubt, conditional_go |
"stay" | "Stay on GCP" | Evidence favors staying — reachable on any decisive factor, not only “cost is sole metric” |
Validation:
path is one of: "migrate_optimized", "migrate_phased", "stay"path_label matches the corresponding display string for pathoutcome, when present, is one of: "go", "conditional_go", "defer_for_evidence", "stay" (readers MUST tolerate absence — pre-extension artifacts)conditions is a non-empty array of strings when outcome == "conditional_go"decision_basis, when present, has measured, assumed, and unknown string arrays (any may be empty)would_flip_if, when present, is an array of stringsoutcome == "stay" requires path == "stay"; outcome == "defer_for_evidence" may pair with any path (path shows what migration would look like)migrate_if and stay_if are non-empty arrays of stringsstay_if / conditions): the whole-stack stay_if list is reserved for factors that argue for staying entirely (e.g. compute economics dominating a sparse-traffic app). A factor affecting a single track (one AI workload’s quality eval, one deferred service’s specialist plan) is track-scoped: it goes in conditions[] prefixed with its track (“AI image: …”) and/or shapes that track’s entry in track_outcomes — it MUST NOT appear as a whole-stack stay reason. This generalizes the existing BigQuery rule (deferral is not a reason to stay unless analytics must cut over in the same window) to every track.track_outcomes, when present, is an array of {track, outcome, note}; track is one of compute_database, ai_text, ai_image, ai_agentic, analytics (use only tracks that exist in the design); outcome uses the same enum as recommendation.outcome. Required when the stack has more than one track (AI artifacts and/or deferred services alongside infrastructure). The stack-level outcome is then a summary: it must not be worse than the compute/database track’s outcome merely because a secondary track has a condition — a failing track demotes that track, never the stack. Readers of pre-extension artifacts must tolerate absence.next_steps is a non-empty array of stringsestimation-infra.json output (Part 7 must write it; Part 7 always writes the v2 fields)When Part 2B of estimate-infra.md produces an observability cost, it is included as an entry in projected_costs.breakdown[] with this shape:
{
"service": "CloudWatch + X-Ray (Observability)",
"low": 4.00,
"mid": 5.21,
"high": 8.00,
"accuracy": "±30%",
"pricing_source": "cached",
"components": {
"log_ingestion": 3.50,
"log_storage": 0.21,
"custom_metrics": 1.50,
"alarms": 0.00,
"tracing": 0.00
},
"volume_source": "heuristic",
"note": "GCP Cloud Operations includes 50 GB/month free logging, free alerting, and free profiling. CloudWatch always-free tier includes 5 GB logs, 10 custom metrics, and 10 alarms per month. Estimate assumes usage above free-tier limits."
}Validation for observability entry:
components keys are exactly: log_ingestion, log_storage, custom_metrics, alarms, tracingvolume_source is one of: "heuristic", "billing" (reflects log volume source — the largest cost component; metrics are always heuristic regardless of this field)tracing is 0 when no tracing signals detected in source — do not add X-Ray costs unpromptedmid equals the sum of all components valuesPresent in estimation-infra.json only when preferences.json → design_constraints.cpu_architecture.value is graviton or mixed (see estimate-infra.md Part 2C and shared/schema-graviton.md). Omit entirely for x86.
"architecture_comparison": {
"graviton_monthly": 245.00,
"x86_equivalent_monthly": 298.00,
"savings_amount": 53.00,
"savings_percent": 17.8,
"note": "Hourly price savings only; performance uplift may allow further downsizing after load testing"
}Validation for architecture_comparison entry:
savings_amount equals x86_equivalent_monthly − graviton_monthlysavings_percent equals savings_amount / x86_equivalent_monthly × 100 (one decimal)shared/schema-graviton.mddesign_source is "infrastructure"pricing_source.status is "cached", "cached_fallback", or "unavailable" (pricing is cache-only — there is no "live" status because no live pricing tool is configured, and there is no "cached_stale" status either: a stale cache is status: "cached" with fallback_staleness.is_stale: true)pricing_source.fallback_staleness.is_stale is true when the cache is older than its staleness threshold, with a non-null staleness_warning; false otherwiseaccuracy_confidence matches the pricing mode (±5-10% for cached, ±15-25% for fallback)current_costs.source is "billing_data" if billing-profile.json was used, "inventory_estimate", "preferences", "user_provided" (asked during estimate), or "unavailable" (user declined) otherwisecurrent_costs.gcp_monthly matches billing-profile.json total (if used) or is a reasonable estimateprojected_costs has all three tiers (premium, balanced, optimized)estimate-infra.md Present Summary / generate-artifacts-report.md)projected_costs.breakdown covers compute, database, storage, networking, supporting services, and observabilityaws-design.json is represented in the cost breakdownprojected_costs.breakdown observability entry (when present) REPLACES any CloudWatch/log/metric costs in the “Supporting” row — never double-countcost_comparison shows all three options with monthly and annual differencescost_comparison.commitment_context is present if billing-profile.json has commitments.has_active_cuds == true; omitted otherwisemigration_cost_considerations.billing_data_available is true if billing-profile.json exists, false otherwisebilling_data_available is true: migration_cost_considerations.categories lists GCP vendor egress / data transfer only (never human or professional-services costs)billing_data_available is false: migration_cost_considerations.categories is empty; note explains that billing data is required for GCP egress fee estimatesroi_analysis presents recurring monthly/annual savings (or increase) per tierroi_analysis is honest — if migration increases cost, say so and justify with non-cost benefitsoptimization_opportunities only includes strategies relevant to the designed architecture, per the eligibility matrix in references/shared/ri-sp-eligibility.md — never claim Database Savings Plan coverage for an ElastiCache target that isn’t Valkey, and never claim DynamoDB Reserved Capacity eligibility for on-demand or Standard-IA tablesoptimization_opportunities[] entry includes required fields: opportunity, target_services, savings_percent, implementation_effort, description. Optional fields: type, savings_monthly (null when post-migration sizing unavailable), commitment, timing, prerequisite, references, alternativesavings_monthly sized from GCP billing — use savings_monthly: null and timing: post-migrationsavings_monthly only when projected DB on-demand exceeds $50/monthoptimization_opportunities savings are incremental to Balanced on-demand totals — not additive on Optimized tier (which already embeds reservation/Spot assumptions)ri-sp-eligibility.md‘s three-state model, state explicitly which state the design landed in rather than omitting the sectionfinancial_summary provides a clear executive-level viewrecommendation block exists with path, path_label, migrate_if, stay_if, and next_steps all populatedrecommendation.path is one of: "migrate_optimized", "migrate_phased", "stay"recommendation.next_steps includes actionable itemsestimate-ai.md)estimate-billing.md)