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
+5
View File
@@ -167,6 +167,11 @@ Current package:
- `seo` - NDC SEO mod domain ontology for site scans, project ontology instances, scope contracts, semantic analysis, market evidence, optimization planning, validation, changesets, and future app-owned SEO assistant actions.
- `map` - provider-neutral NDC Module Studio map ontology for spatial subjects, layers, routes, zones, shared labels, visibility rules, selection, and replaceable renderer adapters.
- `gelios` - provider-neutral Gelios fleet and telemetry ontology, bound to map.moving_object, map.zone and map.place_target without exposing provider credentials or renderer objects.
- `party` - provider-neutral people, organizations, accounts, access subjects, contacts and temporal operational roles.
- `asset` - stable business assets, external references, assignments and lifecycle evidence independent of tracker or provider identity.
- `device` - Device Core direct onboarding, adapter, enrollment, temporal Asset binding, Edge route, session, configuration, typed command and audit ontology.
- `infrastructure` - provider-neutral Host, Endpoint, Deployment, Service Instance and privileged management-session topology for VPS and Edge infrastructure.
- `observation` - time-qualified property, source, freshness, health and position evidence for Assets, Devices and infrastructure.
The package loader merges domain packages into the base catalog before validation. Domain packages extend core meanings; they do not own app data or execute mutations.
@@ -0,0 +1,13 @@
{
"version": "0.1.0",
"updatedAt": "2026-08-22",
"aliases": [
{ "alias": "business asset", "canonicalId": "asset.asset" },
{ "alias": "бизнес-актив", "canonicalId": "asset.asset" },
{ "alias": "трайк как актив", "canonicalId": "asset.asset" },
{ "alias": "тип актива", "canonicalId": "asset.asset_type" },
{ "alias": "внешняя ссылка актива", "canonicalId": "asset.external_reference" },
{ "alias": "назначение актива", "canonicalId": "asset.assignment" },
{ "alias": "событие жизненного цикла актива", "canonicalId": "asset.lifecycle_event" }
]
}
@@ -0,0 +1,11 @@
{
"version": "0.1.0",
"updatedAt": "2026-08-22",
"entities": [
{ "id": "asset.asset", "name": "Asset", "surface": "domain", "status": ["product-required"], "authority": "Owning business domain", "summary": "Stable business or operational object such as a trike, vehicle, machine or facility whose identity survives device, provider and renderer changes." },
{ "id": "asset.asset_type", "name": "Asset Type", "surface": "domain", "status": ["product-required"], "authority": "Owning business domain + Ontology Core", "summary": "Versioned semantic classification of an asset without forcing a rigid inheritance hierarchy." },
{ "id": "asset.external_reference", "name": "Asset External Reference", "surface": "domain", "status": ["product-required"], "authority": "Owning business domain", "summary": "Namespaced reference linking an asset to a source-system record without replacing the NODE.DC asset identity." },
{ "id": "asset.assignment", "name": "Asset Assignment", "surface": "domain", "status": ["product-required"], "authority": "Owning operations domain", "summary": "Time-qualified relationship connecting an asset to a party, role, project or other operational context with provenance and validity interval." },
{ "id": "asset.lifecycle_event", "name": "Asset Lifecycle Event", "surface": "domain", "status": ["product-required"], "authority": "Owning business domain", "summary": "Immutable evidence of an asset lifecycle transition such as commissioning, activation, suspension, retirement or transfer." }
]
}
@@ -0,0 +1,18 @@
{
"version": "0.1.0",
"updatedAt": "2026-08-22",
"sourceRoots": [
{ "surface": "device-core", "path": "/Users/dcconstructions/Downloads/mnt/NODEDC/NODEDC_DEVICE_CORE", "mode": "Read-only device, project, binding, direct lifecycle and restricted-identifier source inspection" },
{ "surface": "foundry", "path": "foundry://application/1c7dcdbb-6e50-4272-b1bc-aa5ece77ae99", "mode": "Robot2B Data Product composition and moving-object projection inspection" },
{ "surface": "ops-decision", "path": "DCPLATFORM-70", "mode": "Accepted direct B2, trike Asset and temporal attachment decision" }
],
"ledgers": [
{ "id": "ledger.asset_domain_v0", "path": "docs/PARTY_ASSET_DOMAIN_ONTOLOGY.md", "entityIds": ["asset.asset", "asset.asset_type", "asset.external_reference", "asset.assignment", "asset.lifecycle_event"] }
],
"baselineDocs": ["docs/PARTY_ASSET_DOMAIN_ONTOLOGY.md"],
"restrictions": [
"Do not use IMEI, provider unit ID, current tracker or renderer ID as the Asset identity.",
"Do not hide reassignment history by mutating one current owner, driver or device field.",
"Do not publish an Asset to a map without a declared spatial observation and Data Product semantic binding."
]
}
@@ -0,0 +1,38 @@
{
"version": "0.1.0",
"updatedAt": "2026-08-22",
"rules": [
{
"id": "guardrail.asset.identity_survives_device_changes",
"severity": "error",
"summary": "Asset identity must not be derived from IMEI, tracker, provider unit, current driver, project or renderer object; those are separate graph subjects and assignments.",
"entityIds": ["asset.asset", "device.tracking_device", "device.restricted_identifier", "gelios.unit", "party.driver_role", "map.moving_object"]
},
{
"id": "guardrail.asset.assignments_are_temporal",
"severity": "error",
"summary": "Asset-to-party, driver, project and device composition requires explicit provenance and valid_from/valid_to semantics; overwriting the current label is not history.",
"entityIds": ["asset.asset", "asset.assignment", "party.driver_role", "device.asset_binding"]
},
{
"id": "guardrail.asset.map_projection_requires_spatial_evidence",
"severity": "error",
"summary": "Foundry may render an asset as a moving object only through a declared Data Product binding backed by a time-qualified spatial observation.",
"entityIds": ["asset.asset", "map.moving_object", "observation.position_observation"]
},
{
"id": "guardrail.asset.ontology_not_asset_store",
"severity": "error",
"summary": "Ontology Core defines Asset meaning and relations; it must not store runtime asset rows, assignments, live positions or lifecycle logs.",
"entityIds": ["asset.asset", "asset.assignment", "asset.lifecycle_event"]
}
],
"blockedConflations": [
["asset.asset", "device.device"],
["asset.asset", "device.tracking_device"],
["asset.asset", "device.restricted_identifier"],
["asset.asset", "gelios.unit"],
["asset.asset", "map.moving_object"],
["asset.assignment", "asset.lifecycle_event"]
]
}
@@ -0,0 +1,7 @@
{
"id": "asset",
"version": "0.1.0",
"updatedAt": "2026-08-22",
"status": "product-required/source-evidenced",
"summary": "Stable business assets, classifications, external references, temporal assignments and lifecycle evidence independent of a tracker, provider or renderer."
}
@@ -0,0 +1,12 @@
{
"version": "0.1.0",
"updatedAt": "2026-08-22",
"relations": [
{ "id": "asset.asset.classified_by_type", "from": ["asset.asset"], "to": ["asset.asset_type"], "status": "product-required", "summary": "An asset uses a versioned semantic type while remaining a stable shallow graph subject." },
{ "id": "asset.asset.has_external_reference", "from": ["asset.asset"], "to": ["asset.external_reference"], "status": "product-required", "summary": "An asset may have multiple namespaced provider or source-system references." },
{ "id": "asset.asset.has_assignment", "from": ["asset.asset"], "to": ["asset.assignment"], "status": "product-required", "summary": "Operational composition is represented by explicit assignments with provenance and validity intervals." },
{ "id": "asset.assignment.assigns_party", "from": ["asset.assignment"], "to": ["party.party", "party.driver_role"], "status": "product-required", "summary": "An assignment connects the asset to a party or operational role for a bounded interval." },
{ "id": "asset.asset.has_lifecycle_event", "from": ["asset.asset"], "to": ["asset.lifecycle_event"], "status": "product-required", "summary": "Lifecycle transitions are preserved as evidence rather than overwritten status labels." },
{ "id": "asset.asset.is_map_moving_object", "from": ["asset.asset"], "to": ["map.moving_object"], "status": "product-required", "summary": "An asset with spatial evidence can be projected into Foundry through the provider-neutral moving-object contract without adopting renderer identity." }
]
}
@@ -0,0 +1,20 @@
{
"version": "0.1.0",
"updatedAt": "2026-08-22",
"aliases": [
{ "alias": "управляемое устройство Device Core", "canonicalId": "device.device" },
{ "alias": "трекер Device Core", "canonicalId": "device.tracking_device" },
{ "alias": "B2 tracker", "canonicalId": "device.tracking_device" },
{ "alias": "привязка трекера к активу", "canonicalId": "device.asset_binding" },
{ "alias": "IMEI устройства", "canonicalId": "device.restricted_identifier" },
{ "alias": "пакет адаптера устройства", "canonicalId": "device.adapter_package" },
{ "alias": "профиль модели устройства", "canonicalId": "device.model_profile" },
{ "alias": "намерение регистрации устройства", "canonicalId": "device.enrollment_intent" },
{ "alias": "регистрация Edge Device Core", "canonicalId": "device.edge_registration" },
{ "alias": "маршрут устройства Device Core", "canonicalId": "device.route" },
{ "alias": "сессия устройства Device Core", "canonicalId": "device.session" },
{ "alias": "ревизия конфигурации устройства", "canonicalId": "device.configuration_revision" },
{ "alias": "командное намерение устройства", "canonicalId": "device.command_intent" },
{ "alias": "аудит Device Core", "canonicalId": "device.audit_event" }
]
}
@@ -0,0 +1,26 @@
{
"version": "0.1.0",
"updatedAt": "2026-08-22",
"entities": [
{ "id": "device.project", "name": "Device Project", "surface": "device-core", "status": ["source-confirmed", "product-required"], "authority": "Device Core", "summary": "Owner-scoped operational boundary that grants access to device, asset and infrastructure composition without becoming the identity of those subjects." },
{ "id": "device.collection", "name": "Device Collection", "surface": "device-core", "status": ["source-confirmed", "product-required"], "authority": "Device Core", "summary": "Logical project-local grouping of devices or assets; grouping is not ownership, topology or attachment." },
{ "id": "device.device", "name": "Device", "surface": "device-core", "status": ["source-confirmed", "product-required"], "authority": "Device Core", "summary": "Stable physical or logical device identity managed by Device Core independently from an attached asset, identifier, adapter, provider or route." },
{ "id": "device.tracking_device", "name": "Tracking Device", "surface": "device-core", "status": ["product-required", "source-evidenced"], "authority": "Device Core", "summary": "Device role that produces time-qualified tracking observations for an asset. A B2 is onboarded as a tracking device while remaining independent from the trike it tracks." },
{ "id": "device.asset_binding", "name": "Device Asset Binding", "surface": "device-core", "status": ["product-required", "source-evidenced"], "authority": "Device Core", "summary": "Explicit time-qualified attachment between one device and one asset with validity interval, provenance and lifecycle state." },
{ "id": "device.restricted_identifier", "name": "Restricted Device Identifier", "surface": "device-core", "status": ["source-confirmed", "product-required"], "authority": "Device Core", "summary": "Namespaced hardware or integration identifier such as IMEI, serial or provider device id protected by field policy and never used as Asset identity." },
{ "id": "device.credential_reference", "name": "Device Credential Reference", "surface": "device-core", "status": ["source-confirmed"], "authority": "Device Core secret boundary", "summary": "Opaque reference to a credential owned by a secret authority; the credential value never enters Ontology Core, Data Products or browser state." },
{ "id": "device.adapter_package", "name": "Device Adapter Package", "surface": "device-core", "status": ["source-confirmed", "product-required"], "authority": "Device Core", "summary": "Stable adapter family describing how a class of devices is decoded and controlled without making a vendor model canonical ontology." },
{ "id": "device.adapter_version", "name": "Device Adapter Version", "surface": "device-core", "status": ["source-confirmed", "product-required"], "authority": "Device Core", "summary": "Immutable executable adapter release selected by a model profile or route." },
{ "id": "device.model_profile", "name": "Device Model Profile", "surface": "device-core", "status": ["source-confirmed", "product-required"], "authority": "Device Core", "summary": "Versioned device model and capability profile binding protocol expectations to an adapter version." },
{ "id": "device.enrollment_intent", "name": "Device Enrollment Intent", "surface": "device-core", "status": ["source-confirmed", "product-required"], "authority": "Device Core", "summary": "Bounded, auditable request to register or claim a discovered/direct device into an owner and project scope." },
{ "id": "device.discovery", "name": "Device Discovery", "surface": "device-core", "status": ["source-confirmed"], "authority": "Device Core", "summary": "Untrusted candidate evidence observed before enrollment and ownership acceptance; it is not yet a managed device." },
{ "id": "device.edge_registration", "name": "Device Edge Registration", "surface": "device-plane", "status": ["source-confirmed", "product-required"], "authority": "Device Control Core", "summary": "Core-approved Edge identity and endpoint registration participating in the core-initiated pinned-mTLS channel." },
{ "id": "device.route", "name": "Device Route", "surface": "device-plane", "status": ["source-confirmed", "product-required"], "authority": "Device Control Core", "summary": "Approved device traffic route resolving a device/model profile to a registered Edge and adapter contract." },
{ "id": "device.session", "name": "Device Session", "surface": "device-plane", "status": ["source-confirmed", "product-required"], "authority": "Device Control Core", "summary": "Bounded runtime communication session for one device over one approved route." },
{ "id": "device.configuration_revision", "name": "Device Configuration Revision", "surface": "device-core", "status": ["source-confirmed", "product-required"], "authority": "Device Core", "summary": "Immutable desired configuration revision for a device or model profile." },
{ "id": "device.configuration_state", "name": "Device Configuration State", "surface": "device-core", "status": ["source-confirmed", "product-required"], "authority": "Device Core", "summary": "Reconciled desired/observed configuration state with revision, evidence and time; it is not the configuration secret payload." },
{ "id": "device.command_intent", "name": "Device Command Intent", "surface": "device-command", "status": ["source-confirmed", "product-required"], "authority": "Device Control Core", "summary": "Explicit governed request for one typed command against one authorized device target, separate from transport and result." },
{ "id": "device.command_event", "name": "Device Command Event", "surface": "device-command", "status": ["source-confirmed", "product-required"], "authority": "Device Control Core", "summary": "Immutable lifecycle evidence for command acceptance, dispatch, acknowledgement, expiry, rejection or failure." },
{ "id": "device.audit_event", "name": "Device Audit Event", "surface": "device-core", "status": ["source-confirmed", "product-required"], "authority": "Device Core", "summary": "Immutable evidence of a governed Device Core action, actor, target, decision and result." }
]
}
@@ -0,0 +1,20 @@
{
"version": "0.1.0",
"updatedAt": "2026-08-22",
"sourceRoots": [
{ "surface": "device-core", "path": "/Users/dcconstructions/Downloads/mnt/NODEDC/NODEDC_DEVICE_CORE", "mode": "Read-only inspection of migrations 001, 002, 004, 006, 008, 010, 013 and 015 plus Device Plane contracts" },
{ "surface": "device-edge-adr", "path": "/Users/dcconstructions/Downloads/mnt/NODEDC/NODEDC_DEVICE_CORE/docs/ADR_0001_CORE_INITIATED_EDGE_CHANNEL.md", "mode": "Core-initiated pinned-mTLS Edge identity, trust and command-boundary evidence" },
{ "surface": "ops-decision", "path": "DCPLATFORM-70", "mode": "Accepted direct B2 onboarding and temporal trike composition" },
{ "surface": "ops-decision", "path": "DCPLATFORM-76", "mode": "Device Core release and architecture milestone" }
],
"ledgers": [
{ "id": "ledger.device_domain_v0", "path": "docs/DEVICE_DOMAIN_ONTOLOGY.md", "entityIds": ["device.project", "device.collection", "device.device", "device.tracking_device", "device.asset_binding", "device.restricted_identifier", "device.adapter_package", "device.adapter_version", "device.model_profile", "device.enrollment_intent", "device.discovery", "device.edge_registration", "device.route", "device.session", "device.configuration_revision", "device.configuration_state", "device.command_intent", "device.command_event", "device.audit_event"] }
],
"baselineDocs": ["docs/DEVICE_DOMAIN_ONTOLOGY.md"],
"restrictions": [
"Do not copy device credentials, private keys, raw command payloads, runtime sessions or observations into Ontology Core.",
"Do not make B2, Gelios or another vendor/provider the canonical root of Device Core ontology.",
"Do not accept direct traffic before enrollment, model-profile, route and Edge-registration checks.",
"Do not expose arbitrary remote shell or untyped command transport as a Device Core command."
]
}
@@ -0,0 +1,58 @@
{
"version": "0.1.0",
"updatedAt": "2026-08-22",
"rules": [
{
"id": "guardrail.device.direct_onboarding_is_provider_neutral",
"severity": "error",
"summary": "New direct B2 onboarding uses Device Core device, model profile, adapter, enrollment and asset-binding contracts. Gelios or another provider may supply legacy evidence but may not become the product identity model.",
"entityIds": ["device.device", "device.tracking_device", "device.model_profile", "device.enrollment_intent", "device.asset_binding", "gelios.tracker_device"]
},
{
"id": "guardrail.device.identifiers_are_restricted_not_identity",
"severity": "error",
"summary": "IMEI, serial, integration device id and credential references are restricted device attributes. They must not become Asset identity, public Data Product keys or browser-readable secrets.",
"entityIds": ["device.device", "device.restricted_identifier", "device.credential_reference", "asset.asset"]
},
{
"id": "guardrail.device.asset_attachment_is_temporal",
"severity": "error",
"summary": "A device-to-asset attachment requires a binding record with valid_from, valid_to, lifecycle state and provenance. Replacing B2 must not replace the trike Asset.",
"entityIds": ["device.tracking_device", "device.asset_binding", "asset.asset"]
},
{
"id": "guardrail.device.discovery_cannot_claim_ownership",
"severity": "error",
"summary": "Discovery is untrusted evidence. Only an authorized enrollment transition may create or claim a managed device and assign owner/project scope.",
"entityIds": ["device.discovery", "device.enrollment_intent", "device.device", "device.project"]
},
{
"id": "guardrail.device.commands_are_typed_red_domain",
"severity": "error",
"summary": "Device commands are typed, explicitly authorized intents with bounded TTL and audit. Arbitrary shell, firmware, reboot, memory wipe or provider command text is not exposed through the safe service-ping contract.",
"entityIds": ["device.command_intent", "device.command_event", "device.route", "device.audit_event"]
},
{
"id": "guardrail.device.edge_identity_is_not_host_identity",
"severity": "error",
"summary": "An Edge registration is an application identity realized by a service instance. It must not be conflated with a VPS host, network endpoint or deployment artifact.",
"entityIds": ["device.edge_registration", "infrastructure.host", "infrastructure.endpoint", "infrastructure.deployment", "infrastructure.service_instance"]
},
{
"id": "guardrail.device.ontology_does_not_store_runtime",
"severity": "error",
"summary": "Ontology Core describes Device meanings and relations only; Device Core owns device rows, sessions, routes, configuration, command events, observations, audit and secret references.",
"entityIds": ["device.device", "device.session", "device.route", "device.configuration_state", "device.command_event", "device.audit_event"]
}
],
"blockedConflations": [
["device.device", "device.restricted_identifier"],
["device.device", "device.model_profile"],
["device.tracking_device", "asset.asset"],
["device.discovery", "device.device"],
["device.edge_registration", "infrastructure.host"],
["device.route", "device.session"],
["device.configuration_revision", "device.configuration_state"],
["device.command_intent", "device.command_event"]
]
}
@@ -0,0 +1,7 @@
{
"id": "device",
"version": "0.1.0",
"updatedAt": "2026-08-22",
"status": "product-required/source-evidenced",
"summary": "Device Core domain ontology for direct device onboarding, asset composition, adapters, enrollment, Edge routing, sessions, configuration, governed commands and audit."
}
@@ -0,0 +1,31 @@
{
"version": "0.1.0",
"updatedAt": "2026-08-22",
"relations": [
{ "id": "device.project.contains_collection", "from": ["device.project"], "to": ["device.collection"], "status": "source-confirmed", "summary": "A project contains logical collections without changing device or asset identity." },
{ "id": "device.project.scopes_subject", "from": ["device.project"], "to": ["asset.asset", "device.device", "device.edge_registration"], "status": "product-required", "summary": "A project grants an operational scope over stable subjects; scope is not ownership or attachment." },
{ "id": "device.collection.groups_subject", "from": ["device.collection"], "to": ["asset.asset", "device.device"], "status": "product-required", "summary": "A collection groups assets or devices independently from physical composition." },
{ "id": "device.tracking_device.is_device", "from": ["device.tracking_device"], "to": ["device.device"], "status": "product-required", "summary": "Tracking is a declared device role/capability, not the identity of the tracked Asset." },
{ "id": "device.asset_binding.attaches_device", "from": ["device.asset_binding"], "to": ["device.device", "device.tracking_device"], "status": "product-required", "summary": "A binding identifies the device participating in a time-qualified asset attachment." },
{ "id": "device.asset_binding.attaches_asset", "from": ["device.asset_binding"], "to": ["asset.asset"], "status": "product-required", "summary": "A binding identifies the asset participating in a time-qualified attachment." },
{ "id": "device.tracking_device.tracks_asset", "from": ["device.tracking_device"], "to": ["asset.asset"], "status": "product-required", "summary": "A tracking device tracks an asset only through an active Device Asset Binding carrying valid_from, valid_to and provenance." },
{ "id": "device.device.has_restricted_identifier", "from": ["device.device", "device.tracking_device"], "to": ["device.restricted_identifier"], "status": "source-confirmed", "summary": "Hardware and provider identifiers are classified restricted references on a device." },
{ "id": "device.device.uses_credential_reference", "from": ["device.device"], "to": ["device.credential_reference"], "status": "source-confirmed", "summary": "A device may use an opaque credential reference resolved only inside the owning secret boundary." },
{ "id": "device.adapter_package.has_version", "from": ["device.adapter_package"], "to": ["device.adapter_version"], "status": "source-confirmed", "summary": "An adapter package publishes immutable executable versions." },
{ "id": "device.model_profile.uses_adapter_version", "from": ["device.model_profile"], "to": ["device.adapter_version"], "status": "source-confirmed", "summary": "A model profile pins one approved adapter version and its capability contract." },
{ "id": "device.discovery.proposes_enrollment", "from": ["device.discovery"], "to": ["device.enrollment_intent"], "status": "source-confirmed", "summary": "Untrusted discovery evidence may seed an enrollment intent but cannot create ownership by itself." },
{ "id": "device.enrollment_intent.registers_device", "from": ["device.enrollment_intent"], "to": ["device.device", "device.tracking_device"], "status": "product-required", "summary": "An accepted enrollment intent creates or claims a stable managed device identity." },
{ "id": "device.enrollment_intent.uses_model_profile", "from": ["device.enrollment_intent"], "to": ["device.model_profile"], "status": "product-required", "summary": "Direct onboarding selects an approved model and adapter contract before traffic is accepted." },
{ "id": "device.edge_registration.runs_as_service_instance", "from": ["device.edge_registration"], "to": ["infrastructure.service_instance"], "status": "product-required", "summary": "A registered Edge is realized by an explicit service instance on infrastructure; Edge identity is not the host identity." },
{ "id": "device.edge_registration.exposes_route", "from": ["device.edge_registration"], "to": ["device.route"], "status": "product-required", "summary": "Only Core-approved Edge registrations can terminate device routes." },
{ "id": "device.route.uses_model_profile", "from": ["device.route"], "to": ["device.model_profile"], "status": "product-required", "summary": "A route resolves traffic through the device model and pinned adapter contract." },
{ "id": "device.session.uses_route", "from": ["device.session"], "to": ["device.route"], "status": "source-confirmed", "summary": "A runtime session is accepted only on one approved route." },
{ "id": "device.session.belongs_to_device", "from": ["device.session"], "to": ["device.device"], "status": "source-confirmed", "summary": "A session belongs to one stable device identity after route and enrollment checks." },
{ "id": "device.configuration_revision.applies_to_device", "from": ["device.configuration_revision"], "to": ["device.device"], "status": "product-required", "summary": "A desired configuration revision targets one managed device." },
{ "id": "device.configuration_state.reconciles_revision", "from": ["device.configuration_state"], "to": ["device.configuration_revision"], "status": "product-required", "summary": "Configuration state reconciles desired revision with observed evidence without mutating revision history." },
{ "id": "device.command_intent.targets_device", "from": ["device.command_intent"], "to": ["device.device"], "status": "product-required", "summary": "Every command intent resolves to one authorized stable device target." },
{ "id": "device.command_intent.uses_route", "from": ["device.command_intent"], "to": ["device.route"], "status": "product-required", "summary": "Typed command transport uses an approved route and never an arbitrary host shell." },
{ "id": "device.command_intent.has_event", "from": ["device.command_intent"], "to": ["device.command_event"], "status": "product-required", "summary": "Command lifecycle is evidenced by immutable events rather than assumed from dispatch." },
{ "id": "device.audit_event.records_subject", "from": ["device.audit_event"], "to": ["device.device", "device.asset_binding", "device.enrollment_intent", "device.configuration_revision", "device.command_intent", "device.edge_registration"], "status": "product-required", "summary": "Governed Device Core mutations and decisions emit audit evidence for their stable target." }
]
}
@@ -1,6 +1,6 @@
{
"version": "1.1.0",
"updatedAt": "2026-07-20",
"version": "1.2.0",
"updatedAt": "2026-08-22",
"sourceRoots": [
{
"surface": "gelios-rest",
@@ -57,6 +57,8 @@
"Do not promote operational_status, freshness, GPS quality, missing position or unknown fallback buckets to Gelios monitoring states. The official filter value contracts are signal_state active/inactive and movement_state moving/stopped only.",
"Do not invoke command send, create, update, delete or purge routes as ontology evidence.",
"Robot2B pilot counts (107 credential-visible units and 95 legacy snapshot units) are historical evidence only; canonical collection scope is dynamically all entities visible to the bound credential.",
"Do not bulk-download history, media or full geozone geometry before collection policy and storage architecture are approved."
"Do not bulk-download history, media or full geozone geometry before collection policy and storage architecture are approved.",
"Do not treat gelios.unit as Asset or gelios.tracker_device as Device Core Tracking Device without an explicit source binding.",
"New direct B2 onboarding must not require a Gelios connection; legacy/provider and direct observations retain distinct provenance."
]
}
@@ -1,6 +1,6 @@
{
"version": "1.1.0",
"updatedAt": "2026-07-20",
"version": "1.2.0",
"updatedAt": "2026-08-22",
"rules": [
{
"id": "guardrail.gelios.ontology_not_runtime_store",
@@ -32,6 +32,12 @@
"summary": "Cesium pins and labels must consume stable gelios.unit and normalized gelios.position_fix through map.moving_object. They must not use raw message IDs, transient Cesium entity IDs or provider credentials as map identity.",
"entityIds": ["gelios.unit", "gelios.position_fix", "gelios.telemetry_snapshot", "map.moving_object", "map.pin", "map.label"]
},
{
"id": "guardrail.gelios.neutral_composition_requires_explicit_binding",
"severity": "error",
"summary": "Gelios unit, tracker and position records may map to Asset, Tracking Device and Position Observation only through explicit versioned source bindings. Provider identities must not silently overwrite NODE.DC identities or direct-device evidence.",
"entityIds": ["gelios.unit", "gelios.tracker_device", "gelios.position_fix", "asset.asset", "device.tracking_device", "observation.position_observation"]
},
{
"id": "guardrail.gelios.monitoring_states_are_closed",
"severity": "error",
@@ -60,6 +66,9 @@
"blockedConflations": [
["gelios.integration", "gelios.access_scope"],
["gelios.unit", "gelios.tracker_device"],
["gelios.unit", "asset.asset"],
["gelios.tracker_device", "device.tracking_device"],
["gelios.position_fix", "observation.position_observation"],
["gelios.telemetry_snapshot", "gelios.raw_telemetry_message"],
["gelios.position_fix", "map.moving_object"],
["gelios.signal_state", "gelios.movement_state"],
@@ -1,7 +1,7 @@
{
"id": "gelios",
"version": "1.1.0",
"updatedAt": "2026-07-20",
"version": "1.2.0",
"updatedAt": "2026-08-22",
"status": "product-required/source-evidenced",
"summary": "Source-evidenced Gelios Pro telemetry, fleet, spatial, reporting and command-domain ontology. Unit monitoring exposes only the official signal and movement value contracts; consumers may not invent additional operational states."
"summary": "Source-evidenced Gelios provider ontology with explicit mappings into provider-neutral Asset, Tracking Device, Observation and Map contracts. Official signal and movement value contracts remain closed."
}
@@ -1,12 +1,16 @@
{
"version": "1.1.0",
"updatedAt": "2026-07-20",
"version": "1.2.0",
"updatedAt": "2026-08-22",
"relations": [
{ "id": "gelios.integration.is_provider_connection", "from": ["gelios.integration"], "to": ["integration.connection"], "status": "product-required", "summary": "A Gelios integration is a tenant-scoped instance of the common external provider connection contract." },
{ "id": "gelios.access_scope.specializes_integration_scope", "from": ["gelios.access_scope"], "to": ["integration.access_scope"], "status": "product-required", "summary": "Gelios credential-visible capability scope specializes the common provider access-scope contract." },
{ "id": "gelios.collection_run.is_integration_collection_run", "from": ["gelios.collection_run"], "to": ["integration.collection_run"], "status": "product-required", "summary": "Gelios collection runs inherit the bounded collection and audit lifecycle of external integrations." },
{ "id": "gelios.raw_message.is_integration_raw_envelope", "from": ["gelios.raw_telemetry_message"], "to": ["integration.raw_envelope"], "status": "product-required", "summary": "A Gelios raw message is a restricted provider envelope, not a UI read model." },
{ "id": "gelios.unit.is_integration_canonical_subject", "from": ["gelios.unit"], "to": ["integration.canonical_subject"], "status": "product-required", "summary": "A Gelios unit is a stable canonical subject produced by the provider adapter." },
{ "id": "gelios.unit.is_integration_canonical_subject", "from": ["gelios.unit"], "to": ["integration.canonical_subject"], "status": "product-required", "summary": "A Gelios unit is a stable provider subject produced by the provider adapter." },
{ "id": "gelios.unit.maps_to_asset", "from": ["gelios.unit"], "to": ["asset.asset"], "status": "product-required", "summary": "A Gelios unit may resolve to a NODE.DC Asset only through an explicit source binding. The provider unit id never becomes the Asset identity." },
{ "id": "gelios.tracker_device.maps_to_tracking_device", "from": ["gelios.tracker_device"], "to": ["device.tracking_device"], "status": "product-required", "summary": "A Gelios tracker record may resolve to a Device Core Tracking Device through an explicit restricted-identifier and source binding." },
{ "id": "gelios.telemetry_snapshot.maps_to_observation", "from": ["gelios.telemetry_snapshot"], "to": ["observation.observation"], "status": "product-required", "summary": "A versioned field mapping may publish provider telemetry as provider-neutral observations while retaining Gelios provenance and exact value contracts." },
{ "id": "gelios.position_fix.maps_to_position_observation", "from": ["gelios.position_fix"], "to": ["observation.position_observation"], "status": "product-required", "summary": "A Gelios position fix may produce a provider-neutral position observation for the explicitly bound Asset and Tracking Device." },
{ "id": "gelios.command_template.is_integration_command_capability", "from": ["gelios.command_template"], "to": ["integration.command_capability"], "status": "product-required", "summary": "Gelios command templates are catalogued provider command capabilities only." },
{ "id": "gelios.command_dispatch.is_integration_command_intent", "from": ["gelios.command_dispatch"], "to": ["integration.command_intent"], "status": "future-concept", "summary": "Any future Gelios command dispatch must become an explicitly governed generic command intent." },
{ "id": "gelios.command_audit.is_integration_command_audit", "from": ["gelios.command_audit"], "to": ["integration.command_audit"], "status": "future-concept", "summary": "Gelios command audit specializes the generic red-domain audit contract." },
@@ -39,8 +43,8 @@
{ "id": "gelios.command_dispatch.targets_scope", "from": ["gelios.command_dispatch"], "to": ["gelios.unit", "gelios.unit_group", "gelios.access_scope"], "status": "future-concept", "summary": "A future dispatch target must resolve to an approved unit or explicitly approved group in scope." },
{ "id": "gelios.command_dispatch.has_delivery", "from": ["gelios.command_dispatch"], "to": ["gelios.command_delivery"], "status": "future-concept", "summary": "A future dispatch is associated with delivery/task state rather than assumed successful on request creation." },
{ "id": "gelios.command_dispatch.has_audit", "from": ["gelios.command_dispatch"], "to": ["gelios.command_audit"], "status": "future-concept", "summary": "Every future dispatch requires immutable user-confirmation and outcome audit." },
{ "id": "gelios.unit.is_map_moving_object", "from": ["gelios.unit"], "to": ["map.moving_object"], "status": "product-required", "summary": "A valid credential-visible Gelios unit is exposed through the provider-neutral moving-object contract, never as a renderer entity identity." },
{ "id": "gelios.position_fix.positions_map_subject", "from": ["gelios.position_fix"], "to": ["map.moving_object"], "status": "product-required", "summary": "A normalized position fix updates the stable map subject bound to the Gelios unit." },
{ "id": "gelios.unit.is_map_moving_object", "from": ["gelios.unit"], "to": ["map.moving_object"], "status": "product-required", "summary": "Legacy/provider Data Products may expose a credential-visible Gelios unit through the moving-object contract. New composed products bind the unit to Asset and use the Asset as stable map subject." },
{ "id": "gelios.position_fix.positions_map_subject", "from": ["gelios.position_fix"], "to": ["map.moving_object"], "status": "product-required", "summary": "Legacy/provider Data Products may position their Gelios moving-object subject; new composed products map the fix to a position observation targeting the bound Asset." },
{ "id": "gelios.geozone.is_map_zone", "from": ["gelios.geozone"], "to": ["map.zone"], "status": "product-required", "summary": "An approved Gelios geozone is exposed to the map through the generic zone contract." },
{ "id": "gelios.geopoint.is_map_place_target", "from": ["gelios.geopoint"], "to": ["map.place_target"], "status": "product-required", "summary": "An approved Gelios geopoint is exposed through a provider-neutral place target." }
]
@@ -0,0 +1,15 @@
{
"version": "0.1.0",
"updatedAt": "2026-08-22",
"aliases": [
{ "alias": "VPS host", "canonicalId": "infrastructure.host" },
{ "alias": "внешний VPS", "canonicalId": "infrastructure.host" },
{ "alias": "инфраструктурный хост", "canonicalId": "infrastructure.host" },
{ "alias": "сетевой endpoint хоста", "canonicalId": "infrastructure.endpoint" },
{ "alias": "развёртывание сервиса", "canonicalId": "infrastructure.deployment" },
{ "alias": "экземпляр сервиса на VPS", "canonicalId": "infrastructure.service_instance" },
{ "alias": "ревизия конфигурации инфраструктуры", "canonicalId": "infrastructure.configuration_revision" },
{ "alias": "ссылка на SSH credential", "canonicalId": "infrastructure.management_credential_reference" },
{ "alias": "браузерная консоль VPS", "canonicalId": "infrastructure.management_session" }
]
}
@@ -0,0 +1,13 @@
{
"version": "0.1.0",
"updatedAt": "2026-08-22",
"entities": [
{ "id": "infrastructure.host", "name": "Infrastructure Host", "surface": "infrastructure", "status": ["product-required", "source-evidenced"], "authority": "Device Core infrastructure inventory", "summary": "Stable compute host such as a VPS, bare-metal server or local node, independent from provider account, endpoint, deployment and running services." },
{ "id": "infrastructure.endpoint", "name": "Infrastructure Endpoint", "surface": "infrastructure", "status": ["product-required", "source-evidenced"], "authority": "Device Core infrastructure inventory", "summary": "Network-reachable address and protocol surface exposed by a host or service under an explicit visibility and trust policy." },
{ "id": "infrastructure.deployment", "name": "Infrastructure Deployment", "surface": "infrastructure", "status": ["product-required", "source-evidenced"], "authority": "Owning deploy system", "summary": "Auditable delivery of a versioned service/configuration artifact to a target host; it is not the running process or host identity." },
{ "id": "infrastructure.service_instance", "name": "Infrastructure Service Instance", "surface": "infrastructure", "status": ["product-required", "source-evidenced"], "authority": "Device Core infrastructure inventory", "summary": "Concrete running instance of a service on a host, linked to deployment evidence and current observations." },
{ "id": "infrastructure.configuration_revision", "name": "Infrastructure Configuration Revision", "surface": "infrastructure", "status": ["product-required"], "authority": "Owning deploy/configuration system", "summary": "Immutable desired infrastructure configuration revision referenced by deployments without embedding secrets." },
{ "id": "infrastructure.management_credential_reference", "name": "Infrastructure Management Credential Reference", "surface": "infrastructure-access", "status": ["product-required"], "authority": "Owning secret authority", "summary": "Opaque reference to a host-management credential; no secret value is stored in Ontology Core, Device Manager browser state or Data Products." },
{ "id": "infrastructure.management_session", "name": "Infrastructure Management Session", "surface": "infrastructure-access", "status": ["product-required"], "authority": "Owning privileged-access service", "summary": "Time-bounded, authorized and audited management channel to a host. Interactive console use is a privileged break-glass operation, not a standard device command." }
]
}
@@ -0,0 +1,19 @@
{
"version": "0.1.0",
"updatedAt": "2026-08-22",
"sourceRoots": [
{ "surface": "device-core", "path": "/Users/dcconstructions/Downloads/mnt/NODEDC/NODEDC_DEVICE_CORE", "mode": "Read-only Edge registration, endpoint, trust, route and manager health source inspection" },
{ "surface": "device-edge-adr", "path": "/Users/dcconstructions/Downloads/mnt/NODEDC/NODEDC_DEVICE_CORE/docs/ADR_0001_CORE_INITIATED_EDGE_CHANNEL.md", "mode": "Replaceable untrusted VPS and Core-initiated Edge channel boundary" },
{ "surface": "ops-decision", "path": "DCPLATFORM-77", "mode": "Accepted ontology-first VPS inventory, monitoring and management boundary" }
],
"ledgers": [
{ "id": "ledger.infrastructure_domain_v0", "path": "docs/INFRASTRUCTURE_DOMAIN_ONTOLOGY.md", "entityIds": ["infrastructure.host", "infrastructure.endpoint", "infrastructure.deployment", "infrastructure.service_instance", "infrastructure.configuration_revision", "infrastructure.management_credential_reference", "infrastructure.management_session"] }
],
"baselineDocs": ["docs/INFRASTRUCTURE_DOMAIN_ONTOLOGY.md"],
"restrictions": [
"Do not treat integration.connection as a VPS or host inventory record.",
"Do not copy passwords, private keys, host tokens or console transcripts into Ontology Core.",
"Do not expose arbitrary host shell through the safe Device Core command channel.",
"Do not project hosts on a map without actual spatial evidence."
]
}
@@ -0,0 +1,51 @@
{
"version": "0.1.0",
"updatedAt": "2026-08-22",
"rules": [
{
"id": "guardrail.infrastructure.host_is_not_connection",
"severity": "error",
"summary": "A VPS or server is an Infrastructure Host. A provider account connection, network endpoint, deployment or Edge registration may reference it but must not replace its identity.",
"entityIds": ["infrastructure.host", "integration.connection", "infrastructure.endpoint", "infrastructure.deployment", "device.edge_registration"]
},
{
"id": "guardrail.infrastructure.runtime_layers_remain_distinct",
"severity": "error",
"summary": "Host, endpoint, deployment, service instance and Edge registration are separate graph subjects with explicit relations and independent lifecycle evidence.",
"entityIds": ["infrastructure.host", "infrastructure.endpoint", "infrastructure.deployment", "infrastructure.service_instance", "device.edge_registration"]
},
{
"id": "guardrail.infrastructure.management_is_break_glass",
"severity": "error",
"summary": "Interactive host management requires an app-owned privileged session with explicit actor, target, reason, expiry and audit. Device safe commands may never proxy arbitrary shell access.",
"entityIds": ["infrastructure.host", "infrastructure.management_credential_reference", "infrastructure.management_session", "device.command_intent", "device.audit_event"]
},
{
"id": "guardrail.infrastructure.secrets_never_reach_ontology_or_browser",
"severity": "error",
"summary": "Ontology, Data Products and browser state may carry only opaque secret references and safe metadata; credentials, private keys and host tokens remain in their owning secret authority.",
"entityIds": ["infrastructure.management_credential_reference", "device.credential_reference", "agent.token"]
},
{
"id": "guardrail.infrastructure.map_requires_spatial_evidence",
"severity": "error",
"summary": "A host or service may appear on a map only when a Data Product supplies real time-qualified spatial evidence. Otherwise Foundry must use a logical graph or Inspector presentation.",
"entityIds": ["infrastructure.host", "infrastructure.service_instance", "observation.position_observation", "map.moving_object", "map.place_target"]
},
{
"id": "guardrail.infrastructure.ontology_not_inventory_store",
"severity": "error",
"summary": "Ontology Core defines infrastructure meanings; Device Core or another owning inventory stores hosts, deployments, service instances, observations, credentials references and management-session audit.",
"entityIds": ["infrastructure.host", "infrastructure.deployment", "infrastructure.service_instance", "infrastructure.management_session"]
}
],
"blockedConflations": [
["infrastructure.host", "integration.connection"],
["infrastructure.host", "infrastructure.endpoint"],
["infrastructure.host", "infrastructure.deployment"],
["infrastructure.deployment", "infrastructure.service_instance"],
["infrastructure.service_instance", "device.edge_registration"],
["infrastructure.management_credential_reference", "infrastructure.management_session"],
["infrastructure.host", "map.moving_object"]
]
}
@@ -0,0 +1,7 @@
{
"id": "infrastructure",
"version": "0.1.0",
"updatedAt": "2026-08-22",
"status": "product-required/source-evidenced",
"summary": "Provider-neutral hosts, endpoints, deployments, service instances, configuration revisions and governed management access for Device Core Edge infrastructure."
}
@@ -0,0 +1,16 @@
{
"version": "0.1.0",
"updatedAt": "2026-08-22",
"relations": [
{ "id": "infrastructure.host.exposes_endpoint", "from": ["infrastructure.host"], "to": ["infrastructure.endpoint"], "status": "product-required", "summary": "A host exposes only explicitly inventoried network endpoints with declared protocol and visibility." },
{ "id": "infrastructure.deployment.targets_host", "from": ["infrastructure.deployment"], "to": ["infrastructure.host"], "status": "product-required", "summary": "A deployment records its target host without becoming that host." },
{ "id": "infrastructure.deployment.uses_configuration_revision", "from": ["infrastructure.deployment"], "to": ["infrastructure.configuration_revision"], "status": "product-required", "summary": "A deployment pins an immutable desired configuration revision and secret references only." },
{ "id": "infrastructure.service_instance.runs_on_host", "from": ["infrastructure.service_instance"], "to": ["infrastructure.host"], "status": "product-required", "summary": "A concrete service instance runs on one inventoried host for a bounded lifecycle interval." },
{ "id": "infrastructure.service_instance.realizes_deployment", "from": ["infrastructure.service_instance"], "to": ["infrastructure.deployment"], "status": "product-required", "summary": "A service instance is reconciled with the deployment that produced its current release." },
{ "id": "infrastructure.service_instance.exposes_endpoint", "from": ["infrastructure.service_instance"], "to": ["infrastructure.endpoint"], "status": "product-required", "summary": "A service may expose an endpoint distinct from the host's management endpoint." },
{ "id": "infrastructure.host.uses_management_credential_reference", "from": ["infrastructure.host"], "to": ["infrastructure.management_credential_reference"], "status": "product-required", "summary": "Host management resolves an opaque credential reference inside the owning privileged service." },
{ "id": "infrastructure.management_session.targets_host", "from": ["infrastructure.management_session"], "to": ["infrastructure.host"], "status": "product-required", "summary": "A management session targets one explicit host and records actor, reason, expiry and audit correlation." },
{ "id": "infrastructure.management_session.uses_credential_reference", "from": ["infrastructure.management_session"], "to": ["infrastructure.management_credential_reference"], "status": "product-required", "summary": "A privileged session resolves a credential reference without returning the secret to the browser." },
{ "id": "infrastructure.host.belongs_to_device_project", "from": ["infrastructure.host"], "to": ["device.project"], "status": "product-required", "summary": "A Device Core project may scope a host while host identity remains independent from the project." }
]
}
@@ -0,0 +1,12 @@
{
"version": "0.1.0",
"updatedAt": "2026-08-22",
"aliases": [
{ "alias": "наблюдение устройства", "canonicalId": "observation.observation" },
{ "alias": "наблюдаемое свойство", "canonicalId": "observation.observed_property" },
{ "alias": "источник наблюдения", "canonicalId": "observation.source" },
{ "alias": "политика свежести наблюдения", "canonicalId": "observation.freshness_policy" },
{ "alias": "проверка здоровья VPS", "canonicalId": "observation.health_observation" },
{ "alias": "позиция актива", "canonicalId": "observation.position_observation" }
]
}
@@ -0,0 +1,12 @@
{
"version": "0.1.0",
"updatedAt": "2026-08-22",
"entities": [
{ "id": "observation.observation", "name": "Observation", "surface": "observation", "status": ["product-required"], "authority": "Owning telemetry or monitoring service", "summary": "Provider-neutral time-qualified statement about one declared property of one stable subject, carrying observed/received time, provenance and quality metadata." },
{ "id": "observation.observed_property", "name": "Observed Property", "surface": "observation", "status": ["product-required"], "authority": "Owning domain + Ontology Core", "summary": "Versioned semantic property contract declaring value type, unit, allowed values and interpretation independently from a provider field name." },
{ "id": "observation.source", "name": "Observation Source", "surface": "observation", "status": ["product-required"], "authority": "Owning telemetry or monitoring service", "summary": "Declared producer or adapter provenance for an observation, including provider-neutral source identity and mapping version." },
{ "id": "observation.freshness_policy", "name": "Observation Freshness Policy", "surface": "observation", "status": ["product-required"], "authority": "Consuming Data Product", "summary": "Explicit TTL, grace and missing-data interpretation selected by a consuming contract; freshness is not part of the observed value itself." },
{ "id": "observation.health_observation", "name": "Health Observation", "surface": "observation", "status": ["product-required", "source-evidenced"], "authority": "Owning monitoring service", "summary": "Time-qualified health or reachability observation for a host, service, Edge or device, retaining check kind and evidence rather than mutating the subject identity." },
{ "id": "observation.position_observation", "name": "Position Observation", "surface": "observation", "status": ["product-required", "source-evidenced"], "authority": "Owning telemetry service", "summary": "Time-qualified spatial observation with coordinate reference, location, quality and provenance that may project an Asset into a map Data Product." }
]
}
@@ -0,0 +1,20 @@
{
"version": "0.1.0",
"updatedAt": "2026-08-22",
"sourceRoots": [
{ "surface": "device-core", "path": "/Users/dcconstructions/Downloads/mnt/NODEDC/NODEDC_DEVICE_CORE", "mode": "Read-only session, route, current health and direct-device evidence inspection" },
{ "surface": "gelios", "path": "catalog/domain-packages/gelios", "mode": "Existing provider telemetry, position and closed monitoring-state contracts" },
{ "surface": "foundry", "path": "foundry://application/1c7dcdbb-6e50-4272-b1bc-aa5ece77ae99", "mode": "Robot2B Data Product semantic facets and moving-object projection inspection" },
{ "surface": "ops-decision", "path": "DCPLATFORM-77", "mode": "Accepted VPS health and provider-neutral observation boundary" }
],
"ledgers": [
{ "id": "ledger.observation_domain_v0", "path": "docs/OBSERVATION_DOMAIN_ONTOLOGY.md", "entityIds": ["observation.observation", "observation.observed_property", "observation.source", "observation.freshness_policy", "observation.health_observation", "observation.position_observation"] }
],
"baselineDocs": ["docs/OBSERVATION_DOMAIN_ONTOLOGY.md"],
"restrictions": [
"Do not copy live telemetry, monitoring histories, positions or raw provider payloads into Ontology Core.",
"Do not add consumer fallback statuses that are absent from the declared observed-property contract.",
"Do not treat missing evidence as unhealthy without an explicit freshness and missing-value rule.",
"Do not project a subject to a map without source-backed spatial evidence."
]
}
@@ -0,0 +1,50 @@
{
"version": "0.1.0",
"updatedAt": "2026-08-22",
"rules": [
{
"id": "guardrail.observation.value_time_and_freshness_are_separate",
"severity": "error",
"summary": "Observed value, observed_at, received_at, provenance and freshness evaluation are separate contract fields. Consumers must not invent fallback status from a missing timestamp.",
"entityIds": ["observation.observation", "observation.observed_property", "observation.source", "observation.freshness_policy"]
},
{
"id": "guardrail.observation.missing_is_not_automatically_unhealthy",
"severity": "error",
"summary": "Missing or expired evidence is unavailable/stale according to an explicit policy; it must not be silently converted to an unhealthy value unless the property contract says so.",
"entityIds": ["observation.health_observation", "observation.freshness_policy", "observation.observed_property"]
},
{
"id": "guardrail.observation.provider_values_require_mapping",
"severity": "error",
"summary": "Provider fields and status values enter Data Products only through a versioned mapping to an observed-property value contract; Foundry and renderers may not classify raw values.",
"entityIds": ["observation.observation", "observation.observed_property", "observation.source", "gelios.signal_state", "gelios.movement_state", "map.state_facet"]
},
{
"id": "guardrail.observation.not_lifecycle_or_command",
"severity": "error",
"summary": "An observation reports evidence. It does not replace immutable lifecycle events, desired configuration, command intent or command outcome.",
"entityIds": ["observation.observation", "asset.lifecycle_event", "device.configuration_state", "device.command_intent", "device.command_event"]
},
{
"id": "guardrail.observation.position_requires_provenance",
"severity": "error",
"summary": "Map projection requires coordinate reference, observed time, source, subject binding and quality/provenance. A host or asset display label alone is not spatial evidence.",
"entityIds": ["observation.position_observation", "observation.source", "asset.asset", "infrastructure.host", "map.moving_object"]
},
{
"id": "guardrail.observation.ontology_not_telemetry_store",
"severity": "error",
"summary": "Ontology Core defines observation meanings and value contracts; it must not store live telemetry, health checks, positions, histories or monitoring snapshots.",
"entityIds": ["observation.observation", "observation.health_observation", "observation.position_observation"]
}
],
"blockedConflations": [
["observation.observation", "observation.observed_property"],
["observation.observation", "observation.source"],
["observation.health_observation", "infrastructure.host"],
["observation.health_observation", "infrastructure.service_instance"],
["observation.position_observation", "asset.asset"],
["observation.position_observation", "map.moving_object"]
]
}
@@ -0,0 +1,7 @@
{
"id": "observation",
"version": "0.1.0",
"updatedAt": "2026-08-22",
"status": "product-required/source-evidenced",
"summary": "Provider-neutral time-qualified observations, properties, sources, freshness policy, health and position evidence for assets, devices and infrastructure."
}
@@ -0,0 +1,16 @@
{
"version": "0.1.0",
"updatedAt": "2026-08-22",
"relations": [
{ "id": "observation.observation.observes_subject", "from": ["observation.observation"], "to": ["asset.asset", "device.device", "device.tracking_device", "infrastructure.host", "infrastructure.service_instance", "device.edge_registration"], "status": "product-required", "summary": "An observation targets one stable subject without becoming that subject or its lifecycle state." },
{ "id": "observation.observation.observes_property", "from": ["observation.observation"], "to": ["observation.observed_property"], "status": "product-required", "summary": "Each observation declares the semantic property and value contract it evaluates." },
{ "id": "observation.observation.produced_by_source", "from": ["observation.observation"], "to": ["observation.source"], "status": "product-required", "summary": "Every observation records source and mapping provenance." },
{ "id": "observation.observation.evaluated_by_freshness", "from": ["observation.observation"], "to": ["observation.freshness_policy"], "status": "product-required", "summary": "Consumers evaluate observed and received time against an explicit freshness contract outside the raw value." },
{ "id": "observation.health_observation.is_observation", "from": ["observation.health_observation"], "to": ["observation.observation"], "status": "product-required", "summary": "Health evidence uses the common time, subject, property, source and freshness contract." },
{ "id": "observation.health_observation.targets_infrastructure", "from": ["observation.health_observation"], "to": ["infrastructure.host", "infrastructure.service_instance", "device.edge_registration", "device.device"], "status": "product-required", "summary": "A health check can target a host, running service, Edge registration or device without collapsing those layers." },
{ "id": "observation.position_observation.is_observation", "from": ["observation.position_observation"], "to": ["observation.observation"], "status": "product-required", "summary": "Position evidence uses the common observation provenance and time contract." },
{ "id": "observation.position_observation.positions_asset", "from": ["observation.position_observation"], "to": ["asset.asset"], "status": "product-required", "summary": "A position observation locates the stable Asset currently tracked by its attached device." },
{ "id": "observation.position_observation.projects_map_subject", "from": ["observation.position_observation"], "to": ["map.moving_object", "map.place_target"], "status": "product-required", "summary": "Foundry may project position evidence through a declared map semantic binding; the observation is not a renderer entity." },
{ "id": "observation.source.uses_device_session", "from": ["observation.source"], "to": ["device.session"], "status": "product-required", "summary": "Direct device observations may retain the accepted Device Plane session as provenance." }
]
}
@@ -0,0 +1,14 @@
{
"version": "0.1.0",
"updatedAt": "2026-08-22",
"aliases": [
{ "alias": "business party", "canonicalId": "party.party" },
{ "alias": "участник предметной области", "canonicalId": "party.party" },
{ "alias": "физическое лицо", "canonicalId": "party.person" },
{ "alias": "юридическое лицо", "canonicalId": "party.organization" },
{ "alias": "учётная запись домена", "canonicalId": "party.account" },
{ "alias": "субъект доступа домена", "canonicalId": "party.access_subject" },
{ "alias": "контактная точка", "canonicalId": "party.contact_point" },
{ "alias": "роль водителя", "canonicalId": "party.driver_role" }
]
}
@@ -0,0 +1,13 @@
{
"version": "0.1.0",
"updatedAt": "2026-08-22",
"entities": [
{ "id": "party.party", "name": "Party", "surface": "domain", "status": ["product-required"], "authority": "Owning product domain", "summary": "Stable provider-neutral actor identity that may be a person or organization and can participate in ownership, responsibility, access and operational assignments." },
{ "id": "party.person", "name": "Person", "surface": "domain", "status": ["product-required"], "authority": "Owning product domain", "summary": "Natural person represented independently from a HUB user, authentication identity, account or driver assignment." },
{ "id": "party.organization", "name": "Organization", "surface": "domain", "status": ["product-required"], "authority": "Owning product domain", "summary": "Legal or operational organization represented independently from a HUB client context, provider connection or project." },
{ "id": "party.account", "name": "Account", "surface": "domain", "status": ["product-required"], "authority": "Owning application", "summary": "Application- or provider-scoped account projection that represents a party but is not the party, credential or authentication session." },
{ "id": "party.access_subject", "name": "Access Subject", "surface": "access", "status": ["product-required"], "authority": "Owning access service", "summary": "Stable subject evaluated by an owning access service. It may bind to a person, organization or service actor without replacing the source authority identity." },
{ "id": "party.contact_point", "name": "Contact Point", "surface": "domain", "status": ["product-required"], "authority": "Owning product domain", "summary": "Classified communication endpoint such as email or phone, subject to field and exposure policy." },
{ "id": "party.driver_role", "name": "Driver Role", "surface": "domain", "status": ["product-required"], "authority": "Owning operations domain", "summary": "Time-qualified operational role through which a person may be assigned to operate an asset; it is not a permanent subtype of person." }
]
}
@@ -0,0 +1,17 @@
{
"version": "0.1.0",
"updatedAt": "2026-08-22",
"sourceRoots": [
{ "surface": "hub", "path": "/Users/dcconstructions/Downloads/mnt/NODEDC/platform/services/launcher", "mode": "Read-only inspection of user, membership, client-context and application-access authority boundaries" },
{ "surface": "ops-decision", "path": "DCPLATFORM-70", "mode": "Accepted provider-neutral person, driver, account, access and moving-object composition decision" }
],
"ledgers": [
{ "id": "ledger.party_domain_v0", "path": "docs/PARTY_ASSET_DOMAIN_ONTOLOGY.md", "entityIds": ["party.party", "party.person", "party.organization", "party.account", "party.access_subject", "party.contact_point", "party.driver_role"] }
],
"baselineDocs": ["docs/PARTY_ASSET_DOMAIN_ONTOLOGY.md"],
"restrictions": [
"Do not copy credentials, authentication sessions, raw PII or app-owned permission state into Ontology Core.",
"Do not infer a person or organization identity from display text alone.",
"Do not turn driver, owner or operator into permanent type hierarchies when a time-qualified assignment is required."
]
}
@@ -0,0 +1,38 @@
{
"version": "0.1.0",
"updatedAt": "2026-08-22",
"rules": [
{
"id": "guardrail.party.source_identities_remain_distinct",
"severity": "error",
"summary": "Person, organization, account, HUB user, authentication identity and agent identity remain distinct records joined only by explicit source-evidenced bindings.",
"entityIds": ["party.person", "party.organization", "party.account", "hub.user", "ndcauth.identity", "agent.identity"]
},
{
"id": "guardrail.party.access_enforcement_stays_with_owner",
"severity": "error",
"summary": "Ontology may describe an access subject and role meaning but must not store credentials or replace HUB, NDCAuth or app-owned authorization enforcement.",
"entityIds": ["party.access_subject", "hub.membership", "hub.app_grant", "ndcauth.identity"]
},
{
"id": "guardrail.party.roles_are_time_qualified",
"severity": "error",
"summary": "Operational roles such as driver are assignments with validity intervals and provenance, not permanent person subtypes or mutable labels on an asset.",
"entityIds": ["party.person", "party.driver_role", "asset.assignment", "asset.asset"]
},
{
"id": "guardrail.party.contacts_require_field_policy",
"severity": "warning",
"summary": "Phone, email and other contact values require an explicit field and exposure policy before Data Product, Foundry or external publication.",
"entityIds": ["party.party", "party.contact_point"]
}
],
"blockedConflations": [
["party.person", "hub.user"],
["party.person", "ndcauth.identity"],
["party.organization", "hub.client_context"],
["party.account", "integration.connection"],
["party.access_subject", "agent.identity"],
["party.person", "party.driver_role"]
]
}
@@ -0,0 +1,7 @@
{
"id": "party",
"version": "0.1.0",
"updatedAt": "2026-08-22",
"status": "product-required/source-evidenced",
"summary": "Provider-neutral actors, people, organizations, accounts, access subjects, contacts and operational roles composed without conflating product identities or authentication records."
}
@@ -0,0 +1,13 @@
{
"version": "0.1.0",
"updatedAt": "2026-08-22",
"relations": [
{ "id": "party.person.is_party", "from": ["party.person"], "to": ["party.party"], "status": "product-required", "summary": "A person participates in cross-domain relations through a stable Party identity." },
{ "id": "party.organization.is_party", "from": ["party.organization"], "to": ["party.party"], "status": "product-required", "summary": "An organization participates in cross-domain relations through a stable Party identity." },
{ "id": "party.account.represents_party", "from": ["party.account"], "to": ["party.party"], "status": "product-required", "summary": "An account explicitly represents a party inside one owning application or provider boundary." },
{ "id": "party.access_subject.represents_party", "from": ["party.access_subject"], "to": ["party.party"], "status": "product-required", "summary": "An access subject may resolve to a party while enforcement remains in the owning access service." },
{ "id": "party.party.has_contact_point", "from": ["party.party"], "to": ["party.contact_point"], "status": "product-required", "summary": "A party may expose classified contact points under an explicit field policy." },
{ "id": "party.driver_role.assigned_to_person", "from": ["party.driver_role"], "to": ["party.person"], "status": "product-required", "summary": "A driver role is assigned to a person for a bounded operational interval." },
{ "id": "party.driver_role.operates_asset", "from": ["party.driver_role"], "to": ["asset.asset"], "status": "product-required", "summary": "A driver role operates an asset through an explicit time-qualified assignment rather than a permanent hierarchy." }
]
}
@@ -0,0 +1,115 @@
# Device Domain Ontology v0.1
Date: 2026-08-22
Status: product-required / source-evidenced baseline for Device Core direct onboarding and Device Plane operation.
## Purpose
This package gives Device Core a provider-neutral semantic contract for registering, composing, connecting, configuring, observing and governing devices. It is derived from the existing Device Core schemas and Device Plane contracts, but it does not copy runtime tables into Ontology Core.
New B2 trackers are onboarded directly through Device Core. Gelios remains a parallel legacy/provider source for already connected units and is not a prerequisite for new devices.
## Runtime authority
Device Core owns:
- owner/project and collection scope;
- stable device identities;
- restricted identifiers and opaque credential references;
- adapter packages, immutable adapter versions and model profiles;
- discovery and enrollment lifecycle;
- time-qualified Asset bindings;
- Edge registrations, routes and sessions;
- desired configuration revisions and reconciled state;
- typed command intents/events and audit;
- device observations and their publication to Data Products.
Ontology Core owns only meanings, relation vocabulary, guardrails and evidence routing. Foundry consumes approved Data Products. Neither Ontology Core nor Foundry executes enrollment, device traffic or commands.
## Source evidence mapping
The first package is source-evidenced by the existing Device Core migrations:
- migration 001: profiles, contours, discoveries, device instances, bindings and audit;
- migration 002: owner scopes, projects, collections and grants;
- migration 004: adapter packages/versions, model profiles, Edge registrations, routes, sessions and enrollment intents;
- migration 006: direct lifecycle and ownership transitions;
- migration 008: restricted identifiers and credential bindings;
- migration 010: resource bindings, configuration revisions/state, commands and events;
- migration 013: Edge endpoint, server name, trust, certificate identity, generation and lifecycle;
- migration 015: integration device id retained as a restricted external reference.
Table names remain implementation details. Canonical entity ids remain stable even if runtime storage is refactored.
## Direct B2 onboarding
The accepted lifecycle is:
```text
candidate evidence
└─▶ device.discovery
└─▶ authorized device.enrollment_intent
├─▶ device.device / device.tracking_device
├─▶ device.model_profile ─▶ device.adapter_version
├─▶ device.restricted_identifier (IMEI/serial/provider id)
└─▶ device.asset_binding ─▶ asset.asset
accepted traffic
└─▶ device.edge_registration
└─▶ device.route
└─▶ device.session
└─▶ observation.source / observations
```
Discovery never claims ownership. Enrollment requires an authorized owner/project, reviewed model profile and exact identifier policy. The B2-to-trike binding is independent and temporal; a device may exist before attachment, and an Asset may exist without a current tracker.
## Adapter boundary
Vendor/protocol specifics live behind `device.adapter_package`, immutable `device.adapter_version` and `device.model_profile`. A future open-source tracking or traffic stack may implement adapters, storage or protocol processing behind this boundary. Its tables and vendor vocabulary do not become product ontology.
## Edge channel
The canonical Edge channel remains Core-initiated and pinned-mTLS:
- Core approves Edge registration identity, endpoint, server name and trust material;
- Edge is replaceable and untrusted for business authority;
- a concrete `infrastructure.service_instance` realizes the Edge registration on a host;
- routes terminate only at an approved Edge registration;
- sessions bind a stable device to one approved route;
- Edge never owns the central business database, secret authority or arbitrary command policy.
## Configuration
`device.configuration_revision` is immutable desired state. `device.configuration_state` reconciles a desired revision with observed evidence and time. A new revision never rewrites the old one. Secrets remain opaque references and are resolved only by the owning service.
## Commands
Commands are a red domain:
- target is a stable Device id;
- command type and payload schema are declared by the approved model/adapter contract;
- authorization, TTL and idempotency are explicit;
- request, acceptance, dispatch, acknowledgement, expiry and failure are separate events;
- arbitrary shell, raw provider text, firmware, reboot or memory wipe is not implied by the current safe `typed-service-ping-v1` contract;
- Device Control Core is authoritative for accepting ACK and final outcome.
## Gelios coexistence
Provider records map explicitly:
- `gelios.tracker_device``device.tracking_device` through a source binding;
- `gelios.unit``asset.asset` through a source binding;
- `gelios.position_fix``observation.position_observation` through a versioned mapping;
- legacy signal/movement values remain their existing closed Gelios value contracts.
Provider collection and direct Device traffic may coexist. They must retain source provenance and must not silently merge conflicting identities.
## Acceptance
- New B2 can be enrolled without a Gelios connection.
- Trike Asset and B2 Device receive different stable ids.
- IMEI remains restricted and can be rotated/reconciled without replacing Asset identity.
- Traffic is rejected before enrollment/profile/route/Edge checks.
- Config revisions and command lifecycle are immutable/auditable.
- Runtime records stay in Device Core, not Ontology Core or Foundry.
@@ -2,7 +2,20 @@
Package: `catalog/domain-packages/gelios`
Status: `v1.1.0`, source-evidenced and product-required.
Status: `v1.2.0`, source-evidenced and product-required.
## Provider-neutral Asset and Device bridge
As of 2026-08-22 Gelios remains a provider/legacy domain and no longer acts as the implicit product identity model for new devices:
- `gelios.unit` may map to `asset.asset` only through an explicit versioned source binding;
- `gelios.tracker_device` may map to `device.tracking_device` only through an explicit restricted-identifier/source binding;
- `gelios.position_fix` may map to `observation.position_observation` while retaining source and mapping provenance;
- existing provider Data Products may continue to use their current `map.moving_object` projection;
- new composed Data Products use the Asset as the stable map subject and the tracker as the observation source;
- direct B2 onboarding through Device Core does not require a Gelios connection.
Provider ids, IMEI values and renderer ids never replace NODE.DC Asset or Device identity. Direct and Gelios observations may coexist but must not silently overwrite one another.
## Purpose and boundary
@@ -0,0 +1,114 @@
# Infrastructure Domain Ontology v0.1
Date: 2026-08-22
Status: product-required / source-evidenced baseline for Device Core infrastructure inventory and Edge topology.
## Purpose
This package models VPS and other compute infrastructure as a provider-neutral graph. It prevents the current UI requirement from becoming a one-off VPS form or a false extension of `integration.connection`.
The canonical layers are:
```text
infrastructure.host
├─exposes──────────────▶ infrastructure.endpoint
├─target_of────────────▶ infrastructure.deployment
├─runs─────────────────▶ infrastructure.service_instance
└─target_of────────────▶ infrastructure.management_session
infrastructure.deployment
└─uses─────────────────▶ infrastructure.configuration_revision
infrastructure.service_instance
├─realizes─────────────▶ infrastructure.deployment
├─exposes──────────────▶ infrastructure.endpoint
└─realizes─────────────▶ device.edge_registration
```
These are peer graph subjects, not a deep type hierarchy. Each has independent identity and lifecycle.
## Authority boundary
Device Core may own the operational inventory required for Device Plane hosts, Edge services, monitoring and configuration. The canonical deploy runner remains authoritative for NODE.DC Synology release application and acceptance. A future provider adapter may own VPS account provisioning. Ontology Core owns none of those runtime mutations.
`integration.connection` represents a provider account/capability connection. It is never a Host. A cloud account may expose many Hosts; one Host may run many Service Instances; one Deployment may create or update one or more instances.
## Host registration
A host record requires at minimum:
- stable NODE.DC host id;
- host kind/capability profile;
- project/owner scope;
- provider-neutral display metadata;
- one or more namespaced external references where available;
- explicit endpoint records with protocol, visibility and trust policy;
- secret references only, never credential values;
- lifecycle state and audit evidence.
Registration alone does not prove reachability or health. Those are observations.
## Deployment and service instance
`infrastructure.deployment` records delivery intent and outcome for a versioned artifact/configuration against a target Host. `infrastructure.service_instance` is the concrete running service reconciled to that deployment.
For Device Plane:
- an Edge container/process is a Service Instance;
- its Core-approved application identity is `device.edge_registration`;
- the VPS is the Host;
- its mTLS/HTTP endpoint is an Endpoint;
- the release action and source version are Deployment evidence.
None of those identifiers are interchangeable.
## Monitoring
Host and service monitoring uses `observation.health_observation` with:
- stable target id;
- check/property id;
- observed and received time;
- source and mapping version;
- value and evidence summary;
- freshness policy selected by the consuming Data Product.
No observation means unavailable evidence. It is not automatically equivalent to unhealthy. Host health, service health, Edge registration state and device transport state remain separate facets.
## Management session and console
Browser console is possible only as an app-owned privileged management session, not as an iframe with an SSH key and not as a Device command.
Required contract:
- explicit authorized actor and project scope;
- exact target Host;
- reason/ticket or approved workflow context;
- short expiry and revocation;
- server-side credential resolution through an opaque reference;
- no secret returned to the browser;
- session start/end and executed-operation audit;
- policy-controlled copy/upload/download and network egress;
- separate break-glass permission from safe monitoring.
The first product slice may register and monitor Hosts without exposing console. That is a complete safe increment, not a placeholder for arbitrary shell.
## Foundry projection
Foundry receives provider-neutral Data Products and semantic bindings:
- inventory/table: Host, endpoints, deployments, service instances;
- topology/graph: Host ↔ Deployment ↔ Service Instance ↔ Edge ↔ routes/devices;
- Inspector: current observations, configuration revision and provenance;
- map: only subjects with actual spatial observation or declared fixed location.
A VPS with no real coordinates does not receive invented map coordinates.
## Acceptance
- Host, endpoint, deployment, service instance and Edge registration use separate ids.
- Credentials are opaque references and do not enter Ontology, Data Products or browser state.
- Monitoring values carry source/time/freshness and do not mutate Host identity.
- Console, if implemented, is privileged, short-lived and audited.
- VPS map presentation is evidence-driven, never hardcoded.
@@ -0,0 +1,116 @@
# Observation Domain Ontology v0.1
Date: 2026-08-22
Status: product-required / source-evidenced baseline for Device Core telemetry, health and spatial projection.
## Purpose
Observation is the provider-neutral bridge from runtime evidence to Data Products, Foundry state facets and monitoring. It separates the subject from a time-qualified statement about that subject.
The package covers:
- generic observations;
- declared observed-property value contracts;
- source/mapping provenance;
- consumer-owned freshness policy;
- health observations;
- position observations.
It is deliberately separate from lifecycle events, desired configuration and commands.
## Canonical observation envelope
An owning runtime service publishes at least:
```text
observation_id
subject_id
subject_entity_id
property_id
value + value_type + optional unit
observed_at
received_at
source_id + mapping_version
quality/evidence metadata
```
Freshness policy is referenced by the consuming Data Product and includes TTL, grace and missing-value behavior. It is not silently embedded in the source value.
`observed_at` is when the described state existed. `received_at` is when NODE.DC accepted the evidence. Both are required where a source can delay or replay data.
## Properties and values
`observation.observed_property` defines exact semantics and allowed values. Provider field names are mapping inputs, not canonical property ids. A Data Product may expose only mapped properties and exact values declared by its contract.
Examples:
- host reachability;
- service readiness;
- Edge channel connectivity;
- device transport session state;
- latitude/longitude position;
- speed or battery measurement;
- provider-specific Gelios `signal_state` and `movement_state` retained as their existing closed value contracts.
Foundry profiles may style declared state facets. They may not invent `unknown`, `stale`, `offline` or aggregate health values unless the bound property contract defines them.
## Missing and stale evidence
Missing evidence means no acceptable observation is available. Expired evidence means an observation failed the selected freshness policy. Neither automatically means unhealthy.
If a product wants `unknown`, `unavailable` or `unhealthy`, the owning property contract must define the value and derivation rule. Derived values must retain source observations and mapping version.
This rule prevents three common conflations:
- source value vs consumer freshness;
- missing observation vs negative observation;
- health of Host vs health of Service/Edge/Device.
## Health observations
`observation.health_observation` targets one stable layer at a time:
- `infrastructure.host` for host reachability/resources;
- `infrastructure.service_instance` for service process/readiness;
- `device.edge_registration` for Core↔Edge channel acceptance;
- `device.device` for device-specific transport or service checks.
An aggregate status may be published only by a versioned derived-property contract that identifies its inputs, precedence and missing-data rules.
## Position observations
`observation.position_observation` includes coordinate reference, coordinates, observed time, source and quality. For direct B2 traffic the provenance chain is:
```text
asset.asset
◀─ active device.asset_binding ─ device.tracking_device
◀─ position observation source ─ device.session / adapter mapping
─▶ map.moving_object Data Product projection
```
The map subject remains the Asset. The B2 remains the source Device. The observation remains evidence. None becomes the renderer entity identity.
Infrastructure may use the same position contract for a real fixed or mobile location. An address label or datacenter name without resolved spatial evidence is insufficient.
## Provider mappings
Existing Gelios mappings remain explicit:
- `gelios.position_fix` can map to a position observation;
- `gelios.telemetry_snapshot` can produce generic observations only through a versioned property mapping;
- raw provider payloads remain restricted;
- direct B2 and Gelios observations retain distinct sources and can be reconciled without silent overwrite.
## Storage and retention
Ontology Core stores no runtime observations. Device Core, an External Data Plane or another owning telemetry service owns current state, history, retention, cursoring and replay. Data Products expose approved projections; Foundry is not a telemetry database.
## Acceptance
- Every observation names stable subject, property, source, observed time and received time.
- Freshness is explicit and separate from the source value.
- Missing evidence is not silently converted to unhealthy.
- Health checks target one infrastructure/device layer at a time.
- Position projection retains Asset, Device and Observation as separate subjects.
- Provider values reach Foundry only through versioned mappings.
@@ -0,0 +1,99 @@
# Party and Asset Domain Ontology v0.1
Date: 2026-08-22
Status: product-required / source-evidenced baseline for Device Core and Foundry composition.
## Purpose
This domain defines stable business actors and assets independently from application accounts, trackers, providers and renderers. It is intentionally a shallow graph. A subject acquires meaning through explicit relations and time-qualified assignments rather than through a deep inheritance tree.
The first accepted product case is Robot2B:
- a trike is `asset.asset`;
- B2 is a separate `device.tracking_device`;
- the active attachment is `device.asset_binding` with `valid_from`, optional `valid_to`, lifecycle state and provenance;
- a driver is `party.person` participating through a time-qualified `party.driver_role` and `asset.assignment`;
- IMEI remains `device.restricted_identifier` on the tracker;
- map presentation is a projection of the Asset through `map.moving_object`, backed by `observation.position_observation`.
Changing the tracker, driver, provider or renderer must not replace the trike identity.
## Authority boundary
Ontology Core owns canonical meanings, relation names, aliases, blocked conflations and evidence routing. It stores no party rows, PII, asset rows, assignments, positions or access decisions.
Owning products remain authoritative for runtime state:
- HUB/NDCAuth own users, memberships, identities and authentication;
- Device Core owns asset/device composition used by Device operations;
- business applications own people, organizations and role assignments in their contour;
- Data Products expose approved projections;
- Foundry renders those projections and does not create domain identity.
## Canonical graph
```text
party.person ──is_party──────────────▶ party.party
party.organization ──is_party───────▶ party.party
party.account ──represents_party────▶ party.party
party.driver_role ──assigned_to─────▶ party.person
party.driver_role ──operates────────▶ asset.asset
asset.asset ──classified_by─────────▶ asset.asset_type
asset.asset ──has_assignment────────▶ asset.assignment
asset.asset ──has_external_ref──────▶ asset.external_reference
asset.asset ──has_lifecycle_event───▶ asset.lifecycle_event
asset.asset ──projected_as──────────▶ map.moving_object
```
The relation record or owning runtime binding carries provenance and validity. A UI may show the current effective relation, but history must remain queryable.
## Identity rules
`asset.asset` uses a stable NODE.DC-owned identifier. External references are namespaced and replaceable. The following values may be indexed for reconciliation but may not become the Asset identity:
- IMEI or hardware serial;
- current tracker id;
- Gelios unit id;
- renderer entity id;
- current driver or owner id;
- project or collection id;
- display name.
`party.person`, `hub.user`, `ndcauth.identity`, `party.account` and `agent.identity` are separate source records. Their composition requires explicit bindings with source authority; matching display name or email alone is insufficient.
## Temporal assignments
Assignments use half-open validity semantics: `valid_from <= t < valid_to`; `valid_to = null` means the relation remains current. The owning service must prevent overlapping active assignments where the product contract requires exclusivity. Closing an assignment appends or transitions evidence; it does not erase the old relation.
Examples include:
- driver operates trike;
- organization owns/manages asset;
- asset belongs to an operational project;
- tracker is attached to asset;
- contact point is valid for a party.
## Foundry projection
Foundry consumes stable Data Product keys and semantic bindings. It may combine identity, technical profile, contacts, current position and state facets by stable subject id. It must not infer Party or Asset identity from a provider-specific payload.
An Asset can be shown on a map only when a bound Data Product supplies a valid position observation. Without spatial evidence, the same Asset remains available in table, graph or Inspector views.
## Gelios coexistence
Existing Gelios records remain provider evidence:
- `gelios.unit` can map to an Asset only through an explicit source binding;
- `gelios.tracker_device` can map to a Tracking Device only through an explicit device binding;
- these mappings do not make provider ids canonical;
- new B2 onboarding does not require Gelios.
## Acceptance
- Trike and B2 resolve to separate canonical subjects.
- Replacing B2 closes one binding and opens another without changing the Asset id.
- IMEI is restricted and absent from public Foundry projections unless an explicit field policy grants it.
- Driver is a temporal role, not a Person subtype or free-text Asset field.
- Map identity is the Asset/Data Product key, not a provider or renderer key.
@@ -31,3 +31,12 @@ Current working evidence artifacts:
- `EVIDENCE_LEDGER_ENGINE_DIRTY_BOUNDARY_P1.md`
- `EVIDENCE_LEDGER_ENGINE_WORKFLOW_P1.md`
- `ONTOLOGY_SERVICE_PLACEMENT_AND_USE_CASES.md`
Accepted additive domain-package baselines from 2026-08-22:
- `../PARTY_ASSET_DOMAIN_ONTOLOGY.md`
- `../DEVICE_DOMAIN_ONTOLOGY.md`
- `../INFRASTRUCTURE_DOMAIN_ONTOLOGY.md`
- `../OBSERVATION_DOMAIN_ONTOLOGY.md`
These packages keep Party, Asset, Device, Observation and infrastructure subjects in a shallow explicit graph. Runtime rows, telemetry, credentials, assignments and commands remain owned by their application services and are not stored in Ontology Core.
@@ -0,0 +1,38 @@
{
"fixture": "device-direct-b2-composition-v1",
"catalogVersion": "ontology-core-v0.4-pre+device-domain-0.1.0",
"project": { "entityId": "device.project", "sourceId": "device-project:robot2b-moscow" },
"asset": { "entityId": "asset.asset", "sourceId": "asset:trike-001", "assetType": "trike" },
"device": {
"entityId": "device.tracking_device",
"sourceId": "device:b2-001",
"restrictedIdentifiers": [
{ "entityId": "device.restricted_identifier", "namespace": "imei", "valueExposure": "restricted" }
],
"modelProfile": { "entityId": "device.model_profile", "sourceId": "model-profile:arnavi-b2-v1" }
},
"binding": {
"entityId": "device.asset_binding",
"sourceId": "device-asset-binding:b2-001:trike-001:20260822",
"deviceSourceId": "device:b2-001",
"assetSourceId": "asset:trike-001",
"validFrom": "2026-08-22T00:00:00Z",
"validTo": null,
"provenance": "device-core-direct-enrollment"
},
"positionObservation": {
"entityId": "observation.position_observation",
"subjectSourceId": "asset:trike-001",
"sourceDeviceId": "device:b2-001",
"observedAt": "2026-08-22T10:00:00Z",
"receivedAt": "2026-08-22T10:00:01Z",
"projectionEntityId": "map.moving_object"
},
"assertions": [
"asset.sourceId != device.sourceId",
"imei is not an asset identifier",
"binding is temporal and replaceable",
"map subject is the asset",
"Gelios connection is not required"
]
}
@@ -0,0 +1,30 @@
{
"fixture": "infrastructure-edge-host-composition-v1",
"catalogVersion": "ontology-core-v0.4-pre+infrastructure-domain-0.1.0",
"host": { "entityId": "infrastructure.host", "sourceId": "host:robot2b-edge-01", "kind": "vps" },
"endpoint": { "entityId": "infrastructure.endpoint", "sourceId": "endpoint:robot2b-edge-01:https", "visibility": "core-egress-only" },
"deployment": { "entityId": "infrastructure.deployment", "sourceId": "deployment:device-edge:20260822-001" },
"serviceInstance": { "entityId": "infrastructure.service_instance", "sourceId": "service-instance:device-edge:robot2b-edge-01" },
"edgeRegistration": { "entityId": "device.edge_registration", "sourceId": "edge-registration:robot2b-edge-01" },
"healthObservation": {
"entityId": "observation.health_observation",
"subjectSourceId": "service-instance:device-edge:robot2b-edge-01",
"propertyId": "service.readiness",
"observedAt": "2026-08-22T10:00:00Z",
"receivedAt": "2026-08-22T10:00:00Z",
"freshnessPolicyId": "health:service-readiness:60s"
},
"management": {
"credentialEntityId": "infrastructure.management_credential_reference",
"secretExposure": "opaque-reference-only",
"consoleEntityId": "infrastructure.management_session",
"mode": "privileged-break-glass"
},
"assertions": [
"host, endpoint, deployment, service instance and edge registration use distinct ids",
"integration.connection is not a host",
"missing health evidence is not automatically unhealthy",
"no management secret reaches the browser",
"map projection requires real spatial evidence"
]
}
+1
View File
@@ -18,6 +18,7 @@
"smoke:assistant-executor": "node src/assistant-action-executor.mjs --smoke",
"smoke:assistant-actions": "node src/assistant-action-resolver.mjs --smoke",
"smoke:assistant-policy": "node src/assistant-policy.mjs --smoke",
"smoke:device-domain": "node src/scripts/smoke-device-domain.mjs",
"smoke:mcp": "node src/scripts/smoke-mcp.mjs",
"smoke:resolver": "node src/resolver.mjs --smoke"
}
@@ -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',
],