clearai-dsh 0.3.1 → 0.4.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.
Files changed (148) hide show
  1. package/CHANGELOG.md +132 -0
  2. package/README.md +28 -28
  3. package/README.zh-CN.md +28 -28
  4. package/lib/client.js +861 -2555
  5. package/lib/domain-language.js +552 -48
  6. package/lib/fold.js +349 -1015
  7. package/lib/host.js +47 -557
  8. package/lib/invariant.js +9 -12
  9. package/lib/knowledge-view.js +363 -226
  10. package/lib/lang.js +81 -0
  11. package/package.json +1 -1
  12. package/presets/clearai/agent.cordis.yml +54 -82
  13. package/presets/clearai/clearai.patch.yml +54 -82
  14. package/presets/clearai/plugins/clearai-kernel.js +1584 -5456
  15. package/presets/clearai/plugins/ontology.js +56 -14
  16. package/presets/clearai/plugins/prompts.js +73 -363
  17. package/presets/clearai/skills/clearai-loop/SKILL.md +73 -59
  18. package/presets/clearai/plugins/brain.js +0 -547
  19. package/presets/clearai/plugins/commands.js +0 -199
  20. package/presets/clearai/template/knowledge/README.md +0 -25
  21. package/presets/clearai/template/memory/README.md +0 -34
  22. package/presets/clearai/template/project.md +0 -49
  23. package/presets/clearai/template/skills/README.md +0 -37
  24. package/presets/clearai/template/skills/chart-diagram-qa/SKILL.md +0 -43
  25. package/presets/clearai/template/skills/citation-management/SKILL.md +0 -73
  26. package/presets/clearai/template/skills/citation-management/references/bibtex_formatting.md +0 -908
  27. package/presets/clearai/template/skills/citation-management/references/citation_validation.md +0 -794
  28. package/presets/clearai/template/skills/citation-management/references/google_scholar_search.md +0 -725
  29. package/presets/clearai/template/skills/citation-management/references/metadata_extraction.md +0 -870
  30. package/presets/clearai/template/skills/citation-management/references/pubmed_search.md +0 -839
  31. package/presets/clearai/template/skills/citation-management/scripts/doi_to_bibtex.py +0 -204
  32. package/presets/clearai/template/skills/citation-management/scripts/extract_metadata.py +0 -569
  33. package/presets/clearai/template/skills/citation-management/scripts/format_bibtex.py +0 -349
  34. package/presets/clearai/template/skills/citation-management/scripts/generate_schematic.py +0 -139
  35. package/presets/clearai/template/skills/citation-management/scripts/generate_schematic_ai.py +0 -817
  36. package/presets/clearai/template/skills/citation-management/scripts/search_google_scholar.py +0 -282
  37. package/presets/clearai/template/skills/citation-management/scripts/search_pubmed.py +0 -398
  38. package/presets/clearai/template/skills/citation-management/scripts/validate_citations.py +0 -497
  39. package/presets/clearai/template/skills/data-analysis/SKILL.md +0 -92
  40. package/presets/clearai/template/skills/data-analysis/checklists/readiness_check.md +0 -23
  41. package/presets/clearai/template/skills/data-analysis/templates/analysis_report.md.tpl +0 -63
  42. package/presets/clearai/template/skills/data-analysis/templates/cleaning_rules_draft.yaml.tpl +0 -32
  43. package/presets/clearai/template/skills/data-analysis/templates/data_dictionary.md.tpl +0 -12
  44. package/presets/clearai/template/skills/data-analysis/templates/domain_knowledge_template.md.tpl +0 -316
  45. package/presets/clearai/template/skills/data-analysis/templates/feature_candidates.json.tpl +0 -20
  46. package/presets/clearai/template/skills/data-analysis/templates/quality_scorecard.md.tpl +0 -30
  47. package/presets/clearai/template/skills/data-analysis/workflows/01-data-profiling.md +0 -42
  48. package/presets/clearai/template/skills/data-analysis/workflows/02-quality-audit.md +0 -36
  49. package/presets/clearai/template/skills/data-analysis/workflows/03-physical-correlation.md +0 -25
  50. package/presets/clearai/template/skills/data-analysis/workflows/04-unstructured-mining.md +0 -26
  51. package/presets/clearai/template/skills/data-qa-analysis/SKILL.md +0 -102
  52. package/presets/clearai/template/skills/data-qa-analysis/checklists/readiness_check.md +0 -62
  53. package/presets/clearai/template/skills/data-qa-analysis/templates/best_in_class_report.md.tpl +0 -56
  54. package/presets/clearai/template/skills/data-qa-analysis/templates/cleaning_rules_draft.yaml.tpl +0 -56
  55. package/presets/clearai/template/skills/data-qa-analysis/templates/data_dictionary.md.tpl +0 -13
  56. package/presets/clearai/template/skills/data-qa-analysis/templates/data_source_inventory_and_lineage.md.tpl +0 -146
  57. package/presets/clearai/template/skills/data-qa-analysis/templates/data_status_report.md.tpl +0 -60
  58. package/presets/clearai/template/skills/data-qa-analysis/templates/steady_state_rules.yaml.tpl +0 -41
  59. package/presets/clearai/template/skills/data-qa-analysis/templates/subsystem_registry.md.tpl +0 -101
  60. package/presets/clearai/template/skills/data-qa-analysis/templates/unified_execution_plan.md.tpl +0 -100
  61. package/presets/clearai/template/skills/data-qa-analysis/workflows/01-data-source-inventory-and-lineage.md +0 -194
  62. package/presets/clearai/template/skills/data-qa-analysis/workflows/02-data-alignment-and-tag-semantics.md +0 -122
  63. package/presets/clearai/template/skills/data-qa-analysis/workflows/03-steady-state-identification.md +0 -126
  64. package/presets/clearai/template/skills/data-qa-analysis/workflows/04-consumption-analysis.md +0 -152
  65. package/presets/clearai/template/skills/data-qa-analysis/workflows/05-best-in-class-and-optimization-space.md +0 -78
  66. package/presets/clearai/template/skills/domain-presearch/SKILL.md +0 -131
  67. package/presets/clearai/template/skills/domain-presearch/checklists/domain_checklist.md +0 -24
  68. package/presets/clearai/template/skills/domain-presearch/references/figure_code.md +0 -78
  69. package/presets/clearai/template/skills/domain-presearch/references/strategic_frameworks.md +0 -38
  70. package/presets/clearai/template/skills/exploration-loop/SKILL.md +0 -81
  71. package/presets/clearai/template/skills/exploratory-data-analysis/SKILL.md +0 -77
  72. package/presets/clearai/template/skills/exploratory-data-analysis/references/bioinformatics_genomics_formats.md +0 -664
  73. package/presets/clearai/template/skills/exploratory-data-analysis/references/chemistry_molecular_formats.md +0 -664
  74. package/presets/clearai/template/skills/exploratory-data-analysis/references/general_scientific_formats.md +0 -518
  75. package/presets/clearai/template/skills/exploratory-data-analysis/references/microscopy_imaging_formats.md +0 -620
  76. package/presets/clearai/template/skills/exploratory-data-analysis/references/proteomics_metabolomics_formats.md +0 -517
  77. package/presets/clearai/template/skills/exploratory-data-analysis/references/spectroscopy_analytical_formats.md +0 -633
  78. package/presets/clearai/template/skills/exploratory-data-analysis/scripts/eda_analyzer.py +0 -547
  79. package/presets/clearai/template/skills/hypothesis-generation/SKILL.md +0 -73
  80. package/presets/clearai/template/skills/hypothesis-generation/references/experimental_design_patterns.md +0 -329
  81. package/presets/clearai/template/skills/hypothesis-generation/references/hypothesis_quality_criteria.md +0 -198
  82. package/presets/clearai/template/skills/hypothesis-generation/references/literature_search_strategies.md +0 -622
  83. package/presets/clearai/template/skills/hypothesis-generation/scripts/generate_schematic.py +0 -139
  84. package/presets/clearai/template/skills/hypothesis-generation/scripts/generate_schematic_ai.py +0 -817
  85. package/presets/clearai/template/skills/literature-review/SKILL.md +0 -72
  86. package/presets/clearai/template/skills/literature-review/references/citation_styles.md +0 -166
  87. package/presets/clearai/template/skills/literature-review/references/database_strategies.md +0 -455
  88. package/presets/clearai/template/skills/literature-review/scripts/generate_pdf.py +0 -176
  89. package/presets/clearai/template/skills/literature-review/scripts/generate_schematic.py +0 -139
  90. package/presets/clearai/template/skills/literature-review/scripts/generate_schematic_ai.py +0 -817
  91. package/presets/clearai/template/skills/literature-review/scripts/search_databases.py +0 -303
  92. package/presets/clearai/template/skills/literature-review/scripts/verify_citations.py +0 -221
  93. package/presets/clearai/template/skills/paper-lookup/SKILL.md +0 -59
  94. package/presets/clearai/template/skills/paper-lookup/references/arxiv.md +0 -161
  95. package/presets/clearai/template/skills/paper-lookup/references/biorxiv.md +0 -118
  96. package/presets/clearai/template/skills/paper-lookup/references/core.md +0 -150
  97. package/presets/clearai/template/skills/paper-lookup/references/crossref.md +0 -181
  98. package/presets/clearai/template/skills/paper-lookup/references/medrxiv.md +0 -104
  99. package/presets/clearai/template/skills/paper-lookup/references/openalex.md +0 -174
  100. package/presets/clearai/template/skills/paper-lookup/references/pmc.md +0 -152
  101. package/presets/clearai/template/skills/paper-lookup/references/pubmed.md +0 -124
  102. package/presets/clearai/template/skills/paper-lookup/references/semantic-scholar.md +0 -203
  103. package/presets/clearai/template/skills/paper-lookup/references/unpaywall.md +0 -127
  104. package/presets/clearai/template/skills/process-presearch/SKILL.md +0 -196
  105. package/presets/clearai/template/skills/process-presearch/checklists/process_checklist.md +0 -18
  106. package/presets/clearai/template/skills/process-presearch/references/figure_code.md +0 -107
  107. package/presets/clearai/template/skills/process-presearch/references/source_attribution_example.md +0 -22
  108. package/presets/clearai/template/skills/process-understanding-extraction/SKILL.md +0 -69
  109. package/presets/clearai/template/skills/process-understanding-extraction/checklists/readiness_check.md +0 -34
  110. package/presets/clearai/template/skills/process-understanding-extraction/templates/docx_raw_dump_extractor.py.tpl +0 -132
  111. package/presets/clearai/template/skills/process-understanding-extraction/templates/entity_map_unit_topology.json.tpl +0 -86
  112. package/presets/clearai/template/skills/process-understanding-extraction/templates/process_brief.md.tpl +0 -89
  113. package/presets/clearai/template/skills/process-understanding-extraction/templates/process_brief_builder_from_raw_dump.py.tpl +0 -203
  114. package/presets/clearai/template/skills/process-understanding-extraction/templates/process_flow_mermaid.md.tpl +0 -41
  115. package/presets/clearai/template/skills/process-understanding-extraction/templates/unified_execution_plan.md.tpl +0 -53
  116. package/presets/clearai/template/skills/process-understanding-extraction/workflows/01-process-doc-discovery.md +0 -173
  117. package/presets/clearai/template/skills/process-understanding-extraction/workflows/02-process-understanding-and-diagramming.md +0 -106
  118. package/presets/clearai/template/skills/scientific-brainstorming/SKILL.md +0 -64
  119. package/presets/clearai/template/skills/scientific-brainstorming/references/brainstorming_methods.md +0 -326
  120. package/presets/clearai/template/skills/scientific-critical-thinking/SKILL.md +0 -72
  121. package/presets/clearai/template/skills/scientific-critical-thinking/references/common_biases.md +0 -364
  122. package/presets/clearai/template/skills/scientific-critical-thinking/references/evidence_hierarchy.md +0 -485
  123. package/presets/clearai/template/skills/scientific-critical-thinking/references/experimental_design.md +0 -496
  124. package/presets/clearai/template/skills/scientific-critical-thinking/references/logical_fallacies.md +0 -478
  125. package/presets/clearai/template/skills/scientific-critical-thinking/references/scientific_method.md +0 -169
  126. package/presets/clearai/template/skills/scientific-critical-thinking/references/statistical_pitfalls.md +0 -506
  127. package/presets/clearai/template/skills/skill-creator/SKILL.md +0 -109
  128. package/presets/clearai/template/skills/skill-creator/references/authoring-guide.md +0 -89
  129. package/presets/clearai/template/skills/statistical-analysis/SKILL.md +0 -79
  130. package/presets/clearai/template/skills/statistical-analysis/references/assumptions_and_diagnostics.md +0 -369
  131. package/presets/clearai/template/skills/statistical-analysis/references/bayesian_statistics.md +0 -653
  132. package/presets/clearai/template/skills/statistical-analysis/references/effect_sizes_and_power.md +0 -578
  133. package/presets/clearai/template/skills/statistical-analysis/references/reporting_standards.md +0 -469
  134. package/presets/clearai/template/skills/statistical-analysis/references/test_selection_guide.md +0 -129
  135. package/presets/clearai/template/skills/statistical-analysis/scripts/assumption_checks.py +0 -538
  136. package/presets/clearai/template/skills/web-artifact/SKILL.md +0 -165
  137. package/presets/clearai/template/skills/web-artifact/assets/renderer/renderer.css +0 -229
  138. package/presets/clearai/template/skills/web-artifact/assets/renderer/renderer.js +0 -373
  139. package/presets/clearai/template/skills/web-artifact/assets/vendor/elkjs/LICENSE +0 -263
  140. package/presets/clearai/template/skills/web-artifact/assets/vendor/elkjs/UPSTREAM.md +0 -26
  141. package/presets/clearai/template/skills/web-artifact/assets/vendor/elkjs/elk.bundled.js +0 -6605
  142. package/presets/clearai/template/skills/web-artifact/references/when-drawing-a-topology.md +0 -150
  143. package/presets/clearai/template/skills/web-artifact/references/when-the-page-must-work-offline.md +0 -62
  144. package/presets/clearai/template/skills/web-artifact/scripts/check_artifact.py +0 -167
  145. package/presets/clearai/template/skills/web-artifact/scripts/render_topology.js +0 -272
  146. package/presets/clearai/template/skills/what-if-oracle/LICENSE.txt +0 -5
  147. package/presets/clearai/template/skills/what-if-oracle/SKILL.md +0 -72
  148. package/presets/clearai/template/skills/what-if-oracle/references/scenario-templates.md +0 -154
