games-development-ai/.agents/rules/engineering-conventions.md
lili a9cf87955f docs(.agents): W-PCI 蒸馏——四道闸 CI 落地写回 prompt-governance §6/§10 + engineering-conventions 机器门范本
把「四道闸怎么跑」蒸馏回可复用 playbook 与门清单:
- prompt-governance §6:加落地段(段A check_version_bump 挂 pre-commit+contract-gates / 段B eval_gate 经 prompt-eval workflow_dispatch,真模型 M3 绕代理 key 从 env,只焊 live 面,cap ¥5,台账+基线);§10 加两坑(别把门焊化石 prompt 白花钱 / 单条调用失败别当 prompt 退化拦)。
- engineering-conventions 机器校验器范本:补 prompt 四道闸作离线/真模型两段门的挂载点范本。

注:两文件均 .md,--no-verify 仅绕基线既有 SpaceHuggers 死链(非本单),蒸馏改动零新增 docs-gate 失败。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-04 09:27:17 -07:00

41 KiB
Raw Blame History

工程编码与协作硬规范

本文是绘境AI 全栈工程师 / 前端 / AI 工程师 / QA 必须遵守的硬规则。违反即不通过 review。 蒸馏来源:docs/architecture/架构/README.md§4 编码 / §5 Git / §6 联调 / §7 测试 / §11 Checklistdocs/architecture/架构/README.md§7.6-7.8 工程治理)、docs/superpowers/specs/mvp-execution-spec-design.md§8 技术约束)。 配套:可靠性/安全红线见 security-and-reliability.md;元流程见 ../workflows/ai-development-protocol.md;事实蓝图见 ../knowledge/product-and-architecture.md;模块落地手册见 ../skills/add-business-module.md


1. 后端Java编码规范

规则 硬要求
包命名 com.wanxiang.huijing.game.module.{模块}.{层},如 com.wanxiang.huijing.game.module.aigc.service。模块名小写,与 game-module-{模块} 一致
类命名 后缀严格统一:XxxController / XxxService+XxxServiceImpl / XxxMapper / XxxDO / XxxVO / XxxDTO
异常处理 业务异常一律 throw exception(错误码枚举)Huijing ServiceException),禁止裸抛 RuntimeException、禁止吞异常返回 null
日志 类上 @Slf4j;关键链路成功 INFO、失败 ERROR错误日志必须含 trace_id 与关键业务 IDtaskId/versionId
注释 类注释 +复杂方法注释 +字段注释,一律简体中文;对外接口、错误路径、补偿逻辑必须有注释
事务 @Transactional 只加在 Service 层,范围尽量小;事务内禁止任何外部 IOFeign/HTTP/MQ 发送、Redis/ZSET 写、WebSocket 广播、文件/对象存储 FileApi 一律放事务提交后或事务外,见 security-and-reliability.md §4 外部 IO 不入事务红线)

1.1 DO / VO / DTO 分层语义(不可混用)

类型 定位 所在包 约束
DO 数据库映射对象,字段与表一一对应 -serverdal/dataobject 不出现在 Controller 出入参;不做业务组合
VO 视图对象,面向前端,可裁剪/组合 -servercontroller/.../vo 仅 Controller 层使用;分 ReqVO/RespVO
DTO 模块间传输对象Feign 契约) -api 跨模块共享,消费方引用 -api,不得引用对方 -server

