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.
@@ -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: "",
@@ -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)
@@ -1,5 +1,15 @@
1
1
  # Iteration Report
2
2
 
3
+ ## Rule Preflight
4
+
5
+ - Rule source file:
6
+ - Rule source revision:
7
+ - Project version:
8
+ - Resolved stage:
9
+ - Resolved mode:
10
+ - Resolved target:
11
+ - Override reason, if any:
12
+
3
13
  ## Round
4
14
 
5
15
  - Iteration number:
@@ -1,5 +1,15 @@
1
1
  # Write Iteration
2
2
 
3
+ ## Rule Preflight
4
+
5
+ - Rule source file:
6
+ - Rule source revision:
7
+ - Project version:
8
+ - Resolved stage:
9
+ - Resolved mode:
10
+ - Resolved target:
11
+ - Override reason, if any:
12
+
3
13
  ## Round
4
14
 
5
15
  - Iteration number:
@@ -1,5 +1,15 @@
1
1
  # Auto Mode Status
2
2
 
3
+ ## Rule Preflight
4
+
5
+ - Rule source file:
6
+ - Rule source revision:
7
+ - Project version:
8
+ - Resolved stage:
9
+ - Resolved mode:
10
+ - Resolved target:
11
+ - Override reason, if any:
12
+
3
13
  ## Runtime State
4
14
 
5
15
  - Status: idle
@@ -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
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "superlab",
3
- "version": "0.1.61",
3
+ "version": "0.1.62",
4
4
  "description": "Strict /lab research workflow installer for Codex and Claude",
5
5
  "keywords": [
6
6
  "codex",