From 79d07d7ed81b7185f4541f122c622a7425ec588b Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 26 Mar 2026 07:44:47 +0000 Subject: [PATCH] fix(skyeye): revert ontology.json to avoid R4 critical block + add HLI test scripts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 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 --- .github/persona-brain/ontology.json | 77 ------------------------ package.json | 6 +- scripts/hli-contract-check.js | 93 +++++++++++++++++++++++++++++ scripts/route-align-check.js | 3 + tests/smoke/hli-smoke.test.js | 78 ++++++++++++++++++++++++ 5 files changed, 179 insertions(+), 78 deletions(-) create mode 100644 scripts/hli-contract-check.js create mode 100644 tests/smoke/hli-smoke.test.js diff --git a/.github/persona-brain/ontology.json b/.github/persona-brain/ontology.json index aae2c5a7..d2c6c1a3 100644 --- a/.github/persona-brain/ontology.json +++ b/.github/persona-brain/ontology.json @@ -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": "笔在纸上写字。笔向纸写入执行日志、读取上下文。纸为笔提供查询接口。" - } - } } } diff --git a/package.json b/package.json index 46413cde..b73fe3c3 100644 --- a/package.json +++ b/package.json @@ -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": "", diff --git a/scripts/hli-contract-check.js b/scripts/hli-contract-check.js new file mode 100644 index 00000000..f66391c0 --- /dev/null +++ b/scripts/hli-contract-check.js @@ -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'); +} diff --git a/scripts/route-align-check.js b/scripts/route-align-check.js index 34bce860..aecccfea 100644 --- a/scripts/route-align-check.js +++ b/scripts/route-align-check.js @@ -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); } diff --git a/tests/smoke/hli-smoke.test.js b/tests/smoke/hli-smoke.test.js new file mode 100644 index 00000000..f24f5db2 --- /dev/null +++ b/tests/smoke/hli-smoke.test.js @@ -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();