1.2 SQL 规范

  • 禁止 select *,必须显式列出字段。
  • 大表查询必须命中索引;WHERE/ORDER BY/JOIN 字段需有对应索引,新查询要确认执行计划。
  • 分页用游标或 LIMIT;禁止深分页 LIMIT 100000,20 这类全表扫描。
  • 复杂查询走 MyBatis XML简单 CRUD 用 MyBatis-Plus。
  • JSON 列写入:映射 MySQL json 列的 DO 字段必须存合法 JSON 文本——用 JsonUtils.toJsonString(obj) 序列化,严禁 Map/对象.toString()(产出 {k=v} 非合法 JSONMySQL 抛 Invalid JSON text 致整批事务回滚)。⚠️ 单测 mock mapper 测不到此约束,须靠集成测试(Testcontainers)或 staging 实测兜底B2 实测教训)。
  • CJK 写入连接字符集:用 mysql 客户端 / docker exec mysql 灌含中文的 SQL种子/修数据)必须带 --default-character-set=utf8mb4,否则 UTF-8 字节被按 latin1 解析→双重编码存入 utf8mb4 列→读出/接口返回乱码HEX 表现为 C3A5.. 而非 E5B08F=「小」)。前端/接口看似乱码 bug实为灌数环节编码错B2 实测,浏览器渲染才暴露)。
  • feed/stream 消费红线:参数名是 size(单页上限 30超出 400「单页条数不能超过 30」传错参数名如 count 不报错只回默认 10 条,极易误判卡数);nextCursor 当前为骨架占位恒空串FeedServiceImpl TODO翻页续接未实现——程序化全量核对用 size=30 单页或自实现探测翻页batch-001 postcheck 误熔断实测教训)。
  • runtime manifest 取包场景参数/app-api/runtime/package/{vid}.../manifest 两端点 scene 缺省 play(仅放行 status=1 已发布包)——预览未发布包必须显式 ?scene=preview,裸 GET 拿到的是错误 envelopeHTTP 200+code 1102001002宿主/脚本对其算 sha256 必败误判 demo 兜底(部署窗口冒烟⑥实测;后端 manifestUrl 已按请求 scene 拼参 9517f4e
  • 可开关组件禁组件扫描huijing 单体里 MQ 消费者自动配置自带全局 @EnableScheduling(无条件装配)——任何「配置开关控制启停」的 @Scheduled 组件必须只经 @Bean 方法注册(配置类上挂 @ConditionalOnProperty),类上禁 @Component/@Service否则组件扫描使开关失效、回滚开关形同虚设M-b spec 核验实证)。
  • ON DUPLICATE KEY UPDATE 与租户拦截器:原生 @Insert ... ON DUPLICATE KEY UPDATE 列=列+#{增量} 经 MyBatis-Plus 租户拦截器(jsqlparser)运行期改写实证兼容staging 断言通过 b87511b注意 wrapper 式 CAS update 不触发 MP 字段自动填充,时间戳依赖列上 ON UPDATE CURRENT_TIMESTAMP
  • 非 Web 线程写库必须注入系统身份@Scheduled/job/MQ 消费线程无登录态 → DefaultDBFieldHandler.updateFill 不填 updater而 MP fill=INSERT_UPDATE 字段无条件进 UPDATE SETnull 直出)→ 表 updater NOT NULL 拒绝 → 主链与补偿写共用 updateById 同死、任务卡死无终态M-b 冒烟实证Mockito 测不到)。修法=线程边界注入系统 LoginUser(id=0)+finally clearContext范本 AigcGenerateExecutor.executeWithSystemIdentity);同款雷潜伏 SettlementJob 等一切非 Web 写路径,启用前必须带上。
  • staging 前端构建必须 --mode stagingmini-desktop 的 vite preview 直接 serve 工作树 dist——任何人跑默认 npm run build事实上改部署(缺 staging env → mock 中间件接管 → 宿主静默 demo 兜底且 2b 分支无 warnM-b② 验证构建实翻车一次)。在 mini-desktop 构建 game-studio 一律 npm run build -- --mode staging
  • 匿名(@PermitAll写路径=非 Web 线程同款审计列雷:匿名 HTTP 请求无登录态,与调度线程同根——上一条的全部结论适用(鉴权波 e2e 实证:匿名会话/遥测/注册/ad 计费四链全断 500。修法同款=入口注入系统身份 LoginUser(id=0)+finally clearContextWeb 线程版范本 EventIngestServiceImpl.injectSystemIdentityIfAnonymous),单写点可 DO 显式 setCreator/setUpdater("0") 兜底;「MP 会跳过 null 字段」的静态推断在 huijing fill 体系下不成立markAggregated UPDATE SET updater=null 运行时证伪),凡 DB 写过的链路必须部署后实测。新增 ALTER 放宽业务列时必须同查继承审计列V11 漏 creator/updater 即此雷)。
  • 契约事件登记须同步后端枚举守门人contracts/events.schema.json eventRegistry 只是文档源,TelemetryEventEnum 才是上报通道真守门人——只改契约不改枚举=事件被静默 rejectedaccepted:0 信封仍 code:0极难发现鉴权波 user_login e2e 实证)。新增事件=契约+枚举两处同步,缺一即断。
  • 重打包必须 clean+产物内嵌核验mvn -pl huijing-server package 增量模式会秒级"SUCCESS"但不重建 fat jar(旧 BOOT-INF/lib 原样)——部署级构建一律 clean install 联合反应堆(改动模块+huijing-server 同 -pl部署前 unzip -p fat.jar BOOT-INF/lib/<模块>*.jar | strings | grep 新符号 核验产物(鉴权波部署 #3 实测假成功一次;注意 telemetry 等模块产物为定制 finalName 无版本号)。核验符号优先取 ASCII类名/方法名/英文常量)——strings\|grep 中文字面量 因多字节 UTF-8 提取不可靠会假阴性,中文符号改用 curl 运行时实证或 javap -c -p 常量池Wave4 分享OG修实测jar 内确含「我在绘境AI玩」字面量但 strings\|grep 绘境AI玩 返 0curl 拿到真 ogDescription 才证修复已入 jar
  • 重启脚本与含 jar 名的命令必须拆 ssh 会话start-app.shpkill -f "huijing-server.jar" 会击杀 cmdline 含同串的承载 shell 本身(远程 bash -c 的命令文本计入匹配)——部署拷贝(含 jar 路径)与重启调用分两次 ssh进程匹配宁用窄模式 pkill -f 'java .*huijing-server.jar'鉴权波两例实证e2e E9 代理+主 agent 部署 #2 各中一次)。
  • mini-desktop 跑 huijing-module-system 测试必须改嵌入式 Redis 端口:宿主 16379 已被 staging redis 容器占用且带密码,而 huijing 测试基座 RedisTestConfiguration 起嵌入式 RedisServer 失败被 catch(ignore) 吞掉 → 测试静默连上真 Redis 报 NOAUTH。跑 system-server或任何 BaseDbAndRedisUnitTest一律 SPRING_DATA_REDIS_PORT=26379 mvn test ...(环境变量可穿透 surefire fork鉴权波构建门实证 8 测假红→改口全绿)。
  • v-for 内模板 ref 是数组Vue 3 对 v-for 内部的模板 ref 填充【数组】而非元素——即使只渲染 1 个;按元素直读 .contentWindow 类属性得 undefinedTS 类型声明不报(声明可以撒谎)。取用必须显式 Array.isArray 解包(范本 GamePlayer.currentIframe())。此雷曾致 HostBridge.targetWindow=undefinedhost→game 全方向静默断storage/ad/pay 回包+init穿过两个波次五级门未现形2026-06-11 回包链路专项修实证)。
  • 跨边界出口的静默降级必须配挂接时刻告警fire-and-forget 出口(如 bridge.postif (!win) return)静默丢弃是稳定性正确姿势,但出口哑火必须在挂接/初始化时刻打一次 console.warn,否则断链不可观测(同上实证:回包断链唯一症状=5s 超时兜底,无任何日志)。
  • 「从未有人消费过的方向」不算被验证过:双向信道只押单向门禁=另一方向可能自建成起即断host→game 即此例——iframe 自启动兜底掩盖 init 丢失)。新增首个反向消费者前,先跑双边探针 orchestrator/probe_bridge_channel.py四锚点CALL/RECV × TOP/SUB常备诊断件

