dsh-math-modeling-agent 0.2.7 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/package.json +1 -1
- package/skills/math-modeling-agent/SKILL.md +11 -11
- package/skills/math-modeling-agent/references/claims-evidence.md +3 -1
- package/skills/math-modeling-agent/references/interaction-protocol.md +28 -2
- package/skills/math-modeling-agent/references/math-grill.md +8 -0
- package/skills/math-modeling-agent/references/report-contract.md +58 -6
- package/skills/math-modeling-agent/references/workflow.md +22 -0
- package/skills/math-modeling-agent/scripts/run-state.mjs +34 -7
package/README.md
CHANGED
|
@@ -108,7 +108,7 @@ D3 方向/D4 裁决),`run-state.mjs gate` 在每次状态转移前强制校
|
|
|
108
108
|
安装:
|
|
109
109
|
|
|
110
110
|
```bash
|
|
111
|
-
dsh plugin --profile web add github:yohanchen1/MathModelingAgent#v0.
|
|
111
|
+
dsh plugin --profile web add github:yohanchen1/MathModelingAgent#v0.3.1
|
|
112
112
|
dsh --profile web --dump-config # 检查组合层(应看到 dsh-math-modeling-agent-skills 行)
|
|
113
113
|
dsh web # 重启以加载插件
|
|
114
114
|
```
|
package/package.json
CHANGED
|
@@ -22,18 +22,18 @@ Return a concise current status, supported claims, unresolved obligations, attem
|
|
|
22
22
|
## Default workflow
|
|
23
23
|
|
|
24
24
|
1. Route the task to Fast, Standard, or High-Assurance using `references/problem-types.md`; ask D1 (task type + assurance mode).
|
|
25
|
-
2.
|
|
26
|
-
3.
|
|
27
|
-
4.
|
|
28
|
-
5. Register
|
|
29
|
-
6.
|
|
30
|
-
7.
|
|
31
|
-
8.
|
|
32
|
-
9.
|
|
25
|
+
2. Literature research FIRST: transition TRIAGE → RESEARCH, search principles and methods by direction (never contest solutions), write `research/sources.jsonl` + methods matrix, ask D-R (user endorses/rejects/adds).
|
|
26
|
+
3. Show the D0 deep restatement — six sections plus the question-dependency relation — and ask D0; gate SCOPE_FROZEN (requires D0+D1+D-R).
|
|
27
|
+
4. Panorama analysis + data profile (INPUT_PROFILED) with user interaction; global assumptions G-class confirmed via D2-G before CLAIMS_REGISTERED.
|
|
28
|
+
5. Register claims and obligations; build the candidate matrix with literature column (CANDIDATES_READY) and ask D3.
|
|
29
|
+
6. For EACH subproblem: subproblem analysis (reference the panorama, do not re-derive), S-class assumptions via D2-SPi, then ATTEMPT → EXECUTE → VERIFY → subproblem robustness (plan→interact→run) → D4 verdict → REVISE or move to the next subproblem.
|
|
30
|
+
7. Live documents: any discovery that shows an earlier phase was incomplete patches that phase incrementally (revision + stale), never re-running unaffected completed work.
|
|
31
|
+
8. Backtracking depth follows the failure root cause (attempt/verify/direction/assumption/analysis/restatement/research), recorded in failed/issues.md.
|
|
32
|
+
9. Probe tools with `scripts/capability-probe.mjs`; create a run-local Python environment with `scripts/python-environment.mjs` when computation is required; announce the tool choice and fallback.
|
|
33
33
|
10. Dispatch subagents for parallel exploration, blind verification, and audits per `references/subagent-dispatch.md`.
|
|
34
|
-
11. Escalate evidence gaps
|
|
35
|
-
12. Write
|
|
36
|
-
13. Before any terminal transition,
|
|
34
|
+
11. Escalate evidence gaps through `references/research-breakthrough.md`; write wall memos and the failure ledger per `references/run-directory.md`.
|
|
35
|
+
12. Write incremental attempt and terminal reports per `references/report-contract.md`; output the per-round runlog digest in the chat.
|
|
36
|
+
13. Before any terminal transition: cleanup gate, ALL required robustness obligations PASS (or robustnessExempt), every subproblem DONE with dependencies satisfied, D4 for the current attempt, report.md present.
|
|
37
37
|
|
|
38
38
|
## Invariants
|
|
39
39
|
|
|
@@ -6,7 +6,9 @@ Store claim ID, exact wording, type, scope/quantifiers, assumptions, risk, verif
|
|
|
6
6
|
|
|
7
7
|
## Assumption record (v2)
|
|
8
8
|
|
|
9
|
-
Store id, statement, scope (
|
|
9
|
+
Store id, statement, scope ('global' for whole-problem assumptions, or a subproblem id list), source category, risk, sensitivity plan, validation status, affected claims, status (active/revised/superseded), and revisionHistory [{at, reason, changedTo}]. Allowed source categories are problem, data, theory, verified literature, domain instruction, and modeling simplification.
|
|
10
|
+
|
|
11
|
+
Two classes: G-class (global, confirmed once in the panorama layer via D2-G) and S-class (per subproblem, confirmed via D2-SPi). Claims carry an `assumptions` field listing the assumption ids they depend on; when an assumption is revised, dependent claims are marked stale and must carry post-revision evidence before a terminal state (validate warns otherwise).
|
|
10
12
|
|
|
11
13
|
Every assumption additionally carries a `basis` field — the evidence chain behind it: `problem-quote` (exact original wording), `data` (evidence id + statistic), `literature` (source id + excerpt location), or `llm-judgment` (explicitly flagged as the LLM's own inference, challengeable in D2).
|
|
12
14
|
|
|
@@ -31,7 +31,8 @@ until the user says "可以了". Mathematical modeling is a deep activity;
|
|
|
31
31
|
| D0 问题重述 | intake complete | the six-section deep restatement below + open clarification questions | accept + no additions |
|
|
32
32
|
| D1 路由 | TRIAGE | task type (prediction/optimization/explanation/proof/…) + assurance mode (Fast/Standard/High-Assurance) | auto-routing result |
|
|
33
33
|
| D-R 文献研究 | CLAIMS_REGISTERED (before CANDIDATES_READY) | the literature list by direction (AI-found); user endorses / rejects / adds their own | accept list |
|
|
34
|
-
| D2
|
|
34
|
+
| D2-G 全局假设确认 | CLAIMS_REGISTERED (全景层) | the GLOBAL assumptions that hold for the whole problem (geometry, data, physical mechanism, numerical basis) — each with basis chain + risk | accept all |
|
|
35
|
+
| D2 子问题假设确认 | **each subproblem starts** | the assumptions for THIS subproblem only (S-class), each with statement + basis chain + risk | accept all |
|
|
35
36
|
| D2' 新假设插问 | mid-subproblem discovery that changes model structure | the new assumption + its effect | record-and-continue |
|
|
36
37
|
| D3 方向选择 | CANDIDATES_READY | candidate matrix with a literature column per direction; user picks or authorizes auto | baseline |
|
|
37
38
|
| D4 结果裁决 | VERIFY done | verdict + evidence digest + key intermediate results (residual/constraint-violation distributions, figure paths) + failure details | verdict-implied |
|
|
@@ -46,8 +47,12 @@ until the user says "可以了". Mathematical modeling is a deep activity;
|
|
|
46
47
|
4. **隐含信息与歧义清单**:numbered; each entry = the LLM's reading + its
|
|
47
48
|
basis + the risk if the reading is wrong. This is the heart of the
|
|
48
49
|
exchange: the user corrects entries here.
|
|
49
|
-
5.
|
|
50
|
+
5. **各子问题数学本质判定**:every sub-question of the problem — however
|
|
51
|
+
many there are (one or ten) — is classified (fitting/optimization/
|
|
50
52
|
geometric optics/simulation/…), with why.
|
|
53
|
+
5.5 **问间依赖关系**:which sub-questions depend on which (models, data,
|
|
54
|
+
verified claims reused downstream) — the整体感 guarantee: later questions
|
|
55
|
+
REFERENCE earlier verified results instead of re-deriving them.
|
|
51
56
|
6. **待澄清问题**:open questions inviting the user to add background,
|
|
52
57
|
correct a reading, or supply their own references — never a yes/no list.
|
|
53
58
|
|
|
@@ -99,6 +104,19 @@ record to real files on disk.
|
|
|
99
104
|
batch runs may declare `scope.contractExempt: true` — production modeling
|
|
100
105
|
must never set it.
|
|
101
106
|
|
|
107
|
+
## Phase pace — interactive beats between phases (v2.8)
|
|
108
|
+
|
|
109
|
+
The exposition is delivered PHASE BY PHASE, never as a firehose. The phase
|
|
110
|
+
sequence is: restatement → analysis → assumptions → modeling → solving →
|
|
111
|
+
verification → robustness → evaluation. Between every two phases there MUST
|
|
112
|
+
be a user interaction point: the completed phase is presented, one line asks
|
|
113
|
+
whether to proceed to the next phase, and the user may interrupt, ask for a
|
|
114
|
+
deeper explanation of any step of the just-finished phase, or contribute
|
|
115
|
+
knowledge. Sensitivity/robustness NEVER follows solving automatically — it
|
|
116
|
+
only starts after the verification phase, the user's go-ahead, and its own
|
|
117
|
+
D-interaction. Within a phase with ≥3 major steps, offer the user one
|
|
118
|
+
interruption opportunity after the first step.
|
|
119
|
+
|
|
102
120
|
## L2 display points (MUST show, never ask)
|
|
103
121
|
|
|
104
122
|
- After every attempt round: the 8-section runlog digest (see report-contract.md).
|
|
@@ -127,6 +145,14 @@ record to real files on disk.
|
|
|
127
145
|
and every downstream claim/obligation that depended on the old assumption is
|
|
128
146
|
marked `stale: true` with the revising assumption id (see claims-evidence.md).
|
|
129
147
|
|
|
148
|
+
## Live documents (every phase can be refined later)
|
|
149
|
+
|
|
150
|
+
Every phase artifact is LIVE: problem-brief.md (restatement), analysisLog,
|
|
151
|
+
assumptions, sources.jsonl, methods.md, attempt reports. While solving,
|
|
152
|
+
anything discovered that shows an earlier phase was incomplete is patched
|
|
153
|
+
INCREMENTALLY — revision record + downstream stale marking — without
|
|
154
|
+
re-running completed unaffected work. This is the "解题中不断完善" rule.
|
|
155
|
+
|
|
130
156
|
## Rolling documents
|
|
131
157
|
|
|
132
158
|
- Problem restatement: written once at intake (problem-brief.md); only
|
|
@@ -17,6 +17,14 @@ Ask one question at a time. Read the problem and attachments first. Ask only que
|
|
|
17
17
|
10. 假设及依据;11. 任务类型(预测/优化/解释/证明/机制/决策);12. 误差/精度要求;
|
|
18
18
|
13. 验证标准;14. 最终交付物;15. 风险与失败模式;16. 不适用字段(标注原因)。
|
|
19
19
|
|
|
20
|
+
## Layered questioning (v0.3)
|
|
21
|
+
|
|
22
|
+
- **全景层**:global assumptions (G-class) are grilled once — geometry, data
|
|
23
|
+
quality, physical mechanism, numerical basis; recorded via D2-G before
|
|
24
|
+
CLAIMS_REGISTERED.
|
|
25
|
+
- **逐问层**:per-subproblem assumptions (S-class) are grilled when the
|
|
26
|
+
subproblem starts (D2-SPi) — only what is specific to this sub-question.
|
|
27
|
+
|
|
20
28
|
## Per-subproblem grilling (v2)
|
|
21
29
|
|
|
22
30
|
- Grill **one subproblem at a time**. Never demand assumptions for Q2 while Q1 is unsolved.
|
|
@@ -24,21 +24,73 @@ Do not copy full prior solutions or private reasoning.
|
|
|
24
24
|
|
|
25
25
|
State the frozen question, final scientific status, answer/recommendation, verified claims and evidence links, conditional/unresolved claims, assumptions and sensitivity, candidate comparison, data and parameter sources, validation, failure cases, limitations, reproducibility commands, and resume conditions when non-SOLVED.
|
|
26
26
|
|
|
27
|
-
|
|
27
|
+
整体感 requirement (v0.3): the terminal report is ONE narrative, not a
|
|
28
|
+
concatenation of sub-question reports — it must show the question-dependency
|
|
29
|
+
chain (which model fed which), the shared global assumptions, and the
|
|
30
|
+
cross-sub-question consistency checks. A reader must be able to see the whole
|
|
31
|
+
problem as one connected argument.
|
|
32
|
+
|
|
33
|
+
## Chat display — the runlog digest (MUST output, v2.7)
|
|
28
34
|
|
|
29
35
|
The following is shown DIRECTLY IN THE CHAT, not only on disk.
|
|
30
36
|
|
|
37
|
+
### Readability standard — write for a human reader, never a bullet list
|
|
38
|
+
|
|
39
|
+
Every section is an EXPOSITION, not a summary: state WHY the step is taken,
|
|
40
|
+
HOW the reasoning runs (derivation, mechanism, first-principles chain), WHAT
|
|
41
|
+
came out (numbers with units), and HOW it is checked. A reader who knows
|
|
42
|
+
nothing about the problem must be able to follow each section without
|
|
43
|
+
guessing.
|
|
44
|
+
|
|
45
|
+
Style: step-by-step numbered exposition with plain direct language (this is
|
|
46
|
+
a working document, not a final paper — no paper-style formal phrasing
|
|
47
|
+
required), but with MORE detail than a paper would carry: every parameter
|
|
48
|
+
choice gets its reason, every formula is followed by a plain-language
|
|
49
|
+
explanation of each symbol, every step ends with a transition line
|
|
50
|
+
("这一步保证了…,为下一步…做好准备"), and every conclusion states what it
|
|
51
|
+
would take to be wrong. Minimum expectations per section:
|
|
52
|
+
|
|
53
|
+
- 问题重述:restate the question in your own words, explaining every
|
|
54
|
+
parameter's meaning and where it comes from in the problem text.
|
|
55
|
+
- 问题分析:walk the physical/geometric mechanism step by step (e.g. why the
|
|
56
|
+
nodes move radially, how the focal geometry pins the paraboloid), each
|
|
57
|
+
step justified by problem text, data, or derivation.
|
|
58
|
+
- 模型假设:for EVERY assumption give the reason it is justified
|
|
59
|
+
(original wording / data statistic / derivation / literature) and what
|
|
60
|
+
happens if it fails.
|
|
61
|
+
- 模型建立与求解:write the derivation in full (equations, variable
|
|
62
|
+
definitions, units, how the equation is solved, numerical method and why
|
|
63
|
+
it was chosen), not just the final formula.
|
|
64
|
+
- 验证:explain the verification LOGIC for each obligation (what would
|
|
65
|
+
falsify it, what tolerance is used and why), then the outcome.
|
|
66
|
+
- 鲁棒性:for each perturbation say what was varied, why that parameter,
|
|
67
|
+
and what would count as a conclusion flip.
|
|
68
|
+
- 评价与改进 / 参考文献:state the comparison criterion and map each
|
|
69
|
+
reference to the exact method it supports.
|
|
70
|
+
|
|
31
71
|
### Intake digest (once, at intake completion) — the six-section deep restatement
|
|
32
72
|
|
|
33
|
-
【题目要点摘录】problem's own numbers and constraints, quoted
|
|
34
|
-
【背景解读】engineering/physical mechanism
|
|
35
|
-
【数据语义】every attachment column by column (meaning/units/coordinate system/magnitudes)
|
|
36
|
-
【隐含信息与歧义清单】numbered; each = LLM reading + basis + risk (the user corrects entries here)
|
|
37
|
-
|
|
73
|
+
【题目要点摘录】the problem's own numbers and constraints, quoted, each explained
|
|
74
|
+
【背景解读】engineering/physical mechanism, walked through
|
|
75
|
+
【数据语义】every attachment column by column (meaning/units/coordinate system/magnitudes), with observed statistics
|
|
76
|
+
【隐含信息与歧义清单】numbered; each = LLM reading + derivation/basis + risk (the user corrects entries here)
|
|
77
|
+
【各子问题数学本质判定】every sub-question (any count) classified + why
|
|
38
78
|
【待澄清问题】open questions inviting user background/corrections/references
|
|
39
79
|
|
|
40
80
|
After the D0 exchange, show the delta applied to problem-brief.md.
|
|
41
81
|
|
|
82
|
+
### Quality self-check (MUST run before every D4 verdict)
|
|
83
|
+
|
|
84
|
+
Before presenting a D4 verdict, run the self-check on the current attempt's
|
|
85
|
+
report and show the result in the chat: for each of the eight digest sections,
|
|
86
|
+
confirm whether it answers all four questions — WHY (why this step), HOW
|
|
87
|
+
(how the reasoning runs), WHAT (result with units), CHECK (how it is
|
|
88
|
+
verified, or what would falsify it). Any section failing one of the four is
|
|
89
|
+
flagged as incomplete and the round is NOT presented for verdict until fixed.
|
|
90
|
+
The self-check is a human-facing declaration: the user decides whether the
|
|
91
|
+
exposition is actually sufficient. This is the quality gate; the machine
|
|
92
|
+
gates above only guarantee existence and structure.
|
|
93
|
+
|
|
42
94
|
### Per-round digest (after EVERY attempt round)
|
|
43
95
|
|
|
44
96
|
```text
|
|
@@ -13,6 +13,12 @@ TRIAGE → SCOPE_FROZEN → INPUT_PROFILED → CLAIMS_REGISTERED → CANDIDATES_
|
|
|
13
13
|
VERIFY may move to REVISE, RESEARCH, FORK, an independent audit, or one terminal status:
|
|
14
14
|
SOLVED, PARTIAL, CONDITIONAL, INCONCLUSIVE, REFUTED, INFEASIBLE, UNIDENTIFIABLE, BLOCKED, CANCELLED.
|
|
15
15
|
|
|
16
|
+
## Three-layer flow (v0.3)
|
|
17
|
+
|
|
18
|
+
- **全景层**(一次建立,贯穿全题):TRIAGE(读题+D1) → RESEARCH(文献+D-R,前置) → SCOPE_FROZEN(D0 七段重述,含问间依赖) → INPUT_PROFILED(全景分析+数据画像) → CLAIMS_REGISTERED(全局假设 G,D2-G) → CANDIDATES_READY(方法矩阵+D3)。
|
|
19
|
+
- **逐问层**(SPi 循环):子问题分析 → 子问题假设 Si(D2-SPi)→ ATTEMPT 建模求解 → VERIFY 该问验证 → 该问鲁棒性(扰动计划→交互→执行)→ D4 裁决 → REVISE(本问修订)或进入 SPi+1(reason: "SPi 完成,进入 SPi+1")。
|
|
20
|
+
- **收束层**:跨问联动检查(终态 gate 校验全部子问题 DONE + 依赖满足)→ 全题鲁棒性汇总 → 终态硬门 → SOLVED + final-report(整体叙事,非拼凑)。
|
|
21
|
+
|
|
16
22
|
## Pre-modeling literature research (v2.6, mandatory)
|
|
17
23
|
|
|
18
24
|
CLAIMS_REGISTERED → RESEARCH → CANDIDATES_READY. Before any candidate is
|
|
@@ -37,6 +43,22 @@ scope.robustnessExempt is set with a reason.
|
|
|
37
43
|
|
|
38
44
|
- REVISE/RESEARCH reasons MUST reference a decisionStack entry id; the round
|
|
39
45
|
returns to that decision point and tries the next option.
|
|
46
|
+
- Backtracking depth is chosen by the failure root cause (recorded in
|
|
47
|
+
failed/issues.md):
|
|
48
|
+
|
|
49
|
+
| Root cause | Depth | Action |
|
|
50
|
+
|---|---|---|
|
|
51
|
+
| IMPLEMENTATION / TOOL | attempt | fix and rerun, no backtrack |
|
|
52
|
+
| VALIDATION | verify | add obligations, re-verify |
|
|
53
|
+
| MODEL (wrong direction) | direction | switch candidate (wall memo) |
|
|
54
|
+
| assumption falsified | assumption | revise assumption (revisionHistory) → dependent claims stale → re-verify |
|
|
55
|
+
| analysis gap | analysis | update analysisLog → re-derive downstream |
|
|
56
|
+
| restatement misunderstanding | restatement | revise problem-brief (re-freeze) |
|
|
57
|
+
| RESEARCH_GAP | research | add sources, switch method |
|
|
58
|
+
|
|
59
|
+
Backtracking to assumption/analysis/restatement depth is a CONTENT revision
|
|
60
|
+
plus downstream re-verification — the state machine does not rewind; the
|
|
61
|
+
loop is expressed as REVISE cycles and event records.
|
|
40
62
|
- FORK records its fork point; each failed branch writes a wall memo
|
|
41
63
|
(run-directory.md) before the next branch starts. A wrong direction always
|
|
42
64
|
returns to the fork point, never mid-branch.
|
|
@@ -18,7 +18,8 @@ const FINAL_STATES = ['SOLVED', 'PARTIAL', 'CONDITIONAL', 'INCONCLUSIVE', 'REFUT
|
|
|
18
18
|
const STATUSES = [...NON_FINAL_STATES, ...FINAL_STATES]
|
|
19
19
|
const STOP_TRANSITIONS = ['BLOCKED', 'CANCELLED']
|
|
20
20
|
const TRANSITIONS = Object.freeze({
|
|
21
|
-
TRIAGE: ['SCOPE_FROZEN', ...STOP_TRANSITIONS],
|
|
21
|
+
TRIAGE: ['RESEARCH', 'SCOPE_FROZEN', ...STOP_TRANSITIONS],
|
|
22
|
+
RESEARCH: ['SCOPE_FROZEN', 'CANDIDATES_READY', ...STOP_TRANSITIONS],
|
|
22
23
|
SCOPE_FROZEN: ['INPUT_PROFILED', ...STOP_TRANSITIONS],
|
|
23
24
|
INPUT_PROFILED: ['CLAIMS_REGISTERED', ...STOP_TRANSITIONS],
|
|
24
25
|
CLAIMS_REGISTERED: ['RESEARCH', 'CANDIDATES_READY', ...STOP_TRANSITIONS],
|
|
@@ -27,7 +28,6 @@ const TRANSITIONS = Object.freeze({
|
|
|
27
28
|
EXECUTE: ['VERIFY', ...STOP_TRANSITIONS],
|
|
28
29
|
VERIFY: ['REVISE', 'RESEARCH', 'FORK', ...FINAL_STATES],
|
|
29
30
|
REVISE: ['ATTEMPT', ...STOP_TRANSITIONS],
|
|
30
|
-
RESEARCH: ['CANDIDATES_READY', ...STOP_TRANSITIONS],
|
|
31
31
|
FORK: ['ATTEMPT', ...STOP_TRANSITIONS],
|
|
32
32
|
})
|
|
33
33
|
const TASK_ID = /^[a-z0-9]+(?:-[a-z0-9]+)*$/
|
|
@@ -440,13 +440,19 @@ function interactionContractViolations(run, ledger, to, reason, subproblem) {
|
|
|
440
440
|
const violations = []
|
|
441
441
|
const transitional = to !== undefined
|
|
442
442
|
const earlyStop = ['BLOCKED', 'CANCELLED'].includes(run.status)
|
|
443
|
-
|
|
443
|
+
const statusOrder = ['TRIAGE', 'RESEARCH', 'SCOPE_FROZEN', 'INPUT_PROFILED', 'CLAIMS_REGISTERED', 'CANDIDATES_READY', 'ATTEMPT', 'EXECUTE', 'VERIFY', 'REVISE', 'FORK']
|
|
444
|
+
const reached = (target) => transitional
|
|
445
|
+
? to === target
|
|
446
|
+
: (statusOrder.indexOf(target) <= statusOrder.indexOf(run.status) && !earlyStop)
|
|
447
|
+
if (reached('SCOPE_FROZEN')) {
|
|
444
448
|
if (!hasDecisionRecord(scope, 'D0')) violations.push('D0 restatement interaction record missing (ledger.scope.interactions)')
|
|
445
449
|
if (!hasDecisionRecord(scope, 'D1')) violations.push('D1 routing interaction record missing (ledger.scope.interactions)')
|
|
450
|
+
if (!hasDecisionRecord(scope, 'D-R', { allowAuto: false })) violations.push('D-R literature-research interaction record missing (literature survey precedes restatement; auto-authorization is not accepted)')
|
|
446
451
|
}
|
|
452
|
+
if (reached('CLAIMS_REGISTERED') && !hasDecisionRecord(scope, 'D2-G')) violations.push('D2-G global-assumptions interaction record missing (global assumptions must be confirmed before claims registration)')
|
|
453
|
+
const candidatesGate = reached('CANDIDATES_READY')
|
|
454
|
+
if (candidatesGate && !hasDecisionRecord(scope, 'D-R', { allowAuto: false })) violations.push('D-R literature-research interaction record missing (backstop check)')
|
|
447
455
|
const afterCandidates = ['CANDIDATES_READY', 'ATTEMPT', 'EXECUTE', 'VERIFY', 'REVISE', 'FORK', ...FINAL_STATES]
|
|
448
|
-
const candidatesGate = transitional ? (to === 'CANDIDATES_READY') : (afterCandidates.includes(run.status) && !earlyStop)
|
|
449
|
-
if (candidatesGate && !hasDecisionRecord(scope, 'D-R', { allowAuto: false })) violations.push('D-R literature-research interaction record missing (pre-modeling literature survey is mandatory; auto-authorization is not accepted)')
|
|
450
456
|
const enteringAttemptFromCandidates = transitional ? (to === 'ATTEMPT' && run.status === 'CANDIDATES_READY') : (run.currentAttempt >= 1)
|
|
451
457
|
if (enteringAttemptFromCandidates) {
|
|
452
458
|
if (transitional && !subproblem) violations.push('ATTEMPT from CANDIDATES_READY requires --subproblem <id>')
|
|
@@ -468,8 +474,19 @@ function interactionContractViolations(run, ledger, to, reason, subproblem) {
|
|
|
468
474
|
: (FINAL_STATES.includes(run.status) && !['BLOCKED', 'CANCELLED'].includes(run.status))
|
|
469
475
|
if (terminalAndExempt) {
|
|
470
476
|
if (scope.robustnessExempt !== true) {
|
|
471
|
-
const
|
|
472
|
-
|
|
477
|
+
const robos = Array.isArray(ledger.obligations) ? ledger.obligations.filter(o => o && o.kind === 'robustness' && o.required !== false) : []
|
|
478
|
+
const allPassed = robos.length > 0 && robos.every(o => o.status === 'PASS')
|
|
479
|
+
if (!allPassed) violations.push(`terminal state requires ALL ${robos.length} required robustness obligations to be PASS (or scope.robustnessExempt: true)`)
|
|
480
|
+
}
|
|
481
|
+
const subs = Array.isArray(ledger.subproblems) ? ledger.subproblems : []
|
|
482
|
+
if (subs.length > 0) {
|
|
483
|
+
const done = (sp) => sp.status === 'DONE' || sp.status === 'CLOSED'
|
|
484
|
+
const unfinished = subs.filter(sp => !done(sp))
|
|
485
|
+
if (unfinished.length > 0) violations.push(`terminal state requires every subproblem DONE (open: ${unfinished.map(sp => sp.id).join(', ')})`)
|
|
486
|
+
const depGaps = subs.filter(sp => done(sp) && Array.isArray(sp.dependencies) && sp.dependencies.some(dep => {
|
|
487
|
+
const d = subs.find(x => x.id === dep); return d === undefined || !done(d)
|
|
488
|
+
}))
|
|
489
|
+
if (depGaps.length > 0) violations.push(`subproblem dependencies incomplete: ${depGaps.map(sp => sp.id).join(', ')}`)
|
|
473
490
|
}
|
|
474
491
|
if (scope.cleanupPassed !== true) violations.push('terminal state requires scope.cleanupPassed: true (run the cleanup checklist in run-directory.md)')
|
|
475
492
|
}
|
|
@@ -574,6 +591,16 @@ async function validateRunUnlocked(root, expectedTaskId) {
|
|
|
574
591
|
warnings.push(`attempt ${run.currentAttempt} report.md unreadable (runlog digest required)`)
|
|
575
592
|
}
|
|
576
593
|
}
|
|
594
|
+
for (const assumption of Array.isArray(ledger.assumptions) ? ledger.assumptions : []) {
|
|
595
|
+
const revised = assumption && (assumption.status === 'revised' || (Array.isArray(assumption.revisionHistory) && assumption.revisionHistory.length > 0))
|
|
596
|
+
if (!revised) continue
|
|
597
|
+
for (const claim of Array.isArray(ledger.claims) ? ledger.claims : []) {
|
|
598
|
+
const depends = claim && Array.isArray(claim.assumptions) && claim.assumptions.includes(assumption.id)
|
|
599
|
+
if (depends && claim.status === 'VERIFIED' && (!Array.isArray(claim.evidenceIds) || claim.evidenceIds.length === 0)) {
|
|
600
|
+
warnings.push(`claim ${claim.id} depends on revised assumption ${assumption.id} but has no post-revision evidence`)
|
|
601
|
+
}
|
|
602
|
+
}
|
|
603
|
+
}
|
|
577
604
|
}
|
|
578
605
|
return { valid: diagnostics.length === 0, diagnostics, warnings, run: clone(run) }
|
|
579
606
|
}
|