# S3 Bucket Lifecycle Policy Missing

> Missing lifecycle policies on S3 buckets leave cold STANDARD-tier data paying full price. ZopNight would price savings as cold GB times the (STANDARD − STANDARD-IA) rate delta times 730 hours, but abstains on live data today: the per-bucket standard_cold_bytes_gb signal from Storage Lens has no producer yet.

Source: https://zop.dev/integrations/aws/recommendations/s3-bucket-lifecycle-policy-missing
Updated: 2026-08-19

---

## Buckets with no lifecycle rule at all

- Metadata["lifecycle_policy_present"] (JSON bool) must be false. The prior lifecycle_policy=true Tag gate had the wrong key (missing _present) and the wrong field (Tags, not Metadata), so it was inert and the rule over-fired on every bucket; abstains when the key is absent (unknown).
- PricingAware: per-resource monthly cost (applicability gate)
- SKURatesAware: STANDARD and STANDARD-IA per-GB-hour rates
- Producer gap on standard_cold_bytes_gb (per-bucket GB of cold STANDARD-tier data from S3 Storage Lens / Storage Class Analysis): getMetadataFloat returns -1 when absent, so the rule abstains until this key is emitted.

## Pricing cold data at the Standard to IA gap

concrete-or-abstain (cost-driven rightsizing). savings = coldGB × (LookupSKURate(STANDARD) − LookupSKURate(STANDARD-IA)) × hoursPerMonth. The rates are per-GB-hour ([the published per-GB-month figures for each storage class](https://aws.amazon.com/s3/pricing/) ÷ 730 at ingest; see pricing/aws/stream.go isStorageRate), so the ×730 is mandatory to get a monthly figure (omitting it under-reports ~730× and the rec is swallowed by the $5 floor, the same trap as GCP RC-147). The rule abstains (returns nil) when standard_cold_bytes_gb is absent (the current live state), either rate is missing, or the delta is non-positive. It never uses the prior cost*0.30 fabricated fraction and never ships a $0 cost rec. (Siblings RC-070/RC-073/RC-1512 already removed the same cost*0.30; RC-072 was missed in that sweep.)

## Building the transition and expiry rules

1. Go to S3 Console → Select bucket → Management
2. Create lifecycle rule for object transitions
3. Transition to Standard-IA after 30 days
4. Transition to a Glacier tier after 90 days (Instant / Flexible Retrieval / Deep Archive by access pattern)
5. Expire objects after 365 days if applicable

## No metrics, just Standard and Standard-IA rates

None (SKURatesAware: STANDARD / STANDARD-IA per-GB-hour rates)
