dsh-data-domain-knowledge 0.1.0-alpha.1

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.
Files changed (231) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +360 -0
  3. package/cordis.patch.yml +410 -0
  4. package/eval/README.md +76 -0
  5. package/eval/evaluate-retrieval.mjs +121 -0
  6. package/eval/queries.example.jsonl +2 -0
  7. package/lib/client.js +111415 -0
  8. package/lib/types/config-schema.d.ts +35 -0
  9. package/lib/types/config-schema.d.ts.map +1 -0
  10. package/lib/types/config-schema.js +34 -0
  11. package/lib/types/config-schema.js.map +1 -0
  12. package/lib/types/convert/core-loader.d.ts +32 -0
  13. package/lib/types/convert/core-loader.d.ts.map +1 -0
  14. package/lib/types/convert/core-loader.js +60 -0
  15. package/lib/types/convert/core-loader.js.map +1 -0
  16. package/lib/types/convert/host.d.ts +88 -0
  17. package/lib/types/convert/host.d.ts.map +1 -0
  18. package/lib/types/convert/host.js +479 -0
  19. package/lib/types/convert/host.js.map +1 -0
  20. package/lib/types/convert/ingest.d.ts +125 -0
  21. package/lib/types/convert/ingest.d.ts.map +1 -0
  22. package/lib/types/convert/ingest.js +228 -0
  23. package/lib/types/convert/ingest.js.map +1 -0
  24. package/lib/types/convert/settings-schema.d.ts +18 -0
  25. package/lib/types/convert/settings-schema.d.ts.map +1 -0
  26. package/lib/types/convert/settings-schema.js +26 -0
  27. package/lib/types/convert/settings-schema.js.map +1 -0
  28. package/lib/types/convert/types.d.ts +46 -0
  29. package/lib/types/convert/types.d.ts.map +1 -0
  30. package/lib/types/convert/types.js +41 -0
  31. package/lib/types/convert/types.js.map +1 -0
  32. package/lib/types/diagnosis/cards.d.ts +71 -0
  33. package/lib/types/diagnosis/cards.d.ts.map +1 -0
  34. package/lib/types/diagnosis/cards.js +482 -0
  35. package/lib/types/diagnosis/cards.js.map +1 -0
  36. package/lib/types/diagnosis/problem-classes.d.ts +51 -0
  37. package/lib/types/diagnosis/problem-classes.d.ts.map +1 -0
  38. package/lib/types/diagnosis/problem-classes.js +66 -0
  39. package/lib/types/diagnosis/problem-classes.js.map +1 -0
  40. package/lib/types/diagnosis/schema.d.ts +65 -0
  41. package/lib/types/diagnosis/schema.d.ts.map +1 -0
  42. package/lib/types/diagnosis/schema.js +208 -0
  43. package/lib/types/diagnosis/schema.js.map +1 -0
  44. package/lib/types/diagnosis/seed-source.d.ts +20 -0
  45. package/lib/types/diagnosis/seed-source.d.ts.map +1 -0
  46. package/lib/types/diagnosis/seed-source.js +96 -0
  47. package/lib/types/diagnosis/seed-source.js.map +1 -0
  48. package/lib/types/diagnosis/seed.d.ts +50 -0
  49. package/lib/types/diagnosis/seed.d.ts.map +1 -0
  50. package/lib/types/diagnosis/seed.js +242 -0
  51. package/lib/types/diagnosis/seed.js.map +1 -0
  52. package/lib/types/diagnosis/store.d.ts +81 -0
  53. package/lib/types/diagnosis/store.d.ts.map +1 -0
  54. package/lib/types/diagnosis/store.js +409 -0
  55. package/lib/types/diagnosis/store.js.map +1 -0
  56. package/lib/types/diagnosis/types.d.ts +124 -0
  57. package/lib/types/diagnosis/types.d.ts.map +1 -0
  58. package/lib/types/diagnosis/types.js +13 -0
  59. package/lib/types/diagnosis/types.js.map +1 -0
  60. package/lib/types/directory-picker.d.ts +94 -0
  61. package/lib/types/directory-picker.d.ts.map +1 -0
  62. package/lib/types/directory-picker.js +110 -0
  63. package/lib/types/directory-picker.js.map +1 -0
  64. package/lib/types/extract-model.d.ts +76 -0
  65. package/lib/types/extract-model.d.ts.map +1 -0
  66. package/lib/types/extract-model.js +193 -0
  67. package/lib/types/extract-model.js.map +1 -0
  68. package/lib/types/extract.d.ts +121 -0
  69. package/lib/types/extract.d.ts.map +1 -0
  70. package/lib/types/extract.js +549 -0
  71. package/lib/types/extract.js.map +1 -0
  72. package/lib/types/fts.d.ts +96 -0
  73. package/lib/types/fts.d.ts.map +1 -0
  74. package/lib/types/fts.js +184 -0
  75. package/lib/types/fts.js.map +1 -0
  76. package/lib/types/index.d.ts +39 -0
  77. package/lib/types/index.d.ts.map +1 -0
  78. package/lib/types/index.js +1112 -0
  79. package/lib/types/index.js.map +1 -0
  80. package/lib/types/intent/engine.d.ts +108 -0
  81. package/lib/types/intent/engine.d.ts.map +1 -0
  82. package/lib/types/intent/engine.js +501 -0
  83. package/lib/types/intent/engine.js.map +1 -0
  84. package/lib/types/intent/host.d.ts +88 -0
  85. package/lib/types/intent/host.d.ts.map +1 -0
  86. package/lib/types/intent/host.js +389 -0
  87. package/lib/types/intent/host.js.map +1 -0
  88. package/lib/types/intent/preset-tools.d.ts +37 -0
  89. package/lib/types/intent/preset-tools.d.ts.map +1 -0
  90. package/lib/types/intent/preset-tools.js +45 -0
  91. package/lib/types/intent/preset-tools.js.map +1 -0
  92. package/lib/types/intent/settings-schema.d.ts +59 -0
  93. package/lib/types/intent/settings-schema.d.ts.map +1 -0
  94. package/lib/types/intent/settings-schema.js +57 -0
  95. package/lib/types/intent/settings-schema.js.map +1 -0
  96. package/lib/types/intent/store.d.ts +75 -0
  97. package/lib/types/intent/store.d.ts.map +1 -0
  98. package/lib/types/intent/store.js +139 -0
  99. package/lib/types/intent/store.js.map +1 -0
  100. package/lib/types/intent/tools.d.ts +63 -0
  101. package/lib/types/intent/tools.d.ts.map +1 -0
  102. package/lib/types/intent/tools.js +108 -0
  103. package/lib/types/intent/tools.js.map +1 -0
  104. package/lib/types/intent/types.d.ts +189 -0
  105. package/lib/types/intent/types.d.ts.map +1 -0
  106. package/lib/types/intent/types.js +62 -0
  107. package/lib/types/intent/types.js.map +1 -0
  108. package/lib/types/knowledge-bases.d.ts +266 -0
  109. package/lib/types/knowledge-bases.d.ts.map +1 -0
  110. package/lib/types/knowledge-bases.js +1107 -0
  111. package/lib/types/knowledge-bases.js.map +1 -0
  112. package/lib/types/layout.d.ts +262 -0
  113. package/lib/types/layout.d.ts.map +1 -0
  114. package/lib/types/layout.js +312 -0
  115. package/lib/types/layout.js.map +1 -0
  116. package/lib/types/migrate.d.ts +110 -0
  117. package/lib/types/migrate.d.ts.map +1 -0
  118. package/lib/types/migrate.js +280 -0
  119. package/lib/types/migrate.js.map +1 -0
  120. package/lib/types/recall-rank.d.ts +158 -0
  121. package/lib/types/recall-rank.d.ts.map +1 -0
  122. package/lib/types/recall-rank.js +261 -0
  123. package/lib/types/recall-rank.js.map +1 -0
  124. package/lib/types/runtime.d.ts +568 -0
  125. package/lib/types/runtime.d.ts.map +1 -0
  126. package/lib/types/runtime.js +3045 -0
  127. package/lib/types/runtime.js.map +1 -0
  128. package/lib/types/settings-schema.d.ts +117 -0
  129. package/lib/types/settings-schema.d.ts.map +1 -0
  130. package/lib/types/settings-schema.js +92 -0
  131. package/lib/types/settings-schema.js.map +1 -0
  132. package/lib/types/settings-volatile.d.ts +102 -0
  133. package/lib/types/settings-volatile.d.ts.map +1 -0
  134. package/lib/types/settings-volatile.js +114 -0
  135. package/lib/types/settings-volatile.js.map +1 -0
  136. package/lib/types/types.d.ts +799 -0
  137. package/lib/types/types.d.ts.map +1 -0
  138. package/lib/types/types.js +387 -0
  139. package/lib/types/types.js.map +1 -0
  140. package/lib/types/wiki-types.d.ts +68 -0
  141. package/lib/types/wiki-types.d.ts.map +1 -0
  142. package/lib/types/wiki-types.js +322 -0
  143. package/lib/types/wiki-types.js.map +1 -0
  144. package/package.json +101 -0
  145. package/preset/tita-data-agent/agent.cordis.yml +376 -0
  146. package/preset/tita-data-agent/preset.yml +3 -0
  147. package/python/requirements.txt +8 -0
  148. package/scripts/doctor.mjs +70 -0
  149. package/scripts/e2e-pipeline.mjs +355 -0
  150. package/scripts/install-agent-preset.mjs +92 -0
  151. package/scripts/setup-embedding.sh +34 -0
  152. package/scripts/sync-agent-preset.mjs +188 -0
  153. package/src/client/AgentPresetCard.tsx +247 -0
  154. package/src/client/DirectoryPicker.tsx +357 -0
  155. package/src/client/InfoHint.tsx +65 -0
  156. package/src/client/IntentLogicTab.tsx +185 -0
  157. package/src/client/IntentTab.tsx +715 -0
  158. package/src/client/KnowledgeBaseTab.tsx +1454 -0
  159. package/src/client/KnowledgeGraphView.tsx +306 -0
  160. package/src/client/KnowledgePanel.tsx +381 -0
  161. package/src/client/KnowledgeStepRail.tsx +60 -0
  162. package/src/client/NodeSettings.tsx +392 -0
  163. package/src/client/PreviewSections.tsx +116 -0
  164. package/src/client/RecallPanel.tsx +399 -0
  165. package/src/client/TypeDefinitionDrawer.tsx +215 -0
  166. package/src/client/WikiFlowCard.tsx +226 -0
  167. package/src/client/WikiTypeEditor.tsx +332 -0
  168. package/src/client/agent-preset.ts +121 -0
  169. package/src/client/arch/AgentArchitectureGraph.tsx +219 -0
  170. package/src/client/arch/NodeLogicPanel.tsx +133 -0
  171. package/src/client/arch/ProblemDetailPanel.tsx +88 -0
  172. package/src/client/arch/model.ts +691 -0
  173. package/src/client/architecture.css +191 -0
  174. package/src/client/architecture.tsx +530 -0
  175. package/src/client/attribution/AttributionGraph.tsx +104 -0
  176. package/src/client/attribution/AttributionTab.tsx +332 -0
  177. package/src/client/attribution/CaseView.tsx +102 -0
  178. package/src/client/attribution/GraphStage.tsx +87 -0
  179. package/src/client/attribution/RunView.tsx +184 -0
  180. package/src/client/attribution/StageChrome.tsx +403 -0
  181. package/src/client/attribution/ViewSwitch.tsx +107 -0
  182. package/src/client/attribution/graph-options.ts +381 -0
  183. package/src/client/attribution/model.ts +462 -0
  184. package/src/client/config-scope.ts +119 -0
  185. package/src/client/convert/ConvertPanel.tsx +594 -0
  186. package/src/client/convert/styles.css +138 -0
  187. package/src/client/convert/styles.ts +49 -0
  188. package/src/client/format.ts +39 -0
  189. package/src/client/graph/layout.ts +181 -0
  190. package/src/client/graph.css +113 -0
  191. package/src/client/index.ts +98 -0
  192. package/src/client/problem-domains.ts +114 -0
  193. package/src/client/styles.css +940 -0
  194. package/src/client/styles.ts +11 -0
  195. package/src/client/useFitScale.ts +68 -0
  196. package/src/config-schema.ts +45 -0
  197. package/src/convert/core-loader.ts +68 -0
  198. package/src/convert/host.ts +579 -0
  199. package/src/convert/ingest.ts +367 -0
  200. package/src/convert/settings-schema.ts +27 -0
  201. package/src/convert/types.ts +65 -0
  202. package/src/diagnosis/cards.ts +498 -0
  203. package/src/diagnosis/problem-classes.ts +117 -0
  204. package/src/diagnosis/schema.ts +260 -0
  205. package/src/diagnosis/seed-source.ts +107 -0
  206. package/src/diagnosis/seed.ts +291 -0
  207. package/src/diagnosis/store.ts +432 -0
  208. package/src/diagnosis/types.ts +152 -0
  209. package/src/directory-picker.ts +164 -0
  210. package/src/extract-model.ts +227 -0
  211. package/src/extract.ts +632 -0
  212. package/src/fts.ts +203 -0
  213. package/src/index.ts +1091 -0
  214. package/src/intent/README.md +63 -0
  215. package/src/intent/engine.ts +527 -0
  216. package/src/intent/host.ts +462 -0
  217. package/src/intent/preset-tools.ts +48 -0
  218. package/src/intent/settings-schema.ts +63 -0
  219. package/src/intent/store.ts +143 -0
  220. package/src/intent/tools.ts +139 -0
  221. package/src/intent/types.ts +245 -0
  222. package/src/knowledge-bases.ts +1160 -0
  223. package/src/layout.ts +350 -0
  224. package/src/migrate.ts +262 -0
  225. package/src/python/embedding_worker.py +471 -0
  226. package/src/recall-rank.ts +299 -0
  227. package/src/runtime.ts +3069 -0
  228. package/src/settings-schema.ts +94 -0
  229. package/src/settings-volatile.ts +122 -0
  230. package/src/types.ts +1140 -0
  231. package/src/wiki-types.ts +357 -0
