docs(prompt-mgmt): 方案A 协同回写 + 补声明 structlog 依赖

- memory/contracts.md:立 C6-ext(load_prompt/SPECS/SCHEMA_CATALOG/
  REVIEW_RESERVED_NAMES/SpecResolver + 打包契约)+ 变更日志一笔
- memory/decisions.md:方案A 决策(运行时值金标准/尾换行方案B/守卫前移/
  schema 留 Python/同一实例)
- memory/gotchas.md:spec.name 连字符命名 / 改稿须重生成金标准 /
  .gitattributes 完整嵌套路径 / wheel artifacts 带 .md / structlog 补声明 /
  SpecResolver 零 DB + 精确匹配
- PROGRESS.md:已封板「Prompt 管理重构 + 全量重写」波次
- ARCHITECTURE.md §5.1:补 prompt 外置 + SPECS/SCHEMA_CATALOG/SpecResolver,
  内置 agent 计数 8→21
- packages/{llm_gateway,core}/pyproject.toml:补声明 structlog>=24.1
  (原直接 import 未声明,靠 apps/api 传递;裸装 import ww_agents 会缺)
This commit is contained in:
Yaojia Wang
2026-06-24 08:25:26 +02:00
parent eb356c42a9
commit 0021426f09
8 changed files with 48 additions and 2 deletions

View File

@@ -155,3 +155,9 @@
- 决策 2**多档分派网关 `build_chain_gateway`**):一条链 run 跨 writer(write)/analyst(review)/light(digest) 三档,但 `build_gateway_for_tier(tier)` 装出的网关 `chain_resolver` 恒返该单档链、忽略 `req.tier`——会把 review/digest 错路由到 writer。故链需一个**按请求 tier 分派**的网关union 三档所有 provider 适配器 + `chain_resolver``req.tier` 返回对应档链。digest 在 accept 节点自建短事务内按 session 现建 light 档网关(`get_digest_gateway_builder`)。
- 决策 3**accept_op 在 apps/api 装配**):链编排(图/节点)在 `ww_core`,但具体验收事务(`run_accept_transaction`/冲突 gate/digest 提炼/伏笔到期扫描)属 apps/api——经 `build_accept_op` 闭包注入图节点,守目录所有权 + 不变量 #3/#4。自动链无作者改稿,`final_text` = `chapters` 该章草稿正文write 节点所落)。
- 决策 4**新错误码 `CONFLICT`**resume 非 awaiting 态须 409但既有 409 码 `CONFLICT_UNRESOLVED` 语义专指「未决冲突禁验收」,不宜复用。新增通用 `ErrorCode.CONFLICT`→409资源状态冲突
## [2026-06-24] Prompt 外置方案A — @llm/@backend/@devops
- 背景21 个内置 agent 的 `system_prompt` 散文内联在 `specs.py` 的 Python 三引号常量里,改稿要碰 Python、diff 脏、加 agent 要改 4 处。设计真源 `docs/design/prompt-management.md`
- 选择:① 散文外置 `packages/agents/ww_agents/prompts/<spec.name>.md``system_prompt=load_prompt(name)` import 期读盘+内存缓存+确定性+fail-fast去 BOM `utf-8-sig`/LF 归一/NFC/`rstrip('\n')`**无运行期插值**——需插值的 prompt 不走此路径,属本波范围外);② **金标准 fixture 取 AST/运行时 `system_prompt` 值算 sha256**`tests/fixtures/prompt_hashes.json`**不取源码文本**——因旧常量含反斜杠折行,源码物理换行≠运行时换行;导出时 `.md` 物理换行≡运行时换行;③ 尾换行方案 B`.md` 允许 ≤1 尾 LFloader `rstrip` 不补回,文件层断言守「尾 LF≤1」与运行时金标准双层契约④ Pydantic 类型**永留 Python**`SCHEMA_CATALOG[name]` 是 name→output 唯一真相源(收敛为 `dict[name,type|None]`,去恒 None 的 input 槽YAGNI⑤ 内置 name`REVIEW_RESERVED_NAMES`=continuity/foreshadow/style/pace为保留命名空间守卫**前移至 SkillRegistry 入库校验**(非 resolver 读路径),用户 skill 同名→`VALIDATION`(安全边界,呼应不变量 #3);⑥ `*_spec` 兼容期保留且 `SPECS[name] is *_spec`(同一实例),编排器 + apps/api 3 路由本波不切 resolver。
- 理由 / 取舍:非工程改稿不碰 Python、缓存断点前块字节稳定不变量 #9);守卫前移让内置 `get` 纯内存零 DB、确定性、不把安全校验耦合进写章热路径。代价`git log -p specs.py` 追不到旧 prompt 演进(迁移 commit body 注明),后续改 prompt 须同步重生成金标准 fixture。
- 影响:加 agent = 写 `.md` + 注册 `SPECS`/`SCHEMA_CATALOG`wheel 必须 `force-include/artifacts``prompts/*.md`@devopsCI 冒烟守);`packages/{llm_gateway,core}` 补声明 `structlog`(原直接 import 未声明)。后续波次可将编排器/路由切 `SpecResolver` 后删 `*_spec`