@antprofuse/saddle-islands-design 0.1.13 → 0.1.14

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.
package/SKILL.md CHANGED
@@ -1,49 +1,45 @@
1
1
  ---
2
2
  name: saddle-islands-design
3
- description: 从 Islands 业务 Spec 设计 Saddle 落地所需的契约。当前支持后端服务契约 backend-contract 与逻辑数据库表设计,可独立或联合执行并审查一致性。不修改业务 Spec,不实现业务代码、外部 RPC 或数据库部署。
3
+ description: 消费 Islands Spec 与 adapt,设计 Saddle 后端服务契约和逻辑数据库表,可独立或联合设计并审查一致性。不修改业务Spec或猜填适配逻辑,不实现业务代码、外部RPC或数据库部署。
4
4
  ---
5
5
 
6
6
  # Saddle Islands 设计
7
7
 
8
- 统一承载 Islands 到 Saddle 的设计规范,使用一个 Skill、一个发布版本;后端契约和 DB 是内部设计模块,不再是独立 Skill。未来经用户确认的设计能力也在此扩展,不因为名称宽泛就自动新增设计职责。
9
-
10
- Spec 是业务输入,设计契约是输出。Islands API 表达逻辑业务入口;backend-contract 表达后端向调用方提供的服务契约,两者不混称,也不预设一对一。profusecontract 是出口角色,不是后端契约的别名。
8
+ Spec定义抽象业务,adapt补充落地输入,后端契约与DB是输出。先推导自洽的设计,再以格式准确承载;不能让业务Spec为工具格式增加技术字段。后端契约不是Dependency出口协议,profusecontract实现不是本模块前置。
11
9
 
12
10
  ## 选择模块
13
11
 
14
- 按用户指定的设计任务选择模块;上下文已明确时不重复询问。只要求某模块时不捆绑另一模块;仅说“设计”且范围不明确时,先确认本次交付范围。
12
+ 按用户范围执行,不捆绑未要求的设计或实现。所有模式先完整阅读[adapt输入与身份规则](references/adapt.md),再读所选模块:
15
13
 
16
- | 任务 | 执行前完整阅读 | 独立交付 |
14
+ | 任务 | 执行前完整阅读 | 交付 |
17
15
  | --- | --- | --- |
18
- | 后端契约 | [设计流程](modules/backend-contract/design.md)、[格式规范](modules/backend-contract/references/backend-contract-v1.md)、[覆盖规则](modules/backend-contract/references/coverage.md) | 指定后端契约目录的 `*.backend-contract.yaml` |
19
- | DB | [设计流程](modules/db/design.md)、[表契约规范](modules/db/references/db-table-v1.md) | 指定 DB 目录的 `*.table.yaml` |
20
- | 联合设计 | 上述两组内容 | 两类文件独立交付,并做下述一致性检查 |
21
-
22
- 有问题时阅读对应模块的 findings 参考;不加载与本次任务无关的模块。模板位于各模块 assets,沿模块说明使用。模块不是独立安装包,不要求用户再安装旧 Skill。
16
+ | 后端契约 | [设计流程](modules/backend-contract/design.md)、[格式](modules/backend-contract/references/backend-contract-v1.md)、[覆盖规则](modules/backend-contract/references/coverage.md) | `*.backend-contract.yaml` |
17
+ | DB | [设计流程](modules/db/design.md)、[表格式](modules/db/references/db-table-v1.md) | `*.table.yaml` |
18
+ | 联合设计 | 上述两组 | 独立文件,做跨层复核 |
23
19
 
24
- ## 共用输入与协作
20
+ 有来源问题时读对应模块findings参考;模板在模块assets。一个Skill、一个版本,模块不是另一个安装包。
25
21
 
26
- - Spec 仓库与 Spec 目录分别指定,目录相对该仓库根目录。记录实际分支及 commit;未指定版本时使用远程默认分支,不猜 master/main。默认覆盖指定目录业务,用户明确的子范围优先。
27
- - 交付仓库与各模块交付目录分别明确,可使用不同仓库;不从 Spec 地址擅自推导。目录建议分别为 `code/backend-contract`、`code/db`,实际位置以用户确认为准。只做 DB 不要求业务前缀;后端契约需要调用方提供完整业务前缀。
28
- - 核对实际安装包名称与版本;完整读取所选模块说明和必需参考,不静默更换版本。无需用户提供包内入口路径。
29
- - Islands 默认参考仓库为 `https://code.alipay.com/profuse/islands`。优先遵守项目版本约束,无约束时读取远程默认分支并记录 commit;调用方可以覆盖。版本不兼容、不可访问不等于业务缺失。
30
- - 通读所选范围相关业务表达及 Islands 指南,按模块取得受支持的编译元数据并核对来源。不因缺少预生成文件而禁止业务推演,但不得把未执行的解析、校验或测试称为通过。
31
- - 默认先粗后细,确认边界后展开完整交付;已授权直接设计则按授权执行。每次聚焦一个问题,不以推测填补业务事实或设计决策。
32
- - 业务 Spec 只读。局部问题及时反馈并说明依据、影响及是否阻塞,继续不受影响部分;只有 Spec 业务缺失或矛盾才记录为 Spec finding。规范能力不足反馈维护者,不自行绕过。只有明确授权维护 Skill 时可修改通用规范。
33
- - Findings 只进入用户指定过程位置,未指定时直接反馈,不混入正式交付目录。默认提交推送前展示 diff tree 并取得确认;已有授权按其范围执行。不自动发布 Skill 或向其他 workspace 分配任务。
22
+ ## 输入与协作
34
23
 
35
- ## 联合设计的一致性
24
+ - 明确Spec仓库与目录、adapt位置、交付仓库与目录,仓库和目录分别记录;上下文已明确的不重复询问。adapt通常与spec、code同级,但必须检查实际存在,不猜内容。Spec、adapt都属于输入;缺失声明不能由设计Agent默认生成。
25
+ - 后端契约另需完整业务前缀;DB不需要。输出建议分别为code/backend-contract、code/db,以用户指定为准。不要求实现语言、生成配置、外部RPC合同作为额外输入。
26
+ - 记录实际输入分支及commit。无版本约束时读取远程默认分支,不猜master/main;Islands默认参考仓库为https://code.alipay.com/profuse/islands。工具不可访问或不兼容不等于Spec业务缺失。
27
+ - 通读所选范围的Spec、adapt及相关Islands指南,检查Prototype与测试责任。元数据不可用时可做来源有据的推演,不能虚报编译、覆盖或测试通过。
28
+ - 逐项讨论真正影响设计的歧义,不以推测补业务事实。已授权完整设计时继续不受影响部分,不要求所有适配实现先完成。
29
+ - 普通消费Agent发现规范缺口应反馈维护者,不私造规则;获得Skill维护授权的设计者先给出合理设计供确认,再修通用规则,不把旧Skill能力当业务限制。
30
+ - Findings只记录Spec业务缺失或矛盾;adapt待定项、规范缺口、消费者迁移问题分别说明,不倒逼Spec改成物理流程。
31
+ - 交付目录仅放有效契约,不放过程记录、检查脚本或findings。用户授权替换时清掉本范围旧设计文件,不并存冲突真源;不越权删除实现代码,也不宣称消费者自动兼容。
32
+ - 提交、推送、发布按用户各仓库授权执行;Spec默认先展示diff tree确认。维护权不等于每次任务自动有发布权,不向其他workspace自行派单。
33
+ - 使用的包名和版本要明确;起手消息模板不自动改写。
36
34
 
37
- 后端契约的范围与完备性由指定 Prototype + 测试用例决定,实体与规则用于解释来源;DB 则按本系统实体的实际持久化责任设计,也覆盖系统任务等非客户端入口。不能用其中一个模块的范围替代另一个。
35
+ ## 联合复核
38
36
 
39
- 共同核对实体身份、归属、字段语义、金额单位、关联和 Logic 读写责任。后端契约是投影,不要求与表字段一一对应;不得从返回字段反向建表,也不得为 external 实体制造本地表。DB 可选 `backendContractId` 指向实际后端契约 id,不代替 Logic 身份。
37
+ 后端契约以Prototype+测试要求确定范围,实体与adapt用于解释字段和边界;DB以adapt明确承载责任确定表集合,不从响应反向建表。
40
38
 
41
- 逻辑实体身份、数据库 uid 与外部识别条件不是同一个概念;本次合并不新增身份编码或入口、出口映射规则。已有格式未覆盖的适配需求先反馈讨论,不让业务 Spec 改成外部函数调用伪代码,不宣称实现已有解析能力。
39
+ 共同核对完整实体属性(Spec+adapt扩展)、实例归属、身份方式、金额单位和可空性。关联跟随目标身份,不能统一假设uid。DB宽松存储约束不能放宽后端契约成功结果;后端结果投影不要求复制全部数据库列。
42
40
 
43
- 允许按模块或已明确部分分阶段交付,不要求一项全部完成才开始另一项。两类设计完成不等于实现测试或生产链路完成;测试研发与业务代码实现仍是后续工作。
41
+ 两类设计完成不等于适配实现、前后端测试或生产链路完成。具体绑定内容由用户或其授权的实现者填写,不从TODO发明加载、同步或对外调用。
44
42
 
45
43
  ## 维护边界
46
44
 
47
- 当前仅有上述两个模块。新增模块须先与用户确认设计职责、输入、交付及模块间关系,再更新本 Skill;不另起独立设计 Skill,也不预建占位模块。版本默认只递增 `0.1.x` 的 patch。
48
-
49
- 统一包不自动迁移已发布旧包、项目文件或消费者。现有模块格式保持;涉及文件发现、格式标识和关联键的历史更名仍需按模块规范单独适配。保留用户未批准草稿,不将其混入发布产物。
45
+ 目前仅后端契约与DB两个模块。新增模块须确认职责,不提前预建。版本默认只递增0.1.x的patch。保持已批准的约定,清理失效规则,避免把单个业务案例固化成通用设计。保留包外未批准草稿,不混入发布。
@@ -1,3 +1,3 @@
1
1
  interface:
2
2
  display_name: "Saddle Islands Design"
3
- short_description: "从 Islands 业务 Spec 统一设计后端服务契约与逻辑数据库表"
3
+ short_description: "消费 Islands Spec 与 adapt,统一设计后端契约与逻辑数据库表"
@@ -4,9 +4,21 @@ binding:
4
4
  type: mobilegw
5
5
  operationType: alipay.profuse.industry.replace.replaceOperation
