Follow-up from the DNS SDK-compat review (#252). These are fidelity gaps rooted in the shared dns/driver.DNS model, so they affect the Portable API too, not just the HTTP handlers — worth fixing at the driver level rather than per-handler.
Zone identity & scoping
dns/driver has no zone name uniqueness — two zones with the same name resolve nondeterministically (map iteration order) in every handler's resolveZoneID. Real Route 53/Azure/Cloud DNS reject duplicates (or scope by id).
ZoneInfo carries no resource-group / project attribution, so Azure ListByResourceGroup and GCP managedZones.list return every zone across RGs/projects (and Azure re-labels each under the requested RG). Needs a scope field on the driver.
- No
GetZoneByName / indexed lookup — every zone/record op does an O(n) ListZones scan (duplicated across the Azure and GCP handlers).
Zone mutation
- No
UpdateZone method → Azure CreateOrUpdate on an existing zone silently drops tag/zoneType updates (returns the stale zone with 200).
Record fidelity
- Flat
Values []string can't represent Azure TXT multi-chunk entries ([][]string); chunks are joined on the wire, so ["a","b"] round-trips to ["ab"] (DKIM/SPF).
DeleteRecord(zoneID, name, type) ignores rrdatas/TTL, so Cloud DNS deletions don't enforce exact-match of the existing record set the way the real API does.
- No
UpsertRecord primitive → the check-then-act upsert is reimplemented (and slightly racy) in the Route 53 and Azure handlers.
Batch atomicity
Acceptance: extend dns/driver.DNS (name/id + scope-aware lookups, UpdateZone, UpsertRecord, structured TXT), update all three providers + the handlers, and add roundtrip tests covering TXT chunks, per-scope listing, tag updates, and duplicate-name rejection.
Follow-up from the DNS SDK-compat review (#252). These are fidelity gaps rooted in the shared
dns/driver.DNSmodel, so they affect the Portable API too, not just the HTTP handlers — worth fixing at the driver level rather than per-handler.Zone identity & scoping
dns/driverhas no zone name uniqueness — two zones with the same name resolve nondeterministically (map iteration order) in every handler'sresolveZoneID. Real Route 53/Azure/Cloud DNS reject duplicates (or scope by id).ZoneInfocarries no resource-group / project attribution, so AzureListByResourceGroupand GCPmanagedZones.listreturn every zone across RGs/projects (and Azure re-labels each under the requested RG). Needs a scope field on the driver.GetZoneByName/ indexed lookup — every zone/record op does an O(n)ListZonesscan (duplicated across the Azure and GCP handlers).Zone mutation
UpdateZonemethod → AzureCreateOrUpdateon an existing zone silently drops tag/zoneType updates (returns the stale zone with 200).Record fidelity
Values []stringcan't represent Azure TXT multi-chunk entries ([][]string); chunks are joined on the wire, so["a","b"]round-trips to["ab"](DKIM/SPF).DeleteRecord(zoneID, name, type)ignores rrdatas/TTL, so Cloud DNS deletions don't enforce exact-match of the existing record set the way the real API does.UpsertRecordprimitive → the check-then-act upsert is reimplemented (and slightly racy) in the Route 53 and Azure handlers.Batch atomicity
changes.createcan't be truly atomic. feat(dns): Secrets-style SDK-compat servers for Route 53, Azure DNS, and Cloud DNS #252 added an up-front validation pass so a bad batch fails before mutating, but a concurrent writer between validate and apply can still race.Acceptance: extend
dns/driver.DNS(name/id + scope-aware lookups,UpdateZone,UpsertRecord, structured TXT), update all three providers + the handlers, and add roundtrip tests covering TXT chunks, per-scope listing, tag updates, and duplicate-name rejection.