/** * 「人类的说明必须到达模型」—— dsh 桥的接线判据(2026-09-13 线上缺陷)。 * * 缺陷现场:人类在界面上拒绝一条 bash 请求并写「我说了让你拉取仓库到program下你 * 听不懂吗」,而桥只把 `决策` 一个词给模型(`note` 在 SSE 回包里没人读)⇒ 模型把 * 同一条命令换个写法又问一遍(连问 9 次)。 * * # 为什么验源码形态 * * dsh 桥的入口是 Cordis 插件工厂,不是可导入的模块(拉起来要整个 Cordis 运行时), * 而这里要钉住的只有一件事:**那个 note 还在、且落在给模型的那句话上**。 * 与 pi 桥同源的那条注释是"接线缺口纯函数测不出来"的教训。 */ import { test } from 'node:test'; import assert from 'node:assert/strict'; import { readFileSync } from 'node:fs'; import { dirname, join } from 'node:path'; import { fileURLToPath } from 'node:url'; const HERE = dirname(fileURLToPath(import.meta.url)); const SRC = readFileSync(join(HERE, '..', 'src', 'index.ts'), 'utf8'); test('权限结论的提示词带上了人类的说明', () => { const fn = SRC.match(/function permissionPrompt\(data: any\): string \{[\s\S]*?\n\}/); assert.ok(fn, 'permissionPrompt 必须存在'); assert.match(fn[0], /note/, '提示词里必须用到 note'); assert.match(fn[0], /用户的说明/, '要显式写成"用户的说明:…",模型才认得出这是人的要求'); }); test('★ 只有一处拼"已有结论"(三处调用点都走同一个 helper)', () => { const hits = [...SRC.matchAll(/你之前发起的权限请求已有结论/g)]; assert.equal(hits.length, 1, `应只有 helper 内部那一处,实际 ${hits.length} 处(分叉就是漏信息的地方)`); assert.match(SRC, /permissionPrompt\(data\)/, '调用点必须用 helper'); }); test('决策回执不再被当成新任务,且记成已交付', () => { assert.match(SRC, /mail_type === 'permission_decision'/, 'new_mail 分支要认得决策回执'); assert.match(SRC, /deliveredMails\.add\(String\(data\.decision_mail_id\)\)/, '收到决策时要记下 decision_mail_id'); }); test('平台回执带不了理由 → 带说明的决策要另投一趟通知', () => { assert.match(SRC, /data\.note\.trim\(\)\)/, '有说明时才另投(空说明不投)'); }); test('★ 判据自检:拿缺陷时的源码形态喂进来必须判红', () => { const old = "return `你之前发起的权限请求已有结论:${data.decision}(决策人:${data.decided_by})。请据此继续后续工作。`;"; assert.equal(/你之前发起的权限请求已有结论/g.test(old), true); assert.equal(/用户的说明/.test(old), false, '旧形态里没有"用户的说明" ⇒ 上面那条断言会判红'); assert.equal([...old.matchAll(/你之前发起的权限请求已有结论/g)].length, 1); });