@@ -0,0 +1,409 @@
1
+ import { mkdir, readFile, readdir, writeFile } from 'node:fs/promises';
2
+ import { join } from 'node:path';
3
+ import { SEED_CASES, SEED_GRAPH } from './seed.js';
4
+ import { seedSources } from './seed-source.js';
5
+ import { DIAGNOSIS_ENTITIES, templateCard, validateDiagnosis } from './schema.js';
6
+ import { cardsToGraph, cardPathOf, graphToCards, parseCard, serializeCard, RUN_EDGE_KINDS, } from './cards.js';
7
+ /**
8
+ * `05_diagnosis/` 的落盘与读取(v0.7 起:**卡片才是真相,这里只放一次排查的产物**)。
9
+ *
10
+ * ## 为什么要改
11
+ *
12
+ * 改版前这里同时扮演两个角色:既是 seed 写出来的 jsonl 数据集,又被当成图的唯一来源。
13
+ * 后果是排查思路**从来没进过 wiki** —— 不在 `01_source_truth`、不是 `02_wiki` 的卡片、
14
+ * 编译器不认它的 entity_type,于是不会被 wikiNote 化、不会进向量索引,**永远召不回来**。
15
+ * 而 `store.ts` 顶上那句「全部内容都能从 wiki 卡片确定性重建」描述的其实是目标状态,
16
+ * 代码走的是相反的路径。
17
+ *
18
+ * ## 现在的分工
19
+ *
20
+ * | 目录 | 内容 | 谁是真相 |
21
+ * | --- | --- | --- |
22
+ * | `01_source_truth/` | 手册与复盘原文(`sourceType=question`) | 人写的原始材料 |
23
+ * | `02_wiki/diagnosis/` | 五类卡片(三段式) | **知识侧的唯一真相** |
24
+ * | `05_diagnosis/` | `evidence` / `cause` / 执行边(`produces` `supports` `refutes` `confirmed_as`)与模板卡 | 一次排查的产物 |
25
+ *
26
+ * 读取顺序是显式的:**有卡片就编译卡片;没有卡片但有旧 jsonl 就按旧格式读出来(并尝试
27
+ * 前向迁移);两者都没有才灌 seed**。老知识根不会因为这次改动而读不出内容。
28
+ */
29
+ const DIR = '05_diagnosis';
30
+ /** 一次排查写下的节点:它们不是知识,所以留在这里,不进卡片。 */
31
+ const RUN_NODE_SHARDS = {
32
+ 'evidence.jsonl': 'evidence',
33
+ 'causes.jsonl': 'cause',
34
+ };
35
+ /**
36
+ * 旧版的类型层分片。**只读,不再写**:v0.7 之前它们就是真相,现在它们的角色是
37
+ * 「迁移输入 + 历史快照」。迁移成功后内容已经在卡片里,这些文件保持原样以便追溯。
38
+ */
39
+ const LEGACY_SHARDS = {
40
+ 'symptoms.jsonl': 'symptom',
41
+ 'hypotheses.jsonl': 'hypothesis',
42
+ 'checks.jsonl': 'check',
43
+ 'failure-modes.jsonl': 'failure-mode',
44
+ 'assets.jsonl': 'asset',
45
+ 'cases.jsonl': 'case',
46
+ };
47
+ const README = `# 05_diagnosis
48
+
49
+ 这个目录**只放一次排查的产物**(\`evidence\` / \`cause\` / 执行边),以及新人照抄的模板卡。
50
+
51
+ 排查思路本身(现象 / 假设 / 检查 / 失败模式 / 案例)现在是 **wiki 卡片**,住在
52
+ \`02_wiki/diagnosis/\`,出处是 \`01_source_truth/\` 里的手册与复盘。图由卡片编译而来 ——
53
+ 所以改知识要改卡片(或改它的来源文档再重新编译),不要改这里。
54
+
55
+ \`*.jsonl\` 里若出现 \`symptoms\` / \`hypotheses\` / \`checks\` / \`failure-modes\` / \`assets\`
56
+ 等分片,那是 v0.7 之前的历史快照:版本升级时被读出来迁移成了卡片,之后不再更新。
57
+ `;
58
+ export class DiagnosisStore {
59
+ host;
60
+ constructor(host) {
61
+ this.host = host;
62
+ }
63
+ get dir() { return join(this.host.rootDir, DIR); }
64
+ get cardsDir() { return join(this.host.rootDir, '02_wiki', 'diagnosis'); }
65
+ /**
66
+ * 幂等初始化。三种状态各自处理,互不覆盖:
67
+ *
68
+ * 1. 已有卡片 → 什么都不做(卡片是真相,人可能刚改过);
69
+ * 2. 没有卡片但有旧 jsonl → **前向迁移**:把旧图反推成卡片写出去,并**校验迁移无损**
70
+ * (重新编译一遍与旧图比对,不一致就不认这次迁移,继续按 jsonl 读 —— 宁可留在旧形态,
71
+ * 也不要静默丢知识);
72
+ * 3. 两者都没有 → 首次启动:先落手册与复盘的 SourceRaw,再把 seed 编译成卡片。
73
+ */
74
+ async ensure() {
75
+ await mkdir(this.dir, { recursive: true });
76
+ const templates = join(this.dir, 'templates');
77
+ await mkdir(templates, { recursive: true });
78
+ await Promise.all(DIAGNOSIS_ENTITIES.map(spec => this.writeIfAbsent(join(templates, `${spec.entityType.replace(/\//g, '-')}.md`), templateCard(spec))));
79
+ // 目录角色的说明也要落盘:下一个人只打开 05_diagnosis 时,得知道知识已经搬走了。
80
+ await this.writeIfAbsent(join(this.dir, 'README.md'), README);
81
+ // 注意:**不要**在这里为一次排查的产物建空占位文件。它们走 `writeIfAbsent`,
82
+ // 而「占位」会在首次 seed 之前就把文件创建出来,于是 seed 的真实内容被判为「已存在」
83
+ // 而写不进去 —— 结果是图上少了 evidence / cause 五个节点,且没有任何报错。
84
+ if ((await this.readCards()).length > 0)
85
+ return { seeded: false, migrated: false, problems: [] };
86
+ if ((await this.legacyShardFiles()).length > 0)
87
+ return await this.migrate();
88
+ return await this.seed();
89
+ }
90
+ async snapshot() {
91
+ const { seeded, migrated, problems } = await this.ensure();
92
+ const cards = await this.readCards();
93
+ const run = await this.readRunArtifacts();
94
+ if (cards.length > 0) {
95
+ const compiled = cardsToGraph(cards);
96
+ const graph = {
97
+ nodes: [...compiled.graph.nodes, ...run.nodes],
98
+ edges: [...compiled.graph.edges, ...run.edges],
99
+ };
100
+ return {
101
+ graph,
102
+ cases: compiled.cases,
103
+ issues: validateDiagnosis(graph),
104
+ seeded,
105
+ migrated,
106
+ source: 'cards',
107
+ problems: [...problems, ...compiled.problems],
108
+ };
109
+ }
110
+ // 还没有卡片:旧 jsonl(或 seed 刚写下的那份)就是当前可读的来源。
111
+ const graph = await this.readGraph();
112
+ const cases = await this.readCases();
113
+ return {
114
+ graph,
115
+ cases,
116
+ issues: validateDiagnosis(graph),
117
+ seeded,
118
+ migrated,
119
+ source: (await this.legacyShardFiles()).length > 0 ? 'jsonl' : 'seed',
120
+ problems,
121
+ };
122
+ }
123
+ /**
124
+ * 图。
125
+ *
126
+ * 有卡片:`cardsToGraph(卡片)` + 一次排查的产物;没有卡片:按旧 jsonl 读。
127
+ * 两条路径都返回同一种形状,调用方不需要知道现在是哪一代。
128
+ */
129
+ async readGraph() {
130
+ const cards = await this.readCards();
131
+ if (cards.length > 0) {
132
+ const compiled = cardsToGraph(cards);
133
+ const run = await this.readRunArtifacts();
134
+ return { nodes: [...compiled.graph.nodes, ...run.nodes], edges: [...compiled.graph.edges, ...run.edges] };
135
+ }
136
+ return await this.readLegacyGraph();
137
+ }
138
+ async readCases() {
139
+ const cards = await this.readCards();
140
+ if (cards.length > 0)
141
+ return cardsToGraph(cards).cases;
142
+ try {
143
+ const raw = await readFile(join(this.dir, 'cases.json'), 'utf8');
144
+ const parsed = JSON.parse(raw);
145
+ return Array.isArray(parsed) ? parsed : [];
146
+ }
147
+ catch {
148
+ return [];
149
+ }
150
+ }
151
+ /* ────────────────────────────────────────────── 卡片:读写 ── */
152
+ /** 读 `02_wiki/diagnosis/**` 下的全部卡片。解析不出来的文件按「不是卡片」跳过。 */
153
+ async readCards() {
154
+ const cards = [];
155
+ for (const file of await walkMarkdown(this.cardsDir)) {
156
+ const card = parseCard(await readFile(file, 'utf8'));
157
+ if (card)
158
+ cards.push(card);
159
+ }
160
+ return cards;
161
+ }
162
+ /** 写一批卡片。返回写失败的原因(schema 不认、出处不存在等),由调用方决定怎么显示。 */
163
+ async writeCards(cards) {
164
+ const problems = [];
165
+ for (const card of cards) {
166
+ const written = await this.host.writeCard({
167
+ entityType: card.entityType,
168
+ entityId: card.entityId,
169
+ title: card.title,
170
+ content: renderBody(card),
171
+ sourceRefs: card.sourceRefs,
172
+ status: card.status,
173
+ ...(card.summary ? { summary: card.summary } : {}),
174
+ ...(card.owner ? { owner: card.owner } : {}),
175
+ });
176
+ if (written.ok === false)
177
+ problems.push(`卡片 ${card.entityId} 写入失败:${written.error.code} ${written.error.message}`);
178
+ }
179
+ return problems;
180
+ }
181
+ /* ────────────────────────────────────────────── 首次 seed ── */
182
+ async seed() {
183
+ const { problems: sourceProblems, refs } = await this.writeSources(seedSources());
184
+ const cards = withSourceRefs(graphToCards(SEED_GRAPH, SEED_CASES), refs, SEED_GRAPH, SEED_CASES);
185
+ const problems = [...sourceProblems, ...await this.writeCards(cards)];
186
+ // 一次排查的产物照旧落在这里 —— seed 本来就等于「已经发生过的那三次排查」。
187
+ await this.writeRunArtifacts(SEED_GRAPH);
188
+ await this.writeLegacySnapshot();
189
+ return { seeded: true, migrated: false, problems };
190
+ }
191
+ /* ────────────────────────────────────────────── 旧知识根迁移 ── */
192
+ async migrate() {
193
+ const legacy = await this.readLegacyGraph();
194
+ const cases = await this.readCases();
195
+ // **先在内存里验证,通过才写盘。**
196
+ //
197
+ // 卡片表达不了的东西确实存在:手工加的边、没有任何假设引用的资产节点……一旦迁移会丢,
198
+ // 就宁可留在旧形态,也不要静默丢知识。而「先写再验、失败回滚」会留一个更糟的中间态:
199
+ // 卡片已经落盘,下一次读就成了卡片来源 —— 于是分歧只在第一次读时被报出来,
200
+ // 之后再也看不见。所以顺序是:编译 → 比对 → 才写。
201
+ const run = await this.readRunArtifacts();
202
+ const draft = graphToCards(legacy, cases);
203
+ const compiled = cardsToGraph(draft);
204
+ const divergence = compareGraphs(legacy, {
205
+ nodes: [...compiled.graph.nodes, ...run.nodes],
206
+ edges: [...compiled.graph.edges, ...run.edges],
207
+ });
208
+ if (divergence) {
209
+ return { seeded: false, migrated: false, problems: [`迁移未生效(仍按 05_diagnosis/*.jsonl 读):${divergence}`] };
210
+ }
211
+ const { problems: sourceProblems, refs } = await this.writeSources(seedSources());
212
+ const problems = [...sourceProblems, ...await this.writeCards(withSourceRefs(draft, refs, legacy, cases))];
213
+ return { seeded: false, migrated: problems.length === 0, problems };
214
+ }
215
+ /* ────────────────────────────────────────────── SourceRaw ── */
216
+ /**
217
+ * 落原始材料。
218
+ *
219
+ * 一个细节:种子手册与三篇复盘在**非首次**运行时可能已经存在(用户的知识根里),
220
+ * `addSource` 用 `externalId` 幂等,所以重复调用不会写出第二份。
221
+ */
222
+ async writeSources(sources) {
223
+ const problems = [];
224
+ const refs = new Map();
225
+ for (const source of sources) {
226
+ const added = await this.host.addSource({
227
+ sourceType: source.sourceType,
228
+ title: source.title,
229
+ content: source.content,
230
+ externalId: `diagnosis-seed:${source.id}`,
231
+ });
232
+ if (added.ok === false)
233
+ problems.push(`来源 ${source.id} 写入失败:${added.error.code} ${added.error.message}`);
234
+ else
235
+ refs.set(source.id, added.data.sourceId);
236
+ }
237
+ return { problems, refs };
238
+ }
239
+ /* ────────────────────────────────────────────── 一次排查的产物 ── */
240
+ async readRunArtifacts() {
241
+ const nodes = [];
242
+ for (const file of Object.keys(RUN_NODE_SHARDS)) {
243
+ for (const row of await this.readLines(join(this.dir, file))) {
244
+ try {
245
+ nodes.push(JSON.parse(row));
246
+ }
247
+ catch { /* 跳过损坏行,不让一行毁掉整张图 */ }
248
+ }
249
+ }
250
+ const edges = [];
251
+ for (const row of await this.readLines(join(this.dir, 'edges.jsonl'))) {
252
+ try {
253
+ const edge = JSON.parse(row);
254
+ // 只认执行边:五种卡片边由卡片投影出来,这里再读一遍就会出现重复边。
255
+ if (RUN_EDGE_KINDS.includes(edge.kind))
256
+ edges.push(edge);
257
+ }
258
+ catch { /* 同上 */ }
259
+ }
260
+ return { nodes, edges };
261
+ }
262
+ async writeRunArtifacts(graph) {
263
+ for (const [file, kind] of Object.entries(RUN_NODE_SHARDS)) {
264
+ const rows = graph.nodes.filter(node => node.kind === kind);
265
+ await this.writeIfAbsent(join(this.dir, file), rows.map(row => JSON.stringify(row)).join('\n'));
266
+ }
267
+ await this.writeIfAbsent(join(this.dir, 'edges.jsonl'), graph.edges.filter(edge => RUN_EDGE_KINDS.includes(edge.kind)).map(edge => JSON.stringify(edge)).join('\n'));
268
+ }
269
+ /** 旧版的类型层快照。首次 seed 时也写一份:它让 `05_diagnosis/` 仍是一份可读的完整快照。 */
270
+ async writeLegacySnapshot() {
271
+ for (const [file, kind] of Object.entries(LEGACY_SHARDS)) {
272
+ const rows = SEED_GRAPH.nodes.filter(node => node.kind === kind);
273
+ await this.writeIfAbsent(join(this.dir, file), rows.map(row => JSON.stringify(row)).join('\n'));
274
+ }
275
+ await this.writeIfAbsent(join(this.dir, 'cases.json'), JSON.stringify(SEED_CASES, null, 2));
276
+ }
277
+ /* ────────────────────────────────────────────── 旧读法 ── */
278
+ async readLegacyGraph() {
279
+ const nodes = [];
280
+ for (const [file, kind] of Object.entries({ ...LEGACY_SHARDS, ...RUN_NODE_SHARDS })) {
281
+ for (const row of await this.readLines(join(this.dir, file))) {
282
+ try {
283
+ nodes.push(JSON.parse(row));
284
+ }
285
+ catch { /* 跳过损坏行 */ }
286
+ }
287
+ void kind;
288
+ }
289
+ const edges = [];
290
+ for (const row of await this.readLines(join(this.dir, 'edges.jsonl'))) {
291
+ try {
292
+ edges.push(JSON.parse(row));
293
+ }
294
+ catch { /* 同上 */ }
295
+ }
296
+ return { nodes, edges };
297
+ }
298
+ /**
299
+ * 是否存在**值得迁移的旧知识根**。
300
+ *
301
+ * 只看旧版的**类型层**分片,而且要求它真的有内容:`ensure()` 自己会为一次排查的产物
302
+ * (`evidence.jsonl` 等)建空占位文件 —— 若把空文件也算成「旧知识根」,首次启动会走进
303
+ * 迁移分支,然后在空图上白跑一趟。
304
+ */
305
+ async legacyShardFiles() {
306
+ const found = [];
307
+ for (const file of Object.keys(LEGACY_SHARDS)) {
308
+ if ((await this.readLines(join(this.dir, file))).length > 0)
309
+ found.push(file);
310
+ }
311
+ return found;
312
+ }
313
+ async readLines(path) {
314
+ try {
315
+ return (await readFile(path, 'utf8')).split('\n').map(line => line.trim()).filter(Boolean);
316
+ }
317
+ catch {
318
+ return [];
319
+ }
320
+ }
321
+ async writeIfAbsent(path, content) {
322
+ try {
323
+ await readFile(path);
324
+ return;
325
+ }
326
+ catch {
327
+ await writeFile(path, content, 'utf8');
328
+ }
329
+ }
330
+ }
331
+ /** 卡片正文:小节 + 结构化块。复用编解码里的同一套序列化,避免两处格式漂移。 */
332
+ function renderBody(card) {
333
+ const text = serializeCard(card);
334
+ return text.slice(text.indexOf('\n---\n', 3) + 5).trim();
335
+ }
336
+ /**
337
+ * 给卡片挂出处。
338
+ *
339
+ * 规则是**数据驱动的**,不是凭印象分的:案例卡片与它自己的复盘原文一一对应;
340
+ * 其它卡片取「第一篇走过它的复盘」,没有走过它的就挂那本手册。
341
+ */
342
+ function withSourceRefs(cards, refs, graph, cases) {
343
+ const handbook = refs.get('handbook');
344
+ /** 节点 id → 它出现在哪篇复盘里(取第一篇)。 */
345
+ const caseOf = new Map();
346
+ for (const item of cases) {
347
+ const ref = refs.get(item.id);
348
+ if (!ref)
349
+ continue;
350
+ caseOf.set(item.symptomId, ref);
351
+ for (const step of item.path)
352
+ if (!caseOf.has(step.nodeId))
353
+ caseOf.set(step.nodeId, ref);
354
+ }
355
+ void graph;
356
+ return cards.map(card => {
357
+ const own = card.entityType === 'diagnosis/case' ? refs.get(card.entityId) : undefined;
358
+ const ref = own ?? caseOf.get(card.entityId) ?? handbook;
359
+ return { ...card, sourceRefs: ref ? [ref] : [] };
360
+ });
361
+ }
362
+ /**
363
+ * 两张图是否一致。返回 `undefined` 表示一致,否则返回第一条差异的人话描述。
364
+ *
365
+ * 比较的是**边的身份**(kind + 两端)而不是边的 id:卡片投影出来的 id 与旧文件的 id
366
+ * 可能不同名(`e-s-h1` vs `e-s1-h1-0`),而 id 不是知识 —— 同一对端点上的同一种关系才是。
367
+ */
368
+ function compareGraphs(expected, actual) {
369
+ const nodesOf = (graph) => new Set(graph.nodes.map(node => `${node.id}:${node.kind}:${node.layer}`));
370
+ const edgesOf = (graph) => new Set(graph.edges.map(edge => `${edge.kind}:${edge.source}->${edge.target}`));
371
+ const expectedNodes = nodesOf(expected);
372
+ const actualNodes = nodesOf(actual);
373
+ for (const node of expectedNodes)
374
+ if (!actualNodes.has(node))
375
+ return `节点 ${node} 在迁移后消失`;
376
+ for (const node of actualNodes)
377
+ if (!expectedNodes.has(node))
378
+ return `迁移后多出节点 ${node}`;
379
+ const expectedEdges = edgesOf(expected);
380
+ const actualEdges = edgesOf(actual);
381
+ for (const edge of expectedEdges)
382
+ if (!actualEdges.has(edge))
383
+ return `边 ${edge} 在迁移后消失`;
384
+ for (const edge of actualEdges)
385
+ if (!expectedEdges.has(edge))
386
+ return `迁移后多出边 ${edge}`;
387
+ return undefined;
388
+ }
389
+ /** 递归收集 markdown 文件。卡片目录是两层(`diagnosis/<kind>/`),但这里不假设层数。 */
390
+ async function walkMarkdown(dir) {
391
+ const found = [];
392
+ let entries;
393
+ try {
394
+ entries = await readdir(dir, { withFileTypes: true });
395
+ }
396
+ catch {
397
+ return found;
398
+ }
399
+ for (const entry of entries) {
400
+ const path = join(dir, entry.name);
401
+ if (entry.isDirectory())
402
+ found.push(...await walkMarkdown(path));
403
+ else if (entry.isFile() && entry.name.endsWith('.md'))
404
+ found.push(path);
405
+ }
406
+ return found;
407
+ }
408
+ export { cardPathOf };
409
+ //# sourceMappingURL=store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"store.js","sourceRoot":"","sources":["../../../src/diagnosis/store.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,124 @@
1
+ /**
2
+ * 归因图谱的**领域模型**:节点 / 边 / 图 的形状与枚举。
3
+ *
4
+ * 为什么它不在 client 里:宿主也要读写同一套结构(`05_diagnosis/*.jsonl`、
5
+ * `/diagnosis/graph`)。视图是消费者,不是所有者 —— 模型放在领域层,客户端和宿主
6
+ * 各自 import,谁都不能私自改形状。
7
+ *
8
+ * 目录约定:`src/diagnosis/` 与 `src/intent/`、`src/convert/` 平级,都是领域子模块;
9
+ * `src/client/` 只放渲染。判据与 0020 第 3 条一致:**目录镜像领域流水线,不镜像技术层次**。
10
+ */
11
+ import type { ProblemClassId } from './problem-classes.js';
12
+ /** 类型层 / 引用层 / 实例层。轴不同,不能合成一种节点。 */
13
+ export type NodeLayer = 'type' | 'reference' | 'instance';
14
+ /** 九类归因节点。与 wiki 卡片的 `entity_type` 一一对应。 */
15
+ export type AttributionNodeKind = 'symptom' | 'hypothesis' | 'check' | 'failure-mode' | 'asset' | 'case' | 'evidence' | 'cause' | 'unknown';
16
+ /** 失败模式切面。分类只影响排序与分组,不影响「能查到什么」。 */
17
+ export type FailureMode = 'upstream-missing' | 'spec-change' | 'data-processing' | 'consumption' | 'permission';
18
+ /**
19
+ * 问题侧的分类字段(只出现在 symptom 节点上)。
20
+ *
21
+ * 与 `FailureMode` 是**两根不同的轴,不能合并**:这一对说的是「问题是什么样」,
22
+ * `failureMode` 说的是「原因出在哪一环」。前者挂在现象上、值班同学看到异常就能填;
23
+ * 后者挂在假设上、要等排查有结论。合成一根轴,就会出现「异常波动归因属于哪个问题大类」
24
+ * 这种没有答案的问题(0021 §4.5 与本文件顶部的分层原则)。
25
+ */
26
+ export interface ProblemTaxonomy {
27
+ /** 问题大类。取值来自 `problem-classes.ts` 的 PROBLEM_CLASSES。 */
28
+ problemClass?: ProblemClassId;
29
+ /** 问题子类;必须属于所选大类。它同时决定 §5.1 的 shape / time_pattern。 */
30
+ problemSubclass?: string;
31
+ }
32
+ /** 九种边。层内定义可能性与顺序,跨层定义证据与复用。 */
33
+ export type AttributionEdgeKind = 'may_be_caused_by' | 'verified_by' | 'categorized_as' | 'produces' | 'supports' | 'refutes' | 'confirmed_as' | 'instance_of' | 'indexed_from';
34
+ export interface AttributionNode extends ProblemTaxonomy {
35
+ id: string;
36
+ kind: AttributionNodeKind;
37
+ layer: NodeLayer;
38
+ title: string;
39
+ /** 一句话判据。图谱视图在 tooltip 与侧栏里用它,而不是靠标题猜。 */
40
+ summary?: string;
41
+ failureMode?: FailureMode;
42
+ /** 被复用次数:节点大小由它决定,这是「图有没有在被用」最直接的读数。 */
43
+ reuseCount?: number;
44
+ /** 最低成本检查的耗时(分钟),单位与 0021 §4.4 一致。 */
45
+ costMinutes?: number;
46
+ automation?: 'auto' | 'manual';
47
+ owner?: string;
48
+ /**
49
+ * 假设的判据:一句**可判真假**的话。
50
+ *
51
+ * 与 `summary` 分开是有意的 —— `summary` 是给人读的说明,`discriminator` 是要被
52
+ * 校验的断言(schema 里必填),它也是新增假设前查重的比对对象。
53
+ */
54
+ discriminator?: string;
55
+ /**
56
+ * 反例边界:什么情况下这个假设**不**成立。
57
+ *
58
+ * 它是 `refutes` 边在文档层的表达,也是唯一能安放「看起来像 A 但不是 A」的地方。
59
+ * 没有它,查重会把所有相似情形并进一条假设,图会慢慢失去分辨力。
60
+ */
61
+ notWhen?: string;
62
+ /** 检查的判定阈值:看到什么算真 / 算假。缺了它,这一步就无法被自动化或复核。 */
63
+ verdictTrue?: string;
64
+ verdictFalse?: string;
65
+ /**
66
+ * 失败模式节点的稳定编码(= `FailureMode`)。只出现在 `failure-mode` 节点上。
67
+ *
68
+ * 假设卡片里写的是 `failure_mode: data-processing`(编码),而边要连到**节点**,
69
+ * 所以需要一条「编码 → 节点 id」的可逆映射。少了它,`categorized_as` 边就只能靠
70
+ * 「F1 恰好是第一个失败模式」这种位置约定去猜 —— 那是会在某次重排后静默出错的东西。
71
+ */
72
+ code?: FailureMode;
73
+ /** 边或节点是否已被判定失效(原因已修好 / 90 天未走)。 */
74
+ stale?: boolean;
75
+ }
76
+ export interface AttributionEdge {
77
+ id: string;
78
+ source: string;
79
+ target: string;
80
+ kind: AttributionEdgeKind;
81
+ /** 边上的计数:`instance_of` 上挂的是这一段的案例数。 */
82
+ count?: number;
83
+ /**
84
+ * 距上次走过这条边的天数。超过 `ZOMBIE_EDGE_DAYS` 就是僵尸边。
85
+ *
86
+ * 存天数而不是布尔值:`stale` 只够染个灰,而化解「权重过期」(0021 §13)需要
87
+ * 知道到底多久没走 —— 「94 天」和「91 天」对维护者是两种不同的紧迫感。
88
+ */
89
+ staleDays?: number;
90
+ }
91
+ /** 超过这么多天没走过的可能性边算僵尸边。 */
92
+ export declare const ZOMBIE_EDGE_DAYS = 90;
93
+ export interface AttributionGraphData {
94
+ nodes: AttributionNode[];
95
+ edges: AttributionEdge[];
96
+ /** 后端返回的图谱总体统计;缺省时由 summarize() 现算。 */
97
+ stats?: Partial<AttributionStats>;
98
+ }
99
+ export interface AttributionStats {
100
+ typeNodes: number;
101
+ referenceNodes: number;
102
+ instanceNodes: number;
103
+ reuseTotal: number;
104
+ /**
105
+ * 现象(问题侧)节点数。
106
+ *
107
+ * 单独数出来,是因为它和图例的关系最容易被看错:图例里的五种颜色**全是原因侧**
108
+ * (失败模式),而问题侧有几个节点、有没有分类,必须能一眼读到 —— 否则「图上那些
109
+ * 颜色在说问题还是说原因」就只能靠猜。
110
+ */
111
+ symptoms: number;
112
+ /**
113
+ * 现象覆盖到的**问题大类个数**(0–4)。
114
+ *
115
+ * 它和 `symptoms` 一起回答「问题侧的层次建起来没有」:3 个现象全挤在一个大类里,
116
+ * 和 3 个现象铺在 3 个大类上,是两种完全不同的知识库存量。
117
+ */
118
+ problemClasses: number;
119
+ /** 空区:有假设,但一条检查都没有。它是「这张图哪里还没建完」的读数。 */
120
+ gaps: number;
121
+ /** 僵尸边:90 天未被走过的 `may_be_caused_by`。 */
122
+ zombies: number;
123
+ }
124
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/diagnosis/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAA;AAE1D,oCAAoC;AACpC,MAAM,MAAM,SAAS,GAAG,MAAM,GAAG,WAAW,GAAG,UAAU,CAAA;AAEzD,4CAA4C;AAC5C,MAAM,MAAM,mBAAmB,GAC3B,SAAS,GACT,YAAY,GACZ,OAAO,GACP,cAAc,GACd,OAAO,GACP,MAAM,GACN,UAAU,GACV,OAAO,GACP,SAAS,CAAA;AAEb,oCAAoC;AACpC,MAAM,MAAM,WAAW,GAAG,kBAAkB,GAAG,aAAa,GAAG,iBAAiB,GAAG,aAAa,GAAG,YAAY,CAAA;AAE/G;;;;;;;GAOG;AACH,MAAM,WAAW,eAAe;IAC9B,wDAAwD;IACxD,YAAY,CAAC,EAAE,cAAc,CAAA;IAC7B,uDAAuD;IACvD,eAAe,CAAC,EAAE,MAAM,CAAA;CACzB;AAED,gCAAgC;AAChC,MAAM,MAAM,mBAAmB,GAC3B,kBAAkB,GAClB,aAAa,GACb,gBAAgB,GAChB,UAAU,GACV,UAAU,GACV,SAAS,GACT,cAAc,GACd,aAAa,GACb,cAAc,CAAA;AAElB,MAAM,WAAW,eAAgB,SAAQ,eAAe;IACtD,EAAE,EAAE,MAAM,CAAA;IACV,IAAI,EAAE,mBAAmB,CAAA;IACzB,KAAK,EAAE,SAAS,CAAA;IAChB,KAAK,EAAE,MAAM,CAAA;IACb,0CAA0C;IAC1C,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,WAAW,CAAC,EAAE,WAAW,CAAA;IACzB,wCAAwC;IACxC,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,sCAAsC;IACtC,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,UAAU,CAAC,EAAE,MAAM,GAAG,QAAQ,CAAA;IAC9B,KAAK,CAAC,EAAE,MAAM,CAAA;IACd;;;;;OAKG;IACH,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB;;;;;OAKG;IACH,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,6CAA6C;IAC7C,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB;;;;;;OAMG;IACH,IAAI,CAAC,EAAE,WAAW,CAAA;IAClB,oCAAoC;IACpC,KAAK,CAAC,EAAE,OAAO,CAAA;CAChB;AAED,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,CAAA;IACV,MAAM,EAAE,MAAM,CAAA;IACd,MAAM,EAAE,MAAM,CAAA;IACd,IAAI,EAAE,mBAAmB,CAAA;IACzB,uCAAuC;IACvC,KAAK,CAAC,EAAE,MAAM,CAAA;IACd;;;;;OAKG;IACH,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAED,0BAA0B;AAC1B,eAAO,MAAM,gBAAgB,KAAK,CAAA;AAElC,MAAM,WAAW,oBAAoB;IACnC,KAAK,EAAE,eAAe,EAAE,CAAA;IACxB,KAAK,EAAE,eAAe,EAAE,CAAA;IACxB,uCAAuC;IACvC,KAAK,CAAC,EAAE,OAAO,CAAC,gBAAgB,CAAC,CAAA;CAClC;AAED,MAAM,WAAW,gBAAgB;IAC/B,SAAS,EAAE,MAAM,CAAA;IACjB,cAAc,EAAE,MAAM,CAAA;IACtB,aAAa,EAAE,MAAM,CAAA;IACrB,UAAU,EAAE,MAAM,CAAA;IAClB;;;;;;OAMG;IACH,QAAQ,EAAE,MAAM,CAAA;IAChB;;;;;OAKG;IACH,cAAc,EAAE,MAAM,CAAA;IACtB,wCAAwC;IACxC,IAAI,EAAE,MAAM,CAAA;IACZ,wCAAwC;IACxC,OAAO,EAAE,MAAM,CAAA;CAChB"}
@@ -0,0 +1,13 @@
1
+ /**
2
+ * 归因图谱的**领域模型**:节点 / 边 / 图 的形状与枚举。
3
+ *
4
+ * 为什么它不在 client 里:宿主也要读写同一套结构(`05_diagnosis/*.jsonl`、
5
+ * `/diagnosis/graph`)。视图是消费者,不是所有者 —— 模型放在领域层,客户端和宿主
6
+ * 各自 import,谁都不能私自改形状。
7
+ *
8
+ * 目录约定:`src/diagnosis/` 与 `src/intent/`、`src/convert/` 平级,都是领域子模块;
9
+ * `src/client/` 只放渲染。判据与 0020 第 3 条一致:**目录镜像领域流水线,不镜像技术层次**。
10
+ */
11
+ /** 超过这么多天没走过的可能性边算僵尸边。 */
12
+ export const ZOMBIE_EDGE_DAYS = 90;
13
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/diagnosis/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AA4GH,0BAA0B;AAC1B,MAAM,CAAC,MAAM,gBAAgB,GAAG,EAAE,CAAA"}