@quan-huayan/dsh-research-engine 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +38 -0
- package/LICENSE +21 -0
- package/README.md +183 -0
- package/cordis.patch.yml +32 -0
- package/package.json +59 -0
- package/presets/research-engine/agent.cordis.yml +305 -0
- package/presets/research-engine/contract/conventions.schema.json +41 -0
- package/presets/research-engine/contract/fields.md +150 -0
- package/presets/research-engine/contract/managed.json +36 -0
- package/presets/research-engine/contract/manifest.schema.json +33 -0
- package/presets/research-engine/contract/note.schema.json +56 -0
- package/presets/research-engine/contract/observations.schema.json +46 -0
- package/presets/research-engine/contract/pipeline.schema.json +43 -0
- package/presets/research-engine/contract/project.schema.json +66 -0
- package/presets/research-engine/contract/templates.schema.json +78 -0
- package/presets/research-engine/plugins/engine-git/main.js +284 -0
- package/presets/research-engine/plugins/exp-ledger/main.js +1324 -0
- package/presets/research-engine/plugins/kb-core/main.js +538 -0
- package/presets/research-engine/plugins/stage-ctrl/main.js +388 -0
- package/presets/research-engine/plugins/task-dispatch/main.js +848 -0
- package/presets/research-engine/preset.yml +3 -0
- package/presets/research-engine/skills/research-engine/SKILL.md +114 -0
- package/scripts/install.mjs +116 -0
- package/startup.js +24 -0
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$id": "https://research-engine.local/contract/conventions.schema.json",
|
|
3
|
+
"title": "convention —— 用户权威(必须带 decision 引用)",
|
|
4
|
+
"type": "object",
|
|
5
|
+
"additionalProperties": false,
|
|
6
|
+
"required": ["schemaVersion"],
|
|
7
|
+
"properties": { "schemaVersion": { "type": "integer", "const": 3 } },
|
|
8
|
+
"$defs": {
|
|
9
|
+
"decision": {
|
|
10
|
+
"type": "object",
|
|
11
|
+
"additionalProperties": false,
|
|
12
|
+
"required": ["askCallId", "answer", "sessionId", "ts"],
|
|
13
|
+
"properties": {
|
|
14
|
+
"askCallId": { "type": "string", "minLength": 1, "description": "用户答复所对应的提问调用标识。" },
|
|
15
|
+
"question": { "type": "string", "description": "提问原文。" },
|
|
16
|
+
"answer": { "type": "string", "minLength": 1, "description": "用户答复原文(工具拷贝,不是模型转述)。" },
|
|
17
|
+
"selected": { "type": "array", "items": { "type": "string" } },
|
|
18
|
+
"custom": { "type": "string", "description": "用户补充说明原文(若有)。" },
|
|
19
|
+
"sessionId": { "type": "string", "minLength": 1 },
|
|
20
|
+
"ts": { "type": "string", "minLength": 1 },
|
|
21
|
+
"attested": { "type": "boolean", "description": "true = 原文在案但无法回源(会话日志缺失)。" }
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
"convention": {
|
|
25
|
+
"type": "object",
|
|
26
|
+
"additionalProperties": false,
|
|
27
|
+
"required": ["id", "statement", "authority", "status", "source", "decision", "createdAt"],
|
|
28
|
+
"properties": {
|
|
29
|
+
"id": { "type": "string", "pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$" },
|
|
30
|
+
"statement": { "type": "string", "minLength": 1 },
|
|
31
|
+
"scope": { "type": "string", "description": "生效范围;缺省 = 全工程。" },
|
|
32
|
+
"authority": { "type": "string", "const": "user" },
|
|
33
|
+
"status": { "type": "string", "enum": ["active", "deprecated"] },
|
|
34
|
+
"source": { "type": "string", "minLength": 1, "description": "依据来源(文件:行 / runId / 实测命令)。" },
|
|
35
|
+
"decision": { "$ref": "#/$defs/decision" },
|
|
36
|
+
"createdAt": { "type": "string", "minLength": 1 },
|
|
37
|
+
"deprecatedAt": { "type": "string" }
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
# research-engine 八要素字段字典(契约 v3)
|
|
2
|
+
|
|
3
|
+
> 与 `contract/*.schema.json` 配套:schema 管结构与类型,本表管**语义、来源、校验**。
|
|
4
|
+
> 每一行 = 一个字段在物理上的唯一落点、谁能写它、写入时校验什么、读它时怎么判合法。
|
|
5
|
+
|
|
6
|
+
## 0. 落点速查
|
|
7
|
+
|
|
8
|
+
| 要素 | 物理落点 | 属主 |
|
|
9
|
+
|---|---|---|
|
|
10
|
+
| 对话 | `registry.jsonl` 的 `decision` 事件 | exp-ledger |
|
|
11
|
+
| 环境 | `project.yaml` / `pipeline.yaml` / `templates.yaml` / `scripts/*.meta.json` | exp-ledger / stage-ctrl / task-dispatch |
|
|
12
|
+
| 状态 | `registry.jsonl`(权威)+ `.research/state.json`、`_report/*`(派生) | exp-ledger / stage-ctrl / kb-core |
|
|
13
|
+
| 证据 | `experiments/<runId>/{config,manifest,observations}.json` + `raw/` | task-dispatch(raw 由进程写) |
|
|
14
|
+
| 用户权威 | `project.yaml.conventions[]` + `decision` 事件 | exp-ledger |
|
|
15
|
+
| 证据权威 | `experiments/<runId>/observations.json` | task-dispatch |
|
|
16
|
+
| agent 提议 | `.kb/notes/*.md`(`status: proposed`) | kb-core |
|
|
17
|
+
| 结论 | `.kb/notes/*.md`(`kind: claim`) | kb-core |
|
|
18
|
+
|
|
19
|
+
## 1. `registry.jsonl` 事件(append-only)
|
|
20
|
+
|
|
21
|
+
每行一个 JSON 对象,公共字段:
|
|
22
|
+
|
|
23
|
+
| 字段 | 类型 | 必填 | 来源 | 校验 |
|
|
24
|
+
|---|---|---|---|---|
|
|
25
|
+
| `record` | string | 是 | 事件类型 | 枚举:`project/entity/decision/pipeline/stage/run/observe/verify/render/reconcile/note` |
|
|
26
|
+
| `ts` | string | 是 | 工具时钟 | ISO 8601 |
|
|
27
|
+
| `actor` | string | 是 | 工具 | `engine`(工具自身)或 `user`(带裁决) |
|
|
28
|
+
| `seq` | integer | 是 | 追加时自增 | 必须 = 行号;旧台账缺此字段按行号解释 |
|
|
29
|
+
| `prev` | string | 是 | 上一行内容的 sha256 | 空台账为 `"genesis"`;断链即台账被外部改写 |
|
|
30
|
+
| `commit` | string | 否 | 版本库 | **内部字段**,绝不进入模型可见文本 |
|
|
31
|
+
|
|
32
|
+
各 `record` 的专有字段:
|
|
33
|
+
|
|
34
|
+
| record | 字段 |
|
|
35
|
+
|---|---|
|
|
36
|
+
| `project` | `action`(`init`/`reconcile`), `root`, `id` |
|
|
37
|
+
| `entity` | `id`, `kind`, `name?`, `props?`, `source` |
|
|
38
|
+
| `decision` | `kind`(`convention`/`note`/`run-archive`), `id`, `askCallId`, `question?`, `answer`, `sessionId`, `attested?` |
|
|
39
|
+
| `pipeline` | `action`(`stage`/`edge`), `stage?`, `edgeFrom?`, `edgeTo?`, `entry`, `graphVersion` |
|
|
40
|
+
| `stage` | `from`, `to`, `graphVersion`(**只有真正的阶段转移**;声明走 `pipeline`) |
|
|
41
|
+
| `run` | `runId`, `template`, `templateVersion`, `stage`, `kind`, `status`, `params`, `paramsHash`, `graphVersion`, `jobId?`, `detail?`, `outputs?`, `complete?` |
|
|
42
|
+
| `observe` | `runId`, `fields[]`, `compareTo?` |
|
|
43
|
+
| `verify` | `status`(`clean`/`dirty`/`unknown`), `dirty[]`, `unknown[]`, `attested[]` |
|
|
44
|
+
| `render` | `kind`(`notes-skill`/`report`/`index`/`state`), `paths[]`, `count` |
|
|
45
|
+
| `reconcile` | `mode`, `paths[]`, `reason`, `decision?` |
|
|
46
|
+
| `note` | `name`, `kind`, `status`, `authority`, `decidedBy?` |
|
|
47
|
+
|
|
48
|
+
**重放语义**:状态 = 按 `seq` 折叠事件。`run` 取该 runId 最后一条(字段逐条合并);`stage` 取最后一条的 `to`(`pipeline` 事件不参与当前阶段的折叠)。
|
|
49
|
+
|
|
50
|
+
## 2. `project.yaml`
|
|
51
|
+
|
|
52
|
+
| 字段 | 类型 | 必填 | 来源 | 校验 |
|
|
53
|
+
|---|---|---|---|---|
|
|
54
|
+
| `schemaVersion` | integer | 是 | 常量 3 | 不等则拒绝写入 |
|
|
55
|
+
| `project.id` | string | 是 | `project_init` | kebab-case,与目录名建议一致 |
|
|
56
|
+
| `project.name` | string | 是 | `project_init` / 用户 | 非空 |
|
|
57
|
+
| `project.domain` | string | 否 | `project_init` | — |
|
|
58
|
+
| `managed` | string[] | 是 | `contract/managed.json` | 必须与受管白名单一致 |
|
|
59
|
+
| `conventions[]` | convention[] | 是 | `convention_declare` | 每条必须带 `decision`;`authority` 恒为 `user` |
|
|
60
|
+
| `vocabulary` | object | 否 | `project_init` / 迁移 | 开放词汇 |
|
|
61
|
+
| `legacy.keep[]` | {pattern,count} | 否 | `project_init` | 只登记不哈希 |
|
|
62
|
+
|
|
63
|
+
### convention
|
|
64
|
+
|
|
65
|
+
| 字段 | 类型 | 必填 | 来源 | 校验 |
|
|
66
|
+
|---|---|---|---|---|
|
|
67
|
+
| `id` | string | 是 | 工具生成(kebab) | 工程内唯一 |
|
|
68
|
+
| `statement` | string | 是 | 模型起草 | 与用户答复不矛盾(答复里的硬约束必须在 statement 中出现) |
|
|
69
|
+
| `scope` | string | 否 | 模型 | 缺省 = 全工程 |
|
|
70
|
+
| `authority` | string | 是 | 常量 `user` | 不可为 `agent` |
|
|
71
|
+
| `status` | string | 是 | 工具 | `active` / `deprecated`(**永不删除**) |
|
|
72
|
+
| `source` | string | 是 | 模型 | `文件:行` / `runId` / 实测命令 |
|
|
73
|
+
| `decision` | decision | 是 | 会话回查 | `askCallId` 必须对应本会话中一次真实提问且用户确有答复 |
|
|
74
|
+
|
|
75
|
+
## 3. `pipeline.yaml`
|
|
76
|
+
|
|
77
|
+
| 字段 | 类型 | 必填 | 校验 |
|
|
78
|
+
|---|---|---|---|
|
|
79
|
+
| `graphVersion` | integer | 是 | 每次 `stage_declare` 成功 +1 |
|
|
80
|
+
| `entry` | string\|null | 否 | 必须是已知阶段;且不得有入边(fatal) |
|
|
81
|
+
| `stages[].id` | string | 是 | 唯一;改名走「新 id + 旧 id `deprecated`」 |
|
|
82
|
+
| `stages[].status` | enum | 否 | `active`(缺省)/ `deprecated` |
|
|
83
|
+
| `edges[].from/to` | string | 是 | 端点必须已声明;不重复;不自环(fatal) |
|
|
84
|
+
|
|
85
|
+
## 4. `templates.yaml`
|
|
86
|
+
|
|
87
|
+
| 字段 | 类型 | 必填 | 校验 |
|
|
88
|
+
|---|---|---|---|
|
|
89
|
+
| `version` | integer | 是 | 内容变更 +1 |
|
|
90
|
+
| `status` | enum | 是 | `active` / `deprecated` |
|
|
91
|
+
| `allow` | string[] | 是 | 非空;`run_launch` 命令前缀必须命中 |
|
|
92
|
+
| `scriptRef` | object | 是 | 必须已由 `script_declare` 声明;哈希与磁盘一致 |
|
|
93
|
+
| `paramsSchema` | object | 是 | JSON Schema(object 根);`run_draft` 用它校验 params |
|
|
94
|
+
| `observables[]` | observable[] | 是 | **可为空数组**,但字段必须显式声明;`run_observe` 只认这里 |
|
|
95
|
+
| `args` | string | 否 | `{{key}}` 必须在 params 中出现;保留占位见 `managed.json` |
|
|
96
|
+
|
|
97
|
+
## 5. `experiments/<runId>/config.json`(实例冻结)
|
|
98
|
+
|
|
99
|
+
| 字段 | 类型 | 来源 | 说明 |
|
|
100
|
+
|---|---|---|---|
|
|
101
|
+
| `runId` | string | `run_draft` | `<projectId>-<template>-<ts>-<rand>` |
|
|
102
|
+
| `template` / `templateVersion` | string / integer | 环境 | 冻结时的模板身份 |
|
|
103
|
+
| `params` / `paramsHash` | object / string | 入参 | 参数与规范化哈希 |
|
|
104
|
+
| `stage` / `graphVersion` | string / integer | 状态 | 冻结时的阶段机 |
|
|
105
|
+
| `command` | string | 工具渲染 | 完整命令行(**权威**,`run_launch` 以它为准) |
|
|
106
|
+
| `scriptRef` | object | 环境 | `{name, mode, path, sha256}` |
|
|
107
|
+
| `interpreter` | string | 工具推导 | 由脚本扩展名决定 |
|
|
108
|
+
| `workdir` | string | 工具 | 工程根 |
|
|
109
|
+
| `envExpectation` | object | 工具 | `{seed, device?, python?, torch?, cuda?, gpu?}`,`probed` 标记是否实测 |
|
|
110
|
+
|
|
111
|
+
## 6. `manifest.json` / `observations.json`
|
|
112
|
+
|
|
113
|
+
manifest:每个产出 `{path, role, sha256, bytes, producer, ts, stored}`;`raw/` 下未登记的文件 → 该 run 证据不完整(`complete:false`)。
|
|
114
|
+
|
|
115
|
+
observations:`{field, value, unit, file, line, sha256, extractedAt, compareTo?}`。
|
|
116
|
+
- `field` 必须来自模板 `observables[].field`;
|
|
117
|
+
- `file` 必须在 manifest 中登记且当前哈希与 `sha256` 一致;
|
|
118
|
+
- `compareTo` 记录 `{runId, verdict, otherValue, delta, deltaPct, tolerancePct}`。
|
|
119
|
+
|
|
120
|
+
## 7. `.kb/notes/<name>.md`
|
|
121
|
+
|
|
122
|
+
frontmatter(YAML):
|
|
123
|
+
|
|
124
|
+
| 字段 | 类型 | 必填 | 校验 |
|
|
125
|
+
|---|---|---|---|
|
|
126
|
+
| `kind` | enum | 是 | `proposal` / `claim` / `lesson` / `question` |
|
|
127
|
+
| `status` | enum | 是 | `proposed`(缺省)/ `accepted` / `superseded` / `retracted` |
|
|
128
|
+
| `authority` | enum | 是 | 写入时恒为 `agent`;裁决后可带 `decidedBy`(user 权威) |
|
|
129
|
+
| `evidence[]` | pointer[] | claim 必填 | `{type:'run'\|'file'\|'observation', ref}`,逐条解析,失败即拒绝 |
|
|
130
|
+
| `scope` | string | claim 必填 | 成立条件 |
|
|
131
|
+
| `decidedBy` | decision | 裁决后 | 用户裁决原文 |
|
|
132
|
+
|
|
133
|
+
## 8. `.research/state.json`(派生)
|
|
134
|
+
|
|
135
|
+
`{derived:true, generatedAt, source:'registry.jsonl', graphVersion, stage, history[]}` —— 可随时重建。
|
|
136
|
+
|
|
137
|
+
**谁写它**:只有 `stage_goto`。
|
|
138
|
+
|
|
139
|
+
| 调用 | 语义 | 是否要用户裁决 |
|
|
140
|
+
|---|---|---|
|
|
141
|
+
| `stage_goto to=<阶段>` | 记录一次真实转移(必须走已声明的边) | 否 |
|
|
142
|
+
| `stage_goto replay=true` | 纯重放:按台账重算,不产生转移 | 见下 |
|
|
143
|
+
|
|
144
|
+
**冲突规则(P3)**:重放只在**会改变现有派生状态断言的值**时才需要用户裁决——
|
|
145
|
+
文件已存在且 `stage` 与台账重放值不同(或形状不合 v3)时,说明**两个来源互相矛盾**,
|
|
146
|
+
裁决权不在工具也不在 agent,必须带 `decision{askCallId, answer}`;裁决会记为 `decision` 事件(`kind: state-replay`)。
|
|
147
|
+
文件缺失、或已与台账一致时,重放只是缓存重建,不需要裁决。
|
|
148
|
+
|
|
149
|
+
**体检**:`project_verify` 会比对派生状态与台账;形状不合或值矛盾即点名并给出修法,
|
|
150
|
+
派生视图永远不会因为「没被检查」而继续撒谎。
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"note": "受管白名单的唯一定义。project.yaml.managed 必须与此一致;工具写入前用它判定守卫范围。",
|
|
4
|
+
"managed": [
|
|
5
|
+
"project.yaml",
|
|
6
|
+
"pipeline.yaml",
|
|
7
|
+
"templates.yaml",
|
|
8
|
+
"registry.jsonl",
|
|
9
|
+
"scripts/**",
|
|
10
|
+
".kb/**",
|
|
11
|
+
"skills/*/SKILL.md",
|
|
12
|
+
"_report/**",
|
|
13
|
+
".research/state.json",
|
|
14
|
+
".research/managed.json",
|
|
15
|
+
".research/ignored.json",
|
|
16
|
+
"experiments/*/config.json",
|
|
17
|
+
"experiments/*/manifest.json",
|
|
18
|
+
"experiments/*/observations.json"
|
|
19
|
+
],
|
|
20
|
+
"processWritable": [
|
|
21
|
+
"experiments/*/raw/**"
|
|
22
|
+
],
|
|
23
|
+
"versionedRaw": [
|
|
24
|
+
"experiments/*/raw/**"
|
|
25
|
+
],
|
|
26
|
+
"never": {
|
|
27
|
+
"note": "遗留区与用户数据:只登记,不改、不删、不入版本库。",
|
|
28
|
+
"extensions": [".pth", ".png", ".txt", ".txt~", ".ipynb", ".zip", ".bin", ".npz", ".pt", ".csv"],
|
|
29
|
+
"areas": ["data", "history", "x", "x1", "x2"]
|
|
30
|
+
},
|
|
31
|
+
"reservedPlaceholders": {
|
|
32
|
+
"__raw__": "experiments/<runId>/raw(本次 run 的原始产出目录,工程内相对路径)",
|
|
33
|
+
"__runId__": "本次 runId",
|
|
34
|
+
"__project__": "工程根(绝对路径)"
|
|
35
|
+
}
|
|
36
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$id": "https://research-engine.local/contract/manifest.schema.json",
|
|
3
|
+
"title": "experiments/<runId>/manifest.json —— 证据清单",
|
|
4
|
+
"type": "object",
|
|
5
|
+
"additionalProperties": false,
|
|
6
|
+
"required": ["schemaVersion", "runId", "entries"],
|
|
7
|
+
"properties": {
|
|
8
|
+
"schemaVersion": { "type": "integer", "const": 3 },
|
|
9
|
+
"runId": { "type": "string", "minLength": 1 },
|
|
10
|
+
"entries": {
|
|
11
|
+
"type": "array",
|
|
12
|
+
"items": { "$ref": "#/$defs/entry" }
|
|
13
|
+
},
|
|
14
|
+
"complete": { "type": "boolean", "description": "false = 证据不完整(存在未登记产出),不得据此下结论。" },
|
|
15
|
+
"updatedAt": { "type": "string" }
|
|
16
|
+
},
|
|
17
|
+
"$defs": {
|
|
18
|
+
"entry": {
|
|
19
|
+
"type": "object",
|
|
20
|
+
"additionalProperties": false,
|
|
21
|
+
"required": ["path", "role", "sha256", "bytes", "producer", "ts"],
|
|
22
|
+
"properties": {
|
|
23
|
+
"path": { "type": "string", "description": "工程内相对路径。" },
|
|
24
|
+
"role": { "type": "string", "description": "证据角色(config / log / stdout / result / checkpoint / figure / other)。" },
|
|
25
|
+
"sha256": { "type": "string", "pattern": "^[0-9a-f]{64}$" },
|
|
26
|
+
"bytes": { "type": "integer", "minimum": 0 },
|
|
27
|
+
"producer": { "type": "string", "description": "产生者:工具名或进程。" },
|
|
28
|
+
"ts": { "type": "string", "minLength": 1 },
|
|
29
|
+
"stored": { "type": "string", "enum": ["versioned", "hash-only"], "description": "versioned = 已随版本库存档;hash-only = 仅记录哈希(版本库不可用或未启用)。" }
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$id": "https://research-engine.local/contract/note.schema.json",
|
|
3
|
+
"title": ".kb/notes/<name>.md —— frontmatter:提议 / 结论 / 教训 / 问题",
|
|
4
|
+
"type": "object",
|
|
5
|
+
"additionalProperties": false,
|
|
6
|
+
"required": ["schemaVersion", "name", "kind", "status", "authority", "description", "evidence", "createdAt", "updatedAt"],
|
|
7
|
+
"properties": {
|
|
8
|
+
"schemaVersion": { "type": "integer", "const": 3 },
|
|
9
|
+
"name": { "type": "string", "pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$" },
|
|
10
|
+
"kind": { "type": "string", "enum": ["proposal", "claim", "lesson", "question"] },
|
|
11
|
+
"status": { "type": "string", "enum": ["proposed", "accepted", "superseded", "retracted"] },
|
|
12
|
+
"authority": { "type": "string", "enum": ["agent", "user", "evidence"] },
|
|
13
|
+
"description": { "type": "string", "minLength": 1 },
|
|
14
|
+
"evidence": {
|
|
15
|
+
"type": "array",
|
|
16
|
+
"items": { "$ref": "#/$defs/pointer" },
|
|
17
|
+
"description": "证据指针;claim 必填且必须可解析。"
|
|
18
|
+
},
|
|
19
|
+
"scope": { "type": "string", "description": "成立条件 / 适用范围。" },
|
|
20
|
+
"decidedBy": { "$ref": "#/$defs/decision" },
|
|
21
|
+
"supersedes": { "type": "array", "items": { "type": "string" } },
|
|
22
|
+
"supersededBy": { "type": "string" },
|
|
23
|
+
"tags": { "type": "array", "items": { "type": "string" } },
|
|
24
|
+
"stage": { "type": "string" },
|
|
25
|
+
"createdAt": { "type": "string", "minLength": 1 },
|
|
26
|
+
"updatedAt": { "type": "string", "minLength": 1 },
|
|
27
|
+
"legacy": { "type": "object", "description": "迁移前的原始 frontmatter 字段(保留不丢)。" }
|
|
28
|
+
},
|
|
29
|
+
"$defs": {
|
|
30
|
+
"pointer": {
|
|
31
|
+
"type": "object",
|
|
32
|
+
"additionalProperties": false,
|
|
33
|
+
"required": ["type", "ref"],
|
|
34
|
+
"properties": {
|
|
35
|
+
"type": { "type": "string", "enum": ["run", "file", "observation"] },
|
|
36
|
+
"ref": { "type": "string", "minLength": 1, "description": "runId / 工程内相对路径(可带 :行) / runId#field。" },
|
|
37
|
+
"note": { "type": "string" }
|
|
38
|
+
}
|
|
39
|
+
},
|
|
40
|
+
"decision": {
|
|
41
|
+
"type": "object",
|
|
42
|
+
"additionalProperties": false,
|
|
43
|
+
"required": ["askCallId", "answer", "sessionId", "ts"],
|
|
44
|
+
"properties": {
|
|
45
|
+
"askCallId": { "type": "string" },
|
|
46
|
+
"question": { "type": "string" },
|
|
47
|
+
"answer": { "type": "string" },
|
|
48
|
+
"selected": { "type": "array", "items": { "type": "string" } },
|
|
49
|
+
"custom": { "type": "string" },
|
|
50
|
+
"sessionId": { "type": "string" },
|
|
51
|
+
"ts": { "type": "string" },
|
|
52
|
+
"attested": { "type": "boolean" }
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$id": "https://research-engine.local/contract/observations.schema.json",
|
|
3
|
+
"title": "experiments/<runId>/observations.json —— 证据权威(工具提取值)",
|
|
4
|
+
"type": "object",
|
|
5
|
+
"additionalProperties": false,
|
|
6
|
+
"required": ["schemaVersion", "runId", "observations"],
|
|
7
|
+
"properties": {
|
|
8
|
+
"schemaVersion": { "type": "integer", "const": 3 },
|
|
9
|
+
"runId": { "type": "string", "minLength": 1 },
|
|
10
|
+
"observations": {
|
|
11
|
+
"type": "array",
|
|
12
|
+
"items": { "$ref": "#/$defs/observation" }
|
|
13
|
+
},
|
|
14
|
+
"updatedAt": { "type": "string" }
|
|
15
|
+
},
|
|
16
|
+
"$defs": {
|
|
17
|
+
"observation": {
|
|
18
|
+
"type": "object",
|
|
19
|
+
"additionalProperties": false,
|
|
20
|
+
"required": ["field", "value", "file", "line", "sha256", "extractedAt"],
|
|
21
|
+
"properties": {
|
|
22
|
+
"field": { "type": "string" },
|
|
23
|
+
"value": { "type": ["number", "string"] },
|
|
24
|
+
"unit": { "type": "string" },
|
|
25
|
+
"file": { "type": "string", "description": "来源文件(工程内相对路径)。" },
|
|
26
|
+
"line": { "type": "integer", "minimum": 1 },
|
|
27
|
+
"sha256": { "type": "string", "pattern": "^[0-9a-f]{64}$", "description": "提取时来源文件的哈希。" },
|
|
28
|
+
"extractedAt": { "type": "string", "minLength": 1 },
|
|
29
|
+
"compareTo": { "$ref": "#/$defs/comparison" }
|
|
30
|
+
}
|
|
31
|
+
},
|
|
32
|
+
"comparison": {
|
|
33
|
+
"type": "object",
|
|
34
|
+
"additionalProperties": false,
|
|
35
|
+
"required": ["runId", "verdict"],
|
|
36
|
+
"properties": {
|
|
37
|
+
"runId": { "type": "string" },
|
|
38
|
+
"verdict": { "type": "string", "enum": ["match", "mismatch", "missing"] },
|
|
39
|
+
"otherValue": { "type": ["number", "string", "null"] },
|
|
40
|
+
"delta": { "type": ["number", "null"] },
|
|
41
|
+
"deltaPct": { "type": ["number", "null"] },
|
|
42
|
+
"tolerancePct": { "type": ["number", "null"] }
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$id": "https://research-engine.local/contract/pipeline.schema.json",
|
|
3
|
+
"title": "pipeline.yaml —— 环境:阶段机",
|
|
4
|
+
"type": "object",
|
|
5
|
+
"additionalProperties": false,
|
|
6
|
+
"required": ["schemaVersion", "graphVersion", "stages", "edges"],
|
|
7
|
+
"properties": {
|
|
8
|
+
"schemaVersion": { "type": "integer", "const": 3 },
|
|
9
|
+
"graphVersion": { "type": "integer", "minimum": 1, "description": "阶段机版本;每次变更递增,run 冻结时抄录。" },
|
|
10
|
+
"entry": { "type": ["string", "null"], "description": "入口阶段 id;可为 null(图未设入口)。" },
|
|
11
|
+
"stages": {
|
|
12
|
+
"type": "array",
|
|
13
|
+
"items": { "$ref": "#/$defs/stage" }
|
|
14
|
+
},
|
|
15
|
+
"edges": {
|
|
16
|
+
"type": "array",
|
|
17
|
+
"items": { "$ref": "#/$defs/edge" }
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
"$defs": {
|
|
21
|
+
"stage": {
|
|
22
|
+
"type": "object",
|
|
23
|
+
"additionalProperties": false,
|
|
24
|
+
"required": ["id", "name"],
|
|
25
|
+
"properties": {
|
|
26
|
+
"id": { "type": "string", "pattern": "^[a-z0-9]+(?:[a-z0-9_-]*[a-z0-9])?$" },
|
|
27
|
+
"name": { "type": "string" },
|
|
28
|
+
"status": { "type": "string", "enum": ["active", "deprecated"] },
|
|
29
|
+
"replacedBy": { "type": "string", "description": "改名后的新 id(旧 id 只 deprecated,永不删除)。" }
|
|
30
|
+
}
|
|
31
|
+
},
|
|
32
|
+
"edge": {
|
|
33
|
+
"type": "object",
|
|
34
|
+
"additionalProperties": false,
|
|
35
|
+
"required": ["from", "to"],
|
|
36
|
+
"properties": {
|
|
37
|
+
"from": { "type": "string" },
|
|
38
|
+
"to": { "type": "string" },
|
|
39
|
+
"note": { "type": "string" }
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$id": "https://research-engine.local/contract/project.schema.json",
|
|
3
|
+
"title": "project.yaml —— 环境:身份 / 受管区 / legacy 声明 / 约定",
|
|
4
|
+
"type": "object",
|
|
5
|
+
"additionalProperties": false,
|
|
6
|
+
"required": ["schemaVersion", "project", "managed", "conventions"],
|
|
7
|
+
"properties": {
|
|
8
|
+
"schemaVersion": { "type": "integer", "const": 3 },
|
|
9
|
+
"project": { "$ref": "#/$defs/identity" },
|
|
10
|
+
"managed": {
|
|
11
|
+
"type": "array",
|
|
12
|
+
"minItems": 1,
|
|
13
|
+
"items": { "type": "string" },
|
|
14
|
+
"description": "受管区白名单(相对工程根的 pathspec);只有这些路径进版本库,也只有这些路径的越权改动会被判 dirty。"
|
|
15
|
+
},
|
|
16
|
+
"conventions": {
|
|
17
|
+
"type": "array",
|
|
18
|
+
"items": { "$ref": "https://research-engine.local/contract/conventions.schema.json#/$defs/convention" },
|
|
19
|
+
"description": "用户权威声明;每条必须带 decision 引用。"
|
|
20
|
+
},
|
|
21
|
+
"vocabulary": {
|
|
22
|
+
"type": "object",
|
|
23
|
+
"additionalProperties": false,
|
|
24
|
+
"properties": {
|
|
25
|
+
"entityKinds": { "type": "array", "items": { "type": "string" } },
|
|
26
|
+
"noteKinds": { "type": "array", "items": { "type": "string" } },
|
|
27
|
+
"observableRoles": { "type": "array", "items": { "type": "string" } }
|
|
28
|
+
},
|
|
29
|
+
"description": "开放词汇表(迁移自旧 kb.types / 实体类别)。"
|
|
30
|
+
},
|
|
31
|
+
"legacy": {
|
|
32
|
+
"type": "object",
|
|
33
|
+
"additionalProperties": false,
|
|
34
|
+
"properties": {
|
|
35
|
+
"note": { "type": "string" },
|
|
36
|
+
"keep": {
|
|
37
|
+
"type": "array",
|
|
38
|
+
"items": {
|
|
39
|
+
"type": "object",
|
|
40
|
+
"additionalProperties": false,
|
|
41
|
+
"required": ["pattern", "count"],
|
|
42
|
+
"properties": {
|
|
43
|
+
"pattern": { "type": "string" },
|
|
44
|
+
"count": { "type": "integer" }
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
},
|
|
48
|
+
"protectedAreas": { "type": "array", "items": { "type": "string" } }
|
|
49
|
+
},
|
|
50
|
+
"description": "遗留区:只登记 size/mtime,不改不删不哈希。"
|
|
51
|
+
}
|
|
52
|
+
},
|
|
53
|
+
"$defs": {
|
|
54
|
+
"identity": {
|
|
55
|
+
"type": "object",
|
|
56
|
+
"additionalProperties": false,
|
|
57
|
+
"required": ["id", "name"],
|
|
58
|
+
"properties": {
|
|
59
|
+
"id": { "type": "string", "pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$" },
|
|
60
|
+
"name": { "type": "string", "minLength": 1 },
|
|
61
|
+
"domain": { "type": "string" },
|
|
62
|
+
"description": { "type": "string" }
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$id": "https://research-engine.local/contract/templates.schema.json",
|
|
3
|
+
"title": "templates.yaml —— 环境:可执行声明(含 observables)",
|
|
4
|
+
"type": "object",
|
|
5
|
+
"additionalProperties": false,
|
|
6
|
+
"required": ["schemaVersion", "templates"],
|
|
7
|
+
"properties": {
|
|
8
|
+
"schemaVersion": { "type": "integer", "const": 3 },
|
|
9
|
+
"templates": {
|
|
10
|
+
"type": "object",
|
|
11
|
+
"additionalProperties": { "$ref": "#/$defs/template" }
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"$defs": {
|
|
15
|
+
"template": {
|
|
16
|
+
"type": "object",
|
|
17
|
+
"additionalProperties": false,
|
|
18
|
+
"required": ["version", "status", "description", "allow", "scriptRef", "paramsSchema", "observables"],
|
|
19
|
+
"properties": {
|
|
20
|
+
"version": { "type": "integer", "minimum": 1 },
|
|
21
|
+
"status": { "type": "string", "enum": ["active", "deprecated"] },
|
|
22
|
+
"description": { "type": "string" },
|
|
23
|
+
"allow": {
|
|
24
|
+
"type": "array",
|
|
25
|
+
"minItems": 1,
|
|
26
|
+
"items": { "type": "string" },
|
|
27
|
+
"description": "命令前缀白名单;run_launch 的安全闸依据。"
|
|
28
|
+
},
|
|
29
|
+
"scriptRef": { "$ref": "#/$defs/scriptRef" },
|
|
30
|
+
"args": { "type": "string", "description": "追加参数模板,支持 {{key}}(来自 params)与 {{__raw__}}/{{__runId__}}/{{__project__}} 保留占位。" },
|
|
31
|
+
"paramsSchema": { "$ref": "#/$defs/paramsSchema" },
|
|
32
|
+
"observables": {
|
|
33
|
+
"type": "array",
|
|
34
|
+
"items": { "$ref": "#/$defs/observable" },
|
|
35
|
+
"description": "可提取字段声明;run_observe 只能提取这里声明过的字段(防挑数字)。"
|
|
36
|
+
},
|
|
37
|
+
"updatedAt": { "type": "string" },
|
|
38
|
+
"deprecatedAt": { "type": "string" }
|
|
39
|
+
}
|
|
40
|
+
},
|
|
41
|
+
"scriptRef": {
|
|
42
|
+
"type": "object",
|
|
43
|
+
"additionalProperties": false,
|
|
44
|
+
"required": ["name", "mode", "path"],
|
|
45
|
+
"properties": {
|
|
46
|
+
"name": { "type": "string" },
|
|
47
|
+
"mode": { "type": "string", "enum": ["create", "adopt"] },
|
|
48
|
+
"path": { "type": "string", "description": "工程内相对路径。" },
|
|
49
|
+
"sha256": { "type": "string", "pattern": "^[0-9a-f]{64}$" },
|
|
50
|
+
"version": { "type": "integer", "minimum": 1 }
|
|
51
|
+
}
|
|
52
|
+
},
|
|
53
|
+
"paramsSchema": {
|
|
54
|
+
"type": "object",
|
|
55
|
+
"additionalProperties": true,
|
|
56
|
+
"required": ["type"],
|
|
57
|
+
"properties": {
|
|
58
|
+
"type": { "type": "string", "const": "object" },
|
|
59
|
+
"properties": { "type": "object" },
|
|
60
|
+
"required": { "type": "array", "items": { "type": "string" } },
|
|
61
|
+
"additionalProperties": { "type": "boolean" }
|
|
62
|
+
}
|
|
63
|
+
},
|
|
64
|
+
"observable": {
|
|
65
|
+
"type": "object",
|
|
66
|
+
"additionalProperties": false,
|
|
67
|
+
"required": ["field", "role", "pattern"],
|
|
68
|
+
"properties": {
|
|
69
|
+
"field": { "type": "string", "pattern": "^[A-Za-z_][A-Za-z0-9_]*$" },
|
|
70
|
+
"role": { "type": "string", "description": "从 manifest 中哪个角色的产出文件提取。" },
|
|
71
|
+
"pattern": { "type": "string", "description": "正则;第 1 个捕获组 = 数值。" },
|
|
72
|
+
"unit": { "type": "string" },
|
|
73
|
+
"description": { "type": "string" },
|
|
74
|
+
"kind": { "type": "string", "enum": ["number", "string"] }
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|