feat(toolbox): F1 拆书 teardown 落库成项目 rules

- teardown_spec.writes=["rules"](只声明 tier,入库仍经白名单 gate,不变量 #3)
- toolbox_registry teardown entry 加 ingest=IngestSpec(table="rules")
- routers/toolbox.py 通用 ingest dispatcher 加 _ingest_rules:
  BookTeardownResult(themes/archetypes/structure/hooks) 拍平为可读 rules 条目,
  落项目级(无 continuity 预检,仿 _ingest_outline 无 409)
- schemas/toolbox.py 加 TeardownIngestView + ToolIngestRequest.teardown
- 单测:teardown ingest→rules 真落行 + 预览(generate)不写库

后端门禁绿:ruff/format/mypy clean · alembic no drift · pytest 644 passed
This commit is contained in:
Yaojia Wang
2026-06-23 20:00:25 +02:00
parent 44642c37b4
commit 61398a1452
8 changed files with 216 additions and 17 deletions

View File

@@ -1,7 +1,8 @@
"""Scope B 竞品快赢 · 4 个生成器的 spec/schema 契约测试。
校验每个 spec 的 name/tier/reads/writes/output_schema/scope/input_schema
对齐不变量 #2只声明 tier/ #34 生成器一律纯预览 writes=[])。不联网、无 DB
对齐不变量 #2只声明 tier/ #3续写/扩写/降AI 纯预览 writes=[];拆书 F1 落库 rules
不联网、无 DB。
"""
from __future__ import annotations
@@ -19,17 +20,25 @@ from ww_agents import (
teardown_spec,
)
# (spec, name, tier, reads, output_schema)
# (spec, name, tier, reads, writes, output_schema)
_COMPETITOR_SPECS = [
(continue_spec, "continue", "writer", ["projects", "outline", "chapters"], ContinuationResult),
(expand_spec, "expand", "writer", ["projects"], PolishResult),
(de_ai_spec, "de-ai", "analyst", ["projects"], DeAiResult),
(teardown_spec, "teardown", "analyst", ["projects"], BookTeardownResult),
(
continue_spec,
"continue",
"writer",
["projects", "outline", "chapters"],
[],
ContinuationResult,
),
(expand_spec, "expand", "writer", ["projects"], [], PolishResult),
(de_ai_spec, "de-ai", "analyst", ["projects"], [], DeAiResult),
# F1拆书结论可落库为项目 ruleswrites=["rules"];其余三者仍纯预览)。
(teardown_spec, "teardown", "analyst", ["projects"], ["rules"], BookTeardownResult),
]
@pytest.mark.parametrize(
("spec", "name", "tier", "reads", "output_schema"),
("spec", "name", "tier", "reads", "writes", "output_schema"),
_COMPETITOR_SPECS,
)
def test_competitor_spec_declares_expected_contract(
@@ -37,12 +46,13 @@ def test_competitor_spec_declares_expected_contract(
name: str,
tier: str,
reads: list[str],
writes: list[str],
output_schema: type,
) -> None:
assert spec.name == name
assert spec.tier == tier
assert spec.reads == reads
assert spec.writes == [] # 不变量 #34 生成器一律纯预览
assert spec.writes == writes # 不变量 #3续写/扩写/降AI 纯预览;拆书落 rules
assert spec.output_schema is output_schema
assert spec.scope == "builtin"
assert spec.input_schema is None # 注入材料为序列化文本,非结构化入参