feat(ontology): add device asset infrastructure domains

This commit is contained in:
Codex
2026-08-22 14:15:57 +03:00
parent 209f4f439e
commit e2ea7e177d
46 changed files with 1324 additions and 14 deletions
@@ -0,0 +1,104 @@
#!/usr/bin/env node
import assert from 'node:assert/strict'
import fs from 'node:fs/promises'
import path from 'node:path'
import { loadCatalog, serviceRoot } from '../catalog.mjs'
const catalog = await loadCatalog()
const directFixture = JSON.parse(
await fs.readFile(path.join(serviceRoot, 'examples/device-direct-b2-composition.fixture.json'), 'utf8'),
)
const infrastructureFixture = JSON.parse(
await fs.readFile(path.join(serviceRoot, 'examples/infrastructure-edge-host-composition.fixture.json'), 'utf8'),
)
const requiredEntities = [
directFixture.project.entityId,
directFixture.asset.entityId,
directFixture.device.entityId,
directFixture.device.restrictedIdentifiers[0].entityId,
directFixture.device.modelProfile.entityId,
directFixture.binding.entityId,
directFixture.positionObservation.entityId,
directFixture.positionObservation.projectionEntityId,
infrastructureFixture.host.entityId,
infrastructureFixture.endpoint.entityId,
infrastructureFixture.deployment.entityId,
infrastructureFixture.serviceInstance.entityId,
infrastructureFixture.edgeRegistration.entityId,
infrastructureFixture.healthObservation.entityId,
infrastructureFixture.management.credentialEntityId,
infrastructureFixture.management.consoleEntityId,
]
for (const entityId of requiredEntities) {
assert.equal(catalog.entityById.has(entityId), true, `fixture entity missing from catalog: ${entityId}`)
}
for (const relationId of [
'device.tracking_device.tracks_asset',
'device.asset_binding.attaches_device',
'device.asset_binding.attaches_asset',
'asset.asset.is_map_moving_object',
'observation.position_observation.positions_asset',
'infrastructure.host.exposes_endpoint',
'infrastructure.deployment.targets_host',
'infrastructure.service_instance.runs_on_host',
'infrastructure.service_instance.realizes_deployment',
'device.edge_registration.runs_as_service_instance',
'observation.health_observation.targets_infrastructure',
'gelios.unit.maps_to_asset',
'gelios.tracker_device.maps_to_tracking_device',
'gelios.position_fix.maps_to_position_observation',
]) {
assert.equal(catalog.relationById.has(relationId), true, `required relation missing: ${relationId}`)
}
assert.notEqual(directFixture.asset.sourceId, directFixture.device.sourceId)
assert.equal(directFixture.binding.assetSourceId, directFixture.asset.sourceId)
assert.equal(directFixture.binding.deviceSourceId, directFixture.device.sourceId)
assert.equal(directFixture.binding.validTo, null)
assert.equal(directFixture.device.restrictedIdentifiers[0].valueExposure, 'restricted')
assert.equal(JSON.stringify(directFixture).includes('integration.connection'), false)
const infrastructureIds = [
infrastructureFixture.host.sourceId,
infrastructureFixture.endpoint.sourceId,
infrastructureFixture.deployment.sourceId,
infrastructureFixture.serviceInstance.sourceId,
infrastructureFixture.edgeRegistration.sourceId,
]
assert.equal(new Set(infrastructureIds).size, infrastructureIds.length)
assert.equal(infrastructureFixture.management.secretExposure, 'opaque-reference-only')
assert.equal(infrastructureFixture.management.mode, 'privileged-break-glass')
for (const guardrailId of [
'guardrail.asset.identity_survives_device_changes',
'guardrail.device.identifiers_are_restricted_not_identity',
'guardrail.device.asset_attachment_is_temporal',
'guardrail.infrastructure.host_is_not_connection',
'guardrail.infrastructure.management_is_break_glass',
'guardrail.observation.missing_is_not_automatically_unhealthy',
'guardrail.gelios.neutral_composition_requires_explicit_binding',
]) {
assert.equal(
catalog.guardrails.rules.some((rule) => rule.id === guardrailId),
true,
`required guardrail missing: ${guardrailId}`,
)
}
console.log(JSON.stringify({
ok: true,
checks: [
'direct_b2_and_trike_have_distinct_identities',
'device_asset_binding_is_temporal',
'imei_exposure_is_restricted',
'direct_fixture_has_no_gelios_dependency',
'host_runtime_layers_have_distinct_identities',
'management_secret_is_opaque_reference_only',
'neutral_gelios_bridge_relations_exist',
'composition_guardrails_exist',
],
}, null, 2))
@@ -66,6 +66,51 @@ try {
})
assert.equal(guardrails.result.structuredContent.rules.some((rule) => rule.id === 'guardrail.gelios.commands_are_red_domain'), true)
const directTracker = await rpc(baseUrl, TOKEN, 51, 'tools/call', {
name: 'ontology_get_entity',
arguments: { term: 'B2 tracker' },
})
assert.equal(directTracker.result.structuredContent.entity.id, 'device.tracking_device')
const infrastructureHost = await rpc(baseUrl, TOKEN, 52, 'tools/call', {
name: 'ontology_get_entity',
arguments: { term: 'внешний VPS' },
})
assert.equal(infrastructureHost.result.structuredContent.entity.id, 'infrastructure.host')
const restrictedIdentifierGuardrails = await rpc(baseUrl, TOKEN, 53, 'tools/call', {
name: 'ontology_get_guardrails',
arguments: { entityId: 'device.restricted_identifier' },
})
assert.equal(
restrictedIdentifierGuardrails.result.structuredContent.rules.some(
(rule) => rule.id === 'guardrail.device.identifiers_are_restricted_not_identity',
),
true,
)
const hostGuardrails = await rpc(baseUrl, TOKEN, 54, 'tools/call', {
name: 'ontology_get_guardrails',
arguments: { entityId: 'infrastructure.host' },
})
assert.equal(
hostGuardrails.result.structuredContent.rules.some(
(rule) => rule.id === 'guardrail.infrastructure.host_is_not_connection',
),
true,
)
const positionObservation = await rpc(baseUrl, TOKEN, 55, 'tools/call', {
name: 'ontology_get_entity',
arguments: { entityId: 'observation.position_observation' },
})
assert.equal(
positionObservation.result.structuredContent.relations.some(
(relation) => relation.id === 'gelios.position_fix.maps_to_position_observation',
),
true,
)
const unauthorized = await fetch(`${baseUrl}/mcp`, {
method: 'POST',
headers: { 'content-type': 'application/json' },
@@ -82,6 +127,11 @@ try {
'gelios_alias_resolution',
'gelios_value_contract_visible',
'gelios_command_guardrail_visible',
'direct_b2_tracker_alias_resolution',
'infrastructure_host_alias_resolution',
'restricted_identifier_guardrail_visible',
'host_connection_conflation_blocked',
'gelios_position_neutral_mapping_visible',
'evidence_paths_not_exposed',
'internal_bearer_required',
],