v0.1.2
Fixes
Most severe: flattening stripped SPF qualifiers before processing mechanisms, so fail/softfail/neutral (-/~/?) mechanisms were published as unconditional passes. Flattening now refuses instead of silently inverting a mechanism's meaning.
Also fixed:
- lookup_cost() undercounted passthrough include:/redirect: terms by not walking their transitive cost, letting a config pass the RFC 7208 guard while the real published record could exceed 10 lookups.
- a:/mx: targets hard-failed the whole domain on NXDOMAIN instead of treating it like NoAnswer, so one stale hostname in an upstream provider's record could permanently block updates.
- redirect= was followed even when the record already had an all mechanism.
- Multi-ResourceRecord Route53 TXT rrsets (e.g. left over from another flattener) could break atomic DELETE batches or falsely compare as unchanged; this now refuses loudly instead.
- Deploy's bundled dependencies weren't pinned to the Lambda's actual platform/Python version, and gave an opaque error under pip-less environments (e.g. uv tool install spf53).
- The release workflow now installs the actual published wheel and exercises the deploy path before publishing, closing the gap that let v0.1.0's broken deploy command ship undetected.
- Config now rejects duplicate domain entries and bare "all" passthrough mechanisms at load time.
- v=spf1 record detection is boundary-anchored; ip4/ip6 family mismatches are rejected instead of silently accepted; added RFC 7208's 10-MX-exchange cap and a total chain-size cap.
263 tests passing, no known regressions.