dnsmadeeasy 0.4.0 → 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (63) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ruby.yml +5 -10
  3. data/.gitignore +2 -0
  4. data/.rubocop.yml +5 -4
  5. data/.rubocop_todo.yml +251 -143
  6. data/CLAUDE.md +67 -0
  7. data/Gemfile +9 -1
  8. data/README.md +858 -0
  9. data/Rakefile +4 -4
  10. data/dnsmadeeasy.gemspec +42 -26
  11. data/docs/badges/coverage_badge.svg +21 -0
  12. data/docs/dry-cli-based-tools.webloc +8 -0
  13. data/docs/plan-zone-management.md +756 -0
  14. data/docs/plans/01-plan-ruby4-baseline.md +38 -0
  15. data/docs/plans/02-plan-dry-cli-launcher.md +44 -0
  16. data/docs/plans/03-plan-account-command.md +43 -0
  17. data/docs/plans/04-plan-zone-record-model.md +48 -0
  18. data/docs/plans/05-plan-zone-parser.md +41 -0
  19. data/docs/plans/06-plan-zone-formatter.md +43 -0
  20. data/docs/plans/07-plan-zone-export.md +58 -0
  21. data/docs/plans/08-plan-zone-diff.md +42 -0
  22. data/docs/plans/09-plan-zone-apply.md +69 -0
  23. data/docs/plans/10-plan-docs-cleanup.md +55 -0
  24. data/docs/spec-zone-management.md +242 -0
  25. data/exe/dme +13 -2
  26. data/exe/dmez +6 -0
  27. data/lib/dme.rb +7 -2
  28. data/lib/dnsmadeeasy/api/client.rb +32 -26
  29. data/lib/dnsmadeeasy/cli/box_output.rb +9 -0
  30. data/lib/dnsmadeeasy/cli/commands/account.rb +222 -0
  31. data/lib/dnsmadeeasy/cli/commands/base.rb +119 -0
  32. data/lib/dnsmadeeasy/cli/commands/legacy_operation.rb +30 -0
  33. data/lib/dnsmadeeasy/cli/commands/version.rb +22 -0
  34. data/lib/dnsmadeeasy/cli/commands/zone.rb +326 -0
  35. data/lib/dnsmadeeasy/cli/commands.rb +19 -0
  36. data/lib/dnsmadeeasy/cli/input.rb +14 -0
  37. data/lib/dnsmadeeasy/cli/launcher.rb +53 -0
  38. data/lib/dnsmadeeasy/cli/message_helpers.rb +81 -0
  39. data/lib/dnsmadeeasy/cli/reported_error.rb +10 -0
  40. data/lib/dnsmadeeasy/credentials/api_keys.rb +11 -9
  41. data/lib/dnsmadeeasy/credentials.rb +0 -1
  42. data/lib/dnsmadeeasy/runner.rb +24 -24
  43. data/lib/dnsmadeeasy/types.rb +19 -0
  44. data/lib/dnsmadeeasy/version.rb +2 -1
  45. data/lib/dnsmadeeasy/zone/aname_flattener.rb +63 -0
  46. data/lib/dnsmadeeasy/zone/apply_executor.rb +189 -0
  47. data/lib/dnsmadeeasy/zone/apply_result.rb +22 -0
  48. data/lib/dnsmadeeasy/zone/diff.rb +152 -0
  49. data/lib/dnsmadeeasy/zone/file.rb +26 -0
  50. data/lib/dnsmadeeasy/zone/parser.rb +172 -0
  51. data/lib/dnsmadeeasy/zone/plan.rb +28 -0
  52. data/lib/dnsmadeeasy/zone/plan_action.rb +29 -0
  53. data/lib/dnsmadeeasy/zone/plan_renderer.rb +91 -0
  54. data/lib/dnsmadeeasy/zone/provider_record.rb +18 -0
  55. data/lib/dnsmadeeasy/zone/record.rb +44 -0
  56. data/lib/dnsmadeeasy/zone/record_set.rb +23 -0
  57. data/lib/dnsmadeeasy/zone/remote_adapter.rb +94 -0
  58. data/lib/dnsmadeeasy/zone/remote_records.rb +26 -0
  59. data/lib/dnsmadeeasy/zone/serializer.rb +115 -0
  60. data/lib/dnsmadeeasy.rb +61 -27
  61. metadata +184 -25
  62. data/.dme-help.png +0 -0
  63. data/README.adoc +0 -690
