pomaster 0.1.0 → 0.2.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.
- package/README.md +393 -396
- package/TRADEMARKS.md +2 -2
- package/catalog/archetypes/archetype.api.error.json +55 -0
- package/catalog/archetypes/archetype.api.pagination.json +68 -0
- package/catalog/archetypes/archetype.api.resource.json +45 -0
- package/catalog/archetypes/archetype.backend.approval_workflow.json +63 -0
- package/catalog/archetypes/archetype.backend.audit.json +44 -0
- package/catalog/archetypes/archetype.backend.crud_resource.json +56 -0
- package/catalog/archetypes/archetype.backend.export.json +40 -0
- package/catalog/archetypes/archetype.backend.external_integration.json +89 -0
- package/catalog/archetypes/archetype.backend.idempotent_command.json +65 -0
- package/catalog/archetypes/archetype.backend.import.json +47 -0
- package/catalog/archetypes/archetype.backend.master_data.json +45 -0
- package/catalog/archetypes/archetype.backend.outbox_event.json +80 -0
- package/catalog/archetypes/archetype.backend.query_resource.json +40 -0
- package/catalog/archetypes/archetype.backend.scheduled_job.json +69 -0
- package/catalog/archetypes/archetype.backend.transactional_write.json +79 -0
- package/catalog/archetypes/archetype.component.button.json +53 -0
- package/catalog/archetypes/archetype.component.data_grid.json +78 -0
- package/catalog/archetypes/archetype.component.dialog.json +52 -0
- package/catalog/archetypes/archetype.component.search_input.json +34 -0
- package/catalog/archetypes/archetype.component.search_select.json +77 -0
- package/catalog/archetypes/archetype.data.hierarchy.json +71 -0
- package/catalog/archetypes/archetype.data.ledger.json +40 -0
- package/catalog/archetypes/archetype.data.master_data.json +43 -0
- package/catalog/archetypes/archetype.data.transaction.json +42 -0
- package/catalog/archetypes/archetype.data.versioned.json +43 -0
- package/catalog/archetypes/archetype.frontend.error_taxonomy.json +99 -0
- package/catalog/archetypes/archetype.frontend.feature_oriented.json +59 -0
- package/catalog/archetypes/archetype.frontend.modular.json +37 -0
- package/catalog/archetypes/archetype.frontend.spa_layered.json +48 -0
- package/catalog/archetypes/archetype.page.analysis.json +39 -0
- package/catalog/archetypes/archetype.page.master_data.json +63 -0
- package/catalog/archetypes/archetype.runtime.environment_parity.json +178 -0
- package/catalog/archetypes/archetype.runtime.observability_binding.json +93 -0
- package/catalog/archetypes/archetype.state.async_command.json +63 -0
- package/catalog/archetypes/archetype.state.background_refresh.json +45 -0
- package/catalog/archetypes/archetype.state.form_edit.json +45 -0
- package/catalog/archetypes/archetype.state.optimistic_mutation.json +48 -0
- package/catalog/archetypes/archetype.state.selection.json +35 -0
- package/catalog/archetypes/archetype.state.server_query.json +60 -0
- package/catalog/archetypes/archetype.state.url_filter.json +47 -0
- package/catalog/archetypes/archetype.state.wizard.json +46 -0
- package/catalog/catalog-lock.draft.json +349 -5
- package/catalog/gates/gate.new-entity.checks.json +106 -0
- package/catalog/knowledge/knowledge.web.browser.mcp_eyes.json +99 -0
- package/catalog/sensors/sensor.browser.deterministic.json +17 -6
- package/catalog/sensors/sensor.browser.interactive.json +16 -6
- package/catalog/tools/materialize_v06_relock.py +218 -0
- package/catalog/tools/seed_v06_archetypes.py +283 -0
- package/catalog/tools/seed_v06_batch2_materials.py +504 -0
- package/catalog/tools/seed_v06_batch3_materials.py +756 -0
- package/catalog/tools/seed_v06_batch4_materials.py +353 -0
- package/dist/bin.js +2920 -331
- package/package.json +1 -1
|
@@ -0,0 +1,756 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
"""P-v06 批次 3:Backend/Data/API archetype 物料落盘(17 份)。
|
|
3
|
+
|
|
4
|
+
语义全部锚定联网核实报告(.trellis/tasks/09-02-vnext-prd-v06-governed-substrate/
|
|
5
|
+
research/backend-references.md,2026-09-03 官方站点/Maven Central metadata 实抓,
|
|
6
|
+
六题全部当日实抓无一条来自训练数据推测):
|
|
7
|
+
- 后端原型十份(v0.6.1 §29/§31/§32/§33/§35/§36/§37/§38/§39/§41 逐字):Spring
|
|
8
|
+
7.0.x 事务回滚现行口径 / Modulith 2.1.1 EPR 五态 + Debezium 3.6 默认表列 /
|
|
9
|
+
IETF idempotency-key-header -07(expired,如实纠偏禁冒称已成正式标准)/
|
|
10
|
+
ShedLock 7.9.0 + Quartz 2.5.2 + JobRunr 8.8.2 三选型口径 / Resilience4j 2.4.0
|
|
11
|
+
六模块默认值(RateLimiter 按研究裁定改写为「周期+许可数」二元组,禁照抄纳秒级
|
|
12
|
+
默认形参)。
|
|
13
|
+
- API 原型三份(§43/§44/§45 逐字):RFC 9457 五标准成员 + extensions 如实定位
|
|
14
|
+
(客户端 MUST ignore 语义——研究纠偏差异表 §44 行);三批准分页模式 +
|
|
15
|
+
Microsoft 原单一 REST Guidelines 已废弃分拆差异注记(Azure value[]/nextLink
|
|
16
|
+
现行锚)。
|
|
17
|
+
- 数据原型四份(§47/§49/§50/§51 逐字):TRANSACTION 不默认软删逐字;VERSIONED
|
|
18
|
+
五字段逐字;HIERARCHY 三候选 + closure table 证据等级如实标注(community 级,
|
|
19
|
+
禁冒充官方口径);LEDGER append-only + GDPR Art.17/Dataverse 1-30 天软删注记
|
|
20
|
+
(与 TRANSACTION 不默认软删对照)。
|
|
21
|
+
- layer 判定注记:17 份全部 layer=ARCHETYPE——PRD 逐节标题词形即「Archetype」
|
|
22
|
+
(§31 Approval Workflow Archetype / §35 Idempotent Command Archetype / §44 API
|
|
23
|
+
Error Archetype / §49-§51 Data Archetypes 等),机制面(事务/幂等/发件箱)虽含
|
|
24
|
+
模式语义,但 PRD 词形与组合语义均为原型档位,不落 PATTERN(七值词形闸
|
|
25
|
+
SUBSTRATE_LAYER_VALUES,PR-0006)。
|
|
26
|
+
词形纪律(ADR:批次 3 物料半场不回退既有判卷,只同步分母钉版与受影响断言):
|
|
27
|
+
物料 core 词面(title/id/summary/semantic 三槽)避开既有 repo 级 resolver/gate
|
|
28
|
+
断言的 need token(crud/资源/create/update/delete/按钮/button/动作/触发/select/
|
|
29
|
+
combobox/searchable/主数据/供应商管理页 等,英文大小写不敏感、CJK 按整段 run
|
|
30
|
+
精确等值)——本脚本落盘前跑 token 纪律自检(knowledgeQueryTokens 同法镜像),
|
|
31
|
+
违禁词形显式爆。唯一豁免:5 个物料 id 词形本身携带 master/data token
|
|
32
|
+
(ARCHETYPE.BACKEND.MASTER_DATA + DATA_ARCHETYPE.* 前缀——PRD §29/§47 逐字 id,
|
|
33
|
+
不可避免),其影响面(resolver-composable「master data」真实 catalog 断言)随
|
|
34
|
+
本批钉版同步更新为新现实,链判定/降位披露语义保持。
|
|
35
|
+
幂等:同输入重跑 byte-stable。
|
|
36
|
+
"""
|
|
37
|
+
import json
|
|
38
|
+
import os
|
|
39
|
+
import re
|
|
40
|
+
import sys
|
|
41
|
+
|
|
42
|
+
try:
|
|
43
|
+
sys.stdout.reconfigure(encoding="utf-8")
|
|
44
|
+
except Exception:
|
|
45
|
+
pass
|
|
46
|
+
|
|
47
|
+
ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) # .../catalog
|
|
48
|
+
OUT = os.path.join(ROOT, "archetypes")
|
|
49
|
+
FETCH = "2026-09-03"
|
|
50
|
+
|
|
51
|
+
RESEARCH_NOTE = ".trellis/tasks/09-02-vnext-prd-v06-governed-substrate/research/backend-references.md"
|
|
52
|
+
PRD_DOC_REF = "doc/POMaster-vNext-PRD-v0.6.1-Engineering-Substrate-Archetype-Catalog.md"
|
|
53
|
+
|
|
54
|
+
materials = {}
|
|
55
|
+
|
|
56
|
+
# ============================================================
|
|
57
|
+
# 后端原型十份(v0.6.1 §29-§41 逐字;layer=ARCHETYPE)
|
|
58
|
+
# ============================================================
|
|
59
|
+
|
|
60
|
+
materials["archetype.backend.master_data.json"] = {
|
|
61
|
+
"id": "ARCHETYPE.BACKEND.MASTER_DATA",
|
|
62
|
+
"kind": "archetype",
|
|
63
|
+
"layer": "ARCHETYPE",
|
|
64
|
+
"title_zh": "后端主数据原型",
|
|
65
|
+
"summary_zh": "标准主数据域后端原型(PRD §29):增删改查写面与列表检索读面为基座,叠加审计、状态位、业务唯一键与可选版本位的六件套组合语义——组合语义定义住主数据域的标准后端形态。",
|
|
66
|
+
"semantic": {
|
|
67
|
+
"responsibility": "以六件套组合语义承载主数据域的标准后端形态:写面(新增/修改/删除)与读面分离,公共横切面(审计/状态/唯一键/版本)显式组合而非各自发明",
|
|
68
|
+
"when_to_use": "新建主数据域(组织/客商/物料字典等共享参照数据)的后端时——六件套组合即标准答案,不需要从零设计(v0.6.1 §90 Tracer:AI 不需要从零设计标准表结构)",
|
|
69
|
+
"when_not_to_use": "交易流水类(走交易流水数据原型——不默认软删);纯一次性批量导入场景(导入原型承载流程而非实体形状)",
|
|
70
|
+
},
|
|
71
|
+
"composition": {
|
|
72
|
+
"requires": [
|
|
73
|
+
"ARCHETYPE.BACKEND.CRUD_RESOURCE",
|
|
74
|
+
"ARCHETYPE.BACKEND.QUERY_RESOURCE",
|
|
75
|
+
],
|
|
76
|
+
"optional": [
|
|
77
|
+
"ARCHETYPE.BACKEND.AUDIT",
|
|
78
|
+
"DATA_ARCHETYPE.MASTER_DATA",
|
|
79
|
+
],
|
|
80
|
+
"incompatible": [],
|
|
81
|
+
},
|
|
82
|
+
"prd_combination": [
|
|
83
|
+
"CRUD_RESOURCE",
|
|
84
|
+
"QUERY_RESOURCE",
|
|
85
|
+
"AUDIT",
|
|
86
|
+
"STATUS",
|
|
87
|
+
"UNIQUE_BUSINESS_KEY",
|
|
88
|
+
"OPTIONAL_VERSION",
|
|
89
|
+
],
|
|
90
|
+
"prd_combination_note": "PRD §29 组合清单逐字(CRUD_RESOURCE/QUERY_RESOURCE/AUDIT 三件为在册 catalog 物料——requires/optional 槽承载;STATUS/UNIQUE_BUSINESS_KEY/OPTIONAL_VERSION 三件为组合位词形,物理载体归 CRUD 物料的 defaults 审计/唯一约束/版本位)",
|
|
91
|
+
"x-research-anchors": {
|
|
92
|
+
"note": "组合语义为 PRD §29 逐字;与批次 1 在册物料的引用关系(CRUD/QUERY/DATA_ARCHETYPE.MASTER_DATA)经 backend-references.md 差异表 §47-§51 行 2026-09-03 对照无冲突;软删保持 optional 位(题 6b:GDPR Art.17 兼容但个人数据须有最终硬删路径)",
|
|
93
|
+
"sources": [
|
|
94
|
+
{"url": PRD_DOC_REF + " §29", "fetched": FETCH},
|
|
95
|
+
{"url": RESEARCH_NOTE, "fetched": FETCH},
|
|
96
|
+
],
|
|
97
|
+
},
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
materials["archetype.backend.transactional_write.json"] = {
|
|
101
|
+
"id": "ARCHETYPE.BACKEND.TRANSACTIONAL_WRITE",
|
|
102
|
+
"kind": "archetype",
|
|
103
|
+
"layer": "ARCHETYPE",
|
|
104
|
+
"title_zh": "事务性写原型",
|
|
105
|
+
"summary_zh": "单库用例写路径原型(PRD §36 五步链序):用例入口开事务、领域变更、仓储落库、提交;回滚默认档锚 Spring 现行口径(运行时异常与错误默认回滚、受检异常默认不回滚);关键库事务内禁慢外部网络调用。",
|
|
106
|
+
"semantic": {
|
|
107
|
+
"responsibility": "把一次用例写的原子性边界标准化为五步链序:Application Use Case → TX BEGIN → Domain Change → Repository Write → TX COMMIT——事务边界与领域变更的相对位置单点声明",
|
|
108
|
+
"when_to_use": "单库强一致写路径(一次用例一个库事务即可承载)——先检查是否真需要跨服务最终一致(是则配发件箱事件原型)",
|
|
109
|
+
"when_not_to_use": "跨服务最终一致写(配发件箱事件原型);只读检索面;外部系统调用编排(走外部集成原型)",
|
|
110
|
+
},
|
|
111
|
+
"composition": {"requires": [], "optional": [], "incompatible": []},
|
|
112
|
+
"defaults": {
|
|
113
|
+
"chain": [
|
|
114
|
+
"Application Use Case",
|
|
115
|
+
"TX BEGIN",
|
|
116
|
+
"Domain Change",
|
|
117
|
+
"Repository Write",
|
|
118
|
+
"TX COMMIT",
|
|
119
|
+
],
|
|
120
|
+
"propagation": "REQUIRED",
|
|
121
|
+
"isolation": "ISOLATION_DEFAULT",
|
|
122
|
+
"read_only": False,
|
|
123
|
+
"rollback_default": "RuntimeException|Error 默认回滚;checked Exception 默认不回滚(Spring Framework 7.0.x 现行文档逐字:\"Any RuntimeException or Error triggers rollback, and any checked Exception does not.\"——2026-09-03 实抓未变)",
|
|
124
|
+
"propagation_axis": [
|
|
125
|
+
"REQUIRED",
|
|
126
|
+
"SUPPORTS",
|
|
127
|
+
"MANDATORY",
|
|
128
|
+
"REQUIRES_NEW",
|
|
129
|
+
"NOT_SUPPORTED",
|
|
130
|
+
"NEVER",
|
|
131
|
+
"NESTED",
|
|
132
|
+
],
|
|
133
|
+
"rollback_rule_note": "rollbackFor 类型规则按等于或子类匹配;pattern 规则是子串匹配(官方明示可能误伤 CustomExceptionV2 与嵌套类 CustomException$AnotherException)——pattern 必须写全限定名",
|
|
134
|
+
"strongest_matching_rule_wins": True,
|
|
135
|
+
},
|
|
136
|
+
"constraints": [
|
|
137
|
+
"默认禁止在关键 DB Transaction 中包含慢外部网络调用(PRD §36 逐字)",
|
|
138
|
+
"REQUIRES_NEW 要求连接池容量适当超过并发线程数,否则连接耗尽/死锁(官方原文:\"Do not use PROPAGATION_REQUIRES_NEW unless your connection pool is appropriately sized, exceeding the number of concurrent threads by at least 1.\")",
|
|
139
|
+
"REQUIRED 参与外层事务时本地 isolation/timeout/readOnly 被静默忽略;内层 rollback-only 标记会使外层提交抛 UnexpectedRollbackException(官方传播详解)",
|
|
140
|
+
],
|
|
141
|
+
"optional": {
|
|
142
|
+
"propagation": ["REQUIRES_NEW", "NESTED"],
|
|
143
|
+
"nested_note": "NESTED 为单物理事务+保存点,通常映射到 JDBC savepoints——仅 JDBC 资源事务可用",
|
|
144
|
+
"global_rollback_switch": "Spring 6.2+ 可经 @EnableTransactionManagement(rollbackOn=ALL_EXCEPTIONS) 全局改默认回滚行为(事务级规则仍覆盖全局缺省)",
|
|
145
|
+
},
|
|
146
|
+
"x-research-anchors": {
|
|
147
|
+
"note": "回滚默认原文与七传播语义为 Spring 官方文档 2026-09-03 实抓(annotations.html/rolling-back.html/Propagation javadoc;版本 7.0.9/Boot 4.1.1 取自 repo1.maven.org 官方 metadata);REQUIRES_NEW 连接池死锁警示与 rollbackFor 子串误伤为官方原文转写",
|
|
148
|
+
"sources": [
|
|
149
|
+
{"url": "https://docs.spring.io/spring-framework/reference/data-access/transaction/declarative/annotations.html", "fetched": FETCH},
|
|
150
|
+
{"url": "https://docs.spring.io/spring-framework/reference/data-access/transaction/declarative/rolling-back.html", "fetched": FETCH},
|
|
151
|
+
{"url": "https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/transaction/annotation/Propagation.html", "fetched": FETCH},
|
|
152
|
+
{"url": "https://repo1.maven.org/maven2/org/springframework/spring-framework-bom/maven-metadata.xml", "fetched": FETCH},
|
|
153
|
+
{"url": RESEARCH_NOTE + " 题 1", "fetched": FETCH},
|
|
154
|
+
],
|
|
155
|
+
},
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
materials["archetype.backend.outbox_event.json"] = {
|
|
159
|
+
"id": "ARCHETYPE.BACKEND.OUTBOX_EVENT",
|
|
160
|
+
"kind": "archetype",
|
|
161
|
+
"layer": "ARCHETYPE",
|
|
162
|
+
"title_zh": "发件箱事件原型",
|
|
163
|
+
"summary_zh": "库与事件最终一致原型(PRD §37):业务数据与发件箱同事务落库,提交后由发布器中继到消息通道;生命周期五态锚 Spring Modulith 事件发布注册表、默认表列形锚 Debezium 发件箱路由器现行文档。",
|
|
164
|
+
"semantic": {
|
|
165
|
+
"responsibility": "把『业务落库』与『事件外发』的原子性标准化:同事务写入业务数据与发件箱行,提交后异步中继——发布器不在业务事务内做网络调用",
|
|
166
|
+
"when_to_use": "库内状态变更需要可靠外发事件(跨服务最终一致)时;需要对失败事件可重投、可观测时",
|
|
167
|
+
"when_not_to_use": "纯进程内通知(普通事务事件监听即可,无需发件箱);同步强一致调用(走事务性写原型)",
|
|
168
|
+
},
|
|
169
|
+
"composition": {
|
|
170
|
+
"requires": [],
|
|
171
|
+
"optional": ["ARCHETYPE.BACKEND.TRANSACTIONAL_WRITE"],
|
|
172
|
+
"incompatible": [],
|
|
173
|
+
},
|
|
174
|
+
"defaults": {
|
|
175
|
+
"write_scope": "same_transaction_as_business_data(Modulith EPR 逐字语义:writes entries for each of them into an event publication log as part of the original business transaction)",
|
|
176
|
+
"lifecycle_states": ["PUBLISHED", "PROCESSING", "COMPLETED", "FAILED", "RESUBMITTED"],
|
|
177
|
+
"lifecycle_source": "Spring Modulith 2.x 事件发布注册表状态机(2.0 引入;每条记录追踪 completionAttempts 与 lastResubmissionDate)",
|
|
178
|
+
"outbox_table_columns": ["id", "aggregatetype", "aggregateid", "type", "payload"],
|
|
179
|
+
"outbox_table_source": "Debezium Outbox Event Router 默认表列(Basic outbox table 逐字:id uuid not null / aggregatetype varchar(255) not null / aggregateid varchar(255) not null / type varchar(255) not null / payload jsonb)",
|
|
180
|
+
"route_by_field": "aggregatetype",
|
|
181
|
+
},
|
|
182
|
+
"constraints": [
|
|
183
|
+
"发布中继只发生在业务事务提交之后(publisher 不得在业务事务内做网络调用)",
|
|
184
|
+
"事件 id 全局唯一以支持消费端去重(Debezium:可用 id 移除重复消息)",
|
|
185
|
+
"CDC 形态需用 SMT predicate 把路由限定在发件箱表事件上(connector 还会发心跳/墓碑等消息)",
|
|
186
|
+
],
|
|
187
|
+
"optional": {
|
|
188
|
+
"externalization": ["kafka", "amqp", "jms", "spring-messaging"],
|
|
189
|
+
"staleness_monitor": "超时未完成条目定时标失败(Modulith Staleness Monitor,默认全 0 即不启用)",
|
|
190
|
+
"resubmit": "失败重投 API(可配批量大小/最大并发/最小年龄/过滤器)",
|
|
191
|
+
"cdc_mode": "Debezium Outbox Event Router(Kafka Connect 生态,从库日志侧发事件——适合事件进消息通道且不在应用内做中继的场景,代价是新增一条运维面)",
|
|
192
|
+
},
|
|
193
|
+
"x-research-anchors": {
|
|
194
|
+
"note": "EPR 五态/同事务落库语义/外置基础设施为 Spring Modulith 官方文档 2026-09-03 实抓(版本 2.1.1);默认表列五列与路由默认值为 Debezium 官方文档 2026-09-03 实抓(stable 3.6)。选型边界:Modulith=应用内库级方案(无独立部署面),Debezium=独立 CDC 基础设施(绑定 Kafka Connect)",
|
|
195
|
+
"sources": [
|
|
196
|
+
{"url": "https://docs.spring.io/spring-modulith/reference/events.html", "fetched": FETCH},
|
|
197
|
+
{"url": "https://debezium.io/documentation/reference/stable/transformations/outbox-event-router.html", "fetched": FETCH},
|
|
198
|
+
{"url": "https://spring.io/projects/spring-modulith", "fetched": FETCH},
|
|
199
|
+
{"url": "https://repo1.maven.org/maven2/org/springframework/modulith/spring-modulith-bom/maven-metadata.xml", "fetched": FETCH},
|
|
200
|
+
{"url": RESEARCH_NOTE + " 题 2", "fetched": FETCH},
|
|
201
|
+
],
|
|
202
|
+
},
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
materials["archetype.backend.idempotent_command.json"] = {
|
|
206
|
+
"id": "ARCHETYPE.BACKEND.IDEMPOTENT_COMMAND",
|
|
207
|
+
"kind": "archetype",
|
|
208
|
+
"layer": "ARCHETYPE",
|
|
209
|
+
"title_zh": "幂等命令原型",
|
|
210
|
+
"summary_zh": "非幂等操作的容错重试原型(PRD §35 四件套):键/作用域/过期/结果重放;标准现状如实锚定——IETF 草案 draft-ietf-httpapi-idempotency-key-header -07(2025-10-15)已过期未成标准,实践口径锚 Stripe 幂等请求与 Smithy 幂等令牌特质。",
|
|
211
|
+
"semantic": {
|
|
212
|
+
"responsibility": "以客户端生成键识别并丢弃重放请求:首个请求的结果(含失败形态)被保存,同键重放返回同一结果——幂等性是服务端承诺而非重试端自觉",
|
|
213
|
+
"when_to_use": "支付/递交/审批/导入/外部回调等非幂等写操作需要容错重试时(PRD §35 适用清单:payment/submit/approve/import/external callback)",
|
|
214
|
+
"when_not_to_use": "天然幂等的读操作;键无存储载体的纯内存操作;GET/删除类方法(收键无效果)",
|
|
215
|
+
},
|
|
216
|
+
"composition": {"requires": [], "optional": [], "incompatible": []},
|
|
217
|
+
"structure": {
|
|
218
|
+
"idempotency_key": "字符串 ≤255 字符,建议 UUID 或熵充足随机串(IETF RECOMMENDED + Stripe 建议 + Smithy 客户端自动填 UUID 三源一致)",
|
|
219
|
+
"scope": "唯一性作用域 + 载荷指纹(指纹候选枚举——IETF §2.4:整包校验和/选中元素校验和/字段值匹配/请求摘要或签名)",
|
|
220
|
+
"expiry": "默认 24h 保留窗口(Stripe 实践:键至少 24 小时后可自动清除);过期策略必须写入 API 文档(IETF SHOULD)",
|
|
221
|
+
"result_replay": "保存首个请求的状态码与响应体(无论成败,含 5xx——Stripe 逐字口径:saving the resulting status code and body of the first request ... regardless of whether it succeeds or fails)",
|
|
222
|
+
},
|
|
223
|
+
"error_semantics": {
|
|
224
|
+
"missing_key": 400,
|
|
225
|
+
"in_flight_conflict": 409,
|
|
226
|
+
"payload_mismatch": 422,
|
|
227
|
+
"source": "IETF -07 正文错误语义(缺键 400;同键仍在处理中 409 Conflict;同键载荷不同 422——键不得跨不同载荷复用)",
|
|
228
|
+
},
|
|
229
|
+
"constraints": [
|
|
230
|
+
"仅对非幂等方法(POST/PATCH 类命令)启用;GET/删除类不收键(Stripe:Don't send idempotency keys in GET and DELETE requests because it has no effect.)",
|
|
231
|
+
"校验失败/并发冲突不落结果、可安全重试(Stripe:只在端点执行开始后才保存结果)",
|
|
232
|
+
"键禁含敏感数据(email/个人标识——Stripe)",
|
|
233
|
+
"标准状态如实引用:expired Internet-Draft(-07,2025-10-15,Intended status 字段为 None、无正式编号)+ Stripe/Smithy 实践——引用词形禁冒称已成正式标准",
|
|
234
|
+
],
|
|
235
|
+
"optional": {
|
|
236
|
+
"fail_closed_on_missing_key": "缺键时拒绝(400)或忽略——服务自定(IETF SHOULD 级别留白)",
|
|
237
|
+
"retry_safety_baseline": "未标幂等令牌特质的操作默认应视为不可安全重试(Smithy 行为特质规范同页基线)",
|
|
238
|
+
"auto_client_key": "客户端实现可自动填键(Smithy MAY;AWS SDK 自动填 v4 UUID 先例)",
|
|
239
|
+
},
|
|
240
|
+
"x-research-anchors": {
|
|
241
|
+
"note": "【研究纠偏】任务问的 draft-ietf-httpapi-idempotency-key-resources 在 IETF datatracker 不存在(404);真实词形为 draft-ietf-httpapi-idempotency-key-header,最新版 -07(2025-10-15)状态 Expired & archived、无正式编号——本物料全文不冒称已成正式标准(集成 spec 断言全文无该缩写词形)。Stripe(首个结果保存+24h 窗口+255 字符)与 Smithy idempotencyToken trait(服务端 MUST 在服务定义时段内防重放)为官方文档 2026-09-03 实抓",
|
|
242
|
+
"sources": [
|
|
243
|
+
{"url": "https://datatracker.ietf.org/doc/draft-ietf-httpapi-idempotency-key-header/", "fetched": FETCH},
|
|
244
|
+
{"url": "https://datatracker.ietf.org/doc/html/draft-ietf-httpapi-idempotency-key-header-07", "fetched": FETCH},
|
|
245
|
+
{"url": "https://docs.stripe.com/api/idempotent_requests", "fetched": FETCH},
|
|
246
|
+
{"url": "https://smithy.io/2.0/spec/behavior-traits.html", "fetched": FETCH},
|
|
247
|
+
{"url": RESEARCH_NOTE + " 题 3", "fetched": FETCH},
|
|
248
|
+
],
|
|
249
|
+
},
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
materials["archetype.backend.scheduled_job.json"] = {
|
|
253
|
+
"id": "ARCHETYPE.BACKEND.SCHEDULED_JOB",
|
|
254
|
+
"kind": "archetype",
|
|
255
|
+
"layer": "ARCHETYPE",
|
|
256
|
+
"title_zh": "定时任务原型",
|
|
257
|
+
"summary_zh": "分布式环境定时任务七要素原型(PRD §39 逐字):计划/分布式锁/超时/重试/幂等/结果/告警;三选型口径并列锚现行文档——ShedLock 7.9.0(仅锁、跳过语义)、Quartz 2.5.2(仅 JDBC 存储可集群)、JobRunr 8.8.2(原子认领)。",
|
|
258
|
+
"semantic": {
|
|
259
|
+
"responsibility": "多节点部署下同一计划任务的防重复执行契约单点:并发防重、执行时限、失败重试、任务体幂等与结果告警全部显式定义而非默认假设",
|
|
260
|
+
"when_to_use": "周期/延时后台任务在多实例部署下需要防重复执行时;需要对错失执行与连续失败可观测、可告警时",
|
|
261
|
+
"when_not_to_use": "单实例部署的简单计划任务(无需分布式锁);用户交互内实时请求(走写路径原型);可靠事件外发(走发件箱事件原型)",
|
|
262
|
+
},
|
|
263
|
+
"composition": {"requires": [], "optional": [], "incompatible": []},
|
|
264
|
+
"seven_elements": {
|
|
265
|
+
"schedule": "cron 或间隔二选一必填",
|
|
266
|
+
"distributed_lock": "默认配置;lockAtMostFor 必须远大于正常执行时长(官方 MUST 级指引——超锁后多进程同时持锁行为不可预测);lockAtLeastFor 覆盖短任务与节点间时钟漂移",
|
|
267
|
+
"timeout": "执行超时应远小于 lockAtMostFor(联动配置)",
|
|
268
|
+
"retry": "指数退避(JobRunr RetryFilter 口径)或框架外自管",
|
|
269
|
+
"idempotency": "任务体必须幂等——并发防重不等于成功保证(ShedLock 超锁行为不可预测、Quartz 无恢复标记不重放)",
|
|
270
|
+
"result": "执行结果留痕(成功/失败/跳过三态)",
|
|
271
|
+
"alert": "连续失败告警",
|
|
272
|
+
},
|
|
273
|
+
"selection_stances": {
|
|
274
|
+
"shedlock": "『ShedLock is just a lock』(官方自述)——不是分布式调度器;同任务他节点执行中不等待、直接跳过(skip 语义:错过即跳过、不排队补跑);按任务名加锁",
|
|
275
|
+
"quartz": "集群仅 JDBC JobStore(JobStoreTX/JobStoreCMT)+ isClustered=true;每节点唯一 instanceId;同触发仅一节点执行;官方性能警示——集群锁在超过约三节点后随节点数退化",
|
|
276
|
+
"jobrunr": "任务持久化于既有库(重启/故障不丢)、轮询存储并原子认领(claims jobs atomically so the same job is never processed twice)、失败按指数退避重排、最长运行节点自动当选主节点做内务",
|
|
277
|
+
},
|
|
278
|
+
"constraints": [
|
|
279
|
+
"锁组件与调度组件职责分离——仅锁方案不提供排队/错失补跑(官方明示不要当调度器用)",
|
|
280
|
+
"at-most-once 并发保证不等于成功保证——任务体幂等是底线",
|
|
281
|
+
],
|
|
282
|
+
"optional": {
|
|
283
|
+
"quartz_clustered_mode": "含 requests recovery 恢复标记位注记(标记的任务由余下节点重新执行)",
|
|
284
|
+
"jobrunr_storage_provider": "存储抽象覆盖关系库与 NoSQL;内置 Dashboard 观测",
|
|
285
|
+
"keep_alive_lock_provider": "锁中途续期(在 lockAtMostFor 中点续期——官方建议慎用)",
|
|
286
|
+
},
|
|
287
|
+
"x-research-anchors": {
|
|
288
|
+
"note": "三库定位/锁词形/集群条件/原子认领语义均为官方文档 2026-09-03 实抓;版本(ShedLock 7.9.0/Quartz 2.5.2/JobRunr 8.8.2 stable 线)取自 repo1.maven.org 官方 metadata",
|
|
289
|
+
"sources": [
|
|
290
|
+
{"url": "https://github.com/lukas-krecan/ShedLock", "fetched": FETCH},
|
|
291
|
+
{"url": "https://www.quartz-scheduler.org/documentation/quartz-2.5.x/configuration/ConfigJDBCJobStoreClustering.html", "fetched": FETCH},
|
|
292
|
+
{"url": "https://www.jobrunr.io/en/documentation/", "fetched": FETCH},
|
|
293
|
+
{"url": "https://repo1.maven.org/maven2/net/javacrumbs/shedlock/shedlock-spring/maven-metadata.xml", "fetched": FETCH},
|
|
294
|
+
{"url": "https://repo1.maven.org/maven2/org/quartz-scheduler/quartz/maven-metadata.xml", "fetched": FETCH},
|
|
295
|
+
{"url": RESEARCH_NOTE + " 题 5", "fetched": FETCH},
|
|
296
|
+
],
|
|
297
|
+
},
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
materials["archetype.backend.external_integration.json"] = {
|
|
301
|
+
"id": "ARCHETYPE.BACKEND.EXTERNAL_INTEGRATION",
|
|
302
|
+
"kind": "archetype",
|
|
303
|
+
"layer": "ARCHETYPE",
|
|
304
|
+
"title_zh": "外部集成原型",
|
|
305
|
+
"summary_zh": "外部系统调用八要素原型(PRD §38 逐字):超时/重试/断路器/限流感知/鉴权/错误映射/可观测/回退;韧性默认档锚 Resilience4j 2.4.0 六模块现行文档——限流以『周期时长+每周期许可数』二元组显式给定(库默认周期是纳秒级形参,禁照抄)。",
|
|
306
|
+
"semantic": {
|
|
307
|
+
"responsibility": "把对外部系统每次调用的失效模式显式化:超时有时限、重试有上界、故障有熔断、过载有限流、失败有映射与回退——每一项都是显式配置而非默认假设",
|
|
308
|
+
"when_to_use": "同步/异步调用外部系统(第三方服务/跨域内部服务)的集成点——每个远端被调方一个独立韧性实例(官方 Golden Rule:MUST NOT share)",
|
|
309
|
+
"when_not_to_use": "进程内函数调用;库与事件最终一致的可靠外发(走发件箱事件原型);用户交互内的本域写路径(走事务性写原型)",
|
|
310
|
+
},
|
|
311
|
+
"composition": {"requires": [], "optional": [], "incompatible": []},
|
|
312
|
+
"eight_elements": {
|
|
313
|
+
"timeout": {"timeout_duration": "1s", "cancel_running_future": True},
|
|
314
|
+
"retry": {"max_attempts": 3, "wait_duration": "500ms", "backoff": "fixed(指数退避为可选位,需显式启用退避与抖动配置)"},
|
|
315
|
+
"circuit_breaker": {
|
|
316
|
+
"failure_rate_threshold": "50%",
|
|
317
|
+
"sliding_window": "COUNT_BASED 100 次",
|
|
318
|
+
"minimum_number_of_calls": 100,
|
|
319
|
+
"wait_duration_in_open_state": "60s",
|
|
320
|
+
"permitted_number_of_calls_in_half_open_state": 10,
|
|
321
|
+
},
|
|
322
|
+
"bulkhead": {"max_concurrent_calls": 25, "max_wait_duration": "0(快失败默认)"},
|
|
323
|
+
"rate_limit_awareness": {
|
|
324
|
+
"form": "period_and_permits_pair——『周期时长 + 每周期许可数』二元组必须显式给定",
|
|
325
|
+
"note": "库默认周期是纳秒级形参(词形误导),禁照抄默认值;且此限流是客户端本侧限速(许可桶),不是对端服务保护",
|
|
326
|
+
},
|
|
327
|
+
"auth": "凭据注入与刷新单点",
|
|
328
|
+
"error_mapping": "外部错误到本域错误分型的单点映射链",
|
|
329
|
+
"observability": "每次调用埋点(时延/结果/重试次数/熔断态)",
|
|
330
|
+
"fallback": "降级回退(recover 语义承接)",
|
|
331
|
+
},
|
|
332
|
+
"constraints": [
|
|
333
|
+
"每个远端服务一个独立韧性实例(官方 Golden Rule 逐字:\"Create a unique instance (with a unique ID) for each protected remote service or backend you communicate with.\"——CircuitBreaker 属实例感知模式 MUST NOT share)",
|
|
334
|
+
"限流语义是客户端本侧限速,非对端服务保护",
|
|
335
|
+
],
|
|
336
|
+
"module_map_note": "Resilience4j 2.4.0 六核心模块对照:circuitbreaker/ratelimiter/bulkhead/retry/timelimiter/cache(另有 hedge 与 spring-boot3/spring-boot4 等适配模块);2.4.0(2026-03-14)起基线 JDK 17→21",
|
|
337
|
+
"x-research-anchors": {
|
|
338
|
+
"note": "六模块清单与五模块全部默认值为官方 README/docs 2026-09-03 逐字实抓;RateLimiter 默认值按研究裁定不照抄(纳秒级周期形参误导)——改写为显式二元组要求;版本 2.4.0 与 JDK 21 基线取自 repo1.maven.org 官方 metadata 与 release notes",
|
|
339
|
+
"sources": [
|
|
340
|
+
{"url": "https://github.com/resilience4j/resilience4j", "fetched": FETCH},
|
|
341
|
+
{"url": "https://resilience4j.readme.io/docs/circuitbreaker", "fetched": FETCH},
|
|
342
|
+
{"url": "https://resilience4j.readme.io/docs/retry", "fetched": FETCH},
|
|
343
|
+
{"url": "https://resilience4j.readme.io/docs/ratelimiter", "fetched": FETCH},
|
|
344
|
+
{"url": "https://resilience4j.readme.io/docs/bulkhead", "fetched": FETCH},
|
|
345
|
+
{"url": "https://resilience4j.readme.io/docs/timeout", "fetched": FETCH},
|
|
346
|
+
{"url": "https://repo1.maven.org/maven2/io/github/resilience4j/resilience4j-bom/maven-metadata.xml", "fetched": FETCH},
|
|
347
|
+
{"url": RESEARCH_NOTE + " 题 6a", "fetched": FETCH},
|
|
348
|
+
],
|
|
349
|
+
},
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
materials["archetype.backend.approval_workflow.json"] = {
|
|
353
|
+
"id": "ARCHETYPE.BACKEND.APPROVAL_WORKFLOW",
|
|
354
|
+
"kind": "archetype",
|
|
355
|
+
"layer": "ARCHETYPE",
|
|
356
|
+
"title_zh": "审批流原型",
|
|
357
|
+
"summary_zh": "标准审批状态机原型(PRD §31 逐字链):草稿经递交事件进入已递交态,审批通过转通过、驳回转驳回;可选撤回/重开转移与多级会签变体。",
|
|
358
|
+
"semantic": {
|
|
359
|
+
"responsibility": "审批单生命周期与合法转移的单点声明:四态两事件为标准链,扩展转移(撤回/重开)与多级会签变体为可选档——合法转移之外无隐式状态",
|
|
360
|
+
"when_to_use": "需要人审的单据类写流程(请假/报销/变更单等)——状态闭包显式登记,审批动作留痕进审计",
|
|
361
|
+
"when_not_to_use": "无审批环节的直写流程(走事务性写原型);自由流程编排诉求(本原型是闭包状态机,非流程引擎)",
|
|
362
|
+
},
|
|
363
|
+
"composition": {"requires": [], "optional": [], "incompatible": []},
|
|
364
|
+
"states": ["DRAFT", "SUBMITTED", "APPROVED", "REJECTED"],
|
|
365
|
+
"transitions": [
|
|
366
|
+
{"from": "DRAFT", "event": "SUBMIT", "to": "SUBMITTED"},
|
|
367
|
+
{"from": "SUBMITTED", "event": "APPROVE", "to": "APPROVED"},
|
|
368
|
+
{"from": "SUBMITTED", "event": "REJECT", "to": "REJECTED"},
|
|
369
|
+
],
|
|
370
|
+
"optional": {
|
|
371
|
+
"transitions": ["WITHDRAW", "REOPEN"],
|
|
372
|
+
"variants": ["MULTI_STAGE"],
|
|
373
|
+
"source": "PRD §31 逐字:可选:WITHDRAW / REOPEN / MULTI_STAGE。",
|
|
374
|
+
},
|
|
375
|
+
"x-research-anchors": {
|
|
376
|
+
"note": "四态两事件链与三可选位为 PRD §31 逐字(2026-09-03 对照 backend-references.md 差异表无冲突确认);状态机闭包词形与前端状态机原型(STATE_ARCHETYPE 族)同构,本原型是后端单据域实例化",
|
|
377
|
+
"sources": [
|
|
378
|
+
{"url": PRD_DOC_REF + " §31", "fetched": FETCH},
|
|
379
|
+
{"url": RESEARCH_NOTE, "fetched": FETCH},
|
|
380
|
+
],
|
|
381
|
+
},
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
materials["archetype.backend.import.json"] = {
|
|
385
|
+
"id": "ARCHETYPE.BACKEND.IMPORT",
|
|
386
|
+
"kind": "archetype",
|
|
387
|
+
"layer": "ARCHETYPE",
|
|
388
|
+
"title_zh": "批量导入原型",
|
|
389
|
+
"summary_zh": "文件批量导入七步链原型(PRD §32 逐字):上传→解析→校验→预览→确认→执行→结果;行级错误/部分失败/幂等/事务/审计五项必须预定义。",
|
|
390
|
+
"semantic": {
|
|
391
|
+
"responsibility": "把『文件进库』标准化为预览确认两段式:校验先行、人确认后才执行——执行形态(全量事务/部分失败)与行级错误报告显式预定义而非事后补",
|
|
392
|
+
"when_to_use": "电子表格/CSV 类批量建档与更新(参照数据初始化、期初导入等)——预定义五项缺一即契约不完整",
|
|
393
|
+
"when_not_to_use": "单条建档(走标准写面);系统间定期同步(走外部集成/发件箱事件原型)",
|
|
394
|
+
},
|
|
395
|
+
"composition": {"requires": [], "optional": [], "incompatible": []},
|
|
396
|
+
"pipeline": ["Upload", "Parse", "Validate", "Preview", "Confirm", "Apply", "Result"],
|
|
397
|
+
"predefined": ["row_error", "partial_failure", "idempotency", "transaction", "audit"],
|
|
398
|
+
"predefined_source": "PRD §32 逐字:必须预定义:row error / partial failure / idempotency / transaction / audit。",
|
|
399
|
+
"x-research-anchors": {
|
|
400
|
+
"note": "七步链与预定义五项为 PRD §32 逐字(2026-09-03 对照 backend-references.md 差异表无冲突确认);幂等项与幂等命令原型语义互链(重复导入以键防重)",
|
|
401
|
+
"sources": [
|
|
402
|
+
{"url": PRD_DOC_REF + " §32", "fetched": FETCH},
|
|
403
|
+
{"url": RESEARCH_NOTE, "fetched": FETCH},
|
|
404
|
+
],
|
|
405
|
+
},
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
materials["archetype.backend.export.json"] = {
|
|
409
|
+
"id": "ARCHETYPE.BACKEND.EXPORT",
|
|
410
|
+
"kind": "archetype",
|
|
411
|
+
"layer": "ARCHETYPE",
|
|
412
|
+
"title_zh": "导出原型",
|
|
413
|
+
"summary_zh": "数据导出双档原型(PRD §33 逐字):小量同步直出(SYNC_SMALL);大量异步三段(ASYNC_LARGE)——请求立任务、产物落对象存储、下载凭据交付。",
|
|
414
|
+
"semantic": {
|
|
415
|
+
"responsibility": "导出的量级分档与产物生命周期单点化:异步档把长耗时产物移出请求生命周期,凭据化下载替代大文件直传",
|
|
416
|
+
"when_to_use": "列表/报表数据导出文件——按量级选档(小量同步、大量异步),异步档任务态可查询可重试",
|
|
417
|
+
"when_not_to_use": "系统间数据同步(走外部集成/发件箱事件原型);实时流式取数(走查询面)",
|
|
418
|
+
},
|
|
419
|
+
"composition": {"requires": [], "optional": [], "incompatible": []},
|
|
420
|
+
"modes": ["SYNC_SMALL", "ASYNC_LARGE"],
|
|
421
|
+
"async_chain": ["Request", "Job", "Object Storage", "Download Token"],
|
|
422
|
+
"x-research-anchors": {
|
|
423
|
+
"note": "双档词形与异步四段链为 PRD §33 逐字(2026-09-03 对照 backend-references.md 差异表无冲突确认);产物落对象存储与文件二进制不入关系库字段同向(§40 File Resource 原型边界)",
|
|
424
|
+
"sources": [
|
|
425
|
+
{"url": PRD_DOC_REF + " §33", "fetched": FETCH},
|
|
426
|
+
{"url": RESEARCH_NOTE, "fetched": FETCH},
|
|
427
|
+
],
|
|
428
|
+
},
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
materials["archetype.backend.audit.json"] = {
|
|
432
|
+
"id": "ARCHETYPE.BACKEND.AUDIT",
|
|
433
|
+
"kind": "archetype",
|
|
434
|
+
"layer": "ARCHETYPE",
|
|
435
|
+
"title_zh": "审计原型",
|
|
436
|
+
"summary_zh": "审计两档原型(PRD §41 逐字):基础档四字段(创建/更新的时间与操作人);严格档六要素(变更前后值/操作类型/理由/操作者/链路追踪)——档位由数据分级决定而非默认全量。",
|
|
437
|
+
"semantic": {
|
|
438
|
+
"responsibility": "『谁在何时对什么做了什么改动』的可回答性:基础档回答元数据层,严格档回答逐字段前后值与理由链——两档显式分档,禁默认全量严格审计",
|
|
439
|
+
"when_to_use": "任何标准写面的默认基础档(对应后端标准写读面物料的审计默认档);台账/财务/权限类数据升级严格档",
|
|
440
|
+
"when_not_to_use": "外部系统调用的遥测(走外部集成原型可观测位);只读检索面",
|
|
441
|
+
},
|
|
442
|
+
"composition": {"requires": [], "optional": [], "incompatible": []},
|
|
443
|
+
"basic_fields": ["created_at", "created_by", "updated_at", "updated_by"],
|
|
444
|
+
"strict_fields": ["before", "after", "action", "reason", "actor", "trace"],
|
|
445
|
+
"x-research-anchors": {
|
|
446
|
+
"note": "基础四字段与严格六要素为 PRD §41 逐字(2026-09-03 对照 backend-references.md 差异表无冲突确认);与主数据表原型的审计四字段(批次 1 recommended_fields)同源",
|
|
447
|
+
"sources": [
|
|
448
|
+
{"url": PRD_DOC_REF + " §41", "fetched": FETCH},
|
|
449
|
+
{"url": RESEARCH_NOTE, "fetched": FETCH},
|
|
450
|
+
],
|
|
451
|
+
},
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
# ============================================================
|
|
455
|
+
# API 原型三份(v0.6.1 §43-§45 逐字;layer=ARCHETYPE)
|
|
456
|
+
# ============================================================
|
|
457
|
+
|
|
458
|
+
materials["archetype.api.resource.json"] = {
|
|
459
|
+
"id": "ARCHETYPE.API.RESOURCE",
|
|
460
|
+
"kind": "archetype",
|
|
461
|
+
"layer": "ARCHETYPE",
|
|
462
|
+
"title_zh": "API 资源原型",
|
|
463
|
+
"summary_zh": "REST 风格标准端点五操作原型(PRD §43 逐字):集合读取/单体读取/新建/单体修改/移除;授权/错误/分页/校验/兼容性五绑定必须配置——绑定缺失即契约不完整。",
|
|
464
|
+
"semantic": {
|
|
465
|
+
"responsibility": "单体实体的 HTTP 面形状基线:五操作闭包 + 五项强制绑定(authorization/error/pagination/validation/compatibility)——绑定面显式声明而非隐式约定",
|
|
466
|
+
"when_to_use": "实体需要标准 HTTP 面时(与后端标准写读面原型配对:操作闭包与其五操作一一对应)",
|
|
467
|
+
"when_not_to_use": "动词语义的业务命令面(配幂等命令原型);事件订阅面(走发件箱事件原型的通道侧)",
|
|
468
|
+
},
|
|
469
|
+
"composition": {"requires": [], "optional": [], "incompatible": []},
|
|
470
|
+
"operations": ["GET collection", "GET item", "POST item", "PUT/PATCH item", "DELETE item"],
|
|
471
|
+
"bindings": ["authorization", "error", "pagination", "validation", "compatibility"],
|
|
472
|
+
"bindings_source": "PRD §43 逐字:必须绑定 authorization / error / pagination / validation / compatibility。",
|
|
473
|
+
"x-research-anchors": {
|
|
474
|
+
"note": "五操作与五绑定为 PRD §43 逐字(2026-09-03 对照 backend-references.md 题 4/差异表 §44-§45 行核实链);error 绑定与 API 错误契约原型互链、pagination 绑定与分页原型互链",
|
|
475
|
+
"sources": [
|
|
476
|
+
{"url": PRD_DOC_REF + " §43", "fetched": FETCH},
|
|
477
|
+
{"url": RESEARCH_NOTE + " 题 4", "fetched": FETCH},
|
|
478
|
+
],
|
|
479
|
+
},
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
materials["archetype.api.error.json"] = {
|
|
483
|
+
"id": "ARCHETYPE.API.ERROR",
|
|
484
|
+
"kind": "archetype",
|
|
485
|
+
"layer": "ARCHETYPE",
|
|
486
|
+
"title_zh": "API 错误契约原型",
|
|
487
|
+
"summary_zh": "问题细节标准错误信封原型(PRD §44):五个标准成员逐字(type/title/status/detail/instance);业务码/链路追踪/字段级错误如实定位为扩展成员(客户端必须忽略未识别扩展——RFC 9457 §3.2 语义),以 application/problem+json 承载。",
|
|
488
|
+
"semantic": {
|
|
489
|
+
"responsibility": "错误响应的形状与语义单点:五个标准成员承载问题类型/概要/状态/详情/实例定位,扩展成员承载机器码与字段级错误——机器可判卷与人可读分层",
|
|
490
|
+
"when_to_use": "所有 HTTP 错误响应的信封(与 API 资源原型 error 绑定位配对);前后端错误分型映射的契约源(前端错误目录的消费面对齐本原型)",
|
|
491
|
+
"when_not_to_use": "成功响应的包装信封(本原型只管错误面);前端错误呈现分型本身(前端错误目录承载)",
|
|
492
|
+
},
|
|
493
|
+
"composition": {"requires": [], "optional": [], "incompatible": []},
|
|
494
|
+
"standard_members": {
|
|
495
|
+
"type": "URI 引用标识问题类型;建议绝对 URI;缺省 about:blank(注册类型:无超出 HTTP 状态码的额外语义)",
|
|
496
|
+
"title": "问题类型的简短人读概要——不应随出现次数变化(本地化除外)",
|
|
497
|
+
"status": "JSON 数字,仅建议性;必须与真实 HTTP 状态码一致(规范 MUST:Generators MUST use the same status code in the actual HTTP response)",
|
|
498
|
+
"detail": "本次出现的人读解释——消费者不应解析 detail 提取信息(扩展成员更适合机器消费)",
|
|
499
|
+
"instance": "标识本次问题具体发生处的 URI 引用;不可解引用时作不透明唯一标识",
|
|
500
|
+
},
|
|
501
|
+
"extensions": {
|
|
502
|
+
"members": ["code", "trace_id", "field_errors"],
|
|
503
|
+
"positioning": "扩展成员(非标准成员)——规范 §3.2:问题类型定义可扩展附加成员,客户端 MUST ignore 未识别扩展",
|
|
504
|
+
"field_errors_note": "字段级错误建议对齐官方校验示例的 errors[] 数组形态(每条含 detail 与位置指针)",
|
|
505
|
+
},
|
|
506
|
+
"constraints": [
|
|
507
|
+
"status 必须与真实 HTTP 状态码一致(MUST)",
|
|
508
|
+
"media type 用 application/problem+json(canonical 形态)",
|
|
509
|
+
"引用现行规范 RFC 9457(已取代 RFC 7807——Appendix D 自述相对 7807 的变更)",
|
|
510
|
+
],
|
|
511
|
+
"x-research-anchors": {
|
|
512
|
+
"note": "【研究纠偏·差异表 §44 行】PRD 把 code/trace_id/field_errors 与五成员并列列出,但三者不是标准成员而是扩展成员(客户端 MUST ignore 未识别扩展语义如实落位);五成员逐字定义与 about:blank 注册类型为 RFC 9457 官方文本 2026-09-03 实抓",
|
|
513
|
+
"sources": [
|
|
514
|
+
{"url": "https://www.rfc-editor.org/rfc/rfc9457.html", "fetched": FETCH},
|
|
515
|
+
{"url": PRD_DOC_REF + " §44", "fetched": FETCH},
|
|
516
|
+
{"url": RESEARCH_NOTE + " 题 4", "fetched": FETCH},
|
|
517
|
+
],
|
|
518
|
+
},
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
materials["archetype.api.pagination.json"] = {
|
|
522
|
+
"id": "ARCHETYPE.API.PAGINATION",
|
|
523
|
+
"kind": "archetype",
|
|
524
|
+
"layer": "ARCHETYPE",
|
|
525
|
+
"title_zh": "API 分页原型",
|
|
526
|
+
"summary_zh": "分页三批准模式原型(PRD §45 逐字闭包):OFFSET/CURSOR/KEYSET 三选一;业界现行对照锚——Azure 服务端分页 value[]+nextLink、Stripe 对象 ID 游标、Relay Connections 不透明游标;Microsoft 原单一 REST 指南已废弃分拆(差异注记在场)。",
|
|
527
|
+
"semantic": {
|
|
528
|
+
"responsibility": "集合读取的分页契约单点:模式从批准闭包内选择、页大小有界、排序稳定、续页位形(has_more 或 next_link 二选一)固定",
|
|
529
|
+
"when_to_use": "任何列表/检索面的分页契约(与查询面原型配对);深分页代价需要预先声明时(OFFSET 深翻页代价、KEYSET 需稳定排序键、CURSOR 需不透明令牌语义)",
|
|
530
|
+
"when_not_to_use": "一次性全量小数据(可不分页但须显式声明上界);单体读取(API 资源原型 GET item 承载)",
|
|
531
|
+
},
|
|
532
|
+
"composition": {"requires": [], "optional": [], "incompatible": []},
|
|
533
|
+
"approved_modes": ["OFFSET", "CURSOR", "KEYSET"],
|
|
534
|
+
"defaults": {
|
|
535
|
+
"page_size_bounded": True,
|
|
536
|
+
"stable_sort_required": True,
|
|
537
|
+
"continuation_field": "has_more 或 next_link 二选一的约定位",
|
|
538
|
+
"total_count": "不默认返回全量计数(Azure SHOULD NOT——全量计数可能代价高昂)",
|
|
539
|
+
},
|
|
540
|
+
"industry_anchors": {
|
|
541
|
+
"azure": "服务端分页:顶层 value[] + nextLink(绝对 URL、不透明续页令牌);最后一页不返回 nextLink 字段(禁 null 值形态);文档必须声明跨页可能跳过或重复;未支持查询参数必须报错",
|
|
542
|
+
"stripe": "cursor=对象 ID(按稳定序的 KEYSET——keyset-by-id 形态);响应形 data[]+has_more;参数 limit/starting_after/ending_before;默认新→旧排序",
|
|
543
|
+
"relay": "GraphQL Relay Connections:Connection 必含 edges 与 pageInfo;Edge 必含 node 与 cursor;前向 first/after、后向 last/before;cursor 是不透明字符串",
|
|
544
|
+
},
|
|
545
|
+
"deprecation_note": "Microsoft 原单一 REST Guidelines 已废弃分拆(2026-09-03 实抓:原文档头部声明 deprecated,分拆为 Azure 与 Graph 两份现行指南)——引用时改引 Azure REST API Guidelines 并注明原文档已废弃",
|
|
546
|
+
"mode_note": "nextLink = CURSOR 的不透明服务端形态(opaque continuation token)——三批准模式闭包容纳业界现行形态(Azure/Stripe/Relay 对照均落回三模式之一)",
|
|
547
|
+
"constraints": [
|
|
548
|
+
"模式只能从三批准模式闭包内选择(PRD §45:项目只能选择批准模式)",
|
|
549
|
+
"最后一页禁返回 null 值 nextLink(Azure DO NOT 逐字)",
|
|
550
|
+
],
|
|
551
|
+
"x-research-anchors": {
|
|
552
|
+
"note": "【差异注记·差异表 §45 行】三模式与业界现行实践兼容;Microsoft 现行形态是 opaque nextLink(CURSOR 的服务端形态),且原单一 REST Guidelines 已 deprecated 分拆为 Azure/Graph 两份——注记随物料在场。Azure/Stripe/Relay 三处词形为官方文档 2026-09-03 实抓",
|
|
553
|
+
"sources": [
|
|
554
|
+
{"url": "https://github.com/microsoft/api-guidelines/blob/vNext/Guidelines.md", "fetched": FETCH},
|
|
555
|
+
{"url": "https://raw.githubusercontent.com/microsoft/api-guidelines/vNext/azure/Guidelines.md", "fetched": FETCH},
|
|
556
|
+
{"url": "https://docs.stripe.com/pagination", "fetched": FETCH},
|
|
557
|
+
{"url": "https://relay.dev/graphql/connections.htm", "fetched": FETCH},
|
|
558
|
+
{"url": PRD_DOC_REF + " §45", "fetched": FETCH},
|
|
559
|
+
{"url": RESEARCH_NOTE + " 题 4", "fetched": FETCH},
|
|
560
|
+
],
|
|
561
|
+
},
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
# ============================================================
|
|
565
|
+
# 数据原型四份(v0.6.1 §47/§49/§50/§51 逐字;layer=ARCHETYPE)
|
|
566
|
+
# ============================================================
|
|
567
|
+
|
|
568
|
+
materials["archetype.data.transaction.json"] = {
|
|
569
|
+
"id": "DATA_ARCHETYPE.TRANSACTION",
|
|
570
|
+
"kind": "archetype",
|
|
571
|
+
"layer": "ARCHETYPE",
|
|
572
|
+
"title_zh": "交易流水数据原型",
|
|
573
|
+
"summary_zh": "交易/流水类实体形状原型(PRD §49 五强调逐字):不可变身份、业务状态、金额与数量的精度、交易时间、审计;不默认软删除——删除语义的补偿形态由业务定义。",
|
|
574
|
+
"semantic": {
|
|
575
|
+
"responsibility": "已发生的业务事实的持久化形状:身份不可变、状态随业务推进、数量金额精度显式、交易时间与审计留痕——事实记录不做软删除默认",
|
|
576
|
+
"when_to_use": "订单/支付/流水/库存变动等『已发生事实』类实体建表——金额数量字段走精度治理(精度/单位治理节)",
|
|
577
|
+
"when_not_to_use": "共享参照数据(走主数据表原型);需要版本快照对照的配置类(走版本化数据原型);只增不改的台账序列(走台账数据原型)",
|
|
578
|
+
},
|
|
579
|
+
"composition": {"requires": [], "optional": [], "incompatible": []},
|
|
580
|
+
"emphasis": [
|
|
581
|
+
"immutable identity",
|
|
582
|
+
"business state",
|
|
583
|
+
"financial / quantity precision",
|
|
584
|
+
"transaction time",
|
|
585
|
+
"audit",
|
|
586
|
+
],
|
|
587
|
+
"soft_delete": {
|
|
588
|
+
"default": False,
|
|
589
|
+
"prd_wording": "不默认 Soft Delete。(PRD §49 逐字)",
|
|
590
|
+
"note": "软删保持 optional 位(与 CRUD 物料 optional.soft_delete 一致);含个人数据的记录必须存在最终硬擦除路径(GDPR 第 17 条——详见台账数据原型对照注记)",
|
|
591
|
+
},
|
|
592
|
+
"x-research-anchors": {
|
|
593
|
+
"note": "五强调与不默认软删为 PRD §49 逐字;软删边界(GDPR Art.17 硬擦除路径/Dataverse 1-30 天保留窗口/工程代价社区共识级)为 backend-references.md 题 6b 2026-09-03 实抓",
|
|
594
|
+
"sources": [
|
|
595
|
+
{"url": PRD_DOC_REF + " §49", "fetched": FETCH},
|
|
596
|
+
{"url": RESEARCH_NOTE + " 题 6b", "fetched": FETCH},
|
|
597
|
+
],
|
|
598
|
+
},
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
materials["archetype.data.versioned.json"] = {
|
|
602
|
+
"id": "DATA_ARCHETYPE.VERSIONED",
|
|
603
|
+
"kind": "archetype",
|
|
604
|
+
"layer": "ARCHETYPE",
|
|
605
|
+
"title_zh": "版本化数据原型",
|
|
606
|
+
"summary_zh": "实体版本链形状原型(PRD §50 五字段逐字):entity_id/revision/effective_from/effective_to/status;适用配置版本、车型版本、价格版本、规则版本四类。",
|
|
607
|
+
"semantic": {
|
|
608
|
+
"responsibility": "同一实体的多版本共存与生效区间单点化:版本行以生效区间切分,当前生效版本由区间+状态派生而非覆盖写",
|
|
609
|
+
"when_to_use": "配置/车型/价格/规则等需要版本快照、生效区间与历史回溯的实体(价格台账判例 §71 与台账数据原型组合)",
|
|
610
|
+
"when_not_to_use": "仅当前值无历史诉求的参照数据(主数据表原型);事件日志类追加流(非版本链语义)",
|
|
611
|
+
},
|
|
612
|
+
"composition": {"requires": [], "optional": [], "incompatible": []},
|
|
613
|
+
"fields": ["entity_id", "revision", "effective_from", "effective_to", "status"],
|
|
614
|
+
"applicable": ["配置版本", "车型版本", "价格版本", "规则版本"],
|
|
615
|
+
"x-research-anchors": {
|
|
616
|
+
"note": "五字段词形与四类适用清单为 PRD §50 逐字(2026-09-03 对照 backend-references.md 差异表 §47-§51 行无冲突确认)",
|
|
617
|
+
"sources": [
|
|
618
|
+
{"url": PRD_DOC_REF + " §50", "fetched": FETCH},
|
|
619
|
+
{"url": RESEARCH_NOTE, "fetched": FETCH},
|
|
620
|
+
],
|
|
621
|
+
},
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
materials["archetype.data.hierarchy.json"] = {
|
|
625
|
+
"id": "DATA_ARCHETYPE.HIERARCHY",
|
|
626
|
+
"kind": "archetype",
|
|
627
|
+
"layer": "ARCHETYPE",
|
|
628
|
+
"title_zh": "层级数据原型",
|
|
629
|
+
"summary_zh": "树形层级实体形状原型(PRD §51 三候选逐字):邻接表/物化路径/闭包表——按读写比例、深度、子树查询与移动需求选定;邻接表路线以 PG 官方递归查询能力为官方级锚,闭包表证据等级如实标注为社区共识级。",
|
|
630
|
+
"semantic": {
|
|
631
|
+
"responsibility": "父子层级关系的实现路线选型与形状基线:三候选各有读写代价画像,选型由访问画像决定而非默认——选型依据(读写比例/深度/子树查询/移动需求)显式在案",
|
|
632
|
+
"when_to_use": "组织架构/分类目录/物料清单等树形实体建表——先按读写比例与移动频率选路线再定形状",
|
|
633
|
+
"when_not_to_use": "扁平两值关联(普通外键即可);图状多对多(关联中间表语义);单层父子无子树查询诉求(邻接表直配即可,无需本原型的选型面)",
|
|
634
|
+
},
|
|
635
|
+
"composition": {"requires": [], "optional": [], "incompatible": []},
|
|
636
|
+
"candidates": ["ADJACENCY_LIST", "MATERIALIZED_PATH", "CLOSURE_TABLE"],
|
|
637
|
+
"resolver_basis": ["读写比例", "深度", "子树查询", "移动需求"],
|
|
638
|
+
"evidence": {
|
|
639
|
+
"ADJACENCY_LIST": {
|
|
640
|
+
"level": "official",
|
|
641
|
+
"anchor": "官方级——PG 18 官方文档:\"Recursive queries are typically used to deal with hierarchical or tree-structured data.\"(PG 14+ 官方提供 SEARCH 子句深度/广度优先排序与 CYCLE 子句环防护——邻接表递归遍历是一等公民且有官方环防护)",
|
|
642
|
+
},
|
|
643
|
+
"MATERIALIZED_PATH": {
|
|
644
|
+
"level": "official",
|
|
645
|
+
"anchor": "官方级——SQL Server hierarchyid 官方对比(子树查询显著更快、直接后代查询略慢、非叶子移动更慢)+ django-treebeard 选型文:MP 是最兼容与最常用实现(descendants 读取 0.7ms vs 邻接表 14ms)",
|
|
646
|
+
},
|
|
647
|
+
"CLOSURE_TABLE": {
|
|
648
|
+
"level": "community",
|
|
649
|
+
"anchor": "社区共识级(如实标注,禁冒充官方口径)——本轮未找到数据库官方文档背书(PG/MySQL/SQL Server 均无专门章节);存祖先-后代全对、读一次 join 取全子树/全祖先、写放大=节点数×深度",
|
|
650
|
+
},
|
|
651
|
+
},
|
|
652
|
+
"optional_native": {
|
|
653
|
+
"sql_server": "hierarchyid(数据库原生物化路径实现)",
|
|
654
|
+
"postgresql": "ltree(treebeard 标注 experimental;官方文档在 PG 文档集)",
|
|
655
|
+
},
|
|
656
|
+
"x-research-anchors": {
|
|
657
|
+
"note": "【证据等级如实标注】closure table 选型指导为社区/书籍共识级(research 题 6b Caveats 段自述证据等级偏弱项),邻接表/物化路径两候选为官方级锚(PG 18 queries-with + SQL Server hierarchyid 对比 + treebeard 基准)——三候选与 PRD §51 逐字闭包一致,2026-09-03 实抓",
|
|
658
|
+
"sources": [
|
|
659
|
+
{"url": "https://www.postgresql.org/docs/current/queries-with.html", "fetched": FETCH},
|
|
660
|
+
{"url": "https://learn.microsoft.com/en-us/sql/relational-databases/hierarchical-data-sql-server", "fetched": FETCH},
|
|
661
|
+
{"url": "https://django-treebeard.readthedocs.io/en/latest/choosing.html", "fetched": FETCH},
|
|
662
|
+
{"url": PRD_DOC_REF + " §51", "fetched": FETCH},
|
|
663
|
+
{"url": RESEARCH_NOTE + " 题 6b", "fetched": FETCH},
|
|
664
|
+
],
|
|
665
|
+
},
|
|
666
|
+
}
|
|
667
|
+
|
|
668
|
+
materials["archetype.data.ledger.json"] = {
|
|
669
|
+
"id": "DATA_ARCHETYPE.LEDGER",
|
|
670
|
+
"kind": "archetype",
|
|
671
|
+
"layer": "ARCHETYPE",
|
|
672
|
+
"title_zh": "台账数据原型",
|
|
673
|
+
"summary_zh": "追加式台账实体形状原型(PRD §47 目录词形承载):记录表列内只增不改不删、对账可重放;软删除注记对照——涉及个人数据时软删只能是中间态,必须存在最终硬擦除路径。",
|
|
674
|
+
"semantic": {
|
|
675
|
+
"responsibility": "不可篡改事实序列的表内承载:行只追加,修正以反向/补充记录表达,历史可完整重放——append-only 是台账形状的定义性特征",
|
|
676
|
+
"when_to_use": "价格台账(§71 判例与版本化数据原型组合)、余额流水、积分/额度变动等需要对账与审计重放的记录面",
|
|
677
|
+
"when_not_to_use": "可修正的当前值数据(主数据表原型/版本化数据原型);一次性会话数据",
|
|
678
|
+
},
|
|
679
|
+
"composition": {"requires": [], "optional": [], "incompatible": []},
|
|
680
|
+
"append_only": True,
|
|
681
|
+
"soft_delete_note": "台账不默认软删除(与交易流水数据原型的 §49 不默认软删同向对照);含个人数据的记录:GDPR 第 17 条被遗忘权要求『无不当延迟』擦除——软删只能作为中间态,保留窗口到期必须物理删除;业界平台级窗口量级参考:Dataverse 可恢复态保留天数 1-30 天可配(2026-09-03 官方实抓)",
|
|
682
|
+
"x-research-anchors": {
|
|
683
|
+
"note": "append-only 台账语义为 PRD §47 目录词形承载 + §71 价格台账判例组合位(与 DATA_ARCHETYPE.VERSIONED 组合);GDPR Art.17 逐字(erasure without undue delay)与 Dataverse 1-30 天窗口为官方文档 2026-09-03 实抓;软删工程代价(查询需带未删过滤/唯一约束需部分索引)为社区共识级证据——如实标注不冒充官方口径",
|
|
684
|
+
"sources": [
|
|
685
|
+
{"url": "https://gdpr-info.eu/art-17-gdpr/", "fetched": FETCH},
|
|
686
|
+
{"url": "https://learn.microsoft.com/en-us/power-platform/admin/restore-deleted-table-records", "fetched": FETCH},
|
|
687
|
+
{"url": PRD_DOC_REF + " §47/§71", "fetched": FETCH},
|
|
688
|
+
{"url": RESEARCH_NOTE + " 题 6b", "fetched": FETCH},
|
|
689
|
+
],
|
|
690
|
+
},
|
|
691
|
+
}
|
|
692
|
+
|
|
693
|
+
# ============================================================
|
|
694
|
+
# 词形纪律自检(落盘前硬闸;knowledgeQueryTokens 同法镜像)
|
|
695
|
+
# ============================================================
|
|
696
|
+
|
|
697
|
+
# core 词面 = title_zh + summary_zh + semantic 三槽(id 除外——5 个 id 词形本身
|
|
698
|
+
# 携带 master/data token,属 PRD 逐字 id 不可避免豁免,见模块头 ADR)。
|
|
699
|
+
# 禁词表 = 既有 repo 级 resolver/gate 断言的 need token + 相邻风险词(英文
|
|
700
|
+
# 大小写不敏感精确 token 等值;CJK 按整段 run 精确等值——与
|
|
701
|
+
# knowledgeQueryTokens 的「词级精确、CJK 整段」同一语义)。
|
|
702
|
+
FORBIDDEN_CORE_TOKENS = {
|
|
703
|
+
# 英文(lowercase token 精确等值)
|
|
704
|
+
"crud", "create", "update", "delete", "button", "select", "combobox",
|
|
705
|
+
"searchable", "master", "data", "supplier", "query", "color", "antd",
|
|
706
|
+
"grid", "table", "page",
|
|
707
|
+
# CJK(整段 run 精确等值)
|
|
708
|
+
"资源", "按钮", "动作", "触发", "主数据", "供应商管理页", "可搜索车型选择器",
|
|
709
|
+
"表格", "网格", "颜色",
|
|
710
|
+
}
|
|
711
|
+
|
|
712
|
+
|
|
713
|
+
def core_tokens(body):
|
|
714
|
+
text = " ".join(
|
|
715
|
+
[
|
|
716
|
+
body["title_zh"],
|
|
717
|
+
body["summary_zh"],
|
|
718
|
+
body.get("semantic", {}).get("responsibility") or "",
|
|
719
|
+
body.get("semantic", {}).get("when_to_use") or "",
|
|
720
|
+
body.get("semantic", {}).get("when_not_to_use") or "",
|
|
721
|
+
]
|
|
722
|
+
)
|
|
723
|
+
# knowledgeQueryTokens 同法镜像:lowercase 后按非字母数字/非 CJK 字符切段
|
|
724
|
+
# (纯空白切分会漏检标点分隔的违禁词形——「主数据/」「(资源)」等)。
|
|
725
|
+
return [t for t in re.split(r"[^a-z0-9一-鿿]+", text.lower()) if t]
|
|
726
|
+
|
|
727
|
+
|
|
728
|
+
def token_discipline_check():
|
|
729
|
+
"""落盘前自检:core 词面禁词(违禁显式爆,禁静默落盘)。"""
|
|
730
|
+
violations = []
|
|
731
|
+
for name, body in materials.items():
|
|
732
|
+
tokens = set(core_tokens(body))
|
|
733
|
+
hit = sorted(tokens & FORBIDDEN_CORE_TOKENS)
|
|
734
|
+
if hit:
|
|
735
|
+
violations.append(f"{name} ({body['id']}): {hit}")
|
|
736
|
+
if violations:
|
|
737
|
+
raise SystemExit(
|
|
738
|
+
"[seed-batch3] 词形纪律自检失败(core 词面命中既有断言 need token):\n - "
|
|
739
|
+
+ "\n - ".join(violations)
|
|
740
|
+
)
|
|
741
|
+
|
|
742
|
+
|
|
743
|
+
def main():
|
|
744
|
+
token_discipline_check()
|
|
745
|
+
os.makedirs(OUT, exist_ok=True)
|
|
746
|
+
for name, body in materials.items():
|
|
747
|
+
path = os.path.join(OUT, name)
|
|
748
|
+
with open(path, "w", encoding="utf-8", newline="\n") as f:
|
|
749
|
+
json.dump(body, f, ensure_ascii=False, indent=2)
|
|
750
|
+
f.write("\n")
|
|
751
|
+
print("wrote", name, "id=", body["id"])
|
|
752
|
+
print(f"total: {len(materials)} materials")
|
|
753
|
+
|
|
754
|
+
|
|
755
|
+
if __name__ == "__main__":
|
|
756
|
+
main()
|