6
6
  callSites:
7
- - kind: visualPageLoad
8
- page: 替换为页面
9
- inputBindings: {}
7
+ - kind: flowEntry
8
+ flow: {board: 替换为板块, entry: 替换为入口}
9
+ ingress:
10
+ path: 替换为ingress文件仓库相对路径
11
+ domain: 替换为业务域
12
+ board: 替换为板块
13
+ entry: 替换为入口
14
+ inputBindings:
15
+ 示例输入:
16
+ ingressField:
17
+ path: 替换为ingress文件仓库相对路径
18
+ domain: 替换为业务域
19
+ board: 替换为板块
20
+ entry: 替换为入口
21
+ field: 替换为外部字段
10
22
  input:
11
23
  type: object
12
24
  nullable: false
@@ -14,12 +26,20 @@ input:
14
26
  示例输入:
15
27
  type: string
16
28
  nullable: false
17
- source: {entity: 替换为实体, field: 替换为字段}
29
+ source:
30
+ kind: ingressField
31
+ path: 替换为ingress文件仓库相对路径
32
+ domain: 替换为业务域
33
+ board: 替换为板块
34
+ entry: 替换为入口
35
+ field: 替换为外部字段
18
36
  # output 只定义成功响应的 data;失败固定为 success:false + failure.code/message。
19
37
  # 来源也支持正式 Flow Form / Rule 返回合同,见参考;不可从样例猜测枚举。
20
38
  output:
21
39
  type: object
22
40
  nullable: false
41
+ invariants:
42
+ - 替换为有来源依据的结果实例归属或字段组合约束,不补造业务。
23
43
  fields:
24
44
  示例字段:
25
45
  type: string
@@ -1,60 +1,23 @@
1
+ # 后端契约设计
1
2
 
2
- # Saddle 后端契约设计
3
+ 消费Spec+adapt,产出后端向前端提供的独立契约。先读共用adapt规则,再完整阅读[格式](references/backend-contract-v1.md)与[覆盖](references/coverage.md)。来源有问题时读[findings](references/findings.md)。
3
4
 
4
- ## 命名与层次
5
+ ## 推演顺序
5
6
 
6
- 本模块 的产物统一称为后端契约(backend-contract):后端向调用方提供的服务契约。Islands API 是业务 Spec 的逻辑入口声明,属于输入侧概念;不得将两者混称,也不预设一对一。`callSites.api` 专指 Islands API 来源,保留该字段,不改写业务 Spec。出口 profusecontract 不属于本模块。
7
-
8
- 本次只统一命名,不增加实体身份编码或逻辑到物理映射规则;有关规则尚待讨论,不因更名自行推导。
9
-
10
- 从 Islands Spec 产出完整、自包含的后端服务契约。后端契约是小程序与 Saddle 后端之间的边界;数据库访问和外部 RPC 属于后续的后端实现设计。
11
-
12
- **设计范围与完备性的基准只有调用方指定范围内的 Prototype + 测试用例。** Prototype 决定交互、展示与通信需求,测试用例决定场景、预期结果和副作用;完整支撑两者即可认定当前范围的后端契约设计完备。其他 Spec 仅用于解释业务含义、追溯实体字段和规则,不据此扩展接口、字段或场景。两者冲突、缺失或不可定位时反馈,不自行补造,也不把缺失当作空集合宣称完成。
13
-
14
- 字段基于实体的业务概念表达,逐字段遵守来源规则;已有 Form/Rule 来源只用于有依据的临时或派生事实,不授权另造业务实体或整包透传技术答复。每份后端契约必须在文件内通过 `coverage` 与 Prototype、测试用例建立可核验的强关联,不能仅声称“已阅读”或只挂链接。设计覆盖不等于实现测试已经运行通过。
15
-
16
- 设计契约前必须阅读 [references/backend-contract-v1.md](references/backend-contract-v1.md) 和 [references/coverage.md](references/coverage.md)。当来源关联、类型、调用点或业务结果不能唯一确定时,阅读 [references/findings.md](references/findings.md)。
17
-
18
- ## 模块输入
19
-
20
- 按统一入口核对 Spec、交付目录及 Islands 版本。后端契约设计额外需要完整业务前缀;operationType 为 `<完整业务前缀>.<动作的camelCase>`,不重复添加前缀,不根据目录名改写。已有 operationType 与任务冲突时反馈,不静默重命名。契约 id 仍按参考使用 snake_case。
21
-
22
- DB 设计、profusecontract 与外部 RPC 协议不是本模块的前置条件;external 实体仍需按业务来源阅读。先对齐服务边界及输入输出概览,再展开字段;用户已授权完整设计时直接执行。
23
-
24
- ## 工作流程
25
-
26
- 1. 先完整列出指定范围的 Prototype 交互/展示及测试用例责任,形成覆盖分母,再按需追溯 Visual、Logic、Structure、Rule 和编译元数据解释含义。不以所有 Spec 内容为接口清单,不要求 Spec 预先声明 API 或 external 调用契约。
27
- 2. 从 Visual 的页面加载、读取和动作出发,再追踪其 Logic 事务与数据引用。只有业务能力、输入含义、结果含义和副作用语义完全一致时,才把多个调用点归入同一个后端契约。页面加载所需的多项关联读取可以形成一个页面读模型;不要按 ER 读取数量机械拆分后端契约。
28
- 3. 使用 v1 格式定义完整后端契约。先确定可直接作为 Rust module 的全局唯一后端契约 ID,再精确绑定每个调用点,并在每个调用点绑定全部输入。
29
- 4. 每个输入和输出业务叶字段必须具有可解析的 Structure、Flow Form 或 Rule 来源,或一组结构化依赖加自然语言派生逻辑。Form 必须追溯正式端口及其赋值链,Rule 必须追溯正式返回合同;不能用样例推断枚举。输入字段的 `source` 表达字段的业务语义,调用点 `inputBindings` 表达本次值从何处取得;两者不可互相替代。绝不创造无根字段。
30
- 5. MobileGW 系统内置提供的值不属于客户端 input,也不属于业务后端契约的定义内容。绝不要求客户端重复提交系统已提供的当前用户 ID 等值。
31
- 6. 只向正式后端契约目录输出完整契约。Spec 中未闭合但被明确排除在现有业务结果之外的状态,可以由一个语义精确的 fail-closed error 暂时承接,并同时记录 Spec finding;不得猜测或细分尚未定义的业务结果。Skill 表达能力不足由规范维护者修复,不记录为项目 Spec finding,也不由消费方另造规则绕过。
32
- 7. 按 coverage 规则双向核对:每项 Prototype 与测试预期均被支撑,每个后端契约调用点、业务结果与所需字段均有依据。逐项推演动作输入、输出断言、副作用及后续交互,记录无需后端契约的纯前端责任,不以样例数量或链接存在代替覆盖证明。名称、类型、枚举、nullable 及来源仍必须封闭明确。
33
-
34
- ## 产出
35
-
36
- - 每个完整后端契约产出一个 `<contract_id>.backend-contract.yaml`;文件名 stem 必须与契约 `id` 原样一致。
37
- - 存在 Spec 问题时,写入调用方指定的过程记录位置;未指定时只在交付说明中报告。`backend-contract-design-findings.yaml` 绝不能进入正式 `code/backend-contract` 目录。
38
- - 不把散文式设计文档作为交付物。
39
-
40
- 以 [assets/backend-contract.template.yaml](assets/backend-contract.template.yaml) 为起始结构。删除示例内容;交付的 `*.backend-contract.yaml` 中绝不能残留 TODO、占位符、阻塞标记或诊断节点。
7
+ 1. 列出指定Prototype交互、展示及测试责任的完整分母。Spec其他内容用于解释实体与业务,不据此扩展接口范围;不要求Spec预先声明物理服务接口。
8
+ 2. 找到实际入口或页面动作,沿业务逻辑走到下次用户参与或交付结果的边界。中间无需用户补充输入的关联读取可以归并一次调用;不按实体数、Logic数或Dependency数机械拆接口,也不强制所有业务只有一个查询。
9
+ 3. 输入逐字段追溯实体属性(含adapt扩展)或ingress。后端不能从系统取得才向前端索要;系统当前用户不出现在input或context。入口字段可直接向后传递,不强制归属实体属性。
10
+ 4. 输出是具体线上字段的实体投影,不是让前后端各自解释的抽象Row。说明本次实体实例根和关联路径,不能仅凭字段同名认定来源正确。不为仅传递对象制造uid、token或身份映射。
11
+ 5. 选择最小充分的结果结构:对象+可空成员已完整表达时无需case;存在真实互斥形状时用联合。完整枚举来自声明,不来自样例。确认的跨字段、实例归属及空值语义写入invariants,不只藏在coverage。
12
+ 6. 对照测试逐项验证输入形成、输出展示、关系和副作用;不把“链接了测试”当作满足测试。需要后端保证的事实仍应验证,不能因删除传输冗余就删除业务条件。
13
+ 7. 只交付当前输入对应的有效设计。用户授权更新范围内移除过时契约;实现迁移另列,不为旧代码保留另一套相冲突的真源。
41
14
 
42
15
  ## 边界
43
16
 
