chore(aps): B0.1 APS 独立工具链与包骨架(uv + ruff + pytest,CI 分流)

This commit is contained in:
zh 2026-09-30 12:32:52 +08:00
parent 4939313eb8
commit 698df32a06
13 changed files with 2383 additions and 6 deletions

View File

@ -50,14 +50,15 @@ jobs:
echo "found=false" >> "$GITHUB_OUTPUT"
echo "aps/ 下暂无 Python 代码,跳过(B1 落地后自动启用)"
fi
- uses: actions/setup-python@v5
- uses: astral-sh/setup-uv@v5
if: steps.detect.outputs.found == 'true'
with:
python-version: '3.11'
enable-cache: true
- name: 安装 APS 工具链(按 uv.lock)
if: steps.detect.outputs.found == 'true'
run: uv sync --locked --directory aps
- name: APS 检查(ruff + pytest)
if: steps.detect.outputs.found == 'true'
run: |
python -m pip install --upgrade pip
pip install ruff pytest
ruff check aps
pytest aps -q
uv run --no-sync --directory aps ruff check .
uv run --no-sync --directory aps pytest -q

1
.gitignore vendored
View File

@ -27,6 +27,7 @@ server/data/
# ---- Python(APS 侧搬迁适配时使用)----
__pycache__/
.ruff_cache/
*.py[cod]
.venv/
venv/

View File

@ -6,6 +6,27 @@
APS 现在还在 `main` 分支里与平台混装(`server/aps_domain` 39,212 行、`server/engines` 7,551 行、`server/state`、`server/importers`,以及早期原型 `aps-frontend/`)。B0–B7 负责把它拆到这里并补齐独立运行所需的能力。
B0.1 已完成:`src/aps/` 子包骨架、`pyproject.toml`、`uv.lock` 与独立 CI job 就位;平台侧的 lint / typecheck / test 与 APS 的 ruff / pytest 互不阻塞。
## 工具链(B0.1)
| 项 | 值 |
| --- | --- |
| Python | 3.11+ |
| 依赖与锁定 | `uv`;`uv.lock` 入库,CI 用 `uv sync --locked` |
| 代码检查 | `ruff`(配置在 `pyproject.toml`) |
| 测试 | `pytest`(`tests/`) |
| 包结构 | `src/aps/`,子包对应 B 线的搬迁目标 |
```bash
cd aps
uv sync # 建 .venv 并按 uv.lock 安装(含 dev 依赖)
uv run ruff check .
uv run pytest -q
```
依赖取舍:依赖清单以 `main` 分支的 `requirements.txt` 为准,按 B 线边界做了两处增删——**去掉** LLM 与对话智能体相关依赖(D12:APS 不内置对话智能体),**保留**求解引擎(ortools / scipy)、文档与图纸解析(openpyxl / pdfplumber / python-docx / lxml / ezdxf)与持久层(sqlalchemy / alembic / pymysql)——它们都归 APS。
## 边界规则
| 规则 | 说明 |

54
aps/pyproject.toml Normal file
View File

@ -0,0 +1,54 @@
[project]
name = "aps"
version = "0.1.0"
description = "APS:独立的高级排产业务系统。开发期与平台同仓不同目录(ADR-0010),工具链与依赖独立。"
requires-python = ">=3.11"
dependencies = [
# 接口层(B5:契约化 API)
"fastapi>=0.115",
"uvicorn[standard]>=0.30",
"pydantic>=2.7",
"python-multipart>=0.0.9",
"httpx>=0.27",
# 求解引擎(B1 搬入 server/engines)
"ortools>=9.10",
"scipy>=1.14",
# 导入与文档解析(B1 搬入 server/importers;图纸解析归 APS)
"openpyxl>=3.1",
"pdfplumber>=0.11",
"python-docx>=1.1",
"lxml>=5.0",
"ezdxf>=1.4",
"fonttools>=4.50",
# 持久层:APS 库归 APS(ADR-0008),独立账号、独立 database
"sqlalchemy>=2.0",
"alembic>=1.13",
"pymysql>=1.1",
# APS 自己的审计归档加密(B4)
"cryptography>=42",
"python-dotenv>=1.0",
]
# 开发依赖用 uv 的 dependency-group(uv sync 默认安装,CI 用 --locked 保证一致)
[dependency-groups]
dev = ["ruff>=0.7", "pytest>=8.3", "pytest-asyncio>=0.24"]
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
[tool.hatch.build.targets.wheel]
packages = ["src/aps"]
[tool.ruff]
line-length = 120
target-version = "py311"
src = ["src", "tests"]
[tool.ruff.lint]
select = ["E", "F", "W", "I", "UP", "B", "SIM"]
[tool.pytest.ini_options]
testpaths = ["tests"]
asyncio_mode = "auto"
addopts = "-q"

