Skip to content

Fix future() negation edge cases; add prune_empty_branches (#269)#282

Merged
jtdub merged 2 commits into
masterfrom
issue-269-future-negation-master
Jul 19, 2026
Merged

Fix future() negation edge cases; add prune_empty_branches (#269)#282
jtdub merged 2 commits into
masterfrom
issue-269-future-negation-master

Conversation

@jtdub

@jtdub jtdub commented Jul 19, 2026

Copy link
Copy Markdown
Contributor

Summary

Port of #281 (next) to the 3.x line — closes #269 together with #281.

_future() resolves negations in an explicit, documented order:

  1. Exact positive match → the negation removes the line and neither survives (issue case 1; the root cause was the idempotency check running first and matching the negation line itself via EOS's unanchored neighbor \S+ description rule).
  2. Idempotency rules → unchanged replace semantics, deliberately covering rule-tracked negated forms: IOS no logging console still replaces logging console X and persists — real device behavior and required by the existing remediation roundtrip test.
  3. Shorthand prefix matchno description removes description foo (issue case 2).
  4. Unmatched negations kept — running-config-native no ... lines and the did-not-apply-cleanly signal the issue asked to preserve.

Issue case 3 ships as opt-in HConfig.future(change, prune_empty_branches=True): prunes sections the change emptied (cascading, e.g. XR router static / address-family), keeping already-empty and newly-added-empty sections.

Also includes the mechanical ruff 0.15 adaptation (suppression syntax + property-docstring rules) — the renovate lock bump had left master unable to pass its own lint gate, so any PR here would have failed CI without it.

Test plan

  • Six new tests mirroring the next-branch set, adapted to the 3.x API (get_hconfig/dump_simple): all three issue repros, the stale-value idempotency pin, the unmatched-signal pin, and prune on/off/originally-empty.
  • Full suite passes (631 tests) including the IOS logging console roundtrip.
  • poetry run ./scripts/build.py lint-and-test — "No issues found".

🤖 Generated with Claude Code

Port of the next-branch fix (#281) to the 3.x line:

- A negation whose positive form exists removes it and neither line
  survives; evaluated before the idempotency rules, which can match the
  negation line itself and previously kept it as a literal child while
  displacing the original.
- Idempotency rules keep their replace semantics, deliberately covering
  rule-tracked negated forms (IOS `no logging console` persists, which
  the remediation roundtrip depends on).
- Shorthand negations (`no description`) remove the valued lines they
  prefix-match, as devices do.
- Unmatched negations are kept as a did-not-apply-cleanly signal.
- HConfig.future() gains prune_empty_branches: sections emptied by the
  change are pruned as devices do on commit; already-empty sections are
  kept.

Also adapts the tree to ruff 0.15 from the renovate lock bump
(suppression-comment syntax and property-docstring rules), which had
left master failing its own lint gate.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Brings ruff to 0.15.22 (matching the suppression syntax this branch
uses and the next branch's toolchain), plus routine dependency bumps.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@jtdub
jtdub merged commit 32e6076 into master Jul 19, 2026
5 checks passed
@jtdub
jtdub deleted the issue-269-future-negation-master branch July 19, 2026 00:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant