From 6334b36b215c73f892f60edbea4070299cf3901a Mon Sep 17 00:00:00 2001 From: rrrozhd Date: Wed, 5 Aug 2026 13:55:10 -0400 Subject: [PATCH] =?UTF-8?q?release:=20v0.15.1.0.1=20=E2=80=94=20classify?= =?UTF-8?q?=20the=20LangGraph=20gateway=20under=20the=20backend=20architec?= =?UTF-8?q?ture=20policy?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 12 ++ frontend/app/lib/version.test.ts | 2 +- frontend/app/lib/version.ts | 2 +- pyproject.toml | 2 +- src/zeroth/_architecture.py | 51 +++++++++ .../architecture/test_backend_dependencies.py | 107 +++++++++++++++++- tests/docs/test_release_metadata.py | 2 +- uv.lock | 2 +- 8 files changed, 174 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 49836caf5..ff5f1cc78 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,18 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 document the canonical eight-domain backend layout and LangGraph extras, and restore current platform concepts to the docs navigation. +## [0.15.1.0.1] - 2026-08-05 + +### Changed + +- Classify `zeroth.core.langgraph_gateway` under the backend architecture + policy through five legacy prefix mappings, so every module in the package + resolves to a domain instead of escaping the dependency scanner. +- Record the two forbidden edges the classification exposes as documented + temporary exceptions — the governance decision service's admission reuse and + the LangGraph integration client's enforcement reuse — with removal tracked + by the gateway relocation task. + ## [0.15.1] - 2026-08-05 ### Added diff --git a/frontend/app/lib/version.test.ts b/frontend/app/lib/version.test.ts index c450ffc02..02cfc8e59 100644 --- a/frontend/app/lib/version.test.ts +++ b/frontend/app/lib/version.test.ts @@ -4,6 +4,6 @@ import { VERSION } from "./version"; describe("console version", () => { it("matches the integrated Python package version", () => { - expect(VERSION).toBe("0.15.1"); + expect(VERSION).toBe("0.15.1.0.1"); }); }); diff --git a/frontend/app/lib/version.ts b/frontend/app/lib/version.ts index 3574454b4..7a4f7916d 100644 --- a/frontend/app/lib/version.ts +++ b/frontend/app/lib/version.ts @@ -1,2 +1,2 @@ // Generated from pyproject.toml; run `npm run gen:version`. -export const VERSION = "0.15.1"; +export const VERSION = "0.15.1.0.1"; diff --git a/pyproject.toml b/pyproject.toml index f8371a761..a6b2c3b2d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "zeroth-core" -version = "0.15.1" +version = "0.15.1.0.1" description = "Governed medium-code platform for production-grade multi-agent systems" readme = "README.md" requires-python = ">=3.12" diff --git a/src/zeroth/_architecture.py b/src/zeroth/_architecture.py index 8ac5f1da7..fec20dd17 100644 --- a/src/zeroth/_architecture.py +++ b/src/zeroth/_architecture.py @@ -55,6 +55,11 @@ "zeroth.core.guardrails": "governance", "zeroth.core.http": "integrations", "zeroth.core.identity": "governance", + "zeroth.core.langgraph_gateway": "service", + "zeroth.core.langgraph_gateway.models": "contracts", + "zeroth.core.langgraph_gateway.inventory": "contracts", + "zeroth.core.langgraph_gateway.capabilities": "governance", + "zeroth.core.langgraph_gateway.events": "governance", "zeroth.core.mappings": "contracts", "zeroth.core.memory": "integrations", "zeroth.core.observability": "platform", @@ -298,6 +303,52 @@ def _exception_group( "docs/backend-import-migration.md." ), ), + **_exception_group( + ("zeroth.governance.decisions.service", "zeroth.core.langgraph_gateway.admission"), + reason=( + "DecisionService reuses the admission orchestrator that ships inside " + "the service-classified langgraph_gateway package to evaluate " + "governance decisions against the same admission path the gateway " + "runs at request time, but governance may only depend on contracts " + "and platform." + ), + removal_task=( + "Task ZER-24 (gateway relocation, Phase B): relocation alone does " + "not clear this exception, because the adopted layout moves " + "admission.py to zeroth.service.langgraph_gateway, keeping it " + "service-owned. The exception is removable only once admission " + "grows a governance-importable seam in a domain governance may " + "depend on (contracts or platform), or governance gets its own " + "decision-admission surface, with " + "zeroth.governance.decisions.service redirected to that seam or " + "surface instead of importing the service-owned orchestrator." + ), + ), + **_exception_group( + ( + "zeroth.integrations.langgraph._gateway_client", + "zeroth.core.langgraph_gateway.enforcement", + ), + reason=( + "The LangGraph integration client reuses the enforcement evidence " + "and decision surface that ships inside the service-classified " + "langgraph_gateway package so the client and the gateway speak one " + "wire contract, but integrations may depend on contracts, econ, " + "governance, platform, and runtime, never on service." + ), + removal_task=( + "Task ZER-24 (gateway relocation, Phase B): enforcement.py " + "postdates the ZER-23 mapping table, so its canonical home is " + "explicitly a ZER-24 decision. Relocation alone does not clear this " + "exception, because moving enforcement.py to " + "zeroth.service.langgraph_gateway keeps it service-owned and leaves " + "the edge forbidden. The exception is removable only once " + "relocation assigns enforcement a canonical home in a domain " + "integrations may import, or extracts a contracts-level enforcement " + "surface, with zeroth.integrations.langgraph._gateway_client " + "redirected to that home or surface." + ), + ), **_exception_group( ("zeroth.econ.analytics.adapter", "zeroth.runtime.agents.provider"), ("zeroth.econ.analytics.opportunities", "zeroth.governance.audit.models"), diff --git a/tests/architecture/test_backend_dependencies.py b/tests/architecture/test_backend_dependencies.py index 7bb5ada48..9d670123b 100644 --- a/tests/architecture/test_backend_dependencies.py +++ b/tests/architecture/test_backend_dependencies.py @@ -7,7 +7,6 @@ import pytest - REPO_ROOT = Path(__file__).parents[2] SOURCE_ROOT = REPO_ROOT / "src" @@ -243,3 +242,109 @@ def test_real_repository_obeys_backend_dependency_direction() -> None: f"{item.path.relative_to(REPO_ROOT)}:{item.line}: {item.importer} imports {item.imported}" for item in scan.violations ) + + +def test_langgraph_gateway_modules_classify_into_the_expected_domains() -> None: + architecture = importlib.import_module("zeroth._architecture") + + assert { + module: architecture._canonical_domain(module) + for module in ( + "zeroth.core.langgraph_gateway", + "zeroth.core.langgraph_gateway.models", + "zeroth.core.langgraph_gateway.inventory", + "zeroth.core.langgraph_gateway.capabilities", + "zeroth.core.langgraph_gateway.events", + "zeroth.core.langgraph_gateway.admission", + "zeroth.core.langgraph_gateway.compatibility", + "zeroth.core.langgraph_gateway.context", + "zeroth.core.langgraph_gateway.enforcement", + "zeroth.core.langgraph_gateway.enforcement_store", + "zeroth.core.langgraph_gateway.headers", + "zeroth.core.langgraph_gateway.proxy", + "zeroth.core.langgraph_gateway.routes", + "zeroth.core.langgraph_gateway.transport", + ) + } == { + "zeroth.core.langgraph_gateway": "service", + "zeroth.core.langgraph_gateway.models": "contracts", + "zeroth.core.langgraph_gateway.inventory": "contracts", + "zeroth.core.langgraph_gateway.capabilities": "governance", + "zeroth.core.langgraph_gateway.events": "governance", + "zeroth.core.langgraph_gateway.admission": "service", + "zeroth.core.langgraph_gateway.compatibility": "service", + "zeroth.core.langgraph_gateway.context": "service", + "zeroth.core.langgraph_gateway.enforcement": "service", + "zeroth.core.langgraph_gateway.enforcement_store": "service", + "zeroth.core.langgraph_gateway.headers": "service", + "zeroth.core.langgraph_gateway.proxy": "service", + "zeroth.core.langgraph_gateway.routes": "service", + "zeroth.core.langgraph_gateway.transport": "service", + } + + +def test_legacy_domain_prefixes_pin_the_exact_gateway_mapping_set() -> None: + architecture = importlib.import_module("zeroth._architecture") + + gateway_prefixes = { + key: value + for key, value in architecture.LEGACY_DOMAIN_PREFIXES.items() + if key.startswith("zeroth.core.langgraph_gateway") + } + + assert gateway_prefixes == { + "zeroth.core.langgraph_gateway": "service", + "zeroth.core.langgraph_gateway.models": "contracts", + "zeroth.core.langgraph_gateway.inventory": "contracts", + "zeroth.core.langgraph_gateway.capabilities": "governance", + "zeroth.core.langgraph_gateway.events": "governance", + } + + +def test_every_langgraph_gateway_file_on_disk_classifies_to_a_domain() -> None: + architecture = importlib.import_module("zeroth._architecture") + gateway_root = SOURCE_ROOT / "zeroth" / "core" / "langgraph_gateway" + + for path in sorted(gateway_root.glob("*.py")): + module, _ = architecture._module_name(path, SOURCE_ROOT) + assert architecture._canonical_domain(module) is not None, module + + +def test_langgraph_gateway_scan_surfaces_exactly_the_forbidden_edges() -> None: + architecture = importlib.import_module("zeroth._architecture") + scan = architecture.scan_backend_dependencies(SOURCE_ROOT, exceptions={}) + gateway_edges = { + (item.importer, item.imported) + for item in scan.violations + if item.importer.startswith("zeroth.core.langgraph_gateway") + or item.imported.startswith("zeroth.core.langgraph_gateway") + } + + assert gateway_edges == { + ("zeroth.governance.decisions.service", "zeroth.core.langgraph_gateway.admission"), + ( + "zeroth.integrations.langgraph._gateway_client", + "zeroth.core.langgraph_gateway.enforcement", + ), + } + + +def test_langgraph_gateway_exceptions_are_the_only_gateway_entries_and_documented() -> None: + architecture = importlib.import_module("zeroth._architecture") + gateway_exceptions = { + edge + for edge in architecture.TEMPORARY_EXCEPTIONS + if "langgraph_gateway" in edge[0] + edge[1] + } + + assert gateway_exceptions == { + ("zeroth.governance.decisions.service", "zeroth.core.langgraph_gateway.admission"), + ( + "zeroth.integrations.langgraph._gateway_client", + "zeroth.core.langgraph_gateway.enforcement", + ), + } + for edge in sorted(gateway_exceptions): + exception = architecture.TEMPORARY_EXCEPTIONS[edge] + assert exception.reason.strip() + assert exception.removal_task.startswith("Task ") diff --git a/tests/docs/test_release_metadata.py b/tests/docs/test_release_metadata.py index 155f8995c..0c2c25dd9 100644 --- a/tests/docs/test_release_metadata.py +++ b/tests/docs/test_release_metadata.py @@ -7,7 +7,7 @@ REPO_ROOT = Path(__file__).resolve().parents[2] -EXPECTED_VERSION = "0.15.1" +EXPECTED_VERSION = "0.15.1.0.1" def test_project_version_matches_release() -> None: diff --git a/uv.lock b/uv.lock index 7e490d074..765154c3d 100644 --- a/uv.lock +++ b/uv.lock @@ -4044,7 +4044,7 @@ source = { directory = "packaging/console" } [[package]] name = "zeroth-core" -version = "0.15.1" +version = "0.15.1.0.1" source = { editable = "." } dependencies = [ { name = "aiosqlite" },