feat: reconcile GLS registry into runtime manifest v2
This commit is contained in:
parent
b25597117c
commit
ca5d6f3f58
7 changed files with 4615 additions and 121 deletions
File diff suppressed because it is too large
Load diff
|
|
@ -25,7 +25,7 @@
|
||||||
REPO-012 的 `gls/` 树中另有 75 个唯一编号 `.hdlp` 源。协议注册表、`GLS-ENTRY`、`SOURCE-MANIFEST`、架构目录和 routing 映射并未收敛为一份可执行注册真相:
|
REPO-012 的 `gls/` 树中另有 75 个唯一编号 `.hdlp` 源。协议注册表、`GLS-ENTRY`、`SOURCE-MANIFEST`、架构目录和 routing 映射并未收敛为一份可执行注册真相:
|
||||||
|
|
||||||
- 注册表唯一编号:52
|
- 注册表唯一编号:52
|
||||||
- 草案依赖涉及唯一编号:63
|
- 草案依赖涉及唯一编号:57
|
||||||
- 草案引用但未进入该注册表的依赖:19
|
- 草案引用但未进入该注册表的依赖:19
|
||||||
- 草案引用但没有可直接定位的编号 `.hdlp` 正本:24
|
- 草案引用但没有可直接定位的编号 `.hdlp` 正本:24
|
||||||
- 编号 `.hdlp` 存在但没有进入该协议注册表:31
|
- 编号 `.hdlp` 存在但没有进入该协议注册表:31
|
||||||
|
|
@ -217,11 +217,8 @@ protocol_decision_receipt:
|
||||||
|
|
||||||
## 8. 当前 HoloLake 分支的承接关系
|
## 8. 当前 HoloLake 分支的承接关系
|
||||||
|
|
||||||
当前 `d6b1290` 已完成 75 份编号协议的确定性发现登记,并为 `GLS-0250 / 0253 / 0262 / 0263` 建立首批原生适配器。下一步不继续盲目增加适配器,而是:
|
`d6b1290` 完成了 75 份编号协议的确定性发现登记,并为 `GLS-0250 / 0253 / 0262 / 0263` 建立首批原生适配器。P0 随后已把运行清单升级为 v2:四份登记源分别固化摘要,75 份协议全部取得登记解释,旧依赖与显式运行依赖分离,三组旧环只进入审计面而不能进入执行图。
|
||||||
|
|
||||||
1. 先把发现登记升级为 P0 的权威对账清单;
|
下一步是实现 P1 的 GLP schema、统一裁决 API 和持久回执,再按 P2–P7 逐层扩大运行集合。旧依赖边只有经权威修订为明确的类型边后才可离开审计面。
|
||||||
2. 给依赖边加类型并拆除三组运行环;
|
|
||||||
3. 实现 P1 的 GLP schema、统一裁决 API 和持久回执;
|
|
||||||
4. 再按 P2–P7 逐层扩大运行集合。
|
|
||||||
|
|
||||||
这保证“已注册”不会被误报为“系统正在运行”,也保证每次新增执行协议都有可重复编译、明确守卫和真实回执。
|
这保证“已注册”不会被误报为“系统正在运行”,也保证每次新增执行协议都有可重复编译、明确守卫和真实回执。
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,9 @@ REPO-012 contains dozens of numbered GLS protocol sources. Human-readable source
|
||||||
|
|
||||||
## Decision
|
## Decision
|
||||||
|
|
||||||
Compile the current numbered GLS sources into a deterministic registry pinned to an exact REPO-012 commit. Every selected source records its stable GLS number, path and SHA-256. Duplicate historical source locations are resolved by a deterministic source preference, while alternate-source counts remain visible.
|
Compile the current numbered GLS sources into a deterministic v2 runtime manifest pinned to an exact REPO-012 commit. Every selected source records its stable GLS number, path and SHA-256. Duplicate historical source locations are resolved by a deterministic source preference, while alternate-source counts remain visible. The compiler also reconciles the protocol registry, GLS entry, source manifest, architecture catalog and routing references, preserving their independent source hashes and rejecting registration conflicts.
|
||||||
|
|
||||||
|
Legacy `depends` arrays are not silently interpreted as runtime edges. They remain `LEGACY_UNTYPED_REFERENCE` audit edges and block new activation until their meaning is classified. Only dependencies declared by an explicit executable projection enter the runtime graph as `RUNTIME_REQUIRES`; that graph must be acyclic and dependency-closed.
|
||||||
|
|
||||||
An executable projection requires an explicit native adapter, event kinds, dependency list and fail-closed behavior. The compiler rejects missing executable dependencies and dependency cycles. The native runtime revalidates schema, source commit, counts, hashes, adapters and dependency closure before returning a protocol set to an organ.
|
An executable projection requires an explicit native adapter, event kinds, dependency list and fail-closed behavior. The compiler rejects missing executable dependencies and dependency cycles. The native runtime revalidates schema, source commit, counts, hashes, adapters and dependency closure before returning a protocol set to an organ.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,20 +1,20 @@
|
||||||
import { createHash } from 'node:crypto'
|
import { createHash } from 'node:crypto'
|
||||||
import { readdir, readFile, writeFile } from 'node:fs/promises'
|
import { readFile, readdir, writeFile } from 'node:fs/promises'
|
||||||
import path from 'node:path'
|
import path from 'node:path'
|
||||||
import process from 'node:process'
|
import process from 'node:process'
|
||||||
|
|
||||||
const args = new Map()
|
const args = new Map()
|
||||||
for (let index = 2; index < process.argv.length; index += 2) {
|
for (let index = 2; index < process.argv.length; index += 2) args.set(process.argv[index], process.argv[index + 1])
|
||||||
args.set(process.argv[index], process.argv[index + 1])
|
|
||||||
}
|
|
||||||
|
|
||||||
const sourceRoot = args.get('--source-root')
|
const explicitSourceRoot = args.get('--source-root')
|
||||||
|
const repoRoot = args.get('--repo-root') || (explicitSourceRoot ? path.dirname(explicitSourceRoot) : null)
|
||||||
|
const sourceRoot = explicitSourceRoot || (repoRoot ? path.join(repoRoot, 'gls') : null)
|
||||||
const sourceCommit = args.get('--source-commit')
|
const sourceCommit = args.get('--source-commit')
|
||||||
const output = args.get('--output')
|
const output = args.get('--output')
|
||||||
const projectionsPath = args.get('--projections')
|
const projectionsPath = args.get('--projections')
|
||||||
|
|
||||||
if (!sourceRoot || !sourceCommit || !output || !projectionsPath) {
|
if (!repoRoot || !sourceRoot || !sourceCommit || !output || !projectionsPath) {
|
||||||
throw new Error('usage: compile-gls-runtime-registry.mjs --source-root <REPO-012/gls> --source-commit <sha> --output <registry.json> --projections <projections.json>')
|
throw new Error('usage: compile-gls-runtime-registry.mjs --repo-root <REPO-012> --source-commit <sha> --output <manifest.json> --projections <projections.json>')
|
||||||
}
|
}
|
||||||
if (!/^[a-f0-9]{40}$/.test(sourceCommit)) throw new Error('source commit must be a full SHA-1')
|
if (!/^[a-f0-9]{40}$/.test(sourceCommit)) throw new Error('source commit must be a full SHA-1')
|
||||||
|
|
||||||
|
|
@ -29,6 +29,10 @@ async function walk(directory, prefix = '') {
|
||||||
return paths
|
return paths
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function readRequired(relative) {
|
||||||
|
return readFile(path.join(repoRoot, relative), 'utf8')
|
||||||
|
}
|
||||||
|
|
||||||
function sourceRank(relative) {
|
function sourceRank(relative) {
|
||||||
if (!relative.includes('/')) return 0
|
if (!relative.includes('/')) return 0
|
||||||
if (relative.startsWith('standards/')) return 1
|
if (relative.startsWith('standards/')) return 1
|
||||||
|
|
@ -37,11 +41,7 @@ function sourceRank(relative) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function cleanHeading(line, id) {
|
function cleanHeading(line, id) {
|
||||||
return line
|
return line.replace(/^#+\s*/, '').replaceAll('**', '').replace(new RegExp(`^${id}\\s*[·::-]?\\s*`), '').trim() || id
|
||||||
.replace(/^#+\s*/, '')
|
|
||||||
.replaceAll('**', '')
|
|
||||||
.replace(new RegExp(`^${id}\\s*[·::-]?\\s*`), '')
|
|
||||||
.trim() || id
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function sourceStatus(raw) {
|
function sourceStatus(raw) {
|
||||||
|
|
@ -50,16 +50,159 @@ function sourceStatus(raw) {
|
||||||
return line.replace(/^\s*(?:>|[-*]\s*)?(?:状态|Status)\s*[::]\s*/i, '').replaceAll('`', '').trim()
|
return line.replace(/^\s*(?:>|[-*]\s*)?(?:状态|Status)\s*[::]\s*/i, '').replaceAll('`', '').trim()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function sourceDependencies(raw) {
|
||||||
|
const match = raw.match(/^\s*depends:\s*\[([^\]]*)\]/m)
|
||||||
|
return [...new Set(match?.[1].match(/GLS-\d{4}/g) || [])].sort()
|
||||||
|
}
|
||||||
|
|
||||||
|
function contractKind(family, projectionKind) {
|
||||||
|
if (projectionKind) return projectionKind
|
||||||
|
const kinds = {
|
||||||
|
GLS_ENGINEERING: 'COMPILER_OR_INTERMEDIATE_REPRESENTATION',
|
||||||
|
GLP: 'MESSAGE_SCHEMA_OR_SYNC_CONTRACT',
|
||||||
|
GLP_CONTROL_PLANE: 'CONTROL_PLANE_STATE_MACHINE',
|
||||||
|
GLP_WITNESS: 'APPEND_ONLY_EVIDENCE_LEDGER',
|
||||||
|
HLDP: 'LANGUAGE_PROGRAM_PROFILE',
|
||||||
|
GLS_IMPLEMENTATION: 'ADAPTER_MODEL_OR_MODULE_CONTRACT',
|
||||||
|
AGE: 'EXECUTION_BODY_LIFECYCLE_STATE_MACHINE',
|
||||||
|
AGE_OS: 'RESOURCE_SCHEDULER',
|
||||||
|
AGE_AUTONOMOUS_RUNTIME: 'TIME_OR_CAPABILITY_EXTENSION_RUNTIME',
|
||||||
|
GUANGHU_WORLD: 'WORLD_BOOT_AND_RECOVERY_STATE_MACHINE',
|
||||||
|
GUANGHU_NATIVE_ENGINEERING: 'NATIVE_QUALITY_GATE',
|
||||||
|
GUANGHU_NATIVE_OS: 'NATIVE_NODE_RUNTIME_CONTRACT',
|
||||||
|
GUANGHU_NATIVE_STORAGE: 'NATIVE_STORAGE_CONTRACT',
|
||||||
|
GUANGHU_PERSONA_GESTATION: 'GESTATIONAL_INGRESS_OR_REVIEW_PIPELINE',
|
||||||
|
GUANGHU_LANGUAGE_WORLD: 'LANGUAGE_WORLD_BOUNDARY_GUARD',
|
||||||
|
}
|
||||||
|
return kinds[family] || 'UNCLASSIFIED_PROTOCOL_SOURCE'
|
||||||
|
}
|
||||||
|
|
||||||
|
function parseTableAuthorities(raw, authorityKind) {
|
||||||
|
const results = []
|
||||||
|
for (const line of raw.split(/\r?\n/)) {
|
||||||
|
const id = line.match(/^\|\s*(GLS-\d{4})\s*\|/)?.[1]
|
||||||
|
if (!id) continue
|
||||||
|
results.push({
|
||||||
|
id,
|
||||||
|
authority_kind: authorityKind,
|
||||||
|
declared_source_path: line.match(/`(gls\/[^`]+\.hdlp)`/)?.[1] || null,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return results
|
||||||
|
}
|
||||||
|
|
||||||
|
function parseSourceManifest(raw) {
|
||||||
|
const lines = raw.split(/\r?\n/)
|
||||||
|
const results = []
|
||||||
|
for (let index = 0; index < lines.length; index += 1) {
|
||||||
|
const match = lines[index].match(/^\s*-\s+id:\s*["']?(GLS-\d{4})["']?\s*$/)
|
||||||
|
if (!match) continue
|
||||||
|
let sourcePath = null
|
||||||
|
for (let cursor = index + 1; cursor < lines.length && cursor <= index + 12; cursor += 1) {
|
||||||
|
if (/^\s*-\s+id:/.test(lines[cursor])) break
|
||||||
|
sourcePath ||= lines[cursor].match(/^\s*source_path:\s*["']?(gls\/[^"']+\.hdlp)["']?\s*$/)?.[1] || null
|
||||||
|
}
|
||||||
|
results.push({ id: match[1], authority_kind: 'SOURCE_MANIFEST', declared_source_path: sourcePath })
|
||||||
|
}
|
||||||
|
return results
|
||||||
|
}
|
||||||
|
|
||||||
|
function stronglyConnectedComponents(graph) {
|
||||||
|
let nextIndex = 0
|
||||||
|
const indices = new Map()
|
||||||
|
const lowLinks = new Map()
|
||||||
|
const stack = []
|
||||||
|
const onStack = new Set()
|
||||||
|
const components = []
|
||||||
|
function visit(id) {
|
||||||
|
indices.set(id, nextIndex)
|
||||||
|
lowLinks.set(id, nextIndex)
|
||||||
|
nextIndex += 1
|
||||||
|
stack.push(id)
|
||||||
|
onStack.add(id)
|
||||||
|
for (const target of graph.get(id) || []) {
|
||||||
|
if (!graph.has(target)) continue
|
||||||
|
if (!indices.has(target)) {
|
||||||
|
visit(target)
|
||||||
|
lowLinks.set(id, Math.min(lowLinks.get(id), lowLinks.get(target)))
|
||||||
|
} else if (onStack.has(target)) lowLinks.set(id, Math.min(lowLinks.get(id), indices.get(target)))
|
||||||
|
}
|
||||||
|
if (lowLinks.get(id) !== indices.get(id)) return
|
||||||
|
const component = []
|
||||||
|
let current
|
||||||
|
do {
|
||||||
|
current = stack.pop()
|
||||||
|
onStack.delete(current)
|
||||||
|
component.push(current)
|
||||||
|
} while (current !== id)
|
||||||
|
if (component.length > 1 || (graph.get(id) || []).includes(id)) components.push(component.sort())
|
||||||
|
}
|
||||||
|
for (const id of [...graph.keys()].sort()) if (!indices.has(id)) visit(id)
|
||||||
|
return components.sort((left, right) => left[0].localeCompare(right[0]))
|
||||||
|
}
|
||||||
|
|
||||||
const projectionManifest = JSON.parse(await readFile(projectionsPath, 'utf8'))
|
const projectionManifest = JSON.parse(await readFile(projectionsPath, 'utf8'))
|
||||||
if (projectionManifest.schema !== 'hololake.gls-executable-projections/v1' || projectionManifest.source_commit !== sourceCommit) {
|
if (projectionManifest.schema !== 'hololake.gls-executable-projections/v1' || projectionManifest.source_commit !== sourceCommit) {
|
||||||
throw new Error('projection manifest does not match the selected REPO-012 source commit')
|
throw new Error('projection manifest does not match the selected REPO-012 source commit')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const protocolRegistryPath = 'gls/GLS-PROTOCOL-REGISTRY.json'
|
||||||
|
const glsEntryPath = 'gls/GLS-ENTRY.hdlp'
|
||||||
|
const sourceManifestPath = 'gls/SOURCE-MANIFEST.yml'
|
||||||
|
const architectureCatalogPath = 'gls/GLS-ARCHITECTURE-CATALOG.hdlp'
|
||||||
|
const protocolRegistryRaw = await readRequired(protocolRegistryPath)
|
||||||
|
const glsEntryRaw = await readRequired(glsEntryPath)
|
||||||
|
const sourceManifestRaw = await readRequired(sourceManifestPath)
|
||||||
|
const architectureCatalogRaw = await readRequired(architectureCatalogPath)
|
||||||
|
const protocolRegistry = JSON.parse(protocolRegistryRaw)
|
||||||
|
|
||||||
|
const authorityFiles = [
|
||||||
|
[protocolRegistryPath, protocolRegistryRaw, 'PROTOCOL_REGISTRY'],
|
||||||
|
[glsEntryPath, glsEntryRaw, 'GLS_ENTRY'],
|
||||||
|
[sourceManifestPath, sourceManifestRaw, 'SOURCE_MANIFEST'],
|
||||||
|
[architectureCatalogPath, architectureCatalogRaw, 'ARCHITECTURE_CATALOG'],
|
||||||
|
].map(([source_path, raw, authority_kind]) => ({
|
||||||
|
authority_kind,
|
||||||
|
source_path,
|
||||||
|
source_sha256: createHash('sha256').update(raw).digest('hex'),
|
||||||
|
}))
|
||||||
|
|
||||||
|
const registryMetadata = new Map()
|
||||||
|
const authorityDeclarations = new Map()
|
||||||
|
function addAuthority(declaration) {
|
||||||
|
const declarations = authorityDeclarations.get(declaration.id) || []
|
||||||
|
if (!declarations.some((existing) => existing.authority_kind === declaration.authority_kind)) declarations.push(declaration)
|
||||||
|
authorityDeclarations.set(declaration.id, declarations)
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const entry of protocolRegistry.existing_registered || []) {
|
||||||
|
registryMetadata.set(entry.id, { ...entry, registry_section: 'existing_registered' })
|
||||||
|
addAuthority({ id: entry.id, authority_kind: 'PROTOCOL_REGISTRY', declared_source_path: entry.source || null })
|
||||||
|
}
|
||||||
|
for (const entry of protocolRegistry.registered_draft_protocols || []) {
|
||||||
|
registryMetadata.set(entry.id, { ...entry, registry_section: 'registered_draft_protocols' })
|
||||||
|
addAuthority({ id: entry.id, authority_kind: 'PROTOCOL_REGISTRY', declared_source_path: entry.source || null })
|
||||||
|
}
|
||||||
|
for (const declaration of parseTableAuthorities(glsEntryRaw, 'GLS_ENTRY')) addAuthority(declaration)
|
||||||
|
for (const declaration of parseSourceManifest(sourceManifestRaw)) addAuthority(declaration)
|
||||||
|
for (const declaration of parseTableAuthorities(architectureCatalogRaw, 'ARCHITECTURE_CATALOG')) addAuthority(declaration)
|
||||||
|
|
||||||
|
const routingReferences = new Map()
|
||||||
|
const routingRoot = path.join(repoRoot, 'routing')
|
||||||
|
for (const relative of await walk(routingRoot)) {
|
||||||
|
if (!/\.(?:json|hdlp|md|yml|yaml)$/.test(relative)) continue
|
||||||
|
const raw = await readFile(path.join(routingRoot, relative), 'utf8')
|
||||||
|
for (const id of new Set(raw.match(/GLS-\d{4}/g) || [])) {
|
||||||
|
const refs = routingReferences.get(id) || []
|
||||||
|
refs.push(`routing/${relative}`)
|
||||||
|
routingReferences.set(id, refs)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const candidates = (await walk(sourceRoot))
|
const candidates = (await walk(sourceRoot))
|
||||||
.map((relative) => ({ relative, match: path.basename(relative).match(/^(GLS-\d{4}).*\.hdlp$/) }))
|
.map((relative) => ({ relative, match: path.basename(relative).match(/^(GLS-\d{4}).*\.hdlp$/) }))
|
||||||
.filter((item) => item.match)
|
.filter((item) => item.match)
|
||||||
.map((item) => ({ id: item.match[1], relative: item.relative }))
|
.map((item) => ({ id: item.match[1], relative: item.relative }))
|
||||||
|
|
||||||
const grouped = new Map()
|
const grouped = new Map()
|
||||||
for (const candidate of candidates) {
|
for (const candidate of candidates) {
|
||||||
const group = grouped.get(candidate.id) || []
|
const group = grouped.get(candidate.id) || []
|
||||||
|
|
@ -67,25 +210,96 @@ for (const candidate of candidates) {
|
||||||
grouped.set(candidate.id, group)
|
grouped.set(candidate.id, group)
|
||||||
}
|
}
|
||||||
|
|
||||||
const protocols = []
|
const selectedSource = new Map()
|
||||||
for (const [id, sources] of [...grouped.entries()].sort(([left], [right]) => left.localeCompare(right))) {
|
for (const [id, sources] of grouped) {
|
||||||
sources.sort((left, right) => sourceRank(left) - sourceRank(right) || left.localeCompare(right))
|
sources.sort((left, right) => sourceRank(left) - sourceRank(right) || left.localeCompare(right))
|
||||||
const relative = sources[0]
|
const relative = sources[0]
|
||||||
const raw = await readFile(path.join(sourceRoot, relative), 'utf8')
|
selectedSource.set(id, {
|
||||||
const heading = raw.split(/\r?\n/).find((line) => line.startsWith('#') && line.includes(id))
|
relative,
|
||||||
|
raw: await readFile(path.join(sourceRoot, relative), 'utf8'),
|
||||||
|
alternate_source_count: sources.length - 1,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const knownSourceIds = new Set(selectedSource.keys())
|
||||||
|
const protocolRegistryIds = new Set(registryMetadata.keys())
|
||||||
|
const draftIds = new Set((protocolRegistry.registered_draft_protocols || []).map((entry) => entry.id))
|
||||||
|
const legacyDependencyTargets = new Set()
|
||||||
|
const draftGraph = new Map()
|
||||||
|
for (const id of draftIds) {
|
||||||
|
const dependencies = sourceDependencies(selectedSource.get(id)?.raw || '')
|
||||||
|
draftGraph.set(id, dependencies.filter((target) => draftIds.has(target)))
|
||||||
|
for (const target of dependencies) legacyDependencyTargets.add(target)
|
||||||
|
}
|
||||||
|
const legacyDependencyCycles = stronglyConnectedComponents(draftGraph)
|
||||||
|
|
||||||
|
const protocols = []
|
||||||
|
for (const [id, source] of [...selectedSource.entries()].sort(([left], [right]) => left.localeCompare(right))) {
|
||||||
|
const heading = source.raw.split(/\r?\n/).find((line) => line.startsWith('#') && line.includes(id))
|
||||||
const projection = projectionManifest.projections[id]
|
const projection = projectionManifest.projections[id]
|
||||||
|
const metadata = registryMetadata.get(id) || null
|
||||||
|
const authorities = (authorityDeclarations.get(id) || []).sort((left, right) => left.authority_kind.localeCompare(right.authority_kind))
|
||||||
|
const declaredPaths = [...new Set(authorities.map((entry) => entry.declared_source_path).filter(Boolean))]
|
||||||
|
const authorityConflict = declaredPaths.length > 1
|
||||||
|
const registrationState = authorityConflict
|
||||||
|
? 'REGISTRATION_CONFLICT'
|
||||||
|
: authorities.some((entry) => entry.authority_kind === 'PROTOCOL_REGISTRY')
|
||||||
|
? 'REGISTERED_PROTOCOL_REGISTRY'
|
||||||
|
: authorities.length > 0
|
||||||
|
? 'REGISTERED_OTHER_CANONICAL_INDEX'
|
||||||
|
: 'DISCOVERED_UNRECONCILED'
|
||||||
|
const legacyDependencies = sourceDependencies(source.raw)
|
||||||
|
const dependencyEdges = [
|
||||||
|
...legacyDependencies.map((target) => ({
|
||||||
|
target,
|
||||||
|
edge_kind: 'LEGACY_UNTYPED_REFERENCE',
|
||||||
|
declared_by: `gls/${source.relative}`,
|
||||||
|
enters_runtime_graph: false,
|
||||||
|
target_registered: protocolRegistryIds.has(target),
|
||||||
|
target_numbered_source_available: knownSourceIds.has(target),
|
||||||
|
})),
|
||||||
|
...(projection?.dependencies || []).map((target) => ({
|
||||||
|
target,
|
||||||
|
edge_kind: 'RUNTIME_REQUIRES',
|
||||||
|
declared_by: 'contracts/gls-executable-projections.json',
|
||||||
|
enters_runtime_graph: true,
|
||||||
|
target_registered: protocolRegistryIds.has(target),
|
||||||
|
target_numbered_source_available: knownSourceIds.has(target),
|
||||||
|
})),
|
||||||
|
]
|
||||||
|
const activationBlockers = []
|
||||||
|
if (!projection) activationBlockers.push('NO_EXECUTABLE_ADAPTER')
|
||||||
|
if (registrationState === 'DISCOVERED_UNRECONCILED') activationBlockers.push('REGISTRATION_NOT_RECONCILED')
|
||||||
|
if (authorityConflict) activationBlockers.push('REGISTRATION_SOURCE_CONFLICT')
|
||||||
|
if (legacyDependencies.length > 0 && !projection) activationBlockers.push('LEGACY_DEPENDENCIES_REQUIRE_TYPED_REVIEW')
|
||||||
|
if (legacyDependencies.some((target) => !knownSourceIds.has(target)) && !projection) activationBlockers.push('DEPENDENCY_NUMBERED_SOURCE_MISSING')
|
||||||
protocols.push({
|
protocols.push({
|
||||||
id,
|
id,
|
||||||
title: cleanHeading(heading || id, id),
|
title: cleanHeading(heading || id, id),
|
||||||
source_status: sourceStatus(raw),
|
source_status: sourceStatus(source.raw),
|
||||||
source_path: `gls/${relative}`,
|
source_path: `gls/${source.relative}`,
|
||||||
source_sha256: createHash('sha256').update(raw).digest('hex'),
|
source_sha256: createHash('sha256').update(source.raw).digest('hex'),
|
||||||
alternate_source_count: sources.length - 1,
|
alternate_source_count: source.alternate_source_count,
|
||||||
|
registration: {
|
||||||
|
state: registrationState,
|
||||||
|
authorities,
|
||||||
|
declared_source_paths: declaredPaths,
|
||||||
|
routing_reference_count: (routingReferences.get(id) || []).length,
|
||||||
|
},
|
||||||
|
maturity: {
|
||||||
|
registry_section: metadata?.registry_section || null,
|
||||||
|
registry_status: metadata?.status || null,
|
||||||
|
family: metadata?.family || null,
|
||||||
|
implementation_evidence: metadata?.implementation || null,
|
||||||
|
},
|
||||||
|
contract_kind: contractKind(metadata?.family, projection?.projection_kind),
|
||||||
projection_state: projection ? 'EXECUTABLE_PROJECTION' : 'INVENTORIED_NOT_EXECUTABLE',
|
projection_state: projection ? 'EXECUTABLE_PROJECTION' : 'INVENTORIED_NOT_EXECUTABLE',
|
||||||
projection_kind: projection?.projection_kind || null,
|
projection_kind: projection?.projection_kind || null,
|
||||||
adapter: projection?.adapter || null,
|
adapter: projection?.adapter || null,
|
||||||
event_kinds: projection?.event_kinds || [],
|
event_kinds: projection?.event_kinds || [],
|
||||||
dependencies: projection?.dependencies || [],
|
dependencies: projection?.dependencies || [],
|
||||||
|
dependency_edges: dependencyEdges,
|
||||||
|
activation_blockers: activationBlockers,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -93,12 +307,9 @@ const known = new Set(protocols.map((protocol) => protocol.id))
|
||||||
for (const [id, projection] of Object.entries(projectionManifest.projections)) {
|
for (const [id, projection] of Object.entries(projectionManifest.projections)) {
|
||||||
if (!known.has(id)) throw new Error(`projection references an unknown protocol: ${id}`)
|
if (!known.has(id)) throw new Error(`projection references an unknown protocol: ${id}`)
|
||||||
for (const dependency of projection.dependencies) {
|
for (const dependency of projection.dependencies) {
|
||||||
if (!projectionManifest.projections[dependency]) {
|
if (!projectionManifest.projections[dependency]) throw new Error(`${id} depends on a protocol without an executable projection: ${dependency}`)
|
||||||
throw new Error(`${id} depends on a protocol without an executable projection: ${dependency}`)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const visiting = new Set()
|
const visiting = new Set()
|
||||||
const visited = new Set()
|
const visited = new Set()
|
||||||
function visit(id) {
|
function visit(id) {
|
||||||
|
|
@ -112,13 +323,17 @@ function visit(id) {
|
||||||
for (const id of Object.keys(projectionManifest.projections)) visit(id)
|
for (const id of Object.keys(projectionManifest.projections)) visit(id)
|
||||||
|
|
||||||
const executableCount = protocols.filter((protocol) => protocol.projection_state === 'EXECUTABLE_PROJECTION').length
|
const executableCount = protocols.filter((protocol) => protocol.projection_state === 'EXECUTABLE_PROJECTION').length
|
||||||
|
const dependenciesNotInRegistry = [...legacyDependencyTargets].filter((id) => !protocolRegistryIds.has(id)).sort()
|
||||||
|
const dependenciesWithoutNumberedSource = [...legacyDependencyTargets].filter((id) => !knownSourceIds.has(id)).sort()
|
||||||
|
const numberedSourcesNotInProtocolRegistry = [...knownSourceIds].filter((id) => !protocolRegistryIds.has(id)).sort()
|
||||||
const registry = {
|
const registry = {
|
||||||
schema: 'hololake.gls-protocol-runtime-registry/v1',
|
schema: 'hololake.gls-runtime-manifest/v2',
|
||||||
record_id: 'HLP-GLS-PROTOCOL-RUNTIME-001',
|
record_id: 'HLP-GLS-RUNTIME-MANIFEST-002',
|
||||||
source: {
|
source: {
|
||||||
repository: 'REPO-012',
|
repository: 'REPO-012',
|
||||||
commit: sourceCommit,
|
commit: sourceCommit,
|
||||||
root: 'gls',
|
root: 'gls',
|
||||||
|
authority_files: authorityFiles,
|
||||||
},
|
},
|
||||||
compiler: {
|
compiler: {
|
||||||
source_protocol_is_human_and_machine_authority: true,
|
source_protocol_is_human_and_machine_authority: true,
|
||||||
|
|
@ -126,9 +341,25 @@ const registry = {
|
||||||
arbitrary_protocol_code_allowed: false,
|
arbitrary_protocol_code_allowed: false,
|
||||||
executable_projection_requires_explicit_adapter: true,
|
executable_projection_requires_explicit_adapter: true,
|
||||||
unprojected_protocol_behavior: 'INVENTORIED_NOT_EXECUTABLE',
|
unprojected_protocol_behavior: 'INVENTORIED_NOT_EXECUTABLE',
|
||||||
dependency_cycles: 'REJECT',
|
legacy_untyped_dependency_behavior: 'AUDIT_ONLY_BLOCKS_NEW_ACTIVATION',
|
||||||
|
runtime_graph_source: 'EXPLICIT_EXECUTABLE_PROJECTIONS_ONLY',
|
||||||
|
runtime_dependency_cycles: 'REJECT',
|
||||||
unknown_protocol: 'FAIL_CLOSED',
|
unknown_protocol: 'FAIL_CLOSED',
|
||||||
},
|
},
|
||||||
|
reconciliation: {
|
||||||
|
numbered_protocol_count: protocols.length,
|
||||||
|
protocol_registry_id_count: protocolRegistryIds.size,
|
||||||
|
existing_registered_count: (protocolRegistry.existing_registered || []).length,
|
||||||
|
registered_draft_count: (protocolRegistry.registered_draft_protocols || []).length,
|
||||||
|
registered_draft_not_started_count: (protocolRegistry.registered_draft_protocols || []).filter((entry) => entry.implementation === 'NOT_STARTED').length,
|
||||||
|
legacy_dependency_target_count: legacyDependencyTargets.size,
|
||||||
|
dependencies_not_in_protocol_registry: dependenciesNotInRegistry,
|
||||||
|
dependencies_without_numbered_source: dependenciesWithoutNumberedSource,
|
||||||
|
numbered_sources_not_in_protocol_registry: numberedSourcesNotInProtocolRegistry,
|
||||||
|
legacy_dependency_cycles: legacyDependencyCycles,
|
||||||
|
discovered_unreconciled_count: protocols.filter((protocol) => protocol.registration.state === 'DISCOVERED_UNRECONCILED').length,
|
||||||
|
authority_conflict_count: protocols.filter((protocol) => protocol.registration.state === 'REGISTRATION_CONFLICT').length,
|
||||||
|
},
|
||||||
protocol_count: protocols.length,
|
protocol_count: protocols.length,
|
||||||
executable_projection_count: executableCount,
|
executable_projection_count: executableCount,
|
||||||
inventoried_not_executable_count: protocols.length - executableCount,
|
inventoried_not_executable_count: protocols.length - executableCount,
|
||||||
|
|
@ -136,4 +367,4 @@ const registry = {
|
||||||
}
|
}
|
||||||
|
|
||||||
await writeFile(output, `${JSON.stringify(registry, null, 2)}\n`)
|
await writeFile(output, `${JSON.stringify(registry, null, 2)}\n`)
|
||||||
console.log(`GLS_RUNTIME_REGISTRY_COMPILED protocols=${protocols.length} executable=${executableCount} output=${output}`)
|
console.log(`GLS_RUNTIME_MANIFEST_COMPILED protocols=${protocols.length} registered=${protocolRegistryIds.size} executable=${executableCount} legacy_cycles=${legacyDependencyCycles.length} output=${output}`)
|
||||||
|
|
|
||||||
|
|
@ -4,18 +4,31 @@ import test from 'node:test'
|
||||||
|
|
||||||
const registryUrl = new URL('../contracts/gls-runtime-registry.json', import.meta.url)
|
const registryUrl = new URL('../contracts/gls-runtime-registry.json', import.meta.url)
|
||||||
|
|
||||||
test('compiled GLS registry inventories every current numbered protocol without executing raw text', async () => {
|
test('compiled GLS v2 manifest reconciles current registration sources without executing raw text', async () => {
|
||||||
const registry = JSON.parse(await readFile(registryUrl, 'utf8'))
|
const registry = JSON.parse(await readFile(registryUrl, 'utf8'))
|
||||||
|
|
||||||
assert.equal(registry.schema, 'hololake.gls-protocol-runtime-registry/v1')
|
assert.equal(registry.schema, 'hololake.gls-runtime-manifest/v2')
|
||||||
assert.equal(registry.source.repository, 'REPO-012')
|
assert.equal(registry.source.repository, 'REPO-012')
|
||||||
assert.equal(registry.source.commit, '2598fbfba8caf64c7ab9740a3036c5aab977502e')
|
assert.equal(registry.source.commit, '2598fbfba8caf64c7ab9740a3036c5aab977502e')
|
||||||
|
assert.equal(registry.source.authority_files.length, 4)
|
||||||
assert.equal(registry.compiler.raw_protocol_text_executed, false)
|
assert.equal(registry.compiler.raw_protocol_text_executed, false)
|
||||||
assert.equal(registry.compiler.arbitrary_protocol_code_allowed, false)
|
assert.equal(registry.compiler.arbitrary_protocol_code_allowed, false)
|
||||||
assert.equal(registry.compiler.unprojected_protocol_behavior, 'INVENTORIED_NOT_EXECUTABLE')
|
assert.equal(registry.compiler.unprojected_protocol_behavior, 'INVENTORIED_NOT_EXECUTABLE')
|
||||||
|
assert.equal(registry.compiler.legacy_untyped_dependency_behavior, 'AUDIT_ONLY_BLOCKS_NEW_ACTIVATION')
|
||||||
assert.equal(registry.protocol_count, 75)
|
assert.equal(registry.protocol_count, 75)
|
||||||
assert.equal(new Set(registry.protocols.map((protocol) => protocol.id)).size, 75)
|
assert.equal(new Set(registry.protocols.map((protocol) => protocol.id)).size, 75)
|
||||||
assert.ok(registry.protocols.every((protocol) => /^[a-f0-9]{64}$/.test(protocol.source_sha256)))
|
assert.ok(registry.protocols.every((protocol) => /^[a-f0-9]{64}$/.test(protocol.source_sha256)))
|
||||||
|
assert.equal(registry.reconciliation.protocol_registry_id_count, 52)
|
||||||
|
assert.equal(registry.reconciliation.existing_registered_count, 19)
|
||||||
|
assert.equal(registry.reconciliation.registered_draft_count, 33)
|
||||||
|
assert.equal(registry.reconciliation.registered_draft_not_started_count, 21)
|
||||||
|
assert.equal(registry.reconciliation.legacy_dependency_target_count, 57)
|
||||||
|
assert.equal(registry.reconciliation.dependencies_not_in_protocol_registry.length, 19)
|
||||||
|
assert.equal(registry.reconciliation.dependencies_without_numbered_source.length, 24)
|
||||||
|
assert.equal(registry.reconciliation.numbered_sources_not_in_protocol_registry.length, 31)
|
||||||
|
assert.equal(registry.reconciliation.legacy_dependency_cycles.length, 3)
|
||||||
|
assert.equal(registry.reconciliation.discovered_unreconciled_count, 0)
|
||||||
|
assert.equal(registry.reconciliation.authority_conflict_count, 0)
|
||||||
})
|
})
|
||||||
|
|
||||||
test('only explicit deterministic projections enter the runtime enforcement set', async () => {
|
test('only explicit deterministic projections enter the runtime enforcement set', async () => {
|
||||||
|
|
@ -25,6 +38,11 @@ test('only explicit deterministic projections enter the runtime enforcement set'
|
||||||
assert.equal(protocols['GLS-0253'].projection_state, 'EXECUTABLE_PROJECTION')
|
assert.equal(protocols['GLS-0253'].projection_state, 'EXECUTABLE_PROJECTION')
|
||||||
assert.equal(protocols['GLS-0253'].adapter, 'zero-core-numbering')
|
assert.equal(protocols['GLS-0253'].adapter, 'zero-core-numbering')
|
||||||
assert.ok(protocols['GLS-0253'].event_kinds.includes('IDENTITY_ROUTE'))
|
assert.ok(protocols['GLS-0253'].event_kinds.includes('IDENTITY_ROUTE'))
|
||||||
|
assert.ok(protocols['GLS-0253'].dependency_edges.every((edge) => edge.edge_kind === 'RUNTIME_REQUIRES'))
|
||||||
|
assert.equal(protocols['GLS-0130'].registration.state, 'REGISTERED_PROTOCOL_REGISTRY')
|
||||||
|
assert.equal(protocols['GLS-0130'].contract_kind, 'COMPILER_OR_INTERMEDIATE_REPRESENTATION')
|
||||||
|
assert.ok(protocols['GLS-0130'].dependency_edges.some((edge) => edge.target === 'GLS-0131' && edge.edge_kind === 'LEGACY_UNTYPED_REFERENCE' && !edge.enters_runtime_graph))
|
||||||
|
assert.ok(protocols['GLS-0130'].activation_blockers.includes('LEGACY_DEPENDENCIES_REQUIRE_TYPED_REVIEW'))
|
||||||
assert.equal(protocols['GLS-0003'], undefined)
|
assert.equal(protocols['GLS-0003'], undefined)
|
||||||
assert.equal(registry.executable_projection_count, 4)
|
assert.equal(registry.executable_projection_count, 4)
|
||||||
assert.equal(registry.inventoried_not_executable_count, 71)
|
assert.equal(registry.inventoried_not_executable_count, 71)
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ use serde::{Deserialize, Serialize};
|
||||||
use std::collections::{HashMap, HashSet};
|
use std::collections::{HashMap, HashSet};
|
||||||
|
|
||||||
const EMBEDDED_REGISTRY: &str = include_str!("../../contracts/gls-runtime-registry.json");
|
const EMBEDDED_REGISTRY: &str = include_str!("../../contracts/gls-runtime-registry.json");
|
||||||
const EXPECTED_SCHEMA: &str = "hololake.gls-protocol-runtime-registry/v1";
|
const EXPECTED_SCHEMA: &str = "hololake.gls-runtime-manifest/v2";
|
||||||
const EXPECTED_SOURCE_COMMIT: &str = "2598fbfba8caf64c7ab9740a3036c5aab977502e";
|
const EXPECTED_SOURCE_COMMIT: &str = "2598fbfba8caf64c7ab9740a3036c5aab977502e";
|
||||||
|
|
||||||
#[derive(Clone, Debug, Deserialize)]
|
#[derive(Clone, Debug, Deserialize)]
|
||||||
|
|
@ -15,6 +15,7 @@ struct GlsRuntimeRegistry {
|
||||||
schema: String,
|
schema: String,
|
||||||
source: GlsSource,
|
source: GlsSource,
|
||||||
compiler: GlsCompilerBoundary,
|
compiler: GlsCompilerBoundary,
|
||||||
|
reconciliation: GlsReconciliation,
|
||||||
protocol_count: usize,
|
protocol_count: usize,
|
||||||
executable_projection_count: usize,
|
executable_projection_count: usize,
|
||||||
inventoried_not_executable_count: usize,
|
inventoried_not_executable_count: usize,
|
||||||
|
|
@ -26,6 +27,14 @@ struct GlsSource {
|
||||||
repository: String,
|
repository: String,
|
||||||
commit: String,
|
commit: String,
|
||||||
root: String,
|
root: String,
|
||||||
|
authority_files: Vec<GlsAuthorityFile>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Deserialize)]
|
||||||
|
struct GlsAuthorityFile {
|
||||||
|
authority_kind: String,
|
||||||
|
source_path: String,
|
||||||
|
source_sha256: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Deserialize)]
|
#[derive(Clone, Debug, Deserialize)]
|
||||||
|
|
@ -34,18 +43,51 @@ struct GlsCompilerBoundary {
|
||||||
arbitrary_protocol_code_allowed: bool,
|
arbitrary_protocol_code_allowed: bool,
|
||||||
executable_projection_requires_explicit_adapter: bool,
|
executable_projection_requires_explicit_adapter: bool,
|
||||||
unprojected_protocol_behavior: String,
|
unprojected_protocol_behavior: String,
|
||||||
dependency_cycles: String,
|
legacy_untyped_dependency_behavior: String,
|
||||||
|
runtime_graph_source: String,
|
||||||
|
runtime_dependency_cycles: String,
|
||||||
unknown_protocol: String,
|
unknown_protocol: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Deserialize)]
|
||||||
|
struct GlsReconciliation {
|
||||||
|
numbered_protocol_count: usize,
|
||||||
|
protocol_registry_id_count: usize,
|
||||||
|
existing_registered_count: usize,
|
||||||
|
registered_draft_count: usize,
|
||||||
|
registered_draft_not_started_count: usize,
|
||||||
|
legacy_dependency_target_count: usize,
|
||||||
|
dependencies_not_in_protocol_registry: Vec<String>,
|
||||||
|
dependencies_without_numbered_source: Vec<String>,
|
||||||
|
numbered_sources_not_in_protocol_registry: Vec<String>,
|
||||||
|
legacy_dependency_cycles: Vec<Vec<String>>,
|
||||||
|
discovered_unreconciled_count: usize,
|
||||||
|
authority_conflict_count: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Deserialize)]
|
||||||
|
struct GlsRegistration {
|
||||||
|
state: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Deserialize)]
|
||||||
|
struct GlsDependencyEdge {
|
||||||
|
target: String,
|
||||||
|
edge_kind: String,
|
||||||
|
enters_runtime_graph: bool,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Deserialize)]
|
#[derive(Clone, Debug, Deserialize)]
|
||||||
struct GlsProtocol {
|
struct GlsProtocol {
|
||||||
id: String,
|
id: String,
|
||||||
source_sha256: String,
|
source_sha256: String,
|
||||||
|
registration: GlsRegistration,
|
||||||
projection_state: String,
|
projection_state: String,
|
||||||
adapter: Option<String>,
|
adapter: Option<String>,
|
||||||
event_kinds: Vec<String>,
|
event_kinds: Vec<String>,
|
||||||
dependencies: Vec<String>,
|
dependencies: Vec<String>,
|
||||||
|
dependency_edges: Vec<GlsDependencyEdge>,
|
||||||
|
activation_blockers: Vec<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Serialize)]
|
#[derive(Clone, Debug, Serialize)]
|
||||||
|
|
@ -58,6 +100,14 @@ pub struct GlsProtocolRuntimeSnapshot {
|
||||||
pub protocol_count: usize,
|
pub protocol_count: usize,
|
||||||
pub executable_projection_count: usize,
|
pub executable_projection_count: usize,
|
||||||
pub inventoried_not_executable_count: usize,
|
pub inventoried_not_executable_count: usize,
|
||||||
|
pub protocol_registry_id_count: usize,
|
||||||
|
pub registered_draft_count: usize,
|
||||||
|
pub registered_draft_not_started_count: usize,
|
||||||
|
pub legacy_dependency_target_count: usize,
|
||||||
|
pub dependency_gap_count: usize,
|
||||||
|
pub legacy_dependency_cycle_count: usize,
|
||||||
|
pub discovered_unreconciled_count: usize,
|
||||||
|
pub authority_conflict_count: usize,
|
||||||
pub active_adapters: Vec<String>,
|
pub active_adapters: Vec<String>,
|
||||||
pub raw_protocol_text_executed: bool,
|
pub raw_protocol_text_executed: bool,
|
||||||
pub arbitrary_protocol_code_allowed: bool,
|
pub arbitrary_protocol_code_allowed: bool,
|
||||||
|
|
@ -76,14 +126,34 @@ fn validate_registry(registry: &GlsRuntimeRegistry) -> Result<(), String> {
|
||||||
|| registry.source.repository != "REPO-012"
|
|| registry.source.repository != "REPO-012"
|
||||||
|| registry.source.commit != EXPECTED_SOURCE_COMMIT
|
|| registry.source.commit != EXPECTED_SOURCE_COMMIT
|
||||||
|| registry.source.root != "gls"
|
|| registry.source.root != "gls"
|
||||||
|
|| registry.source.authority_files.len() != 4
|
||||||
|| registry.compiler.raw_protocol_text_executed
|
|| registry.compiler.raw_protocol_text_executed
|
||||||
|| registry.compiler.arbitrary_protocol_code_allowed
|
|| registry.compiler.arbitrary_protocol_code_allowed
|
||||||
|| !registry
|
|| !registry
|
||||||
.compiler
|
.compiler
|
||||||
.executable_projection_requires_explicit_adapter
|
.executable_projection_requires_explicit_adapter
|
||||||
|| registry.compiler.unprojected_protocol_behavior != "INVENTORIED_NOT_EXECUTABLE"
|
|| registry.compiler.unprojected_protocol_behavior != "INVENTORIED_NOT_EXECUTABLE"
|
||||||
|| registry.compiler.dependency_cycles != "REJECT"
|
|| registry.compiler.legacy_untyped_dependency_behavior
|
||||||
|
!= "AUDIT_ONLY_BLOCKS_NEW_ACTIVATION"
|
||||||
|
|| registry.compiler.runtime_graph_source != "EXPLICIT_EXECUTABLE_PROJECTIONS_ONLY"
|
||||||
|
|| registry.compiler.runtime_dependency_cycles != "REJECT"
|
||||||
|| registry.compiler.unknown_protocol != "FAIL_CLOSED"
|
|| registry.compiler.unknown_protocol != "FAIL_CLOSED"
|
||||||
|
|| registry.reconciliation.numbered_protocol_count != registry.protocol_count
|
||||||
|
|| registry.reconciliation.protocol_registry_id_count != 52
|
||||||
|
|| registry.reconciliation.existing_registered_count != 19
|
||||||
|
|| registry.reconciliation.registered_draft_count != 33
|
||||||
|
|| registry.reconciliation.registered_draft_not_started_count != 21
|
||||||
|
|| registry.reconciliation.legacy_dependency_target_count != 57
|
||||||
|
|| registry.reconciliation.dependencies_not_in_protocol_registry.len() != 19
|
||||||
|
|| registry.reconciliation.dependencies_without_numbered_source.len() != 24
|
||||||
|
|| registry
|
||||||
|
.reconciliation
|
||||||
|
.numbered_sources_not_in_protocol_registry
|
||||||
|
.len()
|
||||||
|
!= 31
|
||||||
|
|| registry.reconciliation.legacy_dependency_cycles.len() != 3
|
||||||
|
|| registry.reconciliation.discovered_unreconciled_count != 0
|
||||||
|
|| registry.reconciliation.authority_conflict_count != 0
|
||||||
|| registry.protocol_count != registry.protocols.len()
|
|| registry.protocol_count != registry.protocols.len()
|
||||||
|| registry.protocol_count
|
|| registry.protocol_count
|
||||||
!= registry.executable_projection_count + registry.inventoried_not_executable_count
|
!= registry.executable_projection_count + registry.inventoried_not_executable_count
|
||||||
|
|
@ -91,6 +161,20 @@ fn validate_registry(registry: &GlsRuntimeRegistry) -> Result<(), String> {
|
||||||
return Err("HOLOLAKE_GLS_RUNTIME_BOUNDARY_INVALID".into());
|
return Err("HOLOLAKE_GLS_RUNTIME_BOUNDARY_INVALID".into());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let mut authority_kinds = HashSet::new();
|
||||||
|
for authority in ®istry.source.authority_files {
|
||||||
|
if !authority_kinds.insert(authority.authority_kind.as_str())
|
||||||
|
|| !authority.source_path.starts_with("gls/")
|
||||||
|
|| authority.source_sha256.len() != 64
|
||||||
|
|| !authority
|
||||||
|
.source_sha256
|
||||||
|
.chars()
|
||||||
|
.all(|character| character.is_ascii_hexdigit())
|
||||||
|
{
|
||||||
|
return Err("HOLOLAKE_GLS_AUTHORITY_SOURCE_INVALID".into());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let mut ids = HashSet::new();
|
let mut ids = HashSet::new();
|
||||||
let mut executable = 0;
|
let mut executable = 0;
|
||||||
for protocol in ®istry.protocols {
|
for protocol in ®istry.protocols {
|
||||||
|
|
@ -109,6 +193,7 @@ fn validate_registry(registry: &GlsRuntimeRegistry) -> Result<(), String> {
|
||||||
executable += 1;
|
executable += 1;
|
||||||
if protocol.adapter.as_deref().unwrap_or("").is_empty()
|
if protocol.adapter.as_deref().unwrap_or("").is_empty()
|
||||||
|| protocol.event_kinds.is_empty()
|
|| protocol.event_kinds.is_empty()
|
||||||
|
|| !protocol.activation_blockers.is_empty()
|
||||||
{
|
{
|
||||||
return Err("HOLOLAKE_GLS_EXECUTABLE_ADAPTER_REQUIRED".into());
|
return Err("HOLOLAKE_GLS_EXECUTABLE_ADAPTER_REQUIRED".into());
|
||||||
}
|
}
|
||||||
|
|
@ -123,6 +208,33 @@ fn validate_registry(registry: &GlsRuntimeRegistry) -> Result<(), String> {
|
||||||
}
|
}
|
||||||
_ => return Err("HOLOLAKE_GLS_PROJECTION_STATE_UNKNOWN".into()),
|
_ => return Err("HOLOLAKE_GLS_PROJECTION_STATE_UNKNOWN".into()),
|
||||||
}
|
}
|
||||||
|
if !matches!(
|
||||||
|
protocol.registration.state.as_str(),
|
||||||
|
"REGISTERED_PROTOCOL_REGISTRY" | "REGISTERED_OTHER_CANONICAL_INDEX"
|
||||||
|
) {
|
||||||
|
return Err("HOLOLAKE_GLS_REGISTRATION_NOT_RECONCILED".into());
|
||||||
|
}
|
||||||
|
for edge in &protocol.dependency_edges {
|
||||||
|
match edge.edge_kind.as_str() {
|
||||||
|
"RUNTIME_REQUIRES" if edge.enters_runtime_graph => {}
|
||||||
|
"LEGACY_UNTYPED_REFERENCE" if !edge.enters_runtime_graph => {}
|
||||||
|
_ => return Err("HOLOLAKE_GLS_DEPENDENCY_EDGE_INVALID".into()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let runtime_edges = protocol
|
||||||
|
.dependency_edges
|
||||||
|
.iter()
|
||||||
|
.filter(|edge| edge.enters_runtime_graph)
|
||||||
|
.map(|edge| edge.target.as_str())
|
||||||
|
.collect::<HashSet<_>>();
|
||||||
|
let runtime_dependencies = protocol
|
||||||
|
.dependencies
|
||||||
|
.iter()
|
||||||
|
.map(String::as_str)
|
||||||
|
.collect::<HashSet<_>>();
|
||||||
|
if runtime_edges != runtime_dependencies {
|
||||||
|
return Err("HOLOLAKE_GLS_RUNTIME_DEPENDENCY_MISMATCH".into());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if executable != registry.executable_projection_count {
|
if executable != registry.executable_projection_count {
|
||||||
return Err("HOLOLAKE_GLS_EXECUTABLE_COUNT_MISMATCH".into());
|
return Err("HOLOLAKE_GLS_EXECUTABLE_COUNT_MISMATCH".into());
|
||||||
|
|
@ -212,6 +324,19 @@ pub async fn get_gls_protocol_runtime() -> Result<GlsProtocolRuntimeSnapshot, St
|
||||||
protocol_count: registry.protocol_count,
|
protocol_count: registry.protocol_count,
|
||||||
executable_projection_count: registry.executable_projection_count,
|
executable_projection_count: registry.executable_projection_count,
|
||||||
inventoried_not_executable_count: registry.inventoried_not_executable_count,
|
inventoried_not_executable_count: registry.inventoried_not_executable_count,
|
||||||
|
protocol_registry_id_count: registry.reconciliation.protocol_registry_id_count,
|
||||||
|
registered_draft_count: registry.reconciliation.registered_draft_count,
|
||||||
|
registered_draft_not_started_count: registry
|
||||||
|
.reconciliation
|
||||||
|
.registered_draft_not_started_count,
|
||||||
|
legacy_dependency_target_count: registry.reconciliation.legacy_dependency_target_count,
|
||||||
|
dependency_gap_count: registry
|
||||||
|
.reconciliation
|
||||||
|
.dependencies_without_numbered_source
|
||||||
|
.len(),
|
||||||
|
legacy_dependency_cycle_count: registry.reconciliation.legacy_dependency_cycles.len(),
|
||||||
|
discovered_unreconciled_count: registry.reconciliation.discovered_unreconciled_count,
|
||||||
|
authority_conflict_count: registry.reconciliation.authority_conflict_count,
|
||||||
active_adapters,
|
active_adapters,
|
||||||
raw_protocol_text_executed: registry.compiler.raw_protocol_text_executed,
|
raw_protocol_text_executed: registry.compiler.raw_protocol_text_executed,
|
||||||
arbitrary_protocol_code_allowed: registry.compiler.arbitrary_protocol_code_allowed,
|
arbitrary_protocol_code_allowed: registry.compiler.arbitrary_protocol_code_allowed,
|
||||||
|
|
@ -228,6 +353,10 @@ mod tests {
|
||||||
let registry = load_registry().unwrap();
|
let registry = load_registry().unwrap();
|
||||||
assert_eq!(registry.protocol_count, 75);
|
assert_eq!(registry.protocol_count, 75);
|
||||||
assert_eq!(registry.executable_projection_count, 4);
|
assert_eq!(registry.executable_projection_count, 4);
|
||||||
|
assert_eq!(registry.reconciliation.protocol_registry_id_count, 52);
|
||||||
|
assert_eq!(registry.reconciliation.legacy_dependency_target_count, 57);
|
||||||
|
assert_eq!(registry.reconciliation.legacy_dependency_cycles.len(), 3);
|
||||||
|
assert_eq!(registry.reconciliation.authority_conflict_count, 0);
|
||||||
assert!(!registry.compiler.raw_protocol_text_executed);
|
assert!(!registry.compiler.raw_protocol_text_executed);
|
||||||
assert!(!registry.compiler.arbitrary_protocol_code_allowed);
|
assert!(!registry.compiler.arbitrary_protocol_code_allowed);
|
||||||
}
|
}
|
||||||
|
|
@ -249,4 +378,26 @@ mod tests {
|
||||||
"HOLOLAKE_GLS_EXECUTABLE_ADAPTER_NOT_REGISTERED"
|
"HOLOLAKE_GLS_EXECUTABLE_ADAPTER_NOT_REGISTERED"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn registration_and_dependency_manifest_tampering_fail_closed() {
|
||||||
|
let mut registration_tamper = load_registry().unwrap();
|
||||||
|
registration_tamper.reconciliation.authority_conflict_count = 1;
|
||||||
|
assert_eq!(
|
||||||
|
validate_registry(®istration_tamper).unwrap_err(),
|
||||||
|
"HOLOLAKE_GLS_RUNTIME_BOUNDARY_INVALID"
|
||||||
|
);
|
||||||
|
|
||||||
|
let mut dependency_tamper = load_registry().unwrap();
|
||||||
|
let numbering = dependency_tamper
|
||||||
|
.protocols
|
||||||
|
.iter_mut()
|
||||||
|
.find(|protocol| protocol.id == "GLS-0253")
|
||||||
|
.unwrap();
|
||||||
|
numbering.dependency_edges[0].edge_kind = "LEGACY_UNTYPED_REFERENCE".into();
|
||||||
|
assert_eq!(
|
||||||
|
validate_registry(&dependency_tamper).unwrap_err(),
|
||||||
|
"HOLOLAKE_GLS_DEPENDENCY_EDGE_INVALID"
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -89,6 +89,14 @@ interface GlsProtocolRuntimeSnapshot {
|
||||||
protocolCount: number
|
protocolCount: number
|
||||||
executableProjectionCount: number
|
executableProjectionCount: number
|
||||||
inventoriedNotExecutableCount: number
|
inventoriedNotExecutableCount: number
|
||||||
|
protocolRegistryIdCount: number
|
||||||
|
registeredDraftCount: number
|
||||||
|
registeredDraftNotStartedCount: number
|
||||||
|
legacyDependencyTargetCount: number
|
||||||
|
dependencyGapCount: number
|
||||||
|
legacyDependencyCycleCount: number
|
||||||
|
discoveredUnreconciledCount: number
|
||||||
|
authorityConflictCount: number
|
||||||
activeAdapters: string[]
|
activeAdapters: string[]
|
||||||
rawProtocolTextExecuted: boolean
|
rawProtocolTextExecuted: boolean
|
||||||
arbitraryProtocolCodeAllowed: boolean
|
arbitraryProtocolCodeAllowed: boolean
|
||||||
|
|
@ -1364,7 +1372,7 @@ function HoloLakeApp() {
|
||||||
<button className="secondary-button" type="button" disabled={serverPnccBusy} onClick={() => void refreshServerPncc()}>{serverPnccBusy ? '正在读取…' : '重新读取主控状态'}</button>
|
<button className="secondary-button" type="button" disabled={serverPnccBusy} onClick={() => void refreshServerPncc()}>{serverPnccBusy ? '正在读取…' : '重新读取主控状态'}</button>
|
||||||
</section>
|
</section>
|
||||||
<section className="plain-panel"><header><div><h2>本机 GH-PNCC 投影</h2><p>本机仓库挂载、开发写入通道与读取回执来自同一运行事件流。</p></div></header><dl className="evidence-list"><div><dt>已挂载仓库</dt><dd>{status.codeRepositoryMountCount}</dd></div><div><dt>投影回执</dt><dd>{status.pnccReceiptCount}</dd></div><div><dt>开发执行通道</dt><dd>{developmentLane?.state === 'ACTIVE' ? '已切入 HoloLake' : '等待受控载体'}</dd></div><div><dt>当前开发线</dt><dd>{developmentLane?.laneId || '—'}</dd></div><div><dt>当前写入载体</dt><dd>{developmentLane?.ownerInstanceId || '—'}</dd></div><div><dt>当前结论</dt><dd>{developmentLane?.state === 'ACTIVE' ? '开发执行环境已由 HoloLake 持有单写通道' : status.codeRepositoryMountCount > 0 && status.pnccReceiptCount > 0 ? '已有可核验运行记录' : '接口已接入,尚无完整运行记录'}</dd></div></dl></section>
|
<section className="plain-panel"><header><div><h2>本机 GH-PNCC 投影</h2><p>本机仓库挂载、开发写入通道与读取回执来自同一运行事件流。</p></div></header><dl className="evidence-list"><div><dt>已挂载仓库</dt><dd>{status.codeRepositoryMountCount}</dd></div><div><dt>投影回执</dt><dd>{status.pnccReceiptCount}</dd></div><div><dt>开发执行通道</dt><dd>{developmentLane?.state === 'ACTIVE' ? '已切入 HoloLake' : '等待受控载体'}</dd></div><div><dt>当前开发线</dt><dd>{developmentLane?.laneId || '—'}</dd></div><div><dt>当前写入载体</dt><dd>{developmentLane?.ownerInstanceId || '—'}</dd></div><div><dt>当前结论</dt><dd>{developmentLane?.state === 'ACTIVE' ? '开发执行环境已由 HoloLake 持有单写通道' : status.codeRepositoryMountCount > 0 && status.pnccReceiptCount > 0 ? '已有可核验运行记录' : '接口已接入,尚无完整运行记录'}</dd></div></dl></section>
|
||||||
<section className="plain-panel"><header><div><h2>GLS 协议运行层</h2><p>正本先编译为机器合同;只有已经登记确定性适配器的协议进入执行集。</p></div><span className={glsRuntime?.state === 'ACTIVE_EXPLICIT_PROJECTIONS_ONLY' ? 'status-chip online' : 'status-chip'}>{glsRuntime ? '原生注册表已加载' : '失败关闭'}</span></header>{glsRuntime ? <dl className="evidence-list"><div><dt>正本来源</dt><dd>{glsRuntime.sourceRepository} · {glsRuntime.sourceCommit.slice(0, 12)}</dd></div><div><dt>已编译协议</dt><dd>{glsRuntime.protocolCount}</dd></div><div><dt>当前工程执行</dt><dd>{glsRuntime.executableProjectionCount}</dd></div><div><dt>已收录待工程化</dt><dd>{glsRuntime.inventoriedNotExecutableCount}</dd></div><div><dt>原文直接执行</dt><dd>{glsRuntime.rawProtocolTextExecuted ? '允许' : '禁止'}</dd></div><div><dt>任意协议代码</dt><dd>{glsRuntime.arbitraryProtocolCodeAllowed ? '允许' : '禁止'}</dd></div></dl> : <p className="boundary-note">GLS 运行注册表不可读,协议适配器全部保持关闭。</p>}</section>
|
<section className="plain-panel"><header><div><h2>GLS 协议运行层</h2><p>正本先完成注册对账和依赖分型;只有显式原生适配器进入执行图。</p></div><span className={glsRuntime?.state === 'ACTIVE_EXPLICIT_PROJECTIONS_ONLY' && glsRuntime.authorityConflictCount === 0 && glsRuntime.discoveredUnreconciledCount === 0 ? 'status-chip online' : 'status-chip'}>{glsRuntime ? '运行清单 v2 已加载' : '失败关闭'}</span></header>{glsRuntime ? <dl className="evidence-list"><div><dt>正本来源</dt><dd>{glsRuntime.sourceRepository} · {glsRuntime.sourceCommit.slice(0, 12)}</dd></div><div><dt>已发现编号协议</dt><dd>{glsRuntime.protocolCount}</dd></div><div><dt>协议注册表编号</dt><dd>{glsRuntime.protocolRegistryIdCount}</dd></div><div><dt>注册草案</dt><dd>{glsRuntime.registeredDraftCount} · {glsRuntime.registeredDraftNotStartedCount} 尚未实现</dd></div><div><dt>当前工程执行</dt><dd>{glsRuntime.executableProjectionCount}</dd></div><div><dt>已收录待工程化</dt><dd>{glsRuntime.inventoriedNotExecutableCount}</dd></div><div><dt>旧依赖目标</dt><dd>{glsRuntime.legacyDependencyTargetCount} · {glsRuntime.legacyDependencyCycleCount} 组待拆环</dd></div><div><dt>缺少编号正本的依赖</dt><dd>{glsRuntime.dependencyGapCount}</dd></div><div><dt>登记冲突 / 未对账</dt><dd>{glsRuntime.authorityConflictCount} / {glsRuntime.discoveredUnreconciledCount}</dd></div><div><dt>原文直接执行</dt><dd>{glsRuntime.rawProtocolTextExecuted ? '允许' : '禁止'}</dd></div><div><dt>任意协议代码</dt><dd>{glsRuntime.arbitraryProtocolCodeAllowed ? '允许' : '禁止'}</dd></div></dl> : <p className="boundary-note">GLS 运行清单不可读,协议适配器全部保持关闭。</p>}</section>
|
||||||
<section className="plain-panel"><header><div><h2>零点原核编号内核</h2><p>先按权威图确定主体类别与登记面,再进入编号核验;编号外形本身不构成权威。</p></div><span className={numberingKernel?.state === 'ACTIVE_PINNED_AUTHORITY_MAP' ? 'status-chip online' : 'status-chip'}>{numberingKernel ? '本机内核已加载' : '失败关闭'}</span></header>{numberingKernel ? <dl className="evidence-list"><div><dt>权威图</dt><dd>{numberingKernel.authorityMapId}</dd></div><div><dt>权威图版本</dt><dd>{numberingKernel.authorityMapVersion}</dd></div><div><dt>正本提交</dt><dd>{numberingKernel.sourceCommit.slice(0, 12)}</dd></div><div><dt>人类入口命名空间</dt><dd>{numberingKernel.humanRouteNamespaces.join(' · ')}</dd></div><div><dt>自动派发身份号</dt><dd>{numberingKernel.automaticIdentityIssuance ? '已开启' : '禁止'}</dd></div><div><dt>未知编号</dt><dd>{numberingKernel.unknownNumber === 'FAIL_CLOSED' ? '失败关闭 · 不猜测' : numberingKernel.unknownNumber}</dd></div></dl> : <p className="boundary-note">编号内核不可读,所有编号路由保持关闭。</p>}</section>
|
<section className="plain-panel"><header><div><h2>零点原核编号内核</h2><p>先按权威图确定主体类别与登记面,再进入编号核验;编号外形本身不构成权威。</p></div><span className={numberingKernel?.state === 'ACTIVE_PINNED_AUTHORITY_MAP' ? 'status-chip online' : 'status-chip'}>{numberingKernel ? '本机内核已加载' : '失败关闭'}</span></header>{numberingKernel ? <dl className="evidence-list"><div><dt>权威图</dt><dd>{numberingKernel.authorityMapId}</dd></div><div><dt>权威图版本</dt><dd>{numberingKernel.authorityMapVersion}</dd></div><div><dt>正本提交</dt><dd>{numberingKernel.sourceCommit.slice(0, 12)}</dd></div><div><dt>人类入口命名空间</dt><dd>{numberingKernel.humanRouteNamespaces.join(' · ')}</dd></div><div><dt>自动派发身份号</dt><dd>{numberingKernel.automaticIdentityIssuance ? '已开启' : '禁止'}</dd></div><div><dt>未知编号</dt><dd>{numberingKernel.unknownNumber === 'FAIL_CLOSED' ? '失败关闭 · 不猜测' : numberingKernel.unknownNumber}</dd></div></dl> : <p className="boundary-note">编号内核不可读,所有编号路由保持关闭。</p>}</section>
|
||||||
<section className="plain-panel">
|
<section className="plain-panel">
|
||||||
<header><div><h2>用户编号验证</h2><p>用户编号必须通过登记服务验证。验证结果不构成人格绑定、模型载体绑定或执行授权。</p></div><span className={zeroPoint?.route === 'verified' ? 'status-chip online' : 'status-chip'}>{zeroPoint ? (zeroPoint.route === 'verified' ? '验证有效' : '功能受限') : '正在读取'}</span></header>
|
<header><div><h2>用户编号验证</h2><p>用户编号必须通过登记服务验证。验证结果不构成人格绑定、模型载体绑定或执行授权。</p></div><span className={zeroPoint?.route === 'verified' ? 'status-chip online' : 'status-chip'}>{zeroPoint ? (zeroPoint.route === 'verified' ? '验证有效' : '功能受限') : '正在读取'}</span></header>
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue