Bedrock Provisioned Throughput on Older Model Generation
What does ZopNight detect here?
Provisioned Throughput purchased against a deprecated Bedrock foundation model generation pays yesterday's per-Model-Unit rate. ZopNight looks up real no-commitment PT rates for both the old model and its successor, pricing savings as cost times (1 minus newRate/oldRate); 1-month and 6-month committed-term PTs abstain because per-term rates are unresolvable.
Signal and threshold
| Field | Value |
|---|---|
| Rule IDs | RC-1610 |
| Category | rightsizing |
| Severity | low |
| Metric | none — pure configuration read |
| Source | bedrock_old_model_generation.go |
Matching a PT to a deprecated base model
- resource.Type: bedrock-pt
- metadata: modelArn and foundationModelArn, both extracted via extractBedrockModelIDs / modelIDFromArn (handles foundation-model / and inference-profile trailing :); matching both means a custom-model PT on a deprecated base FM is still flagged.
- SKU rates: the per-MU-hr provisioned throughput rate for the deprecated model id AND its successor id (via TargetSKUCandidates → SetSKURates).
Pricing the rate delta to the successor model
Concrete or abstain (Category rightsizing, since migrating a PT to a cheaper in-family generation is a rate-delta cost lever). This is live: the producer landed 2026-07-13, in this PR. savings = cost × (1 − newRate/oldRate), both rates looked up directly via model.LookupSKURate (not via the fraction-fallback helpers, which would fabricate). The rule abstains when either rate is missing or the successor is not cheaper. How the producer closed the gap: the AWS Bulk Pricing PT SKU exposes the model only as a CamelCase marketing display token (usagetype …-TitanImageGeneratorV2-ProvisionedThroughput-1month-ModelUnits) / human display string (titanModelUnit/modelUnit “Titan Image Generator V2”), never the canonical foundation-model id the lookup keys on (anthropic.claude-v2, meta.llama2-70b-chat-v1, …), and there is no lossless display→id transform. So the aggregator captures the no-commitment PT rate as a structured bedrock-pt-raw|<displayToken> sentinel (extractBedrockKey, internal/pricing/aws/pricing.go) and resolves the display token → foundation-model id in FetchRates against the discoverer’s live bedrock:ListFoundationModels harvest (exact case/space-normalized match or abstain, never fuzzy), keying the one real per-MU-hour rate under every id that shares the display token. The rule already declared TargetSKUCandidates (successor) and prices the real delta via SetSKURates, so it fires concretely with no rule-logic change. Because the resolved key carries no commitment-term dimension, the rule guards explicitly with bedrockResourceIsCommittedTerm(resource.Metadata) (mirroring the aggregator’s bedrockPTIsNoCommit in internal/cost/calc_bedrock.go; separate modules, kept in lock-step, with drift guards on both sides) and returns nil before the rate lookup for any 1-month/6-month/Custom-term PT. Those remain a tracked, documented abstain (the display token alone can’t select a per-term rate). Never a $0/advisory rec or fabricated fraction. Concrete-fire + abstain matrix pinned in bedrock_old_model_generation_test.go; the aggregator sentinel-capture + committed-term abstain pinned in TestExtractResourceKey_BedrockPT_NotCaptured. See the aggregator docs/COST.md entry for the AWS Bedrock Provisioned Throughput per-MU-hour rate, now live.
Recreating the PT on the newer model
- Identify the latest generation in the same model family (e.g., Claude 3.5/4, Titan v2, Llama 3, Cohere Command R)
- Benchmark output quality on representative prompts
- Recreate the PT against the newer model identifier
- Migrate traffic and delete the old PT
Why metadata alone decides this rule
None (metadata-driven)