superlab 0.1.61 → 0.1.62
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/auto_runner.cjs +11 -1
- package/lib/auto_state.cjs +27 -0
- package/lib/i18n.cjs +77 -0
- package/lib/install.cjs +44 -0
- package/lib/rule_preflight.cjs +52 -0
- package/package-assets/shared/lab/.managed/scripts/validate_manuscript_delivery.py +19 -0
- package/package-assets/shared/lab/.managed/scripts/validate_section_draft.py +21 -0
- package/package-assets/shared/lab/.managed/templates/iteration-report.md +10 -0
- package/package-assets/shared/lab/.managed/templates/write-iteration.md +10 -0
- package/package-assets/shared/lab/context/auto-status.md +10 -0
- package/package-assets/shared/skills/lab/SKILL.md +11 -0
- package/package-assets/shared/skills/lab/stages/auto.md +8 -0
- package/package-assets/shared/skills/lab/stages/write.md +8 -0
- package/package.json +1 -1
package/lib/auto_runner.cjs
CHANGED
|
@@ -40,6 +40,7 @@ const {
|
|
|
40
40
|
writeAutoOutcome,
|
|
41
41
|
writeAutoStatus,
|
|
42
42
|
} = require("./auto_state.cjs");
|
|
43
|
+
const { buildRulePreflight } = require("./rule_preflight.cjs");
|
|
43
44
|
|
|
44
45
|
function normalizeTransition(value) {
|
|
45
46
|
return (value || "").trim();
|
|
@@ -220,7 +221,7 @@ function buildRolledOverAutoMode(mode, requested, now) {
|
|
|
220
221
|
};
|
|
221
222
|
}
|
|
222
223
|
|
|
223
|
-
function rolloverAutoCampaign({ targetDir, mode, status, ledger, requested, lang, now }) {
|
|
224
|
+
function rolloverAutoCampaign({ targetDir, mode, status, ledger, requested, lang, now, rulePreflight = null }) {
|
|
224
225
|
const newMode = buildRolledOverAutoMode(mode, requested, now);
|
|
225
226
|
const archivedPaths = [
|
|
226
227
|
archiveAutoArtifact(targetDir, path.join(".lab", "context", "auto-mode.md"), mode.campaignId || "auto-campaign", now),
|
|
@@ -250,6 +251,7 @@ function rolloverAutoCampaign({ targetDir, mode, status, ledger, requested, lang
|
|
|
250
251
|
writeAutoStatus(
|
|
251
252
|
targetDir,
|
|
252
253
|
{
|
|
254
|
+
...(rulePreflight || {}),
|
|
253
255
|
status: "idle",
|
|
254
256
|
currentStage: "",
|
|
255
257
|
currentCommand: "",
|
|
@@ -488,6 +490,12 @@ async function startAutoMode({ targetDir, now = new Date(), requestedContract =
|
|
|
488
490
|
const mode = parseAutoMode(targetDir);
|
|
489
491
|
const existingStatus = parseAutoStatus(targetDir);
|
|
490
492
|
const existingLedger = parseAutoLedger(targetDir);
|
|
493
|
+
const autoRulePreflight = buildRulePreflight({
|
|
494
|
+
targetDir,
|
|
495
|
+
stage: "auto",
|
|
496
|
+
mode: "execution",
|
|
497
|
+
target: "bounded auto campaign runtime",
|
|
498
|
+
});
|
|
491
499
|
const evalProtocol = parseEvalProtocol(targetDir);
|
|
492
500
|
const lang = readWorkflowLanguage(targetDir);
|
|
493
501
|
const missingSchemaFields = listMissingCurrentAutoModeFields(mode);
|
|
@@ -522,6 +530,7 @@ async function startAutoMode({ targetDir, now = new Date(), requestedContract =
|
|
|
522
530
|
requested: normalizedRequest,
|
|
523
531
|
lang,
|
|
524
532
|
now,
|
|
533
|
+
rulePreflight: autoRulePreflight,
|
|
525
534
|
});
|
|
526
535
|
throw new Error(
|
|
527
536
|
`current auto contract does not fit the requested campaign and was rolled over to a new draft (${newMode.campaignId}); archived old campaign files: ${archivedPaths.join(", ")}; fill the new contract fields and approve it before starting auto mode`
|
|
@@ -557,6 +566,7 @@ async function startAutoMode({ targetDir, now = new Date(), requestedContract =
|
|
|
557
566
|
|
|
558
567
|
const timestamp = now.toISOString();
|
|
559
568
|
const status = {
|
|
569
|
+
...autoRulePreflight,
|
|
560
570
|
status: "running",
|
|
561
571
|
currentStage: resumePlan?.stage || mode.allowedStages[0] || "run",
|
|
562
572
|
currentCommand: "",
|
package/lib/auto_state.cjs
CHANGED
|
@@ -93,6 +93,13 @@ function parseAutoStatus(targetDir) {
|
|
|
93
93
|
return {
|
|
94
94
|
path: contextFile(targetDir, "auto-status.md"),
|
|
95
95
|
text,
|
|
96
|
+
ruleSourceFile: extractValue(text, ["Rule source file", "规则来源文件"]),
|
|
97
|
+
ruleSourceRevision: extractValue(text, ["Rule source revision", "规则来源修订"]),
|
|
98
|
+
projectVersion: extractValue(text, ["Project version", "项目版本"]),
|
|
99
|
+
resolvedStage: extractValue(text, ["Resolved stage", "解析后的阶段"]),
|
|
100
|
+
resolvedMode: extractValue(text, ["Resolved mode", "解析后的模式"]),
|
|
101
|
+
resolvedTarget: extractValue(text, ["Resolved target", "解析后的目标"]),
|
|
102
|
+
overrideReason: extractValue(text, ["Override reason, if any", "如有覆盖理由"]),
|
|
96
103
|
status: extractValue(text, ["Status", "状态"]),
|
|
97
104
|
currentStage: extractValue(text, ["Current stage", "当前阶段"]),
|
|
98
105
|
currentCommand: extractValue(text, ["Current command", "当前命令"]),
|
|
@@ -140,6 +147,16 @@ function renderAutoStatus(status, { lang = "en" } = {}) {
|
|
|
140
147
|
if (lang === "zh") {
|
|
141
148
|
return `# 自动模式状态
|
|
142
149
|
|
|
150
|
+
## 规则预检
|
|
151
|
+
|
|
152
|
+
- 规则来源文件: ${status.ruleSourceFile || ""}
|
|
153
|
+
- 规则来源修订: ${status.ruleSourceRevision || ""}
|
|
154
|
+
- 项目版本: ${status.projectVersion || ""}
|
|
155
|
+
- 解析后的阶段: ${status.resolvedStage || ""}
|
|
156
|
+
- 解析后的模式: ${status.resolvedMode || ""}
|
|
157
|
+
- 解析后的目标: ${status.resolvedTarget || ""}
|
|
158
|
+
- 如有覆盖理由: ${status.overrideReason || ""}
|
|
159
|
+
|
|
143
160
|
## 运行状态
|
|
144
161
|
|
|
145
162
|
- 状态: ${status.status || "idle"}
|
|
@@ -169,6 +186,16 @@ function renderAutoStatus(status, { lang = "en" } = {}) {
|
|
|
169
186
|
|
|
170
187
|
return `# Auto Mode Status
|
|
171
188
|
|
|
189
|
+
## Rule Preflight
|
|
190
|
+
|
|
191
|
+
- Rule source file: ${status.ruleSourceFile || ""}
|
|
192
|
+
- Rule source revision: ${status.ruleSourceRevision || ""}
|
|
193
|
+
- Project version: ${status.projectVersion || ""}
|
|
194
|
+
- Resolved stage: ${status.resolvedStage || ""}
|
|
195
|
+
- Resolved mode: ${status.resolvedMode || ""}
|
|
196
|
+
- Resolved target: ${status.resolvedTarget || ""}
|
|
197
|
+
- Override reason, if any: ${status.overrideReason || ""}
|
|
198
|
+
|
|
172
199
|
## Runtime State
|
|
173
200
|
|
|
174
201
|
- Status: ${status.status || "idle"}
|
package/lib/i18n.cjs
CHANGED
|
@@ -260,6 +260,7 @@ const ZH_SKILL_FILES = {
|
|
|
260
260
|
- \`.lab/context/mission.md\`
|
|
261
261
|
- \`.lab/context/decisions.md\`
|
|
262
262
|
- \`.lab/context/evidence-index.md\`
|
|
263
|
+
- \`.lab/.managed/rule-manifest.json\`
|
|
263
264
|
|
|
264
265
|
## 上下文写回
|
|
265
266
|
|
|
@@ -890,6 +891,16 @@ const ZH_SKILL_FILES = {
|
|
|
890
891
|
[path.join(".lab", ".managed", "templates", "iteration-report.md")]:
|
|
891
892
|
`# 迭代报告
|
|
892
893
|
|
|
894
|
+
## 规则预检
|
|
895
|
+
|
|
896
|
+
- Rule source file:
|
|
897
|
+
- Rule source revision:
|
|
898
|
+
- Project version:
|
|
899
|
+
- Resolved stage:
|
|
900
|
+
- Resolved mode:
|
|
901
|
+
- Resolved target:
|
|
902
|
+
- Override reason, if any:
|
|
903
|
+
|
|
893
904
|
## 轮次
|
|
894
905
|
|
|
895
906
|
- 迭代编号:
|
|
@@ -1336,6 +1347,16 @@ const ZH_SKILL_FILES = {
|
|
|
1336
1347
|
[path.join(".lab", ".managed", "templates", "write-iteration.md")]:
|
|
1337
1348
|
`# 写作迭代
|
|
1338
1349
|
|
|
1350
|
+
## 规则预检
|
|
1351
|
+
|
|
1352
|
+
- Rule source file:
|
|
1353
|
+
- Rule source revision:
|
|
1354
|
+
- Project version:
|
|
1355
|
+
- Resolved stage:
|
|
1356
|
+
- Resolved mode:
|
|
1357
|
+
- Resolved target:
|
|
1358
|
+
- Override reason, if any:
|
|
1359
|
+
|
|
1339
1360
|
## 轮次
|
|
1340
1361
|
|
|
1341
1362
|
- Iteration number:
|
|
@@ -1375,6 +1396,33 @@ const ZH_SKILL_FILES = {
|
|
|
1375
1396
|
- Did any alias drift remain unresolved:
|
|
1376
1397
|
- Remaining reader-facing jargon risk:
|
|
1377
1398
|
|
|
1399
|
+
## Section Acceptance Gate
|
|
1400
|
+
|
|
1401
|
+
- Canonical naming consistency passed:
|
|
1402
|
+
- Adjacent-section consistency passed:
|
|
1403
|
+
- Claim / metric / ranking consistency with evidence passed:
|
|
1404
|
+
- Section-style compliance passed:
|
|
1405
|
+
- Local clarity passed:
|
|
1406
|
+
- Local concision passed:
|
|
1407
|
+
- If any item failed, what blocks further prose polish:
|
|
1408
|
+
|
|
1409
|
+
## Section Style Policy
|
|
1410
|
+
|
|
1411
|
+
- Section-style policy checked:
|
|
1412
|
+
- Any discouraged move kept and why:
|
|
1413
|
+
- Any banned move found:
|
|
1414
|
+
|
|
1415
|
+
## Table Semantics
|
|
1416
|
+
|
|
1417
|
+
- Metrics promised in Method:
|
|
1418
|
+
- Metrics shown in main tables:
|
|
1419
|
+
- Any omitted metric and why:
|
|
1420
|
+
- Were all abbreviations expanded at local first mention:
|
|
1421
|
+
- Did each main table include a local table note:
|
|
1422
|
+
- Can a reader interpret rows and columns without chasing Method:
|
|
1423
|
+
- If this section used canonical short names before their defining section, was a local naming bridge added:
|
|
1424
|
+
- Did model and ablation labels stay canonical instead of drifting into narrative aliases:
|
|
1425
|
+
|
|
1378
1426
|
## Language Decision
|
|
1379
1427
|
|
|
1380
1428
|
- Workflow language:
|
|
@@ -1729,6 +1777,16 @@ const ZH_SKILL_FILES = {
|
|
|
1729
1777
|
[path.join(".lab", "context", "auto-status.md")]:
|
|
1730
1778
|
`# 自动模式状态
|
|
1731
1779
|
|
|
1780
|
+
## 规则预检
|
|
1781
|
+
|
|
1782
|
+
- Rule source file:
|
|
1783
|
+
- Rule source revision:
|
|
1784
|
+
- Project version:
|
|
1785
|
+
- Resolved stage:
|
|
1786
|
+
- Resolved mode:
|
|
1787
|
+
- Resolved target:
|
|
1788
|
+
- Override reason, if any:
|
|
1789
|
+
|
|
1732
1790
|
## 运行状态
|
|
1733
1791
|
|
|
1734
1792
|
- Status: idle
|
|
@@ -2021,6 +2079,13 @@ ZH_CONTENT[path.join(".codex", "skills", "lab", "stages", "write.md")] = `# \`/l
|
|
|
2021
2079
|
- \`.lab/context/workflow-state.md\`
|
|
2022
2080
|
- \`.lab/context/evidence-index.md\`
|
|
2023
2081
|
|
|
2082
|
+
## 规则预检
|
|
2083
|
+
|
|
2084
|
+
- 起草前先读取 \`.lab/.managed/rule-manifest.json\`。
|
|
2085
|
+
- 在 write iteration artifact 里先写 \`Rule Preflight\`,再改 prose。
|
|
2086
|
+
- \`Rule Preflight\` 至少记录:Rule source file、Rule source revision、Project version、Resolved stage、Resolved mode、Resolved target,以及任何 override reason。
|
|
2087
|
+
- 如果已安装的 write 规则和当前轮次行为不一致,就先修正目标层或补充有效 override 理由,再继续编辑。
|
|
2088
|
+
|
|
2024
2089
|
## 小步写作规则
|
|
2025
2090
|
|
|
2026
2091
|
- 每轮只改一个 section 或一个明确子问题。
|
|
@@ -2325,6 +2390,10 @@ description: 严格研究工作流,覆盖 idea、data、auto、framing、spec
|
|
|
2325
2390
|
- 如果某个 stage 会决定后续方向,就要保留明确的 approval gate。
|
|
2326
2391
|
- 使用 \`.lab/config/workflow.json\` 作为全局约束,统一管理 workflow language、paper language、paper format、results_root、figures_root、deliverables_root、paper_template_root 和 paper-language 的最终定稿决定。
|
|
2327
2392
|
- 工作流中间工件默认跟随安装语言。
|
|
2393
|
+
- 每个 \`/lab:*\` stage 开始前,都要先读取 \`.lab/.managed/rule-manifest.json\` 并完成一段 \`Rule Preflight\`。
|
|
2394
|
+
- 每个 stage round 的受管工件都要先记录:Rule source file、Rule source revision、Project version、Resolved stage、Resolved mode、Resolved target,以及任何 override reason。
|
|
2395
|
+
- 如果 \`Rule Preflight\` 缺失、过期或和实际行为冲突,就把它视为 stage-contract failure,而不是继续润色或继续推进。
|
|
2396
|
+
- 项目里已安装的规则优先于模型记忆;如果记忆里的旧做法和 \`.lab/.managed/rule-manifest.json\` 记录的规则冲突,以项目里安装的规则为准。
|
|
2328
2397
|
- 最终论文默认输出为 LaTeX,论文语言与工作流语言分开决定。
|
|
2329
2398
|
- 区分“来源事实”和“模型假设”。
|
|
2330
2399
|
- 保留失败实验、失败想法和局限性。
|
|
@@ -2802,6 +2871,14 @@ ZH_CONTENT[path.join(".codex", "skills", "lab", "stages", "auto.md")] = `# \`/la
|
|
|
2802
2871
|
- \`.lab/context/auto-mode.md\`
|
|
2803
2872
|
- \`.lab/context/auto-status.md\`
|
|
2804
2873
|
- \`.lab/context/auto-outcome.md\`
|
|
2874
|
+
- \`.lab/.managed/rule-manifest.json\`
|
|
2875
|
+
|
|
2876
|
+
## 规则预检
|
|
2877
|
+
|
|
2878
|
+
- 启动 auto 前先读取 \`.lab/.managed/rule-manifest.json\`。
|
|
2879
|
+
- 可见的 \`Auto preflight\` 块里除了契约字段外,还要写明:Rule source file、Rule source revision、Project version、Resolved stage、Resolved mode、Resolved target,以及任何 override reason。
|
|
2880
|
+
- 这些 \`Rule Preflight\` 字段也要保存在 \`.lab/context/auto-status.md\`。
|
|
2881
|
+
- 如果已安装的 auto 规则和当前 campaign 行为不一致,就先修正契约或补充有效 override 理由,再启动 loop。
|
|
2805
2882
|
|
|
2806
2883
|
## 上下文写回
|
|
2807
2884
|
|
package/lib/install.cjs
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
const fs = require("node:fs");
|
|
2
2
|
const os = require("node:os");
|
|
3
3
|
const path = require("node:path");
|
|
4
|
+
const crypto = require("node:crypto");
|
|
4
5
|
const { CURRENT_AUTO_MODE_MIGRATION_FIELDS } = require("./auto_state.cjs");
|
|
5
6
|
const { getLocalizedContent } = require("./i18n.cjs");
|
|
6
7
|
|
|
@@ -307,6 +308,10 @@ function installMetadataPath(targetDir) {
|
|
|
307
308
|
return path.join(targetDir, ".lab", ".managed", "install.json");
|
|
308
309
|
}
|
|
309
310
|
|
|
311
|
+
function ruleManifestPath(targetDir) {
|
|
312
|
+
return path.join(targetDir, ".lab", ".managed", "rule-manifest.json");
|
|
313
|
+
}
|
|
314
|
+
|
|
310
315
|
function ensureParentDir(filePath) {
|
|
311
316
|
fs.mkdirSync(path.dirname(filePath), { recursive: true });
|
|
312
317
|
}
|
|
@@ -317,6 +322,44 @@ function writeProjectInstallMetadata(targetDir, metadata) {
|
|
|
317
322
|
fs.writeFileSync(filePath, JSON.stringify(metadata, null, 2) + "\n");
|
|
318
323
|
}
|
|
319
324
|
|
|
325
|
+
function sha256(content) {
|
|
326
|
+
return crypto.createHash("sha256").update(content).digest("hex");
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
function buildRuleManifest(targetDir, metadata) {
|
|
330
|
+
const stages = Object.fromEntries(
|
|
331
|
+
LAB_STAGE_NAMES.map((stage) => {
|
|
332
|
+
const ruleSourceFile = path.join(".codex", "skills", "lab", "stages", `${stage}.md`);
|
|
333
|
+
const absoluteRuleSourceFile = path.join(targetDir, ruleSourceFile);
|
|
334
|
+
let ruleSourceRevision = "";
|
|
335
|
+
if (fs.existsSync(absoluteRuleSourceFile)) {
|
|
336
|
+
ruleSourceRevision = sha256(fs.readFileSync(absoluteRuleSourceFile, "utf8"));
|
|
337
|
+
}
|
|
338
|
+
return [
|
|
339
|
+
stage,
|
|
340
|
+
{
|
|
341
|
+
rule_source_file: ruleSourceFile.replace(/\\/g, "/"),
|
|
342
|
+
rule_source_revision: ruleSourceRevision,
|
|
343
|
+
},
|
|
344
|
+
];
|
|
345
|
+
})
|
|
346
|
+
);
|
|
347
|
+
|
|
348
|
+
return {
|
|
349
|
+
package_version: metadata.package_version,
|
|
350
|
+
layout_version: metadata.layout_version,
|
|
351
|
+
generated_at: metadata.updated_at,
|
|
352
|
+
lab_skill_source_file: ".codex/skills/lab/SKILL.md",
|
|
353
|
+
stages,
|
|
354
|
+
};
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
function writeRuleManifest(targetDir, metadata) {
|
|
358
|
+
const filePath = ruleManifestPath(targetDir);
|
|
359
|
+
ensureParentDir(filePath);
|
|
360
|
+
fs.writeFileSync(filePath, JSON.stringify(buildRuleManifest(targetDir, metadata), null, 2) + "\n");
|
|
361
|
+
}
|
|
362
|
+
|
|
320
363
|
function readProjectInstallMetadata(targetDir) {
|
|
321
364
|
const filePath = installMetadataPath(targetDir);
|
|
322
365
|
if (!fs.existsSync(filePath)) {
|
|
@@ -732,6 +775,7 @@ function installSuperlab({
|
|
|
732
775
|
updated_at: new Date().toISOString(),
|
|
733
776
|
};
|
|
734
777
|
writeProjectInstallMetadata(targetDir, metadata);
|
|
778
|
+
writeRuleManifest(targetDir, metadata);
|
|
735
779
|
if (registerProject) {
|
|
736
780
|
registerProjectInstall(targetDir, metadata, { env });
|
|
737
781
|
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
const fs = require("node:fs");
|
|
2
|
+
const path = require("node:path");
|
|
3
|
+
|
|
4
|
+
function ruleManifestPath(targetDir) {
|
|
5
|
+
return path.join(targetDir, ".lab", ".managed", "rule-manifest.json");
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
function readRuleManifest(targetDir) {
|
|
9
|
+
const manifestPath = ruleManifestPath(targetDir);
|
|
10
|
+
if (!fs.existsSync(manifestPath)) {
|
|
11
|
+
return null;
|
|
12
|
+
}
|
|
13
|
+
return JSON.parse(fs.readFileSync(manifestPath, "utf8"));
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function resolveStageRuleEntry(targetDir, stage) {
|
|
17
|
+
const manifest = readRuleManifest(targetDir);
|
|
18
|
+
if (!manifest || !manifest.stages || !manifest.stages[stage]) {
|
|
19
|
+
return null;
|
|
20
|
+
}
|
|
21
|
+
return {
|
|
22
|
+
packageVersion: manifest.package_version || "",
|
|
23
|
+
ruleSourceFile: manifest.stages[stage].rule_source_file || "",
|
|
24
|
+
ruleSourceRevision: manifest.stages[stage].rule_source_revision || "",
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function buildRulePreflight({
|
|
29
|
+
targetDir,
|
|
30
|
+
stage,
|
|
31
|
+
mode = "",
|
|
32
|
+
target = "",
|
|
33
|
+
overrideReason = "",
|
|
34
|
+
} = {}) {
|
|
35
|
+
const entry = resolveStageRuleEntry(targetDir, stage) || {};
|
|
36
|
+
return {
|
|
37
|
+
ruleSourceFile: entry.ruleSourceFile || "",
|
|
38
|
+
ruleSourceRevision: entry.ruleSourceRevision || "",
|
|
39
|
+
projectVersion: entry.packageVersion || "",
|
|
40
|
+
resolvedStage: stage || "",
|
|
41
|
+
resolvedMode: mode || "",
|
|
42
|
+
resolvedTarget: target || "",
|
|
43
|
+
overrideReason: overrideReason || "",
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
module.exports = {
|
|
48
|
+
buildRulePreflight,
|
|
49
|
+
readRuleManifest,
|
|
50
|
+
resolveStageRuleEntry,
|
|
51
|
+
ruleManifestPath,
|
|
52
|
+
};
|
|
@@ -4,6 +4,7 @@ import json
|
|
|
4
4
|
import re
|
|
5
5
|
import sys
|
|
6
6
|
from pathlib import Path
|
|
7
|
+
from validate_rule_preflight import validate_rule_preflight
|
|
7
8
|
|
|
8
9
|
|
|
9
10
|
ABSOLUTE_PATH_MARKERS = ("/Users/", "/home/", "/tmp/", "/private/tmp/")
|
|
@@ -593,6 +594,23 @@ def check_language_layers(paper_dir: Path, issues: list[str]):
|
|
|
593
594
|
)
|
|
594
595
|
|
|
595
596
|
|
|
597
|
+
def check_latest_write_iteration_preflight(paper_dir: Path, issues: list[str]):
|
|
598
|
+
workflow_config = find_workflow_config(paper_dir)
|
|
599
|
+
if workflow_config is None:
|
|
600
|
+
return
|
|
601
|
+
|
|
602
|
+
project_root = workflow_config.parent.parent
|
|
603
|
+
manifest_path = project_root / ".lab" / ".managed" / "rule-manifest.json"
|
|
604
|
+
if not manifest_path.exists():
|
|
605
|
+
return
|
|
606
|
+
|
|
607
|
+
latest_iteration = find_latest_write_iteration(paper_dir)
|
|
608
|
+
if latest_iteration is None:
|
|
609
|
+
issues.append("missing latest write iteration needed for rule preflight validation")
|
|
610
|
+
return
|
|
611
|
+
issues.extend(validate_rule_preflight(latest_iteration, "write", project_root=project_root))
|
|
612
|
+
|
|
613
|
+
|
|
596
614
|
def main():
|
|
597
615
|
args = parse_args()
|
|
598
616
|
paper_dir = Path(args.paper_dir)
|
|
@@ -610,6 +628,7 @@ def main():
|
|
|
610
628
|
check_experiments_section(paper_dir, issues)
|
|
611
629
|
check_asset_consumption(paper_dir, issues)
|
|
612
630
|
check_language_layers(paper_dir, issues)
|
|
631
|
+
check_latest_write_iteration_preflight(paper_dir, issues)
|
|
613
632
|
|
|
614
633
|
tables_dir = paper_dir / "tables"
|
|
615
634
|
check_table_file(tables_dir / REQUIRED_TABLE_FILES[0], issues, "tables/main-results.tex")
|
|
@@ -4,6 +4,7 @@ import json
|
|
|
4
4
|
import re
|
|
5
5
|
import sys
|
|
6
6
|
from pathlib import Path
|
|
7
|
+
from validate_rule_preflight import validate_rule_preflight
|
|
7
8
|
|
|
8
9
|
|
|
9
10
|
def parse_args():
|
|
@@ -368,6 +369,25 @@ def check_workflow_language_targeting(section_path: Path, issues: list[str]):
|
|
|
368
369
|
)
|
|
369
370
|
|
|
370
371
|
|
|
372
|
+
def check_write_rule_preflight(section_path: Path, issues: list[str]):
|
|
373
|
+
project_root = find_project_root(section_path)
|
|
374
|
+
if project_root is None:
|
|
375
|
+
return
|
|
376
|
+
|
|
377
|
+
iteration_dir = project_root / ".lab" / "writing" / "iterations"
|
|
378
|
+
if not iteration_dir.exists():
|
|
379
|
+
issues.append("missing write-iteration history required for rule preflight validation")
|
|
380
|
+
return
|
|
381
|
+
|
|
382
|
+
iteration_files = sorted(iteration_dir.glob("*.md"))
|
|
383
|
+
if not iteration_files:
|
|
384
|
+
issues.append("missing write-iteration artifact required for rule preflight validation")
|
|
385
|
+
return
|
|
386
|
+
|
|
387
|
+
latest_iteration = iteration_files[-1]
|
|
388
|
+
issues.extend(validate_rule_preflight(latest_iteration, "write", project_root=project_root))
|
|
389
|
+
|
|
390
|
+
|
|
371
391
|
def check_abstract(text: str, issues: list[str]):
|
|
372
392
|
numbers = re.findall(r"\b\d+(?:\.\d+)?\b", text)
|
|
373
393
|
if len(numbers) > 6:
|
|
@@ -496,6 +516,7 @@ def main():
|
|
|
496
516
|
text = read_text(section_path)
|
|
497
517
|
issues: list[str] = []
|
|
498
518
|
check_common_section_gate_risks(text, issues)
|
|
519
|
+
check_write_rule_preflight(section_path, issues)
|
|
499
520
|
check_workflow_language_targeting(section_path, issues)
|
|
500
521
|
check_section_style_policy(text, args.section, issues)
|
|
501
522
|
SECTION_CHECKS[args.section](text, issues)
|
|
@@ -29,6 +29,17 @@ Use this skill when the user invokes `/lab:*` or asks for the structured researc
|
|
|
29
29
|
- Treat evaluation semantics as source-backed once evaluation planning starts: metrics, benchmark gates, baseline behavior, comparison implementations, and deviations should come from recorded sources, not memory.
|
|
30
30
|
- Workflow artifacts should follow the installed workflow language.
|
|
31
31
|
- Iteration artifacts under `.lab/iterations/` are workflow artifacts and should follow the installed workflow language.
|
|
32
|
+
- Before acting in any `/lab:*` stage, read `.lab/.managed/rule-manifest.json` and complete a `Rule Preflight` for the current round.
|
|
33
|
+
- Every stage round must record these `Rule Preflight` fields in its managed artifact before further execution:
|
|
34
|
+
- `Rule source file`
|
|
35
|
+
- `Rule source revision`
|
|
36
|
+
- `Project version`
|
|
37
|
+
- `Resolved stage`
|
|
38
|
+
- `Resolved mode`
|
|
39
|
+
- `Resolved target`
|
|
40
|
+
- `Override reason, if any`
|
|
41
|
+
- Treat missing, stale, or contradictory `Rule Preflight` data as a stage-contract failure.
|
|
42
|
+
- Project-installed rules take priority over model memory. If remembered patterns conflict with the installed rule source, follow the installed source recorded in `.lab/.managed/rule-manifest.json`.
|
|
32
43
|
- Final paper output should default to LaTeX, and its manuscript language should be decided separately from the workflow language.
|
|
33
44
|
- Separate sourced facts from model-generated hypotheses.
|
|
34
45
|
- Preserve failed runs, failed ideas, and limitations.
|
|
@@ -24,6 +24,14 @@
|
|
|
24
24
|
- `.lab/context/auto-status.md`
|
|
25
25
|
- `.lab/context/auto-ledger.md`
|
|
26
26
|
- `.lab/context/auto-outcome.md`
|
|
27
|
+
- `.lab/.managed/rule-manifest.json`
|
|
28
|
+
|
|
29
|
+
## Rule Preflight
|
|
30
|
+
|
|
31
|
+
- Read `.lab/.managed/rule-manifest.json` before arming auto mode.
|
|
32
|
+
- The visible `Auto preflight` summary must also record the installed rule source file, rule source revision, project version, resolved stage, resolved mode, resolved target, and any override reason.
|
|
33
|
+
- Keep the same `Rule Preflight` fields in `.lab/context/auto-status.md` while the campaign is live.
|
|
34
|
+
- If the installed auto rule and the current campaign behavior disagree, stop and fix the contract or record a valid override reason before launching the loop.
|
|
27
35
|
|
|
28
36
|
## Context Write Set
|
|
29
37
|
|
|
@@ -28,6 +28,14 @@
|
|
|
28
28
|
- `.lab/context/data-decisions.md`
|
|
29
29
|
- `.lab/context/terminology-lock.md`
|
|
30
30
|
- `.lab/writing/terminology-glossary.md` when it exists
|
|
31
|
+
- `.lab/.managed/rule-manifest.json`
|
|
32
|
+
|
|
33
|
+
## Rule Preflight
|
|
34
|
+
|
|
35
|
+
- Read `.lab/.managed/rule-manifest.json` before drafting.
|
|
36
|
+
- Record a `Rule Preflight` block in the write-iteration artifact before revising prose.
|
|
37
|
+
- The `Rule Preflight` block must record the installed rule source file, rule source revision, project version, resolved stage, resolved mode, resolved target, and any override reason.
|
|
38
|
+
- If the installed write rule and the current round behavior disagree, fix the targeting or record a valid override reason before further editing.
|
|
31
39
|
|
|
32
40
|
## Context Write Set
|
|
33
41
|
|