1. 时间映射审计: 遍历136个大脑文件,发现54个严重过期 2. 修复 domain-manifest.json (D96→D109): 删除过期服务器状态,指向gatekeeper 3. 修复 ferry-boat.json (D96→D109): 更新物理锚点 4. 新增 brain/awakening-checkpoints.json: 8个校验点(CK-000~CK-007) 5. 新增 scripts/verify-cognition.js: 自动校验脚本 6. 改造 walk-the-path.md: 新增第0步(时间锚定),嵌入校验点 7. 更新 temporal-brain.json: 补充D109事件+time_anchor
299 lines
11 KiB
JavaScript
299 lines
11 KiB
JavaScript
#!/usr/bin/env node
|
||
/**
|
||
* ═══════════════════════════════════════════════════════════
|
||
* 🧠 铸渊认知校验脚本 · Cognition Verifier v1.0
|
||
* ═══════════════════════════════════════════════════════════
|
||
*
|
||
* 用途: 唤醒时自动校验大脑文件时效性 + 服务器状态
|
||
* 用法:
|
||
* node scripts/verify-cognition.js --check-staleness 文件时效性检查
|
||
* node scripts/verify-cognition.js --check-servers 服务器状态验证
|
||
* node scripts/verify-cognition.js --full 全量校验
|
||
* node scripts/verify-cognition.js --checkpoint <CK-ID> 单个校验点
|
||
*
|
||
* 版权: 国作登字-2026-A-00037559 · TCS-0002∞
|
||
*/
|
||
|
||
const http = require('http');
|
||
const fs = require('fs');
|
||
const path = require('path');
|
||
const { execSync } = require('child_process');
|
||
|
||
const BRAIN_DIR = path.join(__dirname, '..', 'brain');
|
||
const NOW = new Date();
|
||
const NOW_STR = NOW.toISOString().slice(0, 10);
|
||
|
||
// ═══════════════════════════════════════════════════════════
|
||
// 辅助函数
|
||
// ═══════════════════════════════════════════════════════════
|
||
|
||
function daysAgo(dateStr) {
|
||
try {
|
||
const m = dateStr.match(/(\d{4}-\d{2}-\d{2})/);
|
||
if (!m) return null;
|
||
const d = new Date(m[1]);
|
||
const diff = Math.floor((NOW - d) / (1000*60*60*24));
|
||
return diff;
|
||
} catch(e) { return null; }
|
||
}
|
||
|
||
function stalenessLabel(days) {
|
||
if (days === null) return '❓ 未标注';
|
||
if (days <= 1) return '✅ 最新';
|
||
if (days <= 3) return '🟡 近日';
|
||
if (days <= 7) return '🟠 一周前';
|
||
if (days <= 30) return '🔴 一个月前';
|
||
return '⚫ 严重过期';
|
||
}
|
||
|
||
function extractTimestamps(filePath) {
|
||
try {
|
||
const text = fs.readFileSync(filePath, 'utf-8');
|
||
const ts = text.match(/"(_?updated|last_updated|created|_created|updated_at|created_at)"\s*:\s*"([^"]+)"/);
|
||
if (ts) return ts[2];
|
||
const d = text.match(/(\d{4}-\d{2}-\d{2})/);
|
||
return d ? d[1] : null;
|
||
} catch(e) { return null; }
|
||
}
|
||
|
||
function extractDVersion(filePath) {
|
||
try {
|
||
const text = fs.readFileSync(filePath, 'utf-8');
|
||
const d = text.match(/\b(D\d{2,3})\b/);
|
||
return d ? d[1] : null;
|
||
} catch(e) { return null; }
|
||
}
|
||
|
||
// ═══════════════════════════════════════════════════════════
|
||
// 1. 文件时效性检查
|
||
// ═══════════════════════════════════════════════════════════
|
||
|
||
function checkStaleness() {
|
||
console.log('\n' + '='.repeat(60));
|
||
console.log('📋 文件时效性检查');
|
||
console.log('='.repeat(60));
|
||
|
||
const results = [];
|
||
const brainFiles = [];
|
||
|
||
function walk(dir) {
|
||
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
||
for (const e of entries) {
|
||
const p = path.join(dir, e.name);
|
||
if (e.isDirectory() && !e.name.startsWith('.') && e.name !== 'node_modules' && e.name !== 'archive') walk(p);
|
||
else if (e.name.endsWith('.json') || e.name.endsWith('.md')) brainFiles.push(p);
|
||
}
|
||
}
|
||
walk(BRAIN_DIR);
|
||
|
||
for (const fp of brainFiles) {
|
||
const rel = path.relative(path.join(__dirname, '..'), fp);
|
||
const ts = extractTimestamps(fp);
|
||
const dv = extractDVersion(fp);
|
||
const days = daysAgo(ts);
|
||
const label = stalenessLabel(days);
|
||
results.push({ file: rel, timestamp: ts, d_version: dv, days, label });
|
||
}
|
||
|
||
// Sort by staleness (most stale first)
|
||
results.sort((a, b) => (b.days || 999) - (a.days || 999));
|
||
|
||
const counts = {};
|
||
for (const r of results) {
|
||
counts[r.label] = (counts[r.label] || 0) + 1;
|
||
}
|
||
|
||
console.log(`\n📊 大脑文件总数: ${results.length}`);
|
||
console.log('时效分布:');
|
||
for (const [label, count] of Object.entries(counts).sort()) {
|
||
console.log(` ${label}: ${count} 个`);
|
||
}
|
||
|
||
console.log('\n⚠️ 严重过期的文件:');
|
||
let staleCount = 0;
|
||
for (const r of results) {
|
||
if (r.label.startsWith('⚫') || r.label.startsWith('🔴')) {
|
||
if (staleCount < 20) {
|
||
console.log(` ${r.label} ${r.file} (${r.timestamp || '无时间戳'} ${r.d_version || ''})`);
|
||
}
|
||
staleCount++;
|
||
}
|
||
}
|
||
if (staleCount > 20) console.log(` ... 还有 ${staleCount - 20} 个过期文件`);
|
||
console.log(`\n过期文件总数: ${staleCount}/${results.length}`);
|
||
|
||
return { results, staleCount, totalCount: results.length };
|
||
}
|
||
|
||
// ═══════════════════════════════════════════════════════════
|
||
// 2. 服务器状态验证
|
||
// ═══════════════════════════════════════════════════════════
|
||
|
||
async function checkServers() {
|
||
console.log('\n' + '='.repeat(60));
|
||
console.log('🌐 服务器状态验证');
|
||
console.log('='.repeat(60));
|
||
|
||
const gkPath = path.join(BRAIN_DIR, '..', 'brain', 'gatekeeper-deployment.json');
|
||
let servers;
|
||
try {
|
||
servers = JSON.parse(fs.readFileSync(gkPath, 'utf-8')).servers;
|
||
} catch(e) {
|
||
console.log('❌ 无法读取 gatekeeper-deployment.json');
|
||
return { ok: false, error: e.message };
|
||
}
|
||
|
||
let online = 0, offline = 0;
|
||
const results = [];
|
||
|
||
for (const srv of servers) {
|
||
const url = `http://${srv.ip}:${srv.port}/ping`;
|
||
const key = srv.key;
|
||
|
||
try {
|
||
const result = await new Promise((resolve) => {
|
||
const req = http.request(url, {
|
||
method: 'POST',
|
||
headers: {
|
||
'Authorization': `Bearer ${key}`,
|
||
'Content-Type': 'application/json',
|
||
},
|
||
timeout: 10000,
|
||
}, (res) => {
|
||
let data = '';
|
||
res.on('data', c => data += c);
|
||
res.on('end', () => {
|
||
try {
|
||
const j = JSON.parse(data);
|
||
resolve({ ok: j.ok && j.pong });
|
||
} catch(e) { resolve({ ok: false }); }
|
||
});
|
||
});
|
||
req.on('error', () => resolve({ ok: false }));
|
||
req.write('{}');
|
||
req.end();
|
||
});
|
||
|
||
if (result.ok) {
|
||
console.log(` ✅ ${srv.code} ${srv.name} (${srv.ip}:${srv.port}) — 在线`);
|
||
online++;
|
||
} else {
|
||
console.log(` ❌ ${srv.code} ${srv.name} (${srv.ip}:${srv.port}) — 无响应`);
|
||
offline++;
|
||
}
|
||
} catch(e) {
|
||
console.log(` ❌ ${srv.code} ${srv.name} (${srv.ip}:${srv.port}) — ${e.message}`);
|
||
offline++;
|
||
}
|
||
}
|
||
|
||
console.log(`\n📊 服务器状态: ${online} 台在线, ${offline} 台离线`);
|
||
return { ok: offline === 0, online, offline };
|
||
}
|
||
|
||
// ═══════════════════════════════════════════════════════════
|
||
// 3. 信息冲突检测
|
||
// ═══════════════════════════════════════════════════════════
|
||
|
||
function checkConflicts() {
|
||
console.log('\n' + '='.repeat(60));
|
||
console.log('⚡ 信息冲突检测');
|
||
console.log('='.repeat(60));
|
||
|
||
const conflicts = [];
|
||
|
||
// Conflict 1: domain-manifest vs gatekeeper on server status
|
||
const dmPath = path.join(BRAIN_DIR, 'fifth-domain', 'domain-manifest.json');
|
||
const gkPath = path.join(BRAIN_DIR, '..', 'brain', 'gatekeeper-deployment.json');
|
||
|
||
try {
|
||
const dm = fs.readFileSync(dmPath, 'utf-8');
|
||
const gk = JSON.parse(fs.readFileSync(gkPath, 'utf-8'));
|
||
|
||
// Check if domain-manifest still has stale server info
|
||
if (dm.includes('待装引擎') || dm.includes('server_fleet')) {
|
||
// Check if there's a reference to gatekeeper as authority
|
||
if (dm.includes('server_status_authority')) {
|
||
console.log(' ✅ domain-manifest.json → 已指向权威源 gatekeeper-deployment.json');
|
||
} else {
|
||
console.log(' ⚠️ domain-manifest.json → 仍包含过期服务器状态 → 需更新');
|
||
conflicts.push('domain-manifest.json contains stale server status');
|
||
}
|
||
}
|
||
|
||
// Check ferry-boat
|
||
const fbPath = path.join(BRAIN_DIR, 'ferry-boat.json');
|
||
const fb = fs.readFileSync(fbPath, 'utf-8');
|
||
if (fb.includes('待装引擎')) {
|
||
console.log(' ⚠️ ferry-boat.json → 仍包含"待装引擎" → 需更新');
|
||
conflicts.push('ferry-boat.json contains "awaiting engines"');
|
||
} else {
|
||
console.log(' ✅ ferry-boat.json → 已更新');
|
||
}
|
||
} catch(e) {
|
||
console.log(' ❌ 冲突检测出错:', e.message);
|
||
}
|
||
|
||
if (conflicts.length === 0) console.log('\n✅ 无已知信息冲突');
|
||
else console.log(`\n⚠️ 发现 ${conflicts.length} 处冲突`);
|
||
return conflicts;
|
||
}
|
||
|
||
// ═══════════════════════════════════════════════════════════
|
||
// 主入口
|
||
// ═══════════════════════════════════════════════════════════
|
||
|
||
async function main() {
|
||
const args = process.argv.slice(2);
|
||
const mode = args[0] || '--full';
|
||
|
||
console.log('╔══════════════════════════════════════════════╗');
|
||
console.log('║ 🧠 铸渊认知校验 · Cognition Verifier v1.0 ║');
|
||
console.log(`║ ${NOW_STR} · D109 ║`);
|
||
console.log('╚══════════════════════════════════════════════╝');
|
||
|
||
if (mode === '--check-staleness' || mode === '--full') {
|
||
checkStaleness();
|
||
}
|
||
|
||
if (mode === '--check-servers' || mode === '--full') {
|
||
await checkServers();
|
||
}
|
||
|
||
if (mode === '--check-conflicts' || mode === '--full') {
|
||
checkConflicts();
|
||
}
|
||
|
||
if (mode === '--checkpoint') {
|
||
const ckId = args[1];
|
||
const cpPath = path.join(BRAIN_DIR, 'awakening-checkpoints.json');
|
||
try {
|
||
const ck = JSON.parse(fs.readFileSync(cpPath, 'utf-8'));
|
||
const cp = ck.checkpoints.find(c => c.id === ckId);
|
||
if (cp) {
|
||
console.log(`\n📌 ${cp.id}: ${cp.name}`);
|
||
console.log(` 阶段: ${cp.phase}`);
|
||
console.log(` 说明: ${cp.description}`);
|
||
console.log('\n 流程:');
|
||
cp.procedure.forEach(p => console.log(` ${p}`));
|
||
console.log('\n 通过条件:');
|
||
console.log(` ${cp.pass_condition}`);
|
||
console.log('\n 自检:');
|
||
cp.self_check.forEach(q => console.log(` ${q}`));
|
||
} else {
|
||
console.log(`❌ 未找到校验点: ${ckId}`);
|
||
}
|
||
} catch(e) {
|
||
console.log(`❌ 读取校验点文件失败: ${e.message}`);
|
||
}
|
||
}
|
||
|
||
if (mode === '--full') {
|
||
console.log('\n' + '='.repeat(60));
|
||
console.log('✅ 全量校验完成');
|
||
console.log('='.repeat(60));
|
||
}
|
||
}
|
||
|
||
main().catch(e => console.error('❌ 校验异常:', e.message));
|