dsh-vibe-math 2.3.1 → 2.3.3
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/AUDIT-CHECKLIST.md +59 -0
- package/README.md +16 -6
- package/RELEASE-NOTES-2.3.2.md +145 -0
- package/RELEASE-NOTES-2.3.3.md +115 -0
- package/audit-formal-sensitivity.mjs +11 -2
- package/audit-prompt-invariants.mjs +459 -0
- package/audit-spec-traceability.mjs +193 -0
- package/docs/formal-verification.md +37 -13
- package/docs/generate_framework_diagram_v5.mjs +2 -1
- package/docs/test-timing.md +32 -10
- package/formal-verify-v2.test.mjs +288 -2
- package/formal-verify-v3.test.mjs +230 -4
- package/formal-verify-v4.test.mjs +205 -5
- package/formal-verify-v5.test.mjs +114 -4
- package/installer.js +3 -1
- package/package.json +6 -2
- package/prompt-corpus-persona/persona-corpus.json +2 -2
- package/prompt-corpus-persona/persona-corpus.md +6 -2
- package/prompt-corpus-v2/formal-verify-v2.json +164 -44
- package/prompt-corpus-v2/formal-verify-v2.md +1374 -44
- package/prompt-corpus-v3/formal-verify-v3.json +236 -128
- package/prompt-corpus-v3/formal-verify-v3.md +1509 -400
- package/prompt-corpus-v4/formal-verify-v4.json +8 -3
- package/prompt-corpus-v4/formal-verify-v4.md +38 -10
- package/prompt-corpus-v5/prompt-corpus-v5.json +175 -246
- package/prompt-corpus-v5/prompt-corpus-v5.md +341 -781
- package/prompt-v5-integrity.test.mjs +136 -22
- package/run-tests.mjs +30 -11
- package/vibe-math-v2/vibe-math-v2.js +163 -38
- package/vibe-math-v2//345/256/236/347/216/260/346/226/271/346/241/210.md +58 -6
- package/vibe-math-v3/vibe-math-v3.js +95 -25
- package/vibe-math-v3//345/256/236/347/216/260/346/226/271/346/241/210.md +8 -7
- package/vibe-math-v4/vibe-math-v4.js +103 -24
- package/vibe-math-v4//345/256/236/347/216/260/346/226/271/346/241/210.md +37 -14
- package/vibe-math-v5/agent.cordis.yml +6 -2
- package/vibe-math-v5/vibe-math-v5.js +56 -10
- package/vibe-math-v5//345/256/236/347/216/260/346/226/271/346/241/210.md +45 -14
- package/vibe-math-v5//346/236/266/346/236/204/345/233/276.md +16 -2
- package//347/244/272/344/276/213/345/233/276//346/241/206/346/236/266/345/233/276-v5.svg +6 -5
|
@@ -562,25 +562,45 @@ export function apply(ctx) {
|
|
|
562
562
|
} catch (e) {
|
|
563
563
|
return { ok: false, code: 'LEAN_SPAWN_FAILED', message: String((e && e.message) || e), file: rel, ms: now() - started }
|
|
564
564
|
}
|
|
565
|
+
// 超时必须有**主动**兜底:`graceMs` 只是宿主侧的宽限,契约 §7 明确要求"对超时调用
|
|
566
|
+
// handle.terminate()"。此前 v2 只依赖 graceMs,从不终止进程:一个卡住的 Lean 会继续占着
|
|
567
|
+
// 资源,而框架已经报了超时——它与自己的契约不一致。这里与 `handle.done` 竞速:计时器到点
|
|
568
|
+
// 时尽力 terminate(),并给出一份可读的超时结果;`done` 先到就清掉计时器(不留悬挂 timer)。
|
|
569
|
+
let timedOut = false
|
|
570
|
+
let timer = null
|
|
565
571
|
let outcome
|
|
566
572
|
try {
|
|
567
|
-
outcome = await
|
|
573
|
+
outcome = await Promise.race([
|
|
574
|
+
handle.done,
|
|
575
|
+
new Promise(function (resolve) {
|
|
576
|
+
timer = setTimeout(function () {
|
|
577
|
+
timedOut = true
|
|
578
|
+
try { if (handle && typeof handle.terminate === 'function') handle.terminate() } catch (e) { /* best effort:终止失败也要给出可读结果 */ }
|
|
579
|
+
resolve({ exitCode: null, signal: 'SIGTERM' })
|
|
580
|
+
}, cap)
|
|
581
|
+
}),
|
|
582
|
+
])
|
|
568
583
|
} catch (e) {
|
|
584
|
+
if (timer !== null) clearTimeout(timer)
|
|
569
585
|
return { ok: false, code: 'LEAN_RUN_FAILED', message: String((e && e.message) || e), file: rel, ms: now() - started }
|
|
570
586
|
}
|
|
587
|
+
if (timer !== null) clearTimeout(timer)
|
|
571
588
|
let out = '', err = ''
|
|
572
589
|
try { if (handle.collected && handle.collected.stdout) out = handle.collected.stdout.readFrom(0).text } catch (e) { /* best effort */ }
|
|
573
590
|
try { if (handle.collected && handle.collected.stderr) err = handle.collected.stderr.readFrom(0).text } catch (e) { /* best effort */ }
|
|
574
591
|
const exitCode = outcome ? outcome.exitCode : null
|
|
575
592
|
const ms = now() - started
|
|
576
593
|
const ok = exitCode === 0
|
|
594
|
+
// 两种超时都算超时:我们自己的计时器到点(timedOut),或耗时已越过 cap(宿主的 graceMs
|
|
595
|
+
// 杀掉了进程时 done 会先返回一个非零 exitCode)。
|
|
596
|
+
const isTimeout = timedOut || ms >= cap
|
|
577
597
|
// 输出截断到 ~4KB 再入库(避免把巨大的编译器输出写进状态)。
|
|
578
598
|
return {
|
|
579
599
|
ok: ok, exitCode: exitCode, signal: (outcome && outcome.signal) || null, ms: ms,
|
|
580
600
|
command: argv.join(' '), file: rel,
|
|
581
601
|
stdout: tailText(out, 4000), stderr: tailText(err, 4000),
|
|
582
|
-
timedOut:
|
|
583
|
-
code: ok ? undefined : (
|
|
602
|
+
timedOut: isTimeout,
|
|
603
|
+
code: ok ? undefined : (isTimeout ? 'LEAN_TIMEOUT' : 'LEAN_FAILED'),
|
|
584
604
|
}
|
|
585
605
|
}
|
|
586
606
|
// 把一次运行结果写进对象的形式化记录(不提升 status,状态迁移见契约 §4)。
|
|
@@ -727,16 +747,18 @@ export function apply(ctx) {
|
|
|
727
747
|
L.push(' · 若你判断不值得或无法形式化,可以不做,但请在回执的 formal 字段写明难度判断(decision=\'blocked\' 时必须写明 note)。')
|
|
728
748
|
}
|
|
729
749
|
L.push(' · 归档可复用定义/引理前先跑通(vibe_math_lean_archive run=true 或先 vibe_math_lean_run);跑不通不要入库。')
|
|
730
|
-
L.push(' · 宿主没有 Lean 工具链(LEAN_NOT_FOUND)时:把代码写下来归档,并在回执的 note 里写明'
|
|
750
|
+
L.push(' · 宿主没有 Lean 工具链(LEAN_NOT_FOUND)或宿主不提供 subprocess 服务(NO_SUBPROCESS)时:把代码写下来归档,并在回执的 note 里写明'
|
|
731
751
|
+ '"宿主无 Lean 工具链"——这算显式阻塞原因,定论门禁可以据此放行。')
|
|
732
752
|
}
|
|
733
753
|
return L.join('\n')
|
|
734
754
|
}
|
|
735
755
|
function formalWorkLine() {
|
|
736
756
|
if (!formalOn()) return ''
|
|
757
|
+
// `Formal/Proved/` 在项目根下**并不存在**(可复用库故意在项目树之外),只写相对路径会让代理
|
|
758
|
+
// 去项目里找一个永远找不到的目录;这里与验证段落一样给出 VibeMath 根的绝对路径(契约 §6.2)。
|
|
737
759
|
return '【顺手形式化(' + (formalMode() === 'require' ? '强制' : '鼓励') + ')】把你工作中常用或可能复用的对象、假设、'
|
|
738
|
-
+ '新定义用 Lean 形式化定义并归档到全局可复用库(vibe_math_lean_archive kind=\'def\'),已成立的引理归到
|
|
739
|
-
+ '
|
|
760
|
+
+ '新定义用 Lean 形式化定义并归档到全局可复用库(vibe_math_lean_archive kind=\'def\'),已成立的引理归到 '
|
|
761
|
+
+ vibeRoot().replace(/\\/g, '/') + '/Formal/Proved/(kind=\'lemma\');写之前先 vibe_math_lean_lib 查重,避免重复定义。'
|
|
740
762
|
+ '归档前先跑通(vibe_math_lean_run 或 run=true);跑不通的定义不要进可复用库。'
|
|
741
763
|
}
|
|
742
764
|
/**
|
|
@@ -761,13 +783,34 @@ export function apply(ctx) {
|
|
|
761
783
|
+ '"note":"难度判断/阻塞原因/具体偏差"}(decision=\'blocked\'/\'defect\' 时必须写明 note,否则整条记录被拒绝;'
|
|
762
784
|
+ 'decision=\'defect\' 会撤回该证明的「已通过」状态并写入「形式化待办」)。'
|
|
763
785
|
}
|
|
786
|
+
/**
|
|
787
|
+
* 撤回一份归档证明。删除是**尽力而为**,撤回却不是:
|
|
788
|
+
* 宿主没有 `subprocess` 服务、shell 删除失败、或 shell 退出 0 却没真的删掉(stub 宿主、权限问题)时,
|
|
789
|
+
* 必须把撤回通知**写进那个路径**——否则一份已被撤回的证明仍留在 `Verified/Lean/`,那是"所有人找
|
|
790
|
+
* 这个对象的证明"的地方;记录里的 `proof` 已经清空,于是目录与记录脱节,谁也不会再发现它
|
|
791
|
+
* (契约 §4.1 要求撤回,而不是"试过删除")。
|
|
792
|
+
* 返回**实际发生了哪一种**(deleted / overwritten / failed / unreachable),由调用方如实告知读者。
|
|
793
|
+
*/
|
|
794
|
+
async function withdrawArchivedProof(rel) {
|
|
795
|
+
const abs = leanAbsPath(rel)
|
|
796
|
+
if (abs === null) return { rel: String(rel), outcome: 'unreachable' }
|
|
797
|
+
const sub = subprocessOf()
|
|
798
|
+
if (sub !== undefined && typeof sub.spawn === 'function') {
|
|
799
|
+
try { await runShell(rmCmd(abs)) } catch (e) { /* 落到下面的覆写 */ }
|
|
800
|
+
// 用 fs 复核"真的没了":`Remove-Item -ErrorAction SilentlyContinue` / `rm -f` 都可能静默失败。
|
|
801
|
+
if (await readTextAbs(abs) === undefined) return { rel: String(rel), outcome: 'deleted' }
|
|
802
|
+
}
|
|
803
|
+
const ok = await writeTextAbs(abs, '-- 已撤回(' + fmtTime() + '):该形式化被认定与命题原文不一致。\n'
|
|
804
|
+
+ '-- 原代码保留在工作文件 Formal/' + String(rel).split('/').pop() + ';修正并重新跑通后重新归档。\n')
|
|
805
|
+
return { rel: String(rel), outcome: ok ? 'overwritten' : 'failed' }
|
|
806
|
+
}
|
|
764
807
|
/**
|
|
765
808
|
* 契约 §4.1:`defect` = **形式化不合格**,不是"命题为假"。
|
|
766
809
|
*
|
|
767
810
|
* 表决者逐条核对后发现 Lean 代码与命题原文不一致(写窄了/写宽了/换了对象/漏了条件…),
|
|
768
811
|
* 那是这条形式化写得不对,不是命题被证伪。因此:
|
|
769
812
|
* ① 把形式化记录**降级为 `attempted`**(无论此前是 `passed` 还是 `blocked`)、清空 `proof`;
|
|
770
|
-
* ②
|
|
813
|
+
* ② 撤回归档证明 `Verified/Lean/<id>.lean`(工作文件 `Formal/<id>.lean` 保留,代码不丢);
|
|
771
814
|
* ③ `note` 记入记录与 `Formal/TODO.md`,并在活动日志里公告;
|
|
772
815
|
* ④ `require` 档下 `formalGateOk` 随之为假 → 本次裁定**不定论**,修正形式化并重新跑通后再投票。
|
|
773
816
|
*/
|
|
@@ -777,24 +820,50 @@ export function apply(ctx) {
|
|
|
777
820
|
const before = formalRecords()
|
|
778
821
|
const proofs = []
|
|
779
822
|
const pushProof = function (p) { const s = String(p || ''); if (s && proofs.indexOf(s) === -1) proofs.push(s) }
|
|
780
|
-
|
|
781
|
-
|
|
823
|
+
// **同一对象的全部 id 别名**都要看:归档可能写在对象 id(`pX`)上,也可能写在验证 id
|
|
824
|
+
// (`r-pX` / `r-pX-s0` / `r-pX-pf1`)上,而回执点名的可以是任意一侧。只扫 `t` 与 `objectId`
|
|
825
|
+
// 会漏掉"归档用 rId、回执用对象 id"这一组合,于是那份被撤回的证明永远留在 `Verified/Lean/`
|
|
826
|
+
// 里(记录已清空 proof,没人再指向它)——这正是"成对关系只做一半"的缺陷形态(审计清单 §3)。
|
|
827
|
+
for (const k of Object.keys(before)) if (formalObjectIdOf(k) === objectId) pushProof((before[k] || {}).proof)
|
|
782
828
|
// 两套 id 一起降级——只降一侧会让另一侧继续"已通过",门禁/卡片就会照旧放行。
|
|
783
829
|
await putFormalBothIds(t, { status: 'attempted', decision: 'defect', note: note, proof: '', updatedAt: now() })
|
|
784
|
-
//
|
|
785
|
-
|
|
830
|
+
// 备选的归档证明路径 = 记录里记着的那份(一定存在过)+ 各个 id 直接对应的文件名。
|
|
831
|
+
const candidates = []
|
|
832
|
+
for (let i = 0; i < proofs.length; i++) if (proofs[i].indexOf('Verified/Lean/') === 0 && candidates.indexOf(proofs[i]) === -1) candidates.push(proofs[i])
|
|
833
|
+
const keys = Object.keys(before).filter(function (k) { return formalObjectIdOf(k) === objectId })
|
|
834
|
+
for (const id of keys.concat([t, objectId])) { const r = 'Verified/Lean/' + id + '.lean'; if (candidates.indexOf(r) === -1) candidates.push(r) }
|
|
835
|
+
// 只处理**确实存在**(或在记录里被引用)的路径:宿主没有 subprocess 时撤回会退化成"覆写通知",
|
|
836
|
+
// 若把从未存在过的文件名也一并处理,就会凭空造出 `Verified/Lean/<id>.lean`。
|
|
786
837
|
const rels = []
|
|
787
|
-
for (let i = 0; i <
|
|
788
|
-
|
|
789
|
-
|
|
838
|
+
for (let i = 0; i < candidates.length; i++) {
|
|
839
|
+
if (proofs.indexOf(candidates[i]) !== -1) { rels.push(candidates[i]); continue }
|
|
840
|
+
const abs = leanAbsPath(candidates[i])
|
|
841
|
+
if (abs !== null && (await readTextAbs(abs)) !== undefined) rels.push(candidates[i])
|
|
842
|
+
}
|
|
843
|
+
const deleted = [], overwritten = [], failed = []
|
|
844
|
+
for (let i = 0; i < rels.length; i++) {
|
|
845
|
+
let r
|
|
846
|
+
try { r = await withdrawArchivedProof(rels[i]) } catch (e) { r = { rel: rels[i], outcome: 'failed' } }
|
|
847
|
+
if (r.outcome === 'deleted') deleted.push(r.rel)
|
|
848
|
+
else if (r.outcome === 'overwritten') overwritten.push(r.rel)
|
|
849
|
+
else failed.push(r.rel)
|
|
850
|
+
}
|
|
790
851
|
const list = formalTodo().filter(function (x) { return x.id !== objectId })
|
|
791
852
|
list.push({ id: objectId, at: now(), why: 'defect:形式化与命题原文不一致,需修正后重新跑通(' + note + ')' })
|
|
792
853
|
await putFormal(t, Object.assign({}, formalRecords()[t] || {}, { status: 'attempted', decision: 'defect', note: note, proof: '', updatedAt: now() }), list)
|
|
793
854
|
await writeFormalTodo()
|
|
794
855
|
await writeFormalIndex()
|
|
856
|
+
// 公告必须如实说明**撤回实际怎么完成的**:删除成功、只能覆写成撤回通知、还是两者都没做到。
|
|
857
|
+
// 否则读者会以为归档目录里已经干净了,而一份坏证明还躺在那里(契约 §4.1)。
|
|
795
858
|
logActivity('formal', '【形式化】' + who + ' 通过回执记录 ' + objectId + ' 的忠实性缺陷(decision=defect):' + note
|
|
796
|
-
+ ' —— 已撤回「已通过」状态(降级 attempted
|
|
797
|
-
|
|
859
|
+
+ ' —— 已撤回「已通过」状态(降级 attempted'
|
|
860
|
+
+ (deleted.length ? '、删除归档证明 ' + deleted.join('、') : '')
|
|
861
|
+
+ (overwritten.length ? '、把归档证明覆写为撤回通知 ' + overwritten.join('、') + '(宿主无法删除,但该路径已不再是一份证明)' : '')
|
|
862
|
+
+ (failed.length ? '、⚠ 归档证明 ' + failed.join('、') + ' 既未删除也未能覆写,记录已降级——请不要把它当作该对象的证明' : '')
|
|
863
|
+
+ '、写入 Formal/TODO.md)。'
|
|
864
|
+
// 强度必须与档位一致(契约 §4.1 第 3 条):encourage 没有门禁,不能声称框架会搁置裁定。
|
|
865
|
+
+ (formalRequired() ? '本次裁定不定论。' : '本档没有门禁:本次裁定是否定论由表决结果决定(靠表决者的弃权值阻止布尔一致结论)。'))
|
|
866
|
+
return { ok: true, decision: 'defect', target: objectId, named: t, status: 'attempted', note: note, cleared: rels, deleted: deleted, overwritten: overwritten, failed: failed }
|
|
798
867
|
}
|
|
799
868
|
/**
|
|
800
869
|
* 回执通道(契约 §4 / §6.3):代理**即使一次 Lean 工具都没调用**,也必须能留下"实现难度判断"或
|
|
@@ -828,10 +897,21 @@ export function apply(ctx) {
|
|
|
828
897
|
}
|
|
829
898
|
if (decision === 'used') {
|
|
830
899
|
const file = String(f.file || ('Formal/' + target + '.lean'))
|
|
831
|
-
|
|
900
|
+
// 契约 §4:`used` 只表示"这一轮碰了形式化/写了草稿",它**不得**撤销已经成立的证明。
|
|
901
|
+
// 无条件写 attempted 会静默抹掉 passed:投票提示词丢掉忠实性分支、require 档对一份已跑通的
|
|
902
|
+
// 归档证明重新关门,而 `proof` 指针还留着(记录自相矛盾)。v3/v4/v5 都保留 passed/blocked——
|
|
903
|
+
// 这是"四套同构"里最容易被漏掉的一处(AUDIT-CHECKLIST §1.8)。
|
|
904
|
+
// 两套 id 空间都可能是"更强的那一侧"(对象侧 blocked、验证侧 passed 这类历史状态),
|
|
905
|
+
// 所以取两者的最强状态:passed > blocked > attempted——保证 `used` 在任何一侧都不降级。
|
|
906
|
+
const own = formalOf(target).status
|
|
907
|
+
const merged = formalGateRecord(target).status
|
|
908
|
+
const status = (own === 'passed' || merged === 'passed') ? 'passed'
|
|
909
|
+
: ((own === 'blocked' || merged === 'blocked') ? 'blocked' : 'attempted')
|
|
910
|
+
await putFormalBothIds(target, { status: status, decision: 'used', file: file, updatedAt: now() })
|
|
832
911
|
await writeFormalIndex()
|
|
833
|
-
logActivity('formal', '【形式化】' + who + ' 通过回执记录 ' + target + ' 形式化草稿:' + file
|
|
834
|
-
|
|
912
|
+
logActivity('formal', '【形式化】' + who + ' 通过回执记录 ' + target + ' 形式化草稿:' + file
|
|
913
|
+
+ (status === 'attempted' ? '' : '(保留已有的 ' + status + ' 状态:一次 used 回执不撤销已成立的证明)'))
|
|
914
|
+
return { ok: true, decision: 'used', target: target, status: status, file: file }
|
|
835
915
|
}
|
|
836
916
|
logActivity('formal', '【形式化】' + who + ' 的 formal.decision 只能是 \'used\' | \'blocked\' | \'defect\'(收到 '
|
|
837
917
|
+ String(f.decision) + '),已忽略(V2_INVALID_ARGUMENT)。')
|
|
@@ -959,7 +1039,14 @@ export function apply(ctx) {
|
|
|
959
1039
|
const run = args.run === false ? null : await leanRunFile(abs)
|
|
960
1040
|
await rebuildLeanLibIndexes()
|
|
961
1041
|
logActivity('formal', (memberId || 'office') + ' 归档了' + (kind === 'def' ? '可复用定义' : '已证引理') + ' `' + name + '` → ' + rel + (run ? '(运行 ' + (run.ok ? '通过' : '未通过') + ')' : ''))
|
|
962
|
-
|
|
1042
|
+
// 工具返回值同样是代理读到的文字:`run` 为红时**不能**声称"可直接 import 复用"——
|
|
1043
|
+
// 那份文件没有通过编译,"可复用库"里的它是有害的(契约 §6 第 3 条 / v2 实现方案 §9.4)。
|
|
1044
|
+
return {
|
|
1045
|
+
ok: true, kind: kind, name: name, file: rel, run: run || undefined,
|
|
1046
|
+
note: (run && !run.ok)
|
|
1047
|
+
? '⚠ 该文件**运行未通过**(见 run.stderr):它已写入 ' + rel + ',但**不合格**,请不要当作可复用定义;请修复后用 vibe_math_lean_run(或再次归档 run=true)跑通。'
|
|
1048
|
+
: '已并入全局可复用库,后续项目可直接 import 复用',
|
|
1049
|
+
}
|
|
963
1050
|
}
|
|
964
1051
|
if (kind === 'proof') {
|
|
965
1052
|
const rawTarget = String(args.target || '').trim()
|
|
@@ -977,16 +1064,23 @@ export function apply(ctx) {
|
|
|
977
1064
|
const run = await leanRunFile(workRel)
|
|
978
1065
|
const prev = formalOf(target)
|
|
979
1066
|
const passed = !!run.ok
|
|
1067
|
+
// A RED re-archive invalidates the previous proof: the work file it proved has just been
|
|
1068
|
+
// overwritten by code that does not compile. Keeping the pointer (or leaving the archived
|
|
1069
|
+
// file) would produce "attempted + 归档证明 X.lean" in the index and let the fidelity prompt
|
|
1070
|
+
// print a proof path for code that no longer exists — `proof` is for `passed` only (§4).
|
|
1071
|
+
const stalePrev = passed ? '' : String(prev.proof || ('Verified/Lean/' + target + '.lean'))
|
|
980
1072
|
const rec = Object.assign({}, prev, {
|
|
981
1073
|
status: passed ? 'passed' : 'attempted',
|
|
982
1074
|
file: workRel,
|
|
983
|
-
proof: passed ? 'Verified/Lean/' + target + '.lean' :
|
|
1075
|
+
proof: passed ? 'Verified/Lean/' + target + '.lean' : '',
|
|
984
1076
|
decision: 'used',
|
|
985
1077
|
note: String(args.note || prev.note || ''),
|
|
986
1078
|
run: { at: now(), ok: !!run.ok, exitCode: run.exitCode === undefined ? null : run.exitCode, ms: run.ms || 0, stdoutTail: tailText(run.stdout, 800), stderrTail: tailText(run.stderr, 800) },
|
|
987
1079
|
updatedAt: now(),
|
|
988
1080
|
})
|
|
1081
|
+
let withdrawn = null
|
|
989
1082
|
if (passed) await writeText('Verified/Lean/' + target + '.lean', body)
|
|
1083
|
+
else if (stalePrev) { try { withdrawn = await withdrawArchivedProof(stalePrev) } catch (e) { withdrawn = { rel: stalePrev, outcome: 'failed' } } }
|
|
990
1084
|
await putFormal(target, rec)
|
|
991
1085
|
// ★ 让"归档"与"验证对象"两套 id 对齐。
|
|
992
1086
|
// 验证提示词与门禁关心的是**这一次验证**(rId,例如 r-pGate),而代理用 vibe_math_lean_archive
|
|
@@ -995,7 +1089,10 @@ export function apply(ctx) {
|
|
|
995
1089
|
// 裁定还是被反复搁置。两套记录都写,门禁与提示词任取其一都自洽。
|
|
996
1090
|
await syncVerificationTarget(target, passed ? 'passed' : 'attempted', rec)
|
|
997
1091
|
await rebuildLeanLibIndexes()
|
|
998
|
-
logActivity('formal', (memberId || 'office') + ' 为 ' + target + ' 归档形式化证明 ' + workRel + '(运行 ' + (passed
|
|
1092
|
+
logActivity('formal', (memberId || 'office') + ' 为 ' + target + ' 归档形式化证明 ' + workRel + '(运行 ' + (passed
|
|
1093
|
+
? '通过,已归档到 ' + rec.proof + ',验证转为忠实性审查'
|
|
1094
|
+
: '未通过:' + tailText(run.stderr || run.message, 160)
|
|
1095
|
+
+ ';已撤回上一份已通过状态与归档证明' + (withdrawn && withdrawn.outcome !== 'failed' ? '(' + withdrawn.outcome + ')' : '(⚠ 撤回失败,请不要把 ' + stalePrev + ' 当作该对象的证明)')) + ')')
|
|
999
1096
|
return { ok: true, kind: kind, target: target, file: workRel, proof: rec.proof, passed: passed, run: run, status: rec.status }
|
|
1000
1097
|
}
|
|
1001
1098
|
if (kind === 'blocked') {
|
|
@@ -1024,14 +1121,22 @@ export function apply(ctx) {
|
|
|
1024
1121
|
async function deferForFormal(target, why) {
|
|
1025
1122
|
const t = safeId(String(target || ''))
|
|
1026
1123
|
if (!t) return false
|
|
1027
|
-
const rec = formalOf(t)
|
|
1028
1124
|
if (!formalRequired()) return false
|
|
1125
|
+
// ★ 判定必须用**合并后**的记录(`formalGateRecord`,两套 id 都认),不能只看自己那一侧。
|
|
1126
|
+
// 代理是用**对象 id** 归档的(提示词里给它的就是对象 id),而验证/门禁问的是 rId;
|
|
1127
|
+
// `syncVerificationTarget` 只更新**已存在**的别名键,所以"归档写了 pX、r-pX 还没有记录"是
|
|
1128
|
+
// 首次形式化后的真实状态。那时 `formalOf('r-pX')` 返回 `{status:'none'}`,门禁会把一个
|
|
1129
|
+
// **已经 passed 的对象**判为未形式化(假阴性);更糟的是这次搁置本身会写下 r-pX =
|
|
1130
|
+
// status:'none',于是此后**每一轮**都继续搁置、继续重开一次完整辩论——对象永远无法定论。
|
|
1131
|
+
// 这正是实现方案 §四写明的"门禁与提示词取记录时两个方向都认(formalGateRecord)"。
|
|
1132
|
+
const rec = formalGateRecord(t)
|
|
1029
1133
|
if (formalGateOk(rec)) return false
|
|
1134
|
+
const own = formalOf(t)
|
|
1030
1135
|
const reason = 'formal-required:尚未取得 Lean 形式化通过,也没有显式阻塞记录(当前状态 ' + (rec.status || 'none') + ')' + (why ? '|' + why : '')
|
|
1031
1136
|
const list = formalTodo().filter(function (x) { return x.id !== t })
|
|
1032
1137
|
list.push({ id: t, at: now(), why: reason })
|
|
1033
1138
|
// 不改动对象的既有权重/概率字段:只补一条 formal 记录(status 保持 none/attempted)。
|
|
1034
|
-
await putFormal(t,
|
|
1139
|
+
await putFormal(t, own.status === 'none' ? { status: 'none', deferredAt: now() } : Object.assign({}, own, { deferredAt: now() }), list)
|
|
1035
1140
|
await writeFormalTodo()
|
|
1036
1141
|
await writeFormalIndex()
|
|
1037
1142
|
// v2 没有群聊文件(没有 Shared/Chat/),所以"群聊公告"落在它的可读通道上:
|
|
@@ -1411,7 +1516,16 @@ export function apply(ctx) {
|
|
|
1411
1516
|
L.push(' ▸ **发现任何偏差,不要投 0**:偏差只说明**形式化不合格**,不代表命题为假。此时请:')
|
|
1412
1517
|
L.push(" ① Result 给一个严格介于 0 与 1 之间的值(记为弃权),并在 Reason 里写清偏差;")
|
|
1413
1518
|
L.push(" ② 用回执 formal:{decision:'defect', note:'<具体偏差>'} 记录它。框架会撤回这条证明的")
|
|
1414
|
-
|
|
1519
|
+
if (formalMode() === 'require') {
|
|
1520
|
+
// 这一档真的有门禁,所以"本次裁定**不定论**"是框架**能兑现**的承诺(契约 §6.1)。
|
|
1521
|
+
L.push(' 「已通过」状态(降级为 attempted、删除归档证明、写入形式化待办),本次裁定**不定论**;')
|
|
1522
|
+
} else {
|
|
1523
|
+
// encourage 档没有门禁:撤回证明 ≠ 搁置裁定。承诺一个框架无法强制的"不定论",会让表决者
|
|
1524
|
+
// 以为不必自己弃权——那正是"提示词承诺的强度档位必须与实现一致"这条不变式(契约 §4.1 第 3 条
|
|
1525
|
+
// / §6.1,审计清单 §1.7)。这里如实说明:阻止本轮定论的是**你的弃权值**。
|
|
1526
|
+
L.push(' 「已通过」状态(降级为 attempted、删除归档证明、写入形式化待办)。**本档没有门禁**:')
|
|
1527
|
+
L.push(' 框架不会强制搁置本次裁定——请务必给出①里的弃权值,靠它阻止本轮得出布尔一致结论;')
|
|
1528
|
+
}
|
|
1415
1529
|
L.push(' 修正形式化并重新跑通后再投票。')
|
|
1416
1530
|
L.push(' ▸ 只有当你**独立于这份 Lean 代码**也能确定命题为假时,才投 0,并在 Reason 里写清独立理由。')
|
|
1417
1531
|
} else if (rec.status === 'blocked') {
|
|
@@ -2085,19 +2199,30 @@ export function apply(ctx) {
|
|
|
2085
2199
|
if (q.判断命题 && !sol.来源列表) {
|
|
2086
2200
|
const ap = await findProposition(q.判断命题)
|
|
2087
2201
|
if (ap) {
|
|
2088
|
-
|
|
2089
|
-
//
|
|
2090
|
-
//
|
|
2091
|
-
//
|
|
2092
|
-
//
|
|
2093
|
-
//
|
|
2094
|
-
|
|
2095
|
-
ap
|
|
2096
|
-
|
|
2097
|
-
else
|
|
2098
|
-
|
|
2099
|
-
|
|
2100
|
-
|
|
2202
|
+
// ★ require 门禁:这条路径把**源命题**的 布尔估计 直接写成 0/1、置 优先级='never'、
|
|
2203
|
+
// 并标记 已验证(此后不再入选验证)——这就是一次对源命题的布尔裁定,必须先过门禁。
|
|
2204
|
+
// 原来的写法只让 writeVerifiedCardIfNeeded 去拦卡片,而它的返回值没人检查,概率字段
|
|
2205
|
+
// 早已落库:一个未形式化的命题会被侧面判为"假"并永久退出调度(v=1 时上面那道门禁
|
|
2206
|
+
// 拦得住,v=0 拦不住)。实现方案 §八把顺序写得很清楚:先拿卡片写入许可,再改
|
|
2207
|
+
// 布尔估计/优先级(契约 §8:门禁不通过时"不改变对象的既有权重/概率字段")。
|
|
2208
|
+
const judgeBool = (v === 1 || v === 0)
|
|
2209
|
+
if (judgeBool && await deferForFormal(ap.id, '「判断命题」问题解法的裁定转移到源命题(' + v + ')')) {
|
|
2210
|
+
logActivity('gate', t.rId + ' 对源命题 ' + ap.id + ' 的裁定 ' + v + ' 被 require 模式搁置为未定论(formal-required)')
|
|
2211
|
+
} else {
|
|
2212
|
+
ap.布尔估计 = v
|
|
2213
|
+
// 收敛闸门:本条路径只在 v=1/0 时才写入证明/证伪条目,中间裁决(flat 默认给出
|
|
2214
|
+
// 0.5,forced 给出加权浮点)会让 ap 停留在"中间布尔估计 + 两个列表皆空"的状态——
|
|
2215
|
+
// 而这正是 buildVerifyCandidates 认定"裸命题需要验证"的条件。若不在此标记,该命题
|
|
2216
|
+
// 会在每个 tick 重新入选、重开一轮完整辩论;又因 processVerify 每 tick 只跑一个验证,
|
|
2217
|
+
// 其它对象被无限饿死,终止条件(所有问题已解决)永不可达。标记后不再重复消耗验证配额,
|
|
2218
|
+
// 裁决值仍保留在 布尔估计 中。
|
|
2219
|
+
ap.已验证 = true
|
|
2220
|
+
if (v === 1) { ap.证明列表 = ap.证明列表 || []; ap.证明列表.push({ 完整过程: strongestReason(t, 1) || '判断问题解法验证通过', 正确概率: 1, '支持信息/依据': '经「判断下述命题是否成立」问题解法验证', 已验: true }); ap.优先级 = 'never' }
|
|
2221
|
+
else if (v === 0) { ap.证伪列表 = ap.证伪列表 || []; ap.证伪列表.push({ 完整过程: strongestReason(t, 0) || '判断问题解法判定不成立', 正确概率: 1, '支持信息/依据': '经「判断下述命题是否成立」问题解法验证', 已验: true }); ap.优先级 = 'never' }
|
|
2222
|
+
await upsertProposition(ap)
|
|
2223
|
+
await writeVerifiedCardIfNeeded(ap)
|
|
2224
|
+
logActivity('judge-sync', 'judge problem verdict ' + v + ' synced to proposition ' + ap.id)
|
|
2225
|
+
}
|
|
2101
2226
|
}
|
|
2102
2227
|
}
|
|
2103
2228
|
if (v === 1) { q.已解决 = true; q.优先级 = 'never'; await writeVerifiedProblemCardIfNeeded(q) }
|
|
@@ -263,12 +263,18 @@ v2 **没有会话投影**,所以记录与待办一起持久化在 v2 自己的
|
|
|
263
263
|
门禁与提示词取记录时两个方向都认(`formalGateRecord`),避免"代理确实形式化了,门禁却仍
|
|
264
264
|
按未尝试处理"的假阴性。
|
|
265
265
|
|
|
266
|
+
> **必须注意**:`syncVerificationTarget` 只更新**已经存在**的别名键,所以"归档写了对象 id、
|
|
267
|
+
> rId 侧还没有记录"是首次形式化后的**真实状态**。因此**门禁的判定**也必须走
|
|
268
|
+
> `formalGateRecord`(`deferForFormal`),不能只看 `formalOf(rId)`:否则一个已 `passed`
|
|
269
|
+
> 的对象会被判为未形式化,而且这次搁置本身会写下 `r-<id> = status:'none'`,此后每一轮都
|
|
270
|
+
> 继续搁置并重开一次完整辩论——对象**永远无法定论**(真实缺陷,已由套件第 13 节守住)。
|
|
271
|
+
|
|
266
272
|
### 五、三个工具
|
|
267
273
|
|
|
268
274
|
| 工具 | 作用 |
|
|
269
275
|
|---|---|
|
|
270
|
-
| `vibe_math_lean_run` | 在 `<VibeMath 根>` 内的一个 `.lean` 文件上执行工具链并原样回报:`{ok, exitCode, signal, ms, command, stdout, stderr, file}`;`target=<对象 id>` 时同时记录该对象的运行结果。**绝不向调度循环抛异常**:工具链缺失 → `LEAN_NOT_FOUND`;宿主无 `subprocess` 服务 → `NO_SUBPROCESS`;spawn 失败 → `LEAN_SPAWN_FAILED`;超时 → `LEAN_TIMEOUT` |
|
|
271
|
-
| `vibe_math_lean_archive` | `kind='def'` → 全局 `Formal/Lib/<name>.lean`;`kind='lemma'` → 全局 `Formal/Proved/<name>.lean`(两者都会重建对应 `Index.md`;`run:false` 可跳过执行)。`kind='proof'` → `Formal/<target>.lean`,且**该文件最近一次运行通过**时再写 `Verified/Lean/<target>.lean` 并把对象标为 `passed`,否则标为 `attempted`。`kind='blocked'` → 记录显式难度判断/阻塞原因(`note` 空 → 拒绝)并把对象标为 `blocked` |
|
|
276
|
+
| `vibe_math_lean_run` | 在 `<VibeMath 根>` 内的一个 `.lean` 文件上执行工具链并原样回报:`{ok, exitCode, signal, ms, command, stdout, stderr, file, timedOut}`;`target=<对象 id>` 时同时记录该对象的运行结果。**绝不向调度循环抛异常**:工具链缺失 → `LEAN_NOT_FOUND`;宿主无 `subprocess` 服务 → `NO_SUBPROCESS`;spawn 失败 → `LEAN_SPAWN_FAILED`;超时 → `LEAN_TIMEOUT`。**超时是主动的**(契约 §7):`handle.done` 与一个 `cap` 毫秒的计时器竞速,计时器到点时尽力调用 `handle.terminate()`,再给出可读的超时结果;`done` 先到就清掉计时器(不留悬挂 timer)。 |
|
|
277
|
+
| `vibe_math_lean_archive` | `kind='def'` → 全局 `Formal/Lib/<name>.lean`;`kind='lemma'` → 全局 `Formal/Proved/<name>.lean`(两者都会重建对应 `Index.md`;`run:false` 可跳过执行)。`kind='proof'` → `Formal/<target>.lean`,且**该文件最近一次运行通过**时再写 `Verified/Lean/<target>.lean` 并把对象标为 `passed`,否则标为 `attempted`。`kind='blocked'` → 记录显式难度判断/阻塞原因(`note` 空 → 拒绝)并把对象标为 `blocked`。`kind='def'/'lemma'` 的返回值在**运行未通过**时不得声称"可直接 import 复用"(工具返回值同样是代理读到的文字)。 |
|
|
272
278
|
| `vibe_math_lean_lib` | 扫描并重建三处索引(项目 `Formal/Index.md`、全局 `Lib/Index.md`、全局 `Proved/Index.md`),返回可复用库清单,供代理写新定义前查重;`refresh:false` 时只读不重建 |
|
|
273
279
|
|
|
274
280
|
参数 schema:
|
|
@@ -298,12 +304,18 @@ v2 **没有会话投影**,所以记录与待办一起持久化在 v2 自己的
|
|
|
298
304
|
|---|---|
|
|
299
305
|
| `verifierReviewPrompt(r)` | `formalPromptBlock(r.rId)`(非 off 档)+ 判定指引 |
|
|
300
306
|
| `verifierDebatePrompt(r, transcript)` | 同上——**辩论轮也必须带**,否则辩论阶段的代理会丢掉"审查对象已变成忠实性"这一变化 |
|
|
301
|
-
| `solverPrompt` / `explorerPrompt` / `rederivePrompt` | `formalWorkLine()`("顺手形式化",`off`
|
|
307
|
+
| `solverPrompt` / `explorerPrompt` / `rederivePrompt` | `formalWorkLine()`("顺手形式化",`off` 档为空串)。可复用库的路径写 **`<VibeMath 根>/Formal/Proved/`**(`Formal/Proved/` 在项目根下并不存在,只写相对路径会让代理去项目里找一个永远找不到的目录) |
|
|
302
308
|
| `vibe_math_status` / `vibe_math_report` / 卡片 / 索引 | 可读参数表、形式化记录概览、`- 形式化: <状态>` |
|
|
303
309
|
|
|
304
310
|
对象已 `passed` 时,验证提示词改为强调**忠实性审查**("你不需要重新检查推导");
|
|
305
311
|
已 `blocked` 时改为要求复核"这个阻塞判断是否成立"。
|
|
306
312
|
|
|
313
|
+
**忠实性分支里的"撤回"措辞必须与档位一致**(契约 §4.1 第 3 条 / §6.1):
|
|
314
|
+
`require` 档才有门禁,所以那里写"本次裁定**不定论**";
|
|
315
|
+
`encourage` 档**没有**门禁,撤回证明并不等于搁置裁定,那里必须写明
|
|
316
|
+
"**本档没有门禁**:框架不会强制搁置本次裁定——请务必给出弃权值,靠它阻止本轮得出布尔一致结论"。
|
|
317
|
+
承诺一个框架无法强制的"不定论",会让表决者以为不必自己弃权(审计清单 §1.7)。
|
|
318
|
+
|
|
307
319
|
### 八、门禁的实现位置
|
|
308
320
|
|
|
309
321
|
- **`writeVerifiedCardIfNeeded(p)`**(命题卡片)与 **`writeVerifiedProblemCardIfNeeded(q)`**
|
|
@@ -316,6 +328,15 @@ v2 **没有会话投影**,所以记录与待办一起持久化在 v2 自己的
|
|
|
316
328
|
- **`processStatusUpdates`**——概率=1 的**自动收口**路径。先申请卡片写入许可
|
|
317
329
|
(`writeVerifiedCardIfNeeded(p, target)` / `writeVerifiedProblemCardIfNeeded(q, true)`),
|
|
318
330
|
拿到许可才写入 `布尔估计` / `已解决` / `优先级`;被搁置则整条跳过。
|
|
331
|
+
- **门禁的判定记录一律取合并后的 `formalGateRecord`**(两套 id 都认,见 §四):
|
|
332
|
+
`deferForFormal` 内部即如此。只看 `formalOf(rId)` 会让"代理用对象 id 归档 passed、rId 侧
|
|
333
|
+
还没有记录"这种首次形式化的真实状态被判成未形式化。
|
|
334
|
+
- **`settleVerdict` 的「判断命题」转移路径**(`'problem-solution'` 且 `q.判断命题 && !sol.来源列表`):
|
|
335
|
+
它把**源命题**的 `布尔估计` 直接写成 0/1、置 `优先级 = 'never'` 并标记 `已验证`
|
|
336
|
+
(此后不再入选验证),这是一次对源命题的布尔裁定;因此对 `v === 1 || v === 0` 必须先
|
|
337
|
+
`deferForFormal(ap.id, …)`,被搁置时源命题的概率/优先级/已验证字段**分毫不动**。
|
|
338
|
+
(v=1 会被上面那道门禁拦下,v=0 不会——只拦卡片而忽略返回值,会让一个未形式化的命题
|
|
339
|
+
被侧面判为"假"并永久退出调度。真实缺陷,已由套件第 15 节守住。)
|
|
319
340
|
|
|
320
341
|
### 九、回执通道(`formal` 字段)与 `defect` 语义
|
|
321
342
|
|
|
@@ -332,7 +353,11 @@ v2 **没有会话投影**,所以记录与待办一起持久化在 v2 自己的
|
|
|
332
353
|
在三条解析回执的路径上都被调用:`handleVerifier`(验证者)、`handleSolver`、`handleExplorer`
|
|
333
354
|
(工作轮)。验证者路径里的调用**先于**裁定:`defect` 必须先把记录降级,紧随其后的
|
|
334
355
|
`settleVerdict` 才会在 `require` 档把本次裁定正确地记为未定论。
|
|
335
|
-
- `decision` 的落库:`blocked` → 记录 `blocked` + `note`;`defect` → 见 9.2
|
|
356
|
+
- `decision` 的落库:`blocked` → 记录 `blocked` + `note`;`defect` → 见 9.2;
|
|
357
|
+
`used` → `attempted` + `file`,**但若该对象(两个 id 空间任一)已经是 `passed`/`blocked`,则保持原状态**
|
|
358
|
+
——一次"这一轮碰了形式化"的 `used` 回执**不得**撤销已成立的证明:无条件写 `attempted` 会让投票提示词
|
|
359
|
+
丢掉忠实性分支、`require` 档对一份已跑通的归档证明重新关门,而 `proof` 指针还留着(记录自相矛盾)。
|
|
360
|
+
撤销证明只有 `defect` 一条路(契约 §4)。
|
|
336
361
|
- **拒绝规则**(返回 `V2_INVALID_ARGUMENT`,并在活动日志里公告,**不留下任何记录**):
|
|
337
362
|
`blocked`/`defect` 的 `note` 为空;缺 `target`(`safeId('')` 会返回 `anon`,绝不允许凭空造记录);
|
|
338
363
|
`decision` 不在三值之内。回执通道**绝不抛异常**进调度循环:一次记账失败不该吞掉一次表决。
|
|
@@ -351,8 +376,18 @@ v2 **没有会话投影**,所以记录与待办一起持久化在 v2 自己的
|
|
|
351
376
|
1. **表决者**:不得投 `1` 或 `0`;给一个严格介于 0 与 1 之间的值(记为弃权),在 `Reason` 里写清偏差,
|
|
352
377
|
并用回执 `formal:{decision:'defect', note:'<具体偏差>'}` 记录(`note` 必填)。
|
|
353
378
|
2. **框架**(`formalDefectDowngrade`):把形式化记录**降级为 `attempted`**(无论此前是 `passed`
|
|
354
|
-
还是 `blocked`)、清空 `proof
|
|
355
|
-
|
|
379
|
+
还是 `blocked`)、清空 `proof`、**撤回**归档证明(工作文件 `Formal/<id>.lean` 保留,代码不丢)、
|
|
380
|
+
`note` 记入记录与 `Formal/TODO.md`、在活动日志里公告。
|
|
381
|
+
|
|
382
|
+
「撤回」不是"尽力删除"(`withdrawArchivedProof`):
|
|
383
|
+
1. 先尽力删除(有 `subprocess` 时走 shell),并用 fs **复核真的没了**;
|
|
384
|
+
2. 删不掉(宿主无 `subprocess`、权限、`rm -f` 静默失败)时,把撤回通知**覆写进那个路径**
|
|
385
|
+
(`-- 已撤回(<时间>):该形式化被认定与命题原文不一致。` + 指向保留的工作文件),
|
|
386
|
+
使一份已撤回的证明**不可能**再被读成该对象的证明;
|
|
387
|
+
3. 活动日志如实说明发生了哪一种(删除 / 覆写成撤回通知 / ⚠ 两者都失败)。
|
|
388
|
+
候选路径 = **同一对象的全部 id 别名**(对象 id、`r-<id>`、`r-<id>-s0|pf<n>|rf<n>`)在记录里
|
|
389
|
+
引用的 `proof`,加上各 id 直接对应的 `Verified/Lean/<id>.lean`;只处理确实存在(或被记录引用)
|
|
390
|
+
的路径——宿主不能删除时"覆写"会把不存在的文件名**凭空造出来**。
|
|
356
391
|
3. **`require` 档**:降级后 `formalGateOk` 为假 ⇒ 本次裁定**不定论**(`formal-required`),
|
|
357
392
|
对象进入「形式化待办」。修正形式化并重新跑通后再投票。
|
|
358
393
|
4. **唯一可以投 0 的情形**:表决者**独立于这份 Lean 代码**也能确定命题为假(`Reason` 必须写清独立理由)。
|
|
@@ -398,4 +433,21 @@ v2 **没有会话投影**,所以记录与待办一起持久化在 v2 自己的
|
|
|
398
433
|
+ `proof` 清空 + `Verified/Lean/<id>.lean` 被删 + `Formal/TODO.md` 出现条目 + 公告),断言缺 `note`
|
|
399
434
|
被 `V2_INVALID_ARGUMENT` 拒绝且不落记录,断言 `defect` 之后 `require` 档**不得定论**(无 Verified 卡片、
|
|
400
435
|
命题布尔估计不变),并落盘人可读语料(§9.5)。
|
|
436
|
+
|
|
437
|
+
后续补强(同一套件):
|
|
438
|
+
|
|
439
|
+
- 第 4b 节:超时必须**主动**终止——mock 记录 `terminate()` 调用(`-- HANG` 文件模拟一个不会自己
|
|
440
|
+
结束的运行),断言返回 `LEAN_TIMEOUT` 且真的调用了 `terminate()`;并断言 `done` 先到时计时器
|
|
441
|
+
被清掉(套件用 test-only 的悬挂 `setTimeout` 计数;mock 自身的兜底用真实计时器,不污染计数)。
|
|
442
|
+
- 第 13 节:归档写在**对象 id**、`rId` 侧还没有记录时,`require` 档仍必须能定论(门禁读合并记录),
|
|
443
|
+
且该对象**不得**被写进「形式化待办」。
|
|
444
|
+
- 第 14 节:`defect` 的撤回覆盖**全部 id 别名**(归档写 `rId`、回执写对象 id 也能删干净);
|
|
445
|
+
宿主**不能删除**时(`{ noSubprocess: true }` 的宿主)归档路径必须不再包含原证明文本、并且带
|
|
446
|
+
撤回通知;活动日志必须说明"覆写"而不是"删除"。
|
|
447
|
+
- 第 15 节:`require` 档必须拦住「判断命题」问题解法到**源命题**的转移(`布尔估计` / `优先级` /
|
|
448
|
+
`已验证` / 概率=1 条目 / Verified 卡片全部不动,源命题进待办)。
|
|
449
|
+
- 模式相关的忠实性措辞:`encourage` 档**不得**出现"本次裁定**不定论**"(改写为"本档没有门禁"),
|
|
450
|
+
`require` 档**必须**出现(那里门禁真的会搁置裁定)。
|
|
451
|
+
- `kind='def'/'lemma'` 运行未通过时,工具返回值**不得**声称"可直接 import 复用"。
|
|
452
|
+
|
|
401
453
|
套件支持 `V2_PLUGIN` 环境变量指向变异副本,供灵敏度探针使用。
|