44
- - 通用响应固定为成功 `{success: true, data: <output>}` 或失败 `{success: false, failure: {code, message}}`。output 只定义成功 data,不重复包装;不使用旧 value/errorCode 信封。failure.code 取本接口声明的错误码,failure.message 是字符串说明,不是程序判别字段。
45
- - Spec 拥有业务真相;后端契约可以基于它做面向前后端的分层设计,包括实体投影、读取归并、实体引用和结果联合。技术表达不必逐字照搬 Spec,也不要求 Spec 声明物理字段或传输编码;不得改变业务条件、授权、副作用或缺失事实的含义。
46
- - 页面入参不会自动成为后端契约 input;外部 RPC 参数也不会自动成为后端契约 input。
47
- - `visualPageLoad` 表达页面打开时对一个后端读模型的调用。它不列举内部 ER 读取,不规定查询顺序,也不阻止后端依据已取得的事实短路执行。
48
- - `binding` 只选择平台已有的协议类型和业务 operationType,不增加任何协议扩展字段。
49
- - 后端契约 ID 是实现切片的唯一机器身份,后端契约文件、Backend operation 目录和 Rust module 必须原样复用,任何层级都不得二次命名或格式转换。
50
- - 后端契约 input 类型必须显式声明,并与调用点绑定值的业务语义一致。若 Visual 的宽泛标量声明与 Structure 的封闭类型冲突,只有 Visual 的明确业务约束与 Structure 完全一致时,才可采用 Structure 类型继续产出并记录 Spec finding;否则不得自行收窄。
51
- - `discriminatedUnion` 只是在后端契约中描述互斥 JSON 形状的程序结构,不是业务建模。判别字段必须来自 Structure 的已有封闭枚举;case key 直接复用枚举值,不得新增“结果类型”等无来源业务字段。
52
- - 跨实体事实形成的结果可使用 `flowResult`,线上固定为 `case + data`。case 是契约分支标识,不是 Structure 字段,也不是页面路由指令;不能要求 Spec 为它新增业务枚举。保留上述单字段 `discriminatedUnion`,两者不混用。
53
- - 正式实体引用使用 `entityReference`,目标实体由契约声明,线上为不透明字符串,前端原样回传,后端解析并独立校验权限。不假定引用等于数据库 uid,不因 external 实体未声明 ID 属性而认定业务模型缺少身份。
54
- - 新版 Business Flow Graph 使用 `visualFlow` 调用点,关联真实页面组件及板块/节点,不虚构旧 Paragraph 身份。元数据唯一解析是验证要求,不代表现有消费者已经支持新格式。
55
- - 公开业务 Entry 可以使用 `flowEntry` 作为调用来源;没有本域页面时不虚构页面。终止 Logic 的公开交付也可以形成结果 case,不强制补造 Visual。具体规则见契约参考;不能因此将任意后台事件或外部 RPC 自动暴露成后端契约。
56
- - 除非 Visual 明确将其定义为用户可观察的业务信息,否则不得暴露路由、服务商、链路追踪、物理地址、适配器或审计事实。
57
- - 一段不完整流程只阻塞受影响的契约,不阻塞项目其余部分。
58
- - Spec 是业务输入,后端契约和本模块 是设计输出。不得让 Spec 为满足传输格式而新增实体或接口声明;只有业务含义确实缺失或冲突才反馈 Spec 问题。
59
- - 审查投影时覆盖后续纯前端导航和重试。实体引用不是完整实体数据,页面需要的名称、关联和业务值必须有可取得的投影;重试应使用流程实际交付的当前上下文,不能默认入口上下文在写入后仍有效。
60
- - 页面呈现的跨域办理意图不等于本域存在可调用流程。没有真实办理合同和调用点时,不复制查询结果构造确认接口。
17
+ - 字段集合、类型、可空性、合法枚举、单位、时刻格式及错误码含义由契约完整定义,不交给前后端各自约定。使用[模板](assets/backend-contract.template.yaml),清除示例占位。
18
+ - 后端契约不包含SQL、代码组织、代码生成配置、外部RPC调用顺序或profusecontract实现。id与文件名按格式规范一致,不把实现目录约定混入业务字段。
19
+ - 后端若明确保证同一响应中对象归属一致,前端可以消费该保证而不重复身份字段。必须有来源依据及明确结果约束,不能取消源业务条件;若要求独立身份比较或跨请求回传,另核对真实身份需求。
20
+ - 字段省略不等于null,零金额不等于空结果,查询失败不等于无业务数据。展示文案、时间格式化和页面组织归前端。
21
+ - 一般按Prototype+测试所需字段投影;用户确认简单实体字段扩展保留倾向时可保留,但注明来源与扩展理由,不声称页面已消费,不据此暴露敏感或内部路由事实。
22
+ - 技术错误与非技术失败边界必须互斥。未定义业务结果可按用户确认隔离并记录问题,不借错误码硬补已要求的业务语义。
23
+ - adapt的具体转换TODO不是自动阻塞;只对真正依赖它且无法唯一确定的字段或结果反馈。设计可完成不代表链路实现完成。
@@ -6,6 +6,8 @@
6
6
 
7
7
  使用受限 YAML:UTF-8 编码、与 JSON 兼容的数据值;禁止 alias、anchor、tag、merge key 和重复 key。
8
8
 
9
+ 线上对象只包含声明字段,所有字段必须出现,nullable仅允许显式null而非省略。type/ref/来源/invariants均为设计元数据,不是线上字段。文件内模型独立,不跨契约复用业务类型;types为空合法,不强迫请求结果起额外类型名。
10
+
9
11
  ## 必需的顶层结构
10
12
 
11
13
  ```yaml
@@ -26,7 +28,7 @@ coverage: []
26
28
 
27
29
  coverage 是必填设计元数据;旧八字段契约不能宣称符合新版设计门禁。严格只接受八字段的消费者需适配;现有项目应单独 review 后补关联,不捏造旧测试证据。
28
30
 
29
- 0.1.12 统一更名:格式标识为 `backend-contract/v1`,文件后缀为 `.backend-contract.yaml`。线上请求、响应、operationType 和契约 id 的语义不变,但文件发现规则与格式标识校验必须同步迁移;不得宣称旧消费者自动兼容。旧发布版本及历史交付不自动重写,项目迁移须单独获得授权。`callSites.api` 仍引用 Islands 逻辑 API,不属于本层名称。
31
+ 0.1.12 统一更名:格式标识为 `backend-contract/v1`,文件后缀为 `.backend-contract.yaml`。线上请求、响应、operationType 和契约 id 的语义不变,但文件发现规则与格式标识校验必须同步迁移;不得宣称旧消费者自动兼容。旧发布版本及历史交付不自动重写,项目迁移须单独获得授权。0.1.14使用Spec入口+adapt来源,不再接受callSites.api或旧逻辑API声明。
30
32
 
31
33
  ## 后端契约 ID
32
34
 
@@ -93,26 +95,7 @@ Visual 读取:
93
95
  - 输出仍须逐字段遵守下述来源规则,并由 Visual 的实际消费证明必要性;
94
96
  - 页面中彼此独立、刷新周期不同或业务语义不同的读取不得强行聚合。
95
97
 
96
- Visual 事务动作:
97
-
98
- ```yaml
99
- - kind: visualTransaction
100
- page: 欠费单查询
101
- pageBranch: 查询失败
102
- component: 重新查询
103
- transaction:
104
- paragraph: 查缴域·查账
105
- branch: 主分支
106
- transactionId: 查询并形成欠费单
107
- inputBindings:
108
- 临时查账资料: {actionInput: "&临时查账资料"}
109
- ```
110
-
111
- - 每个身份都必须通过 Compiler 元数据唯一解析。
112
- - 只有组件不属于任何页面分支时,才能省略 `pageBranch`。
113
- - 每个调用点都必须绑定全部非 nullable 输入;嵌套绑定的结构与 input schema 一致。
114
- - v1 支持的来源为 `pageInput`、`pageRead`、`actionInput` 和下述 `collectionItem`。格式本身缺少来源表达能力时修复 Skill,不登记为 Spec finding。
115
- - 绝不持久化源码数组下标或不稳定的生成 key。
98
+ 所有调用点都绑定全部定义输入,嵌套结构与input一致。位置使用真实稳定语义身份,不使用源码数组下标或旧Paragraph身份。
116
99
 
117
100
  新版 Business Flow 动作使用 `visualFlow`:
118
101
 
@@ -131,39 +114,43 @@ Visual 事务动作:
131
114
 
132
115
  Visual Form 的宽泛类型不自动构成业务类型冲突:应追溯真实赋值来源。若完整赋值链均来自同一 Structure 封闭枚举且无转换,可以在后端契约保留该枚举;不能仅依据同名字段猜测值域。
133
116
 
134
- 公开业务入口已有明确上游交互来源、且属于已确认前后端调用范围时,可以使用 `flowEntry`:
117
+ 公开入口以Spec板块/入口与adapt ingress共同定位,不要求逻辑API声明:
135
118
 
136
119
  ```yaml
137
120
  - kind: flowEntry
138
- flow: {board: 查询欠费单, entry: 上游已选定户号}
139
- api: 提交已选定户号查账
121
+ flow: {board: 查询账单, entry: 开始查询}
122
+ ingress:
123
+ path: example/adapt/ingress.binding.yaml
124
+ domain: 示例域
125
+ board: 查询账单
126
+ entry: 开始查询
140
127
  inputBindings:
141
- 已选定户号: {eventInput: 已选定户号}
128
+ 账户编号:
129
+ ingressField:
130
+ path: example/adapt/ingress.binding.yaml
131
+ domain: 示例域
132
+ board: 查询账单
133
+ entry: 开始查询
134
+ field: accountNumber
142
135
  ```
143
136
 
144
- entry 必须解析到真实板块入口,api 必须是该入口绑定的 Islands 逻辑 API,eventInput 必须是其真实参数;系统身份仍不进入客户端 input。这里的 api 是业务输入边界,不是外部 SOFA RPC。不能为了兼容旧格式虚构首页、页面加载或按钮,也不能将任意后台事件机械转换为 MobileGW 后端契约。
137
+ flowEntry必需kind/flow/ingress/inputBindings;ingress四键必须同时定位唯一条目,flow必须与目标一致。ingressField五键表达本次输入值来源;每个定义的输入(含nullable)均须绑定。不得使用旧api/eventInput,不能把任意后台事件自动暴露成MobileGW调用。无本域页面的真实公开入口不虚构页面。
138
+
139
+ 页面调用点仍使用pageInput/pageRead/actionInput/collectionItem绑定,位置必须真实存在;请求的业务含义还须遵守下述实体或ingress来源限制。旧Paragraph事务来源不用于当前Graph,按真实visualFlow或flowEntry定位。
145
140
 
146
141
  ## Schema 节点
147
142
 
148
- 每个节点都必须包含 `type` 和 `nullable`。
143
+ 每个节点都必须包含 `type` 和 `nullable`。object可附 `invariants`:非空字符串数组,表达该对象的实例来源、归属、字段关联、单位及组合约束。它是正式契约语义,不进入线上数据;每项须有Spec或已确认设计依据。应由coverage关联这些约束,不把约束只写在coverage解释里。
149
144
 
150
145
  标量类型为 `string / integer / decimal / boolean / date / datetime`:
151
146
 
152
147
  - `date`:RFC 3339 完整日期 `YYYY-MM-DD`。
153
- - `datetime`:带明确时区偏移的 RFC 3339 时间戳。
148
+ - `datetime`:UTC、固定毫秒精度的JSON字符串,唯一格式为 `YYYY-MM-DDTHH:mm:ss.SSSZ`;不接受Unix时间戳、无时区时间、非UTC偏移或可变小数秒精度。date/datetime不规定实现语言对象。
154
149
  - `integer`:位于约定运行时安全范围内的 JSON 整数。
155
150
  - `decimal`:使用精确的十进制 JSON 字符串,绝不使用二进制浮点数。业务正确性依赖精度和舍入时,来源语义必须定义二者。
156
151
  - `string`:不隐含格式。业务编码、月份等应有 Spec 业务依据;后端契约自有传输编码由契约规范定义,不要求业务 Spec 表达技术细节。
157
152
 
158
- 实体引用:
159
-
160
- ```yaml
161
- type: entityReference
162
- nullable: false
163
- entity: 机构
164
- ```
165
-
166
- `entity` 必须解析到真实 Structure 实体(包括 external),本身构成身份来源,不另外虚构一个 ID 属性作为 source。线上为不透明字符串;客户端保存和原样回传,后端恢复对应实体身份并校验当前权限。引用不构成授权,不等于展示名称、样例 Row 别名或数据库 uid。具体编码和运行时解析不由后端契约规定;不得宣称尚未实现的解析能力已可用。`nullable: true` 时允许 null。
153
+ 实体身份不能靠一个抽象entityReference让两端各自决定编码。本版请求优先采用真实实体属性或ingress字段,输出为具体字段投影。需要跨请求身份回传时,必须先按adapt确认真实身份及其传输字段;不为仅对象传递实体生成uid、token或映射。旧entityReference节点不用于新交付;它的删除不授权修改业务要求。
167
154
 
168
155
  枚举:
169
156
 
@@ -275,7 +262,7 @@ cases:
275
262
 
276
263
  `input` 是完整、显式的对象。名称必须携带完整业务含义,例如 `当前户号绑定ID`,绝不使用依赖周边语义才能理解的缩写。
277
264
 
278
- 每个 input 业务叶字段也必须声明 `source`,或声明完整的 `dependencies` 与 `derivation`。这里的来源表示字段在理想业务模型中的语义身份,不表示客户端值的传输来源:
265
+ 每个input业务叶字段必须声明直接source,限定为真实实体属性(含adapt扩展)或ingress外部字段,不通过派生表达制造第三类请求来源。source定义含义,inputBindings定义本次取值,两者都要核对:
279
266
 
280
267
  ```yaml
