项目文件夹

文件
Ali Khokhar d428b5904a Replace historical architecture tests with declarative boundaries (#1050)
## Problem

Architecture contracts mixed real dependency rules with deleted-module
tombstones and exact internal file inventories. Correct refactors
therefore had to preserve history instead of the current ownership
model.

## Changes

| Before | After |
| --- | --- |
| Cross-package rules were duplicated across narrow source and layout
assertions. | One least-privilege matrix and AST scanner enforce every
production package edge. |
| Bare imports, undeclared ownership roots, and module cycles could
escape generic enforcement. | Namespaced imports, initialized owners,
exact exceptions, and an acyclic module graph are enforced. |
| Responses, messaging-tree, and optional dependency ownership relied on
scattered checks. | Facade use and lazy optional dependency owners are
declared and verified centrally. |
| The messaging facade re-exported workflow, persistence, and parsing
internals. | The messaging facade exposes only ingress values, platform
ports, and managed-session protocols. |
| Migration-era tests froze deleted modules and internal filenames. |
Customer contracts remain while obsolete tombstones and layout
inventories are removed. |

<!-- greptile_comment -->

<details open><summary><h3>Greptile Summary</h3></summary>

This PR replaces historical architecture checks with declarative
import-boundary rules. The main changes are:

- Added a documented package dependency matrix and facade ownership
rules.
- Narrowed the messaging package facade to its supported extension
surface.
- Moved messaging tree consumers to the `messaging.trees` facade.
- Reworked architecture tests around AST scanning, optional dependency
owners, and acyclic imports.
- Bumped the package version and refreshed the lockfile.
</details>

<h3>Confidence Score: 5/5</h3>

This looks safe to merge.

No blocking issues found in the changed code.

<details><summary><h3><a href="https://www.greptile.com/trex"><img
alt="T-Rex"
src="https://greptile-static-assets.s3.amazonaws.com/trex/trex_green.svg"
height="20" align="absmiddle"></a> T-Rex Logs</h3></summary>

**What T-Rex did**
- The architecture contracts tests were executed as part of the general
contract validation.
- The test run completed with exit code 0, indicating success.
- The pytest summary shows 26 tests passed in 3.99 seconds.
- An artifact log captures the exact command, working directory,
environment recreation output, and verbose test item names for audit.

<a
href="https://app.greptile.com/trex/runs/14085499/artifacts"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://greptile-static-assets.s3.amazonaws.com/badges/ViewAllArtifactsDark.svg?v=4"><source
media="(prefers-color-scheme: light)"
srcset="https://greptile-static-assets.s3.amazonaws.com/badges/ViewAllArtifacts.svg?v=4"><img
alt="View all artifacts"
src="https://greptile-static-assets.s3.amazonaws.com/badges/ViewAllArtifacts.svg?v=4"></picture></a>

<sub><a href="https://www.greptile.com/trex"><img alt="T-Rex"
src="https://greptile-static-assets.s3.amazonaws.com/trex/trex_green.svg"
height="14" align="absmiddle"></a> Ran code and verified through
T-Rex</sub>
</details>

<details open><summary><h3>Important Files Changed</h3></summary>

| Filename | Overview |
|----------|----------|
| src/free_claude_code/messaging/__init__.py | Narrows the top-level
messaging exports to the documented supported extension types. |
| tests/contracts/test_import_boundaries.py | Replaces historical layout
checks with declarative import-boundary enforcement. |
| ARCHITECTURE.md | Documents the current dependency matrix, facade
boundaries, and optional dependency owners. |
| src/free_claude_code/messaging/node_event_pipeline.py | Uses the
messaging tree facade for `NodeClaim`. |
| src/free_claude_code/messaging/node_runner.py | Uses the messaging
tree facade for queue, snapshot, cancellation, and claim types. |

</details>

<sub>Reviews (2): Last reviewed commit: ["Enforce architecture with
declarative
im..."](https://github.com/alishahryar1/free-claude-code/commit/68508f3d2bad19d4d1b8a9ca5d181e1433db4d71)
| [Re-trigger
Greptile](https://app.greptile.com/api/retrigger?id=43498975)</sub>

<!-- /greptile_comment -->
2026-07-11 03:25:01 -07:00

65 行
2.1 KiB
Python

import re
import tomllib
from pathlib import Path
from urllib.parse import unquote, urlsplit
def test_architecture_document_exists() -> None:
repo_root = Path(__file__).resolve().parents[2]
assert (repo_root / "ARCHITECTURE.md").is_file()
def test_architecture_document_relative_links_resolve() -> None:
repo_root = Path(__file__).resolve().parents[2]
architecture = repo_root / "ARCHITECTURE.md"
text = architecture.read_text(encoding="utf-8")
missing: list[str] = []
for match in re.finditer(r"(?<!!)\[[^\]]+\]\(([^)]+)\)", text):
raw_target = match.group(1).strip()
target = raw_target.split("#", 1)[0]
if not target or urlsplit(target).scheme:
continue
if not (repo_root / unquote(target)).exists():
missing.append(raw_target)
assert missing == []
def test_root_env_example_is_the_single_template_source() -> None:
repo_root = Path(__file__).resolve().parents[2]
root_example = repo_root / ".env.example"
duplicate_example = (
repo_root / "src" / "free_claude_code" / "config" / "env.example"
)
assert root_example.is_file()
assert not duplicate_example.exists()
def test_root_env_example_is_packaged_for_config_template_loader() -> None:
repo_root = Path(__file__).resolve().parents[2]
pyproject = tomllib.loads((repo_root / "pyproject.toml").read_text("utf-8"))
force_include = pyproject["tool"]["hatch"]["build"]["targets"]["wheel"][
"force-include"
]
assert force_include[".env.example"] == "free_claude_code/config/env.example"
def test_pyproject_first_party_packages_match_packaged_roots() -> None:
repo_root = Path(__file__).resolve().parents[2]
pyproject = (repo_root / "pyproject.toml").read_text(encoding="utf-8")
match = re.search(r"known-first-party = \[(?P<items>[^\]]+)\]", pyproject)
assert match is not None
configured = {
item.strip().strip('"')
for item in match.group("items").split(",")
if item.strip()
}
expected = {"free_claude_code", "smoke"}
assert configured == expected