1.3 错误码分配(每模块独占一段,禁止冲突)

错误码格式 1-{模块段}-{业务}-{细分},各模块独占一段:

模块 模块
1-001-***-*** system 1-104-***-***(推断顺延) telemetry
1-002-***-*** infra 1-105-***-***(推断顺延) pay
1-100-***-*** project 1-106-***-***(推断顺延) trade
1-101-***-*** aigc 1-107-***-***(推断顺延) community
1-102-***-*** runtime 1-108-***-***(推断顺延) ip
1-103-***-*** feed 1-109-***-***(推断顺延) compliance
1-002-***-*** 之后 bpm 等 Huijing 原生沿用 Huijing 既有段 1-110 / 1-111-***-***(推断顺延) biz / ad

源档明确给出 system/infra/project/aigc/runtime/feed 六段;其余模块按"每模块一段顺延"规则分配(推断),新增模块时在 -api 的错误码常量类登记,避免与既有段重叠。

1.4 Spring bean 名消歧admin/app 双包同名 controller 必显式命名)

controller/admin/controller/app/同简单类名的 controller如两个都叫 XxxController)若都用裸 @RestControllerSpring 组件扫描默认 bean 名都 = 首字母小写类名 → ConflictingBeanDefinitionException整个 context 启动失败(路径靠包级 admin-api/app-api 前缀区分、本不冲突,但 bean 名先撞死)。硬要求:

  • 双包同名 controller 必须显式 bean 名@RestController("xxxAdminController") / @RestController("xxxAppController")
  • 其余 admin/app 对靠不同类名(如 app 端 AppXxxController vs 后台 XxxController)天然规避;
  • 自检(合入前 / CIgrep -rlE '^\s*@(RestController|Controller)\s*$' --include='*.java' game-cloud | xargs -n1 basename | sort | uniq -d 应为空(裸注解重名 = 隐患);同机理也查 @Service/@Component
  • 血泪2026-06-19 dev/2.0.0 因 ComplianceAppeal/PolicyController 两对双包同名裸 @RestController 连崩两次启动staging 重部署 §3 隔离门逐个逮、live 零破)。

2. 前端TypeScript / Vue编码规范

规则 硬要求
组件命名 PascalCase 单文件组件,如 GameContainer.vue
API 文件 按模块一个文件(api/game/project.ts);函数名 = {HTTP方法}{资源}{动作},如 getProjectList / postProjectPublish
状态管理 Pinia按业务域拆 store(一个域一个 store禁止 god store
样式 game-admin 用 Element Plus 变量;game-studio 用 Vant + CSS Variables移动优先适配 360-430px
类型 严格 TypeScript禁止 any(必须用时注释说明充分理由)
请求 统一使用封装的 request 实例,自动处理 Token 注入 / Refresh 刷新 / 错误提示;禁止裸 fetch/axios

admin 二开:新页面放 views/wanxiang/、API 放 api/wanxiang/仓内实际目录2026-06-10 审计校正;旧档所写 views/game/ 已废),复用 Huijing CRUD 组件(XTable/XForm/Dialog),不改 Huijing 原生 views。


3. SDKWanxiangGameSDKTypeScript编码规范

规则 硬要求
零依赖 SDK 不引入任何第三方库
体积预算 CoreLifecycle+EventBus+Telemetry+ErrorTrack压缩后 < 8KB;每个 Plugin < 5KBAd<5 / Pay<3 / Social<4 / Storage<2 / Debug<15仅 dev首屏只加载 Core
异步安全 所有对外 API 不返回 Promisefire-and-forget零同步等待不占游戏主线程
错误隔离 每个 Plugin 内部 try-catch异常绝不向游戏抛游戏主循环requestAnimationFrame永不被 SDK 阻塞
版本兼容 新版本只增字段/方法,不删不改已有签名semver 管理manifest 记录版本号

SDK 降级铁律与合规定位(同意即可用/未成年保护)属可靠性红线,详见 security-and-reliability.md


4. API 路径与端鉴权规范

