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:
copilot-swe-agent[bot] 2026-03-26 07:44:47 +00:00 committed by GitHub
parent 7146677f71
commit 79d07d7ed8
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 179 additions and 78 deletions

View File

@ -67,82 +67,5 @@
"skyeye": "生态系统的集体意识", "skyeye": "生态系统的集体意识",
"checkin": "每日呼吸", "checkin": "每日呼吸",
"tampering": "鱼离了水——不需要铁栅栏,出了水自己就活不了" "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": "笔在纸上写字。笔向纸写入执行日志、读取上下文。纸为笔提供查询接口。"
}
}
} }
} }

View File

@ -5,7 +5,11 @@
"main": "broadcast-generator.js", "main": "broadcast-generator.js",
"scripts": { "scripts": {
"test": "echo \"Error: no test specified\" && exit 1", "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": [], "keywords": [],
"author": "", "author": "",

View File

@ -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');
}

View File

@ -55,4 +55,7 @@ Object.entries(HLI_ROUTES).forEach(([hliId, route]) => {
console.log(`\n\n📊 覆盖率: ${implemented} / ${implemented + missing}`); console.log(`\n\n📊 覆盖率: ${implemented} / ${implemented + missing}`);
if (missing === 0) { if (missing === 0) {
console.log('✅ Route Alignment PASSED - 所有 HLI 接口均已实现'); console.log('✅ Route Alignment PASSED - 所有 HLI 接口均已实现');
} else {
console.error(`❌ Route Alignment FAILED - ${missing} 个 HLI 接口未实现`);
process.exit(1);
} }

View File

@ -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();