281
268
  费种:
@@ -285,9 +272,40 @@ cases:
285
272
  source: {entity: 户号, field: 费种}
286
273
  ```
287
274
 
288
- 来源定义在每个调用点的 `inputBindings` 中。Compiler 验证来源作用域和精确类型兼容性。不能仅因为 Logic、数据库或外部 RPC 需要某值,就增加客户端字段;后端应从系统内置能力、稳定标识、Structure、settings 和其他后端事实中取得这些值。系统内置提供的值不进入 `input` 或 `inputBindings`。
275
+ 取值来源定义在每个调用点的 `inputBindings` 中,须核对作用域和类型兼容性;这是设计校验要求,不宣称现有Compiler已实现adapt检查。不能仅因为Logic、数据库或外部RPC需要某值就增加客户端字段;系统内置提供的值不进入input或inputBindings。
289
276
 
290
- 若 Visual 把字段声明为宽泛标量,但同一页面的业务说明明确给出与 Structure 完全相同的封闭值域,可以采用 Structure 类型产出,同时在过程记录中保留 `type-conflict` Spec finding。缺少这组一致证据时必须停止受影响字段,不能仅凭字段名推断或收窄。
277
+ 入口字段保持来源类型;明确固定值可表达为单值enum。普通字符串的几个示例不构成封闭枚举,不自行增加长度、trim、空串拒绝或默认值。实体必填、请求nullable与DB可空列是不同合同。
278
+
279
+ ## adapt字段来源
280
+
281
+ 以下为source的新增封闭形状:
282
+
283
+ ```yaml
284
+ # 输入专用;仅source多一个kind,inputBindings.ingressField不带kind。
285
+ source:
286
+ kind: ingressField
287
+ path: example/adapt/ingress.binding.yaml
288
+ domain: 示例域
289
+ board: 查询账单
290
+ entry: 开始查询
291
+ field: accountNumber
292
+
293
+ # 实体扩展字段,可用于请求或结果,地位与Spec属性相同。
294
+ source:
295
+ kind: adaptEntityField
296
+ path: example/adapt/entities/机构代理.binding.yaml
297
+ domain: 示例域
298
+ entity: 机构代理
299
+ field: 机构代理编码
300
+ ```
301
+
302
+ ingressField只允许kind/path/domain/board/entry/field;adaptEntityField只允许kind/path/domain/entity/field。必须解析到真实字段,不能用入口field来源为响应添无实体根的透传字段。扩展字段的来源可用于下述派生dependencies。
303
+
304
+ ## 结果结构与约束
305
+
306
+ 如果对象+nullable已充分表达所有结果,不添加冗余case标签。需要互斥形状时仍按下述联合规则设计,不把一个业务的“单张或空”固化为所有业务规则。
307
+
308
+ 例如来源明确订单与所查账户一致,经确认由后端保证时,在output.invariants明确“返回订单属于同一响应的账户”。前端可消费该保证,不再重复身份字段;后端测试仍验证不串户。若前端必须独立比较身份,不能省略其必要字段。缺失字段不是null,零值不是无结果,相关可空字段的成对性必须写明。
291
309
 
292
310
  ## Output 来源
293
311
 
@@ -313,7 +331,7 @@ cases:
313
331
  derivation: 当前房东正常收款范围内的房间名称去重数量。
314
332
  ```
315
333
 
316
- `source` 表示精确的语义同一性;field 可使用点分路径定位实体内嵌结构的属性,每一段必须真实存在。`dependencies` 必须完整且非空;`derivation` 描述不含实现细节的确定性业务投影。容器节点不要求来源,但其所有业务叶字段都必须有来源;entityReference 以目标实体作为身份来源,flowResult 的技术标签以 case 来源及条件作为依据。
334
+ `source` 表示精确的语义同一性;field 可使用点分路径定位实体内嵌结构的属性,每一段必须真实存在。`dependencies` 必须完整且非空;`derivation` 描述不含实现细节的确定性业务投影。容器节点不要求叶字段source,但须通过invariants或调用上下文明确具体实例根及关联路径;其所有业务叶字段都必须有来源。flowResult的技术标签以case来源及条件作为依据。
317
335
 
318
336
  ## Flow Form 与 Rule 来源(0.1.9)
319
337
 
@@ -347,7 +365,7 @@ source:
347
365
 
348
366
  投影可以用已经证明的 case 代替临时答复的整体传输。必须证明页面及后续纯前端动作所需事实都能从结果取得,不能机械照搬所有页面内部入参,也不能用实体引用代替未提供的展示属性。重试调用点与写入后实际绑定同样属于契约完备性检查。
349
367
 
350
- 以上为 v1 来源能力的增量扩展,旧来源仍有效;消费方需支持新来源元数据。规范升级不代表现有生成器、运行时或校验器已经兼容。
368
+ 以上为 v1 来源能力的增量扩展,输出的实体、Form与Rule来源仍有效;Form/Rule不扩大请求来源范围,消费方需支持新来源元数据。规范升级不代表现有生成器、运行时或校验器已经兼容。
351
369
 
352
370
  ## Errors 与响应信封(线上结构)
353
371
 
@@ -377,6 +395,8 @@ source:
377
395
 
378
396
  消费方必须统一运行时信封;仅升级设计文档不代表已有实现已迁移。迁移不得改变业务 output、错误码意义或具体后端契约的结果分支。
379
397
 
398
+ 技术异常归TECHNICAL_FAILURE;若使用BUSINESS_RESULT_UNDEFINED,只承接非技术原因未形成合法业务结果,二者不能按发生环节任选。具体项目可以有其他有明确依据的错误码,不强制每个接口都包含上述两码。
399
+
380
400
  当 Spec 明确表示某些状态不得映射为已定义业务结果、但尚未为其定义精确结果时,可以增加一个 fail-closed error 继续交付已明确部分。该 error 必须:
381
401
 
382
402
  - 只说明“未形成当前契约已定义的结果”,不替 Spec 分类或解释具体原因;
@@ -2,6 +2,10 @@
2
2
 
3
3
  覆盖元数据与后端契约同生命周期,放在每份后端契约文件顶层 `coverage`,不进入线上请求/响应,也不是运行测试日志。实体 source 表达字段业务来源,callSites 表达调用位置,coverage 表达为何足以支撑输入要求;三者不能互相替代。
4
4
 
5
+ 针对当前Islands,先读取test list及相关test show的正式责任与操作断言。逻辑测试的Row身份、世界数据库、Mock不能直接要求生产生成对应表或身份token:根据adapt承载重述其业务义务,保留正确对象、依赖实参、本次答复及不写入等保证。无法对应时报告,不把责任编号存在当作全覆盖。Prototype组件通过Visual稳定语义定位,并检查实际原型消费,不只挂页面总链接。
6
+
7
+ 跨字段、归属和空值条件应先进入output或所属object的invariants,coverage约束项可指向该数组。页面显示事实、后端保障和纯前端动作分别核对;不为已确认由后端保证的关系重复身份字段,也不以此删除对应测试义务。扩展字段保留倾向须用户确认,不将未消费字段虚构为Prototype责任。
8
+
5
9
  ## 形状
6
10
 
7
11
  `coverage` 为非空数组,每项必填且只允许 `id / prototypes / tests / obligations`。id 是文件内唯一的稳定语义标识,不使用数组序号。
@@ -2,6 +2,8 @@
2
2
 
3
3
  当 Spec 无法支持完整契约时记录 finding。Finding 是诊断,不是后端契约字段,也不构成自行增加业务 fallback 的授权。Skill 或 v1 格式自身的表达能力问题应修复 Skill,不登记成项目 Spec finding。
4
4
 
5
+ adapt输入缺失、身份约定待定及消费者迁移问题单独反馈,不归为Spec业务缺陷。已授权维护Skill时先推导合理设计并确认规则,再补规范,不能让旧格式反向限制业务。仅缺具体适配实现、不影响输入输出时继续设计明确部分。
6
+
5
7
  Finding 写入调用方指定的过程记录位置;未指定时只在交付说明中报告。不得在正式 `code/backend-contract` 目录创建 findings 文件。
6
8
 
