feat(goose-v149): add offline phase3 gate without real LLM calls
Memind CI / Test, build, and release guards (push) Has been cancelled

Block unattended DashScope smokes by default and provide a zero-token
merge verification entry via run-goosed-v149-phase3-offline.mjs.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
john
2026-09-09 22:10:19 +08:00
parent 67220a14ea
commit 2fa9523587
3 changed files with 141 additions and 4 deletions
+12 -2
View File
@@ -7,9 +7,19 @@
## 聚合验证入口
**默认(不消耗 LLM token):**
```bash
bash scripts/run-goosed-v149-local.sh # :18049 另开终端
node scripts/run-goosed-v149-phase3.mjs # Phase 2 + parity + drift
node scripts/run-goosed-v149-phase3-offline.mjs
```
通过时应输出 **`GOOSE_V149_PHASE3_OFFLINE_OK`**。
**完整 smoke(须用户明确批准 + DashScope 配额):**
```bash
GOOSE_V149_ALLOW_REAL_LLM=1 bash scripts/run-goosed-v149-local.sh # :18049 另开终端
GOOSE_V149_ALLOW_REAL_LLM=1 node scripts/run-goosed-v149-phase3.mjs
```
通过时应输出 **`GOOSE_V149_PHASE3_OK`**。
+8 -2
View File
@@ -37,8 +37,14 @@ GOOSE_V149_ALLOW_REAL_LLM=1 node scripts/check-goosed-v149-reply-smoke.mjs
## 推荐替代
- 合并前优先:`node --test scripts/goose-v149-canary.test.mjs``compare-goose-v149-message-sanitize.mjs``compare-goose-v149-memory-manifest.mjs`
- 必须验证 Portal 集成时:单次、有人值守、先确认 DashScope 配额
- **零 LLM 合并前验证**(默认推荐):
```bash
node scripts/run-goosed-v149-phase3-offline.mjs
```
- 单项:`node --test scripts/goose-v149-canary.test.mjs``compare-goose-v149-message-sanitize.mjs``compare-goose-v149-memory-manifest.mjs`
- 必须验证 Portal 集成时:单次、有人值守、先确认 DashScope 配额,且 `GOOSE_V149_ALLOW_REAL_LLM=1`
## 回滚 Canary
+121
View File
@@ -0,0 +1,121 @@
#!/usr/bin/env node
/**
* Phase 3 offline closeout: unit tests + manifest drift only (no real LLM).
* Use when DashScope quota is exhausted or unattended smokes must stay blocked.
*
* Full portal/page/memory smokes still require:
* GOOSE_V149_ALLOW_REAL_LLM=1 node scripts/run-goosed-v149-phase3.mjs
*/
import { spawnSync } from 'node:child_process';
import path from 'node:path';
import { fileURLToPath } from 'node:url';
import { prepareGooseV149CheckEnv } from './goose-v149-canary.mjs';
import { checkPassed, classifyCheckResult } from './goose-v149-check-result.mjs';
const root = path.join(path.dirname(fileURLToPath(import.meta.url)), '..');
const checkEnv = prepareGooseV149CheckEnv({ ...process.env }, root);
const checks = [
{
name: 'real-llm-gate-unit',
command: [process.execPath, '--test', 'scripts/goose-v149-real-llm-gate.test.mjs'],
required: true,
},
{
name: 'deepseek-parity',
command: [process.execPath, '--test', 'release-gate/deepseek-production-parity.test.mjs'],
required: true,
},
{
name: 'goose-canary-unit',
command: [process.execPath, '--test', 'scripts/goose-v149-canary.test.mjs'],
required: true,
},
{
name: 'memory-manifest-unit',
command: [process.execPath, '--test', 'scripts/compare-goose-v149-memory-manifest.test.mjs'],
required: true,
},
{
name: 'memory-drift',
script: 'compare-goose-v149-memory-manifest.mjs',
required: true,
},
{
name: 'memory-failopen',
script: 'check-goosed-v149-memory-failopen.mjs',
required: true,
},
{
name: 'context-runtime-unit',
command: [
process.execPath,
'--test',
'memind-headroom-policy.test.mjs',
'context-budget.test.mjs',
'recall-fusion.test.mjs',
'mcp-result-compactor.test.mjs',
],
required: true,
},
];
function runScript(script, extraEnv = {}) {
const result = spawnSync(process.execPath, [path.join(root, 'scripts', script)], {
cwd: root,
env: { ...checkEnv, ...extraEnv },
encoding: 'utf8',
});
return {
ok: checkPassed(result),
outcome: classifyCheckResult(result),
status: result.status,
stdout: result.stdout?.trim() ?? '',
stderr: result.stderr?.trim() ?? '',
};
}
function runCommand(command, extraEnv = {}) {
const [bin, ...args] = command;
const result = spawnSync(bin, args, {
cwd: root,
env: { ...checkEnv, ...extraEnv },
encoding: 'utf8',
});
return {
ok: checkPassed(result),
outcome: classifyCheckResult(result),
status: result.status,
stdout: result.stdout?.trim() ?? '',
stderr: result.stderr?.trim() ?? '',
};
}
function main() {
const results = [];
for (const check of checks) {
const item = {
...check,
...(check.script
? runScript(check.script, check.extraEnv ?? {})
: runCommand(check.command, check.extraEnv ?? {})),
};
results.push(item);
console.log(`[goose-v149-offline] ${item.outcome} ${check.name}`);
if (item.stdout) console.log(item.stdout);
if (!item.ok && item.stderr) console.error(item.stderr);
}
const failedRequired = results.filter((item) => item.required && !item.ok);
if (failedRequired.length) {
console.error(`GOOSE_V149_PHASE3_OFFLINE_FAIL: ${failedRequired.map((item) => item.name).join(', ')}`);
process.exit(1);
}
console.log('GOOSE_V149_PHASE3_OFFLINE_OK');
console.log(' note: portal/page/memory smokes skipped; see docs/goose-v149-real-llm-gate.md');
}
main();