Skip to content

Commit 2184c1d

Browse files
JuliaEdomclaude
andcommitted
test(control-plane): pin the capability-repository structure; record F-08 closure
A new capabilities test enforces the audit F-08 shape both ways: every port method must resolve inside a capability repository (never the assembly facade), and the embedded and PostgreSQL implementations of one method must live in same-named modules — the two adapters cannot drift apart silently. Plus the CHANGELOG entry for the split. Full gate on this host: SHARDED_SUITE=PASS 2436/2436 (peaks 739-934 MiB under the 1024 MiB guard), full-src mypy clean, ruff check/format clean, integration outbox 9/9, property 13/13. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
1 parent 5813a04 commit 2184c1d

2 files changed

Lines changed: 45 additions & 0 deletions

File tree

‎CHANGELOG.md‎

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,23 @@ All notable changes to AgentFlow are documented in this file.
44

55
## [Unreleased]
66

7+
### Refactor — control-plane adapters split into capability repositories (audit F-08)
8+
9+
The two control-plane monoliths (`embedded.py` 1,977 lines, `postgres.py`
10+
1,914 lines) are now bounded capability repositories — webhook, alert,
11+
outbox/replay, usage/audit over a shared base — with method bodies moved
12+
verbatim. `embedded.py` / `postgres.py` stay the assembly points and the
13+
only public import surfaces, so no consumer import changes; the tests'
14+
monkeypatch seams (`embedded.connect_duckdb`, `postgres.psycopg`, …) keep
15+
their pre-split homes. A new capabilities test pins the structure both
16+
ways: every port method must resolve inside a capability repository (never
17+
the facade), and the embedded and PostgreSQL implementations of one method
18+
must live in same-named modules, so the two adapters cannot silently
19+
drift apart. Path-pinned tooling (ruff S608 ignore, security-tooling S608
20+
count, the enqueue-lease static contract) moved with the code. Verified:
21+
full mypy over `src` clean, ruff check/format clean, the bounded Windows
22+
shard runner green across the unit suite.
23+
724
### Docs — project closure contract
825

926
- `docs/PROJECT_CLOSURE.md` freezes the engineering scope, maps the July

‎tests/unit/test_control_plane_capabilities.py‎

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,34 @@ def test_capabilities_cover_the_wide_facade_without_exposing_it_to_consumers() -
5151
)
5252

5353

54+
def _home_suffix(adapter: type, name: str, prefix: str) -> str:
55+
"""The capability-module suffix (``webhook``, ``alert``, ...) whose
56+
repository class defines ``name`` for this adapter family."""
57+
for klass in adapter.__mro__:
58+
if name in klass.__dict__:
59+
module = klass.__module__.rsplit(".", 1)[-1]
60+
assert module.startswith(prefix), (
61+
f"{adapter.__name__}.{name} resolves outside the {prefix}* "
62+
f"capability repositories: {module}"
63+
)
64+
return module.removeprefix(prefix)
65+
raise AssertionError(f"{adapter.__name__} does not define {name}")
66+
67+
68+
def test_capability_methods_live_in_matching_bounded_repositories() -> None:
69+
# Audit F-08: the two adapters must evolve in sync, and review/mutation
70+
# locality comes from each capability method living in its bounded
71+
# repository module. Every port method must resolve inside a capability
72+
# repository (never the assembly facade), and the embedded and PostgreSQL
73+
# implementations of one method must live in same-named modules.
74+
for name in sorted(ControlPlaneStore.__abstractmethods__):
75+
embedded_home = _home_suffix(EmbeddedControlPlaneStore, name, "embedded_")
76+
postgres_home = _home_suffix(PostgresControlPlaneStore, name, "postgres_")
77+
assert embedded_home == postgres_home, (
78+
f"{name} drifted: embedded_{embedded_home} vs postgres_{postgres_home}"
79+
)
80+
81+
5482
def test_app_repository_resolvers_return_narrow_views_of_same_store() -> None:
5583
store = SimpleNamespace()
5684
app = SimpleNamespace(state=SimpleNamespace(control_plane_store=store))

0 commit comments

Comments
 (0)