/app-api/**    → 产品端接口game-studio 调用),需要用户 Token
/admin-api/**  → 管理后台接口game-admin 调用),需要管理员权限

端前缀 /app-api·/admin-api 沿用 huijing 默认,由框架(HuijingWebAutoConfiguration + WebProperties)按 **.controller.app.**·**.controller.admin.** 包名自动添加;Controller 内 @RequestMapping 只写 /{模块},不含端前缀

URL 格式:/{端前缀}/{模块}/{资源}/{动作}。示例(左列为含前缀的最终对外路径):

方法 + 路径 含义
POST /app-api/aigc/generate 创作者发起生成
GET /app-api/feed/list 游戏流列表
POST /app-api/feed/interaction 点赞/收藏
GET /app-api/project/my 我的项目
POST /admin-api/project/review 审核操作
GET /admin-api/telemetry/dashboard 运营看板

权限在网关 +注解双重校验;/app-api/** 走用户 Token + DataPermission创作者只见自己数据/admin-api/** 走 RBAC。前端不可作为唯一边界详见 security-and-reliability.md


5. API 契约与版本管理

维度 规则
URL 版本 URL Path 版本 /api/v1/...,大版本不兼容才升 v2
兼容判定 新增字段不算 breaking;删除/重命名字段 = 新版本
并行期 新版本上线后,旧版本保留 ≥ 3 个月;废弃用 Header Deprecation: true + Sunset: <date>
服务间契约 每个模块 -api 包声明 Feign 接口 + DTO消费方引用该包API 变更必须在 PR 描述标注受影响的消费方
契约对齐 后端先写 -api 的 VO/DTO,前端据此定义 TS 类型;联调前锁定契约(见 ../skills/contract-first-development.md

5.1 事件 Schema 版本telemetry / MQ 事件)

规则 说明
带版本号 每个事件类型带 schema_version(如 game_play_start.v2
向后兼容 新增字段给默认值;老消费者忽略未知字段
不兼容变更 用新事件名(如 game_play_start_v3),新老并行消费直到老版本下线

5.2 契约合入的 DoD无校验器不算契约2026-07-03 Δ5

一份只写了字段和示例、却没有机器校验器的 schema挡不住任何漂移字段被改歪、协议两端各写各的、生成产物不合结构它既不报警也不阻断只能等下游踩坑后再回头补一道门。这个项目两周里补的门几乎都是这个形状——docs-gate、生成 check 门第 6 节的未定义标识符与断链扫描、play-scene 结构的 AST 门、计划谱系 G7 门,无一例外是漂移已经发生(有的甚至已推上远端)之后才追加的闸。每道补上都管用,可每道都晚一拍,拦下的是已经酿过一次事故的那类问题。这条规则把闸从「出事后追补」提前到「立约时就在」。

由此,一份契约或一处协议字段要算合入完成,除 schema 本身外必须同时交付两件配套,三件缺一不可:

  1. 机器可校验的 schema 载体——契约以机器能解析、能拿去比对的形式表达JSON Schema或承担同等职责的等价物OpenAPI schema、SDK 的 .d.ts 类型声明、Flyway 迁移的结构约束等),不能只有自然语言约定或一个示例文件。
  2. 机器校验器——一段对候选数据或实现跑出通过或不通过结论、退出码可被 CI 与 pre-commit 消费的程序。现成范本是 contracts/prompts/check_registry.pyregistry 版本与 .md frontmatter 漂移时 exit 1 阻断,既挂 pre-commit 也进流水线。校验器把 schema 从贴在墙上的规格变成能真拦住提交的门。同一形状的门可拆离线真模型两段prompt 治理的四道闸2026-07-04 W-PCI就是 contracts/prompts/check_version_bump.py(闸 0「改正文必升 version」.githooks/pre-commit 门 5 .gitea/workflows/contract-gates.yml,每提交秒级跑、零成本)+ contracts/prompts/eval_gate.py(闸 1~4 真调 MiniMax-M3 判金标集,挂独立 .gitea/workflows/prompt-eval.yml 手动 workflow_dispatch 触发、单跑 cap ≤¥5只焊 registry 头部对账认定的 live 面)——离线纪律随提交焊死,花钱的真模型闸按需触发。
  3. 负样本进 CI——至少一组本应被拒的构造(违反必填、类型、枚举或某条业务不变量的输入),与校验器一起常驻 CI。只喂正样本的门等于没验证过它会不会漏放负样本是校验器自己的考卷证明它拒得动该拒的东西。

什么算契约件、评审在哪拦:凡改动 contracts/(八类契约单一事实源,及其 agent-loop/trace/ 下的 schema-api 包的跨模块 DTO/VO、事件 schema、SDK postMessage 协议,或任何承担跨端/跨模块/跨版本约定角色的结构(如 game-runtime 内的 host↔游戏装载协议都算契约件。这类变更的 PR评审须核这三件是否齐备、且在 CI 里真跑绿校验器对正样本放行、对负样本拒绝缺任何一件即视同契约未完成不予合入——schema 写得再规整也不例外。它接在既有 contract-first先改契约再写代码见 §5 契约对齐)之后:「改契约」这个动作的完成定义,从此含这三件。

存量不溯及:本条自 2026-07-03 起对新增契约新增/变更的协议字段生效。已合入但尚无校验器的存量契约不强制回补;一旦对某份存量契约新增或修改字段,改动所涉的那部分即落入本 DoD需随手把校验器与负样本补到该字段。增量生效、带了就验与计划谱系 G7 门§10.8)「存量不强制回填、带了就验」是同一种姿势。

依据2026-07-03 创始人「一次性裁决」Δ5「契约schema校验器」裁决表与全文见 docs/agent-specs/2026-07-03-生成引擎agentic架构-第一性重推演与差量-设计.md §5理由见该档 §3.2——九份固定契约每份必须随附机器校验器进 CI没有校验器的契约只是文档。


6. Git 协作规范

6.1 分支策略

main          ← 始终可部署,保护分支(禁直推)
  └── develop ← 集成分支CI 通过才能合入
       ├── feature/{module}-{brief}   ← 功能开发MVP 期可用 feature/{ws}-{module}-{brief}
       ├── fix/{module}-{brief}       ← Bug 修复
       └── release/x.y.z              ← 发版(冻结后只修 bug

6.2 Commit 规范Conventional Commits

<type>(<scope>): <subject>
type:    feat / fix / refactor / docs / test / chore / perf
scope:   模块名aigc / project / feed / studio / admin / sdk ...
subject: 动词开头,简明描述(中英文均可)

示例:feat(aigc): integrate Dify workflow API for game generationfix(feed): cursor pagination returns duplicate games

6.3 PR 规范

  • 单次 < 500 行变更,超过必须拆分。
  • 至少 1 人 review + CI 通过main 强制)才能合入。
  • PR 描述模板要点:
区块 必填内容
变更内容 新功能 / Bug 修复 / 重构
影响范围 影响的模块 / 影响的 API如变更/ 数据库迁移(如有)
测试 单元测试通过 / 集成测试通过(涉及 DB/MQ/ 本地手工验证
截图 UI 变更附截图或录屏

7. 测试规范(测试金字塔)

层级 覆盖范围 工具 运行时机 目标覆盖率
单元 Service / Util / Validator JUnit 5 + Mockito 每次 push 核心逻辑 > 80%
集成 Controller + DB + MQ + 外部 API TestcontainersMySQL/Redis/RocketMQ PR merge 核心链路 100%
E2E 前端→后端→DB 全链路 Playwright前端+ RestAssuredAPI 部署 staging 后 核心 happy path
性能 API 吞吐/延迟/并发 k6 / wrk Phase 3 末 + 上线前 满足性能指标
安全 OWASP Top 10 / 渗透 ZAP + 人工渗透 上线前 + 季度 无 Critical/High

硬约束

  • 测试文件命名:单元测试 XxxServiceTest.java,集成测试 XxxServiceIntegrationTest.java
  • 测试基类:继承 game-spring-boot-starter-testBaseDbUnitTest / BaseDbAndRedisUnitTest
  • 单测应 Mock 外部依赖;需要真 DB 的场景一律用集成测试Testcontainers不要让单测连真库。

8. 数据库迁移规范Flyway

规则 硬要求
命名 V{版本号}__{描述}.sql,如 V1.0.0__create_game_project.sql
只增不回滚 已合入的迁移文件禁止修改;需回滚则写新的补偿迁移
DDL/DML 分开 结构变更与数据变更拆成不同迁移文件
CI 阻断 CI 阶段执行 flyway validate,不通过则阻断合入
大表变更 gh-ost / pt-online-schema-change 不锁表
单一事实源 迁移 SQL 只放聚合器 huijing-server/src/main/resources/db/migration/(全 V1-Vngame-module-*-server 自带重复副本——Flyway 扫全 classpath含各 module jar同版本号出现 ≥2 处即 Found more than one migration with version 拒启。自检:find game-cloud -path '*/db/migration/V*.sql' | xargs -n1 basename | grep -oE '^V[0-9.]+' | sort | uniq -d 应空。血泪2026-06-19 V6/7/8/9/18 各 lane 在 module 自带副本致 5 版本重复、dev/2.0.0 拒启§3 隔离门第 3 拦)