@@ -18,13 +18,14 @@
18
18
  * 面向人的新字符串一律先落在 `GLOSSARY`(内部词 → 一句 plain + 在哪看 + 下一步做什么);
19
19
  * `client.js` 的 `LOCALE_ZH/LOCALE_EN` 与它同源登记。
20
20
  */
21
- import { graphProjection } from './domain-language.js'
21
+ import { graphProjection, ontologyOutline } from './domain-language.js'
22
+ import { bilingual, tr } from './lang.js'
22
23
 
23
24
  /** 卡文本上限。模型每一步只读这一张卡,而卡是**每回合**重算的:它必须小到能进预算。 */
24
25
  const CARD_LIMIT = 3000
25
26
 
26
27
  /**
27
- * **判据逐条进卡的三个界**。判据是**多条**的(`SetGoal` 收 `criteria: string[]`,每条一句话),
28
+ * **判据逐条进卡的三个界**。判据是**多条**的(`Frame` 收 `criteria: string[]`,每条一句话),
28
29
  * 挤成一行会把「第 3 条没做到」抹平;而整段重发又会把卡撑爆、断前缀缓存。
29
30
  * 每个界都对得上一条纪律:每行有上限(一条千字判据不占满一行)、条数有上限(判据条数不能
30
31
  * 决定卡大小)、超出**如实说**(写清还有几条、全文在哪,不静默丢)。
@@ -43,49 +44,183 @@ const TERMINAL_STATUS = new Set(['refuted', 'superseded', 'retracted'])
43
44
  * 为什么要三格:只说「未走过 L0」是术语;说了「L0 是什么、这次为什么没走、下一步走不走」
44
45
  * 才是一句据以行动的话。缺口 code、等级、实体来源、阶段名都在这里。
45
46
  */
