superlab 0.1.70 → 0.1.72
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/lib/i18n.cjs +178 -6
- package/lib/install.cjs +1 -0
- package/lib/lab_idea_contract.json +4 -4
- package/lib/lab_write_contract.json +1 -1
- package/package-assets/claude/commands/lab/idea.md +1 -1
- package/package-assets/claude/commands/lab/report.md +1 -0
- package/package-assets/claude/commands/lab/write.md +1 -0
- package/package-assets/claude/commands/lab-idea.md +1 -1
- package/package-assets/claude/commands/lab-report.md +1 -0
- package/package-assets/claude/commands/lab-write.md +1 -0
- package/package-assets/claude/commands/lab:idea.md +1 -1
- package/package-assets/claude/commands/lab:report.md +1 -0
- package/package-assets/claude/commands/lab:write.md +1 -0
- package/package-assets/claude/commands/lab/357/274/232idea.md +1 -1
- package/package-assets/claude/commands/lab/357/274/232report.md +1 -0
- package/package-assets/claude/commands/lab/357/274/232write.md +1 -0
- package/package-assets/codex/prompts/lab/idea.md +1 -1
- package/package-assets/codex/prompts/lab/report.md +1 -0
- package/package-assets/codex/prompts/lab/write.md +1 -1
- package/package-assets/codex/prompts/lab-idea.md +1 -1
- package/package-assets/codex/prompts/lab-report.md +1 -0
- package/package-assets/codex/prompts/lab-write.md +1 -1
- package/package-assets/codex/prompts/lab:idea.md +1 -1
- package/package-assets/codex/prompts/lab:report.md +1 -0
- package/package-assets/codex/prompts/lab:write.md +1 -1
- package/package-assets/codex/prompts/lab/357/274/232idea.md +1 -1
- package/package-assets/codex/prompts/lab/357/274/232report.md +1 -0
- package/package-assets/codex/prompts/lab/357/274/232write.md +1 -1
- package/package-assets/shared/lab/.managed/scripts/validate_collaborator_report.py +55 -1
- package/package-assets/shared/lab/.managed/scripts/validate_idea_artifact.py +75 -0
- package/package-assets/shared/lab/.managed/scripts/validate_section_draft.py +119 -0
- package/package-assets/shared/lab/.managed/scripts/validate_stage_report.py +547 -0
- package/package-assets/shared/lab/.managed/templates/final-report.md +11 -0
- package/package-assets/shared/lab/.managed/templates/idea.md +18 -0
- package/package-assets/shared/lab/.managed/templates/main-tables.md +6 -0
- package/package-assets/shared/lab/.managed/templates/paper-plan.md +9 -0
- package/package-assets/shared/lab/.managed/templates/stage-report.md +71 -0
- package/package-assets/shared/lab/.managed/templates/write-iteration.md +13 -0
- package/package-assets/shared/skills/lab/SKILL.md +23 -0
- package/package-assets/shared/skills/lab/references/paper-writing/abstract.md +14 -0
- package/package-assets/shared/skills/lab/references/paper-writing/conclusion.md +13 -0
- package/package-assets/shared/skills/lab/references/paper-writing/experiments.md +19 -0
- package/package-assets/shared/skills/lab/references/paper-writing/introduction.md +17 -2
- package/package-assets/shared/skills/lab/references/paper-writing/method.md +10 -0
- package/package-assets/shared/skills/lab/references/paper-writing/section-style-policies.md +10 -1
- package/package-assets/shared/skills/lab/stages/auto.md +26 -0
- package/package-assets/shared/skills/lab/stages/data.md +9 -0
- package/package-assets/shared/skills/lab/stages/framing.md +9 -0
- package/package-assets/shared/skills/lab/stages/idea.md +33 -13
- package/package-assets/shared/skills/lab/stages/iterate.md +9 -0
- package/package-assets/shared/skills/lab/stages/report.md +17 -0
- package/package-assets/shared/skills/lab/stages/review.md +9 -0
- package/package-assets/shared/skills/lab/stages/run.md +9 -0
- package/package-assets/shared/skills/lab/stages/spec.md +9 -0
- package/package-assets/shared/skills/lab/stages/write.md +18 -0
- package/package.json +1 -1
|
@@ -0,0 +1,547 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
import argparse
|
|
3
|
+
import re
|
|
4
|
+
import sys
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
REQUIRED_SECTIONS = {
|
|
9
|
+
"Rule Preflight": [r"^##\s+Rule Preflight\s*$", r"^##\s+规则预检\s*$"],
|
|
10
|
+
"Stage Identity": [r"^##\s+Stage Identity\s*$", r"^##\s+阶段身份\s*$"],
|
|
11
|
+
"Requested Outcome Mapping": [r"^##\s+Requested Outcome Mapping\s*$", r"^##\s+请求结果映射\s*$"],
|
|
12
|
+
"Core Explanation Table": [r"^##\s+Core Explanation Table\s*$", r"^##\s+核心说明表\s*$"],
|
|
13
|
+
"Evidence And Artifacts": [r"^##\s+Evidence And Artifacts\s*$", r"^##\s+证据与工件\s*$"],
|
|
14
|
+
"Next Action": [r"^##\s+Next Action\s*$", r"^##\s+下一步动作\s*$"],
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
REPAIR_CONTROL_SECTION = [r"^##\s+Repair Control\s*$", r"^##\s+修复控制\s*$"]
|
|
18
|
+
|
|
19
|
+
REQUIRED_CORE_ROWS = {
|
|
20
|
+
"stage": ("这是什么阶段", "what stage is this", "stage"),
|
|
21
|
+
"background": ("背景是什么", "background"),
|
|
22
|
+
"why_now": ("为什么现在要做", "why now", "why this stage ran"),
|
|
23
|
+
"what_done": ("这轮具体做了什么", "what this stage did", "what did this stage do"),
|
|
24
|
+
"how_done": ("怎么做的", "how it was done", "how was it done"),
|
|
25
|
+
"worked": ("结果好的地方是什么", "what worked"),
|
|
26
|
+
"did_not_work": ("结果坏的地方是什么", "what did not work", "negative result"),
|
|
27
|
+
"verifies": ("这验证了什么", "what this verifies", "what was verified"),
|
|
28
|
+
"unverified": ("还没有验证什么", "what remains unverified", "not yet verified"),
|
|
29
|
+
"improve_why": ("是否需要改进", "need improvement", "what needs improvement"),
|
|
30
|
+
"how_improve": ("下一步怎么改", "how to improve"),
|
|
31
|
+
"evidence": ("关键证据在哪里", "key evidence", "evidence"),
|
|
32
|
+
"decision": ("现在应该继续", "continue, stop", "decision"),
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
PLACEHOLDER_VALUES = {
|
|
36
|
+
"",
|
|
37
|
+
"-",
|
|
38
|
+
"--",
|
|
39
|
+
"—",
|
|
40
|
+
"todo",
|
|
41
|
+
"tbd",
|
|
42
|
+
"n/a",
|
|
43
|
+
"na",
|
|
44
|
+
"none",
|
|
45
|
+
"待补",
|
|
46
|
+
"待定",
|
|
47
|
+
"无",
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
SHALLOW_VALUES = {
|
|
51
|
+
"done",
|
|
52
|
+
"ok",
|
|
53
|
+
"pass",
|
|
54
|
+
"passed",
|
|
55
|
+
"符合预期",
|
|
56
|
+
"已完成",
|
|
57
|
+
"继续优化",
|
|
58
|
+
"继续推进",
|
|
59
|
+
"没有问题",
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
INTERNAL_META_PATTERNS = [
|
|
63
|
+
r"用户说",
|
|
64
|
+
r"我来解释",
|
|
65
|
+
r"我会",
|
|
66
|
+
r"我已经",
|
|
67
|
+
r"你要求",
|
|
68
|
+
r"\bagent\b",
|
|
69
|
+
r"\bsubagent\b",
|
|
70
|
+
r"\bprompt\b",
|
|
71
|
+
r"提示词",
|
|
72
|
+
r"按.*技能",
|
|
73
|
+
r"service-style",
|
|
74
|
+
r"AI-assistant",
|
|
75
|
+
]
|
|
76
|
+
|
|
77
|
+
WHY_MARKERS = (
|
|
78
|
+
"because",
|
|
79
|
+
"so that",
|
|
80
|
+
"therefore",
|
|
81
|
+
"reason",
|
|
82
|
+
"why",
|
|
83
|
+
"因为",
|
|
84
|
+
"所以",
|
|
85
|
+
"因此",
|
|
86
|
+
"原因",
|
|
87
|
+
"以便",
|
|
88
|
+
"用于",
|
|
89
|
+
"避免",
|
|
90
|
+
)
|
|
91
|
+
|
|
92
|
+
IMPROVEMENT_NEEDED_MARKERS = (
|
|
93
|
+
"need improvement",
|
|
94
|
+
"needs improvement",
|
|
95
|
+
"needs revision",
|
|
96
|
+
"must improve",
|
|
97
|
+
"should improve",
|
|
98
|
+
"needs repair",
|
|
99
|
+
"needs rerun",
|
|
100
|
+
"需要改进",
|
|
101
|
+
"需要修复",
|
|
102
|
+
"需要重跑",
|
|
103
|
+
"需要继续",
|
|
104
|
+
"仍需",
|
|
105
|
+
)
|
|
106
|
+
|
|
107
|
+
NO_IMPROVEMENT_MARKERS = (
|
|
108
|
+
"no improvement needed",
|
|
109
|
+
"does not need improvement",
|
|
110
|
+
"not need improvement",
|
|
111
|
+
"无需改进",
|
|
112
|
+
"不需要改进",
|
|
113
|
+
"不需改进",
|
|
114
|
+
)
|
|
115
|
+
|
|
116
|
+
STOP_DECISION_MARKERS = (
|
|
117
|
+
"decision: stop",
|
|
118
|
+
"decision:stop",
|
|
119
|
+
"decision: 停止",
|
|
120
|
+
"decision:停止",
|
|
121
|
+
"决策: stop",
|
|
122
|
+
"决策:stop",
|
|
123
|
+
"决策: 停止",
|
|
124
|
+
"决策:停止",
|
|
125
|
+
)
|
|
126
|
+
|
|
127
|
+
TERMINAL_BOUNDARY_MARKERS = (
|
|
128
|
+
"budget exhausted",
|
|
129
|
+
"budget boundary",
|
|
130
|
+
"exceeded budget",
|
|
131
|
+
"fatal",
|
|
132
|
+
"safety",
|
|
133
|
+
"invalid artifact",
|
|
134
|
+
"invalid metric",
|
|
135
|
+
"frozen core",
|
|
136
|
+
"outside the envelope",
|
|
137
|
+
"outside approved envelope",
|
|
138
|
+
"user requested stop",
|
|
139
|
+
"approval required",
|
|
140
|
+
"requires approval",
|
|
141
|
+
"escalation boundary",
|
|
142
|
+
"impossible",
|
|
143
|
+
"not allowed",
|
|
144
|
+
"terminal boundary",
|
|
145
|
+
"integrity",
|
|
146
|
+
"ethics",
|
|
147
|
+
"预算耗尽",
|
|
148
|
+
"预算边界",
|
|
149
|
+
"超过预算",
|
|
150
|
+
"致命",
|
|
151
|
+
"安全",
|
|
152
|
+
"无效工件",
|
|
153
|
+
"无效指标",
|
|
154
|
+
"冻结核心",
|
|
155
|
+
"超出边界",
|
|
156
|
+
"超出已批准",
|
|
157
|
+
"用户要求停止",
|
|
158
|
+
"需要批准",
|
|
159
|
+
"升级边界",
|
|
160
|
+
"不可能",
|
|
161
|
+
"不允许",
|
|
162
|
+
"终止边界",
|
|
163
|
+
"诚信",
|
|
164
|
+
"伦理",
|
|
165
|
+
)
|
|
166
|
+
|
|
167
|
+
REPAIR_CONTROL_FIELDS = (
|
|
168
|
+
("Repair budget:", "修复预算:"),
|
|
169
|
+
("Repair attempts used:", "已用修复次数:"),
|
|
170
|
+
("Current failure class:", "当前失败类型:"),
|
|
171
|
+
("Repair hypothesis:", "修复假设:"),
|
|
172
|
+
("Evidence-changing knobs changed:", "改变证据解释的旋钮:"),
|
|
173
|
+
("Ordinary engineering fixes allowed:", "允许的普通工程修复:"),
|
|
174
|
+
("Frozen core unchanged:", "冻结核心不变:"),
|
|
175
|
+
("Forbidden repairs avoided:", "已避免的禁用修复:"),
|
|
176
|
+
("Confirmation check:", "确认验证:"),
|
|
177
|
+
)
|
|
178
|
+
|
|
179
|
+
FORBIDDEN_REPAIR_PATTERNS = (
|
|
180
|
+
r"\b(changed|modified|relaxed|lowered|loosened|rewrote)\s+(the\s+)?(primary\s+)?metric\b",
|
|
181
|
+
r"\b(changed|modified|relaxed|lowered|loosened)\s+(the\s+)?(target|threshold|target\s+range)\b",
|
|
182
|
+
r"\b(drop|dropped|delete|deleted|remove|removed|exclude|excluded)\s+(hard|failed|bad)\s+(cases|examples|samples)\b",
|
|
183
|
+
r"\b(changed|modified|rewrote)\s+(labels?|ground\s+truth)\b",
|
|
184
|
+
r"\b(changed|modified|swapped|replaced)\s+(the\s+)?(final\s+)?test\s+split\b",
|
|
185
|
+
r"\b(changed|modified|expanded)\s+(the\s+)?(paper-facing\s+)?claim\b",
|
|
186
|
+
r"\b(changed|modified|switched)\s+(the\s+)?(threat\s+model|reviewer\s+profile|dataset\s+scope)\b",
|
|
187
|
+
r"修改(主)?指标",
|
|
188
|
+
r"放宽(目标|阈值|目标区间)",
|
|
189
|
+
r"(删除|移除|剔除)(困难|失败|坏)(样本|案例)",
|
|
190
|
+
r"修改(标签|真值|测试集|主张|威胁模型|数据集范围)",
|
|
191
|
+
)
|
|
192
|
+
|
|
193
|
+
REPAIR_SUCCESS_MARKERS = (
|
|
194
|
+
"repair passed",
|
|
195
|
+
"repair succeeded",
|
|
196
|
+
"passed after repair",
|
|
197
|
+
"promotion is planned",
|
|
198
|
+
"promote",
|
|
199
|
+
"promotion",
|
|
200
|
+
"修复通过",
|
|
201
|
+
"修复成功",
|
|
202
|
+
"准备推广",
|
|
203
|
+
"推广",
|
|
204
|
+
)
|
|
205
|
+
|
|
206
|
+
NO_CONFIRMATION_MARKERS = (
|
|
207
|
+
"not needed",
|
|
208
|
+
"not required",
|
|
209
|
+
"none",
|
|
210
|
+
"n/a",
|
|
211
|
+
"无需",
|
|
212
|
+
"不需要",
|
|
213
|
+
"无",
|
|
214
|
+
)
|
|
215
|
+
|
|
216
|
+
CONFIRMATION_MARKERS = (
|
|
217
|
+
"confirmation",
|
|
218
|
+
"confirm",
|
|
219
|
+
"holdout",
|
|
220
|
+
"control",
|
|
221
|
+
"new seed",
|
|
222
|
+
"seed",
|
|
223
|
+
"batch",
|
|
224
|
+
"rerun",
|
|
225
|
+
"复验",
|
|
226
|
+
"确认",
|
|
227
|
+
"留出",
|
|
228
|
+
"对照",
|
|
229
|
+
"新 seed",
|
|
230
|
+
"批次",
|
|
231
|
+
"重跑",
|
|
232
|
+
)
|
|
233
|
+
|
|
234
|
+
|
|
235
|
+
def parse_args():
|
|
236
|
+
parser = argparse.ArgumentParser(description="Validate a plain-language lab stage report.")
|
|
237
|
+
parser.add_argument("--stage-report", required=True, help="Path to the stage report markdown file.")
|
|
238
|
+
parser.add_argument("--stage", default="", help="Expected lab stage name, such as run, auto, or write.")
|
|
239
|
+
return parser.parse_args()
|
|
240
|
+
|
|
241
|
+
|
|
242
|
+
def normalize(text: str) -> str:
|
|
243
|
+
return re.sub(r"\s+", " ", text.strip().lower())
|
|
244
|
+
|
|
245
|
+
|
|
246
|
+
def extract_section(text: str, patterns: list[str]) -> str:
|
|
247
|
+
for pattern in patterns:
|
|
248
|
+
match = re.search(pattern, text, flags=re.MULTILINE)
|
|
249
|
+
if not match:
|
|
250
|
+
continue
|
|
251
|
+
start = match.end()
|
|
252
|
+
next_heading = re.search(r"^##\s+", text[start:], flags=re.MULTILINE)
|
|
253
|
+
end = start + next_heading.start() if next_heading else len(text)
|
|
254
|
+
return text[start:end].strip()
|
|
255
|
+
return ""
|
|
256
|
+
|
|
257
|
+
|
|
258
|
+
def find_missing_sections(text: str) -> list[str]:
|
|
259
|
+
missing = []
|
|
260
|
+
for name, patterns in REQUIRED_SECTIONS.items():
|
|
261
|
+
if not any(re.search(pattern, text, flags=re.MULTILINE) for pattern in patterns):
|
|
262
|
+
missing.append(name)
|
|
263
|
+
return missing
|
|
264
|
+
|
|
265
|
+
|
|
266
|
+
def parse_core_table_rows(text: str) -> dict[str, str]:
|
|
267
|
+
section = extract_section(text, REQUIRED_SECTIONS["Core Explanation Table"])
|
|
268
|
+
rows = {}
|
|
269
|
+
for raw_line in section.splitlines():
|
|
270
|
+
line = raw_line.strip()
|
|
271
|
+
if not line.startswith("|") or line.count("|") < 3:
|
|
272
|
+
continue
|
|
273
|
+
cells = [cell.strip() for cell in line.strip("|").split("|")]
|
|
274
|
+
if len(cells) < 2:
|
|
275
|
+
continue
|
|
276
|
+
question = normalize(cells[0])
|
|
277
|
+
answer = cells[1].strip()
|
|
278
|
+
if question in {"question", "---", ""}:
|
|
279
|
+
continue
|
|
280
|
+
rows[question] = answer
|
|
281
|
+
return rows
|
|
282
|
+
|
|
283
|
+
|
|
284
|
+
def find_row_value(rows: dict[str, str], markers: tuple[str, ...]) -> str | None:
|
|
285
|
+
normalized_markers = tuple(normalize(marker) for marker in markers)
|
|
286
|
+
for question, answer in rows.items():
|
|
287
|
+
if any(marker in question for marker in normalized_markers):
|
|
288
|
+
return answer
|
|
289
|
+
return None
|
|
290
|
+
|
|
291
|
+
|
|
292
|
+
def is_blank_or_placeholder(value: str | None) -> bool:
|
|
293
|
+
if value is None:
|
|
294
|
+
return True
|
|
295
|
+
compact = normalize(value).strip(" .:;,。;:")
|
|
296
|
+
return compact in PLACEHOLDER_VALUES
|
|
297
|
+
|
|
298
|
+
|
|
299
|
+
def has_marker_with_value(body: str, markers: tuple[str, ...]) -> bool:
|
|
300
|
+
for line in body.splitlines():
|
|
301
|
+
stripped = line.strip()
|
|
302
|
+
for marker in markers:
|
|
303
|
+
if marker not in stripped:
|
|
304
|
+
continue
|
|
305
|
+
value = stripped.split(marker, 1)[1].strip()
|
|
306
|
+
return not is_blank_or_placeholder(value)
|
|
307
|
+
return False
|
|
308
|
+
|
|
309
|
+
|
|
310
|
+
def marker_value(body: str, markers: tuple[str, ...]) -> str:
|
|
311
|
+
for line in body.splitlines():
|
|
312
|
+
stripped = line.strip()
|
|
313
|
+
for marker in markers:
|
|
314
|
+
if marker not in stripped:
|
|
315
|
+
continue
|
|
316
|
+
return stripped.split(marker, 1)[1].strip()
|
|
317
|
+
return ""
|
|
318
|
+
|
|
319
|
+
|
|
320
|
+
def is_shallow(value: str | None) -> bool:
|
|
321
|
+
if value is None:
|
|
322
|
+
return True
|
|
323
|
+
compact = normalize(value).strip(" .:;,。;:")
|
|
324
|
+
return compact in SHALLOW_VALUES or len(compact) < 8
|
|
325
|
+
|
|
326
|
+
|
|
327
|
+
def has_why(value: str) -> bool:
|
|
328
|
+
lowered = normalize(value)
|
|
329
|
+
return any(marker in lowered for marker in WHY_MARKERS)
|
|
330
|
+
|
|
331
|
+
|
|
332
|
+
def improvement_is_needed(value: str | None) -> bool:
|
|
333
|
+
lowered = normalize(value or "")
|
|
334
|
+
if any(marker in lowered for marker in NO_IMPROVEMENT_MARKERS):
|
|
335
|
+
return False
|
|
336
|
+
return any(marker in lowered for marker in IMPROVEMENT_NEEDED_MARKERS)
|
|
337
|
+
|
|
338
|
+
|
|
339
|
+
def next_action_is_stop(body: str) -> bool:
|
|
340
|
+
lowered = normalize(body)
|
|
341
|
+
if any(marker in lowered for marker in STOP_DECISION_MARKERS):
|
|
342
|
+
return True
|
|
343
|
+
return re.search(r"^\s*-\s*(decision|决策)\s*[::]\s*(stop|停止)\b", body, flags=re.IGNORECASE | re.MULTILINE) is not None
|
|
344
|
+
|
|
345
|
+
|
|
346
|
+
def has_terminal_boundary(value: str) -> bool:
|
|
347
|
+
lowered = normalize(value)
|
|
348
|
+
return any(marker in lowered for marker in TERMINAL_BOUNDARY_MARKERS)
|
|
349
|
+
|
|
350
|
+
|
|
351
|
+
def parse_repair_attempts(value: str) -> int | None:
|
|
352
|
+
match = re.search(r"\d+", value or "")
|
|
353
|
+
if not match:
|
|
354
|
+
return None
|
|
355
|
+
return int(match.group(0))
|
|
356
|
+
|
|
357
|
+
|
|
358
|
+
def validate_core_table(text: str) -> list[str]:
|
|
359
|
+
issues = []
|
|
360
|
+
rows = parse_core_table_rows(text)
|
|
361
|
+
missing_rows = []
|
|
362
|
+
for row_name, markers in REQUIRED_CORE_ROWS.items():
|
|
363
|
+
value = find_row_value(rows, markers)
|
|
364
|
+
if is_blank_or_placeholder(value):
|
|
365
|
+
missing_rows.append(row_name)
|
|
366
|
+
if missing_rows:
|
|
367
|
+
issues.append(f"Core Explanation Table is missing non-empty answers for: {', '.join(missing_rows)}")
|
|
368
|
+
|
|
369
|
+
for row_name in ("did_not_work", "verifies", "improve_why", "how_improve", "decision"):
|
|
370
|
+
value = find_row_value(rows, REQUIRED_CORE_ROWS[row_name])
|
|
371
|
+
if is_shallow(value):
|
|
372
|
+
issues.append(f"Core Explanation Table row '{row_name}' is too shallow")
|
|
373
|
+
|
|
374
|
+
for row_name in ("improve_why", "how_improve"):
|
|
375
|
+
value = find_row_value(rows, REQUIRED_CORE_ROWS[row_name])
|
|
376
|
+
if value and not has_why(value):
|
|
377
|
+
issues.append(f"Core Explanation Table row '{row_name}' must include a reason, not only an action")
|
|
378
|
+
return issues
|
|
379
|
+
|
|
380
|
+
|
|
381
|
+
def validate_evidence_section(text: str) -> list[str]:
|
|
382
|
+
issues = []
|
|
383
|
+
body = extract_section(text, REQUIRED_SECTIONS["Evidence And Artifacts"])
|
|
384
|
+
marker_groups = (
|
|
385
|
+
("Primary artifact:", "主工件:"),
|
|
386
|
+
("Supporting artifacts:", "支撑工件:"),
|
|
387
|
+
("Validation commands:", "验证命令:"),
|
|
388
|
+
("Known gaps:", "已知缺口:"),
|
|
389
|
+
)
|
|
390
|
+
if not body:
|
|
391
|
+
return ["Evidence And Artifacts section is empty"]
|
|
392
|
+
for group in marker_groups:
|
|
393
|
+
if not any(marker in body for marker in group):
|
|
394
|
+
issues.append(f"Evidence And Artifacts is missing '{group[0]}'")
|
|
395
|
+
continue
|
|
396
|
+
if not has_marker_with_value(body, group):
|
|
397
|
+
issues.append(f"Evidence And Artifacts field '{group[0]}' must have a non-empty value")
|
|
398
|
+
return issues
|
|
399
|
+
|
|
400
|
+
|
|
401
|
+
def validate_requested_outcome_mapping(text: str) -> list[str]:
|
|
402
|
+
issues = []
|
|
403
|
+
body = extract_section(text, REQUIRED_SECTIONS["Requested Outcome Mapping"])
|
|
404
|
+
marker_groups = (
|
|
405
|
+
("Original request:", "原始请求:"),
|
|
406
|
+
("Requested deliverables:", "请求交付物:"),
|
|
407
|
+
("Completion mapping:", "完成映射:"),
|
|
408
|
+
("Response shape:", "回答形态:"),
|
|
409
|
+
)
|
|
410
|
+
if not body:
|
|
411
|
+
return ["Requested Outcome Mapping section is empty"]
|
|
412
|
+
for group in marker_groups:
|
|
413
|
+
if not any(marker in body for marker in group):
|
|
414
|
+
issues.append(f"Requested Outcome Mapping is missing '{group[0]}'")
|
|
415
|
+
continue
|
|
416
|
+
if not has_marker_with_value(body, group):
|
|
417
|
+
issues.append(f"Requested Outcome Mapping field '{group[0]}' must have a non-empty value")
|
|
418
|
+
return issues
|
|
419
|
+
|
|
420
|
+
|
|
421
|
+
def validate_repair_control(text: str, expected_stage: str) -> list[str]:
|
|
422
|
+
body = extract_section(text, REPAIR_CONTROL_SECTION)
|
|
423
|
+
is_auto_stage = expected_stage.lower() == "auto"
|
|
424
|
+
if not body:
|
|
425
|
+
if is_auto_stage:
|
|
426
|
+
return ["Repair Control section is required for auto stage reports"]
|
|
427
|
+
return []
|
|
428
|
+
|
|
429
|
+
issues = []
|
|
430
|
+
for group in REPAIR_CONTROL_FIELDS:
|
|
431
|
+
if not any(marker in body for marker in group):
|
|
432
|
+
issues.append(f"Repair Control is missing '{group[0]}'")
|
|
433
|
+
continue
|
|
434
|
+
if not has_marker_with_value(body, group):
|
|
435
|
+
issues.append(f"Repair Control field '{group[0]}' must have a non-empty value")
|
|
436
|
+
|
|
437
|
+
for pattern in FORBIDDEN_REPAIR_PATTERNS:
|
|
438
|
+
if re.search(pattern, body, flags=re.IGNORECASE):
|
|
439
|
+
issues.append(f"Repair Control contains forbidden repair: {pattern}")
|
|
440
|
+
|
|
441
|
+
attempts = parse_repair_attempts(marker_value(body, ("Repair attempts used:", "已用修复次数:")))
|
|
442
|
+
confirmation = marker_value(body, ("Confirmation check:", "确认验证:"))
|
|
443
|
+
whole_text = normalize(text)
|
|
444
|
+
repair_succeeded = any(marker in whole_text for marker in REPAIR_SUCCESS_MARKERS)
|
|
445
|
+
if attempts and attempts > 0 and repair_succeeded:
|
|
446
|
+
normalized_confirmation = normalize(confirmation)
|
|
447
|
+
if (
|
|
448
|
+
any(marker in normalized_confirmation for marker in NO_CONFIRMATION_MARKERS)
|
|
449
|
+
or not any(marker in normalized_confirmation for marker in CONFIRMATION_MARKERS)
|
|
450
|
+
):
|
|
451
|
+
issues.append(
|
|
452
|
+
"Repair Control requires a confirmation check after a successful repair before promotion or final success"
|
|
453
|
+
)
|
|
454
|
+
|
|
455
|
+
return issues
|
|
456
|
+
|
|
457
|
+
|
|
458
|
+
def validate_rule_preflight(text: str) -> list[str]:
|
|
459
|
+
body = extract_section(text, REQUIRED_SECTIONS["Rule Preflight"])
|
|
460
|
+
marker_groups = (
|
|
461
|
+
("Rule source file:",),
|
|
462
|
+
("Rule source revision:",),
|
|
463
|
+
("Project version:",),
|
|
464
|
+
("Resolved stage:",),
|
|
465
|
+
("Resolved mode:",),
|
|
466
|
+
("Resolved target:",),
|
|
467
|
+
("Preflight stamp:",),
|
|
468
|
+
)
|
|
469
|
+
issues = []
|
|
470
|
+
for group in marker_groups:
|
|
471
|
+
marker = group[0]
|
|
472
|
+
if marker not in body:
|
|
473
|
+
issues.append(f"Rule Preflight is missing '{marker}'")
|
|
474
|
+
continue
|
|
475
|
+
if not has_marker_with_value(body, group):
|
|
476
|
+
issues.append(f"Rule Preflight field '{marker}' must have a non-empty value")
|
|
477
|
+
return issues
|
|
478
|
+
|
|
479
|
+
|
|
480
|
+
def validate_next_action(text: str) -> list[str]:
|
|
481
|
+
body = extract_section(text, REQUIRED_SECTIONS["Next Action"])
|
|
482
|
+
if is_shallow(body):
|
|
483
|
+
return ["Next Action section must state a concrete decision and next step"]
|
|
484
|
+
allowed = ("continue", "stop", "revise", "rerun", "escalate", "handoff", "继续", "停止", "修订", "重跑", "升级", "交接")
|
|
485
|
+
if not any(marker in normalize(body) for marker in allowed):
|
|
486
|
+
return ["Next Action must choose continue, stop, revise, rerun, escalate, or handoff"]
|
|
487
|
+
if not has_why(body):
|
|
488
|
+
return ["Next Action must include why the next step is appropriate"]
|
|
489
|
+
rows = parse_core_table_rows(text)
|
|
490
|
+
improve_value = find_row_value(rows, REQUIRED_CORE_ROWS["improve_why"]) or ""
|
|
491
|
+
if improvement_is_needed(improve_value) and next_action_is_stop(body) and not has_terminal_boundary(body):
|
|
492
|
+
return [
|
|
493
|
+
"Next Action cannot stop after a recoverable improvement need without an explicit terminal boundary; choose continue, revise, rerun, or escalate, or state the budget/frozen-core/safety boundary"
|
|
494
|
+
]
|
|
495
|
+
return []
|
|
496
|
+
|
|
497
|
+
|
|
498
|
+
def validate_stage_identity(text: str, expected_stage: str) -> list[str]:
|
|
499
|
+
if not expected_stage:
|
|
500
|
+
return []
|
|
501
|
+
body = extract_section(text, REQUIRED_SECTIONS["Stage Identity"])
|
|
502
|
+
if expected_stage.lower() not in body.lower():
|
|
503
|
+
return [f"Stage Identity must mention expected stage '{expected_stage}'"]
|
|
504
|
+
return []
|
|
505
|
+
|
|
506
|
+
|
|
507
|
+
def validate_internal_meta(text: str) -> list[str]:
|
|
508
|
+
issues = []
|
|
509
|
+
for pattern in INTERNAL_META_PATTERNS:
|
|
510
|
+
if re.search(pattern, text, flags=re.IGNORECASE):
|
|
511
|
+
issues.append(f"stage report contains internal or service-style meta language: {pattern}")
|
|
512
|
+
return issues
|
|
513
|
+
|
|
514
|
+
|
|
515
|
+
def validate(path: Path, expected_stage: str = "") -> list[str]:
|
|
516
|
+
if not path.exists():
|
|
517
|
+
return [f"stage report does not exist: {path}"]
|
|
518
|
+
text = path.read_text(encoding="utf-8")
|
|
519
|
+
issues = []
|
|
520
|
+
missing_sections = find_missing_sections(text)
|
|
521
|
+
if missing_sections:
|
|
522
|
+
issues.append(f"stage report is missing required sections: {', '.join(missing_sections)}")
|
|
523
|
+
if not missing_sections:
|
|
524
|
+
issues.extend(validate_rule_preflight(text))
|
|
525
|
+
issues.extend(validate_stage_identity(text, expected_stage))
|
|
526
|
+
issues.extend(validate_requested_outcome_mapping(text))
|
|
527
|
+
issues.extend(validate_repair_control(text, expected_stage))
|
|
528
|
+
issues.extend(validate_core_table(text))
|
|
529
|
+
issues.extend(validate_evidence_section(text))
|
|
530
|
+
issues.extend(validate_next_action(text))
|
|
531
|
+
issues.extend(validate_internal_meta(text))
|
|
532
|
+
return issues
|
|
533
|
+
|
|
534
|
+
|
|
535
|
+
def main():
|
|
536
|
+
args = parse_args()
|
|
537
|
+
issues = validate(Path(args.stage_report), args.stage)
|
|
538
|
+
if issues:
|
|
539
|
+
for issue in issues:
|
|
540
|
+
print(issue, file=sys.stderr)
|
|
541
|
+
return 1
|
|
542
|
+
print("stage report is valid")
|
|
543
|
+
return 0
|
|
544
|
+
|
|
545
|
+
|
|
546
|
+
if __name__ == "__main__":
|
|
547
|
+
raise SystemExit(main())
|
|
@@ -9,6 +9,9 @@
|
|
|
9
9
|
## Reader Summary
|
|
10
10
|
|
|
11
11
|
- One-sentence conclusion:
|
|
12
|
+
- Core insight:
|
|
13
|
+
- Evidence that supports the insight:
|
|
14
|
+
- Decision or action implication:
|
|
12
15
|
- What is validated:
|
|
13
16
|
- What is still unproven:
|
|
14
17
|
- Biggest reporting risk:
|
|
@@ -35,6 +38,8 @@
|
|
|
35
38
|
|
|
36
39
|
- Approved method name:
|
|
37
40
|
- Plain-language method summary:
|
|
41
|
+
- Mechanism tested or explained:
|
|
42
|
+
- Why the design follows from the insight:
|
|
38
43
|
- What this method changes relative to prior work:
|
|
39
44
|
- Most relevant prior work or baseline anchors:
|
|
40
45
|
- What those prior methods do:
|
|
@@ -115,10 +120,16 @@
|
|
|
115
120
|
|
|
116
121
|
Summarize validated iteration outcomes.
|
|
117
122
|
|
|
123
|
+
- Diagnostic interpretation:
|
|
124
|
+
- What this teaches beyond the raw numbers:
|
|
125
|
+
|
|
118
126
|
## Ablations
|
|
119
127
|
|
|
120
128
|
Describe meaningful ablations and what they showed.
|
|
121
129
|
|
|
130
|
+
- Mechanism tested:
|
|
131
|
+
- What the ablation teaches beyond the delta:
|
|
132
|
+
|
|
122
133
|
## Failures
|
|
123
134
|
|
|
124
135
|
Preserve failed runs and rejected ideas.
|
|
@@ -159,6 +159,24 @@ Suggested levels:
|
|
|
159
159
|
- Expected advantage:
|
|
160
160
|
- Evidence needed to prove the advantage:
|
|
161
161
|
|
|
162
|
+
## Contribution vs Insight
|
|
163
|
+
|
|
164
|
+
- Contribution:
|
|
165
|
+
- Insight:
|
|
166
|
+
- Core insight anchor sentence:
|
|
167
|
+
- Why the insight matters beyond the artifact:
|
|
168
|
+
- Action or community value:
|
|
169
|
+
|
|
170
|
+
## Insight Evidence Chain
|
|
171
|
+
|
|
172
|
+
- Observation:
|
|
173
|
+
- Why existing explanations fail:
|
|
174
|
+
- Core insight:
|
|
175
|
+
- Mechanism:
|
|
176
|
+
- Validation tests:
|
|
177
|
+
- Generalization or action implication:
|
|
178
|
+
- Prediction:
|
|
179
|
+
|
|
162
180
|
## Rough Approach
|
|
163
181
|
|
|
164
182
|
- Plain-language description of how this would work:
|
|
@@ -36,27 +36,33 @@
|
|
|
36
36
|
- Table 2 is for:
|
|
37
37
|
- Table 3 is for:
|
|
38
38
|
- Table 4 is for:
|
|
39
|
+
- Diagnostic takeaway:
|
|
40
|
+
- What the tables do not prove:
|
|
39
41
|
|
|
40
42
|
## Table 1
|
|
41
43
|
|
|
42
44
|
- Purpose:
|
|
43
45
|
- Metrics used:
|
|
44
46
|
- Strongest supported claim:
|
|
47
|
+
- Mechanism or insight tested:
|
|
45
48
|
|
|
46
49
|
## Table 2
|
|
47
50
|
|
|
48
51
|
- Purpose:
|
|
49
52
|
- Metrics used:
|
|
50
53
|
- Strongest supported claim:
|
|
54
|
+
- Mechanism or insight tested:
|
|
51
55
|
|
|
52
56
|
## Table 3
|
|
53
57
|
|
|
54
58
|
- Purpose:
|
|
55
59
|
- Metrics used:
|
|
56
60
|
- Strongest supported claim:
|
|
61
|
+
- Mechanism or insight tested:
|
|
57
62
|
|
|
58
63
|
## Table 4
|
|
59
64
|
|
|
60
65
|
- Purpose:
|
|
61
66
|
- Metrics used:
|
|
62
67
|
- Strongest supported claim:
|
|
68
|
+
- Mechanism or insight tested:
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
- Venue or audience:
|
|
6
6
|
- Paper status:
|
|
7
7
|
- Core story in one sentence:
|
|
8
|
+
- Core insight anchor:
|
|
8
9
|
- Approved framing artifact:
|
|
9
10
|
- Terminology lock:
|
|
10
11
|
|
|
@@ -24,6 +25,14 @@
|
|
|
24
25
|
- Limitation sources:
|
|
25
26
|
- Claims that still need more evidence:
|
|
26
27
|
|
|
28
|
+
## Insight Integration Map
|
|
29
|
+
|
|
30
|
+
- Introduction contrast:
|
|
31
|
+
- Method design consequence:
|
|
32
|
+
- Experiments diagnostic evidence:
|
|
33
|
+
- Conclusion principle or action implication:
|
|
34
|
+
- Alternative explanation to address:
|
|
35
|
+
|
|
27
36
|
## Asset Coverage Targets
|
|
28
37
|
|
|
29
38
|
- Core asset floor:
|