18
aps/src/aps/__init__.py Normal file
View File

@ -0,0 +1,18 @@
"""APS:独立的高级排产业务系统。
开发期与本仓库的平台代码同仓不同目录(ADR-0010),但按独立系统对待:
自己的工具链(Python / uv)、自己的库、自己的 CI job、自己的界面。
包内布局对应 B 线的搬迁顺序:
| 子包 | 内容 | 来源(main 分支) | 任务 |
| --- | --- | --- | --- |
| ``domain`` | 业务主体:排产、主数据、订单、柔性、闭环运行时 | ``server/aps_domain`` | B1–B3 |
| ``engines`` | 求解引擎:CP-SAT / GA / NSGA2 / 池 / 规则 | ``server/engines`` | B1 |
| ``state`` | 世界状态、检查点、分支、数据包 | ``server/state`` | B1 |
| ``importers`` | Excel / SQL / MOM 导入与 profile | ``server/importers`` | B1 |
| ``governance`` | APS 自己的动作分级、确认与审计 | 新写(可借鉴旧权力矩阵与链式哈希) | B4 |
| ``api`` | 对平台的契约化接口层(capabilityId + schema) | 新写 | B5 |
"""
__version__ = "0.1.0"

View File

@ -0,0 +1 @@
"""契约化接口层(B5):按能力语义暴露 HTTP API,schema 与平台 provider-sdk 对齐。"""

View File

@ -0,0 +1 @@
"""业务主体(B1–B3):从 main 的 ``server/aps_domain`` 迁入,去掉对平台 agent_core 的反向引用。"""

View File

@ -0,0 +1 @@
"""求解引擎(B1):CP-SAT / GA / NSGA2 / 池 / 规则,以及求解进程隔离。"""

View File

@ -0,0 +1 @@
"""APS 自带的治理(B4):动作分级与确认、只追加的审计链。"""

View File

@ -0,0 +1 @@
"""导入(B1):Excel / SQL / MOM 导入与 profile 机制。"""

View File

@ -0,0 +1 @@
"""世界状态(B1):状态、检查点、分支、数据包。"""

35
aps/tests/test_package.py Normal file
View File

@ -0,0 +1,35 @@
"""B0.1 冒烟:工具链与包结构可用(不测业务逻辑,业务逻辑随 B1 迁移进来)。"""
import subprocess
import sys
import pytest
def test_package_imports() -> None:
import aps
assert aps.__version__ == "0.1.0"
@pytest.mark.parametrize("name", ["api", "domain", "engines", "state", "importers", "governance"])
def test_subpackages_import(name: str) -> None:
"""每个子包都对应 B 线的一个搬迁目标,导入不了说明结构被改坏了。"""
module = __import__(f"aps.{name}", fromlist=[name])
assert module.__doc__, f"aps.{name} 缺少说明它负责什么的 docstring"
def test_platform_code_is_not_imported() -> None:
"""APS 不依赖平台代码:aps 包内不得出现对平台模块的引用(ADR-0010)。"""
result = subprocess.run(
[
sys.executable,
"-c",
"import aps, aps.api, aps.domain, aps.engines, aps.state, aps.importers, aps.governance",
],
capture_output=True,
text=True,
)
assert result.returncode == 0, result.stderr

2241
aps/uv.lock Normal file

File diff suppressed because it is too large Load Diff