46
- export const GLOSSARY = {
47
+ export const GLOSSARY = bilingual({
47
48
  // ── 认识论等级(「这条结论多大程度只能靠信任做的人」) ──
48
- L0: { plain: '推理自检:结论只是自己推了一遍,没有引入任何外部输入', where: 'docs/verification-loop.md 的等级表', nextAction: '把这一级要检查的对象过一遍,或写明这一级在本项目里为什么不适用' },
49
- L1: { plain: '已有知识:引用自己或别人手上已有的材料', where: 'docs/verification-loop.md 的等级表', nextAction: '指出引用的具体材料;没有就升级到能验的等级' },
50
- L2: { plain: '可复算:照一份能重跑的步骤自己算一遍', where: 'docs/verification-loop.md 的等级表', nextAction: '把复算步骤与产物落成文件,让下一个人能重跑' },
51
- L3: { plain: '独立裁决:由另一个评估者读产物后给结论', where: 'docs/verification-loop.md 的等级表', nextAction: '派一次独立评估,把评估卡作为出处' },
52
- L4: { plain: '人放行:交付前有人看过并批准', where: 'docs/verification-loop.md 的等级表', nextAction: '等一次人的放行记录;没有人就不要声称到过这一级' },
49
+ L0: {
50
+ plain: ['推理自检:结论只是自己推了一遍,没有引入任何外部输入', 'Reasoning check: the conclusion was only reasoned through, with no outside input'],
51
+ where: ['docs/verification-loop.md 的等级表', 'the level table in docs/verification-loop.md'],
52
+ nextAction: ['把这一级要检查的对象过一遍,或写明这一级在本项目里为什么不适用', 'Go through what this level checks, or write down why it does not apply in this project'],
53
+ },
54
+ L1: {
55
+ plain: ['已有知识:引用自己或别人手上已有的材料', 'Existing knowledge: cites material already at hand'],
56
+ where: ['docs/verification-loop.md 的等级表', 'the level table in docs/verification-loop.md'],
57
+ nextAction: ['指出引用的具体材料;没有就升级到能验的等级', 'Point to the material cited; without it, move up to a level that can be checked'],
58
+ },
59
+ L2: {
60
+ plain: ['可复算:照一份能重跑的步骤自己算一遍', 'Reproducible: computed by following steps anyone can rerun'],
61
+ where: ['docs/verification-loop.md 的等级表', 'the level table in docs/verification-loop.md'],
62
+ nextAction: ['把复算步骤与产物落成文件,让下一个人能重跑', 'Save the steps and outputs as files so the next person can rerun them'],
63
+ },
64
+ L3: {
65
+ plain: ['独立裁决:由另一个评估者读产物后给结论', 'Independent verdict: another evaluator reads the outputs and decides'],
66
+ where: ['docs/verification-loop.md 的等级表', 'the level table in docs/verification-loop.md'],
67
+ nextAction: ['派一次独立评估,把评估卡作为出处', 'Get one independent evaluation and cite its evaluation card'],
68
+ },
69
+ L4: {
70
+ plain: ['人放行:交付前有人看过并批准', 'Released by a person: someone looked at it and approved before delivery'],
71
+ where: ['docs/verification-loop.md 的等级表', 'the level table in docs/verification-loop.md'],
72
+ nextAction: ['等一次人的放行记录;没有人就不要声称到过这一级', 'Wait for a person to release it; without one, do not claim this level'],
73
+ },
53
74
  // ── 阶段(派生读数) ──
54
- planning: { plain: '还没建计划:先想清楚要怎么回答', where: '运行态卡 · 当前计划', nextAction: '用 CreatePlan 把回答拆成可交付的步骤' },
55
- executing: { plain: '执行中:有活动计划且还有未落定的步', where: '运行态卡 · 当前计划', nextAction: '推进第一个未落定步,交付落在它上面' },
56
- stage_boundary: { plain: '阶段边界:当前计划的步都落定了,该结案或起新计划', where: '运行态卡 · 当前计划', nextAction: '结案(CloseGoal)或起下一阶段计划' },
57
- auditing: { plain: '在等裁决:有交付/结案在飞,或上一次裁决还没回来', where: '运行态卡 · 阶段(派生)', nextAction: '等评估者回灌;不要重复派同一个裁决' },
58
- stalled: { plain: '卡住了:连续几次没通过观测准入,停下等人', where: '运行态卡 · 计划被拦', nextAction: '说一句怎么改(改计划或补判据)' },
59
- achieved: { plain: '目标已达成(终局)', where: '运行态卡 · 当前目标', nextAction: '没有待办:要做新事就立新目标' },
60
- abandoned: { plain: '目标已如实放弃(终局)', where: '运行态卡 · 当前目标', nextAction: '没有待办:放弃也是结论,记录保留' },
75
+ planning: {
76
+ plain: ['还没建计划:先想清楚要怎么回答', 'No plan yet: first work out how to answer'],
77
+ where: ['运行态卡 · 当前计划', 'runtime card · current plan'],
78
+ nextAction: ['用 CreatePlan 把回答拆成可交付的步骤', 'Use CreatePlan to split the answer into deliverable steps'],
79
+ },
80
+ executing: {
81
+ plain: ['执行中:有活动计划且还有未落定的步', 'Executing: there is an active plan with unsettled steps'],
82
+ where: ['运行态卡 · 当前计划', 'runtime card · current plan'],
83
+ nextAction: ['推进第一个未落定步,交付落在它上面', 'Work on the first unsettled step and deliver it'],
84
+ },
85
+ stage_boundary: {
86
+ plain: ['阶段边界:当前计划的步都落定了,该结案或起新计划', 'Stage boundary: every step of the current plan is settled; conclude or start a new plan'],
87
+ where: ['运行态卡 · 当前计划', 'runtime card · current plan'],
88
+ nextAction: ['结案(Conclude)或起下一阶段计划', 'Conclude, or plan the next stage'],
89
+ },
90
+ auditing: {
91
+ plain: ['在等裁决:有交付/结案在飞,或上一次裁决还没回来', 'Waiting for a verdict: a delivery or conclusion is in flight, or the last verdict has not returned'],
92
+ where: ['运行态卡 · 阶段(派生)', 'runtime card · phase (derived)'],
93
+ nextAction: ['等评估者回灌;不要重复派同一个裁决', 'Wait for the evaluator; do not request the same verdict again'],
94
+ },
95
+ stalled: {
96
+ plain: ['卡住了:连续几次没通过观测准入,停下等人', 'Stuck: observation admission failed several times in a row; waiting for a person'],
97
+ where: ['运行态卡 · 计划被拦', 'runtime card · plan blocked'],
98
+ nextAction: ['说一句怎么改(改计划或补判据)', 'Say how to change it (revise the plan or the criteria)'],
99
+ },
100
+ achieved: {
101
+ plain: ['目标已达成(终局)', 'Goal achieved (final)'],
102
+ where: ['运行态卡 · 当前目标', 'runtime card · current goal'],
103
+ nextAction: ['没有待办:要做新事就立新目标', 'Nothing to do: set a new goal for new work'],
104
+ },
105
+ abandoned: {
106
+ plain: ['目标已如实放弃(终局)', 'Goal honestly abandoned (final)'],
107
+ where: ['运行态卡 · 当前目标', 'runtime card · current goal'],
108
+ nextAction: ['没有待办:放弃也是结论,记录保留', 'Nothing to do: abandoning is a conclusion too, and the record stays'],
109
+ },
61
110
  // ── 实体图的三个来源 ──
62
- registered: { plain: '已登记:某实例在某出处下被登记下来(一等写入口)', where: '本体面板 · 实体图节点', nextAction: '用 Assert 给它挂断言,图才长出边' },
63
- promoted: { plain: '已升格:来自过了独立裁决的事实断言', where: '本体面板 · 实体图边', nextAction: '它已经带等级与边界;要改就去改那条事实' },
64
- asserted: { plain: '实体断言:登记那一刻就成立的边,有出处但未经独立裁决', where: '本体面板 · 实体图虚线边', nextAction: '要让它进「已知」就把它升格成事实(走独立裁决)' },
111
+ registered: {
112
+ plain: ['已登记:某实例在某出处下被登记下来(一等写入口)', 'Registered: an instance recorded with its source (first-class entry)'],
113
+ where: ['本体面板 · 实体图节点', 'ontology panel · entity graph node'],
114
+ nextAction: ['在它的实体文件里写 relations(每条带出处),图才长出边', 'Write relations (each with a source) in its entity file so the graph grows edges'],
115
+ },
116
+ promoted: {
117
+ plain: ['已升格:来自过了独立裁决的事实断言', 'Promoted: from a fact assertion that passed an independent verdict'],
118
+ where: ['本体面板 · 实体图边', 'ontology panel · entity graph edge'],
119
+ nextAction: ['它已经带等级与边界;要改就去改那条事实', 'It already carries a level and a boundary; to change it, change that fact'],
120
+ },
121
+ asserted: {
122
+ plain: ['实体断言:登记那一刻就成立的边,有出处但未经独立裁决', 'Entity assertion: an edge recorded with a source but no independent verdict'],
123
+ where: ['本体面板 · 实体图虚线边', 'ontology panel · dashed entity graph edge'],
124
+ nextAction: ['要让它进「已知」就把它升格成事实(走独立裁决)', 'To make it "known", promote it to a fact (through an independent verdict)'],
125
+ },
65
126
  // ── 派生读数 ──
66
- supportedLevel: { plain: '支持到哪一级:所有支持证据里最高的那一级', where: '运行态卡 · 假设状态', nextAction: '等级不够就补更硬的那一档证据' },
67
- untouchedLevels: { plain: '从没走过的等级:已用到最高级之下、一条证据都没有的级', where: '运行态卡 · 假设状态', nextAction: '低等级不适用就写明理由(跳级不违规,但要说清)' },
68
- refutations: { plain: '被推翻次数:收到过几条推翻证据', where: '运行态卡 · 假设状态', nextAction: '被推翻是终态:要么改主张换 id,要么如实放弃' },
69
- inconclusive: { plain: '无法判定次数:判过但判不出来', where: '运行态卡 · 假设状态', nextAction: '补判据或补产物,让下一次判得出结果' },
127
+ supportedLevel: {
128
+ plain: ['支持到哪一级:所有支持证据里最高的那一级', 'Supported level: the highest level among all supporting evidence'],
129
+ where: ['运行态卡 · 假设状态', 'runtime card · judgment status'],
130
+ nextAction: ['等级不够就补更硬的那一档证据', 'If the level is too low, add harder evidence'],
131
+ },
132
+ refutations: {
133
+ plain: ['被推翻次数:收到过几条推翻证据', 'Refutations: how many pieces of refuting evidence arrived'],
134
+ where: ['运行态卡 · 假设状态', 'runtime card · judgment status'],
135
+ nextAction: ['被推翻是终态:要么改主张换 id,要么如实放弃', 'Refuted is final: either restate the claim under a new id, or honestly give it up'],
136
+ },
137
+ inconclusive: {
138
+ plain: ['无法判定次数:判过但判不出来', 'Inconclusive: judged but could not be decided'],
139
+ where: ['运行态卡 · 假设状态', 'runtime card · judgment status'],
140
+ nextAction: ['补判据或补产物,让下一次判得出结果', 'Add criteria or outputs so the next judgment can decide'],
141
+ },
70
142
  // ── 缺口 code(与 deriveKnowledge 一一对应) ──
71
- no_language: { plain: '还没有概念与谓词:换一轮只能靠重读散文取用结论', where: '运行态卡 · 缺口 / 本体面板', nextAction: '先 RegisterTerm 立词,再 RegisterPredicate 说明关系' },
72
- prose_only_claims: { plain: '命题只有散文主张:两条结论是不是在说同一件事只能靠重读判断', where: '运行态卡 · 缺口', nextAction: '用 SetGoal 的修订把这条主张写成断言(主词–谓词–宾语),引用已登记的 id' },
73
- unstructured_facts: { plain: '已升格事实没带断言:进不了实体图,也不能按概念取用', where: '运行态卡 · 缺口', nextAction: '下次升格时带上 assertions;这条老事实的形态靠新一次升格补' },
74
- untouched_claims: { plain: '有命题一条证据都没碰过:没看过不等于没问题', where: '运行态卡 · 缺口 / 结案留痕', nextAction: '给它派一个带 tests 的步骤并交付:支持 / 推翻 / 无法判定都算碰过' },
75
- entities_unlanded: { plain: '断言的主体还没有落到实体图上:句子只挂在命题上,不构成「已知」', where: '运行态卡 · 缺口 / 本体面板 · 实体图', nextAction: '先 RegisterInstance 把实例连出处登记下来;确实不值得留下形态就如实说清' },
76
- levels_skipped: { plain: '有等级被跳过而没写理由:跳级不违规,但要说清为什么不适用', where: '运行态卡 · 假设状态 / 缺口', nextAction: '用 ExplainLevelSkip 写明「为什么这一级在本项目里不适用」' },
77
- orphan_terms: { plain: '有概念没有任何结论引用:它们还只是约定,不是已知', where: '本体面板 · 零引用的概念', nextAction: '要么在断言里用起来,要么在货架上如实标出「未被引用」' },
143
+ prose_only_claims: {
144
+ plain: ['命题只有散文主张:两条结论是不是在说同一件事只能靠重读判断', 'Prose-only claims: whether two conclusions say the same thing can only be judged by rereading'],
145
+ where: ['运行态卡 · 缺口', 'runtime card · gaps'],
146
+ nextAction: [
147
+ '先在 clear/ontology/ 下写概念、关系与主体的实体文件,再用 Frame 修订把主张写成断言(主词–谓词–宾语)',
148
+ 'First write concept, relation and subject entity files under clear/ontology/, then revise with Frame to turn the claim into assertions (subject–predicate–object)',
149
+ ],
150
+ },
151
+ untouched_claims: {
152
+ plain: ['有命题一条证据都没碰过:没看过不等于没问题', 'Some propositions were never touched by evidence: not looked at is not the same as fine'],
153
+ where: ['运行态卡 · 缺口 / 结案留痕', 'runtime card · gaps / closing record'],
154
+ nextAction: ['给它派一个带 tests 的步骤并交付:支持 / 推翻 / 无法判定都算碰过', 'Give it a step with tests and deliver it: support, refute and inconclusive all count'],
155
+ },
156
+ entities_unlanded: {
157
+ plain: ['断言的主体还没有落到实体图上:句子只挂在命题上,不构成「已知」', 'Assertion subjects are not on the entity graph: the sentences hang on the proposition only and are not "known"'],
158
+ where: ['运行态卡 · 缺口 / 本体面板 · 实体图', 'runtime card · gaps / ontology panel · entity graph'],
159
+ nextAction: [
160
+ '给这些主体各写一个实体文件(clear/ontology/entities/<id>.json,带类型与出处);确实不值得留下形态就把断言从判断上拿掉(Frame 修订)',
161
+ 'Write an entity file for each subject (clear/ontology/entities/<id>.json, with type and source); if one is really not worth keeping, drop the assertion from the judgment (Frame revision)',
162
+ ],
163
+ },
78
164
  // ── 判据 ──
79
- done_criteria: { plain: '判据没改过:它还是立约时那一份(要原文读账本里的 done_criteria)', where: '运行态卡 · 当前目标 / 账本', nextAction: '要改判据就走修订,并带一份独立裁决的 auditKey' },
80
- criteria_verdict: { plain: '判据改动要有一份独立裁决:改「怎样算完成」不能被顺手做掉', where: '账本 · goal.criteriaHistory', nextAction: '拿独立裁决的 auditKey 再改判据文本' },
165
+ done_criteria: {
166
+ plain: ['判据没改过:它还是立约时那一份(要原文读账本里的 done_criteria)', 'The criteria are unchanged since framing (read done_criteria in the ledger for the full text)'],
167
+ where: ['运行态卡 · 当前目标 / 账本', 'runtime card · current goal / ledger'],
168
+ nextAction: ['要改判据就走修订,并带一份独立裁决的 auditKey', 'To change the criteria, revise them with the auditKey of an independent verdict'],
169
+ },
170
+ criteria_verdict: {
171
+ plain: ['判据改动要有一份独立裁决:改「怎样算完成」不能被顺手做掉', 'Changing the criteria needs an independent verdict: "what counts as done" cannot be changed in passing'],
172
+ where: ['账本 · goal.criteriaHistory', 'ledger · goal.criteriaHistory'],
173
+ nextAction: ['拿独立裁决的 auditKey 再改判据文本', 'Get an independent verdict auditKey, then change the criteria text'],
174
+ },
81
175
  // ── 宿主读面降级(宿主健康) ──
82
- sessions: { plain: '宿主会话服务读不到:这一刻拿不到会话,写盘可能写到错地方', where: '运行态卡 · 宿主读面降级 / 面板', nextAction: '不要写盘:等宿主服务可用,或如实说这一步没做' },
83
- sessionProjections: { plain: '投影服务读不到:这一刻的读数是空的,不是「没有」', where: '运行态卡 · 宿主读面降级 / 面板', nextAction: '不要把空读数当成事实;等投影可用再读一次' },
84
- }
176
+ sessions: {
177
+ plain: ['宿主会话服务读不到:这一刻拿不到会话,写盘可能写到错地方', 'The host session service is unavailable: no session right now, and writes may land in the wrong place'],
178
+ where: ['运行态卡 · 宿主读面降级 / 面板', 'runtime card · host read degraded / panel'],
179
+ nextAction: ['不要写盘:等宿主服务可用,或如实说这一步没做', 'Do not write files: wait for the host service, or say plainly this step was not done'],
180
+ },
181
+ sessionProjections: {
182
+ plain: ['投影服务读不到:这一刻的读数是空的,不是「没有」', 'The projection service is unavailable: the reading is empty, not "nothing"'],
183
+ where: ['运行态卡 · 宿主读面降级 / 面板', 'runtime card · host read degraded / panel'],
184
+ nextAction: ['不要把空读数当成事实;等投影可用再读一次', 'Do not treat an empty reading as a fact; read again once projections are available'],
185
+ },
186
+ })
85
187
 
