🎉 feat: 建立阶段 0 工程骨架与 OpenAPI 契约机器化(WP-01 起步)

- Makefile:统一命令入口(backend/engine/docker/openapi/generate,含 make help)
- backend:FastAPI + uv 最小工程,统一错误体(契约第 7 节)、ADR-015 平台 ID 生成与校验(uuid-utils);pytest 7 项、ruff、mypy strict、启动冒烟全部通过
- engine:灵台引擎 C++23/CMake 骨架,按 Lingtai C ABI 契约实现 lingtai.h(13 个 HjStatus、版本协商、句柄表防二次释放、线程局部错误上下文);doctest 5 用例通过,nm 验证仅导出 hj_* 符号
- openapi:OpenAPI 3.1 单一真源初始版(错误体/分页/Money/首批平台 ID/ContentBlock 全 21 类型/流事件 envelope),Redocly lint 0 错误、bundle 通过
- frontend:Next.js 最小骨架,openapi-typescript 生成 API 类型并通过 strict tsc
- docker:hunjing-postgres(pgvector:17)compose;.env.example 与 config 示例
- ADR-025:登记测试与契约工具链(doctest/libFuzzer/Redocly/openapi-typescript/uuid-utils)
- desktop:Tauri v2 占位与初始化说明(WP-10 启动)
This commit is contained in:
chenxin committed 2026-09-09 21:45:04 +08:00
1 parent 5da1efe921
commit 3fbcd0437c
32 files changed
+11459

No files matched your search

+27
View File
@@ -0,0 +1,27 @@
import pytest
from fastapi.testclient import TestClient
from app.main import create_app
@pytest.fixture()
def client() -> TestClient:
return TestClient(create_app())
def test_healthz_ok(client: TestClient) -> None:
resp = client.get("/healthz")
assert resp.status_code == 200
body = resp.json()
assert body["status"] == "ok"
assert "env" in body
def test_validation_error_uses_contract_envelope(client: TestClient) -> None:
# 触发路径参数/请求体校验失败,验证统一错误体结构
resp = client.post("/healthz", json={"unexpected": 1})
assert resp.status_code in (405, 422)
if resp.status_code == 422:
err = resp.json()["error"]
assert err["code"] == "validation_failed"
assert err["details"]["field_errors"]
+33
View File
@@ -0,0 +1,33 @@
import pytest
from app.core.ids import is_valid_id, new_id, parse_id
def test_new_id_prefix_and_version() -> None:
value = new_id("user_")
assert value.startswith("user_")
parsed = parse_id(value, "user_")
assert parsed.version == 7
def test_request_id_is_uuidv4() -> None:
value = new_id("request_", version=4)
assert parse_id(value, "request_", version=4).version == 4
def test_reject_wrong_prefix() -> None:
value = new_id("user_")
with pytest.raises(ValueError, match="前缀"):
parse_id(value, "run_")
def test_reject_wrong_version() -> None:
value = new_id("user_", version=4)
assert not is_valid_id(value, "user_")
with pytest.raises(ValueError, match="version"):
parse_id(value, "user_")
def test_reject_non_canonical_text() -> None:
with pytest.raises(ValueError):
parse_id("user_NOT-A-UUID", "user_")