refactor(backend)!: separate algorithm and data layers

Reorganize algorithm packages by business responsibility, move orchestration into services, and keep database access behind pooled repositories.

Harden analysis API validation, remove unsafe legacy simulation endpoints, and add regression and architecture boundary coverage.

BREAKING CHANGE: legacy algorithm module paths and obsolete simulation endpoints are removed.
This commit is contained in:
2026-09-04 17:30:55 +08:00
parent 9b095c7439
commit 5966d039de
91 changed files with 1418 additions and 4020 deletions
+14 -44
View File
@@ -1,26 +1,10 @@
from collections import defaultdict
from app.algorithms.isolation import valve
from app.algorithms.valve_isolation import topology_search as valve
def test_non_isolatable_omits_affected_node_ids_but_keeps_count(monkeypatch):
pipe_adj = defaultdict(
set,
{
"A": {"B"},
"B": {"A", "C"},
"C": {"B"},
},
)
topology = (
pipe_adj,
{"V-optional": ("A", "C")},
{"P-1": ("A", "B", "pipe")},
{"A", "B", "C"},
)
monkeypatch.setattr(valve, "_get_network_topology", lambda _network: topology)
def test_non_isolatable_omits_affected_node_ids_but_keeps_count():
links = ["P-1:pipe:A:B", "P-2:pipe:B:C", "V-optional:valve:A:C"]
result = valve.valve_isolation_analysis("demo", "P-1")
result = valve.valve_isolation_analysis(links, "P-1")
assert result["isolatable"] is False
assert result["affected_node_count"] == 3
@@ -28,17 +12,10 @@ def test_non_isolatable_omits_affected_node_ids_but_keeps_count(monkeypatch):
assert result["optional_valves"] == ["V-optional"]
def test_isolatable_keeps_affected_node_ids_and_count(monkeypatch):
pipe_adj = defaultdict(set, {"A": {"B"}, "B": {"A"}})
topology = (
pipe_adj,
{"V-close": ("B", "C")},
{"P-1": ("A", "B", "pipe")},
{"A", "B", "C"},
)
monkeypatch.setattr(valve, "_get_network_topology", lambda _network: topology)
def test_isolatable_keeps_affected_node_ids_and_count():
links = ["P-1:pipe:A:B", "V-close:valve:B:C"]
result = valve.valve_isolation_analysis("demo", "P-1")
result = valve.valve_isolation_analysis(links, "P-1")
assert result["isolatable"] is True
assert result["affected_node_count"] == 2
@@ -46,21 +23,14 @@ def test_isolatable_keeps_affected_node_ids_and_count(monkeypatch):
assert result["must_close_valves"] == ["V-close"]
def test_disabled_valve_expands_affected_area_before_counting(monkeypatch):
pipe_adj = defaultdict(set, {"A": {"B"}, "B": {"A"}})
topology = (
pipe_adj,
{
"V-disabled": ("B", "C"),
"V-close": ("C", "D"),
},
{"P-1": ("A", "B", "pipe")},
{"A", "B", "C", "D"},
)
monkeypatch.setattr(valve, "_get_network_topology", lambda _network: topology)
def test_disabled_valve_expands_affected_area_before_counting():
links = [
"P-1:pipe:A:B",
"V-disabled:valve:B:C",
"V-close:valve:C:D",
]
result = valve.valve_isolation_analysis(
"demo",
links,
"P-1",
disabled_valves=["V-disabled"],
)