86
188
  /** 等级那五个(`levels` 是给消费方一个不用过滤的入口,与 `GLOSSARY` 同源)。 */
87
189
  export const LEVELS = ['L0', 'L1', 'L2', 'L3', 'L4']
88
190
 
191
+ /**
192
+ * **说人话的三张小表**(第六阶段)。内部名不改;卡、工具结果与面板上一律写右边那一列。
193
+ * 模型读到什么就会照着说什么——所以卡先说人话,答复才说得出人话。
194
+ */
195
+ export const LEVEL_WORD = bilingual({ L0: ['自己推了一遍', 'reasoned through alone'], L1: ['引用已有材料', 'cites existing material'], L2: ['可复算', 'reproducible'], L3: ['独立核验', 'independent check'], L4: ['人放行', 'released by a person'] })
196
+ export const VERDICT_WORD = bilingual({ support: ['支持', 'support'], refute: ['推翻', 'refute'], inconclusive: ['不确定', 'inconclusive'] })
197
+ /** 判断短名的上限(汉字);没起名时取主张开头这么宽。与内核同一个数。 */
198
+ export const HANDLE_LIMIT = 12
199
+ /**
200
+ * 短名按**显示宽度**算:中日韩字算 2,其余算 1。上限是 `HANDLE_LIMIT` 个汉字的宽度,
201
+ * 所以中文仍是十二字,英文约二十四个字母——按字数一刀切会让英文短名短得没法用。
202
+ */
203
+ const wideChar = (char) => /[\u1100-\u115f\u2e80-\ua4cf\uac00-\ud7a3\uf900-\ufaff\ufe30-\ufe4f\uff00-\uff60\uffe0-\uffe6]/.test(char)
204
+ const textWidth = (text) => [...text].reduce((sum, char) => sum + (wideChar(char) ? 2 : 1), 0)
205
+ function clipWidth(text, limit) {
206
+ if (textWidth(text) <= limit) return text
207
+ let out = ''
208
+ let width = 0
209
+ for (const char of text) {
210
+ width += wideChar(char) ? 2 : 1
211
+ if (width > limit) break
212
+ out += char
213
+ }
214
+ return `${out.trimEnd()}…`
215
+ }
216
+ /** 一条判断的短名:模型起的名字;旧日志没有,就取主张开头。 */
217
+ export function handleOf(hypothesis) {
218
+ const name = typeof hypothesis?.name === 'string' ? hypothesis.name.trim() : ''
219
+ if (name !== '') return name
220
+ const claim = String(hypothesis?.claim ?? '').replace(/\s+/g, ' ').trim()
221
+ return clipWidth(claim, HANDLE_LIMIT * 2)
222
+ }
223
+
89
224
  const isPlainObject = (value) => value !== null && typeof value === 'object' && !Array.isArray(value)
90
225
  const oneLine = (value) => String(value ?? '').replace(/\s+/g, ' ').trim()