7
9
  ```yaml
@@ -14,7 +16,7 @@ findings:
14
16
  contractCandidate: query_bill_input_model
15
17
  path: callSites
16
18
  evidence:
17
- - {kind: logicTransaction, paragraph: 查缴域·查账, branch: 主分支, transactionId: 查询并形成欠费单}
19
+ - {kind: logic, board: 查询欠费单, node: 查询欠费单}
18
20
  - {kind: visualPage, page: 欠费单查询}
19
21
  message: Logic 要求取得动态字段协议后接收用户输入,但 Visual 中不存在取得并展示该协议的调用点。
20
22
  requiredUpstreamChange: 增加承载输入模型的 Visual 状态,以及取得模型并绑定提交动作的精确读取或动作。
@@ -1,7 +1,11 @@
1
1
  schemaVersion: saddle-db-table/v1
2
2
  entity:
3
3
  source: {entity: 替换为内部持久化实体}
4
- persistenceReason: 替换为可追溯的跨事务持久化原因。
4
+ persistenceBinding:
5
+ path: 替换为adapt实体文件仓库相对路径
6
+ domain: 替换为业务域
7
+ entity: 替换为内部持久化实体
8
+ persistenceReason: 替换为明确的adapt本地持久化声明依据。
5
9
  table:
6
10
  name: 替换为同一个Structure实体名
7
11
  comment: 替换为表的业务语义。
@@ -28,6 +32,8 @@ systemColumns:
28
32
  default: false
29
33
  maintainedBy: saddle
30
34
  readPolicy: exclude_deleted_by_default
35
+ # columns包含Spec与adapt扩展的全部属性;来源不同不改变列规则。
36
+ # 实体关联须添加storesEntityIdentity及目标adapt来源,参见格式规范。
31
37
  columns:
32
38
  替换为Structure字段名:
33
39
  type: {kind: varchar, length: 64}
@@ -1,45 +1,22 @@
1
+ # DB设计
1
2
 
2
- # Saddle DB 设计
3
+ 消费Spec+adapt,产出逻辑表结构。先读共用adapt规则,再完整阅读[表格式](references/db-table-v1.md)。后端契约用于一致性复核,不是建表前提;数据库也不能由响应模型反向生成。
3
4
 
4
- 从 Islands Spec 确定性产出 Saddle 拥有的逻辑表契约。数据库设计覆盖后端契约、系统事务、定时任务、消息和回调等全部 Saddle 持久化责任;后端契约只是可选入口,不是建表前提。
5
+ ## 推演顺序
5
6
 
6
- 执行前必须阅读 [references/db-table-v1.md](references/db-table-v1.md)。遇到实体归属、生命周期、字段来源、类型或事务责任无法唯一确定时,阅读 [references/findings.md](references/findings.md)。
7
+ 1. 核对所有相关实体的adapt承载声明:本地持久化实体建表,不持久化和代码静态实体不建实体表。声明缺失或矛盾先反馈;不以未见写操作推翻明确承载,也不由Spec旧external标记推导。
8
+ 2. 合并Spec原始属性与adapt扩展属性。二者在物理设计上都是实体属性,只是来源不同;持久化实体全部正常落列。
9
+ 3. 逐个关联核对目标身份:本地uid、静态固定主键、原生标识或已确认身份映射。不能一律存uid,不能存展示名称代替身份,不能自行给仅对象传递实体增加映射。
10
+ 4. 按已确认规则定义系统列、基础类型、长度档位、可空性。DB宽松约束与业务必填分开,不自行增加唯一性、外键或索引。
11
+ 5. 记录输入已明确的Logic持久访问责任,不将内存字段消费或传入Dependency推导成独立DB查询,不补同步、建档和外部CRUD。未完成适配影响访问计划不等于表结构不成立。
12
+ 6. 复核表集合、完整属性、关联方向和身份、后端契约非空结果与DB可空列的区别。后端契约不需要展示的本地属性仍可落列;非持久化返回对象不建表。
7
13
 
8
- ## 输入
14
+ 使用[模板](assets/table.template.yaml)。每表一份实体名.table.yaml,交付目录只放表契约,不放findings、DDL、物理名称映射、迁移或测试工具。局部问题直接报告或进入用户指定过程位置;见[findings](references/findings.md)。
9
15
 
10
- - 用户明确提供的交付目录;不得自行改用固定仓库路径。
11
- - 已编译 Islands Spec 中相关 Structure、Logic、Rule 与 Test Responsibility。
12
- - 已确认的后端契约可作为事务入口证据,但不是必需输入。
13
-
14
- ## 工作流程
15
-
16
- 1. 从 Logic 生命周期识别必须跨事务保留并在后续读取、更新或判定的事实。
17
- 2. 回到 Structure 确认实体所有权。只有未声明 `external: true` 的实体才可能建表;本地所有权不自动等于需要持久化。
18
- 3. 每个需要持久化的具体实体产出一个完整表契约。表与业务列原样复用 Structure 实体和字段身份,并包含全部 Structure 字段。
19
- 4. 子实体表展开全部继承字段。父实体只有存在独立持久化生命周期时才单独建表。
20
- 5. 精确关联每个访问该表的 Logic 事务及其读写字段。事务由后端契约承载时可附加 `backendContractId`,但不得用后端契约身份替代 Logic 事务身份。
21
- 6. 跨文件检查逻辑表身份唯一、字段来源可解析、关联目标存在、类型完整。
22
- 7. 只交付完整表文件。局部不确定项按 findings 规则报告,不用临时字段、宽泛类型或冗余表绕过。
23
-
24
- ## 产出
25
-
26
- - 在用户指定的 DB 交付目录中,每个持久化实体产出一个 `<Structure实体名>.table.yaml`。
27
- - DB 交付目录只放正式表契约。Findings 写入用户指定的过程协作位置;未指定时直接反馈给用户,不在交付目录落盘。
28
-
29
- 使用 [assets/table.template.yaml](assets/table.template.yaml) 作为起始结构。交付文件不得包含 TODO、占位符、阻塞标记或诊断节点。
16
+ ## 固定边界
30
17
 
31
- 不生成物理表名/列名映射、索引、外键、唯一约束、CHECK、DDL、迁移脚本或数据库访问代码。Saddle 的必填映射能力只负责逻辑表名/列名到物理标识符的映射,不拥有其他表结构设计权。
18
+ 保持uid、gmt_create、gmt_modified、is_deleted四列;统一UUIDv7和软删除。业务列nullable为true且无数据库默认值,业务必填与关系合法性由业务逻辑保证。关联角色沿实体字段名,不翻译成无差别的“引用ID”。
32
19
 
33
- ## 固定边界
20
+ Saddle物理映射只改表名列名,不改变列集合、类型、默认值、主键和系统语义。数据库实例时区、字符集及运行期索引优化不属于此设计。人民币金额采用BIGINT分存储,长文本支持TEXT;没有本地金额或长文本字段就不凭空新增。
34
21
 
35
- - 表契约使用 MySQL 基础类型,但逻辑表名和业务列名保持 Islands 原始业务概念。
36
- - 每张表固定使用 `uid`、`gmt_create`、`gmt_modified`、`is_deleted` 四个系统列;业务 Agent 不增删或改写其语义。
37
- - 所有业务字段允许 `NULL`,且不设置数据库默认值。必填、枚举、值域、业务唯一性和关联完整性由 Saddle 业务逻辑负责。
38
- - 不设计业务唯一约束、普通索引或数据库外键。索引属于运行后的观测与运维优化。
39
- - 实体关联字段保留 Structure 的关联业务语义;内部关联存目标 uid,external 关联存可长期解析的外部身份引用,不强制本地 UUID。多重关联依靠原始角色语义区分。不得为制造 uid 而给 external 实体建表,也不要求业务 Spec 定义技术编码。
40
- - varchar 使用已确认的长度分档;人民币金额沿用有符号 BIGINT 分存储,不沿用后端契约的元字符串作为物理列类型。
41
- - 文章正文等长文本可使用 `type: {kind: text}`,对应 MySQL TEXT,不填写 length。仍需真实 Structure 字段来源、nullable 为 true 且无默认值;TEXT 不是无限容量,也不用于绕过不明确的结构化建模。具体容量边界见类型参考。
42
- - 新版 Flow 使用真实板块/节点记录 Logic、Branch 访问责任,也覆盖 Visual 的持久读取;不虚构旧 Paragraph/Transaction。已传入 Row 的纯内存消费不等于再次读库。
43
- - 删除统一为软删除。Saddle 数据访问层必须对普通读取强制过滤 `is_deleted = false`;业务查询不得各自实现这条规则。
44
- - 把业务状态更新为“已删除”仍是 update,不等于实体 delete,不自动联动 is_deleted。
45
- - 一个不完整实体只阻塞对应表,不阻塞其他完整表的交付。
22
+ 外部身份映射仅在用户明确配置且结构依据充分时设计;当前只有语义没有映射结构的输入,应反馈其缺失,不自动发明额外表。
@@ -1,104 +1,33 @@
1
- # Saddle DB 逻辑表契约 v1
1
+ # Saddle DB逻辑表契约v1
2
2
 
3
- 0.1.4 命名调整:可选的后端契约关联键统一为 `backendContractId`,旧键 `apiId` 不用于新交付。其值仍为对应后端契约的 `id`,不替代 Logic 事务身份。现有表文件与消费者需单独迁移,不能宣称旧消费者自动兼容;表结构和运行时存储语义不变。
3
+ 一个本地持久化实体对应一张逻辑表,文件名为实体名.table.yaml,table.name与entity.source.entity必须一致。中文逻辑名称合法;Saddle必填物理映射只改表名列名,不得改变结构、类型或系统语义,本Skill不产出物理映射。
4
4
 
5
- ## 设计单位与身份
5
+ ## 必需结构
6
6
 
7
- 一个 `*.table.yaml` 只定义一个 Saddle 内部持久化实体的一张逻辑表。v1 不支持一个实体拆多表或多实体合表;遇到该场景产出 `unsupported-shape` finding。
8
-
9
- 逻辑表身份直接复用 Islands Structure 实体名。文件固定命名为 `<Structure实体名>.table.yaml`,`table.name`、`entity.source.entity` 和文件名 stem 必须原样一致。中文业务身份合法,不翻译为物理标识符。
10
-
11
- Saddle 的必填物理映射配置负责逻辑表名/列名到 MySQL 表名/列名的映射。映射层只改名字,不得改变字段集合、类型、nullable、默认值、主键或系统语义;物理映射不属于本 Skill 产物。
12
-
13
- ## 完整结构
7
+ 顶层仅允许且必须包含schemaVersion/entity/table/systemColumns/columns/accessResponsibilities。schemaVersion固定saddle-db-table/v1。
14
8
 
15
9
  ```yaml
