@ultime/codecraft 0.0.0-stage → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,310 @@
1
+ # 代码宪法 v0(语言无关)
2
+
3
+ > 2026-10-26 · v0 草稿,等确认后固化为 v1。
4
+ > 用途:给人和 AI 的共同约束;语言无关,具体语法见《代码族卡 v0》。
5
+ > 读者:团队 / AI(Design Specification)。
6
+ > 术语:English(中文)。
7
+
8
+ ## 0. 第一性
9
+
10
+ **可预测性(Predictability)**:同一类东西长得一样;同一类改动只动一处;错误看得见;文档不会撒谎。
11
+
12
+ 规范面向未来,不迁就历史;历史只提供反例与来源。
13
+
14
+ > 不是统一所有代码,而是「同族同形 + 可验证 + 防漂移」。
15
+ >
16
+ > 完整在底层,取舍在上层:规范覆盖大型项目的能力,默认只启用小项目需要的那部分;能力有档位,项目按需启用。
17
+
18
+ ## 1. 五条元判据
19
+
20
+ | ID | 元判据 | 一句话 |
21
+ |---|---|---|
22
+ | M1 | 缺席检验(Deletion Test) | 删掉它,哪一层会塌?说不出就删。 |
23
+ | M2 | 单一来源(Single Source) | 一个事实、一份正文、一个入口。 |
24
+ | M3 | 结构与值分离(Structure vs Value) | 骨架恒常、值可变;契约恒常、实现可变。 |
25
+ | M4 | 变化局部化(Locality of Change) | 改一个需求最多动一族;动两族以上说明边界错了。 |
26
+ | M5 | 可验证性(Verifiability) | 能算、能 diff、能 lint、能测,才算契约。 |
27
+
28
+ ## 2. 二十一条不变量
29
+
30
+ | ID | 不变量 | 为什么 | 验收 |
31
+ |---|---|---|---|
32
+ | A1 | 同族同形(Same Family, Same Shape) | 降低认知负担;AI 可预测 | 每个代码族只有一种模板 |
33
+ | A2 | 依赖向内(Dependencies Point Inward) | 核心可脱离框架测试 | core 不 import 框架 / UI / 传输 |
34
+ | A3 | 传输透明(Transport Transparency) | 后端可能不按规范;特殊 code 要定制 | 传输层不解释业务 code |
35
+ | A4 | 单一收口(Single Funnel) | 改一处全局生效 | 401 / 提示 / 配色 / 分类 / 分页各一处 |
36
+ | A5 | 状态穷尽(Exhaustive States) | 非法状态不可表示 | 联合类型 + `assertNever` + `satisfies` |
37
+ | A6 | 预期失败是值(Expected Failure as Value) | 错误必须被处理 | Result / 域变体;空 catch 为零 |
38
+ | A7 | 表优于分支(Tables over Branches) | 加 case 只加一行 | 可枚举变化用表 |
39
+ | A8 | 派生不存储(Derive, Don't Store) | 避免不同步 | 派生状态用 selector / computed |
40
+ | A9 | 注释消歧义(Comments Disambiguate) | 注释会漂移 | 只写意图 / 契约 / 边界 / 反例 / 警告 |
41
+ | A10 | 例外登记(Exceptions Registered) | 例外会变成第二套规则 | 理由 + 主人 + 到期;安全红线不可豁免 |
42
+ | A11 | 生成物只读(Generated Code Is Read-Only) | 手改会漂移 | 标「勿手改」;CI 比对;生成文档可重建 / 校验 |
43
+ | A12 | 复制登记(Copy Registered) | 复制是分发,不是标准 | 母版名 / 版本 / 分叉点 / 升级路径 |
44
+ | A13 | 可定位性(Locatability) | 抽象不能让人找不到源头 | 每加一层都能一眼定位 |
45
+ | A14 | 按需求付工程费(Pay for Engineering by Need) | 过度设计也是债 | L0→L1→L2,有触发条件 |
46
+ | A15 | AI 输出契约(AI Output Contract) | 多模型 / 多 agent 会漂移 | 说明改了什么 / 为什么 / 怎么验 / 风险 |
47
+ | A16 | 命名即导航(Naming as Navigation) | 前缀 / 后缀标层、防重名、可搜索;组合时读出骨架 | 同族一种前缀;搜索可见 |
48
+ | A17 | 内外分离(Inside/Outside Separation) | 前端规范只管内部;外部契约在包装层转换 | 内部不 import 外部类型 |
49
+ | A18 | 预案完整,默认最小(Full Plan, Minimal Default) | 规范覆盖大项目能力,默认只启用小项目所需 | 有档位;默认 L0;按触发升级 |
50
+ | A19 | 实现自由,边界固定(Implementation Free, Boundary Fixed) | 模块内部形式自由;public contract 固定;可替换 | 入参/出参/错误/副作用边界一致;有契约测试 |
51
+ | A20 | 记录环节,不记录实现(Record the Stage, Not the Implementation) | 只记录需要什么功能 / 环节、职责与契约;实现可自研 / 第三方 / 暂时没有 | 环节可消失;不把库当架构层 |
52
+ | A21 | 文档安全边界(Document Security Boundaries) | 外部文档不引内部;git 不存密钥;内部文档不外发 | 分级 + 扫描 + 交付白名单;不可豁免 |
53
+
54
+ ## 3. 决策程序
55
+
56
+ | 问题 | 判据 | 默认 |
57
+ |---|---|---|
58
+ | 模块内部组织(Module Internal Organization) | 只约束边界与 public contract;函数组合 / 声明式 / OOP / 闭包 / 状态机 / 管道 / actor 都可;按状态复杂度、生命周期、性能 / 体积、可测试性选 | 组合函数 |
59
+ | map vs switch | 值是表 → map;动作同签名 → 函数表;不同签名 / 局部 2–3 分支 → switch | 先看签名 |
60
+ | 抽象 vs 重复 | 同一性 / 第三次出现 / 第三个消费者 → 抽象;文本相同但语义无关 → 重复 | 先重复 |
61
+ | 分层 vs 平铺 | 按「什么一起变」;职责单一、依赖单向即可 | 平铺优先 |
62
+ | 框架 vs 原生 | 框架移除的复杂度 > 引入的复杂度 | 原生 / 最小功率 |
63
+ | 同步 vs 异步 | 只有 IO / 等待才异步;异步 UI 用状态机 | 同步 |
64
+
65
+ ### 3.1 命名设计(Naming Design)
66
+
67
+ > 历史做法 ≠ 规范。`api_` / `Model` 是验证过可用的旧约定;新代码按下面的推荐设计,旧项目保留方言,不强制迁移。
68
+
69
+ **命名四问**
70
+
71
+ 1. 命名空间是否已经给出上下文?(模块 / 目录 / import)→ 是则不重复前缀。
72
+ 2. 是否在扁平 / 全局命名空间?(CSS 类、easycom、旧 API 模块)→ 是则加前缀。
73
+ 3. 类型是否已由 TS 表达?→ 是则不加类型后缀(`IUser` / `UserModel`)。
74
+ 4. 是否需要跨仓库搜索?→ 是则加领域前缀(`api_` / `Doc`)。
75
+
76
+ **推荐(新代码) vs 历史(旧项目)**
77
+
78
+ | 场景 | 推荐(新代码) | 历史(可保留,不强制迁移) |
79
+ |---|---|---|
80
+ | 传输 | `api/<domain>/<action>.ts` + `fetchXxx` / `getXxx` | `api_xxx` 前缀 |
81
+ | 行为适配器 | `useXxx` | 同左 |
82
+ | 行为核心 | `xxxCore` / `xxxBehavior` | `services/*`(Vue2) |
83
+ | 内部实体 | `User` | `UserModel` |
84
+ | 内部查询 | `UserQuery` | `UserSearchModel` |
85
+ | 内部输入 | `UserInput` | `UserSetModel` |
86
+ | 内部视图模型 | `UserView` | 无 |
87
+ | 外部类型(后端 / 第三方) | 只存在于 `external/` 或 Wrapper(包装层);不参与内部命名 | 生成物原名 |
88
+ | UI 原语 | `app-` | 同左 |
89
+ | 页面类 | `page-*` | 同左 |
90
+ | 表 | `statusMap` / `apiMap` | 同左 |
91
+
92
+ **动词表**
93
+
94
+ | 动词 | 用途 |
95
+ |---|---|
96
+ | `get` | 同步 / 本地读取 |
97
+ | `fetch` | 异步 / 远程读取 |
98
+ | `set` | 写入 / 设置 |
99
+ | `update` | 局部更新 |
100
+ | `create` | 新建 |
101
+ | `build` | 组装 |
102
+ | `resolve` | 补默认 / 归一 |
103
+ | `parse` | 外部输入 → 领域类型 |
104
+ | `validate` | 校验(只报问题) |
105
+ | `assert` | 断言不变量 |
106
+ | `is` / `has` | 布尔判断 |
107
+ | `to` / `from` | 转换 |
108
+ | `on` | 事件绑定 |
109
+ | `handle` | 内部事件处理 |
110
+
111
+ **类型命名(Type Naming)**
112
+
113
+ > 外部保持原名;内部分**通用层(General)**与**业务层(Business)**;后缀表角色,类型用 PascalCase。
114
+
115
+ | 层 | 类别 | 命名 | 例子 |
116
+ |---|---|---|---|
117
+ | External | 外部(后端 / 第三方) | 保持原名,不重命名、不失真 | `AdminUserVO` / `ProductDTO` |
118
+ | General | 通用结果 | `Result<T, E>` / `Option<T>` | — |
119
+ | General | 通用响应 | `Res<T>` / `ResList<T>` | — |
120
+ | General | 通用分页 | `PageParams` / `PageResponse<T>` | — |
121
+ | General | 通用状态 | `AsyncState` / `ListState<T>` | — |
122
+ | Business | 领域实体 | `Xxx` | `User` |
123
+ | Business | 查询参数 | `XxxQuery` | `UserQuery` |
124
+ | Business | 输入载荷 | `XxxInput` | `UserInput` |
125
+ | Business | 视图模型 | `XxxView` | `UserView` |
126
+ | Business | 操作结果 | `XxxResult` | `PaymentResult` |
127
+ | Business | 领域错误 | `XxxError` | `PaymentError` |
128
+ | Business | 业务状态 | `XxxState` | `UserState` |
129
+ | Business | 业务选项 | `XxxOptions` | `UserOptions` |
130
+ | UI | 组件属性 | `XxxProps` | `CardProps` |
131
+ | UI | 组件事件 | `XxxEmits` | `CardEmits` |
132
+ | Value | 表 / 常量 | `xxxMap` / `UPPER_SNAKE` | `statusMap` / `MAX_RETRY` |
133
+
134
+ - **通用层**放 `types/common/`(单应用);**`shared/types/` 只是项目决策**:当单仓多包且前后端同为 TS 时,可作为前后端单一类型源;只放类型 / 契约,不放业务 / UI;跨应用业务类型建领域包。
135
+ - **业务层**放 `types/<domain>/`;可以 import 通用层,不能 import 外部类型。
136
+ - 依赖方向:External → Wrapper → Business → UI;General 被所有层引用,自己不引用业务。
137
+ - 外部类型保持原名,由 Wrapper 函数(`toXxx` / `parseXxx`)负责映射;不需要 `BackendXxx` 这类改名。
138
+ - 不用 `I` 前缀(`IUser`);不用 `model_xxx` 小写下划线作类型名。
139
+ - 一个实体一个基名;同概念多体系时用限定词(`LoginUser` / `MemberUser`),不用 `User1 / User2`。
140
+ - 为什么不用 `model_xxx`:类型名用 PascalCase;`model_user` 破坏大小写惯例,`ModelUser` 读起来像「对 user 做 model 动作」;角色已经由后缀 / 文件夹表达,不需要再前缀一遍。
141
+
142
+ **规则**
143
+
144
+ - 同一族只用一种模式;新旧不混用。
145
+ - 改名是契约变更:同族一次同步。
146
+ - 前缀只解决「命名空间 / 搜索 / 防重名」,不做装饰。
147
+
148
+ ### 3.2 内外边界(Inside/Outside Boundary)
149
+
150
+ - 前端规范只管**内部代码**;后端 API、第三方 API 的契约风格不在规范内。
151
+ - 外部内容只在 **Wrapper(包装层)** 出现;Wrapper 负责把外部类型 / 字段 / code 转成内部类型 / 错误。
152
+ - 内部代码不 import 外部类型;Wrapper 是唯一入口。
153
+ - Wrapper 可自由适配,但必须:类型安全、错误归一、不泄漏外部字段、可插拔。
154
+ - 换后端 / 第三方 = 换 Wrapper,不改内部。
155
+ - 类型分三层:**External(外部形状)/ Domain(内部领域)/ View(页面视图)**。
156
+ - External 只被 Wrapper import;Domain 供行为层 / 页面;View 由页面 / 行为层派生。
157
+ - 页面 / 组件不得用后端类型定义交互状态;UI 状态用内部联合类型 / 视图模型。
158
+
159
+ ### 3.3 规模档位(Scale Tiers)
160
+
161
+ | 档 | 场景 | 默认启用 |
162
+ |---|---|---|
163
+ | **L0** | 单应用 | 单层 `types/`、无 shared、无契约测试 |
164
+ | **L1** | 单仓多包 | `shared/types/`(按需)、跨包契约、生成物比对 |
165
+ | **L2** | 单仓多包(应用 + 工具包 + 类型包 + UI 包) | 跨包契约、生成物比对、兼容矩阵、视觉回归 |
166
+
167
+ - 规范定义所有档位,项目只启用需要的档位。
168
+ - **多产品 / 多团队是管理问题,不在代码规范内**;仓库之间通过外部契约对接。
169
+ - 升级触发:重复 bug、接口漂移、多人 / 多 agent、跨包复用。
170
+
171
+ **包类型(Package Types)**
172
+
173
+ | 类型 | 例子 | 职责 | 兼容性 |
174
+ |---|---|---|---|
175
+ | **App(应用包)** | client / admin / server / mp / app / web | 单一交付物 | 端内 |
176
+ | **Shared Types(类型包)** | `shared/types` | 前后端 / 跨包类型单一来源 | 跟随契约 |
177
+ | **Toolkit(工具包)** | PDF 导出、业务工具、代码工具 | 多端通用能力 | 包负责兼容矩阵 |
178
+ | **UI(UI 包)** | tokens / components | 设计系统 | 包负责跨端 |
179
+ | **Adapter(适配包)** | 平台 API 适配 | 隔离平台差异 | 按平台 |
180
+
181
+ - 包类型是**开放式指引**,不是封闭枚举;组织自由,包内高内聚;新增类型按职责命名,不强套现有类型。
182
+
183
+ **目录类型(Directory Types)**
184
+
185
+ | 类型 | 例子 | 用途 | 共享方式 |
186
+ |---|---|---|---|
187
+ | **Assets(资源目录)** | 图片 / 字体 / 图标 | 跨应用共享 / 兜底 / 离线 | 目录引用;跨应用且需版本化时升包 |
188
+ | **Docs(文档目录)** | `docs/` | 设计说明书 / 交付说明书 / 其他 | 仓库内;内部组织自由;交付内容由开发者定义 |
189
+ | **Temp(临时目录)** | `.local/` / `tmp/` | 个人草稿 / 临时文档 | 不入 git |
190
+
191
+ - 目录优先:资源 / 文档默认是目录,不是包;升包条件 = 跨应用共享 + 需要版本 / 兜底 / 离线 / public API。
192
+ - 文件存储不设默认:OSS / 本地目录 / CDN / 仓库文档 / `.local` 都是实现;记录环节,不记录实现。
193
+ - 文档目录统一为根 `docs/`;内部组织自由;交付物属于开发者自定义内容,规范只到 `docs/` 这一层;临时文档放 `.local/`(不入 git)。
194
+
195
+ - 一包一能力;禁止 `utils` / `common` / `helpers` 杂物包。
196
+ - Toolkit 对外 API 平台无关;平台差异在包内 adapter 或独立适配包。
197
+ - 应用包依赖工具包,工具包不 import 应用。
198
+ - 第二个消费者出现才升包;一个消费者先留本地模块。
199
+ - 跨端兼容性由包负责:兼容矩阵 + 每端 smoke / contract test。
200
+ - semver + changelog;破坏性变更 major;发布不可覆盖。
201
+
202
+ ### 3.4 目录约定(Directory Layout)
203
+
204
+ ```text
205
+ repo/
206
+ apps/
207
+ <app>/ # 交付物:client / admin / server / mp / app / web
208
+ src/
209
+ pages/
210
+ components/
211
+ behavior/
212
+ api/
213
+ adapters/
214
+ types/
215
+ external/
216
+ packages/
217
+ <capability>/ # 可复用包:types / toolkit / ui / adapter
218
+ src/
219
+ package.json
220
+ README.md
221
+ CHANGELOG.md
222
+ compat.md # 工具包 / UI 包 / 适配包
223
+ tests/
224
+ ```
225
+
226
+ - `apps/` 只放交付物;`packages/` 只放可复用能力;应用不跨 app import。
227
+ - 包类型:`types`(类型 / 契约)、`toolkit-<capability>`(工具)、`ui`(设计系统)、`adapter-<platform>`(平台适配)。
228
+ - 包名推荐 `@scope/<capability>`;工具包可用 `@scope/toolkit-<capability>` 或 `@scope/<capability>`;**不强制定式**,但同一仓库内保持一种风格;禁止 `utils` / `common` / `helpers` 这类无能力名。
229
+ - 兼容矩阵放包内 `compat.md` + CI matrix;应用不维护兼容。
230
+ - 依赖方向:apps → packages;packages → packages(无环);packages 不 import apps。
231
+ - `shared` 是包,不是特殊目录:`packages/types` 或 `packages/shared-types`;只在「前后端同为 TS + 多消费者」时建。
232
+ - 外部类型跟 Wrapper 走:应用本地放 `apps/<app>/src/external/`;跨应用放 `packages/contracts-<source>/`。
233
+
234
+ ### 3.5 环节清单(Stage Catalog)
235
+
236
+ | 环节 | 职责 | 是否必需 | 可选实现 |
237
+ |---|---|---|---|
238
+ | **Transport(传输)** | 网络 / HTTP / 取消 | 有远程调用时 | 自研 / 第三方 |
239
+ | **Wrapper(包装)** | 外部 → 内部转换 | 有外部契约时 | 自研 / 生成 |
240
+ | **Behavior(行为)** | 页面无关行为 | 有复用 / 复杂逻辑时 | composable / hook / service |
241
+ | **State(状态)** | 状态建模与转移 | 有异步 / 多态时 | 联合类型 / 状态机 |
242
+ | **Concurrency(并发控制)** | 去重 / 共享 in-flight / 取消 | 有并发请求时 | 自研 / 第三方 / 不做 |
243
+ | **Observability(可观测性)** | 日志 / 追踪 / 请求序 | 需要排障时 | console / APM / 不做 |
244
+ | **Cache(缓存)** | 数据缓存与失效 | 需要时 | 自研 / 第三方 / 不做 |
245
+ | **Auth(鉴权)** | 登录态 / 401 刷新 | 有鉴权时 | 自研 / 第三方 |
246
+
247
+ - 环节可消失:技术变化导致某环节不再需要时,直接删除,不留兼容壳。
248
+ - 不把某个库当成架构层;库只是当前实现。
249
+ - 项目没有这个职责时,对应环节可以不存在。
250
+
251
+ ### 3.6 文档安全(Document Security)
252
+
253
+ > 文档组织由项目决定;规范只管分级与安全,不管目录结构。
254
+
255
+ **分级**
256
+
257
+ | 级别 | 读者 | 规则 |
258
+ |---|---|---|
259
+ | **Public(公开)** | 客户 / 外部 | 自包含;不引用内部文档 / 路径 / 主机名;不含敏感信息 |
260
+ | **Internal(内部)** | 团队 / AI | 可引用内部文档;不对外交付 |
261
+ | **Confidential(机密)** | 指定人 | 不进 git;放 `.local/` 或密钥管理;不进入提示词 |
262
+
263
+ **红线**
264
+
265
+ - 进 git 的文档禁止出现密码、密钥、令牌、AK/SK、连接串、客户隐私数据。
266
+ - 外部文档禁止引用内部文档、内部路径、内部主机名、内部系统名。
267
+ - 内部文档必须标 `Internal(内部)`;交付物必须来自 `docs/` 下项目声明的交付目录(如 `docs/交付/`),不得把整个 `docs/` 直接打包交付。
268
+ - AI 生成文档时禁止复制配置值;发现敏感信息必须脱敏并提示。
269
+ - CI:secret scanning + 外部文档链接 / 路径检查;交付前跑白名单检查。
270
+ - 密钥一旦进 git:立即轮换,按已泄露处理;不要只删文件。
271
+ - 安全红线不可豁免;不得以例外登记绕过。
272
+
273
+ ### 3.7 文档格式(Document Format)
274
+
275
+ - 文档中的英文术语首次出现用 `English(中文)`,如 `Transport(传输层)`。
276
+ - 同一篇文档内,同一术语的译名保持一致。
277
+ - 代码标识符、命令、路径、API 名保持英文,不加中文括注。
278
+ - 标题、表格、图注同样适用。
279
+ - 对外文档也遵守;面向非技术读者时,首次出现后可只用中文。
280
+
281
+ ## 4. 规则字段
282
+
283
+ 每条规则必须有:`ID / 规则 / 理由 / 正例 / 反例 / 验收 / 范围 / 主人 / 到期`。
284
+
285
+ 没有反例的规则,降级为「参考」;没有验收的规则,等于不存在。
286
+
287
+ ## 5. 使用方式
288
+
289
+ - **人**:review 时按 A1–A21 检查;新规则先写 ADR(Architecture Decision Record,架构决策记录)。
290
+ - **AI**:先读本宪法 + 相关《代码族卡》+ 项目覆盖;输出按 A15,安全按 A21。
291
+ - **修改**:一次变更一个状态;契约类改动全仓原子提交。
292
+
293
+ **规则分类**
294
+
295
+ | 类型 | 规则 |
296
+ |---|---|
297
+ | 硬规则(可机检或二元) | A2、A3、A4、A7(部分)、A11、A17、A21 |
298
+ | 判断规则(人检) | A1、A5、A8、A9、A10、A13、A14、A16、A18、A19、A20 |
299
+ | 流程规则 | A6、A12、A15 |
300
+
301
+ ## 6. 机检现状
302
+
303
+ - 已内置(`codecraft check`):A2 / A11 / A17 / A21(静态、文本级)。
304
+ - 需要项目门禁或人工评审:A3 / A4(收口判断)/ A5–A9(类型与结构)/ A12–A20。
305
+ - 静态扫描只覆盖高置信模式;漏报由项目门禁补,误报按 A12 登记例外。
306
+
307
+ ## 7. 待定
308
+
309
+ - 第一个语言方言是 TS/JS,还是同时写 Java/Go?
310
+ - 每条规则的 owner 和到期日。
@@ -0,0 +1,169 @@
1
+ # 代码族卡 v0(11 个环节)
2
+
3
+ > 2026-10-26 · v0 草稿。
4
+ > 用途:把《代码宪法 v0》落到每个代码族(环节);不同族可以不同形状,族内必须同形。
5
+ > 术语:English(中文)。
6
+
7
+ ## 0. 卡模板
8
+
9
+ 每个代码族写清:**职责 / 形状 / 命名 / 契约 / 状态与错误 / 测试 / 正例 / 反例 / 验收**。
10
+
11
+ > 族是「环节」,不是必须模块;项目没有这个职责时,这一族可以不存在。
12
+
13
+ ## 1. Page(页面)
14
+
15
+ - **职责**:组合根;路由入口;只做编排、布局、状态展示;不承载业务规则。
16
+ - **形状**:`pages/<domain>/index.vue` + `index.config.ts`;页面级类 `page-*`;页面骨架固定为顶栏 / 内容 / 底栏 / 弹层四插槽(组件名按项目命名)。
17
+ - **命名**:目录 kebab-case;组件 PascalCase;页面级类 `page-*`(标作用域,不做装饰)。
18
+ - **契约**:接收路由参数;调用 Behavior Layer(行为层);渲染 loading / empty / error / success;不直接 import api。
19
+ - **状态与错误**:页面状态由 Behavior Layer 提供;页面只持有纯 UI 状态(弹窗、tab);错误必须可见。
20
+ - **测试**:集成 / 视觉回归;纯 UI 不写单元测试。
21
+ - **正例**:列表页只组合列表组件与行为层;详情页只组合详情组件与行为层。
22
+ - **反例**:页面直接 import api;页面里写请求与转换;多个互斥布尔。
23
+ - **验收**:lint「pages 不 import `@/api`」;路由 / 页面清单;视觉回归。
24
+
25
+ ## 2. Behavior Layer(行为层)
26
+
27
+ - **职责**:页面无关的行为;状态转移、校验、编排;不放 UI、不放平台细节。
28
+ - **形状**:Vue3 `composables/<domain>/<verb>.ts`;React `hooks/<domain>/<verb>.ts`;需要跨框架时拆 `behavior/<domain>/core.ts` + `useXxx.ts`。
29
+ - **命名**:`useXxx` 适配器;`xxxCore` / `xxxBehavior` 核心;一个文件一个动词;同族一种前缀。
30
+ - **契约**:入参 / 选项明确;返回状态 + 动作;不藏模块级单例;core 不 import 框架。
31
+ - **状态与错误**:状态用联合类型;派生用 computed / selector;预期失败用 Result / 域变体。
32
+ - **测试**:core 属性测试;适配器集成测试。
33
+ - **正例**:`useList` / `refreshList(state, fetchPage)` / `useFilterList`。
34
+ - **反例**:composable 直接 toast / 跳转;模块级可变状态;为一次性页面逻辑硬抽 composable。
35
+ - **验收**:依赖规则「behavior core 不 import vue / react / uni / taro」;状态转移测试;`any` lint。
36
+
37
+ ## 3. Transport(传输层)
38
+
39
+ - **职责**:网络、HTTP、取消;原样透传;不解释业务 code。401 / 日志是可选环节;外部契约转换在 Wrapper(包装层)。
40
+ - **形状**:`api/` 或 `request/`;`adapter/` / `interceptors/` / `modules/`;`pending/` / `console/` 是可选环节,不是必须目录。
41
+ - **命名**:API 文件 snake_case 且与 URL 同名;一 URL 一文件。新代码推荐 `api/<domain>/<action>.ts` + `fetchXxx` / `getXxx`;旧项目可保留 `api_` 前缀(防重名、可搜索、标层);同族不要混用。
42
+ - **契约**:返回 raw response 或传输层结果;不产出域类型;错误只做传输层归一。
43
+ - **状态与错误**:无 UI 状态;401 单一收口;超时 / 取消 / 网络错误;不弹业务 toast。
44
+ - **并发与去重**:可选环节;查询默认共享 in-flight(同一 key 返回同一 Promise),变更默认按 key 去重;可按 route / page / instance 隔离 scope;可用第三方库或不实现。
45
+ - **日志**:可选环节;dev-only 结构化日志(request id / method / url / timing / status);prod 静默;可用第三方 APM 或不实现。
46
+ - **测试**:契约测试 / mock server;边界 schema 校验在域解析器。
47
+ - **正例**:`adapter + interceptors` 组合;`createApi` 工厂统一注入 baseURL / 超时 / 错误归一。
48
+ - **反例**:传输层把业务 code 解析成域变体;transport import store / UI;全局单例藏副作用。
49
+ - **验收**:lint「transport 不 import UI / store」;401 / pending 测试;契约测试。
50
+
51
+ ## 4. Wrapper(包装层)
52
+
53
+ - **职责**:外部契约适配;把后端 / 第三方的类型、字段、code 转成内部类型 / 错误;不放业务规则、不放 UI。
54
+ - **形状**:`adapters/<source>/` 或 `api/<domain>/<source>.ts`;一个外部来源一个适配器。
55
+ - **命名**:`fromXxx` / `toXxx` / `parseXxx`;外部类型只在包装层内命名(如 `BackendUser` / `ThirdPartyArticle`)。
56
+ - **契约**:输入外部 raw / 外部类型;输出内部 `Xxx` / `Result`;外部字段不泄漏。
57
+ - **状态与错误**:把外部 code / 错误映射成内部错误分类;不弹 toast、不做 UI。
58
+ - **测试**:fixture / 契约测试;第三方响应快照。
59
+ - **正例**:gen-api 类型 → 内部 `User`;资讯平台 → `Article`;支付渠道 → `PaymentResult`。
60
+ - **反例**:页面直接 import `UserDto`;内部类型叫 `UserVo`;第三方字段名出现在 UI。
61
+ - **验收**:lint「内部代码不 import `external/` 或生成类型」;Wrapper 单测;换源不改内部。
62
+ - **转换示例**:一个后端接口返回三个系统的数据 → Wrapper 拆成 `FinanceSummary / OperationsSummary / SupportSummary` 三个内部模型;三个页面各取所需,不共享一个「大而全」的后端类型。
63
+ - **导入规则**:只有 Wrapper / API 层可以 import `external/`;页面 / 组件 / 行为层不得 import。
64
+
65
+ ## 5. Type(类型)
66
+
67
+ - **职责**:描述三层形状——External(外部)/ Domain(领域)/ View(视图);不放行为。
68
+ - **形状**:
69
+ - `external/<source>/`:保持外部原名,勿手改;
70
+ - 单应用:`types/common/`;单仓多包且前后端同为 TS:可用 `shared/types/` 作为前后端单一类型源(只放类型 / 契约;业务类型留应用;跨应用业务建领域包);
71
+ - `types/<domain>/`:业务类型(`Xxx / XxxQuery / XxxInput / XxxView / XxxResult / XxxError / XxxState / XxxOptions`);
72
+ - UI 类型(`XxxProps / XxxEmits`)放组件目录或 `types/<domain>`。
73
+ - **项目决策**:`shared` 不是强制层;后端非 TS 时用 external + Wrapper;只有一个消费者时不建 shared。
74
+ - **特殊**:`shared/types/` 不能变成杂物间;跨应用业务类型用 `packages/domain-<x>`。
75
+ - **命名**:按《代码宪法 v0》§3.1(外部保持原名;通用中性;业务后缀角色;不用 `I` / `model_xxx`);本卡不重复全表。
76
+ - **依赖**:General ← Business;Business 不 import External;UI 只消费 Business / General。
77
+ - **契约**:外部类型只被 Wrapper import;页面 / 组件 / 行为层只用内部类型。
78
+ - **状态与错误**:类型里不允许不可能组合;互斥状态用联合类型。
79
+ - **测试**:类型测试(tsd / expect-type)可选;Wrapper 契约测试。
80
+ - **正例**:`BackendUser` → `toUser()` → `User` → `UserView`。
81
+ - **反例**:页面直接 import `BackendUser`;内部类型命名为 `UserDto`;用后端类型定义页面 loading / error 状态。
82
+ - **验收**:lint「pages / components / behavior 不 import `external/` 或生成类型」;生成物 CI 比对。
83
+
84
+ ## 6. Package(包)
85
+
86
+ - **职责**:一个可发布的单一能力单元;有明确 public API、版本与兼容责任。
87
+ - **类型**:App(应用)/ Shared Types(类型)/ Toolkit(工具包)/ UI(UI 包)/ Adapter(适配包);Assets / Docs / Temp 是目录,不是包。
88
+ - **开放清单**:包类型不是封闭枚举;组织自由;包内高内聚;新增类型按职责命名,不强套现有类型。
89
+ - **目录优先**:资源 / 文档默认是目录,不是包;跨应用共享 + 需要版本 / 兜底 / 离线 / public API 时才升包;文件存储不设默认(OSS / 本地 / CDN / 仓库 / `.local`)。
90
+ - **形状**:`packages/<name>/{src,package.json,README.md,CHANGELOG.md,compat.md,tests}`;`exports` 明确公开入口。
91
+ - **目录**:`apps/` 只放交付物;`packages/` 只放可复用能力;应用不跨 app import。
92
+ - **共享类型**:`shared` 是包,不是特殊目录(`packages/types` / `packages/shared-types`);只在前后端同为 TS + 多消费者时建。
93
+ - **外部类型**:跟 Wrapper 走;应用本地 `apps/<app>/src/external/`;跨应用 `packages/contracts-<source>/`。
94
+ - **命名**:推荐 `@scope/<capability>`;工具包可 `@scope/toolkit-<capability>` 或 `@scope/<capability>`;不强制定式;同仓一种风格;禁止 `utils` / `common` / `helpers`。
95
+ - **契约**:只暴露 public API;禁止深层 import;跨包只走包名 + `exports`。
96
+ - **兼容性**:工具包负责平台兼容矩阵;每端 smoke / contract test;不把兼容责任丢给应用。
97
+ - **版本**:semver + changelog;破坏性变更 major;发布不可覆盖。
98
+ - **正例**:PDF 导出工具包、`shared/types`、tokens / UI 包。
99
+ - **反例**:`utils` 包;工具包 import 应用;包内混入业务页面。
100
+ - **验收**:`boundaries`;包 build / test;`exports` 检查;兼容矩阵。
101
+
102
+ ## 7. Component(组件)
103
+
104
+ - **职责**:UI 展示与交互;只消费 props / emit;不取数、不放业务规则;可复用、可组合。
105
+ - **形状**:目录式 `components/<Name>/index.vue` + `index.scss`;全局原语放 `app-ui/`;页面私有组件放页面目录。
106
+ - **命名**:PascalCase 目录 / 组件;`app-` 用于全局原语;角色后缀 `XxxCard / XxxList / XxxForm / XxxModal / XxxPage`;类型 `XxxProps / XxxEmits`。
107
+ - **契约**:props 下行、emit 上行;不 import api / behavior;不读业务 store(仅全局身份 / 权限例外);样式 scoped / BEM;可访问性(键盘 / ARIA / 对比度)。
108
+ - **状态与错误**:只持有纯 UI 状态(open / hover / focus);loading / empty / error 由 props 传入;不吞错。
109
+ - **测试**:示例页 / Storybook;交互测试;视觉回归;a11y。
110
+ - **正例**:页面骨架组件、`XxxCard`、`XxxGrid`。
111
+ - **反例**:组件内发请求;组件直接读业务 store;组件里写路由;为覆盖样式包一层无业务组件。
112
+ - **验收**:lint「components 不 import api / behavior」;props / emits 类型;a11y / visual checks。
113
+
114
+ ## 8. State(状态)
115
+
116
+ - **职责**:领域状态建模;状态是数据,不是布尔堆;转移通过事件 / 动作。
117
+ - **形状**:`types/<domain>` 的联合类型;`behavior/<domain>/core.ts` 的 reducer / state machine;store 只存数据 + setter。
118
+ - **命名**:`XxxState` / `XxxStatus` / `XxxEvent` / `XxxAction`;通用 `AsyncState / ListState` 放 `types/common`。
119
+ - **契约**:状态用联合类型;非法状态不可表示;`success` 有 data,`error` 有 error;派生用 selector / computed。
120
+ - **错误**:错误分类;预期失败用 Result / 域变体;空 catch 为零。
121
+ - **测试**:状态转移表 / 属性测试;关键流程。
122
+ - **正例**:`useList` 的 status;auth machine;form state。
123
+ - **反例**:`loading / error / data` 三个布尔;store 放请求逻辑;派生状态另存一份。
124
+ - **验收**:`assertNever`;`satisfies Record<Union, T>`;状态转移测试。
125
+
126
+ ## 9. Util(工具)
127
+
128
+ - **职责**:纯函数、无副作用、可单测;不依赖框架 / 业务状态。
129
+ - **形状**:`utils/<domain>/index.ts` 或单文件;跨项目通用工具放 `packages/toolkit-*`;领域工具放 `utils/<domain>`。
130
+ - **命名**:`toXxx / fromXxx`、`isXxx / hasXxx`、`parseXxx / formatXxx`、`assertXxx`;避免 `helper / utils / common` 大杂烩。
131
+ - **契约**:输入输出明确;不读全局;不弹 toast / 不跳路由;不写 DOM 交互(DOM / 平台适配放 adapter / ui)。
132
+ - **错误**:纯函数返回 Result / 默认值;不抛业务异常;处理边界输入。
133
+ - **测试**:属性测试 / 边界测试;纯函数。
134
+ - **正例**:date / format、palette、categories、queryString。
135
+ - **反例**:util 里发请求 / 读 store;util 里写业务规则;`utils` 包什么都装。
136
+ - **验收**:lint「utils 不 import api / store / ui」;纯函数测试;覆盖率。
137
+
138
+ ## 10. Script(脚本)
139
+
140
+ - **职责**:开发 / 构建 / 生成 / 审计 / 迁移;不是运行时业务代码。
141
+ - **形状**:`scripts/<verb>-<object>.ts`;包内 `scripts/`;生成物不手改。
142
+ - **命名**:`build-*`、`gen-*`、`audit-*`、`sync-*`、`migrate-*`;动词开头。
143
+ - **契约**:参数 / 环境变量明确;幂等;stdout 出数据、stderr 出日志;退出码 0 / 1 / 2;不隐式改工作区。
144
+ - **错误**:失败即非零退出;错误信息包含下一步;不吞错。
145
+ - **测试**:脚本 smoke test;fixture;CI 运行。
146
+ - **正例**:`gen-api`、`tokens`、`boundaries`、`design-audit-code`。
147
+ - **反例**:脚本依赖本机私有路径;脚本无退出码;脚本隐式改文件;脚本里写业务。
148
+ - **验收**:`--check` 模式;CI;用法文档。
149
+
150
+ ## 11. Test(测试)
151
+
152
+ - **职责**:保护契约与关键路径;不是追覆盖率。
153
+ - **形状**:`tests/` 或 `__tests__/`;fixture 单独;命名 `<unit>.test.ts`。
154
+ - **命名**:`describe('<unit> · <behavior>')`、`it('does X when Y')`;中英文随项目,保持一致。
155
+ - **契约**:
156
+ - Pure core → 属性测试 / 单元测试;
157
+ - Behavior adapter → 集成测试;
158
+ - Wrapper → 契约测试 / fixture;
159
+ - Page / Component → 交互 / 视觉 / a11y;
160
+ - Script → smoke / exit code;
161
+ - 不测框架 / 第三方内部。
162
+ - **覆盖重点**:非法状态、错误分支、取消 / 重试、边界输入;不只 happy path。
163
+ - **正例**:`_shared/list` 分页;`derive` 对比度;Wrapper fixture。
164
+ - **反例**:为覆盖率写断言;mock 一切;只测 happy path;测试实现细节。
165
+ - **验收**:CI;关键路径覆盖;bug fix 附回归测试。
166
+
167
+ ## 12. 扩展位
168
+
169
+ 新的族先在这里登记,不预建结构。
@@ -0,0 +1,68 @@
1
+ # AI 生成契约 v0
2
+
3
+ > 2026-10-26 · v0 草稿。
4
+ > 用途:所有模型 / agent 生成或修改代码前先读;与《代码宪法 v0》《代码族卡 v0》配套。
5
+ > 术语:English(中文)。
6
+
7
+ ## 1. 先读
8
+
9
+ 1. 《代码宪法 v0》
10
+ 2. 相关《代码族卡 v0》
11
+ 3. 设计架构时:`06-architecture.md`(档位 / 七步法 / 边界 / ADR)
12
+ 4. 需要选型时:`05-patterns.md`(按力选,不按名字选)
13
+ 5. 项目覆盖:`AGENTS.md` / `rules/` / `README`
14
+ 6. 相关契约 / 类型 / 测试 / 示例
15
+
16
+ ## 2. 禁止
17
+
18
+ - 禁止新增 token / 组件 / API 而没有真实消费方。
19
+ - 禁止新增运行时依赖而不说明体积与必要性。
20
+ - 禁止把业务逻辑放进 Transport(传输层)或 Page(页面)。
21
+ - 禁止制造第二份真源(手写会漂移的文档 / 类型 / 常量)。
22
+ - 禁止注释复述代码。
23
+ - 禁止手改生成物。
24
+ - 禁止空 catch / 静默失败。
25
+ - 禁止跨族复制而不登记母版与分叉点。
26
+ - 禁止复制项目门禁(如 `kit:check`);只通过 config 调用。
27
+ - 禁止在 Plan 模式改文件;只输出计划。
28
+ - 禁止把密码 / 密钥 / 令牌 / AK/SK / 连接串 / 客户隐私写进代码、文档、示例或提示词;发现即脱敏并提醒。
29
+ - 禁止外部文档引用内部文档 / 内部路径 / 内部主机名。
30
+ - 安全红线不可豁免;不得以例外登记绕过。
31
+
32
+ ## 3. 文档安全
33
+
34
+ - 文档分级:`Public(公开)` / `Internal(内部)` / `Confidential(机密)`。
35
+ - 外部文档自包含;不出现内部链接、路径、主机名、系统名。
36
+ - 内部文档标 `Internal`;不进入交付目录。
37
+ - 生成示例值用占位符(`<TOKEN>` / `<PASSWORD>`),不得复制真实配置。
38
+ - 发现疑似密钥 / 隐私,停止生成、脱敏、提示轮换。
39
+ - 术语格式:英文首次出现用 `English(中文)`;代码标识符保持英文。
40
+
41
+ ## 4. 必须
42
+
43
+ - 说明改了哪些文件、为什么(引用 A1–A21)。
44
+ - 跑项目验证命令,报告命令与结果;不能跑要说明原因。
45
+ - Apply 前后跑项目门禁;Audit 先跑内置规则,再跑 config gates;不得跳过失败。
46
+ - 新增例外必须写理由 + 主人 + 到期。
47
+ - 注释只写意图 / 契约 / 边界 / 反例 / 警告。
48
+ - 状态用联合类型;switch / map 穷尽。
49
+
50
+ ## 5. 输出格式
51
+
52
+ 1. **改了什么**:文件列表
53
+ 2. **为什么**:规则 ID(A1–A21)
54
+ 3. **怎么验**:命令 + 结果
55
+ 4. **风险 / 不确定**
56
+ 5. **后续**:owner + 到期
57
+
58
+ ## 6. Review Checklist(评审清单)
59
+
60
+ - [ ] 族形正确(Page / Behavior / Transport)
61
+ - [ ] 依赖向内
62
+ - [ ] 状态穷尽
63
+ - [ ] 错误可见
64
+ - [ ] 注释只消歧义
65
+ - [ ] 生成物未手改
66
+ - [ ] 例外已登记
67
+ - [ ] 无敏感信息 / 无内部路径外泄
68
+ - [ ] 验证命令通过
@@ -0,0 +1,90 @@
1
+ # 风格总图(一页)
2
+
3
+ > 一页看完全套约束的形状;细则见 `00-constitution.md`,字段见 `01-family-cards.md`。
4
+ > 读法:先看第 1 节「不变的」和第 2 节「变的」,其余是判据与代价。
5
+
6
+ ## 一句话
7
+
8
+ 先画承重墙,再摆家具。
9
+ 承重墙 = 边界、契约、收口、命名;家具 = 栈、状态库、UI 库、样式实现。
10
+
11
+ > 完整在底层,取舍在上层:规范覆盖大项目能力,默认只启用小项目所需(A18)。
12
+
13
+ ## 1. 不变的承重墙
14
+
15
+ | 层 | 不变量 |
16
+ |---|---|
17
+ | 边界 | 外部契约不参与内部规范;外部只在 Wrapper 出现;内部不 import 外部类型(A17) |
18
+ | 传输 | 传输层只负责收发与取消,不解释业务 code(A3) |
19
+ | 收口 | 鉴权失效、错误提示、分页、配色、分类各一处(A4) |
20
+ | 页面 | 一个页面一个编排入口;页面只编排,不写传输与领域规则(A1) |
21
+ | 组件 | 原语薄、业务组件按域;同族同形(A1) |
22
+ | 行为 | 页面无关行为单独成层;页面不复制行为(A1 / A4) |
23
+ | 状态 | 异步 / 多态用联合类型;非法状态不可表示(A5);派生不存储(A8) |
24
+ | 类型 | 外部保持原名;内部通用层与业务层分离(A17) |
25
+ | 命名 | 同族一种前缀;前缀标层、防重名、可搜索(A16) |
26
+ | 错误 | 预期失败是值;空 catch 为零(A6) |
27
+ | 生成物 | 只读;有标记;可重建(A11) |
28
+ | 实现 | 模块内部自由;public contract 固定(A19) |
29
+ | 环节 | 记录职责,不记录实现;环节可消失(A20) |
30
+ | 注释 | 只写代码不能直接表达的意思(A9) |
31
+ | 目录 | `apps/` 交付物;`packages/` 能力;`assets` / `docs` 默认是目录 |
32
+ | 文档 | 统一 `docs/`;分级 + 安全边界(A21) |
33
+
34
+ ## 2. 变的家具
35
+
36
+ - 栈:按项目选;一次只换一个轴。
37
+ - 状态:按复杂度选;局部状态优先。
38
+ - 样式:字面量 → 变量 → token + 审计。
39
+ - 类型:手写 → 生成;生成物只读。
40
+ - 传输:手写 → 库;换实现不换契约。
41
+ - 设计:无 → 设计工程;稿码同构是翻译前提。
42
+
43
+ 换栈 = 换家具,不动承重墙;换家具要重建该轴的体系,不是局部替换。
44
+
45
+ ## 3. 抽象判据
46
+
47
+ - 语义同源 > 形状相同 > 文本相同;文本相同不构成理由。
48
+ - Wrapper 只承载转换,不承载样式补丁与业务堆叠。
49
+ - 差异收在边界:平台差异走目录 / 后缀 / Wrapper。
50
+ - 抽不抽:第二次出现警惕,第三次出现或第三个消费者再抽象(A14)。
51
+ - 复制 vs 抽象:复制要登记母版、版本、分叉点(A12)。
52
+ - 加一层必须能一眼定位源头(A13)。
53
+
54
+ ## 4. 复用方式
55
+
56
+ | 方式 | 场景 | 代价 |
57
+ |---|---|---|
58
+ | 复制母版 | 一次性交付、生命周期短 | 同一缺陷修多次 |
59
+ | 同仓多分支 | 多客户强定制 | 长期 fork,合并面大 |
60
+ | 同仓多包 | 多应用共享能力 | 包负责兼容矩阵与版本 |
61
+
62
+ ## 5. 稿码关系
63
+
64
+ ```
65
+ 设计稿(展开态)── 折叠 ──► 代码(组件调用)
66
+ └── class / DOM 同构 ──┘
67
+ ```
68
+
69
+ - 结构 / 样式默认 design-first;行为导致的样式变化 code-first。
70
+ - 同构是翻译前提;不成立时只能靠理解,必然漂移。
71
+ - 审计只做可判定项初筛,终审是人。
72
+
73
+ ## 6. AI 协作
74
+
75
+ - AI 是实施者,人是判断者;瓶颈是审稿带宽。
76
+ - 规则从现有代码与既有决策提炼,不发明。
77
+ - 输出必须说明改了什么 / 为什么 / 怎么验 / 风险(A15)。
78
+ - 被 AI 使用的形态要短、硬、可验证;长解释放参考文档。
79
+
80
+ ## 7. 代价
81
+
82
+ - 复制放大缺陷;测试缺位时只在线上暴露。
83
+ - 换 UI 库要重建样式体系。
84
+ - 收口点多,接手要先学一张地图。
85
+ - 规范本身有维护成本;改契约要整族刷新。
86
+
87
+ ## 8. 一句话
88
+
89
+ **先定边界,再选实现。**
90
+ 承重墙是契约与收口,不是某个框架或某个库。