@@ -0,0 +1,38 @@
1
+ # 01 Plan: Ruby 4 Baseline
2
+
3
+ ## Stacked PR Metadata
4
+
5
+ - Plan identifier: `01`
6
+ - Branch: `stack-01-ruby4-baseline`
7
+ - Base branch: `master`
8
+ - PR title: `01: Establish Ruby 4 baseline for dnsmadeeasy 1.0`
9
+ - PR description must reference: `Plan 01 - Ruby 4 Baseline`
10
+
11
+ ## Scope
12
+
13
+ - Drop Ruby 2 support.
14
+ - Add Ruby 4 support.
15
+ - Bump `DnsMadeEasy::VERSION` to `1.0.0`.
16
+ - Update gem metadata and CI Ruby version.
17
+ - Add the first dependency baseline needed by later PRs only when it is directly required here.
18
+ - Preserve current library behavior.
19
+
20
+ ## Implementation Notes
21
+
22
+ - Prefer Ruby 4 only with `spec.required_ruby_version = '~> 4.0'` unless we decide public compatibility requires Ruby 3.2+.
23
+ - Add `tsort` explicitly to quiet the Ruby 4.1 default-gem warning from `sym`.
24
+ - Update GitHub Actions from Ruby 2.7 and old `actions/setup-ruby` usage to current `ruby/setup-ruby`.
25
+
26
+ ## RSpec Requirements
27
+
28
+ - Update or add specs proving `DnsMadeEasy::VERSION == '1.0.0'`.
29
+ - Keep the Ruby 4 keyword-argument compatibility specs passing.
30
+ - Use modern nested `describe`/`context` blocks with block-local `subject`.
31
+ - Use concise one-liner expectations, including `it { ... }` and `its(:property) { ... }` where readable.
32
+
33
+ ## Acceptance Criteria
34
+
35
+ - `bundle exec rspec` passes on Ruby 4.
36
+ - CI config targets Ruby 4.
37
+ - The gem metadata no longer claims Ruby 2 support.
38
+ - No live DNS Made Easy calls are made.
@@ -0,0 +1,44 @@
1
+ # 02 Plan: dry-cli Launcher and Aruba Test Harness
2
+
3
+ ## Stacked PR Metadata
4
+
5
+ - Plan identifier: `02`
6
+ - Branch: `stack-02-dry-cli-launcher`
7
+ - Base branch: `stack-01-ruby4-baseline`
8
+ - PR title: `02: Introduce dry-cli launcher and Aruba harness`
9
+ - PR description must reference: `Plan 02 - dry-cli Launcher and Aruba Test Harness`
10
+
11
+ ## Scope
12
+
13
+ - Add `dry-cli`.
14
+ - Include `tty-spinner` as a runtime dependency for later threaded zone export/apply progress reporting.
15
+ - Add a `DnsMadeEasy::CLI::Commands` registry.
16
+ - Add `DnsMadeEasy::CLI::Launcher`.
17
+ - Add `DnsMadeEasy::CLI::Commands::Base`.
18
+ - Add a `version` command.
19
+ - Configure Aruba for in-process CLI tests.
20
+ - Update `exe/dme` to call the launcher.
21
+ - Keep `DnsMadeEasy::Runner` temporarily for migration reference.
22
+
23
+ ## Implementation Notes
24
+
25
+ - Follow the `../githuh` launcher shape, but keep the implementation smaller.
26
+ - All command output must use injected `stdout` and `stderr`.
27
+ - Do not put business logic in the launcher.
28
+ - Do not make zone commands in this PR.
29
+
30
+ ## RSpec Requirements
31
+
32
+ - Add launcher specs using direct `StringIO` streams.
33
+ - Add Aruba specs for:
34
+ - `dme --help`
35
+ - `dme version`
36
+ - Use `subject(:launcher)` or block-local `subject { output }` per describe block.
37
+ - Use `its(:stdout)` style only where the object exposes a clear property; otherwise use `it { is_expected.to ... }`.
38
+
39
+ ## Acceptance Criteria
40
+
41
+ - `dme --help` is handled through dry-cli.
42
+ - `dme version` prints `1.0.0`.
43
+ - Aruba runs the CLI in-process.
44
+ - Existing library specs still pass.
@@ -0,0 +1,43 @@
1
+ # 03 Plan: Account Command for Existing API Operations
2
+
3
+ ## Stacked PR Metadata
4
+
5
+ - Plan identifier: `03`
6
+ - Branch: `stack-03-account-command`
7
+ - Base branch: `stack-02-dry-cli-launcher`
8
+ - PR title: `03: Move existing API operations under account command`
9
+ - PR description must reference: `Plan 03 - Account Command for Existing API Operations`
10
+
11
+ ## Scope
12
+
13
+ - Add `dme account <operation> [args...]`.
14
+ - Move existing CLI behavior from `DnsMadeEasy::Runner` into a dry-cli command.
15
+ - Preserve output formats where practical.
16
+ - Validate operation names using `DnsMadeEasy::Api::Client.public_operations`.
17
+ - Replace runner specs with Aruba command specs.
18
+
19
+ ## Implementation Notes
20
+
21
+ - Treat `<operation>` as an argument to one `Account` command.
22
+ - Do not generate one dry-cli class per API method unless the single-command design becomes unworkable.
23
+ - For version 1.0, prefer a clear migration hint for old root operations like `dme domains`.
24
+ - Preserve method arity diagnostics where reasonable.
25
+
26
+ ## RSpec Requirements
27
+
28
+ - Add Aruba specs for:
29
+ - `dme account operations`
30
+ - `dme account domains`
31
+ - `dme account records_for example.com`
32
+ - invalid account operation
33
+ - invalid arity where current behavior provides a useful message
34
+ - Mock `DnsMadeEasy.client`; do not hit the network.
35
+ - Use nested `describe '#call'`, `context 'with valid operation'`, and `context 'with invalid operation'`.
36
+ - Use `subject { output }` for CLI output examples and `its(:exit_status)` if command objects expose it.
37
+
38
+ ## Acceptance Criteria
39
+
40
+ - Existing API operations are reachable through `dme account`.
41
+ - Old `Runner` can be deleted or made a thin deprecated wrapper.
42
+ - `bundle exec rspec` passes.
43
+ - No live DNS Made Easy calls are made.
@@ -0,0 +1,48 @@
1
+ # 04 Plan: Typed Zone Record Model
2
+
3
+ ## Stacked PR Metadata
4
+
5
+ - Plan identifier: `04`
6
+ - Branch: `stack-04-zone-record-model`
7
+ - Base branch: `stack-03-account-command`
8
+ - PR title: `04: Add typed zone record domain model`
9
+ - PR description must reference: `Plan 04 - Typed Zone Record Model`
10
+
11
+ ## Scope
12
+
13
+ - Add `dry-types`.
14
+ - Add `dry-struct`.
15
+ - Define internal provider-neutral zone record objects.
16
+ - Define record-set and sorting behavior.
17
+ - Keep provider IDs out of serializable zone records.
18
+
19
+ ## Implementation Notes
20
+
21
+ - Create `DnsMadeEasy::Types`.
22
+ - Support initial record types:
23
+ - `A`
24
+ - `AAAA`
25
+ - `CNAME`
26
+ - `MX`
27
+ - `NS`
28
+ - `PTR`
29
+ - `SPF`
30
+ - `SRV`
31
+ - `TXT`
32
+ - Represent DNS Made Easy metadata separately from record equality.
33
+ - Build deterministic sort keys now because serializer and diff will depend on them.
34
+
35
+ ## RSpec Requirements
36
+
37
+ - Add specs for valid construction.
38
+ - Add specs for invalid record type, TTL, and required attributes.
39
+ - Add specs for deterministic sorting.
40
+ - Add specs proving provider metadata is separate from record equality.
41
+ - Use `subject(:record) { described_class.new(...) }`.
42
+ - Use `its(:owner) { ... }`, `its(:type) { ... }`, and `it { is_expected.to ... }` one-liners where useful.
43
+
44
+ ## Acceptance Criteria
45
+
46
+ - Zone records are immutable typed value objects.
47
+ - Invalid input fails before parser/diff/apply logic can use it.
48
+ - `bundle exec rspec` passes.
@@ -0,0 +1,41 @@
1
+ # 05 Plan: Zone File Parser and Validation Command
2
+
3
+ ## Stacked PR Metadata
4
+
5
+ - Plan identifier: `05`
6
+ - Branch: `stack-05-zone-parser`
7
+ - Base branch: `stack-04-zone-record-model`
8
+ - PR title: `05: Parse and validate standard zone files`
9
+ - PR description must reference: `Plan 05 - Zone File Parser and Validation Command`
10
+
11
+ ## Scope
12
+
13
+ - Add `dns-zonefile`.
14
+ - Add `dry-monads` and use `Dry::Monads::Result` for parser and validation service results.
15
+ - Add parser adapter at the boundary.
16
+ - Add `dme zone validate FILE`.
17
+ - Convert parser output immediately into internal zone records.
18
+
19
+ ## Implementation Notes
20
+
21
+ - `aeden/dns-zonefile` is sufficient for v1 parsing of downloaded or standard RFC-style zone files.
22
+ - Parser and validation workflows should return `Success(value)` / `Failure(errors)` rather than raising for expected user-input errors.
23
+ - Do not leak `DNS::Zonefile::*` classes beyond the adapter.
24
+ - Unsupported syntax should produce actionable validation errors.
25
+ - `HTTPRED` is not represented in standard zone files and does not need parser support in v1.
26
+
27
+ ## RSpec Requirements
28
+
29
+ - Add parser unit specs with fixture zone files.
30
+ - Add Aruba specs for:
31
+ - valid zone file
32
+ - invalid zone file
33
+ - unsupported record type
34
+ - Use `subject(:result) { described_class.new(...).call }` for service specs.
35
+ - Use `its(:records) { ... }`, `its(:errors) { ... }`, and one-liner `it { is_expected.to be_success }` style where available.
36
+
37
+ ## Acceptance Criteria
38
+
39
+ - `dme zone validate FILE` succeeds for standard fixture zone files.
40
+ - Parser adapter returns internal records only.
41
+ - `bundle exec rspec` passes.
@@ -0,0 +1,43 @@
1
+ # 06 Plan: Canonical Zone Serializer and Formatter
2
+
3
+ ## Stacked PR Metadata
4
+
5
+ - Plan identifier: `06`
6
+ - Branch: `stack-06-zone-formatter`
7
+ - Base branch: `stack-05-zone-parser`
8
+ - PR title: `06: Add canonical zone serializer and formatter`
9
+ - PR description must reference: `Plan 06 - Canonical Zone Serializer and Formatter`
10
+
11
+ ## Scope
12
+
13
+ - Add canonical serializer.
14
+ - Add `dme zone fmt FILE`.
15
+ - Optionally add `dme zone format FILE` as an alias.
16
+ - Normalize whitespace and ordering.
17
+
18
+ ## Normalized Output Rules
19
+
20
+ - one zone per file
21
+ - explicit owner on every record
22
+ - `$ORIGIN`
23
+ - `$TTL`
24
+ - `@` for zone apex
25
+ - deterministic ordering
26
+ - normalized, aligned whitespace
27
+ - provider-managed SOA omitted
28
+ - apex NS records omitted by default
29
+ - delegated NS records preserved
30
+
31
+ ## RSpec Requirements
32
+
33
+ - Add golden-file specs for formatter output.
34
+ - Add idempotency spec: parse, serialize, parse, serialize produces byte-identical output.
35
+ - Add specs for apex NS omission and delegated NS preservation.
36
+ - Use `subject(:serialized_zone) { described_class.new(...).to_s }`.
37
+ - Use one-liners for exact matches and property checks where readable.
38
+
39
+ ## Acceptance Criteria
40
+
41
+ - `dme zone fmt FILE` emits canonical zone text.
42
+ - Already formatted files remain byte-identical.
43
+ - `bundle exec rspec` passes.
@@ -0,0 +1,58 @@
1
+ # 07 Plan: Remote Adapter and Zone Export
2
+
3
+ ## Stacked PR Metadata
4
+
5
+ - Plan identifier: `07`
6
+ - Branch: `stack-07-zone-export`
7
+ - Base branch: `stack-06-zone-formatter`
8
+ - PR title: `07: Export DNS Made Easy records as canonical zone files`
9
+ - PR description must reference: `Plan 07 - Remote Adapter and Zone Export`
10
+
11
+ ## Scope
12
+
13
+ - Add remote record adapter.
14
+ - Add `dme zone export DOMAIN`.
15
+ - Convert DNS Made Easy API responses to internal zone records.
16
+ - Serialize remote records through the canonical serializer.
17
+
18
+ ## Implementation Notes
19
+
20
+ - Use the existing API client as the provider boundary.
21
+ - Keep provider IDs separate from exported records.
22
+ - Omit `HTTPRED` from exports.
23
+ - Emit warnings listing omitted `HTTPRED` records.
24
+ - Write zone text to stdout by default.
25
+ - Write warnings to stderr so stdout remains pipe-safe.
26
+ - When export requires multiple independent provider calls, split work into bounded worker-thread chunks.
27
+ - Use one `TTY::Spinner` per active worker/chunk for interactive progress.
28
+ - Use `TTY::Spinner::Multi` for concurrent thread progress:
29
+ https://github.com/piotrmurach/tty-spinner#5-ttyspinnermulti-api
30
+ - Collect worker results and render final zone output deterministically after all workers finish.
31
+ - Inject a fake/no-op spinner in specs so output remains stable.
32
+
33
+ ## Live Integration Note
34
+
35
+ Opt-in live specs may use:
36
+
37
+ - Domain: `isdue.today`
38
+ - DNS Made Easy domain ID: `8218117`
39
+
40
+ Live specs must be gated by `DNSMADEEASY_LIVE_TESTS=1` or equivalent and must only touch test-owned records.
41
+
42
+ ## RSpec Requirements
43
+
44
+ - Add unit specs for remote adapter conversion.
45
+ - Add Aruba specs for export using a mocked client.
46
+ - Add specs proving `HTTPRED` is omitted and warning text is emitted.
47
+ - Add specs for chunked parallel execution with deterministic result ordering.
48
+ - Add specs for failed worker chunks and aggregated error reporting.
49
+ - Add optional live integration specs marked/skipped unless explicitly enabled.
50
+ - Use `subject(:records)`, `subject(:output)`, and `its(:warnings)` where the object model supports it.
51
+
52
+ ## Acceptance Criteria
53
+
54
+ - `dme zone export example.com` produces deterministic zone output with mocked data.
55
+ - Provider metadata is not serialized.
56
+ - Independent provider reads can run concurrently with bounded worker threads.
57
+ - Progress is displayed with `TTY::Spinner` during interactive export work.
58
+ - `bundle exec rspec` passes without live credentials.
@@ -0,0 +1,42 @@
1
+ # 08 Plan: Zone Diff Engine and Plan Command
2
+
3
+ ## Stacked PR Metadata
4
+
5
+ - Plan identifier: `08`
6
+ - Branch: `stack-08-zone-diff-plan`
7
+ - Base branch: `stack-07-zone-export`
8
+ - PR title: `08: Add zone diff engine and plan command`
9
+ - PR description must reference: `Plan 08 - Zone Diff Engine and Plan Command`
10
+
11
+ ## Scope
12
+
13
+ - Add diff engine.
14
+ - Add execution plan objects.
15
+ - Add text and JSON plan renderers.
16
+ - Add `dme zone plan FILE`.
17
+
18
+ ## Implementation Notes
19
+
20
+ - Default behavior:
21
+ - create missing records
22
+ - update modified records only when unambiguous
23
+ - never delete records
24
+ - Multiple records with the same owner/type must be modeled as record sets.
25
+ - Prefer conservative create/delete reporting over unsafe update matching.
26
+ - Ambiguous changes should be reported as requiring manual intervention.
27
+
28
+ ## RSpec Requirements
29
+
30
+ - Add unit specs for create, update, no-op, skipped delete, and ambiguous cases.
31
+ - Add golden-file specs for text plan output.
32
+ - Add JSON output specs.
33
+ - Add Aruba specs for `dme zone plan FILE` with mocked remote state.
34
+ - Use `subject(:plan) { described_class.new(...).call }`.
35
+ - Use `its(:creates)`, `its(:updates)`, `its(:skipped_deletes)`, and one-liner expectations.
36
+
37
+ ## Acceptance Criteria
38
+
39
+ - Plan output is deterministic.
40
+ - Deletes are skipped by default.
41
+ - Ambiguous changes are not applied silently.
42
+ - `bundle exec rspec` passes.
@@ -0,0 +1,69 @@
1
+ # 09 Plan: Safe Zone Apply Command
2
+
3
+ ## Stacked PR Metadata
4
+
5
+ - Plan identifier: `09`
6
+ - Branch: `stack-09-zone-apply`
7
+ - Base branch: `stack-08-zone-diff-plan`
8
+ - PR title: `09: Apply zone plans safely`
9
+ - PR description must reference: `Plan 09 - Safe Zone Apply Command`
10
+
11
+ ## Scope
12
+
13
+ - Add `dme zone apply FILE`.
14
+ - Reuse the same planner used by `zone plan`.
15
+ - Execute creates and updates through the existing API client.
16
+ - Keep deletes opt-in.
17
+ - Split independent API operations into bounded worker-thread chunks.
18
+ - Use one `TTY::Spinner` per active worker/chunk for interactive progress.
19
+ - Use `TTY::Spinner::Multi` for concurrent thread progress:
20
+ https://github.com/piotrmurach/tty-spinner#5-ttyspinnermulti-api
21
+ - Keep final execution summaries deterministic even when worker completion order varies.
22
+
23
+ ## Safety Rules
24
+
25
+ - Never delete by default.
26
+ - Never delete SOA records.
27
+ - Never delete apex NS records in v1.
28
+ - Require confirmation unless `--yes` is provided.
29
+ - Fail before applying if parsing or validation fails.
30
+ - Report partial failures clearly.
31
+ - Parallelize only actions proven independent by the plan.
32
+ - Aggregate worker errors by action/chunk.
33
+
34
+ ## Options (flags)
35
+
36
+ -a | --add-only Ensures that only new records are being added, especially if the zone file does not contain all existing records
37
+ -d | --delete-only Applies only the deletion part of the plan
38
+ -m | --merge Default mode - compare existing DNS Zone with the provided, and merge the differences, turning them into add/update or delete actions.
39
+
40
+ ## Live Integration Note
41
+
42
+ Opt-in live specs may use:
43
+
44
+ - Domain: `isdue.today`
45
+ - DNS Made Easy domain ID: `8218117`
46
+
47
+ Live specs must only mutate predictable test records such as `_dnsmadeeasy-test.isdue.today` and must clean them up.
48
+
49
+ ## RSpec Requirements
50
+
51
+ - Add unit specs for executor behavior.
52
+ - Add Aruba specs for confirmation flow.
53
+ - Add specs for `--yes`.
54
+ - Add specs for delete refusal without `--delete`.
55
+ - Add specs for threaded chunk execution.
56
+ - Add specs using fake/no-op spinner objects.
57
+ - Add specs proving final summaries are deterministic.
58
+ - Add optional gated live integration specs for create/update/delete of test-owned records.
59
+ - Use `subject(:result) { described_class.new(...).call }`.
60
+ - Use `its(:applied_actions)`, `its(:failed_actions)`, and concise one-liners where useful.
61
+
62
+ ## Acceptance Criteria
63
+
64
+ - Apply executes the current plan.
65
+ - Apply refuses destructive operations unless explicitly allowed.
66
+ - Independent actions can run concurrently with bounded worker threads.
67
+ - Progress is displayed with `TTY::Spinner` during interactive apply work.
68
+ - Default test suite never touches live DNS.
69
+ - `bundle exec rspec` passes.
@@ -0,0 +1,55 @@
1
+ # 10 Plan: Documentation, Migration Notes, and Cleanup
2
+
3
+ ## Stacked PR Metadata
4
+
5
+ - Plan identifier: `10`
6
+ - Branch: `stack-10-docs-cleanup`
7
+ - Base branch: `stack-09-zone-apply`
8
+ - PR title: `10: Document dnsmadeeasy 1.0 CLI and zone workflow`
9
+ - PR description must reference: `Plan 10 - Documentation, Migration Notes, and Cleanup`
10
+
11
+ ## Scope
12
+
13
+ - Update README examples for the new command tree.
14
+ - Document Ruby 4 and version 1.0 breaking changes.
15
+ - Document the zone-file workflow.
16
+ - Remove deprecated runner leftovers if still present.
17
+ - Ensure command examples are represented by smoke specs where practical.
18
+
19
+ ## Documentation Requirements
20
+
21
+ Include examples for:
22
+
23
+ ```text
24
+ dme account domains
25
+ dme account records_for example.com
26
+ dme zone export example.com > example.com.zone
27
+ dme zone validate example.com.zone
28
+ dme zone fmt example.com.zone
29
+ dme zone plan example.com.zone
30
+ dme zone apply example.com.zone --yes
31
+ ```
32
+
33
+ Document that `HTTPRED` is omitted from standard zone exports in v1, with warnings.
34
+
35
+ Document the live integration test domain:
36
+
37
+ - Domain: `isdue.today`
38
+ - DNS Made Easy domain ID: `8218117`
39
+
40
+ ## RSpec Requirements
41
+
42
+ - Add or update CLI smoke specs for README command examples where practical.
43
+ - Add specs for migration messages if old commands are intentionally unsupported.
44
+ - Keep specs in the modern style:
45
+ - nested `describe`/`context`
46
+ - block-local `subject`
47
+ - concise `it { ... }`
48
+ - `its(:property) { ... }` where it improves readability
49
+
50
+ ## Acceptance Criteria
51
+
52
+ - README accurately reflects the 1.0 CLI.
53
+ - Old docs for root-level operations are removed or marked as legacy.
54
+ - All specs pass.
55
+ - The stacked PR series is ready to merge from `01` through `10`.