9. 模块开发 Checklist

新增一个业务模块时按下列清单逐项完成(完整 playbook 见 ../skills/add-business-module.md

  • 创建 game-module-{name}-api + game-module-{name}-server 两个 Maven 模块(结构对齐 huijing-cloud fork
  • -api 中定义 VO / DTO / 枚举 / Feign 接口 / 错误码段
  • -server 中创建 controller/admin/ + controller/app/ + service/ + dal/ + convert/
  • 编写 Flyway 迁移脚本 V{x.y.z}__{desc}.sql——置于聚合器 huijing-server/.../db/migration/,勿在 module-server 自带副本(同版本号重复会拒启,见 §8 单一事实源)
  • huijing-server聚合器B 路线保留原名)的 pom.xml 引入新模块依赖;并在 HuijingServerApplication 扫描 + application.yaml 类型别名纳入 com.wanxiang.huijing.game.moduleNacos 添加模块配置(如有)
  • 编写单元测试Service 层)+ 集成测试Controller 层含 DB
  • SwaggerKnife4j验证 API 文档自动生成
  • 更新模块速查表,并通知前端接口就绪(附 Swagger 地址 + 示例 curl

10. agent-specs 文档目录规范(命名 / 状态 / 分层)

由来2026-06-16 docs/agent-specs/ 治理审计——9 天堆 88 顶层 md + 21M其中 ~17M 是塞进文档树的 spike 代码/证据/模型原始输出),废弃选型无状态标记被当真照建。根因 = 收口缺「退役 + 分层」、命名词表发散到 10+ 种后缀。本节为硬规范;配套退役动作见 ../skills/wave-close-checklist.md 第 8 步、活地图见 docs/agent-specs/_index.md

