docs: 技术栈与工程约束写入 AGENTS.md,交付形态定为 pip 包

- 新增 AGENTS.md:技术栈选型、五条架构决策、硬规则、目录、命令、测试策略
- 明确不提供独立 HTTP 服务:核心包禁止 fastapi,路由由宿主 include_router 挂载
- README 同步:集成方式改为纯库/挂路由/嵌入式三种,FastAPI 列为 [api] 可选依赖
- 非目标补充“不做独立服务”
This commit is contained in:
Donny committed 2026-11-05 01:58:19 +08:00
1 parent be472a70ea
commit 33eb5d54f1
2 files changed
+154 -14

No files matched your search

+116
View File
@@ -0,0 +1,116 @@
# adapter_python_pg 项目指令
基于 ontology(本体)数据基座的 **Python 中间层适配器**。用 YAML 定义实体、关系、属性、动作、规则,由本适配器驱动 PostgreSQL 完成读写与图查询,对上暴露实体/对象级的语义接口。
**这是一份给 AI 编码工具(Claude Code / Codex / Hermes / OpenCode)的项目约定**,优先级高于 README 的描述性内容;与本文冲突的实现一律视为错误。
---
## 1. 使用形态(硬规则)
| 项 | 约定 |
|---|---|
| 交付物 | **pip 包**,被已有的 FastAPI 项目 `include_router` 引用 |
| 不做的事 | **不提供独立 HTTP 服务**,不带 `uvicorn` 启动入口,不假设自己是独立进程 |
| FastAPI 位置 | 只出现在 `adapter_python_pg/api/`,是 **optional extra**;核心包禁止 import fastapi |
| 宿主感知边界 | 宿主看不到 SQL / Cypher,只拿到实体对象与语义方法 |
| 契约来源 | 本体 YAML 是唯一事实来源;**只加载 YAML 即可工作**,不做代码生成、不要求手写 DDL |
宿主项目的典型用法:
```python
from fastapi import FastAPI
from adapter_python_pg import Adapter, build_router
adapter = Adapter.load("ontology/factory-twin.yaml", dsn=settings.pg_dsn)
app = FastAPI()
app.include_router(build_router(adapter), prefix="/ontology")
```
## 2. 技术栈
| 层 | 选型 | 约束 |
|---|---|---|
| 语言 | Python **3.11+** | 与 `pricing-service`、`data-mould` 对齐 |
| 包管理 | **uv**(`uv.lock` 入库) | 不用手工 venv + pip |
| 构建 | hatchling | `src/` 布局,带 `py.typed` |
| 驱动 | **psycopg 3**(async + `psycopg_pool`) | 不用 asyncpg、不用任何 ORM |
| 图 | **`age`**(AGE 官方 psycopg3 驱动) | `AgeLoader` 处理 agtype,不手写解析 |
| 对象 | **pydantic v2** + `create_model()` | 运行期按本体动态建类 |
| 本体校验 | pydantic 模型 + 导出 JSON Schema | 本体先自查,schema 供其他语言消费 |
| 表达式 | **SQL 下推** + **CEL**(`cel-python`) | 不自研表达式解析器,不 `eval` |
| 批量写 | `COPY` 协议 | 时序吞吐量级差异 |
| API | FastAPI `add_api_route()` 动态注册 | 泛化 OpenAPI,不做 codegen |
| 测试 | pytest + pytest-asyncio + testcontainers | 集成测试连真库 |
| 质量 | ruff(line-length 100, py311)+ mypy | 配置写在 `pyproject.toml` |
依赖分层:`[project.dependencies]` 只放核心(psycopg / age / pydantic / pyyaml / cel-python);fastapi 放 `[project.optional-dependencies].api`。
## 3. 目录结构
```text
src/adapter_python_pg/
├── ontology/ YAML 解析与校验(pydantic spec:entities/links/actions/functions/rules/constraints)
├── compiler/ 本体 → 存储映射:幂等 DDL、索引推导、版本记录
├── storage/ psycopg 连接池、事务边界、动态 SQL 构建(标识符管控)
├── repository/ 实体读写、批量、部分更新、约束校验
├── graph/ AGE 封装:建图、建边、遍历、路径 —— 转义与白名单集中在这里
├── timeseries/ hypertable 读写、COPY 批量、聚合查询
├── expr/ 表达式双轨:SQL 下推编译 + CEL 求值
├── rules/ 派生链接(传递闭包)、派生属性、计算属性
├── api/ FastAPI router 工厂(optional)
└── errors.py 统一错误模型
```
## 4. 架构决策(已拍板,勿反复)
1. **异步优先 + 同步门面**:内部全 async;对同步调用方提供 `SyncAdapter` 薄包装,不复制实现。
2. **多本体并存**:文档落在 `docs.collection = "{ontology}.{entity}"`;每个本体一个 AGE graph;多本体之间不做跨本体 JOIN。
3. **先全 JSONB**:属性一律存 JSONB,`column: true`(属性提升为真实列)在 spec 里**预留字段但不实现**,等性能有真实压力再开。
4. **FastAPI 路由动态生成**:`entity` 作为路径参数,OpenAPI 是泛化 schema;**不做**逐实体 typed routes、不导出 OpenAPI 代码。
5. **发布方式**:先支持 `pip install git+ssh://git@gitlab.cnsjzn.com/donnyzhang/adapter_python_pg.git`;GitLab PyPI registry 后续再接。
## 5. 硬规则(违反即回退)
- **核心包禁止 `import fastapi` / `import uvicorn`**。跑 `python -c "import adapter_python_pg"` 不应拉起任何 web 依赖。
- **Cypher 禁止字符串拼接值**。所有进入 `cypher()` 的标识符走白名单、值走转义函数,集中在 `graph/`,并配独立的注入用例矩阵。
- **实体与图必须同事务**。一个实体既有 JSONB 行又有图节点,写入在一个事务内完成;禁止 repository 与 graph 各自 commit 造成半实体。
- **禁止 `eval` / `exec` / `importlib` 执行 YAML 内容**。表达式只允许两条路:编译成 SQL 下推,或交给 CEL 求值。
- **DDL 必须幂等**(`IF NOT EXISTS`);本体演进只做加法,破坏性变更不做自动迁移。
- **默认不建索引**。只有 `index: true` / `unique: true` 才建;GIN 不是默认项。
- **公共接口必须完整类型标注**;动态 pydantic 模型只出现在数据边界,不穿透内部函数签名。
- **不用 `print`**,用标准库 `logging`(库不配置 handler,由宿主决定)。
- **测试不得写真实业务库**;集成测试用 testcontainers 起的临时实例。
## 6. 常用命令
```bash
uv sync --extra api # 安装(含 FastAPI 可选依赖)
uv sync # 只装核心,验证"无 web 依赖"边界
uv run pytest # 全部测试
uv run pytest -m "not integration" # 只跑不连库的单元测试
uv run ruff check . && uv run ruff format --check .
uv run mypy src
```
## 7. 测试约定
| 层 | 做法 |
|---|---|
| 本体解析 / 编译 | 纯单元测试,断言生成的 SQL 字符串与索引清单 |
| 仓储 / 图 / 时序 | 集成测试,testcontainers 起 `pg-multimodel:pg18-age-timescale` |
| 注入防护 | 专门的用例矩阵:非法标识符、引号、`$$`、注释符、Unicode 绕过 |
| 回归 | 每个 bug 先写失败用例(RED),再修(GREEN) |
集成测试镜像默认复用本机已构建的 `pg-multimodel:pg18-age-timescale`;CI 里改为拉 registry 里的预构建镜像,避免每次重新编译 AGE。
## 8. 与其他仓库的关系
| 仓库 | 关系 |
|---|---|
| `E:\code\ueos\devops\devos\server-resources\postgres-multimodel` | 底层多模型 PostgreSQL 的 Dockerfile / compose / 初始化脚本 |
| `ueos/backend` 的 `ontology` 模块(Java) | 概念同源(Action / Function / Query / 编排);**不共享代码**,接口语义对齐即可 |
## 9. 当前状态
v0.1 设计阶段:README 与本文已定契约,代码未开始。落地顺序见 README「路线」:本体解析 → 文档读写 → 图 → 时序 → 推理 → FastAPI 路由 → Actions。