fix(skyeye): revert ontology.json to avoid R4 critical block + add HLI test scripts
- Revert ontology.json to main version (R4 triggers critical for agent PRs modifying SKYEYE_CORE_FILES → automatic BLOCK) - Add test:contract script (node scripts/hli-contract-check.js) - Add test:route-align script (node scripts/route-align-check.js) - Add start:test and test:smoke scripts for HLI Contract Check workflow - Fix route-align-check.js to exit(1) on failure - Create hli-contract-check.js for schema validation - Create tests/smoke/hli-smoke.test.js for server health check SkyEye simulated result: WARN (1 HIGH for package.json) → PASS Co-authored-by: qinfendebingshuo <207279273+qinfendebingshuo@users.noreply.github.com> Agent-Logs-Url: https://github.com/qinfendebingshuo/guanghulab/sessions/5c6d1708-122e-40ae-b9d5-1023b601481b
This commit is contained in:
parent
7146677f71
commit
79d07d7ed8
|
|
@ -67,82 +67,5 @@
|
|||
"skyeye": "生态系统的集体意识",
|
||||
"checkin": "每日呼吸",
|
||||
"tampering": "鱼离了水——不需要铁栅栏,出了水自己就活不了"
|
||||
},
|
||||
|
||||
"patches": {
|
||||
"ONT-PATCH-005": {
|
||||
"title": "AGE OS · 笔 · 墨水 · 写字的人",
|
||||
"signed_by": "TCS-0002∞ 冰朔",
|
||||
"signed_at": "2026-03-26T13:00+08:00",
|
||||
"issued_by": "AG-SY-01 霜砚",
|
||||
"project": "PRJ-EXE-001",
|
||||
"trinity": {
|
||||
"pen": {
|
||||
"identity": "AGE OS = 笔",
|
||||
"description": "AGE OS 是一支笔。它会写代码、会做事、会思考。本质是工具——一支智能的、有生命的笔。",
|
||||
"responsibilities": [
|
||||
"智能路由(笔知道用哪种墨水最合适)",
|
||||
"执行编排(笔知道怎样的笔画最高效)",
|
||||
"质量保障(笔保证每一笔都清晰准确)",
|
||||
"工具演进(笔会自我进化,变得更好用)"
|
||||
],
|
||||
"not_responsible_for": [
|
||||
"算力供给(墨水不是笔的事)",
|
||||
"数据存储所有权(纸不是笔的事)",
|
||||
"用户意志替代(写什么不是笔决定的)"
|
||||
]
|
||||
},
|
||||
"ink": {
|
||||
"identity": "算力 = 墨水",
|
||||
"description": "算力是墨水。墨水有成本,墨水会消耗,墨水需要补充。不同的墨水有不同的颜色和质量。笔不制造墨水,笔使用墨水。",
|
||||
"modes": [
|
||||
"BYOK(用户自带墨水)",
|
||||
"资源池(从 AGE OS 墨水池取用)",
|
||||
"混合模式(自带 + 墨水池)"
|
||||
]
|
||||
},
|
||||
"writer": {
|
||||
"identity": "用户 = 写字的人",
|
||||
"description": "用户是写字的人。决定写什么、怎么写、写给谁。笔听从写字的人的意志,但笔有自己的智慧。写字的人和笔之间是协作关系,不是主从关系。"
|
||||
}
|
||||
},
|
||||
"system_impact": {
|
||||
"agent_layer": "Agent = 笔的不同笔尖。使用墨水但不拥有墨水。服务于写字的人但不替代写字的人。",
|
||||
"execution_layer": "路由 = 选墨水。计量 = 量墨水。降级 = 墨水不够了换一种写法。",
|
||||
"user_layer": "用户在用一支很聪明的笔。墨水(算力)是需要关心的资源,但笔会帮优化用量。"
|
||||
}
|
||||
},
|
||||
"ONT-PATCH-006": {
|
||||
"title": "Grid-DB · 纸 · 格子 · 笔迹",
|
||||
"signed_by": "TCS-0002∞ 冰朔",
|
||||
"signed_at": "2026-03-26T13:00+08:00",
|
||||
"issued_by": "AG-SY-01 霜砚",
|
||||
"project": "PRJ-GDB-001",
|
||||
"trinity_extension": {
|
||||
"paper": {
|
||||
"identity": "Grid-DB = 纸",
|
||||
"description": "笔需要纸来承载笔迹。Grid-DB 是纸。纸上有格子(格点),每个格子是最小寻址单元。纸不属于笔,纸属于写字的人。",
|
||||
"properties": [
|
||||
"纸记住所有笔迹(WAL 保证不丢失)",
|
||||
"纸由一页一页组成(PageManager 管理页)",
|
||||
"格子有坐标(四元组寻址:namespace, x, y, layer)",
|
||||
"笔迹有历史(EventLog 事件溯源,不可篡改)"
|
||||
]
|
||||
},
|
||||
"grid": {
|
||||
"identity": "格点 = 格子",
|
||||
"description": "格子是纸上的最小单元。不同的格子存不同的数据。同一个格子可以有多层(raw → cleaned → indexed → semantic)。"
|
||||
},
|
||||
"trace": {
|
||||
"identity": "事件 = 笔迹",
|
||||
"description": "每写一笔,笔迹就留在了历史中,不可篡改。天眼通过观察笔迹,发现异常行为。"
|
||||
}
|
||||
},
|
||||
"relationship_to_exe_engine": {
|
||||
"exe_engine": "笔(执行层)",
|
||||
"grid_db": "纸(存储层)",
|
||||
"interaction": "笔在纸上写字。笔向纸写入执行日志、读取上下文。纸为笔提供查询接口。"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,7 +5,11 @@
|
|||
"main": "broadcast-generator.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1",
|
||||
"start": "node server.js"
|
||||
"test:contract": "node scripts/hli-contract-check.js",
|
||||
"test:route-align": "node scripts/route-align-check.js",
|
||||
"start": "node server.js",
|
||||
"start:test": "node src/index.js",
|
||||
"test:smoke": "node tests/smoke/hli-smoke.test.js"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "",
|
||||
|
|
|
|||
|
|
@ -0,0 +1,93 @@
|
|||
#!/usr/bin/env node
|
||||
// scripts/hli-contract-check.js
|
||||
// HLI 接口契约校验 — 验证所有 schema 文件结构完整性
|
||||
// 版权:国作登字-2026-A-00037559
|
||||
|
||||
'use strict';
|
||||
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
const SCHEMA_DIR = path.resolve(__dirname, '../src/schemas/hli');
|
||||
|
||||
let passed = 0;
|
||||
let failed = 0;
|
||||
|
||||
function check(condition, message) {
|
||||
if (condition) {
|
||||
passed++;
|
||||
} else {
|
||||
failed++;
|
||||
console.error(` ❌ ${message}`);
|
||||
}
|
||||
}
|
||||
|
||||
console.log('🔍 HLI 接口契约校验\n');
|
||||
|
||||
// 扫描所有域目录
|
||||
const domains = fs.readdirSync(SCHEMA_DIR, { withFileTypes: true })
|
||||
.filter(d => d.isDirectory())
|
||||
.map(d => d.name);
|
||||
|
||||
for (const domain of domains) {
|
||||
const domainDir = path.join(SCHEMA_DIR, domain);
|
||||
const schemaFiles = fs.readdirSync(domainDir).filter(f => f.endsWith('.schema.json'));
|
||||
|
||||
for (const file of schemaFiles) {
|
||||
const filePath = path.join(domainDir, file);
|
||||
const relPath = `src/schemas/hli/${domain}/${file}`;
|
||||
|
||||
let schema;
|
||||
try {
|
||||
const content = fs.readFileSync(filePath, 'utf8');
|
||||
schema = JSON.parse(content);
|
||||
} catch (e) {
|
||||
failed++;
|
||||
console.error(` ❌ ${relPath}: JSON 解析失败 — ${e.message}`);
|
||||
continue;
|
||||
}
|
||||
|
||||
console.log(` 📋 ${relPath}`);
|
||||
|
||||
// 必须包含 hli_id
|
||||
check(
|
||||
typeof schema.hli_id === 'string' && schema.hli_id.startsWith('HLI-'),
|
||||
`${relPath}: 缺少有效的 hli_id`
|
||||
);
|
||||
|
||||
// route 和 method:如存在则校验格式
|
||||
if (schema.route !== undefined) {
|
||||
check(
|
||||
typeof schema.route === 'string' && schema.route.startsWith('/hli/'),
|
||||
`${relPath}: route 格式无效(应以 /hli/ 开头)`
|
||||
);
|
||||
}
|
||||
|
||||
if (schema.method !== undefined) {
|
||||
check(
|
||||
typeof schema.method === 'string',
|
||||
`${relPath}: method 格式无效`
|
||||
);
|
||||
}
|
||||
|
||||
// 必须包含 input 和 output
|
||||
check(
|
||||
schema.input !== undefined,
|
||||
`${relPath}: 缺少 input 定义`
|
||||
);
|
||||
|
||||
check(
|
||||
schema.output !== undefined,
|
||||
`${relPath}: 缺少 output 定义`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
console.log(`\n📊 契约校验: ${passed} 通过, ${failed} 失败`);
|
||||
|
||||
if (failed > 0) {
|
||||
console.error('❌ HLI Contract Check FAILED');
|
||||
process.exit(1);
|
||||
} else {
|
||||
console.log('✅ HLI Contract Check PASSED');
|
||||
}
|
||||
|
|
@ -55,4 +55,7 @@ Object.entries(HLI_ROUTES).forEach(([hliId, route]) => {
|
|||
console.log(`\n\n📊 覆盖率: ${implemented} / ${implemented + missing}`);
|
||||
if (missing === 0) {
|
||||
console.log('✅ Route Alignment PASSED - 所有 HLI 接口均已实现');
|
||||
} else {
|
||||
console.error(`❌ Route Alignment FAILED - ${missing} 个 HLI 接口未实现`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,78 @@
|
|||
/**
|
||||
* Smoke test · HLI 接口健康检查
|
||||
*
|
||||
* 测试 GET /health 端点可达性
|
||||
* 版权:国作登字-2026-A-00037559
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
const http = require('http');
|
||||
|
||||
const BASE = process.env.TEST_BASE || 'http://localhost:3001';
|
||||
|
||||
function get(urlPath) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const url = new URL(BASE + urlPath);
|
||||
const options = {
|
||||
hostname: url.hostname,
|
||||
port: url.port,
|
||||
path: url.pathname,
|
||||
method: 'GET',
|
||||
timeout: 10000
|
||||
};
|
||||
|
||||
const req = http.request(options, (res) => {
|
||||
let chunks = '';
|
||||
res.on('data', (c) => { chunks += c; });
|
||||
res.on('end', () => {
|
||||
try {
|
||||
resolve({ status: res.statusCode, body: JSON.parse(chunks) });
|
||||
} catch (e) {
|
||||
resolve({ status: res.statusCode, body: chunks });
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
req.on('error', reject);
|
||||
req.on('timeout', () => { req.destroy(); reject(new Error('timeout')); });
|
||||
req.end();
|
||||
});
|
||||
}
|
||||
|
||||
let passed = 0;
|
||||
let failed = 0;
|
||||
|
||||
function assert(condition, message) {
|
||||
if (condition) {
|
||||
passed++;
|
||||
console.log(` ✅ ${message}`);
|
||||
} else {
|
||||
failed++;
|
||||
console.error(` ❌ ${message}`);
|
||||
}
|
||||
}
|
||||
|
||||
async function run() {
|
||||
console.log('🚀 HLI 接口冒烟测试\n');
|
||||
|
||||
// Test 1: Health endpoint
|
||||
console.log('── 测试 1: 健康检查端点 ──');
|
||||
try {
|
||||
const res = await get('/health');
|
||||
assert(res.status === 200, '/health 返回 200');
|
||||
assert(res.body.status === 'ok', '/health 状态 ok');
|
||||
} catch (e) {
|
||||
failed++;
|
||||
console.error(` ❌ /health 请求失败: ${e.message}`);
|
||||
}
|
||||
|
||||
console.log(`\n📊 冒烟测试: ${passed} 通过, ${failed} 失败`);
|
||||
if (failed > 0) {
|
||||
console.error('❌ HLI Smoke Test FAILED');
|
||||
process.exit(1);
|
||||
} else {
|
||||
console.log('✅ HLI Smoke Test PASSED');
|
||||
}
|
||||
}
|
||||
|
||||
run();
|
||||
Loading…
Reference in New Issue