Optimize cutover compare/monitor per the 2026-10-12 plan.

Correctness (A): normalize port-map names with the template rules (snapshot v2,
v1 replays unchanged); protect mappings/templates that are referenced; stop
dropping edited mapping text; accept pulled-but-not-shutdown ports as migrated;
validate baseline ownership on project create; one canonical key form; fix
built-in template tolerances and upgrade old packaged values in place.

Cross-vendor identity (B): single identity pipeline for every path, per-side and
per-vendor interface rules, value maps, filters after normalization, mapping
pre-flight for compare and cutover projects, SQL eligibility fixes.

Data quality (V): no_data / suspect_parse / not_collected sheet states, command
slice coverage, directional compare modes, value-sorted duplicate pairing,
before-side raw names in results and CSV.

Robustness (H): bounded auto-run history, background evaluate/finish with
polling, manual route tables out of the acceptance gate, baseline row cache,
scoped duplicate-key failures, merged HF tasks with a per-NE session cap,
same-device cutover, explicit scope_by_port_map, read-only GETs, resolvable red
tickets.

Frontend: pre-flight report, mapping table view, template editor support for the
new rules, data-state banners. Docs: canonical field contract.

Not included: Huawei status parsers (no real samples), SQL-path route compare.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
oliver 2026-10-12 11:51:55 +08:00
parent fff7d63b9b
commit 315539e0fd
59 changed files with 6483 additions and 487 deletions

View file

@ -406,3 +406,21 @@ def test_diff_filters_apply_before_pagination_and_escape_wildcards(db):
def test_invalid_correction_rules_fail_before_evaluation(condition):
with pytest.raises(HTTPException):
validate_monitor_rules({}, [{"metric_id": "arp", "success": [{"old_groups": [[condition]], "new": ["added"]}]}])
@pytest.mark.parametrize("raw", [None, True, " v "])
def test_odd_key_values_still_match_expected_key(raw):
"""A6: diff-derived key strings must use the same form as the expect set."""
from netx_api.biz_migration.monitor_templates import preset_override_for_metric
from netx_api.biz_state.compare_rules import scalar_text
old = {"ip": "a", "vrf": raw, "mac": "m", "port": "old"}
new = {"ip": "a", "vrf": raw, "mac": "m", "port": "new"}
out = evaluate(
key_fields=["ip", "vrf"], compare_fields=["mac"], iface_fields=[],
old_baseline_rows=[old], old_current_rows=[], new_baseline_rows=[], new_current_rows=[new],
port_map={}, window_active=False, acceptance=True,
sheet_override=preset_override_for_metric("arp"),
expect=parse_expect_set({"items": [{"metric_id": "arp", "key": ["a", scalar_text(raw).strip()]}]}),
)
assert [r["verdict"] for r in out["rows"]] == ["migrated"]