Two things the entity window redesign surfaced but deliberately left alone. **blast_radius answered the wrong question.** It walked source→target for every relationship type, but which end of an edge is the dependent differs per type: "machine hosts container" means the target breaks, while "service depends-on service" and "ingress routes-to service" mean the SOURCE breaks. Walking everything forwards was right for hosts/provides and backwards for everything else — and swept in 2,800+ documents/involves/targets edges of pure bookkeeping, so the result contained tasks and executions that cannot break. Direction is now declared per relationship type in seeds/ontology.yaml (blast_direction: forward | backward | none), the same shape as the entity types' monitoring: declaration, and defaults to none so an undeclared edge contributes nothing rather than a confidently wrong answer. It also needed a modelling fix: `routes-to` names an ingress's BACKEND, so nothing recorded that all 21 public hostnames are terminated by caddy. A `served-by` edge type now says so. pool:ludo-lvm 2 -> 23 (every container storing on it, then their services) lxc:caddy 4 -> 22 (service:caddy, then all 21 ingress routes) service:authentik 7 (what authenticates via it) **Every ping check was reporting down.** Not a host:strong false positive: all seven, including ws:mac-mini — the Docker host itself. The scheduler runs in Docker on macOS, whose VM does not route ICMP to the LAN; loopback pings succeed and every LAN ping fails. Under health aggregation each broken probe dragged its entity to down. The question the check exists to answer is "is it reachable", and ICMP is only one way to ask it. checkPing now falls back to a TCP connect before concluding anything, which restores an honest verdict for the four hosts that are genuinely up while leaving the genuinely unreachable ones down. TestBlastRadiusTerminatesOnCycles asserted the old direction (caddy=1, authentik=2 — the cycle walked the wrong way); it now asserts the corrected depths, and its exact-node-count check is relaxed because walking the right way also surfaces the seed's own real dependents, which are correct answers. Co-Authored-By: Claude <noreply@anthropic.com>
1028 lines
33 KiB
YAML
1028 lines
33 KiB
YAML
# Oikos ontology seed — the systems model of the homelab.
|
|
#
|
|
# Bootstraps entity_types / relationship_types / lifecycle_defs on first
|
|
# deploy (migration 001). After ingest the DB is authoritative; this file
|
|
# is regenerated by `GET /api/v1/export` for DR + version control.
|
|
#
|
|
# Conventions:
|
|
# - entity type names are kebab-case
|
|
# - `parent:` builds the is-a hierarchy; `abstract: true` types cannot be
|
|
# instantiated (validation walks the hierarchy for relationship
|
|
# endpoints and policy rules — plan R3-1)
|
|
# - `layer:` one of meta | infrastructure | governance | cognition
|
|
# - relationship `cardinality:` describes source→target multiplicity:
|
|
# one-to-one | one-to-many | many-to-one | many-to-many
|
|
# - relationship endpoints may name abstract types
|
|
# - lifecycle transition `requires:` entries are NAMED CHECKS implemented
|
|
# in Go (internal/ontology); the DB stores which checks gate a
|
|
# transition, the code implements them
|
|
# - mount details (mount_point, options) live as ATTRIBUTES on `mounts`
|
|
# edges, not as a separate entity type
|
|
#
|
|
# Rule of completeness: if something can break, be changed, or hold data,
|
|
# it has an entity type here and edges to the things it touches.
|
|
|
|
version: 1
|
|
|
|
# ─── Lifecycles ────────────────────────────────────────────────────────
|
|
|
|
lifecycles:
|
|
infrastructure:
|
|
states: [planned, provisioning, active, migrating, failed, deprecated, destroyed]
|
|
default_state: active # legacy inventory entries without state are active
|
|
terminal_states: [destroyed]
|
|
transitions:
|
|
planned:
|
|
provisioning: {requires: [inventory-entry, ip-reserved, storage-pool-chosen, doc-page-stub]}
|
|
destroyed: {requires: [cancelled-note]}
|
|
provisioning:
|
|
active: {requires: [age-key-enrolled-if-needed, mesh-joined-if-needed,
|
|
ingress-live-if-public, health-check-answering,
|
|
doc-page-complete]}
|
|
failed: {requires: []}
|
|
active:
|
|
migrating: {requires: [preflight, backup-verified]}
|
|
deprecated: {requires: [replacement-live-or-role-retired]}
|
|
failed: {requires: []}
|
|
migrating:
|
|
active: {requires: [post-verify, caddy-backends-checked, mounts-checked, docs-updated]}
|
|
failed: {requires: []}
|
|
failed:
|
|
active: {requires: [recovery-verified]}
|
|
deprecated: {requires: [write-off-note]}
|
|
deprecated:
|
|
active: {requires: [un-deprecate-note]}
|
|
destroyed: {requires: [backups-verified, secrets-revoked-and-rekeyed,
|
|
ingress-and-dns-removed, no-inbound-edges,
|
|
archaeology-entry]}
|
|
|
|
signal:
|
|
states: [raised, acknowledged, acting, muted, resolved, failed]
|
|
default_state: raised
|
|
terminal_states: [resolved]
|
|
transitions:
|
|
raised:
|
|
acknowledged: {requires: []}
|
|
muted: {requires: [mute-ttl-set]}
|
|
resolved: {requires: [condition-cleared]}
|
|
acknowledged:
|
|
acting: {requires: [classification-exists]}
|
|
resolved: {requires: []}
|
|
muted: {requires: [mute-ttl-set]}
|
|
acting:
|
|
resolved: {requires: [verification-passed]}
|
|
raised: {requires: [retry-budget-remaining]}
|
|
failed: {requires: []}
|
|
failed:
|
|
acknowledged: {requires: [operator-retry]}
|
|
muted:
|
|
raised: {requires: [mute-ttl-expired]}
|
|
|
|
execution:
|
|
states: [proposed, approved, auto_approved, denied, expired, executing,
|
|
verifying, verified, failed, timed_out, cancelled, rolled_back,
|
|
rollback_failed]
|
|
default_state: proposed
|
|
terminal_states: [verified, failed, denied, expired, cancelled,
|
|
rolled_back, rollback_failed]
|
|
transitions:
|
|
proposed:
|
|
approved: {requires: [operator-approval]}
|
|
auto_approved: {requires: [autonomy-allows]}
|
|
denied: {requires: []}
|
|
approved:
|
|
executing: {requires: [approval-token-valid]}
|
|
expired: {requires: [approval-ttl-elapsed]}
|
|
auto_approved:
|
|
executing: {requires: []}
|
|
executing:
|
|
verified: {requires: [verification-passed]}
|
|
failed: {requires: []}
|
|
timed_out: {requires: []}
|
|
cancelled: {requires: [operator-abort]}
|
|
timed_out:
|
|
verifying: {requires: []} # check if the command completed anyway
|
|
verifying:
|
|
verified: {requires: [verification-passed]}
|
|
failed: {requires: []}
|
|
failed:
|
|
rolled_back: {requires: [rollback-procedure-exists]}
|
|
rollback_failed: {requires: []}
|
|
|
|
approval:
|
|
states: [pending, approved, denied, expired, revoked]
|
|
default_state: pending
|
|
terminal_states: [denied, expired, revoked]
|
|
transitions:
|
|
pending:
|
|
approved: {requires: [token-verified]}
|
|
denied: {requires: []}
|
|
expired: {requires: [ttl-elapsed]}
|
|
approved:
|
|
revoked: {requires: [not-yet-executing]}
|
|
|
|
pattern:
|
|
states: [hypothesized, validated, active, deprecated, invalidated]
|
|
default_state: hypothesized
|
|
terminal_states: [deprecated, invalidated]
|
|
transitions:
|
|
hypothesized:
|
|
validated: {requires: [evidence-count-5plus, confidence-0.7plus]}
|
|
invalidated: {requires: []}
|
|
validated:
|
|
active: {requires: [operator-approval]} # S4: never automatic
|
|
invalidated: {requires: []}
|
|
active:
|
|
deprecated: {requires: []}
|
|
invalidated: {requires: [contradicting-evidence]}
|
|
|
|
skill:
|
|
states: [drafted, tested, active, refined, failed, deprecated]
|
|
default_state: drafted
|
|
terminal_states: [deprecated]
|
|
transitions:
|
|
drafted:
|
|
tested: {requires: [test-execution-recorded]}
|
|
deprecated: {requires: []}
|
|
tested:
|
|
active: {requires: [operator-approval]}
|
|
failed: {requires: []}
|
|
failed:
|
|
drafted: {requires: []}
|
|
active:
|
|
refined: {requires: [new-version-created]}
|
|
deprecated: {requires: []}
|
|
refined:
|
|
active: {requires: [operator-approval]}
|
|
|
|
# ─── Entity types ──────────────────────────────────────────────────────
|
|
# domain: physical | compute | network | storage | software | external |
|
|
# identity | cognition
|
|
|
|
entity_types:
|
|
|
|
# Root
|
|
entity:
|
|
abstract: true
|
|
domain: meta
|
|
layer: meta
|
|
description: Root abstract type. Relationship endpoints that accept any
|
|
entity (documented-by, procedure-for, checks) reference this.
|
|
|
|
# ── Infrastructure / physical ──
|
|
site:
|
|
parent: entity
|
|
domain: physical
|
|
layer: infrastructure
|
|
lifecycle: infrastructure
|
|
description: Physical location (home, VPS datacenter).
|
|
monitoring: none # topological — health is its members'
|
|
attributes: {type: object, properties: {address: {type: string}}}
|
|
ups:
|
|
parent: entity
|
|
domain: physical
|
|
layer: infrastructure
|
|
lifecycle: infrastructure
|
|
description: Uninterruptible power supply.
|
|
monitoring: none # warranted, but no SNMP/NUT checker exists yet
|
|
attributes: {type: object, properties: {vendor: {type: string}, va: {type: integer}}}
|
|
sensor:
|
|
parent: entity
|
|
domain: physical
|
|
layer: infrastructure
|
|
lifecycle: infrastructure
|
|
description: Environmental sensor.
|
|
monitoring: none # readings are metrics, not health
|
|
peripheral:
|
|
parent: entity
|
|
domain: physical
|
|
layer: infrastructure
|
|
lifecycle: infrastructure
|
|
description: Attached hardware (GPU, e-ink display, dongle).
|
|
monitoring: none # visible only through its host
|
|
|
|
# ── Infrastructure / compute ──
|
|
compute-entity:
|
|
parent: entity
|
|
abstract: true
|
|
domain: compute
|
|
layer: infrastructure
|
|
description: Anything that executes workloads (machine, VM, container).
|
|
machine:
|
|
parent: compute-entity
|
|
abstract: true
|
|
domain: compute
|
|
layer: infrastructure
|
|
description: Physical machine. Always instantiated as a subtype.
|
|
monitoring: [ping, resource, updates] # inherited by proxmox-host /
|
|
# standalone-server / workstation / appliance
|
|
attributes:
|
|
type: object
|
|
properties:
|
|
cpu_arch: {type: string}
|
|
ram_gb: {type: number}
|
|
os: {type: string, enum: [linux, macos]}
|
|
lan_ip: {type: string}
|
|
mesh: {type: object}
|
|
ssh: {type: object}
|
|
age_pubkey: {type: string}
|
|
proxmox-host:
|
|
parent: machine
|
|
domain: compute
|
|
layer: infrastructure
|
|
lifecycle: infrastructure
|
|
description: Machine running Proxmox VE.
|
|
attributes:
|
|
type: object
|
|
properties: {pve_version: {type: string}}
|
|
standalone-server:
|
|
parent: machine
|
|
domain: compute
|
|
layer: infrastructure
|
|
lifecycle: infrastructure
|
|
description: Machine outside PVE management (e.g. external VPS).
|
|
attributes:
|
|
type: object
|
|
properties:
|
|
hypervisor: {type: string}
|
|
provider: {type: string}
|
|
control_level: {type: string, enum: [full, partial, none]}
|
|
public_ipv4: {type: string}
|
|
workstation:
|
|
parent: machine
|
|
domain: compute
|
|
layer: infrastructure
|
|
lifecycle: infrastructure
|
|
description: Operator machine (may also host services, e.g. mac-mini).
|
|
attributes:
|
|
type: object
|
|
properties: {user: {type: string}}
|
|
appliance:
|
|
parent: machine
|
|
domain: compute
|
|
layer: infrastructure
|
|
lifecycle: infrastructure
|
|
description: Vendor appliance with limited management access.
|
|
attributes:
|
|
type: object
|
|
properties: {vendor: {type: string}, model: {type: string}}
|
|
vm:
|
|
parent: compute-entity
|
|
domain: compute
|
|
layer: infrastructure
|
|
lifecycle: infrastructure
|
|
description: Virtual machine.
|
|
monitoring: [ping] # no guest agent assumed; reachability only
|
|
attributes:
|
|
type: object
|
|
properties:
|
|
pve_id: {type: integer}
|
|
vcpus: {type: integer}
|
|
memory_mb: {type: integer}
|
|
lan_ip: {type: string}
|
|
public_host: {type: string}
|
|
role: {type: string}
|
|
container:
|
|
parent: compute-entity
|
|
abstract: true
|
|
domain: compute
|
|
layer: infrastructure
|
|
description: OS-level container (LXC or Docker).
|
|
monitoring: [resource] # inherited by lxc / docker-container
|
|
attributes:
|
|
type: object
|
|
properties: {runtime: {type: string}}
|
|
lxc:
|
|
parent: container
|
|
domain: compute
|
|
layer: infrastructure
|
|
lifecycle: infrastructure
|
|
description: Proxmox LXC container.
|
|
attributes:
|
|
type: object
|
|
properties:
|
|
pve_id: {type: integer}
|
|
lan_ip: {type: string}
|
|
public_host: {type: string}
|
|
public_hosts: {type: array, items: {type: string}}
|
|
role: {type: string}
|
|
mesh: {type: object}
|
|
age_pubkey: {type: string}
|
|
destroyed: {type: string}
|
|
reason: {type: string}
|
|
docker-container:
|
|
parent: container
|
|
domain: compute
|
|
layer: infrastructure
|
|
lifecycle: infrastructure
|
|
description: Docker container (the OS models its own stack with these).
|
|
attributes:
|
|
type: object
|
|
properties: {image: {type: string}}
|
|
hypervisor:
|
|
parent: entity
|
|
domain: compute
|
|
layer: infrastructure
|
|
lifecycle: infrastructure
|
|
description: Hypervisor software running on a machine (PVE, KVM, OrbStack).
|
|
monitoring: none # the hosting machine's checks cover it
|
|
attributes:
|
|
type: object
|
|
properties: {type: {type: string}, version: {type: string}}
|
|
|
|
# ── Infrastructure / network ──
|
|
network:
|
|
parent: entity
|
|
abstract: true
|
|
domain: network
|
|
layer: infrastructure
|
|
description: A network things connect to.
|
|
monitoring: none # inherited by lan / mesh / vlan — a network's
|
|
# reachability is a property of its members
|
|
lan:
|
|
parent: network
|
|
domain: network
|
|
layer: infrastructure
|
|
lifecycle: infrastructure
|
|
description: Local area network.
|
|
attributes: {type: object, properties: {subnet: {type: string}}}
|
|
mesh:
|
|
parent: network
|
|
domain: network
|
|
layer: infrastructure
|
|
lifecycle: infrastructure
|
|
description: Overlay mesh network (NetBird, Tailscale).
|
|
attributes:
|
|
type: object
|
|
properties:
|
|
provider: {type: string}
|
|
subnet: {type: string}
|
|
domain: {type: string}
|
|
vlan:
|
|
parent: network
|
|
domain: network
|
|
layer: infrastructure
|
|
lifecycle: infrastructure
|
|
description: Tagged VLAN.
|
|
attributes: {type: object, properties: {tag: {type: integer}}}
|
|
network-interface:
|
|
parent: entity
|
|
domain: network
|
|
layer: infrastructure
|
|
description: Optional per-interface refinement (mac, ip). The seed uses
|
|
coarse connects-via edges; interfaces can be backfilled later.
|
|
monitoring: none # covered by its machine's ping/resource checks
|
|
attributes: {type: object, properties: {mac: {type: string}, ip: {type: string}}}
|
|
dns-zone:
|
|
parent: entity
|
|
domain: network
|
|
layer: infrastructure
|
|
lifecycle: infrastructure
|
|
description: DNS zone (e.g. split-horizon hubris.network).
|
|
monitoring: [dns] # NOTE: no `dns` checker exists yet — this is a
|
|
# real gap and coverageSweep will report it
|
|
attributes: {type: object, properties: {zone: {type: string}, authority: {type: string}}}
|
|
dns-record:
|
|
parent: entity
|
|
domain: network
|
|
layer: infrastructure
|
|
description: Individual DNS record.
|
|
monitoring: none # the zone is the unit of monitoring
|
|
attributes:
|
|
type: object
|
|
properties: {name: {type: string}, record_type: {type: string}, value: {type: string}}
|
|
ingress-route:
|
|
parent: entity
|
|
domain: network
|
|
layer: infrastructure
|
|
lifecycle: infrastructure
|
|
description: Public hostname → upstream mapping (Caddy).
|
|
monitoring: [http] # end-to-end: exercises Caddy + DNS + TLS + upstream
|
|
attributes:
|
|
type: object
|
|
properties:
|
|
pattern: {type: string}
|
|
upstream: {type: string}
|
|
forward_auth: {type: boolean}
|
|
certificate:
|
|
parent: entity
|
|
domain: network
|
|
layer: infrastructure
|
|
description: TLS certificate.
|
|
monitoring: [cert-expiry]
|
|
attributes: {type: object, properties: {issuer: {type: string}, expires: {type: string}}}
|
|
firewall-rule:
|
|
parent: entity
|
|
domain: network
|
|
layer: infrastructure
|
|
description: Firewall / port-forward rule.
|
|
monitoring: none # declarative config, not a running thing
|
|
|
|
# ── Infrastructure / storage ──
|
|
storage-pool:
|
|
parent: entity
|
|
domain: storage
|
|
layer: infrastructure
|
|
lifecycle: infrastructure
|
|
description: Storage pool (LVM, ZFS, NFS).
|
|
monitoring: [capacity]
|
|
attributes:
|
|
type: object
|
|
properties:
|
|
type: {type: string}
|
|
capacity_gb: {type: number}
|
|
volume:
|
|
parent: entity
|
|
domain: storage
|
|
layer: infrastructure
|
|
lifecycle: infrastructure
|
|
description: Named volume / dataset within a pool. Mount details live as
|
|
attributes on `mounts` edges.
|
|
monitoring: [capacity]
|
|
attributes: {type: object, properties: {size_gb: {type: number}, path: {type: string}}}
|
|
backup-target:
|
|
parent: entity
|
|
domain: storage
|
|
layer: infrastructure
|
|
lifecycle: infrastructure
|
|
description: Where backups land (Proton Drive, PBS).
|
|
monitoring: [backup-freshness] # checker lands in Phase 4
|
|
attributes: {type: object, properties: {provider: {type: string}, encrypted: {type: boolean}}}
|
|
dataset:
|
|
parent: entity
|
|
domain: storage
|
|
layer: infrastructure
|
|
description: Logical data collection worth tracking independently of its
|
|
volume (e.g. paperless documents).
|
|
monitoring: none # its volume and owning service carry the checks
|
|
|
|
# ── Infrastructure / software ──
|
|
service:
|
|
parent: entity
|
|
domain: software
|
|
layer: infrastructure
|
|
lifecycle: infrastructure
|
|
description: A running service with consumers.
|
|
monitoring: [http, process] # http when it has a `url`, else a process check
|
|
# on the host resolved through its hosting edge
|
|
attributes:
|
|
type: object
|
|
properties:
|
|
url: {type: string}
|
|
port: {type: integer}
|
|
health: {type: string}
|
|
endpoint: {type: string}
|
|
systemd_unit: {type: string}
|
|
doc_page: {type: string}
|
|
risk_notes: {type: string}
|
|
note: {type: string}
|
|
application:
|
|
parent: entity
|
|
domain: software
|
|
layer: infrastructure
|
|
description: Deployed application/package a service runs.
|
|
monitoring: none # the service in front of it is the probe target
|
|
attributes: {type: object, properties: {version: {type: string}}}
|
|
config-repo:
|
|
parent: entity
|
|
domain: software
|
|
layer: infrastructure
|
|
description: Git repo holding tracked configuration.
|
|
monitoring: none # its Gitea service carries the checks
|
|
attributes:
|
|
type: object
|
|
properties: {url: {type: string}, branch: {type: string}}
|
|
deploy-pipeline:
|
|
parent: entity
|
|
domain: software
|
|
layer: infrastructure
|
|
description: Automated deploy path (webhook → script).
|
|
monitoring: none # health is per-deploy, tracked as executions
|
|
attributes:
|
|
type: object
|
|
properties: {trigger: {type: string}, target_path: {type: string}}
|
|
package-set:
|
|
parent: entity
|
|
domain: software
|
|
layer: infrastructure
|
|
description: Managed package baseline for a host class.
|
|
monitoring: none # drift shows up via each host's updates check
|
|
cluster:
|
|
parent: entity
|
|
domain: software
|
|
layer: infrastructure
|
|
lifecycle: infrastructure
|
|
description: Proxmox cluster.
|
|
monitoring: none # topological — its member hosts carry the checks
|
|
attributes: {type: object, properties: {quorum: {type: string}}}
|
|
compose-stack:
|
|
parent: entity
|
|
domain: software
|
|
layer: infrastructure
|
|
lifecycle: infrastructure
|
|
description: Docker Compose stack (the Oikos OS itself is one).
|
|
monitoring: [process]
|
|
attributes: {type: object, properties: {path: {type: string}}}
|
|
|
|
# ── Infrastructure / external ──
|
|
domain-registration:
|
|
parent: entity
|
|
domain: external
|
|
layer: infrastructure
|
|
description: Registered public domain.
|
|
monitoring: none # expiry is a calendar concern, not a probe
|
|
attributes: {type: object, properties: {registrar: {type: string}, expires: {type: string}}}
|
|
cloud-service:
|
|
parent: entity
|
|
domain: external
|
|
layer: infrastructure
|
|
description: External SaaS/cloud dependency.
|
|
monitoring: [http] # only when the entity carries a `url`
|
|
isp-link:
|
|
parent: entity
|
|
domain: external
|
|
layer: infrastructure
|
|
description: Internet uplink.
|
|
monitoring: none # no probe target; reachability shows up fleet-wide
|
|
vendor-dependency:
|
|
parent: entity
|
|
domain: external
|
|
layer: infrastructure
|
|
description: Vendor the lab depends on (registrar, IONOS, Proton).
|
|
monitoring: none # a commercial relationship, not a running thing
|
|
|
|
# ── Governance / identity ──
|
|
person:
|
|
parent: entity
|
|
domain: identity
|
|
layer: governance
|
|
description: Human actor (operator).
|
|
attributes:
|
|
type: object
|
|
properties: {matrix_id: {type: string}, oidc_sub: {type: string}, email: {type: string}}
|
|
agent:
|
|
parent: entity
|
|
domain: identity
|
|
layer: governance
|
|
lifecycle: infrastructure # agents are deployed/retired like infrastructure
|
|
description: Software agent actor (Nomos, the Oikos control loop).
|
|
monitoring: [http] # governance layer, but genuinely probeable —
|
|
# Nomos serves a gateway on :8092
|
|
attributes:
|
|
type: object
|
|
properties:
|
|
provider: {type: string}
|
|
model: {type: string}
|
|
gateway_port: {type: integer}
|
|
identity-provider:
|
|
parent: entity
|
|
domain: identity
|
|
layer: governance
|
|
description: OIDC / forward-auth provider (Authentik).
|
|
attributes:
|
|
type: object
|
|
properties:
|
|
issuer: {type: string}
|
|
client_id: {type: string}
|
|
auth_mode: {type: string, enum: [oidc, forward-auth, both]}
|
|
account:
|
|
parent: entity
|
|
domain: identity
|
|
layer: governance
|
|
description: An account a person/agent holds on a service.
|
|
secret:
|
|
parent: entity
|
|
domain: identity
|
|
layer: governance
|
|
description: Managed secret (Infisical path).
|
|
attributes:
|
|
type: object
|
|
properties: {path: {type: string}, rotation_days: {type: integer}}
|
|
key:
|
|
parent: entity
|
|
domain: identity
|
|
layer: governance
|
|
description: Cryptographic key (SSH, age).
|
|
access-grant:
|
|
parent: entity
|
|
domain: identity
|
|
layer: governance
|
|
description: Grant of access to a secret/scope.
|
|
attributes: {type: object, properties: {scope: {type: string}, expires: {type: string}}}
|
|
|
|
# ── Cognition ──
|
|
check:
|
|
parent: entity
|
|
domain: cognition
|
|
layer: cognition
|
|
description: Probe definition (checks-as-data, R3-7). Typed row in check_defs.
|
|
signal:
|
|
parent: entity
|
|
domain: cognition
|
|
layer: cognition
|
|
lifecycle: signal
|
|
description: Something needing attention. Typed row in signals.
|
|
classification:
|
|
parent: entity
|
|
domain: cognition
|
|
layer: cognition
|
|
description: A classifier decision with full reasoning. Typed row in classifications.
|
|
execution:
|
|
parent: entity
|
|
domain: cognition
|
|
layer: cognition
|
|
lifecycle: execution
|
|
description: An action the OS performed. Typed row in executions.
|
|
feedback:
|
|
parent: entity
|
|
domain: cognition
|
|
layer: cognition
|
|
description: What was learned from an execution. Typed row in feedback.
|
|
pattern:
|
|
parent: entity
|
|
domain: cognition
|
|
layer: cognition
|
|
lifecycle: pattern
|
|
description: Generalized rule extracted from feedback. Typed row in patterns.
|
|
skill:
|
|
parent: entity
|
|
domain: cognition
|
|
layer: cognition
|
|
lifecycle: skill
|
|
description: Codified, versioned procedure. Typed rows in skills.
|
|
approval:
|
|
parent: entity
|
|
domain: cognition
|
|
layer: cognition
|
|
lifecycle: approval
|
|
description: Operator approval request/decision. Typed row in approvals.
|
|
document:
|
|
parent: entity
|
|
domain: cognition
|
|
layer: cognition
|
|
description: Knowledge document ingested from docs/.
|
|
attributes:
|
|
type: object
|
|
properties: {title: {type: string}, source_path: {type: string}, content_hash: {type: string}}
|
|
runbook:
|
|
parent: entity
|
|
domain: cognition
|
|
layer: cognition
|
|
description: Step-by-step procedure for an entity/action.
|
|
attributes:
|
|
type: object
|
|
properties: {risk_class: {type: string}, source_path: {type: string}}
|
|
investigation:
|
|
parent: entity
|
|
domain: cognition
|
|
layer: cognition
|
|
description: Recorded investigation/postmortem.
|
|
task:
|
|
parent: entity
|
|
domain: cognition
|
|
layer: cognition
|
|
description: A goal-structured unit of agent work — one chat/session elevated
|
|
to a task with a plan, lifecycle status, and outcome. Anchors the knowledge
|
|
and involved-entity relationships for the task so future tasks can learn
|
|
from it. Typed rows in agent_sessions.
|
|
|
|
# ─── Relationship types ────────────────────────────────────────────────
|
|
# cardinality is source→target: e.g. `hosts` one-to-many = one machine
|
|
# hosts many compute entities; each hosted entity has one hosting machine.
|
|
|
|
relationship_types:
|
|
|
|
# Infrastructure topology
|
|
hosts:
|
|
inverse: runs-on
|
|
source: machine
|
|
target: compute-entity
|
|
cardinality: one-to-many
|
|
description: Machine hosts a VM/container (hubris hosts lxc:apps).
|
|
blast_direction: forward
|
|
runs-hypervisor:
|
|
inverse: hypervisor-on
|
|
source: machine
|
|
target: hypervisor
|
|
cardinality: one-to-one
|
|
description: Machine runs hypervisor software.
|
|
blast_direction: forward
|
|
member-of:
|
|
inverse: has-member
|
|
source: proxmox-host
|
|
target: cluster
|
|
cardinality: many-to-one
|
|
description: PVE host belongs to a cluster.
|
|
blast_direction: backward
|
|
part-of:
|
|
inverse: comprises
|
|
source: docker-container
|
|
target: compose-stack
|
|
cardinality: many-to-one
|
|
description: Docker container belongs to a compose stack.
|
|
blast_direction: backward
|
|
provides:
|
|
inverse: provided-by
|
|
source: compute-entity
|
|
target: service
|
|
cardinality: one-to-many
|
|
description: Compute entity provides a service (lxc:gitea provides service:gitea).
|
|
blast_direction: forward
|
|
runs:
|
|
inverse: run-by
|
|
source: service
|
|
target: application
|
|
cardinality: one-to-many
|
|
description: Service runs an application.
|
|
blast_direction: backward
|
|
configured-by:
|
|
inverse: configures
|
|
source: entity
|
|
target: config-repo
|
|
cardinality: many-to-one
|
|
description: Entity's config is tracked in a repo (mutations = commit+push).
|
|
deploys-to:
|
|
inverse: deployed-by
|
|
source: deploy-pipeline
|
|
target: entity
|
|
cardinality: many-to-one
|
|
description: Pipeline deploys to a service/host.
|
|
blast_direction: forward
|
|
routes-to:
|
|
inverse: routed-via
|
|
source: ingress-route
|
|
target: service
|
|
cardinality: many-to-one
|
|
description: Public hostname routes to a service.
|
|
blast_direction: backward
|
|
served-by:
|
|
inverse: serves
|
|
source: ingress-route
|
|
target: service
|
|
cardinality: many-to-one
|
|
description: Ingress route is terminated by this reverse proxy. Distinct
|
|
from routes-to, which names the BACKEND the route forwards to — without
|
|
this edge the proxy's blast radius is invisible, and lxc:caddy reported
|
|
one affected entity despite terminating every *.hubris.network route.
|
|
blast_direction: backward
|
|
secured-by:
|
|
inverse: secures
|
|
source: ingress-route
|
|
target: identity-provider
|
|
cardinality: many-to-one
|
|
description: Route gated by forward-auth.
|
|
blast_direction: backward
|
|
uses-certificate:
|
|
inverse: certifies
|
|
source: ingress-route
|
|
target: certificate
|
|
cardinality: many-to-one
|
|
description: Route served with this certificate.
|
|
blast_direction: backward
|
|
authenticates-via:
|
|
inverse: authenticates-service
|
|
source: service
|
|
target: identity-provider
|
|
cardinality: many-to-one
|
|
description: Service uses native OIDC (jellyfin authenticates-via authentik).
|
|
blast_direction: backward
|
|
in-zone:
|
|
inverse: contains-record
|
|
source: dns-record
|
|
target: dns-zone
|
|
cardinality: many-to-one
|
|
description: Record belongs to a zone.
|
|
blast_direction: backward
|
|
resolves-to:
|
|
inverse: resolved-from
|
|
source: dns-record
|
|
target: entity
|
|
cardinality: many-to-one
|
|
description: Record points at an ingress route or host.
|
|
depends-on:
|
|
inverse: dependency-of
|
|
source: service
|
|
target: service
|
|
cardinality: many-to-many
|
|
description: Runtime dependency (blast-radius edge).
|
|
blast_direction: backward
|
|
connects-via:
|
|
inverse: connects
|
|
source: compute-entity
|
|
target: network
|
|
cardinality: many-to-many
|
|
description: Coarse network membership (host on LAN / mesh).
|
|
blast_direction: backward
|
|
has-interface:
|
|
inverse: interface-of
|
|
source: compute-entity
|
|
target: network-interface
|
|
cardinality: one-to-many
|
|
description: Optional per-interface refinement.
|
|
blast_direction: backward
|
|
interface-on:
|
|
inverse: has-endpoint
|
|
source: network-interface
|
|
target: network
|
|
cardinality: many-to-one
|
|
description: Interface attaches to a network.
|
|
blast_direction: backward
|
|
|
|
# Storage
|
|
mounts:
|
|
inverse: mounted-by
|
|
source: compute-entity
|
|
target: volume
|
|
cardinality: many-to-many
|
|
description: Compute entity mounts a volume. Edge attributes carry
|
|
mount_point and options.
|
|
blast_direction: backward
|
|
stores-on:
|
|
inverse: stores-for
|
|
source: compute-entity
|
|
target: storage-pool
|
|
cardinality: many-to-many
|
|
description: Rootfs/data lives on a pool.
|
|
blast_direction: backward
|
|
contains:
|
|
inverse: contained-in
|
|
source: storage-pool
|
|
target: volume
|
|
cardinality: one-to-many
|
|
description: Pool contains a volume.
|
|
blast_direction: forward
|
|
holds-dataset:
|
|
inverse: dataset-on
|
|
source: volume
|
|
target: dataset
|
|
cardinality: one-to-many
|
|
description: Volume holds a tracked dataset.
|
|
blast_direction: backward
|
|
backs-up-to:
|
|
inverse: backup-of
|
|
source: entity
|
|
target: backup-target
|
|
cardinality: many-to-many
|
|
description: Entity's data is backed up to a target.
|
|
|
|
# Physical / external
|
|
powered-by:
|
|
inverse: powers
|
|
source: machine
|
|
target: ups
|
|
cardinality: many-to-one
|
|
description: Machine on UPS power.
|
|
blast_direction: backward
|
|
located-at:
|
|
inverse: location-of
|
|
source: machine
|
|
target: site
|
|
cardinality: many-to-one
|
|
description: Machine's physical site.
|
|
blast_direction: backward
|
|
registered-with:
|
|
inverse: registrar-of
|
|
source: domain-registration
|
|
target: vendor-dependency
|
|
cardinality: many-to-one
|
|
description: Domain registered with a registrar.
|
|
|
|
# Governance
|
|
owns:
|
|
inverse: owned-by
|
|
source: person
|
|
target: agent
|
|
cardinality: one-to-many
|
|
description: Person owns/controls an agent.
|
|
authenticates:
|
|
inverse: authenticated-by
|
|
source: identity-provider
|
|
target: person
|
|
cardinality: one-to-many
|
|
description: IdP authenticates a person.
|
|
holds-grant:
|
|
inverse: granted-to
|
|
source: agent
|
|
target: access-grant
|
|
cardinality: one-to-many
|
|
description: Agent holds an access grant.
|
|
grants:
|
|
inverse: granted-by
|
|
source: access-grant
|
|
target: secret
|
|
cardinality: many-to-one
|
|
description: Grant covers a secret.
|
|
blast_direction: forward
|
|
can-decrypt:
|
|
inverse: readable-by
|
|
source: compute-entity
|
|
target: secret
|
|
cardinality: many-to-many
|
|
description: Host can decrypt a secret (legacy SOPS; Infisical grants later).
|
|
blast_direction: backward
|
|
|
|
# Cognition
|
|
checks:
|
|
inverse: checked-by
|
|
source: check
|
|
target: entity
|
|
cardinality: many-to-one
|
|
description: Check probes an entity.
|
|
raises:
|
|
inverse: raised-by
|
|
source: check
|
|
target: signal
|
|
cardinality: one-to-many
|
|
description: Check raised a signal.
|
|
about:
|
|
inverse: subject-of
|
|
source: entity
|
|
target: entity
|
|
cardinality: many-to-many
|
|
description: Entity concerns (or is about) another entity.
|
|
classifies:
|
|
inverse: classified-as
|
|
source: classification
|
|
target: signal
|
|
cardinality: many-to-one
|
|
description: Classification of a signal.
|
|
precedes:
|
|
inverse: follows
|
|
source: classification
|
|
target: execution
|
|
cardinality: one-to-one
|
|
description: Classification that led to an execution.
|
|
targets:
|
|
inverse: targeted-by
|
|
source: execution
|
|
target: entity
|
|
cardinality: many-to-one
|
|
description: Execution acts on an entity.
|
|
requires-approval:
|
|
inverse: approves
|
|
source: execution
|
|
target: approval
|
|
cardinality: one-to-one
|
|
description: Execution gated by an approval.
|
|
performs:
|
|
inverse: performed-by
|
|
source: agent
|
|
target: execution
|
|
cardinality: one-to-many
|
|
description: Agent performed an execution.
|
|
decides:
|
|
inverse: decided-by
|
|
source: person
|
|
target: approval
|
|
cardinality: one-to-many
|
|
description: Person decided an approval.
|
|
produces:
|
|
inverse: produced-by
|
|
source: execution
|
|
target: feedback
|
|
cardinality: one-to-one
|
|
description: Execution produced feedback.
|
|
contributes-to:
|
|
inverse: built-from
|
|
source: feedback
|
|
target: pattern
|
|
cardinality: many-to-many
|
|
description: Feedback supports a pattern.
|
|
informs:
|
|
inverse: informed-by
|
|
source: pattern
|
|
target: skill
|
|
cardinality: many-to-one
|
|
description: Pattern informs a skill.
|
|
guides:
|
|
inverse: guided-by
|
|
source: skill
|
|
target: classification
|
|
cardinality: one-to-many
|
|
description: Skill guided a classification.
|
|
documents:
|
|
inverse: documented-by
|
|
source: document
|
|
target: entity
|
|
# many-to-many, not many-to-one: a single investigation routinely covers
|
|
# several entities (a fleet-wide apt audit documents every host it
|
|
# touched), and Nomos has been writing such edges for months. The stricter
|
|
# declaration made ~40 of them cardinality violations, which only surfaced
|
|
# once the seed could complete far enough to run ValidateCardinality.
|
|
cardinality: many-to-many
|
|
description: Document describes an entity.
|
|
involves:
|
|
inverse: involved-in
|
|
source: task
|
|
target: entity
|
|
cardinality: many-to-many
|
|
description: Task explored or acted on an entity (captured from its tool
|
|
calls). A task's involved-entity set is its graph neighborhood, so future
|
|
tasks on the same entities can surface this task's knowledge and outcome.
|
|
procedure-for:
|
|
inverse: has-procedure
|
|
source: runbook
|
|
target: entity
|
|
cardinality: many-to-many
|
|
description: Runbook applies to an entity.
|