91
226
  const clamp = (value, max) => {
@@ -96,15 +231,12 @@ const clamp = (value, max) => {
96
231
  /** 卡上的时间由调用方给(读面不读时钟);给了毫秒数就按本地时间格式化。 */
97
232
 
98
233
  /** 人话的阶段名;表外的阶段原样给(不猜)。 */
99
- const phasePlain = (phase) => (phase === null || phase === undefined ? '阶段还没算出来' : GLOSSARY[phase]?.plain ?? String(phase))
100
-
101
- /** 一条命题的跳级理由(`level/skipped` 折出来的那几段),有才写。 */
102
- function skipLine(hypothesis) {
103
- const skips = Array.isArray(hypothesis?.skips) ? hypothesis.skips : []
104
- if (skips.length === 0) return ''
105
- const parts = skips.map((skip) => `${(skip?.levels ?? []).join('/')}(${clamp(skip?.reason, 60) || '未写理由'})`)
106
- return ` · 已说明跳过 ${parts.join(';')}`
107
- }
234
+ /**
235
+ * 进度那一格只放一个短语:词汇表里的 plain 是「词:解释」,卡上取冒号前那半句。
236
+ * 「阶段边界」本身是内部词,换成它要人做的那件事。
237
+ */
238
+ const PHASE_SHORT = bilingual({ stage_boundary: ['这份计划做完了,该结案或起新计划', 'this plan is done; conclude or start a new plan'] })
239
+ const phasePlain = (phase) => (phase === null || phase === undefined ? tr('阶段还没算出来', 'phase not derived yet') : (PHASE_SHORT[phase] ?? String(GLOSSARY[phase]?.plain ?? phase).split(':')[0]))
108
240
 
109
241
  /**
110
242
  * **卡文本的行装配**(带优先级)。
@@ -125,7 +257,7 @@ function fitLines(lines, limit = CARD_LIMIT) {
125
257
  }
126
258
  }
127
259
  if (dropped > 0) {
128
- const note = `- …(卡片为 ${limit} 字符上限省去 ${dropped} 行细节:完整读数在面板「运行态」与 CheckPlan 里)`
260
+ const note = tr(`- …(卡片为 ${limit} 字符上限省去 ${dropped} 行细节:完整读数在面板「运行态」里)`, `- … (${dropped} detail lines left out to fit the ${limit}-character card limit; the full reading is in the panel)`)
129
261
  /** 给这句提示**留出位置**:丢了行却不说,读的人会把这张卡当成全部。 */
130
262
  while (measure(kept) + note.length + 1 > limit) {
131
263
  let index = -1
@@ -142,7 +274,7 @@ function fitLines(lines, limit = CARD_LIMIT) {
142
274
  if (measure(kept) + note.length + 1 <= limit) kept.push({ text: note, tier: 0 })
143
275
  }
144
276
  if (measure(kept) > limit) {
145
- const note = `- …(卡片到达 ${limit} 字符上限,后面的行没有展开:完整读数在面板「运行态」与 CheckPlan 里)`
277
+ const note = tr(`- …(卡片到达 ${limit} 字符上限,后面的行没有展开:完整读数在面板「运行态」里)`, `- … (the card reached its ${limit}-character limit; the remaining lines are not shown; the full reading is in the panel)`)
146
278
  const out = []
147
279
  let total = 0
148
280
  for (const item of kept) {
@@ -156,10 +288,63 @@ function fitLines(lines, limit = CARD_LIMIT) {
156
288
  return kept.map((item) => item.text).join('\n')
157
289
  }
158
290
 
291
+ /**
292
+ * **可信度分组**(第六阶段):一条判断此刻落在哪一组。面板的清单、卡上的判断、图上的颜色读同一份。
293
+ *
294
+ * · 已验证——独立核验过(或已写进长期知识),而且没被推翻;
295
+ * · 待核验——有支持的结果,但都是做的人自己判的;
296
+ * · 不确定——检验过,但只得到「不确定」;
297
+ * · 验证中——还没有任何结果;
298
+ * · 已推翻 / 已替换 / 已撤回——终态,留着不删。
299
+ */
300
+ export const TRUST_LABEL = bilingual({
301
+ credible: ['已验证', 'Verified'],
302
+ pending: ['待核验', 'Awaiting check'],
303
+ testing: ['验证中', 'Testing'],
304
+ unclear: ['不确定', 'Uncertain'],
305
+ refuted: ['已推翻', 'Refuted'],
306
+ replaced: ['已替换', 'Replaced'],
307
+ })
308
+ export const TRUST = ['credible', 'pending', 'testing', 'unclear', 'refuted', 'replaced'].map((key) => ({
309
+ key,
310
+ get label() {
311
+ return TRUST_LABEL[key]
312
+ },
313
+ }))
314
+ const levelRank = (level) => LEVELS.indexOf(String(level ?? ''))
315
+ export function trustOf(hypothesis, promoted = false) {
316
+ const status = String(hypothesis?.status ?? '')
317
+ if (status === 'refuted' || (hypothesis?.refutations ?? 0) > 0) return 'refuted'
318
+ if (status === 'superseded' || status === 'retracted') return 'replaced'
319
+ if (promoted === true || status === 'confirmed') return 'credible'
320
+ const level = levelRank(hypothesis?.supportedLevel)
321
+ if (level >= 3) return 'credible'
322
+ if (level >= 0) return 'pending'
323
+ if ((hypothesis?.inconclusive ?? 0) > 0) return 'unclear'
324
+ return 'testing'
325
+ }
326
+
327
+ /** 一条判断的读数,一句人话(卡上与面板同一句)。 */
328
+ export function readingOf(hypothesis) {
329
+ const parts = []
330
+ const level = hypothesis?.supportedLevel
331
+ if (level !== null && level !== undefined) parts.push(tr(`支持(${LEVEL_WORD[level] ?? level})`, `supported (${LEVEL_WORD[level] ?? level})`))
332
+ if ((hypothesis?.refutations ?? 0) > 0) parts.push(tr(`推翻 ${hypothesis.refutations} 次`, `refuted ${hypothesis.refutations}×`))
333
+ if ((hypothesis?.inconclusive ?? 0) > 0) parts.push(tr(`不确定 ${hypothesis.inconclusive} 次`, `inconclusive ${hypothesis.inconclusive}×`))
334
+ return parts.length === 0 ? tr('还没检验', 'not tested yet') : parts.join(' · ')
335
+ }
336
+
337
+ /** 步骤状态的人话。 */
338
+ const STEP_WORD = bilingual({ open: ['待做', 'to do'], advanced: ['已交付', 'delivered'], void: ['已作废', 'voided'] })
339
+
159
340
  /**
160
341
  * **卡的正文**。它只读已经算好的 `view` 与 `(state, derived)`,不重算任何判据——
161
342
  * 同一份账本永远给出同一串字节:卡里**不带时刻**——时间戳会让同一个状态的卡每分钟变一次,
162
343
  * 按内容去重的那条纪律因此失效。要看「什么时候发生」,账本里有事件时间。
344
+ *
345
+ * **第六阶段起只说人话**:没有目标 id、修订号、阶段码、命题状态码、证据 id、缺口 code。
346
+ * 判断用短名(模型起的,没起就取主张开头),结果用「支持 / 推翻 / 不确定」,
347
+ * 等级用「自己推了一遍 … 人放行」。模型读到什么就会照着说什么。
163
348
  */
164
349
  function cardLines(state, derived, options, view) {
165
350
  const goal = isPlainObject(state?.goal) ? state.goal : null
@@ -170,205 +355,156 @@ function cardLines(state, derived, options, view) {
170
355
  const issues = Array.isArray(derived?.lexiconIssues) ? derived.lexiconIssues : []
171
356
  const lexicon = isPlainObject(derived?.lexicon) ? derived.lexicon : { terms: [], predicates: [] }
172
357
  const plan = isPlainObject(derived?.activePlan) ? derived.activePlan : null
173
- const forks = Array.isArray(derived?.forks) ? derived.forks : []
174
- const inbox = Array.isArray(derived?.inbox) ? derived.inbox : []
175
358
  const evidence = Array.isArray(state?.evidence) ? state.evidence : []
176
359
  const facts = Array.isArray(state?.facts) ? state.facts : []
177
- const materials = Array.isArray(state?.materials) ? state.materials : []
178
- const scouts = Array.isArray(state?.scouts) ? state.scouts : []
179
360
  const hostHealth = Array.isArray(state?.hostHealth) ? state.hostHealth : []
180
361
  const graph = graphProjection(state)
181
362
  const entityNodes = graph.nodes.filter((node) => node.layer === 'entity')
363
+ const promotedIds = new Set(facts.map((fact) => fact?.hypothesis).filter((id) => typeof id === 'string'))
364
+ const byId = new Map(hypotheses.map((hypothesis) => [hypothesis.id, hypothesis]))
365
+ const nameOf = (id) => (byId.has(id) ? tr(`「${handleOf(byId.get(id))}」`, `"${handleOf(byId.get(id))}"`) : tr('一条已不在账上的判断', 'a judgment no longer on record'))
182
366
  const lines = []
183
367
  const push = (value, tier = 0) => lines.push({ text: value, tier })
184
- push('【运行态卡 · Harness-owned state】')
185
- /**
186
- * **卡里不写时刻**。分钟级的时间戳对决策没有信息量,却让"同一个状态的卡"每过一分钟就变一次
187
- * ——按内容去重的那条纪律因此永远失效,整卡重发。真需要精确时间,`bash date` 是工具的活。
188
- * 要看"什么时候发生",账本里有事件时间。
189
- */
190
- push(`- 正在解决:${view.headline.now}`)
191
- push(`- 怎样算完成:${view.headline.done}`)
192
- push(`- 我做到哪了:${view.headline.where}`)
193
- const autonomy = isPlainObject(state?.autonomy?.effective) ? state.autonomy.effective : null
194
- if (autonomy !== null) {
195
- push(`- 运行档:${autonomy.value === 'unattended' ? '无人值守' : '人在场'}(部署预设写的;它不是"要不要人参与"的开关——要不要人由**门**决定:计划待确认/等裁决/有人在等)`, 1)
196
- }
197
- if (goal === null) push('- 当前目标:未立(SetGoal 需要一份「怎样算回答了」的判据)')
368
+ push(tr('【现在的状态】', '[Current state]'))
369
+ push(tr(`- 在回答:${view.headline.now}`, `- Answering: ${view.headline.now}`))
370
+ if (goal === null) push(tr('- 怎样算答完:还没定(用 Frame 写下判据与判断)', '- Done when: not set yet (write criteria and judgments with Frame)'))
198
371
  else {
199
- // claim 可以很长(真跑里上千字):卡上给压缩版,一句话在「正在解决」那行,全文在目标文档里。
200
- push(`- 当前目标(${goal.id} · rev${goal.revision} · ${goal.status}):${clamp(String(goal.claim ?? ''), 160)}${String(goal.claim ?? '').length > 160 ? `…(全文 ${String(goal.claim).length} 字在 clear/goals/${goal.id}.md)` : ''}`)
201
372
  /**
202
- * **判据正文只出现一次,在顶部「怎样算完成」那一行**;这里只交代
203
- * "改过没有、谁裁的、全文在哪"。
204
- *
205
- * 为什么要这么抠:一段千余字的判据在几百步里反复重发,换来的只是"读得慢 + 前缀缓存断"。
206
- * 全文的家是 `clear/goals/{goalId}.md`(内核在每次目标变更后幂等落盘),
207
- * 要逐字核对的场合(评估者、人复核、模型自己重读)去读它;
208
- * **修订后的第一张卡**仍会补全文一次(见内核 pre-step)——那时模型必须逐字看到新尺子。
373
+ * **判据逐条**,每行 80 字封顶、最多 6 条;全文的家在目标文档里。
374
+ * 判据正文只在这里出现一次:它是尺子,不是叙述。
209
375
  */
210
- const criteriaLength = String(goal.done_criteria ?? '').length
211
376
  const criteriaLines = Array.isArray(view.goal.criteriaLines) ? view.goal.criteriaLines : []
212
377
  const criteriaTotal = typeof view.goal.criteriaTotal === 'number' ? view.goal.criteriaTotal : criteriaLines.length
213
378
  const criteriaDoc = view.goal.docPath ?? `clear/goals/${goal.id}.md`
214
- const revisionNote = view.goal.criteriaChanged
215
- ? `第 ${view.goal.criteriaHistory.length} 次修订 · 独立裁决 ${view.goal.criteriaHistory[view.goal.criteriaHistory.length - 1]?.audit ?? '—'} · `
216
- : '立约时那一份 · '
217
379
  if (criteriaLines.length > 0) {
218
- /**
219
- * **逐条一行**。判据是清点清单:「第 3 条没做到」只有逐条列出来才看得见。
220
- * 但逐条不等于整段重发——每行 80 字封顶、最多 6 条,超出写清还有几条与全文在哪。
221
- * 于是「判据多长」不再决定卡多大,而欠账仍然看得见。
222
- *
223
- * 指针写进**这一行**(tier 0):显存紧张时被丢的是细节行,不是「全文在哪」。
224
- */
225
- push(`- 判据(${criteriaTotal} 条,逐条;全文在 ${criteriaDoc}):`)
380
+ push(tr(`- 怎样算答完(${criteriaTotal} 条):`, `- Done when (${criteriaTotal} criteria):`))
226
381
  const shown = criteriaLines.slice(0, CRITERIA_ROWS_MAX)
227
- /**
228
- * 逐条那几行与旧的那句压缩判据**同一档**(tier 0):尺子不许被挤掉。
229
- * 这条不是新加的优待——原来那一行判据就是 tier 0,这里只是把它拆成多行。
230
- */
231
382
  for (let index = 0; index < shown.length; index += 1) push(` ${index + 1}. ${clamp(shown[index], CRITERIA_LINE_LIMIT)}`)
232
- if (criteriaTotal > shown.length) push(` · (还有 ${criteriaTotal - shown.length} 条,全文在 ${criteriaDoc})`, 1)
233
- push(` · 判据留痕:${revisionNote}全文 ${criteriaLength} 字在 ${criteriaDoc}`, 1)
234
- } else if (view.goal.criteriaChanged) {
235
- const last = view.goal.criteriaHistory[view.goal.criteriaHistory.length - 1]
236
- push(`- 判据:第 ${view.goal.criteriaHistory.length} 次修订 · 独立裁决 ${last?.audit ?? '—'} · 全文 ${criteriaLength} 字在 clear/goals/${goal.id}.md`)
237
- } else if (criteriaLength > 0) {
238
- push(`- 判据:立约时那一份 · 全文 ${criteriaLength} 字在 clear/goals/${goal.id}.md`)
239
- } else push(`- 判据:${GLOSSARY.done_criteria.plain}`)
240
- const progress = derived?.progress === null || derived?.progress === undefined ? '无法计算' : `${Math.round(derived.progress * 100)}%`
241
- push(`- 阶段(派生):${derived?.phase ?? '—'} · 完成度(派生):${progress}`)
383
+ if (criteriaTotal > shown.length) push(tr(` · 还有 ${criteriaTotal - shown.length} 条,全文在 ${criteriaDoc}`, ` · ${criteriaTotal - shown.length} more; full text in ${criteriaDoc}`), 1)
384
+ } else {
385
+ const full = String(goal.done_criteria ?? '')
386
+ push(tr(`- 怎样算答完:${clamp(full, 140) || GLOSSARY.done_criteria.plain}${oneLine(full).length > 140 ? `(全文在 ${criteriaDoc})` : ''}`, `- Done when: ${clamp(full, 140) || GLOSSARY.done_criteria.plain}${oneLine(full).length > 140 ? ` (full text in ${criteriaDoc})` : ''}`))
387
+ }
388
+ if (view.goal.criteriaChanged) push(tr(` · 判据改过 ${view.goal.criteriaHistory.length} 次(每次都有独立裁决),全文在 ${criteriaDoc}`, ` · criteria changed ${view.goal.criteriaHistory.length}× (each with an independent verdict); full text in ${criteriaDoc}`), 1)
389
+ const steps = plan === null ? null : plan.steps.filter((step) => step.status !== 'void')
390
+ const stepNote = steps === null ? '' : tr(` · 计划做到第 ${steps.filter((step) => step.status === 'advanced').length} / ${steps.length} 步`, ` · plan at step ${steps.filter((step) => step.status === 'advanced').length} / ${steps.length}`)
391
+ push(tr(`- 进度:${phasePlain(derived?.phase)}${stepNote}`, `- Progress: ${phasePlain(derived?.phase)}${stepNote}`))
242
392
  }
243
393
  if (hostHealth.length > 0) {
244
394
  const last = hostHealth[hostHealth.length - 1]
245
- push(`- 宿主读面降级 ${hostHealth.length} 次(最近:${last?.scope ?? '未知'} · ${clamp(last?.detail, 100)})——${GLOSSARY[String(last?.scope)]?.plain ?? GLOSSARY.sessions.plain}`)
395
+ push(tr(`- 读不到宿主 ${hostHealth.length} 次(最近:${clamp(last?.detail, 100)})——${GLOSSARY[String(last?.scope)]?.plain ?? GLOSSARY.sessions.plain}`, `- Host unreadable ${hostHealth.length}× (latest: ${clamp(last?.detail, 100)}): ${GLOSSARY[String(last?.scope)]?.plain ?? GLOSSARY.sessions.plain}`))
246
396
  }
247
397
  if (hypotheses.length > 0) {
248
- push('- 假设状态(由证据算出):')
249
- for (const hypothesis of hypotheses.slice(0, 10)) {
250
- /**
251
- * 三样全零 = **没人碰过它**,与「判过但无法判定」是两回事:
252
- * 前者要如实说「未触及」,后者本来就有「无法判定 n」这个读数。
253
- */
254
- const untouched = (hypothesis.supportedLevel === null || hypothesis.supportedLevel === undefined) && (hypothesis.refutations ?? 0) === 0 && (hypothesis.inconclusive ?? 0) === 0
255
- const skipped = (hypothesis.untouchedLevels ?? []).length === 0 ? '' : ` · 未走过 ${hypothesis.untouchedLevels.join('/')}`
256
- const readings = untouched ? '(未触及)' : `(支持到 ${hypothesis.supportedLevel ?? '—'} · 推翻 ${hypothesis.refutations} · 无法判定 ${hypothesis.inconclusive}${skipped})`
257
- push(` · ${hypothesis.id} [${hypothesis.status}] ${hypothesis.claim} — 推翻条件:${hypothesis.refute_when}${readings}${skipLine(hypothesis)}`)
258
- }
259
- if (hypotheses.length > 10) push(` · (还有 ${hypotheses.length - 10} 条命题未展开:面板「命题」里有全部)`, 2)
260
- }
261
- if (knowledge.mode === 'knowledge') {
262
- push(`- 知识模式:${knowledge.why}`)
263
- const preflight = view.deliver.preflight
264
- if (preflight !== null && (preflight.terms.length > 0 || preflight.predicates.length > 0)) {
265
- const more = (count) => (count > 0 ? `(还有 ${count} 个未列出)` : '')
266
- push(
267
- ` · 相关已知(词面命中,可直接引用):概念 ${preflight.terms.map((term) => `${term.id}${term.label === term.id ? '' : `(${term.label})`}`).join('、') || '无'}${more(preflight.termsTruncated)};谓词 ${preflight.predicates.map((predicate) => `${predicate.id}${predicate.label === predicate.id ? '' : `(${predicate.label})`}`).join('、') || '无'}${more(preflight.predicatesTruncated)}`,
268
- 1,
269
- )
270
- if (preflight.facts.length > 0) push(` · 可复用事实 ${preflight.facts.length} 条:${preflight.facts.map((fact) => `${fact.id}(${fact.level ?? '?'})`).join('、')}${preflight.factsTruncated > 0 ? `(还有 ${preflight.factsTruncated} 条未列出)` : ''}`, 1)
271
- } else {
272
- push(' · 相关已知:当前主张文本没有命中任何已有概念 / 谓词——要写断言就先立词(带依据),别把查不到当成不存在', 1)
273
- }
274
- if (gaps.length === 0) {
275
- push(' · 结构完整:语言、断言的命题、带断言的已升格事实、证据覆盖、实体图、跳级理由、词条引用这七项今天都不欠')
276
- } else {
277
- const total = gaps.reduce((sum, gap) => sum + (Number(gap.count) || 0), 0)
278
- push(` · 缺口 ${total} 条(${gaps.map((gap) => `${gap.code} ${gap.count}`).join(' · ')}):`)
279
- for (const gap of gaps) push(` - ${gap.code}:${gap.detail} → 下一步:${gap.nextAction}`)
398
+ push(tr('- 判断:', '- Judgments:'))
399
+ const shown = hypotheses.slice(0, 10)
400
+ for (const group of TRUST) {
401
+ const rows = shown.filter((hypothesis) => trustOf(hypothesis, promotedIds.has(hypothesis.id)) === group.key)
402
+ if (rows.length === 0) continue
403
+ push(` ${group.label}:`)
404
+ for (const hypothesis of rows) {
405
+ const terminal = group.key === 'refuted' || group.key === 'replaced'
406
+ const named = typeof hypothesis.name === 'string' && hypothesis.name.trim() !== ''
407
+ const head = tr(named ? `「${hypothesis.name.trim()}」${clamp(hypothesis.claim, 120)}` : `「${clamp(hypothesis.claim, 120)}」`, named ? `"${hypothesis.name.trim()}" ${clamp(hypothesis.claim, 120)}` : `"${clamp(hypothesis.claim, 120)}"`)
408
+ const refute = terminal ? '' : tr(` — 算错的条件:${clamp(hypothesis.refute_when, 100)}`, ` — wrong if: ${clamp(hypothesis.refute_when, 100)}`)
409
+ push(` · ${head}${refute} · ${readingOf(hypothesis)}`, terminal ? 1 : 0)
410
+ }
280
411
  }
412
+ if (hypotheses.length > 10) push(tr(` · 还有 ${hypotheses.length - 10} 条判断没展开(面板「本体」里有全部)`, ` · ${hypotheses.length - 10} more judgments not shown (all are in the Ontology pane)`), 2)
281
413
  }
282
- if (plan === null) push('- 当前计划:无活动计划', 1)
283
- else {
284
- if (derived?.planConfirmationPending) {
285
- push('- 授权:记号未落账。未经人批准的计划不会自动续跑;显式推进时,第一次交付会按事实补写归属(行为即授权)')
286
- } else if (plan.confirmed_at === null) {
287
- push('- 授权:记号未落账,但本计划已推进过——授权已经发生(行为即授权),继续执行')
288
- } else {
289
- push(`- 授权:已于 ${plan.confirmed_at} 落账(${plan.confirmed_by === 'user' ? '人显式批准' : plan.confirmed_by === 'progress' ? '据推进事实补写归属' : String(plan.confirmed_by)})`)
290
- }
291
- push(`- 当前计划(${plan.id}${plan.goal === null || plan.goal === undefined ? '' : ` · 目标 ${plan.goal} 的一个阶段`})步骤:`, 1)
414
+ if (plan === null) {
415
+ if (goal !== null && String(goal.status) === 'open') push(tr('- 计划:还没有(用 CreatePlan 把检验拆成步骤)', '- Plan: none yet (use CreatePlan to split the tests into steps)'), 1)
416
+ } else {
417
+ push(tr('- 计划:', '- Plan:'), 1)
292
418
  for (const step of plan.steps.slice(0, 12)) {
293
- const tests = step.tests === null || step.tests === undefined ? '' : ` 【验 ${step.tests.hypothesis} · ${step.tests.level}】`
294
- push(` ${step.ordinal}. [${step.status}] ${step.do}${tests} → 物证:${(step.artifacts ?? []).join(', ') || '(未声明)'}`, 2)
419
+ const tested = Array.isArray(step.tests?.hypotheses) ? step.tests.hypotheses : typeof step.tests?.hypothesis === 'string' ? [step.tests.hypothesis] : []
420
+ const level = LEVEL_WORD[step.tests?.level] ?? step.tests?.level ?? tr('未定', 'unset')
421
+ const tests = tested.length === 0 ? '' : tr(` · 检验 ${tested.map(nameOf).join('、')}(${level})`, ` · tests ${tested.map(nameOf).join(', ')} (${level})`)
422
+ push(tr(` 第 ${step.ordinal} 步(${step.id})${clamp(step.do, 60)} · ${STEP_WORD[step.status] ?? step.status}${tests}`, ` Step ${step.ordinal} (${step.id}) ${clamp(step.do, 60)} · ${STEP_WORD[step.status] ?? step.status}${tests}`), 2)
295
423
  }
296
- if (plan.steps.length > 12) push(` · (还有 ${plan.steps.length - 12} 步未展开:面板「计划」里有全部)`, 2)
424
+ if (plan.steps.length > 12) push(tr(` · 还有 ${plan.steps.length - 12} 步没展开(右栏「世界树」里有全部)`, ` · ${plan.steps.length - 12} more steps not shown (all are in the World Tree on the right)`), 2)
297
425
  const first = plan.steps.find((step) => step.status === 'open')
298
- if (first !== undefined) push(`- 下一个可交付步:${first.id}(交付只能落在第一个未落定步)`)
299
- if (plan.blocked !== undefined && plan.blocked !== null) push(`- 计划被拦:${plan.blocked.reason}(连续 ${plan.blocked.attempts} 次未过闸,停下等人)`)
300
- }
301
- if (derived?.hasOpenGate === true) push(`- 门(等人,${inbox.length} 件):${inbox.map((item) => `${item.kind}·${item.title}`).join(' / ')}`)
302
- for (const fork of forks.slice(0, 3)) {
303
- const ruler = fork.decide_by === null || fork.decide_by === undefined ? '(无尺子)' : `${fork.decide_by.metric}(${fork.decide_by.direction === 'min' ? '越小越好' : '越大越好'})`
304
- push(`- 世界线(步 ${fork.step} · ${fork.phase}):${fork.question} — 裁决指标 ${ruler}`, 2)
305
- for (const branch of fork.branches) {
306
- const reading = branch.reading === null || branch.reading === undefined ? '未报读数' : `读数 ${branch.reading}${branch.validity === 'usable' ? '' : '(不可用)'}`
307
- const executing = branch.execution ?? null
308
- const runner =
309
- executing === null
310
- ? '(执行者未派出)'
311
- : branch.unreturned === true
312
- ? '(执行者未归 · 分叉已收口,结论不再回灌)'
313
- : executing.ok === null
314
- ? '(执行中,结论会自动回灌)'
315
- : executing.ok === true
316
- ? '(已回灌)'
317
- : `(执行没跑成:${executing.note ?? 'unknown'})`
318
- push(` · [${branch.status}] ${branch.label}:${branch.approach}(${reading})${runner}`, 2)
319
- }
320
- if (fork.verdict !== null && fork.verdict !== undefined) push(` → 已采纳 ${fork.verdict.winner},差额 ${fork.verdict.margin ?? '—'}${fork.verdict.tie === true ? ' · 并列' : ''}(算术裁决,不是谁说得响)`, 2)
321
- if (fork.undecidable !== null && fork.undecidable !== undefined) push(` → 算不出来(${fork.undecidable.code}):${fork.undecidable.reason} 停下问人,不许退化成随便挑一条。`, 2)
322
- if (fork.abandoned === true) push(` → 已放弃探索:${fork.abandonReason ?? ''}(留痕)`, 2)
323
- if (fork.phase === 'exploring' || fork.phase === 'deciding') push(' · 这一步长着未收敛的分叉:先交付每条世界线,再 ConvergeFork;普通交付不能越过它。', 2)
324
- if (fork.humanDecision !== null && fork.humanDecision !== undefined && !fork.settled) {
325
- const decision = fork.humanDecision
326
- push(
327
- decision.action === 'adopt_branch'
328
- ? ` · **人已裁决**:采纳「${fork.branches.find((branch) => branch.id === decision.branch)?.label ?? decision.branch}」——跑 ConvergeFork 落实它(合并是内核的活)。`
329
- : ' · **人已裁决**:放弃这条分叉——跑 AbandonFork 落实它(清理工作副本是内核的活)。',
330
- 2,
331
- )
332
- }
333
- if (fork.merge?.provisional === true) push(` · **临时采纳**(待复核):${fork.merge.decisionNote ?? '分差不足以称结论'}——它不是结论,是一个待复核的决定。`, 2)
426
+ if (first !== undefined) push(tr(`- 下一步:交付第 ${first.ordinal} 步(${first.id})——只能交付第一个没做完的步`, `- Next: deliver step ${first.ordinal} (${first.id}); only the first unfinished step can be delivered`))
427
+ else if (goal !== null && String(goal.status) === 'open') push(tr('- 下一步:计划的步都做完了,ClosePlan 收尾,然后 Conclude 结案或开下一阶段', '- Next: every step is done; ClosePlan, then Conclude or start the next stage'))
428
+ if (plan.blocked !== undefined && plan.blocked !== null) push(tr(`- 计划停下等人:${plan.blocked.reason}(连续 ${plan.blocked.attempts} 次没过,已经问人怎么办;没人答就等着)`, `- Plan stopped, waiting for a person: ${plan.blocked.reason} (failed ${plan.blocked.attempts}× in a row; a person has been asked; wait if nobody answers)`))
334
429
  }
335
- if (forks.length > 3) push(`- (还有 ${forks.length - 3} 盘世界线未展开:面板「世界线」里有全部)`, 2)
336
430
  if (evidence.length > 0) {
337
431
  const last = evidence[evidence.length - 1]
338
- push(`- 最近一条证据:${last.id} ${last.verdict}(${last.evaluator} · ${last.level})`, 1)
432
+ const who = last.evaluator === 'independent' ? LEVEL_WORD.L3 : LEVEL_WORD[last.level] ?? tr('自己判的', 'self-judged')
433
+ const target = last.hypothesis === null || last.hypothesis === undefined ? tr('目标判据', 'goal criteria') : nameOf(last.hypothesis)
434
+ push(tr(`- 最近一次结果:${target}${VERDICT_WORD[last.verdict] ?? last.verdict}(${who})`, `- Latest result: ${target} ${VERDICT_WORD[last.verdict] ?? last.verdict} (${who})`), 1)
339
435
  }
340
- if (facts.length > 0) push(`- 已升格事实:${facts.length} 条`, 1)
341
- if (lexicon.terms.length > 0 || lexicon.predicates.length > 0) {
342
- const typed = facts.filter((fact) => Array.isArray(fact.assertions) && fact.assertions.length > 0).length
343
- push(`- 领域词汇:${lexicon.terms.length} 个概念 · ${lexicon.predicates.length} 个谓词;已升格事实里 ${typed}/${facts.length} 条带类型化断言`, 1)
344
- if (issues.some((issue) => issue.severity === 'warning')) push(` · 词汇健康度有 ${issues.filter((issue) => issue.severity === 'warning').length} 条待看(悬空引用 / 成环;在面板「本体」里)`, 1)
436
+ /** 事实行含别的会话留下的(`foreign`):攒下来的东西从这里开始被看见。 */
437
+ const factRows = Array.isArray(derived?.factRows) ? derived.factRows : facts
438
+ if (factRows.length > 0) {
439
+ const foreign = factRows.filter((fact) => fact?.foreign === true).length
440
+ const changed = factRows.filter((fact) => Array.isArray(fact?.definitionsChanged) && fact.definitionsChanged.length > 0 && fact?.review?.decision !== 'retracted').length
441
+ push(
442
+ tr(
443
+ `- 已写进长期知识:${factRows.length} 条${foreign > 0 ? `(${foreign} 条来自以前的会话)` : ''},总览在 clear/knowledge/facts/INDEX.md${changed > 0 ? `;其中 ${changed} 条用到的定义后来改过,需复核` : ''}`,
444
+ `- In long-term knowledge: ${factRows.length}${foreign > 0 ? ` (${foreign} from earlier sessions)` : ''}, overview in clear/knowledge/facts/INDEX.md${changed > 0 ? `; ${changed} use definitions that changed since and need review` : ''}`,
445
+ ),
446
+ 1,
447
+ )
345
448
  }
346
- if (entityNodes.length > 0) {
347
- const assertionEdges = graph.edges.filter((edge) => edge.kind === 'assertion')
348
- push(`- 实体图:${view.entities.length} 个实例节点(已登记 ${view.entityCounts.registered} · 已升格 ${view.entityCounts.promoted} · 实体断言 ${view.entityCounts.asserted}) · ${assertionEdges.length} 条实体边(登记只产节点,Assert 才产边)`, 1)
449
+ /**
450
+ * **本体大纲**:概念树与实体树的前两层(每支标节点数)、关系总数、跨文件问题。
451
+ * 细节在 clear/ontology/ 下的文件里,模型自己去读。
452
+ */
453
+ const outline = ontologyOutline(state)
454
+ const ontologyProblems = Array.isArray(state?.ontologyProblems) ? state.ontologyProblems : []
455
+ if (outline.concepts.total > 0 || outline.entities.total > 0 || outline.relations > 0) {
456
+ const entityRelations = Array.isArray(state?.entityAssertions) ? state.entityAssertions.length : 0
457
+ push(
458
+ tr(
459
+ `- 本体(clear/ontology/):${outline.concepts.total} 个概念 · ${outline.relations} 种关系 · ${outline.entities.total} 个实体 · ${entityRelations} 条实体关系`,
460
+ `- Ontology (clear/ontology/): ${outline.concepts.total} concepts · ${outline.relations} relation types · ${outline.entities.total} entities · ${entityRelations} entity relations`,
461
+ ),
462
+ 1,
463
+ )
464
+ if (outline.concepts.lines.length > 0) push(tr(` · 概念树:${outline.concepts.lines.join(';')}${outline.concepts.more > 0 ? `;顶层还有 ${outline.concepts.more} 个` : ''}`, ` · Concept tree: ${outline.concepts.lines.join('; ')}${outline.concepts.more > 0 ? `; ${outline.concepts.more} more at the top level` : ''}`), 1)
465
+ if (outline.entities.lines.length > 0) push(tr(` · 实体树:${outline.entities.lines.join(';')}${outline.entities.more > 0 ? `;顶层还有 ${outline.entities.more} 个` : ''}`, ` · Entity tree: ${outline.entities.lines.join('; ')}${outline.entities.more > 0 ? `; ${outline.entities.more} more at the top level` : ''}`), 1)
466
+ } else if (entityNodes.length > 0) push(tr(`- 实体图上 ${entityNodes.length} 个实例`, `- ${entityNodes.length} instances on the entity graph`), 1)
467
+ if (ontologyProblems.length > 0) {
468
+ push(tr(`- 本体文件有 ${ontologyProblems.length} 处问题(有问题的节点或关系没进图):`, `- Ontology files have ${ontologyProblems.length} problems (the affected nodes or relations stay off the graph):`), 1)
469
+ for (const item of ontologyProblems.slice(0, 5)) push(` · ${item.path}: ${clamp(item.detail, 160)}`, 1)
470
+ if (ontologyProblems.length > 5) push(tr(` · 还有 ${ontologyProblems.length - 5} 处(面板「本体」里有全部)`, ` · ${ontologyProblems.length - 5} more (all are in the Ontology pane)`), 2)
471
+ } else if (issues.some((issue) => issue.severity === 'warning')) {
472
+ const count = issues.filter((issue) => issue.severity === 'warning').length
473
+ push(tr(`- 词汇里有 ${count} 处要看(引用了不存在的词,或绕成了环)`, `- The vocabulary has ${count} things to check (references to missing terms, or cycles)`), 1)
349
474
  }
350
- for (const conflict of conflicts.slice(0, 3)) {
351
- const sides = conflict.sides.map((side) => `${side.fact ?? '?'}(${side.value})`).join(' 对 ')
352
- push(`- **冲突(${conflict.predicate} · ${conflict.subject})**:${sides}——两条都还没被撤回。它是读数不是裁决:要么用证据推翻一侧,要么由人撤回一侧;系统不替你选。`)
475
+ if (knowledge.mode === 'knowledge') {
476
+ const preflight = view.deliver.preflight
477
+ if (preflight !== null && (preflight.terms.length > 0 || preflight.predicates.length > 0)) {
478
+ const more = (count) => (count > 0 ? tr(`(还有 ${count} 个)`, ` (${count} more)`) : '')
479
+ const named = (entry) => (entry.label === entry.id ? entry.id : `${entry.label}(${entry.id})`)
480
+ const none = tr('无', 'none')
481
+ const terms = preflight.terms.map(named).join(tr('、', ', ')) || none
482
+ const predicates = preflight.predicates.map(named).join(tr('、', ', ')) || none
483
+ push(tr(`- 已有的词,可直接用:概念 ${terms}${more(preflight.termsTruncated)};关系 ${predicates}${more(preflight.predicatesTruncated)}`, `- Existing terms you can use: concepts ${terms}${more(preflight.termsTruncated)}; relations ${predicates}${more(preflight.predicatesTruncated)}`), 1)
484
+ if (preflight.facts.length > 0) push(tr(` · 能复用的已知 ${preflight.facts.length} 条${preflight.factsTruncated > 0 ? `(还有 ${preflight.factsTruncated} 条)` : ''}`, ` · ${preflight.facts.length} known facts to reuse${preflight.factsTruncated > 0 ? ` (${preflight.factsTruncated} more)` : ''}`), 1)
485
+ } else
486
+ push(
487
+ tr(
488
+ '- 已有的词里没有命中这些判断的:要写「主体 · 关系 · 对象」就先在 clear/ontology/ 下写概念与关系文件(字段见 SCHEMA.json);查不到不等于不存在',
489
+ '- No existing term matches these judgments: to write "subject · relation · object", first write concept and relation files under clear/ontology/ (fields in SCHEMA.json); not found does not mean it does not exist',
490
+ ),
491
+ 1,
492
+ )
493
+ if (gaps.length === 0) push(tr('- 结构完整:判断都写成了断言、都检验过、主体都在实体图上', '- Structure complete: every judgment has assertions, has been tested, and its subjects are on the entity graph'))
494
+ /** 缺口只给模型(人看不到):说清欠什么、下一步做什么,不写 code。 */
495
+ for (const gap of gaps) push(tr(`- 还欠的:${gap.detail} → ${gap.nextAction}`, `- Still owed: ${gap.detail} → ${gap.nextAction}`))
353
496
  }
354
- if (conflicts.length > 3) push(`- (还有 ${conflicts.length - 3} 对冲突未展开:面板「本体」里有全部)`, 2)
355
- if (goal !== null && Array.isArray(goal.unjudged) && goal.unjudged.length > 0) push(`- 结案留痕:有 ${goal.unjudged.length} 条假设没有被任何证据触及(${goal.unjudged.join(', ')})`)
356
- {
357
- const foreign = materials.filter((material) => material.source !== 'self')
358
- const flying = scouts.filter((scout) => scout.conclusion === null || scout.conclusion === undefined)
359
- if (foreign.length > 0 || flying.length > 0) {
360
- push('- 资料面(外脑送来的观测 + 还在跑的侦察;全文在工作区文件里,要细节就 read):')
361
- for (const material of foreign.slice(-3)) {
362
- const note = String(material.note ?? '')
363
- const excerpt = note.replace(/\s+/g, ' ').slice(0, 120)
364
- const where = material.path === null || material.path === undefined ? `账本 ${material.ref}` : material.path
365
- push(` · [${material.source}] ${where}${material.bytes === null || material.bytes === undefined ? '' : `(${material.bytes} 字)`}:${excerpt}${note.length > 120 ? '…' : ''}`)
366
- }
367
- if (foreign.length > 3) push(` · (还有 ${foreign.length - 3} 条更早的,全在 clear/knowledge/materials/ 下)`)
368
- for (const scout of flying) push(` · [在跑] 侦察 ${scout.id}${scout.trigger === null || scout.trigger === undefined ? '' : `(${scout.trigger})`}:结论回来时会作为观测送到你面前`)
369
- }
497
+ for (const conflict of conflicts.slice(0, 3)) {
498
+ push(
499
+ tr(
500
+ `- **矛盾**(${conflict.subject} 的 ${conflict.predicate}):${conflict.sides.map((side) => `「${side.value}」`).join(' 对 ')}。系统不替你选:用证据推翻一边,或请人定。`,
501
+ `- **Conflict** (${conflict.predicate} of ${conflict.subject}): ${conflict.sides.map((side) => `"${side.value}"`).join(' vs ')}. The system does not pick: refute one side with evidence, or ask a person.`,
502
+ ),
503
+ )
370
504
  }
371
- push('- 提醒:进度、阶段、假设状态都是系统算出来的;你不能声明它们,只能通过交付与裁决推进。')
505
+ if (conflicts.length > 3) push(tr(`- 还有 ${conflicts.length - 3} 处矛盾没展开(面板「本体」里有全部)`, `- ${conflicts.length - 3} more conflicts not shown (all are in the Ontology pane)`), 2)
506
+ if (goal !== null && Array.isArray(goal.unjudged) && goal.unjudged.length > 0) push(tr(`- 结案时没检验过的判断:${goal.unjudged.map(nameOf).join('、')}`, `- Judgments never tested at close: ${goal.unjudged.map(nameOf).join(', ')}`))
507
+ push(tr('- 进度和可信度由系统按证据算,你只能通过交付推进。对人说起时用短名和这里的词,不写编号。', '- Progress and trust are computed by the system from evidence; you move them only by delivering. When talking to people, use the short names and the words here, not ids.'))
372
508
  return lines
373
509
  }
374
510
 
@@ -410,21 +546,24 @@ export function knowledgeView(state, derived, options = {}) {
410
546
  */
411
547
  const doneText =
412
548
  goal === null
413
- ? '还没有立约:没有「怎样算完成」可算——SetGoal 要一份可核对的判据'
549
+ ? tr('还没有立约:没有「怎样算完成」可算——Frame 要一份可核对的判据', 'Nothing framed yet: there is no "done when" to measure; Frame needs checkable criteria')
414
550
  : Array.isArray(goal.criteria) && goal.criteria.length > 0
415
- ? `${goal.criteria.length} 条:${clamp(goal.criteria.join(' / '), 140)}`
551
+ ? tr(`${goal.criteria.length} 条:${clamp(goal.criteria.join(' / '), 140)}`, `${goal.criteria.length} criteria: ${clamp(goal.criteria.join(' / '), 140)}`)
416
552
  : clamp(String(goal.done_criteria ?? ''), 140) || GLOSSARY.done_criteria.plain
417
553
  const entityCounts = { registered: 0, promoted: 0, asserted: 0 }
418
554
  for (const node of entityNodes) if (entityCounts[node.source] !== undefined) entityCounts[node.source] += 1
419
555
  const preflight = isPlainObject(options?.preflight) ? options.preflight : null
420
556
  const view = {
421
557
  headline: {
422
- now: goal === null ? '还没有立目标(SetGoal 需要一份「怎样算回答了」的判据)' : clamp(goal.headline ?? goal.claim, 160),
558
+ now: goal === null ? tr('还没有立目标(Frame 需要一份「怎样算回答了」的判据)', 'No goal yet (Frame needs criteria for "answered")') : clamp(goal.headline ?? goal.claim, 160),
423
559
  done: doneText,
424
560
  where:
425
561
  goal === null
426
- ? '还没开始:立约之后才有进度可算'
427
- : `${phasePlain(phase)} · 完成度 ${progress === null ? '无法计算' : `${Math.round(progress * 100)}%`}${live.length > 0 ? ` · ${live.length} 条在验命题` : ''}${gaps.length > 0 ? ` · ${gaps.length} 条缺口` : ''}`,
562
+ ? tr('还没开始:立约之后才有进度可算', 'Not started: progress exists once the goal is framed')
563
+ : tr(
564
+ `${phasePlain(phase)} · 完成度 ${progress === null ? '无法计算' : `${Math.round(progress * 100)}%`}${live.length > 0 ? ` · ${live.length} 条判断验证中` : ''}${gaps.length > 0 ? ` · ${gaps.length} 条缺口` : ''}`,
565
+ `${phasePlain(phase)} · completion ${progress === null ? 'not computable' : `${Math.round(progress * 100)}%`}${live.length > 0 ? ` · ${live.length} judgments under test` : ''}${gaps.length > 0 ? ` · ${gaps.length} gaps` : ''}`,
566
+ ),
428
567
  },
429
568
  goal:
430
569
  goal === null
@@ -459,10 +598,8 @@ export function knowledgeView(state, derived, options = {}) {
459
598
  supportedLevel: hypothesis.supportedLevel ?? null,
460
599
  refutations: hypothesis.refutations ?? 0,
461
600
  inconclusive: hypothesis.inconclusive ?? 0,
462
- untouchedLevels: Array.isArray(hypothesis.untouchedLevels) ? hypothesis.untouchedLevels : [],
463
- skips: Array.isArray(hypothesis.skips) ? hypothesis.skips : [],
464
601
  /** 一句读数(与卡上同一句):`未触及` 与「无法判定」分得开。 */
465
- readings: (hypothesis.supportedLevel === null || hypothesis.supportedLevel === undefined) && (hypothesis.refutations ?? 0) === 0 && (hypothesis.inconclusive ?? 0) === 0 ? '未触及' : `支持到 ${hypothesis.supportedLevel ?? '—'}`,
602
+ readings: (hypothesis.supportedLevel === null || hypothesis.supportedLevel === undefined) && (hypothesis.refutations ?? 0) === 0 && (hypothesis.inconclusive ?? 0) === 0 ? tr('未触及', 'untouched') : tr(`支持到 ${hypothesis.supportedLevel ?? '—'}`, `supported to ${hypothesis.supportedLevel ?? '—'}`),
466
603
  /** 已带断言的条数(断言的人话芯片在投影侧算好,这里只报数)。 */
467
604
  assertions: Array.isArray(hypothesis.assertions) ? hypothesis.assertions.length : 0,
468
605
  })),
@@ -487,8 +624,7 @@ export function knowledgeView(state, derived, options = {}) {
487
624
  return { total: rows.length, last: last === null ? null : { id: last.id ?? null, verdict: last.verdict ?? null, level: last.level ?? null, evaluator: last.evaluator ?? null, at: last.at ?? null } }
488
625
  })(),
489
626
  deliver: {
490
- plan: isPlainObject(d.activePlan) ? { id: d.activePlan.id, status: d.activePlan.status, brief: d.activePlan.brief ?? '', confirmedBy: d.activePlan.confirmed_by ?? null } : null,
491
- authorized: d.planConfirmationPending !== true,
627
+ plan: isPlainObject(d.activePlan) ? { id: d.activePlan.id, status: d.activePlan.status, brief: d.activePlan.brief ?? '' } : null,
492
628
  steps: isPlainObject(d.activePlan) ? (d.activePlan.steps ?? []).map((step) => ({ id: step.id, ordinal: step.ordinal, do: step.do, status: step.status, artifacts: step.artifacts ?? [] })) : [],
493
629
  next: isPlainObject(d.activePlan) ? ((d.activePlan.steps ?? []).find((step) => step.status === 'open')?.id ?? null) : null,
494
630
  /** 知识预检(宿主算好的那一份):进了知识模式才有,否则 null。 */
@@ -498,13 +634,14 @@ export function knowledgeView(state, derived, options = {}) {
498
634
  conflicts: conflicts.map((conflict) => ({ predicate: conflict.predicate, subject: conflict.subject, sides: conflict.sides.map((side) => ({ fact: side.fact ?? null, value: side.value ?? null })) })),
499
635
  /** **这张卡不声称什么**:边界与卡放在一起,读的人不必去别处找。 */
500
636
  boundaries: [
501
- '进度、阶段、假设状态都是系统算出来的:模型不能声明它们,只能通过交付与裁决推进。',
502
- '冲突只暴露不裁决:系统不替你选哪一侧为真。',
503
- '实体断言有出处但未经独立裁决:它进图,但还不是「已知」。',
504
- '读面降级(读不到会话 / 投影)时给的是空读数,不是「没有」——不要把读不到当成不存在。',
637
+ tr('进度、阶段、假设状态都是系统算出来的:模型不能声明它们,只能通过交付与裁决推进。', 'Progress, phase and judgment status are computed by the system: the model cannot declare them, only move them through delivery and verdicts.'),
638
+ tr('冲突只暴露不裁决:系统不替你选哪一侧为真。', 'Conflicts are surfaced, not resolved: the system does not pick a side.'),
639
+ tr('实体断言有出处但未经独立裁决:它进图,但还不是「已知」。', 'Entity assertions have a source but no independent verdict: they are on the graph but not yet "known".'),
640
+ tr('读面降级(读不到会话 / 投影)时给的是空读数,不是「没有」——不要把读不到当成不存在。', 'When reads are degraded (no session or projection), the reading is empty, not "nothing": unreadable does not mean absent.'),
505
641
  ],
506
- glossary: GLOSSARY,
507
- levels: Object.fromEntries(LEVELS.map((level) => [level, GLOSSARY[level]])),
642
+ /** 术语表按此刻的语言取一份平的拷贝(表本身按读的那一刻取语言,投影要的是定下来的字)。 */
643
+ glossary: JSON.parse(JSON.stringify(GLOSSARY)),
644
+ levels: Object.fromEntries(LEVELS.map((level) => [level, JSON.parse(JSON.stringify(GLOSSARY[level]))])),
508
645
  card: '',
509
646
  }
510
647
  view.card = fitLines(cardLines(state, d, options, view), CARD_LIMIT)