16
- schemaVersion: saddle-db-table/v1
17
10
  entity:
18
- source: {entity: 用户账单}
19
- persistenceReason: 用户账单由本系统创建并跨事务保留,供后续查询和状态更新。
11
+ source: {entity: 机构代理}
12
+ persistenceBinding:
13
+ path: example/adapt/entities/机构代理.binding.yaml
14
+ domain: 示例域
15
+ entity: 机构代理
16
+ persistenceReason: adapt明确声明本地持久化实体,身份为Saddle标准uid。
20
17
  table:
21
- name: 用户账单
22
- comment: 用户账单持久化事实
23
- systemColumns:
24
- uid:
25
- type: {kind: varchar, length: 32}
26
- nullable: false
27
- primaryKey: true
28
- generation: {owner: saddle, algorithm: uuid_v7, format: lowercase_hex_without_hyphens}
29
- gmt_create:
30
- type: {kind: datetime, precision: 3}
31
- nullable: false
32
- default: current_timestamp
33
- maintainedBy: database
34
- gmt_modified:
35
- type: {kind: datetime, precision: 3}
36
- nullable: false
37
- default: current_timestamp
38
- onUpdate: current_timestamp
39
- maintainedBy: database
40
- is_deleted:
41
- type: {kind: boolean}
42
- nullable: false
43
- default: false
44
- maintainedBy: saddle
45
- readPolicy: exclude_deleted_by_default
46
- columns:
47
- 账单标识:
48
- type: {kind: varchar, length: 64}
49
- nullable: true
50
- comment: 用户账单的业务标识
51
- source: {entity: 用户账单, field: 账单标识}
52
- 所属用户:
53
- type: {kind: varchar, length: 32}
54
- nullable: true
55
- comment: 关联用户的 uid
56
- source: {entity: 用户账单, field: 所属用户}
57
- storesEntityUid: {entity: 用户}
58
- 应缴金额:
59
- type: {kind: bigint}
60
- nullable: true
61
- comment: 应缴金额,单位为人民币分
62
- money: {currency: CNY, unit: minor, minorUnitsPerMajor: 100}
63
- source: {entity: 用户账单, field: 应缴金额}
64
- accessResponsibilities:
65
- - transaction:
66
- paragraph: 账单域·账单维护
67
- branch: 主分支
68
- transactionId: 创建用户账单
69
- backendContractId: create_user_bill
70
- operations:
71
- - kind: insert
72
- columns: [账单标识, 所属用户, 应缴金额]
73
- predicateColumns: []
74
- - transaction:
75
- paragraph: 账单域·账单维护
76
- branch: 主分支
77
- transactionId: 查询用户账单
78
- operations:
79
- - kind: read
80
- columns: [账单标识, 所属用户, 应缴金额]
81
- predicateColumns: [所属用户]
18
+ name: 机构代理
19
+ comment: 机构代理实体的本地持久化
82
20
  ```
83
21
 
84
- 顶层字段 `schemaVersion / entity / table / systemColumns / columns / accessResponsibilities` 全部必填,禁止未知顶层字段。示例中的 `backendContractId` 可省略;其他示例身份和内容必须替换为真实编译来源。
85
-
86
- ## 持久化判定
22
+ entity必需source/persistenceBinding/persistenceReason。persistenceBinding与身份来源必须解析到对应adapt条目;reason说明依据,不替代声明。table必需name/comment。完整系统列见[模板](../assets/table.template.yaml)。
87
23
 
88
- DB 设计覆盖 Saddle 拥有的全部持久化事实,不以是否存在后端契约为边界。只有同时满足以下条件的实体才产出表:
24
+ ## 建表与字段集合
89
25
 
90
- 1. 实体未声明 `external: true`;
91
- 2. Logic 明确要求该事实跨事务保留;
92
- 3. 后续 Logic 会读取、更新、删除或据此判定;
93
- 4. 实体生命周期和所有权可以唯一确定。
26
+ adapt明确本地持久化才建实体表;不持久化实体和代码静态实体不建表。不检查Spec旧external标记,不强制先有本地写入流程。已明确同步到本地的实体可以持久化,但同步实现不能由表结构反向推导。
94
27
 
95
- 以下内容不建表:`external: true` 的实体;只由外部 SOFA RPC 维护的事实;页面状态、后端契约返回模型 或请求内临时对象;一次 External 调用的临时快照;没有独立持久化生命周期的可重算结果。
28
+ columns完整覆盖该实体的Spec属性与adapt扩展属性。二者同等落列;不因未被后端契约输出而省略,也不因前端显示需要而给非持久化实体建表。
96
29
 
97
- “页面需要展示”“后端契约需要返回”或“Structure 中存在实体”本身都不构成持久化理由。
98
-
99
- ## 实体与继承
100
-
101
- 一个需要持久化的具体实体对应一张逻辑表,并包含其全部 Structure 字段。子实体表直接展开父实体继承的全部字段;继承字段的 `source` 指向其原始声明实体和字段。父实体只有存在独立持久化生命周期时才单独建表。v1 不设计父子表连接或其他数据库继承策略。
30
+ 若输入使用继承,按来源明确的继承属性展开,source指向实际声明;所有实体承载仍以adapt为准。抽象父实体、拆表或继承结构未明确时反馈,不从未声明生命周期猜表。
102
31
 
103
32
  ## 系统列
104
33
 
@@ -113,64 +42,85 @@ DB 设计覆盖 Saddle 拥有的全部持久化事实,不以是否存在后端
113
42
 
114
43
  Saddle 数据访问层必须对所有普通读取强制施加 `is_deleted = false`。只有明确的恢复、审计或运维能力可以读取已删除记录。普通业务查询不得自行重复实现或绕过默认过滤。关联到已软删除记录时,业务上视为目标不存在。
115
44
 
116
- ## 业务列与来源
117
45
 
118
- `columns` 必须包含实体的全部 Structure 字段。每个业务列名原样复用 Structure 字段名,并具有且仅具有一个直接来源:
46
+ ## 业务字段来源
47
+
48
+ 所有业务列nullable固定true,无default或onUpdate。业务必填、值域、唯一性和关联正确性由业务逻辑保证,不能将数据库null当作后端契约成功结果的合法值。
49
+
50
+ 每列必需type/nullable/source,可有comment、money、storesEntityIdentity;字段名保留原实体属性角色。普通属性:
51
+
52
+ ```yaml
53
+ source: {entity: 机构, field: 机构名称}
54
+ ```
55
+
56
+ adapt扩展属性:
119
57
 
120
58
  ```yaml
121
- source: {entity: 用户账单, field: 账单状态}
59
+ source:
60
+ kind: adaptEntityField
61
+ path: example/adapt/entities/机构代理.binding.yaml
62
+ domain: 示例域
63
+ entity: 机构代理
64
+ field: 机构代理编码
122
65
  ```
123
66
 
124
- 所有业务列固定 `nullable: true`,不允许 `default` 或 `onUpdate`。Structure 的必填、枚举和值域仍是业务规则,由 Saddle 逻辑校验,不下沉为数据库约束。
67
+ 扩展来源kind/path/domain/entity/field五键必须同时定位真实声明。来源不同不是另一种列类型。系统列单独定义,不伪造其Spec来源。
125
68
 
126
- 内部实体关联保留原始业务角色名,并存储目标实体的 `uid`:
69
+ ## 关联身份
70
+
71
+ 每个实体关联列必需storesEntityIdentity,非关联列不使用。包含且仅包含entity/strategy/source;source为目标实体的adapt位置{path,domain,entity},必须与关联目标一致。
127
72
 
128
73
  ```yaml
129
- 卖家:
74
+ 机构:
130
75
  type: {kind: varchar, length: 32}
131
76
  nullable: true
132
- source: {entity: 订单, field: 卖家}
133
- storesEntityUid: {entity: 用户}
134
- 买家:
135
- type: {kind: varchar, length: 32}
77
+ source: {entity: 机构代理, field: 机构}
78
+ storesEntityIdentity:
79
+ entity: 机构
80
+ strategy: saddle_uid
81
+ source: {path: example/adapt/entities/机构.binding.yaml, domain: 示例域, entity: 机构}
82
+
83
+ 费种:
84
+ type: {kind: varchar, length: 64}
136
85
  nullable: true
137
- source: {entity: 订单, field: 买家}
138
- storesEntityUid: {entity: 用户}
86
+ source: {entity: 机构, field: 费种}
87
+ storesEntityIdentity:
88
+ entity: 费种
89
+ strategy: fixed_primary_key
90
+ source: {path: example/adapt/entities/费种.binding.yaml, domain: 示例域, entity: 费种}
139
91
  ```
140
92
 
141
- 同一目标实体被多次关联时,以 Structure 中不同的关联角色区分。不得改成含义不清的统一“用户”列,也不建立数据库外键。
93
+ strategy只允许如下值,并与adapt身份一一核对:
142
94
 
143
- external 关联使用 `storesExternalReference`,与 `storesEntityUid` 互斥:
95
+ | strategy | adapt身份 | 存储 |
96
+ | --- | --- | --- |
97
+ | saddle_uid | Saddle标准uid | varchar(32),目标本地实体uid |
98
+ | fixed_primary_key | 固定主键 | 目标静态实例主键,按明确值类型与长度选基本类型;当前字符串编码按64档 |
99
+ | external_native_id | 外部原生标识 | 已声明稳定原生标识,不能猜成内部uid |
100
+ | external_mapped_uid | 外部身份映射 | 已确认映射的本地标准uid,varchar(32);要求映射定义已充分 |
144
101
 
145
- ```yaml
146
- 户号:
147
- type: {kind: varchar, length: 256}
148
- nullable: true
149
- comment: 可长期解析的外部户号身份,包含区分机构和费种的身份语义。
150
- source: {entity: 户号绑定关系, field: 户号}
151
- storesExternalReference: {entity: 户号}
152
- ```
102
+ 目标仅对象传递则不允许持久身份引用;报告配置冲突,不为它创建映射。外部身份映射结构不足时不生成猜测表,也不宣称引用可解。固定主键与原生ID不能用展示名称代替,保存值不得截断。
153
103
 
154
- 目标必须是真实 external 实体。引用必须跨请求持续定位同一外部身份,不强制本地 UUIDv7,不用可能重名的展示字段代替身份,不把有失效期的后端契约令牌直接作为长期关联。长度是引用实现必须遵守的存储上界;不能静默截断,也不能宣称未知编码已经验证可用。具体编码和解析由实现层承担,出现冲突反馈讨论,不要求业务 Spec 表达技术细节。不因此新增本地映射表或 external 镜像表。
104
+ 相同目标的不同业务角色保留不同列,例如买家和卖家;不为“都是用户引用”合并一列。不使用storesEntityUid/storesExternalReference双轨旧结构;不生成外键、业务唯一键或代理复合主键。
155
105
 
156
106
  ## 基础 MySQL 类型
157
107
 
158
108
  v1 只允许以下封闭类型:
159
109
 
160
110
  ```yaml
