dsh-vibe-math 2.7.1 → 2.7.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/README.en.md +682 -690
- package/README.md +19 -27
- package/cordis.patch.yml +112 -16
- package/docs/AUDIT-CHECKLIST.md +744 -518
- package/docs/COMPAT-AUDIT-ROUND2.md +35 -9
- package/docs/COMPAT-AUDIT-ROUND3.md +154 -154
- package/docs/final-paper.md +172 -172
- package/docs/formal-verification.md +588 -588
- package/docs/math-computation.md +194 -163
- package/docs/parameter-schema.md +37 -0
- package/docs/release-notes/README.en.md +49 -0
- package/docs/release-notes/README.md +48 -0
- package/docs/release-notes/RELEASE-NOTES-2.7.2.en.md +72 -0
- package/docs/release-notes/RELEASE-NOTES-2.7.2.md +72 -0
- package/docs/release-notes/RELEASE-NOTES-2.7.3.en.md +67 -0
- package/docs/release-notes/RELEASE-NOTES-2.7.3.md +67 -0
- package/docs/release-notes/TEMPLATE.md +126 -0
- package/docs/status-report-fields.md +167 -0
- package/docs/test-timing.md +157 -154
- package/installer.js +27 -17
- package/package.json +55 -3
- package/prompt-corpus-persona/persona-corpus.json +9 -9
- package/prompt-corpus-persona/persona-corpus.md +225 -33
- package/prompt-corpus-v2/formal-verify-v2.json +305 -113
- package/prompt-corpus-v2/formal-verify-v2.md +2399 -279
- package/prompt-corpus-v3/formal-verify-v3.json +134 -110
- package/prompt-corpus-v3/formal-verify-v3.md +409 -141
- package/prompt-corpus-v4/formal-verify-v4.json +18 -18
- package/prompt-corpus-v4/formal-verify-v4.md +49 -44
- package/prompt-corpus-v5/prompt-corpus-v5.json +82 -82
- package/prompt-corpus-v5/prompt-corpus-v5.md +513 -259
- package/scripts/update-doc-counts.mjs +71 -0
- package/tests/audit-artifact-docs.mjs +72 -0
- package/tests/audit-artifact-docs.mutants.mjs +58 -0
- package/tests/audit-installer-assertions.mutants.mjs +63 -0
- package/tests/audit-installer-compat.test.mjs +52 -4
- package/tests/audit-installer-policy.test.mjs +41 -8
- package/tests/audit-math-computation-contract.mjs +107 -9
- package/tests/audit-math-computation-contract.mutants.mjs +106 -0
- package/tests/audit-math-computation-parity.mjs +164 -3
- package/tests/audit-math-computation-sensitivity.mjs +6 -4
- package/tests/audit-package-membership.mjs +57 -0
- package/tests/audit-package-membership.mutants.mjs +28 -0
- package/tests/audit-participant-set-parity.mjs +160 -0
- package/tests/audit-path-discipline.mjs +83 -0
- package/tests/audit-path-discipline.mutants.mjs +51 -0
- package/tests/audit-persona-sensitivity.mjs +14 -0
- package/tests/audit-persona-surface.mutants.mjs +69 -0
- package/tests/audit-persona-surface.test.mjs +63 -22
- package/tests/audit-prompt-duplication.mjs +143 -0
- package/tests/audit-prompt-duplication.mutants.mjs +50 -0
- package/tests/audit-prompt-invariants.mjs +43 -5
- package/tests/audit-readme-bilingual.test.mjs +152 -0
- package/tests/audit-readme-counts.mjs +95 -0
- package/tests/audit-readme-counts.mutants.mjs +52 -0
- package/tests/audit-registration.mjs +78 -0
- package/tests/audit-status-report-fields.mjs +172 -0
- package/tests/audit-status-report-fields.mutants.mjs +64 -0
- package/tests/audit-v3-registration-parity.mjs +156 -0
- package/tests/audit-v5-integrity.mjs +300 -13
- package/tests/audit-v5-lean-abstention.mjs +392 -0
- package/tests/audit-v5-lean-abstention.mutants.mjs +106 -0
- package/tests/audit-v5-prompt-duplication.mjs +88 -0
- package/tests/audit-v5-prompt-duplication.mutants.mjs +34 -0
- package/tests/audit-v5-sensitivity.mjs +15 -8
- package/tests/e2e-identity-a6.mutants.mjs +65 -0
- package/tests/e2e-v5-round2.test.mjs +566 -12
- package/tests/formal-verify-v2.test.mjs +91 -5
- package/tests/formal-verify-v3.mutants.mjs +117 -0
- package/tests/formal-verify-v3.test.mjs +85 -6
- package/tests/formal-verify-v4.mutants.mjs +152 -0
- package/tests/formal-verify-v4.test.mjs +628 -9
- package/tests/formal-verify-v5.test.mjs +68 -9
- package/tests/helpers/doc-counts-format.mjs +41 -0
- package/tests/helpers/math-computation-fake-seam.mjs +4 -0
- package/tests/math-computation-a1.mutants.mjs +72 -0
- package/tests/math-computation-archive-rerun.mutants.mjs +65 -0
- package/tests/math-computation-discovery.mutants.mjs +76 -0
- package/tests/math-computation-shared.test.mjs +396 -2
- package/tests/math-computation-v2.test.mjs +767 -0
- package/tests/math-computation-v3.test.mjs +759 -0
- package/tests/math-computation-v4.mutants.mjs +133 -0
- package/tests/math-computation-v4.test.mjs +739 -0
- package/tests/prompt-v5-integrity.test.mjs +13 -2
- package/tests/run-tests.mjs +139 -9
- package/tests/run-tests.mutants.mjs +70 -0
- package/tests/selfdrive-v5.mjs +53 -1
- package/tests/selfdrive-v5.mutants.mjs +132 -0
- package/tests/v2-fix-probes.mutants.mjs +100 -0
- package/tests/v2-fix-probes.test.mjs +1039 -0
- package/tests/v2-list-agents-and-next-step.mutants.mjs +106 -0
- package/tests/v3-fix-probes.mutants.mjs +95 -0
- package/tests/v3-fix-probes.test.mjs +891 -0
- package/tests/v5-institute-fixes.mutants.mjs +190 -0
- package/vibe-math-v2/agent.cordis.yml +62 -6
- package/vibe-math-v2/math-computation.js +229 -29
- package/vibe-math-v2/math-engines.js +12 -12
- package/vibe-math-v2/vibe-math-v2.js +458 -119
- package/vibe-math-v2//345/256/236/347/216/260/346/226/271/346/241/210.md +5 -1
- package/vibe-math-v3/agent.cordis.yml +72 -6
- package/vibe-math-v3/math-computation.js +229 -29
- package/vibe-math-v3/math-engines.js +12 -12
- package/vibe-math-v3/vibe-math-v3.js +482 -139
- package/vibe-math-v4/agent.cordis.yml +44 -8
- package/vibe-math-v4/math-computation.js +229 -29
- package/vibe-math-v4/math-engines.js +12 -12
- package/vibe-math-v4/vibe-math-v4.js +245 -52
- package/vibe-math-v4//345/256/236/347/216/260/346/226/271/346/241/210.md +2 -0
- package/vibe-math-v5/agent.cordis.yml +46 -12
- package/vibe-math-v5/math-computation.js +229 -29
- package/vibe-math-v5/math-engines.js +12 -12
- package/vibe-math-v5/vibe-math-v5.js +1307 -243
- package/vibe-math-v5//345/256/236/347/216/260/346/226/271/346/241/210.md +1728 -1655
- package/vibe-math-v5//346/236/266/346/236/204/345/233/276.md +693 -693
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Mutant harness for the two v2 harness-gap rows (ships: `tests/*.mutants.mjs`):
|
|
4
|
+
* F3 v2 `vibe_math_list_agents` — the tool must EXIST and be MENTIONED
|
|
5
|
+
* F4 v2 require-gate — a refusal must carry an EXECUTABLE NEXT STEP
|
|
6
|
+
*
|
|
7
|
+
* Each case copies the v2 preset (and, for the persona case, all four preset dirs) into a private root,
|
|
8
|
+
* applies ONE logical mutation, drives the SHIPPED owning suite through its own seam, and requires a NAMED
|
|
9
|
+
* red. Every target suite also runs GREEN on the unmutated copies first (faithful-copy baseline), so the
|
|
10
|
+
* mutation is the only red cause. Seams used: MC_V2_PLUGIN, V2_PLUGIN, PERSONA_ROOT.
|
|
11
|
+
*
|
|
12
|
+
* Run: node tests/v2-list-agents-and-next-step.mutants.mjs
|
|
13
|
+
*/
|
|
14
|
+
import { mkdtempSync, cpSync, copyFileSync, readFileSync, writeFileSync, rmSync } from 'node:fs'
|
|
15
|
+
import { tmpdir } from 'node:os'
|
|
16
|
+
import { join } from 'node:path'
|
|
17
|
+
import { spawnSync } from 'node:child_process'
|
|
18
|
+
import { fileURLToPath } from 'node:url'
|
|
19
|
+
|
|
20
|
+
const HERE = fileURLToPath(new URL('./', import.meta.url))
|
|
21
|
+
const REPO = join(HERE, '..')
|
|
22
|
+
const PRESETS = ['vibe-math-v2', 'vibe-math-v3', 'vibe-math-v4', 'vibe-math-v5']
|
|
23
|
+
let passed = 0, failed = 0
|
|
24
|
+
const ok = (c, l, d) => { if (c) { passed++; console.log(' ok ' + l) } else { failed++; console.log(' FAIL ' + l + (d ? ' — ' + d : '')) } }
|
|
25
|
+
|
|
26
|
+
function runSuite(file, env) {
|
|
27
|
+
const r = spawnSync(process.execPath, [join(HERE, file)], { cwd: REPO, encoding: 'utf8', maxBuffer: 1 << 26, env: Object.assign({}, process.env, env || {}) })
|
|
28
|
+
const o = String(r.stdout || '') + String(r.stderr || '')
|
|
29
|
+
return {
|
|
30
|
+
status: r.status, out: o,
|
|
31
|
+
failLines: o.split('\n').filter((l) => /^\s*(FAIL| FAIL)\b/.test(l)),
|
|
32
|
+
sum: (o.split('\n').filter((l) => /passed, \d+ failed/.test(l)).slice(-1)[0] || '').trim(),
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
const named = (r, needle) => r.failLines.some((l) => l.indexOf(needle) !== -1)
|
|
36
|
+
const V2_SRC = join(REPO, 'vibe-math-v2', 'vibe-math-v2.js')
|
|
37
|
+
const ORIGIN = readFileSync(V2_SRC, 'utf8')
|
|
38
|
+
const REGISTER = "registerTool('vibe_math_list_agents'"
|
|
39
|
+
const NEXT_STEP = '下一步:把该对象形式化到 Lean 通过'
|
|
40
|
+
const COPY_AS = 'vibe_math_list_agentsX'
|
|
41
|
+
|
|
42
|
+
// ---------- baselines: the shipped suites are green on the COPIED artifacts ----------
|
|
43
|
+
const baseRoot = mkdtempSync(join(tmpdir(), 'v2gaps-base-'))
|
|
44
|
+
cpSync(join(REPO, 'vibe-math-v2'), join(baseRoot, 'vibe-math-v2'), { recursive: true })
|
|
45
|
+
{
|
|
46
|
+
const a = runSuite('math-computation-v2.test.mjs', { MC_V2_PLUGIN: join(baseRoot, 'vibe-math-v2', 'vibe-math-v2.js') })
|
|
47
|
+
ok(a.status === 0, 'baseline: math-computation-v2 is green on the COPIED v2 preset (MC_V2_PLUGIN)', a.sum.slice(0, 60))
|
|
48
|
+
const c = runSuite('v2-fix-probes.test.mjs', { V2_PLUGIN: join(baseRoot, 'vibe-math-v2', 'vibe-math-v2.js') })
|
|
49
|
+
ok(c.status === 0, 'baseline: v2-fix-probes is green on the COPIED v2 preset (V2_PLUGIN)', c.sum.slice(0, 60))
|
|
50
|
+
}
|
|
51
|
+
{
|
|
52
|
+
const pRoot = mkdtempSync(join(tmpdir(), 'v2gaps-persona-'))
|
|
53
|
+
for (const d of PRESETS) cpSync(join(REPO, d), join(pRoot, d), { recursive: true })
|
|
54
|
+
const p = runSuite('audit-persona-surface.test.mjs', { PERSONA_ROOT: pRoot })
|
|
55
|
+
ok(p.status === 0, 'baseline: audit-persona-surface is green on the COPIED preset tree (PERSONA_ROOT)', p.sum.slice(0, 60))
|
|
56
|
+
rmSync(pRoot, { recursive: true, force: true })
|
|
57
|
+
}
|
|
58
|
+
rmSync(baseRoot, { recursive: true, force: true })
|
|
59
|
+
|
|
60
|
+
// ---------- F3a: the tool must EXIST (rename the registration -> the documented call fails) ----------
|
|
61
|
+
{
|
|
62
|
+
const dir = mkdtempSync(join(tmpdir(), 'v2gaps-exist-'))
|
|
63
|
+
cpSync(join(REPO, 'vibe-math-v2'), join(dir, 'vibe-math-v2'), { recursive: true })
|
|
64
|
+
const p = join(dir, 'vibe-math-v2', 'vibe-math-v2.js')
|
|
65
|
+
const src = readFileSync(p, 'utf8')
|
|
66
|
+
writeFileSync(p, src.replace(REGISTER, REGISTER.replace('list_agents', 'list_agentsX')))
|
|
67
|
+
const r = runSuite('math-computation-v2.test.mjs', { MC_V2_PLUGIN: p })
|
|
68
|
+
ok(r.status !== 0 && named(r, '对照:vibe_math_list_agents 可调用'),
|
|
69
|
+
'★ F3 (exists): renaming the registration reddens the named "list_agents is callable" assertion (unit: tool name)',
|
|
70
|
+
r.sum.slice(0, 70))
|
|
71
|
+
if (!named(r, '对照:vibe_math_list_agents 可调用')) for (const l of r.failLines.slice(0, 3)) console.log(' ' + l.trim().slice(0, 130))
|
|
72
|
+
rmSync(dir, { recursive: true, force: true })
|
|
73
|
+
}
|
|
74
|
+
// ---------- F3b: the tool must be MENTIONED (persona still names the old name) ----------
|
|
75
|
+
{
|
|
76
|
+
const root = mkdtempSync(join(tmpdir(), 'v2gaps-mention-'))
|
|
77
|
+
for (const d of PRESETS) cpSync(join(REPO, d), join(root, d), { recursive: true })
|
|
78
|
+
const p = join(root, 'vibe-math-v2', 'vibe-math-v2.js')
|
|
79
|
+
writeFileSync(p, readFileSync(p, 'utf8').split(REGISTER).join(REGISTER.replace('list_agents', 'list_agentsX')))
|
|
80
|
+
const r = runSuite('audit-persona-surface.test.mjs', { PERSONA_ROOT: root })
|
|
81
|
+
ok(r.status !== 0 && named(r, 'every registered tool is mentioned in the persona, or explicitly allow-listed'),
|
|
82
|
+
'★ F3 (mentioned): a registered tool the persona never names reddens the named allow-list assertion (unit: registered tool names)',
|
|
83
|
+
r.sum.slice(0, 70))
|
|
84
|
+
if (!named(r, 'every registered tool is mentioned in the persona, or explicitly allow-listed')) for (const l of r.failLines.slice(0, 3)) console.log(' ' + l.trim().slice(0, 130))
|
|
85
|
+
rmSync(root, { recursive: true, force: true })
|
|
86
|
+
}
|
|
87
|
+
// ---------- F4: a require-gate refusal must carry an executable NEXT STEP ----------
|
|
88
|
+
{
|
|
89
|
+
const dir = mkdtempSync(join(tmpdir(), 'v2gaps-next-'))
|
|
90
|
+
cpSync(join(REPO, 'vibe-math-v2'), join(dir, 'vibe-math-v2'), { recursive: true })
|
|
91
|
+
const p = join(dir, 'vibe-math-v2', 'vibe-math-v2.js')
|
|
92
|
+
const src = readFileSync(p, 'utf8')
|
|
93
|
+
if (src.indexOf(NEXT_STEP) === -1) ok(false, 'F4: the single-site next-step anchor applies', 'ANCHOR MISS')
|
|
94
|
+
else {
|
|
95
|
+
writeFileSync(p, src.replace(NEXT_STEP, '下一步:见文档'))
|
|
96
|
+
const r = runSuite('v2-fix-probes.test.mjs', { V2_PLUGIN: p })
|
|
97
|
+
ok(r.status !== 0 && named(r, 'require-gate 反馈行携带下一步'),
|
|
98
|
+
'★ F4: dropping the executable next step from the require-gate refusal reddens its named assertion (unit: refusal sites)',
|
|
99
|
+
r.sum.slice(0, 70))
|
|
100
|
+
if (!named(r, 'require-gate 反馈行携带下一步')) for (const l of r.failLines.slice(0, 3)) console.log(' ' + l.trim().slice(0, 130))
|
|
101
|
+
}
|
|
102
|
+
rmSync(dir, { recursive: true, force: true })
|
|
103
|
+
}
|
|
104
|
+
console.log('')
|
|
105
|
+
console.log('=== V2 LIST-AGENTS / NEXT-STEP MUTANTS: ' + passed + ' passed, ' + failed + ' failed ===')
|
|
106
|
+
process.exit(failed === 0 ? 0 : 1)
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
// Registered mutant harness for tests/v3-fix-probes.test.mjs — the probe carries its own proof.
|
|
2
|
+
// Defect class covered: silent-failure surfacing (F6a/F6b/F6c), cap sharing (F2cap), declared asymmetry (F-A),
|
|
3
|
+
// fence-root drift (F5), shell-fallback silence (F4c). Every family is a SINGLE content-anchored mutation
|
|
4
|
+
// of the v3 preset (no line numbers) and the suite runs through its V3_PLUGIN seam.
|
|
5
|
+
// Exit criterion (audit-path-discipline.mutants.mjs paradigm): every family must redden BY NAME;
|
|
6
|
+
// ALL MUTANTS RED AS REQUIRED + exit 0 only when all do.
|
|
7
|
+
// Run: node tests/v3-fix-probes.mutants.mjs
|
|
8
|
+
import { readFileSync, writeFileSync, mkdirSync, copyFileSync, rmSync, readdirSync } from 'node:fs'
|
|
9
|
+
import { execFileSync } from 'node:child_process'
|
|
10
|
+
import { dirname, join } from 'node:path'
|
|
11
|
+
import { tmpdir } from 'node:os'
|
|
12
|
+
import { fileURLToPath } from 'node:url'
|
|
13
|
+
const HERE = dirname(fileURLToPath(import.meta.url))
|
|
14
|
+
const REPO = join(HERE, '..')
|
|
15
|
+
const PRESET = 'vibe-math-v3'
|
|
16
|
+
const SUITE = 'tests/v3-fix-probes.test.mjs'
|
|
17
|
+
const ENV = 'V3_PLUGIN'
|
|
18
|
+
// Bound every child run: run-tests has no per-suite timeout, so an unbounded child hangs the whole gate.
|
|
19
|
+
// A timeout is reported as HANG, counts as a failure for that family, and is listed in hangs=[].
|
|
20
|
+
const CHILD_TIMEOUT_MS = Number(process.env.MUTANT_CHILD_TIMEOUT_MS || 120000)
|
|
21
|
+
const TIMES = []
|
|
22
|
+
// R15: whole-process wall time, printed at the end (the timeout row quotes this line).
|
|
23
|
+
const START_MS = Date.now()
|
|
24
|
+
const hangs = []
|
|
25
|
+
let lastHang = false
|
|
26
|
+
function copyGraph(file, dest) {
|
|
27
|
+
const src = join(REPO, PRESET, file)
|
|
28
|
+
copyFileSync(src, join(dest, file))
|
|
29
|
+
for (const m of readFileSync(src, 'utf8').matchAll(/from\s+'(\.\/[A-Za-z0-9_.-]+\.js)'/g)) {
|
|
30
|
+
const dep = m[1].slice(2)
|
|
31
|
+
if (!readdirSync(dest).includes(dep)) copyGraph(dep, dest)
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
function runFamily(f) {
|
|
35
|
+
const dest = join(tmpdir(), 'v3probes-mut-' + Math.random().toString(36).slice(2, 10))
|
|
36
|
+
mkdirSync(dest, { recursive: true })
|
|
37
|
+
copyGraph(PRESET + '.js', dest)
|
|
38
|
+
const target = join(dest, f.editFile || (PRESET + '.js'))
|
|
39
|
+
const before = readFileSync(target, 'utf8')
|
|
40
|
+
const n = before.split(f.from).length - 1
|
|
41
|
+
if (f.lastOnly ? n < 1 : n !== 1) { console.error(' NO-OP - ' + f.name + ' (anchor x' + n + (f.lastOnly ? ', lastOnly' : '') + ')'); rmSync(dest, { recursive: true, force: true }); return false }
|
|
42
|
+
const mutated = f.lastOnly
|
|
43
|
+
? (() => { const i = before.lastIndexOf(f.from); return before.slice(0, i) + f.to + before.slice(i + f.from.length) })()
|
|
44
|
+
: before.split(f.from).join(f.to)
|
|
45
|
+
writeFileSync(target, mutated, 'utf8')
|
|
46
|
+
try { execFileSync(process.execPath, ['--check', target], { stdio: 'pipe' }) }
|
|
47
|
+
catch (e) { writeFileSync(target, before, 'utf8'); console.error(' FAIL - ' + f.name + ' (mutation did not compile; restored)'); rmSync(dest, { recursive: true, force: true }); return false }
|
|
48
|
+
let out = ''
|
|
49
|
+
let code = 0
|
|
50
|
+
try { out = execFileSync(process.execPath, [SUITE], { cwd: REPO, encoding: 'utf8', timeout: CHILD_TIMEOUT_MS, killSignal: 'SIGKILL', env: Object.assign({}, process.env, { [ENV]: join(dest, PRESET + '.js') }) }) }
|
|
51
|
+
catch (e) { if (e && (e.killed || e.signal === 'SIGKILL')) lastHang = true; code = (e && e.status) || 1; out = String((e && e.stdout) || '') + String((e && e.stderr) || '') }
|
|
52
|
+
const named = out.split(/\r?\n/).filter((l) => /^\s*(FAIL - | {2}- )/.test(l) && f.expect.test(l)).map((l) => l.trim())
|
|
53
|
+
const ok = !lastHang && code !== 0 && named.length > 0
|
|
54
|
+
console.log((lastHang ? ' HANG - ' : (ok ? ' ok - ' : ' FAIL - ')) + f.name + (named.length ? ' :: ' + named[0].slice(0, 140) : ' :: no named red (exit=' + code + ')'))
|
|
55
|
+
rmSync(dest, { recursive: true, force: true })
|
|
56
|
+
return ok
|
|
57
|
+
}
|
|
58
|
+
const FAMILIES = [
|
|
59
|
+
{ name: 'F2cap: status site reverted to a literal 10', expect: /\[F2cap\] status 与 report 两处都走同一常量/,
|
|
60
|
+
from: "recentActivity: activityLog.slice(-Math.min(ACTIVITY_REPORT_MAX, Number(params.activityLogCap) || 100)), params: params,",
|
|
61
|
+
to: "recentActivity: activityLog.slice(-Math.min(10, Number(params.activityLogCap) || 100)), params: params," },
|
|
62
|
+
{ name: 'F2cap: param description hard-codes the number', expect: /\[F2cap\] 参数描述\*\*引用\*\*该常量/,
|
|
63
|
+
from: "' + ACTIVITY_REPORT_MAX + ' 条)', suggestion: 100 },", to: "' + 30 + ' 条)', suggestion: 100 }," },
|
|
64
|
+
{ name: 'F-A: status gains pendingDecisionItems', expect: /\[F-A\] status \*\*不得\*\*携带明细/,
|
|
65
|
+
from: "pendingDecisions: decisionQueue.filter(function (d) { return d.status === 'pending' }).length,",
|
|
66
|
+
to: "pendingDecisions: decisionQueue.filter(function (d) { return d.status === 'pending' }).length,\n pendingDecisionItems: decisionQueue.filter(function (d) { return d.status === 'pending' }).map(function (d) { return { id: d.id, node: d.node, context: d.context } }),",
|
|
67
|
+
lastOnly: true },
|
|
68
|
+
{ name: 'F5: fence-root comparison removed', expect: /\[F5\/v3\] 围栏根漂移/,
|
|
69
|
+
from: 'if (actual && expected && actual !== expected) warnFenceDriftOnce(actual, expected)', to: 'void actual' },
|
|
70
|
+
{ name: 'F4c: ensureDirs failure warning removed', expect: /\[F4c\] ensureDirs 失败不是沉默/,
|
|
71
|
+
from: "if (!r || !r.ok) warnShellOnce('ensureDirs (mkdir ' + base + ')', r)", to: 'void r' },
|
|
72
|
+
{ name: 'F6a: provider list-failure warning removed', expect: /\[F6a\/v3\]/,
|
|
73
|
+
from: "warnProviderFallback('subagents.list() failed: ' + ((e && e.message) || e))", to: 'void e' },
|
|
74
|
+
{ name: 'F6b: interrupt emit statement deleted (anchored by content)', expect: /\[F6b\/v3\]/,
|
|
75
|
+
from: "if (r && r.ok === false) logActivity('interrupt', '中断失败(' + why + '):' + String(cid) + ' — ' + String(r.message || r.code || ''))", to: 'void r' },
|
|
76
|
+
{ name: 'F6c: project-pointer write failure re-silenced', expect: /\[F6c\/v3\]/,
|
|
77
|
+
from: "noteStateWriteFailure('current.' + safeId(sessionId) + '.json', (e && e.message) || e)", to: 'void e' },
|
|
78
|
+
]
|
|
79
|
+
let red = 0
|
|
80
|
+
FAMILIES.push(
|
|
81
|
+
{ name: 'F-B: derivation drops the source descriptions', expect: /\[F-B\/v3\] 每个机读描述都来自真源且非空/,
|
|
82
|
+
from: 'if (e.description) p.description = e.description', to: 'void e /* MUTANT F-B: no source description */' },
|
|
83
|
+
{ name: 'F-B: one exception entry deleted', expect: /\[F-B\/v3\] 例外集合 == docs\/parameter-schema\.md/,
|
|
84
|
+
from: "mode: { type: 'string', enum: ['manual', 'auto'] },", to: '' },
|
|
85
|
+
{ name: 'F-B: one registration site reverted to a literal', expect: /\[F-B\/v3\] 两处注册点都由 paramProps\(\)/,
|
|
86
|
+
from: "objParams(paramProps()), 'vibe_math_set_params')", to: "objParams({ mode: { type: 'string', enum: ['manual', 'auto'] } }), 'vibe_math_set_params')" },
|
|
87
|
+
)
|
|
88
|
+
for (const f of FAMILIES) { const t0 = Date.now(); lastHang = false; const ok = runFamily(f); const ms = Date.now() - t0; TIMES.push([f.name, ms]); if (lastHang) hangs.push(f.name + '(' + Math.round(ms / 1000) + 's)'); if (ok) red++ }
|
|
89
|
+
console.log('')
|
|
90
|
+
console.log('mutant families reddening the v3 probe by name: ' + red + '/' + FAMILIES.length)
|
|
91
|
+
console.log('timings: ' + TIMES.map((t) => String(t[0]).split(':')[0] + '=' + t[1] + 'ms').join(' '))
|
|
92
|
+
console.log('TOTAL WALL TIME (all families + setup): ' + (Date.now() - START_MS) + 'ms (' + Math.round((Date.now() - START_MS) / 1000) + 's)')
|
|
93
|
+
console.log('hangs=[' + hangs.join(' | ') + ']')
|
|
94
|
+
if (red !== FAMILIES.length || hangs.length) process.exit(1)
|
|
95
|
+
console.log('ALL MUTANTS RED AS REQUIRED')
|