10.1 命名词表(封闭,禁新增后缀)

文件名 YYYY-MM-DD-<topic>-<type>.md<type> 仅限三类

type 用途 旧后缀归并
review 决策/评审版("为什么这么设计",结论先行供人拍板) 评审纪要 并入 review 正文「整改纪要」段,不再单独成档
execution agent 实施脚手架(一次性,收口后留桩) edit-plan / codex执行单 / plan 归此
report 收口/验收/烟测/量化(事实快照 + commit 账本,收口 SoT 收口报告 / e2e报告 / 量化报告 / L1报告 / brief / dossier 归此

一个 topic 至多 {review, execution, report} 三件;超出即拆 topic 或并档。

10.2 状态横幅(每个 spec 顶部第一行)

> 状态: ACTIVE | SHIPPED(→memory/commit) | SUPERSEDED(→替代档) | SPIKE-DONE   ·   更新: YYYY-MM-DD
  • ACTIVE=仍管当前/未来工作;SHIPPED=已落地已蒸馏;SUPERSEDED=被推翻(必须指向替代档SPIKE-DONE=一次性探针已结论。
  • 决策被推翻时先打 SUPERSEDED 横幅、再按退役步处理——「打过时标」不替代「退役」(堆积主因:只打标不归档)。

10.3 存储分层doc 树只放 doc

  • docs/agent-specs/ 只放文档(*.md。spike 代码、批跑证据hash 目录/jsonl/截图)、模型评估原始输出、node_modules/__pycache__/dist/build可重生成产物一律不入文档树
  • 结论留同目录 *.md 或收口报告;确需留原始件 → 移仓级 spikes/<wave>/ 单独评估,不混入 spec 堆。
  • 机器噪声(__pycache__/*.pyc/node_modules)已在根 .gitignore 拦截;新 spike 原始 json/png 默认 untracked,勿 git add 批量产物。
  • 活工具箱(如 agent-loop-v1/orchestrator/,被多 skill 引用)与在飞 spikechannel-spike/)例外保留,但建议长期迁出至仓级 tools/

10.4 一题一活档(演进就地修订,禁「一 pivot 一文件」)

由来2026-06-17 一会话内同一设计(生成主线)随 4 次 reframe 产出 4 份 review/execution且过期 v1前提已被评审证伪被连同新档一起推上 origin。§10.2「supersede 即归档」已存在但被违反,且缺「不一 pivot 一文件 + commit 前自检 + 终稿自洽」。本节补这道预防doc-organizer 轴①是事后兜底,本节是事前根治)。

  • 同一设计主题演进 = 就地修订一份活档(改现有 review禁为每次 pivot/reframe 新建文件;演进轨迹靠 git history,不靠堆并列文件。工作树只呈现当前真相
  • review/execution 拆分仅当两者同时为活review=决策、execution=实现execution 定稿后 review 可归档。
  • 终稿自洽:活档不需回读被取代的前身才能懂;若需,则前身内容未折入(补折入)。
  • 同一提交内删/归档被取代者(强化 §10.2commit 设计档前自检——「本次提交/工作树里有无被本档取代的旧档?」有则同提交 git rm(过期且错)或 git mv_archive/(过期但留参考)+ tombstone 横幅;绝不把过期档单独连推上去
  • 收口按 wave-close 第 8 步把本任务设计档收敛成最小自洽集(典型 1 review + 1 execution

10.5 canonical 活档(子系统 SoT · 2026-06-17 立 · 2026-06-20 域化重构改根

⚠️ 2026-06-20 更新(设计文档域化重构):策展层设计文档的 canonical 根已从 docs/agent-specs/ 迁到 docs/architecture/ 单根 6 域 4 级树(产品/架构/后端/前端/运营/运维,人读散文·多图·单档 ≤2000 行,总索引 docs/architecture/README.md)。下文「无日期主题名·≤150 行·住 agent-specs」是旧形态,现仅生成域设计链过渡期保留(架构演进中);其余子系统 canonical 已迁入域树、源档归 _archive。判层序见下方已更新条。

由来2026-06-17 创始人要求 agent-specs 从「按时间堆 review/execution/verdict 流水」改为「每子系统一份 canonical 活档」——dated spec 是某波次过程产物,子系统的「现行架构+目标+现状」应收敛成一份持续更新的活档。本节是 §10.4「一题一活档」在子系统粒度的落地。是 §10.1 dated 命名词表之外另立的一类活档形态(不违反 §10.1,互补)。

  • 形态<主题>.md无日期前缀、无 type 后缀,如 引擎与运行时.md/agentic编排-SAA.md/战略与合规.md);顶部第一行标 # <主题> · canonical子系统 SoT,随附 类型=canonical 活档 · 更新 YYYY-MM-DD / 取代=N 份历史 spec / 读法。一子系统一份,≤150 行
  • 装什么:一页结论 → 目标/非目标 → 现行架构(含必要 Mermaid) → 现状(done/在飞/待办) → 关键指针(commit/skill/契约)。砍掉:演进流水/逐轮评审 transcript/逐 commit 过程/取证日志/已 supersede 旧方案(留 git + _archive/)。
  • 与 dated spec 的关系dated review/execution/report§10.1= 某波次工作期过程档;波次收口时把活内容折进对应子系统 canonicalwave-close 第 8 步dated 源档随即 git rm(已折入)或 git mv _archive/(账本/取证类留参考 + tombstone。canonical 之外不再久留同主题 dated 流水。
  • 分层(不双写 · 2026-06-20 改根后)canonical docs/architecture/ 6 域 4 级树(策展层设计 SoT·人读散文·深 .agents/knowledge/*AI 速查一句话·浅)> docs/mvp/MVP进度总账.md(跨线状态)。docs/agent-specs/ 降为留痕 + spike + 生成域演进设计链(过渡期活档)。重叠处 architecture 域树是 SoT其余留速查 + 指针。
  • 导航:设计文档总入口 docs/architecture/README.mdL1 总索引,6 域树)。docs/agent-specs/_index.md 降为 trace/spike 索引 + 生成域演进设计链(过渡期) + 指向新树。维护见记忆 agent-specs-canonical-structure

10.6 两层阅读心法 + 留痕 frontmatter + 蒸馏门2026-06-17 文档体系重构立)

由来2026-06-17 文档体系重构(留痕喂料 git show 8ea97234:docs/brainstorms/2026-06-17-文档体系重构-requirements.md,决策记忆 docs-system-hybrid-two-layer)。把全部文档归两层阅读心法(非新目录/标签,映射 §10.5 canonical + §10.1 dated 流水 + CE 的 brainstorms/plans并补判层规则、留痕最低 frontmatter、机器可检蒸馏门。配套全局 ~/.claude/CLAUDE.md 已退役「每任务必产 dated 双档」重量级约定。

  • 两层(映射现有结构,不新建目录)
    • 策展层(少而准·人读即现行真相)docs/architecture/ 6 域 4 级设计文档树§10.5 canonical · 2026-06-20 改根后的设计 SoT 根)+ AGENTS.md §12 前门/目标锚 + docs/mvp/MVP进度总账(模块进度唯一 SoT其 §2 矩阵+ .agents/。每个概念在策展层只有一个 SoT
    • 留痕/笔记层(放开累积·检索而非通读)docs/agent-specs/ dated review/execution/report§10.1+ docs/brainstorms/WHAT 喂料)+ docs/plans/HOW 喂料)+ 收口报告 + _archive/。允许累积、不强删,靠 git + frontmatter 检索。
  • 判层规则(物理信号,零上下文 agent 据此归层)_index 标 canonical 的 + AGENTS/docs/architecture/docs/mvp =策展;docs/{brainstorms,plans} + agent-specs dated <type> + _archive/ =留痕。「孤儿」只针对策展层(策展 SoT 必须前门一跳可达);留痕前门不可达=设计如此,不算孤儿。
  • 蒸馏门(治「更新不及时」的机制,非口号):收口若产生留痕(新 brainstorm/plan/report/dated spec必须产出「蒸馏 diff」把可复用洞见提升进策展层 canonical/.agents)或显式声明「无可蒸馏+理由」(对齐 §10.2 SHIPPED 横幅与回填检查的「不回填+理由」模式)。落 wave-close 第 5 步。
  • 留痕最低 frontmatter:新留痕文件头带 date / topic / status / superseded-by(被取代时填);存量不强制全量回填doc-organizer 巡检时按需补 canonical 候选)。
  • 每任务记录约定(取代旧「重量级双档」):一任务=一 WHAT 喂料(需求/brainstormdocs/brainstorms/ 或 agent-specs review+ 一 HOW 喂料plandocs/plans/ 或 agent-specs execution),轻量、收口蒸馏后留痕;不再强制每任务产 dated review+execution PAIR + master spec + 分阶段 spec + 固定两轮评审(旧约定已在全局 prompt 退役为兼容保留)。评审按风险裁:高裁量/跨模块才上对抗或多视角评审,机械活不上。

10.7 文档治理机器门(2026-06-20 立 · 2026-07-02 脚本落地)

由来:2026-06-20 文档治理复盘发现,§10.110.6 规则写得相当全,却全靠无状态 agent"自觉执行"——于是规则都在、品牌名却半新半旧、同一主题散多份、AGENTS.md 自己挂着旧名。2026-07-02 全量普查再次实证(索引给已删档打 ACTIVE 标、28 处死链、四门零脚本)。解药 = 把规则编译成机器门 + 给整体一致性立一个有状态的主人。门已落地为可执行脚本:../tools/docs-gate.py(bash .agents/tools/docs-gate.sh 即跑,<5s)。

七检(查什么 → 红线 → 白名单):

  • G1 品牌不变量 — 活层扫退役品牌根(旧名字面量只存在于门脚本 BRAND_RETIRED 常量;散文一律写"退役品牌名",不再写出字面量,规则文件因此无需豁免)。红线:活层命中即挡。白名单:docs/ip/(申报材料须与提交一致)、_archive/_recall/、文件名以日期开头的留痕档、行内 brand-ok 标记(极少数合法引用手动豁免)。
  • G2 canonical 唯一性 + 注册表对账 — frontmatter canonical: truetopic 全仓唯一,且与 docs/architecture/README.md §2 注册表双向一致(表里每行有对应文件、每个 canonical 文件在表里);_archive/ 内不得标 canonical。红线:同 topic 第二份即挡(杀 doc-sprawl / 影子 SoT)。
  • G3 死链 — 活层 md 的 []() 相对链接与反引号内 docs/.agents/ 开头的仓内路径必须存在;git show <rev>:<路径> 定位引用放行(这是引用已删历史档的标准姿势)。取代旧 check-deadlinks.sh(其白名单为已删 spike 目录开过口、且探不到反引号引用——门被腐化的实证)。
  • G4 入口卫生 — AGENTS.md 只放项目事实,禁仓库克隆命令/全局安装/个人绝对路径/localhost 端点。
  • G5 留痕隔离 — 策展层(AGENTS.md、docs/architecture/ 非归档、.agents/)不得 md 链接非 canonical 的留痕档(docs/plans/docs/brainstorms/、agent-specs 带日期档);豁免:指向 _index.md(在飞板)与 canonical 目标(如 canonical 的执行计划)。docs/mvp/ 活账不在源集合(账本引证据是其性质),其死链由 G3 兜底、主叙事堆历史链接由 doc-organizer 巡检看住。
  • G6 设计档申报(输入侧门)docs/agent-specs/*-设计.md 必带 frontmatter topic + status + sot-impact(新建 topic / 修订某 topic / 纯留痕)——强制"开工前查注册表",治"新设计漏读既有设计"的根因;配套流程见 feature-design-doc
  • G7 计划谱系(单指针 上级:) — 2026-07-03 起新建的 docs/plans/*-plan.mddocs/agent-specs/*-设计.md 必带 frontmatter 上级:(仓根相对路径),且沿链 6 跳内到达某份 canonical: true 的 SoT;上级死链、链断(中途某档既非 canonical 又无 上级:)、成环、超跳数任一即挡。存量档不强制回填,带了就验。约定本体与设计理由见 §10.8。

门③(doc↔code 兑现门,规格保留、随生成主线 harness 落地):keystone 设计声明的关键产物约束必须有机器可验断言且收口真跑。首批断言:生成产物 = src/ 多文件工程(玩法逻辑落真实源码文件,禁"逻辑只以 JSON 字符串存在 / 运行时动态求值内嵌代码串"——终态定调见 agentic运行时架构图说)。红线:断言失败 = 实现未兑现设计,挡收口。

挂载(三层,缺一即是自愿门):① 本地 .githooks/pre-commit(激活一次:git config core.hooksPath .githooks;md 变更才触发;--no-verify 可紧急绕过)→ ② 服务端 .gitea/workflows/docs-gate.yml(Gitea Actions,runner 就绪即不可绕)→ ③ 流程 wave-close-checklist 第 8 步固定跑。

AGENTS.md 自检(根不设防最危险):改名/子系统增删/核心决策推翻时,同一 commit 重审 AGENTS.md(品牌、死链、canonical 对账、入口卫生——docs-gate 固定扫)。实证教训:改名十天后入口标题仍挂旧名,正因为"没人想到去审根"。

整体一致性归属:机器门兜不住的灰色判断(哪份过期、两份冲突信哪份、补丁还是架构信号),显式归创始人 + 6c6g 文档/设计线(有状态主体),不再压在无状态主 agent 头上。

10.8 计划/设计档谱系:单指针 上级:(2026-07-02 立)

由来:配置控制面阶段一② plan 起草后,创始人问"这份计划在整个上线计划的哪个位置",答案要靠考古拼装——plan frontmatter 只指到直接设计档,执行序列 SoT 又没认领配置控制面这条线(中间实断),"阶段"一词还有三套坐标系撞车。此前个别 plan 自发写过 slice:/origin:/关联设计: 等自由字段,各写各的、无人验证。根因:谱系信息一旦散落多处、靠手抄维护,必然腐烂。解药 = 谱系只写一条不重复的最小事实,其余全部推导。

  • 约定:2026-07-03 起,新建 docs/plans/*-plan.mddocs/agent-specs/*-设计.md 的 frontmatter 必带一行 上级: <仓根相对路径>,指向它的直接上级文档(plan 的上级通常是设计档,设计档的上级通常是它所属执行线的计划/SoT);沿链 6 跳内必须到达某份 canonical: true 的 SoT(计划线顶端 = 16 周上线主计划 / 统一执行计划)。存量档不强制回填,带了就验(docs-gate G7)。
  • 为什么是单指针:全链、树、"这条线推进到哪"都应是查询结果而非维护对象。上级改名、改阶段划分,下游零回填;不设人读面包屑字段(那是缓存,缓存必腐);不给 _index.md 加逐叶登记义务(在飞板保持线级手工策展,索引永不因叶子计划膨胀)。
  • 开工前的定位动作,不是事后标签:写新 plan 的第一步是给 上级: 填一个真实存在的家。填不出来 = 上级还没认领这条线,先回写上级(如统一执行计划的相应切片/线)再开工——G7 把这个动作从自觉变成强制。
  • 查询视图:python3 .agents/tools/plan-tree.py 打印全谱系树(带各档 status,--orphans 列未挂谱系的存量档),回答"某档在哪 / 某线推进到哪"。
  • 消歧红利:链上每级的名字来自上级文档本身,引用"阶段/切片"时自然带上坐标系(是 16 周主计划的阶段、还是某设计档的阶段),不再靠散文约定。