161
- {kind: varchar, length: 64}
162
- {kind: text}
163
- {kind: bigint}
164
- {kind: decimal, precision: 18, scale: 2}
165
- {kind: boolean}
166
- {kind: date}
167
- {kind: datetime, precision: 3}
111
+ - {kind: varchar, length: 64}
112
+ - {kind: text}
113
+ - {kind: bigint}
114
+ - {kind: decimal, precision: 18, scale: 2}
115
+ - {kind: boolean}
116
+ - {kind: date}
117
+ - {kind: datetime, precision: 3}
168
118
  ```
169
119
 
170
- - `varchar.length` 默认采用已确认的64/256/1024档:标识符、编码、户号文本、枚举64;名称256;地址1024。明确的项目约定优先。外部复合身份引用不是裸户号文本,应按已确认编码预算选档;例如 bill 的用户引用64、户号引用256。内部 uid 固定32。不要求 Spec 精确给出数据库长度;超出已选上界或需要新类型时讨论,不静默截断。
120
+ - `varchar.length` 默认采用已确认的64/256/1024档:标识符、编码、户号文本、枚举64;名称256;地址1024。明确的项目约定优先。外部复合身份引用不是裸户号文本,应按已确认编码预算选档;不得把历史项目外部引用长度当作新项目身份编码。内部 uid 固定32。不要求 Spec 精确给出数据库长度;超出已选上界或需要新类型时讨论,不静默截断。
171
121
  - `bigint` 固定生成 MySQL 64 位有符号整数。
172
122
  - `text` 对应 MySQL `TEXT`,类型节点仅为 `{kind: text}`,不允许 length、precision 或 scale。适用于文章正文等有明确业务含义的长文本,不强制按 varchar 的长度分档。最大容量为 65,535 字节而非字符数,可容纳字符数取决于数据库字符集;环境字符集仍由运维负责,不新增实例配置。业务长度与内容格式由业务逻辑处理,不生成数据库约束,不静默截断。明确超过 TEXT 容量时反馈讨论,不自动升级 MEDIUMTEXT/LONGTEXT。依据:[MySQL 字符串类型](https://dev.mysql.com/doc/refman/8.4/en/string-type-syntax.html)。
173
- - TEXT 字段继续使用 `nullable: true`、无数据库默认值和原始 Structure 字段来源。仅选择存储类型,不擅自规定正文是纯文本、HTML 或 Markdown,也不因正文可能很长而另拆表、增加索引或生成 DDL。不能用 TEXT 序列化未知对象来绕过未支持的结构或关联。
123
+ - TEXT 字段继续使用 `nullable: true`、无数据库默认值和Spec或adapt实体属性来源。仅选择存储类型,不擅自规定正文是纯文本、HTML 或 Markdown,也不因正文可能很长而另拆表、增加索引或生成 DDL。不能用 TEXT 序列化未知对象来绕过未支持的结构或关联。
174
124
  - `decimal` 必须明确 precision、scale 和单位;精度与小数位来自 Structure/Rule。
175
125
  - 人民币金额使用有符号 `bigint` 保存分,附加 `money: {currency: CNY, unit: minor, minorUnitsPerMajor: 100}`;与后端契约的元精确十进制字符串在应用边界准确换算,不使用二进制浮点数。非负等业务值域仍由业务逻辑负责。其他币种或需要不足一分的精度时先讨论,不套用人民币比例。没有本地金额字段时不为使用此规则新增字段或表。
176
126
  - `boolean` 固定生成 MySQL `TINYINT(1)`,但契约保留布尔业务语义。
@@ -201,53 +151,34 @@ v1 只允许以下封闭类型:
201
151
 
202
152
  业务唯一性、关联一致性、必填和值域校验由 Saddle 业务逻辑实现。索引属于系统运行后的性能观测和运维优化,不在初始表结构设计阶段预判。
203
153
 
204
- ## Logic 事务访问责任
205
-
206
- `accessResponsibilities` 穷举当前表支持的 Logic 事务读写责任。事务身份必须通过 Islands Compiler 元数据唯一解析:
207
154
 
208
- ```yaml
209
- transaction:
210
- paragraph: 查缴域·查账
211
- branch: 主分支
212
- transactionId: 查询并形成欠费单
213
- ```
155
+ ## 已声明的持久访问责任
214
156
 
215
- 事务可以来自人工后端契约、系统事务、定时任务、消息或回调。`backendContractId` 仅在该事务由已确认后端契约承载时出现,并必须解析到对应后端契约。
157
+ accessResponsibilities记录当前输入明确的直接持久操作,不是完整后端执行计划。没有可定位的直接操作可为[];不代表表不会被访问、没有价值或禁止实现加载。不能因此省略明确的本地持久化表。已知操作不能遗漏,未填写adapt实现不能被猜成按编码查询或同步任务。
216
158
 
217
- 每个 operation:
218
-
219
- - `kind` 只允许 `read / insert / update / delete`;
220
- - `columns` 精确列出读取、插入或变更的逻辑业务列;
221
- - `predicateColumns` 精确列出定位、关联或筛选使用的逻辑业务列;
222
- - 不记录 SQL、索引或物理列名;
223
- - `delete` 表达 Logic 删除语义,运行时固定执行软删除,不执行物理 `DELETE`。
224
-
225
- 系统列生成、时间维护和默认软删除过滤是 Saddle 固定责任,不在每个 operation 中重复列出。
226
-
227
- ### 新版 Flow 与 Visual 来源
228
-
229
- 每项责任用 `transaction`(旧结构)或 `source`(新结构)之一,不能同时填写。新版 source 支持:
159
+ 每项必需source/operations,可选backendContractId/atomic。source只采用当前Graph/Visual稳定身份:
230
160
 
231
161
  ```yaml
232
- source: {kind: logic, board: 查询欠费单, node: 替换为新户号绑定}
233
- source: {kind: branch, board: 查询欠费单, node: 校验户号绑定}
234
- source: {kind: visualRead, page: 查询户号, read: $本人绑定列表}
162
+ accessResponsibilities:
163
+ - source: {kind: logic, board: 查询账单, node: 查询服务商}
164
+ backendContractId: query_bill
165
+ operations:
166
+ - kind: read
167
+ columns: [服务商]
168
+ predicateColumns: [机构]
235
169
  ```
236
170
 
237
- 节点类型必须与来源一致;名字通过编译元数据或稳定源码身份解析,不保存数组下标。责任覆盖当前持久查询和写入,不把每个页面对已传入 Row 的内存读取都编造为独立数据库查询;后端契约引用解析需要的按 uid 加载属于运行时实现责任,不能虚构 Spec 事务。
171
+ source支持{kind:logic,board,node}、{kind:branch,board,node}、{kind:visualRead,page,read},类型需与来源一致,不使用旧Paragraph事务。backendContractId指真实契约id,不替代节点身份。
238
172
 
239
- Logic 责任可附 `atomic: true` 表示来源明确要求该节点的多项操作同一事务提交,不代表整条后端契约链路或外部调用具备原子性。更新传入 Row 时 operation 可附 `targetInput: 当前绑定`:必须对应该节点真实 Row 入参,通过其实体身份定位目标行;不把 uid 塞入业务 predicateColumns,也不把空 predicateColumns 解释为全表更新。新建行及同节点后续赋值可以合为一个 insert 责任,但必须包含全部赋值列。
173
+ operation必需kind/columns/predicateColumns;kind仅read/insert/update/delete,字段必须在当前业务列中。读取或变更列与筛选列分别说明,不写SQL、索引或物理列名。显式按入参身份更新可有targetInput,必须定位真实Row输入;空predicateColumns不表示全表操作。atomic:true仅当来源已确认原子要求,不声称跨RPC原子性。
240
174
 
241
- Spec 把业务状态写为“已删除”时,记录 update 和相应业务列,不推导额外的 is_deleted 更新。只有实体 delete 语义才执行统一软删除。
175
+ 关联对象已在内存时字段消费不另列DB查询;不能为每个页面值生成独立事务。适配实现尚未确定的访问计划单独反馈,不在正式表文件写TODO或阻塞节点。所有明确写入与delete仍必须记录,delete统一软删除;状态字段赋值“已删除”仍为update,不自行联动is_deleted。
242
176
 
243
- ## 完成门禁
177
+ ## 完成检查
244
178
 
245
- 1. 实体已证明为 Saddle 内部持久化实体,且不是 `external: true`;
246
- 2. 文件名、`table.name` 和 Structure 实体身份原样一致;
247
- 3. 表包含固定且完整的四个系统列;
248
- 4. 全部 Structure 字段均出现,且每个业务列解析到唯一 Structure 字段;
249
- 5. 内部关联声明 storesEntityUid;external 关联声明 storesExternalReference,引用稳定且长度明确;两者互斥,多重关联角色无歧义;
250
- 6. 类型参数完整,全部业务字段 nullable 且无默认值;
251
- 7. 每个旧事务或新版 Flow/Visual 来源身份可解析,字段访问责任完整;更新传入Row时目标身份明确;
252
- 8. 不存在业务唯一约束、普通索引、外键、物理映射、TODO、占位符或诊断节点;
253
- 9. 交付目录中不存在本 Skill 生成的 findings、DDL、迁移脚本或 `structure.sql`。
179
+ - 表集合严格对应adapt承载;身份、实体和扩展来源可解析,无默认推导。
180
+ - Spec+adapt全部属性正常落列,关联目标与身份策略一致,无误加身份映射。
181
+ - 四个系统列完整且固定;类型参数明确,业务列可空无默认,不加业务约束或索引。
182
+ - 已知访问责任来源与字段可核对,空列表不伪装完整执行计划。
183
+ - 表文件没有TODO、占位符、诊断、DDL或运行时物理名映射。
184
+ - DB结构设计检查、Skill格式检查和真实数据库/业务测试是不同结论;未执行的测试不宣称通过。
@@ -1,37 +1,22 @@
1
- # DB 设计 Findings v1
1
+ # DB问题反馈
2
2
 
3
- 当 Islands Spec 的业务表达无法支持完整表契约时,报告 DB finding。Skill 自身的格式问题由 lead 修复,不伪装为 Spec 问题;技术编码、长度选档和外部引用实现问题也不要求业务 Spec 补字段。Finding 是过程诊断,不是正式 DB 交付物,也不授权 Agent 创建临时字段、宽泛类型、冗余表或物理约束绕过问题。
3
+ 仅当Spec自身的业务表达缺失或矛盾时记录Spec finding。adapt缺失承载、身份冲突、扩展属性不明单独向用户反馈,不能要求Spec补external、外部编码或写入剧情来迁就表设计。规范能力不足由维护者处理,消费者适配问题另列。
4
4
 
5
- DB 交付目录只放完整的 `*.table.yaml`。用户指定过程协作位置时,可在那里写入 `db-design-findings.yaml`;未指定时直接向用户反馈,不自行在交付目录或其他仓库落盘。
5
+ 反馈必须有实际实体、属性、节点及来源证据,说明影响哪张表、是否影响结构、能否继续其余设计。仅缺具体访问实现时不能把已确认表结构判为失败。缺失身份映射结构时不发明映射表。
6
+
7
+ 正式DB目录只放表契约。用户指定过程位置才持久化findings;未指定直接报告。沿用过程记录格式:
6
8
 
7
9
  ```yaml
8
10
  findingsVersion: saddle-db-findings/v1
9
11
  findings:
10
- - id: BILL-DB-001
12
+ - id: EXAMPLE-DB-001
11
13
  severity: blocker
12
- category: persistence-ownership-unknown
13
- affected:
14
- entity: 欠费单
15
- path: entity.persistenceReason
14
+ category: association-target-ambiguous
15
+ affected: {entity: 订单, path: columns.关联对象}
16
16
  evidence:
17
- - {kind: structureEntity, entity: 欠费单}
18
- - {kind: logicTransaction, paragraph: 查缴域·查账, branch: 主分支, transactionId: 查询并形成欠费单}
19
- message: 当前只能确认欠费单来自一次外部查询,不能证明 Saddle 需要跨事务持久保存。
20
- requiredUpstreamChange: 明确该事实只在请求内使用,或补齐由 Saddle 创建、读取、更新或删除的跨事务生命周期。
17
+ - {kind: structureEntity, entity: 订单}
18
+ message: 替换为实际Spec关联目标矛盾及证据。
19
+ requiredUpstreamChange: 替换为需要业务负责人确认的关联含义,不预设答案。
21
20
  ```
22
21
 
23
- 必填字段为 `id / severity / category / affected / evidence / message / requiredUpstreamChange`。
24
-
25
- 严重程度为 `blocker / warning`。
26
-
27
- v1 分类:
28
-
29
- - `persistence-ownership-unknown`
30
- - `external-entity-local-table-conflict`
31
- - `missing-field-source`
32
- - `missing-type-bound`
33
- - `association-target-ambiguous`
34
- - `logic-responsibility-missing`
35
- - `unsupported-shape`
36
-
37
- Finding 必须精确到实体、字段或 Logic 事务。一个实体的问题不能阻塞其他完整表文件。Evidence 优先使用 Islands Compiler 的稳定身份,不得只使用源码行号。
22
+ 字段id/severity/category/affected/evidence/message/requiredUpstreamChange必填。severity为blocker或warning,仅阻塞真正受影响部分。category采用missing-field-source/missing-type-bound/association-target-ambiguous/logic-responsibility-missing;类型能力等技术问题直接反馈,不伪装成Spec finding。没有Spec问题不生成空报告。
package/package.json CHANGED
@@ -1,9 +1,9 @@
1
1
  {
2
2
  "name": "@antprofuse/saddle-islands-design",
3
- "version": "0.1.13",
4
- "description": "从 Islands Spec 统一设计 Saddle 后端服务契约与逻辑数据库表。",
3
+ "version": "0.1.14",
4
+ "description": "消费 Islands Spec 与 adapt,统一设计 Saddle 后端服务契约与逻辑数据库表。",
5
5
  "license": "MIT OR Apache-2.0",
6
- "files": ["SKILL.md", "agents", "modules"],
6
+ "files": ["SKILL.md", "agents", "modules", "references"],
7
7
  "publishConfig": {
8
8
  "access": "public",
9
9
  "registry": "https://registry.npmjs.org/"
@@ -0,0 +1,93 @@
1
+ # adapt输入与身份规则
2
+
3
+ 两模块共用。adapt是Spec到code之间的明确设计输入,不是Islands运行时语法,也不是Saddle表列名映射。读取它不表示已实现转换或编译器已支持。
4
+
5
+ ## 输入结构与职责
6
+
7
+ 常见结构为同级spec、adapt、code;adapt含ingress.binding.yaml、entities/实体名.binding.yaml、dependencies/依赖名.binding.yaml。位置以调用方指定为准,每个实体、每个Dependency独立文件;ingress以目标板块和入口定位条目。不把Islands旧physical.yaml与adapt自动合并,也不由同名猜优先级。发现同范围冲突先反馈。
8
+
9
+ 所有实体都应有显式承载及身份声明。承载与身份属于adapt,不要求Spec理想实体写external、技术主键或外部编码。没有实际写操作不代表不建表;一次对象属性读取也不代表DB或RPC调用。声明缺失先问,不允许消费者隐含推导。
10
+
11
+ ## 实体承载与身份
12
+
13
+ ```yaml
14
+ 业务域: 示例域
15
+ 实体: 机构代理
16
+ 承载: 本地持久化实体
17
+ 身份:
18
+ 方式: Saddle标准uid
19
+ 扩展属性:
20
+ 机构代理编码:
21
+ 类型: string
22
+ 说明: 外部体系中的机构代理编码。
23
+ ```
24
+
25
+ 完整落地实体属性=Spec属性+adapt扩展属性。两者同等进入字段设计,只区分追溯来源;不在属性定义写“对应入口某字段”。同名冲突不得静默覆盖,类型和语义需确认。
26
+
27
+ | 承载 | 身份方式 | 设计含义 |
28
+ | --- | --- | --- |
29
+ | 本地持久化实体 | Saddle标准uid | 建实体表,标准UUIDv7身份 |
30
+ | 代码静态实体 | 固定主键 | 实例固定于代码,不建表;引用保存固定主键 |
31
+ | 不持久化实体 | 外部原生标识 | 不建实体表;原生稳定ID可直接作为引用 |
32
+ | 不持久化实体 | 仅对象传递 | 不建表,不为传递制造身份或映射 |
33
+ | 不持久化实体 | 外部身份映射 | 仅在已明确需要持久引用时使用已确认的本地身份映射;不是业务实体镜像表 |
34
+
35
+ 这里规定身份语义,不默认生成外部身份映射的具体表。稳定外部识别条件、映射生命周期和映射结构尚未明确时,反馈对应待定项,不能自行设计组合键、hash或token。映射不能解决外部身份本身不稳定的问题。有合适原生ID时不重复映射。
36
+
37
+ 原生标识声明例:
38
+
39
+ ```yaml
40
+ 身份:
41
+ 方式: 外部原生标识
42
+ 标识:
43
+ 字段: 用户ID
44
+ 来源: 平台用户ID
45
+ ```
46
+
47
+ 静态实例声明例(示例列表不是任何项目的默认值域):
48
+
49
+ ```yaml
50
+ 身份:
51
+ 方式: 固定主键
52
+ 实例:
53
+ - 主键: WATER
54
+ 属性:
55
+ 费种名称: 水费
56
+ ```
57
+
58
+ 固定主键是adapt身份,不是新增业务编码属性。合法值和属性来自实际实例声明,不能仅凭几个示例认定枚举穷尽。静态实体引用不保存名称,不另建uid映射。
59
+
60
+ 持久化关联以目标身份为准;若目标仅对象传递而来源要求持久引用,必须反馈冲突,不能暗中升级承载模式或创建映射。
61
+
62
+ ## 入口适配
63
+
64
+ ```yaml
65
+ 业务域: 示例域
66
+ 入口:
67
+ - 目标: {板块: 查询账单, 入口: 开始查询}
68
+ 外部入参:
69
+ subBizType:
70
+ 类型: string
71
+ 可空: false
72
+ 实体映射:
73
+ 缴费账户: {实体: 缴费账户}
74
+ 适配: |
75
+ subBizType 可映射 @费种(主键=$subBizType)
76
+ TODO:由用户填写其余适配逻辑。
77
+ ```
78
+
79
+ 入口描述外部字段到内部实体体系的关系,不是函数返回值。实体映射必须与Spec目标入口类型一致;集合等基数必须有输入声明,不能猜测。适配允许自然语言与上述轻量记号混合,不宣称有可执行表达式解释器。
80
+
81
+ 后端契约请求字段只能来自实体属性(含扩展)或ingress外部入参。字段允许向后传递而不归属实体属性;必须保留来源含义和类型,不因为后端需要就新增客户端参数。非null不隐含trim、空串拒绝、缺省值或其他校验政策。系统可信身份不进入业务请求或context段。
82
+
83
+ TODO只影响它真正决定的内容。若只缺具体加载实现而请求、结果可确定,继续设计;若缺失会决定字段、实例归属、合法结果或持久化结构,先反馈,不拿“并行”当作猜填许可。
84
+
85
+ ## Dependency边界
86
+
87
+ 每份Dependency绑定指向正式依赖,输入与返回显式声明实体类型及来源约束;返回集合使用实体+集合声明,空值仅在来源明确时允许。其实现可由用户留TODO。非持久化对象可仅作为Dependency实参,不代表存在该实体自己的外部CRUD。Dependency实现、profusecontract协议及调用细节不写入后端契约或表结构。
88
+
89
+ ## 来源定位
90
+
91
+ 本版本的path均为已指定输入仓库根目录相对路径,不是shell工作目录或URL。实体类型在业务域内解析;歧义不能按同名猜。不同来源仓库必须先明确解析上下文,不能把Spec仓库相对路径用于另一个仓库。
92
+
93
+ 实体绑定位置用 `{path, domain, entity}`,入口位置用 `{path, domain, board, entry}`,入口字段再加field。路径与语义目标必须同时匹配,不使用数组下标。契约版本跟随Spec+adapt内容重新核对,不只替换commit字符串。