{
  "available": true,
  "generatedAt": "2026-08-18T06:54:17.611Z",
  "runner": "scripts/jarvisos-discover.mjs",
  "snapshotDir": "/var/lib/jarvisos/discovery",
  "policy": {
    "authority": "VIN holds the estate's record. Every value in the catalogue carries the source that claimed it and the moment it was claimed; where sources disagree the higher-authority fresh claim is shown and the other is kept as a conflict, never deleted.",
    "freshness": "A source has a freshness budget. Inside it the claim is fresh; up to staleAfter times it, aging; beyond that, stale. A stale claim never overwrites a fresh one, whatever its authority. A source that has never run is missing, which is not the same statement as empty.",
    "homeAssistant": "Home Assistant is telemetry and action input only. It is declared telemetryOnly, the validator refuses to let it claim an identity field, and everything it does say is filed as advisory: displayable, never authoritative. An HA automation cannot rewrite the estate map.",
    "secrets": "No collector resolves a credential into argv and no snapshot contains one. Records are scrubbed at the reconciliation boundary: secret-named keys are dropped, token-shaped values are replaced, URL userinfo is stripped. Auth is recorded as a reference — a provider, a variable name and where that variable lives — and the validator refuses an auth block that carries a value.",
    "coverage": "A declared item names the sources that ought to see it. Without that, 'nobody reported it' proves nothing, and the catalogue says so rather than raising a fault it cannot justify.",
    "rollback": "Discovery is additive and read-only. Stop the timer, delete the snapshot directory, and the catalogue falls back to the declared inventory with every source reported missing. Nothing else in the console depends on it."
  },
  "summary": {
    "items": 26,
    "byKind": {
      "auth": 1,
      "database": 2,
      "dependency": 2,
      "dns": 2,
      "node": 5,
      "replica": 2,
      "service": 8,
      "storage": 2,
      "tunnel": 2
    },
    "byState": {
      "live": 0,
      "stale": 0,
      "declared-only": 25,
      "unknown": 1
    },
    "declared": 25,
    "undeclared": 0,
    "covered": 18,
    "uncovered": 7,
    "linkedToInventory": 20,
    "conflicts": 0,
    "sources": 11,
    "externalSources": 9,
    "freshSources": 0,
    "staleSources": 0,
    "missingSources": 9,
    "telemetryOnlySources": 1,
    "redactions": 0,
    "findings": {
      "crit": 0,
      "warn": 27,
      "info": 7
    }
  },
  "query": {},
  "matched": 26,
  "total": 26,
  "truncated": false,
  "facets": {
    "kind": [
      {
        "value": "service",
        "count": 8
      },
      {
        "value": "node",
        "count": 5
      },
      {
        "value": "database",
        "count": 2
      },
      {
        "value": "dependency",
        "count": 2
      },
      {
        "value": "dns",
        "count": 2
      },
      {
        "value": "replica",
        "count": 2
      },
      {
        "value": "storage",
        "count": 2
      },
      {
        "value": "tunnel",
        "count": 2
      },
      {
        "value": "auth",
        "count": 1
      }
    ],
    "node": [
      {
        "value": "vin",
        "count": 12
      },
      {
        "value": "home1",
        "count": 5
      },
      {
        "value": "nas",
        "count": 3
      },
      {
        "value": "gwscli-s3",
        "count": 2
      },
      {
        "value": "vps1",
        "count": 1
      }
    ],
    "project": [
      {
        "value": "platform",
        "count": 13
      },
      {
        "value": "jarvisos",
        "count": 7
      },
      {
        "value": "edge",
        "count": 2
      },
      {
        "value": "external",
        "count": 2
      },
      {
        "value": "media",
        "count": 1
      }
    ],
    "state": [
      {
        "value": "declared-only",
        "count": 25
      },
      {
        "value": "unknown",
        "count": 1
      }
    ],
    "source": []
  },
  "sources": [
    {
      "id": "inventory",
      "title": "Declared inventory",
      "adapter": "jarvisos-inventory",
      "internal": true,
      "transport": "internal",
      "runsOn": null,
      "telemetryOnly": false,
      "authority": 65,
      "claims": [],
      "reads": "config/inventory.json, already loaded by this process",
      "rollback": "not applicable — this is the declaration the rest of the console is built on",
      "credential": null,
      "freshness": "fresh",
      "collectedAt": null,
      "ageSec": 0,
      "maxAgeSec": 900,
      "ok": true,
      "error": null,
      "records": 20,
      "notes": []
    },
    {
      "id": "catalogue",
      "title": "Curated catalogue",
      "adapter": "jarvisos-catalogue",
      "internal": true,
      "transport": "internal",
      "runsOn": null,
      "telemetryOnly": false,
      "authority": 70,
      "claims": [],
      "reads": "the catalogue block of this file",
      "rollback": "not applicable — removing an entry only removes curated knowledge, never a discovered fact",
      "credential": null,
      "freshness": "fresh",
      "collectedAt": null,
      "ageSec": 0,
      "maxAgeSec": 900,
      "ok": true,
      "error": null,
      "records": 25,
      "notes": []
    },
    {
      "id": "tailscale-vin",
      "title": "Tailnet membership (VIN)",
      "adapter": "tailscale-status",
      "internal": false,
      "transport": "local",
      "runsOn": "vin",
      "telemetryOnly": false,
      "authority": 70,
      "claims": [
        "address",
        "addresses",
        "dnsName",
        "os",
        "runtime",
        "mesh",
        "lastSeenAt",
        "exitNode"
      ],
      "reads": "the local tailscaled status socket, read-only. Node keys are never requested.",
      "rollback": "stop running the collector and delete /var/lib/jarvisos/discovery/tailscale-vin.json",
      "credential": null,
      "freshness": "missing",
      "collectedAt": null,
      "ageSec": null,
      "maxAgeSec": 900,
      "ok": false,
      "error": null,
      "records": 0,
      "notes": []
    },
    {
      "id": "docker-vin",
      "title": "Docker containers (VIN)",
      "adapter": "docker-ps",
      "internal": false,
      "transport": "local",
      "runsOn": "vin",
      "telemetryOnly": false,
      "authority": 80,
      "claims": [
        "runtime",
        "runtimeDetail",
        "image",
        "ports",
        "healthCheck",
        "project",
        "domain",
        "tags",
        "restartPolicy"
      ],
      "reads": "the local Docker socket, read-only (docker ps). Container environments are never read.",
      "rollback": "stop running the collector and delete /var/lib/jarvisos/discovery/docker-vin.json",
      "credential": null,
      "freshness": "missing",
      "collectedAt": null,
      "ageSec": null,
      "maxAgeSec": 600,
      "ok": false,
      "error": null,
      "records": 0,
      "notes": []
    },
    {
      "id": "systemd-vin",
      "title": "systemd units (VIN)",
      "adapter": "systemd-units",
      "internal": false,
      "transport": "local",
      "runsOn": "vin",
      "telemetryOnly": false,
      "authority": 80,
      "claims": [
        "runtime",
        "runtimeDetail",
        "unit",
        "description"
      ],
      "reads": "systemctl list-units on the local host. No unit is started, stopped or inspected for its environment.",
      "rollback": "stop running the collector and delete /var/lib/jarvisos/discovery/systemd-vin.json",
      "credential": null,
      "freshness": "missing",
      "collectedAt": null,
      "ageSec": null,
      "maxAgeSec": 600,
      "ok": false,
      "error": null,
      "records": 0,
      "notes": []
    },
    {
      "id": "docker-home1",
      "title": "Docker containers (home1)",
      "adapter": "docker-ps",
      "internal": false,
      "transport": "local",
      "runsOn": "home1",
      "telemetryOnly": false,
      "authority": 80,
      "claims": [
        "runtime",
        "runtimeDetail",
        "image",
        "ports",
        "healthCheck",
        "project",
        "domain",
        "tags"
      ],
      "reads": "the Docker socket on home1, read-only, by the same runner running there",
      "rollback": "stop the timer on home1 and delete /var/lib/jarvisos/discovery/docker-home1.json here",
      "credential": null,
      "freshness": "missing",
      "collectedAt": null,
      "ageSec": null,
      "maxAgeSec": 3600,
      "ok": false,
      "error": null,
      "records": 0,
      "notes": []
    },
    {
      "id": "caddy-vin",
      "title": "Caddy ingress (VIN)",
      "adapter": "caddy-config",
      "internal": false,
      "transport": "http",
      "runsOn": "vin",
      "telemetryOnly": false,
      "authority": 85,
      "claims": [
        "ingress",
        "domain",
        "tls"
      ],
      "reads": "the Caddy admin API on loopback, GET /config/ only",
      "rollback": "stop running the collector and delete /var/lib/jarvisos/discovery/caddy-vin.json",
      "credential": null,
      "freshness": "missing",
      "collectedAt": null,
      "ageSec": null,
      "maxAgeSec": 900,
      "ok": false,
      "error": null,
      "records": 0,
      "notes": []
    },
    {
      "id": "coolify",
      "title": "Coolify applications",
      "adapter": "coolify-resources",
      "internal": false,
      "transport": "local",
      "runsOn": "vin",
      "telemetryOnly": false,
      "authority": 75,
      "claims": [
        "project",
        "environment",
        "runtime",
        "image",
        "domain",
        "managementUrl",
        "gitRepository",
        "gitBranch"
      ],
      "reads": "the Coolify read scope through the existing adapter, which resolves its own credential and never prints one",
      "rollback": "stop running the collector and delete /var/lib/jarvisos/discovery/coolify.json",
      "credential": null,
      "freshness": "missing",
      "collectedAt": null,
      "ageSec": null,
      "maxAgeSec": 3600,
      "ok": false,
      "error": null,
      "records": 0,
      "notes": []
    },
    {
      "id": "cloudflare-dns",
      "title": "Cloudflare DNS",
      "adapter": "cloudflare-dns",
      "internal": false,
      "transport": "http",
      "runsOn": null,
      "telemetryOnly": false,
      "authority": 85,
      "claims": [
        "domain",
        "dnsType",
        "dnsTarget",
        "proxied",
        "zone",
        "ttl"
      ],
      "reads": "the Cloudflare DNS records of the declared zone, read-only",
      "rollback": "revoke the read token and delete /var/lib/jarvisos/discovery/cloudflare-dns.json",
      "credential": {
        "name": "CLOUDFLARE_API_TOKEN",
        "location": "/var/lib/jarvisos/secrets/cloudflare-dns-read.token (0600), or the same variable in /etc/jarvisos/config.env"
      },
      "freshness": "missing",
      "collectedAt": null,
      "ageSec": null,
      "maxAgeSec": 21600,
      "ok": false,
      "error": null,
      "records": 0,
      "notes": []
    },
    {
      "id": "jarvisos-status",
      "title": "JarvisOS health",
      "adapter": "jarvisos-status",
      "internal": false,
      "transport": "http",
      "runsOn": "vin",
      "telemetryOnly": false,
      "authority": 60,
      "claims": [
        "health",
        "node"
      ],
      "reads": "this console's own status endpoint on loopback",
      "rollback": "stop running the collector and delete /var/lib/jarvisos/discovery/jarvisos-status.json",
      "credential": null,
      "freshness": "missing",
      "collectedAt": null,
      "ageSec": null,
      "maxAgeSec": 300,
      "ok": false,
      "error": null,
      "records": 0,
      "notes": []
    },
    {
      "id": "home-assistant",
      "title": "Home Assistant telemetry",
      "adapter": "home-assistant-states",
      "internal": false,
      "transport": "http",
      "runsOn": null,
      "telemetryOnly": true,
      "authority": 10,
      "claims": [
        "telemetry"
      ],
      "reads": "the Home Assistant states API, read-only, for the explicitly mapped entities only",
      "rollback": "revoke the long-lived token in Home Assistant and delete /var/lib/jarvisos/discovery/home-assistant.json",
      "credential": {
        "name": "HOME_ASSISTANT_TOKEN",
        "location": "/var/lib/jarvisos/secrets/home-assistant-read.token (0600)"
      },
      "freshness": "missing",
      "collectedAt": null,
      "ageSec": null,
      "maxAgeSec": 900,
      "ok": false,
      "error": null,
      "records": 0,
      "notes": []
    }
  ],
  "items": [
    {
      "id": "jarvisos-auth",
      "name": "JarvisOS Auth (SSO)",
      "kind": "auth",
      "entityId": "jarvisos-auth",
      "declared": true,
      "state": "declared-only",
      "freshness": "missing",
      "lastSeenAt": null,
      "node": "vin",
      "project": "jarvisos",
      "domains": [],
      "expect": [
        "systemd-vin",
        "docker-vin"
      ],
      "note": null,
      "links": {
        "node": "vin",
        "entity": "jarvisos-auth",
        "project": "jarvisos",
        "domains": [],
        "ingress": null,
        "auth": {
          "provider": "google-oauth",
          "entityId": "google-oauth",
          "method": "OAuth 2.0 authorization code",
          "secretName": "GOOGLE_CLIENT_SECRET",
          "location": "/etc/jarvisos/config.env on VIN"
        },
        "healthCheck": {
          "type": "http",
          "path": "/healthz",
          "expect": "200"
        },
        "dependsOn": [
          "vin",
          "google-oauth",
          "redis"
        ],
        "managementUrl": "/entity/jarvisos-auth",
        "recovery": {
          "runbook": "docs/RECOVERY.md#rb-jarvisos-auth",
          "note": "If this is down, every session-issuing surface is down. The break-glass path is in docs/CONTROL-PLANE-HA.md."
        }
      },
      "fields": {
        "kind": {
          "value": "auth",
          "merge": "value",
          "source": "catalogue",
          "sourceTitle": "Curated catalogue",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 70,
          "agreedBy": [
            "catalogue",
            "inventory"
          ],
          "conflicts": []
        },
        "node": {
          "value": "vin",
          "merge": "value",
          "source": "catalogue",
          "sourceTitle": "Curated catalogue",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 70,
          "agreedBy": [
            "catalogue",
            "inventory"
          ],
          "conflicts": []
        },
        "dependsOn": {
          "value": [
            "vin",
            "google-oauth",
            "redis"
          ],
          "merge": "union",
          "contributions": [
            {
              "value": "vin",
              "sources": [
                "inventory"
              ]
            },
            {
              "value": "google-oauth",
              "sources": [
                "inventory"
              ]
            },
            {
              "value": "redis",
              "sources": [
                "inventory"
              ]
            }
          ],
          "source": "inventory",
          "sourceTitle": "Declared inventory",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 65,
          "agreedBy": [
            "inventory"
          ],
          "conflicts": []
        },
        "tier": {
          "value": "critical",
          "merge": "value",
          "source": "inventory",
          "sourceTitle": "Declared inventory",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 65,
          "agreedBy": [
            "inventory"
          ],
          "conflicts": []
        },
        "description": {
          "value": "Session issuer and forward-auth endpoint for every published route.",
          "merge": "value",
          "source": "inventory",
          "sourceTitle": "Declared inventory",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 65,
          "agreedBy": [
            "inventory"
          ],
          "conflicts": []
        },
        "owner": {
          "value": "homelab-operator",
          "merge": "value",
          "source": "catalogue",
          "sourceTitle": "Curated catalogue",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 70,
          "agreedBy": [
            "catalogue",
            "inventory"
          ],
          "conflicts": []
        },
        "managementUrl": {
          "value": "/entity/jarvisos-auth",
          "merge": "value",
          "source": "inventory",
          "sourceTitle": "Declared inventory",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 65,
          "agreedBy": [
            "inventory"
          ],
          "conflicts": []
        },
        "project": {
          "value": "jarvisos",
          "merge": "value",
          "source": "catalogue",
          "sourceTitle": "Curated catalogue",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 70,
          "agreedBy": [
            "catalogue"
          ],
          "conflicts": []
        },
        "auth": {
          "value": {
            "provider": "google-oauth",
            "entityId": "google-oauth",
            "method": "OAuth 2.0 authorization code",
            "secretName": "GOOGLE_CLIENT_SECRET",
            "location": "/etc/jarvisos/config.env on VIN"
          },
          "merge": "value",
          "source": "catalogue",
          "sourceTitle": "Curated catalogue",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 70,
          "agreedBy": [
            "catalogue"
          ],
          "conflicts": []
        },
        "healthCheck": {
          "value": {
            "type": "http",
            "path": "/healthz",
            "expect": "200"
          },
          "merge": "value",
          "source": "catalogue",
          "sourceTitle": "Curated catalogue",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 70,
          "agreedBy": [
            "catalogue"
          ],
          "conflicts": []
        },
        "recovery": {
          "value": {
            "runbook": "docs/RECOVERY.md#rb-jarvisos-auth",
            "note": "If this is down, every session-issuing surface is down. The break-glass path is in docs/CONTROL-PLANE-HA.md."
          },
          "merge": "value",
          "source": "catalogue",
          "sourceTitle": "Curated catalogue",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 70,
          "agreedBy": [
            "catalogue"
          ],
          "conflicts": []
        }
      },
      "advisory": [],
      "sources": [],
      "conflicts": [],
      "redactions": 0
    },
    {
      "id": "postgres-primary",
      "name": "Postgres (primary)",
      "kind": "database",
      "entityId": "postgres-primary",
      "declared": true,
      "state": "declared-only",
      "freshness": "missing",
      "lastSeenAt": null,
      "node": "home1",
      "project": "platform",
      "domains": [],
      "expect": [
        "docker-home1"
      ],
      "note": null,
      "links": {
        "node": "home1",
        "entity": "postgres-primary",
        "project": "platform",
        "domains": [],
        "ingress": null,
        "auth": {
          "provider": "postgres",
          "method": "password authentication over the WireGuard link",
          "secretName": "POSTGRES_PASSWORD",
          "location": "/etc/jarvisos/config.env on home1"
        },
        "healthCheck": {
          "type": "tcp",
          "ports": [
            5432
          ]
        },
        "dependsOn": [
          "home1"
        ],
        "managementUrl": "/entity/postgres-primary",
        "recovery": {
          "runbook": "docs/RECOVERY.md#rb-postgres-primary"
        }
      },
      "fields": {
        "kind": {
          "value": "database",
          "merge": "value",
          "source": "catalogue",
          "sourceTitle": "Curated catalogue",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 70,
          "agreedBy": [
            "catalogue",
            "inventory"
          ],
          "conflicts": []
        },
        "node": {
          "value": "home1",
          "merge": "value",
          "source": "catalogue",
          "sourceTitle": "Curated catalogue",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 70,
          "agreedBy": [
            "catalogue",
            "inventory"
          ],
          "conflicts": []
        },
        "dependsOn": {
          "value": [
            "home1"
          ],
          "merge": "union",
          "contributions": [
            {
              "value": "home1",
              "sources": [
                "inventory"
              ]
            }
          ],
          "source": "inventory",
          "sourceTitle": "Declared inventory",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 65,
          "agreedBy": [
            "inventory"
          ],
          "conflicts": []
        },
        "tier": {
          "value": "critical",
          "merge": "value",
          "source": "inventory",
          "sourceTitle": "Declared inventory",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 65,
          "agreedBy": [
            "inventory"
          ],
          "conflicts": []
        },
        "description": {
          "value": "System of record for control plane state, task history and workspace metadata.",
          "merge": "value",
          "source": "inventory",
          "sourceTitle": "Declared inventory",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 65,
          "agreedBy": [
            "inventory"
          ],
          "conflicts": []
        },
        "owner": {
          "value": "homelab-operator",
          "merge": "value",
          "source": "catalogue",
          "sourceTitle": "Curated catalogue",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 70,
          "agreedBy": [
            "catalogue",
            "inventory"
          ],
          "conflicts": []
        },
        "managementUrl": {
          "value": "/entity/postgres-primary",
          "merge": "value",
          "source": "inventory",
          "sourceTitle": "Declared inventory",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 65,
          "agreedBy": [
            "inventory"
          ],
          "conflicts": []
        },
        "project": {
          "value": "platform",
          "merge": "value",
          "source": "catalogue",
          "sourceTitle": "Curated catalogue",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 70,
          "agreedBy": [
            "catalogue"
          ],
          "conflicts": []
        },
        "auth": {
          "value": {
            "provider": "postgres",
            "method": "password authentication over the WireGuard link",
            "secretName": "POSTGRES_PASSWORD",
            "location": "/etc/jarvisos/config.env on home1"
          },
          "merge": "value",
          "source": "catalogue",
          "sourceTitle": "Curated catalogue",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 70,
          "agreedBy": [
            "catalogue"
          ],
          "conflicts": []
        },
        "healthCheck": {
          "value": {
            "type": "tcp",
            "ports": [
              5432
            ]
          },
          "merge": "value",
          "source": "catalogue",
          "sourceTitle": "Curated catalogue",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 70,
          "agreedBy": [
            "catalogue"
          ],
          "conflicts": []
        },
        "recovery": {
          "value": {
            "runbook": "docs/RECOVERY.md#rb-postgres-primary"
          },
          "merge": "value",
          "source": "catalogue",
          "sourceTitle": "Curated catalogue",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 70,
          "agreedBy": [
            "catalogue"
          ],
          "conflicts": []
        }
      },
      "advisory": [],
      "sources": [],
      "conflicts": [],
      "redactions": 0
    },
    {
      "id": "redis",
      "name": "Redis (cache / queue)",
      "kind": "database",
      "entityId": "redis",
      "declared": true,
      "state": "declared-only",
      "freshness": "missing",
      "lastSeenAt": null,
      "node": "home1",
      "project": "platform",
      "domains": [],
      "expect": [
        "docker-home1"
      ],
      "note": null,
      "links": {
        "node": "home1",
        "entity": "redis",
        "project": "platform",
        "domains": [],
        "ingress": null,
        "auth": null,
        "healthCheck": {
          "type": "tcp",
          "ports": [
            6379
          ]
        },
        "dependsOn": [
          "home1"
        ],
        "managementUrl": "/entity/redis",
        "recovery": {
          "runbook": "docs/RECOVERY.md#rb-redis"
        }
      },
      "fields": {
        "kind": {
          "value": "database",
          "merge": "value",
          "source": "catalogue",
          "sourceTitle": "Curated catalogue",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 70,
          "agreedBy": [
            "catalogue",
            "inventory"
          ],
          "conflicts": []
        },
        "node": {
          "value": "home1",
          "merge": "value",
          "source": "catalogue",
          "sourceTitle": "Curated catalogue",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 70,
          "agreedBy": [
            "catalogue",
            "inventory"
          ],
          "conflicts": []
        },
        "dependsOn": {
          "value": [
            "home1"
          ],
          "merge": "union",
          "contributions": [
            {
              "value": "home1",
              "sources": [
                "inventory"
              ]
            }
          ],
          "source": "inventory",
          "sourceTitle": "Declared inventory",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 65,
          "agreedBy": [
            "inventory"
          ],
          "conflicts": []
        },
        "tier": {
          "value": "important",
          "merge": "value",
          "source": "inventory",
          "sourceTitle": "Declared inventory",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 65,
          "agreedBy": [
            "inventory"
          ],
          "conflicts": []
        },
        "description": {
          "value": "Task queue and ephemeral cache. Data here is rebuildable.",
          "merge": "value",
          "source": "inventory",
          "sourceTitle": "Declared inventory",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 65,
          "agreedBy": [
            "inventory"
          ],
          "conflicts": []
        },
        "owner": {
          "value": "homelab-operator",
          "merge": "value",
          "source": "inventory",
          "sourceTitle": "Declared inventory",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 65,
          "agreedBy": [
            "inventory"
          ],
          "conflicts": []
        },
        "managementUrl": {
          "value": "/entity/redis",
          "merge": "value",
          "source": "inventory",
          "sourceTitle": "Declared inventory",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 65,
          "agreedBy": [
            "inventory"
          ],
          "conflicts": []
        },
        "project": {
          "value": "platform",
          "merge": "value",
          "source": "catalogue",
          "sourceTitle": "Curated catalogue",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 70,
          "agreedBy": [
            "catalogue"
          ],
          "conflicts": []
        },
        "healthCheck": {
          "value": {
            "type": "tcp",
            "ports": [
              6379
            ]
          },
          "merge": "value",
          "source": "catalogue",
          "sourceTitle": "Curated catalogue",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 70,
          "agreedBy": [
            "catalogue"
          ],
          "conflicts": []
        },
        "recovery": {
          "value": {
            "runbook": "docs/RECOVERY.md#rb-redis"
          },
          "merge": "value",
          "source": "catalogue",
          "sourceTitle": "Curated catalogue",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 70,
          "agreedBy": [
            "catalogue"
          ],
          "conflicts": []
        }
      },
      "advisory": [],
      "sources": [],
      "conflicts": [],
      "redactions": 0
    },
    {
      "id": "google-oauth",
      "name": "Google OAuth",
      "kind": "dependency",
      "entityId": "google-oauth",
      "declared": true,
      "state": "declared-only",
      "freshness": "missing",
      "lastSeenAt": null,
      "node": null,
      "project": "external",
      "domains": [],
      "expect": [],
      "note": null,
      "links": {
        "node": null,
        "entity": "google-oauth",
        "project": "external",
        "domains": [],
        "ingress": null,
        "auth": {
          "provider": "google",
          "method": "OAuth 2.0 client",
          "secretName": "GOOGLE_CLIENT_SECRET",
          "location": "/etc/jarvisos/config.env on VIN"
        },
        "healthCheck": null,
        "dependsOn": [
          "isp-uplink"
        ],
        "managementUrl": "/entity/google-oauth",
        "recovery": {
          "runbook": "docs/RECOVERY.md#rb-google-oauth",
          "note": "Outside operator control; nothing here can discover it."
        }
      },
      "fields": {
        "kind": {
          "value": "dependency",
          "merge": "value",
          "source": "catalogue",
          "sourceTitle": "Curated catalogue",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 70,
          "agreedBy": [
            "catalogue",
            "inventory"
          ],
          "conflicts": []
        },
        "dependsOn": {
          "value": [
            "isp-uplink"
          ],
          "merge": "union",
          "contributions": [
            {
              "value": "isp-uplink",
              "sources": [
                "inventory"
              ]
            }
          ],
          "source": "inventory",
          "sourceTitle": "Declared inventory",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 65,
          "agreedBy": [
            "inventory"
          ],
          "conflicts": []
        },
        "tier": {
          "value": "critical",
          "merge": "value",
          "source": "inventory",
          "sourceTitle": "Declared inventory",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 65,
          "agreedBy": [
            "inventory"
          ],
          "conflicts": []
        },
        "description": {
          "value": "Upstream identity provider. Outside operator control.",
          "merge": "value",
          "source": "inventory",
          "sourceTitle": "Declared inventory",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 65,
          "agreedBy": [
            "inventory"
          ],
          "conflicts": []
        },
        "owner": {
          "value": "vendor",
          "merge": "value",
          "source": "inventory",
          "sourceTitle": "Declared inventory",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 65,
          "agreedBy": [
            "inventory"
          ],
          "conflicts": []
        },
        "managementUrl": {
          "value": "/entity/google-oauth",
          "merge": "value",
          "source": "inventory",
          "sourceTitle": "Declared inventory",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 65,
          "agreedBy": [
            "inventory"
          ],
          "conflicts": []
        },
        "project": {
          "value": "external",
          "merge": "value",
          "source": "catalogue",
          "sourceTitle": "Curated catalogue",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 70,
          "agreedBy": [
            "catalogue"
          ],
          "conflicts": []
        },
        "auth": {
          "value": {
            "provider": "google",
            "method": "OAuth 2.0 client",
            "secretName": "GOOGLE_CLIENT_SECRET",
            "location": "/etc/jarvisos/config.env on VIN"
          },
          "merge": "value",
          "source": "catalogue",
          "sourceTitle": "Curated catalogue",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 70,
          "agreedBy": [
            "catalogue"
          ],
          "conflicts": []
        },
        "recovery": {
          "value": {
            "runbook": "docs/RECOVERY.md#rb-google-oauth",
            "note": "Outside operator control; nothing here can discover it."
          },
          "merge": "value",
          "source": "catalogue",
          "sourceTitle": "Curated catalogue",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 70,
          "agreedBy": [
            "catalogue"
          ],
          "conflicts": []
        }
      },
      "advisory": [],
      "sources": [],
      "conflicts": [],
      "redactions": 0
    },
    {
      "id": "isp-uplink",
      "name": "ISP Uplink",
      "kind": "dependency",
      "entityId": "isp-uplink",
      "declared": true,
      "state": "declared-only",
      "freshness": "missing",
      "lastSeenAt": null,
      "node": null,
      "project": "external",
      "domains": [],
      "expect": [],
      "note": null,
      "links": {
        "node": null,
        "entity": "isp-uplink",
        "project": "external",
        "domains": [],
        "ingress": null,
        "auth": null,
        "healthCheck": null,
        "dependsOn": [],
        "managementUrl": "/entity/isp-uplink",
        "recovery": {
          "runbook": "docs/RECOVERY.md#rb-isp-uplink",
          "note": "Outside operator control."
        }
      },
      "fields": {
        "kind": {
          "value": "dependency",
          "merge": "value",
          "source": "catalogue",
          "sourceTitle": "Curated catalogue",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 70,
          "agreedBy": [
            "catalogue",
            "inventory"
          ],
          "conflicts": []
        },
        "tier": {
          "value": "critical",
          "merge": "value",
          "source": "inventory",
          "sourceTitle": "Declared inventory",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 65,
          "agreedBy": [
            "inventory"
          ],
          "conflicts": []
        },
        "description": {
          "value": "Home internet connectivity. Everything at the home rack depends on it being up.",
          "merge": "value",
          "source": "inventory",
          "sourceTitle": "Declared inventory",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 65,
          "agreedBy": [
            "inventory"
          ],
          "conflicts": []
        },
        "owner": {
          "value": "vendor",
          "merge": "value",
          "source": "inventory",
          "sourceTitle": "Declared inventory",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 65,
          "agreedBy": [
            "inventory"
          ],
          "conflicts": []
        },
        "managementUrl": {
          "value": "/entity/isp-uplink",
          "merge": "value",
          "source": "inventory",
          "sourceTitle": "Declared inventory",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 65,
          "agreedBy": [
            "inventory"
          ],
          "conflicts": []
        },
        "project": {
          "value": "external",
          "merge": "value",
          "source": "catalogue",
          "sourceTitle": "Curated catalogue",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 70,
          "agreedBy": [
            "catalogue"
          ],
          "conflicts": []
        },
        "recovery": {
          "value": {
            "runbook": "docs/RECOVERY.md#rb-isp-uplink",
            "note": "Outside operator control."
          },
          "merge": "value",
          "source": "catalogue",
          "sourceTitle": "Curated catalogue",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 70,
          "agreedBy": [
            "catalogue"
          ],
          "conflicts": []
        }
      },
      "advisory": [],
      "sources": [],
      "conflicts": [],
      "redactions": 0
    },
    {
      "id": "internal-dns",
      "name": "Internal DNS",
      "kind": "dns",
      "entityId": "internal-dns",
      "declared": true,
      "state": "declared-only",
      "freshness": "missing",
      "lastSeenAt": null,
      "node": "home1",
      "project": "platform",
      "domains": [],
      "expect": [
        "docker-home1"
      ],
      "note": null,
      "links": {
        "node": "home1",
        "entity": "internal-dns",
        "project": "platform",
        "domains": [],
        "ingress": null,
        "auth": null,
        "healthCheck": null,
        "dependsOn": [
          "home1"
        ],
        "managementUrl": "/entity/internal-dns",
        "recovery": {
          "runbook": "docs/RECOVERY.md#rb-internal-dns"
        }
      },
      "fields": {
        "kind": {
          "value": "dns",
          "merge": "value",
          "source": "catalogue",
          "sourceTitle": "Curated catalogue",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 70,
          "agreedBy": [
            "catalogue",
            "inventory"
          ],
          "conflicts": []
        },
        "node": {
          "value": "home1",
          "merge": "value",
          "source": "catalogue",
          "sourceTitle": "Curated catalogue",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 70,
          "agreedBy": [
            "catalogue",
            "inventory"
          ],
          "conflicts": []
        },
        "dependsOn": {
          "value": [
            "home1"
          ],
          "merge": "union",
          "contributions": [
            {
              "value": "home1",
              "sources": [
                "inventory"
              ]
            }
          ],
          "source": "inventory",
          "sourceTitle": "Declared inventory",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 65,
          "agreedBy": [
            "inventory"
          ],
          "conflicts": []
        },
        "tier": {
          "value": "important",
          "merge": "value",
          "source": "inventory",
          "sourceTitle": "Declared inventory",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 65,
          "agreedBy": [
            "inventory"
          ],
          "conflicts": []
        },
        "description": {
          "value": "Resolves 10.10.0.0/24 names for LAN services.",
          "merge": "value",
          "source": "inventory",
          "sourceTitle": "Declared inventory",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 65,
          "agreedBy": [
            "inventory"
          ],
          "conflicts": []
        },
        "owner": {
          "value": "homelab-operator",
          "merge": "value",
          "source": "inventory",
          "sourceTitle": "Declared inventory",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 65,
          "agreedBy": [
            "inventory"
          ],
          "conflicts": []
        },
        "managementUrl": {
          "value": "/entity/internal-dns",
          "merge": "value",
          "source": "inventory",
          "sourceTitle": "Declared inventory",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 65,
          "agreedBy": [
            "inventory"
          ],
          "conflicts": []
        },
        "project": {
          "value": "platform",
          "merge": "value",
          "source": "catalogue",
          "sourceTitle": "Curated catalogue",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 70,
          "agreedBy": [
            "catalogue"
          ],
          "conflicts": []
        },
        "recovery": {
          "value": {
            "runbook": "docs/RECOVERY.md#rb-internal-dns"
          },
          "merge": "value",
          "source": "catalogue",
          "sourceTitle": "Curated catalogue",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 70,
          "agreedBy": [
            "catalogue"
          ],
          "conflicts": []
        }
      },
      "advisory": [],
      "sources": [],
      "conflicts": [],
      "redactions": 0
    },
    {
      "id": "cloudflare-dns",
      "name": "Public DNS",
      "kind": "dns",
      "entityId": "cloudflare-dns",
      "declared": true,
      "state": "declared-only",
      "freshness": "missing",
      "lastSeenAt": null,
      "node": null,
      "project": "edge",
      "domains": [],
      "expect": [
        "cloudflare-dns"
      ],
      "note": null,
      "links": {
        "node": null,
        "entity": "cloudflare-dns",
        "project": "edge",
        "domains": [],
        "ingress": null,
        "auth": {
          "provider": "cloudflare",
          "method": "scoped API token",
          "secretName": "CLOUDFLARE_API_TOKEN",
          "location": "/var/lib/jarvisos/secrets/cloudflare-dns-read.token"
        },
        "healthCheck": null,
        "dependsOn": [
          "isp-uplink"
        ],
        "managementUrl": "https://dash.cloudflare.com/",
        "recovery": {
          "runbook": "docs/RECOVERY.md#rb-cloudflare-dns"
        }
      },
      "fields": {
        "kind": {
          "value": "dns",
          "merge": "value",
          "source": "catalogue",
          "sourceTitle": "Curated catalogue",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 70,
          "agreedBy": [
            "catalogue",
            "inventory"
          ],
          "conflicts": []
        },
        "dependsOn": {
          "value": [
            "isp-uplink"
          ],
          "merge": "union",
          "contributions": [
            {
              "value": "isp-uplink",
              "sources": [
                "inventory"
              ]
            }
          ],
          "source": "inventory",
          "sourceTitle": "Declared inventory",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 65,
          "agreedBy": [
            "inventory"
          ],
          "conflicts": []
        },
        "tier": {
          "value": "critical",
          "merge": "value",
          "source": "inventory",
          "sourceTitle": "Declared inventory",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 65,
          "agreedBy": [
            "inventory"
          ],
          "conflicts": []
        },
        "description": {
          "value": "Authoritative public DNS. Controls whether published routes resolve at all.",
          "merge": "value",
          "source": "inventory",
          "sourceTitle": "Declared inventory",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 65,
          "agreedBy": [
            "inventory"
          ],
          "conflicts": []
        },
        "owner": {
          "value": "homelab-operator",
          "merge": "value",
          "source": "inventory",
          "sourceTitle": "Declared inventory",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 65,
          "agreedBy": [
            "inventory"
          ],
          "conflicts": []
        },
        "project": {
          "value": "edge",
          "merge": "value",
          "source": "catalogue",
          "sourceTitle": "Curated catalogue",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 70,
          "agreedBy": [
            "catalogue"
          ],
          "conflicts": []
        },
        "auth": {
          "value": {
            "provider": "cloudflare",
            "method": "scoped API token",
            "secretName": "CLOUDFLARE_API_TOKEN",
            "location": "/var/lib/jarvisos/secrets/cloudflare-dns-read.token"
          },
          "merge": "value",
          "source": "catalogue",
          "sourceTitle": "Curated catalogue",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 70,
          "agreedBy": [
            "catalogue"
          ],
          "conflicts": []
        },
        "managementUrl": {
          "value": "https://dash.cloudflare.com/",
          "merge": "value",
          "source": "catalogue",
          "sourceTitle": "Curated catalogue",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 70,
          "agreedBy": [
            "catalogue"
          ],
          "conflicts": []
        },
        "recovery": {
          "value": {
            "runbook": "docs/RECOVERY.md#rb-cloudflare-dns"
          },
          "merge": "value",
          "source": "catalogue",
          "sourceTitle": "Curated catalogue",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 70,
          "agreedBy": [
            "catalogue"
          ],
          "conflicts": []
        }
      },
      "advisory": [],
      "sources": [],
      "conflicts": [],
      "redactions": 0
    },
    {
      "id": "gwscli-s3",
      "name": "GWSCLI / S3",
      "kind": "node",
      "entityId": "gwscli-s3",
      "declared": true,
      "state": "declared-only",
      "freshness": "missing",
      "lastSeenAt": null,
      "node": "gwscli-s3",
      "project": "platform",
      "domains": [],
      "expect": [],
      "note": null,
      "links": {
        "node": "gwscli-s3",
        "entity": "gwscli-s3",
        "project": "platform",
        "domains": [],
        "ingress": null,
        "auth": null,
        "healthCheck": null,
        "dependsOn": [],
        "managementUrl": "/entity/gwscli-s3",
        "recovery": {
          "runbook": "docs/RECOVERY.md#rb-gwscli-s3",
          "note": "Offsite object storage. Third-party surface: nothing here can enumerate it."
        }
      },
      "fields": {
        "kind": {
          "value": "node",
          "merge": "value",
          "source": "catalogue",
          "sourceTitle": "Curated catalogue",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 70,
          "agreedBy": [
            "catalogue",
            "inventory"
          ],
          "conflicts": []
        },
        "tier": {
          "value": "important",
          "merge": "value",
          "source": "inventory",
          "sourceTitle": "Declared inventory",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 65,
          "agreedBy": [
            "inventory"
          ],
          "conflicts": []
        },
        "description": {
          "value": "Offsite object storage. Last line of defence for backups; the only copy that survives loss of the home rack.",
          "merge": "value",
          "source": "inventory",
          "sourceTitle": "Declared inventory",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 65,
          "agreedBy": [
            "inventory"
          ],
          "conflicts": []
        },
        "owner": {
          "value": "homelab-operator",
          "merge": "value",
          "source": "inventory",
          "sourceTitle": "Declared inventory",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 65,
          "agreedBy": [
            "inventory"
          ],
          "conflicts": []
        },
        "managementUrl": {
          "value": "/entity/gwscli-s3",
          "merge": "value",
          "source": "inventory",
          "sourceTitle": "Declared inventory",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 65,
          "agreedBy": [
            "inventory"
          ],
          "conflicts": []
        },
        "project": {
          "value": "platform",
          "merge": "value",
          "source": "catalogue",
          "sourceTitle": "Curated catalogue",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 70,
          "agreedBy": [
            "catalogue"
          ],
          "conflicts": []
        },
        "recovery": {
          "value": {
            "runbook": "docs/RECOVERY.md#rb-gwscli-s3",
            "note": "Offsite object storage. Third-party surface: nothing here can enumerate it."
          },
          "merge": "value",
          "source": "catalogue",
          "sourceTitle": "Curated catalogue",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 70,
          "agreedBy": [
            "catalogue"
          ],
          "conflicts": []
        }
      },
      "advisory": [],
      "sources": [],
      "conflicts": [],
      "redactions": 0
    },
    {
      "id": "home1",
      "name": "Home1",
      "kind": "node",
      "entityId": "home1",
      "declared": true,
      "state": "declared-only",
      "freshness": "missing",
      "lastSeenAt": null,
      "node": "home1",
      "project": "platform",
      "domains": [],
      "expect": [
        "tailscale-vin"
      ],
      "note": null,
      "links": {
        "node": "home1",
        "entity": "home1",
        "project": "platform",
        "domains": [],
        "ingress": null,
        "auth": null,
        "healthCheck": null,
        "dependsOn": [],
        "managementUrl": "/entity/home1",
        "recovery": {
          "runbook": "docs/RECOVERY.md#rb-home1",
          "note": "Primary compute. Losing it moves the control plane to VIN; see docs/CONTROL-PLANE-HA.md."
        }
      },
      "fields": {
        "kind": {
          "value": "node",
          "merge": "value",
          "source": "catalogue",
          "sourceTitle": "Curated catalogue",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 70,
          "agreedBy": [
            "catalogue",
            "inventory"
          ],
          "conflicts": []
        },
        "address": {
          "value": "uk-james-home1.tail99ba7.ts.net",
          "merge": "value",
          "source": "inventory",
          "sourceTitle": "Declared inventory",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 65,
          "agreedBy": [
            "inventory"
          ],
          "conflicts": []
        },
        "tier": {
          "value": "critical",
          "merge": "value",
          "source": "inventory",
          "sourceTitle": "Declared inventory",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 65,
          "agreedBy": [
            "inventory"
          ],
          "conflicts": []
        },
        "description": {
          "value": "Primary home compute node. Runs the JarvisOS control plane, the Postgres primary and internal DNS.",
          "merge": "value",
          "source": "inventory",
          "sourceTitle": "Declared inventory",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 65,
          "agreedBy": [
            "inventory"
          ],
          "conflicts": []
        },
        "owner": {
          "value": "homelab-operator",
          "merge": "value",
          "source": "catalogue",
          "sourceTitle": "Curated catalogue",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 70,
          "agreedBy": [
            "catalogue",
            "inventory"
          ],
          "conflicts": []
        },
        "node": {
          "value": "home1",
          "merge": "value",
          "source": "catalogue",
          "sourceTitle": "Curated catalogue",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 70,
          "agreedBy": [
            "catalogue"
          ],
          "conflicts": []
        },
        "project": {
          "value": "platform",
          "merge": "value",
          "source": "catalogue",
          "sourceTitle": "Curated catalogue",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 70,
          "agreedBy": [
            "catalogue"
          ],
          "conflicts": []
        },
        "managementUrl": {
          "value": "/entity/home1",
          "merge": "value",
          "source": "catalogue",
          "sourceTitle": "Curated catalogue",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 70,
          "agreedBy": [
            "catalogue"
          ],
          "conflicts": []
        },
        "recovery": {
          "value": {
            "runbook": "docs/RECOVERY.md#rb-home1",
            "note": "Primary compute. Losing it moves the control plane to VIN; see docs/CONTROL-PLANE-HA.md."
          },
          "merge": "value",
          "source": "catalogue",
          "sourceTitle": "Curated catalogue",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 70,
          "agreedBy": [
            "catalogue"
          ],
          "conflicts": []
        }
      },
      "advisory": [],
      "sources": [],
      "conflicts": [],
      "redactions": 0
    },
    {
      "id": "nas",
      "name": "NAS",
      "kind": "node",
      "entityId": "nas",
      "declared": true,
      "state": "declared-only",
      "freshness": "missing",
      "lastSeenAt": null,
      "node": "nas",
      "project": "platform",
      "domains": [],
      "expect": [],
      "note": null,
      "links": {
        "node": "nas",
        "entity": "nas",
        "project": "platform",
        "domains": [],
        "ingress": null,
        "auth": null,
        "healthCheck": null,
        "dependsOn": [],
        "managementUrl": "/entity/nas",
        "recovery": {
          "runbook": "docs/RECOVERY.md#rb-nas",
          "note": "Not on the tailnet and running no collector, so the catalogue tracks it by declaration only."
        }
      },
      "fields": {
        "kind": {
          "value": "node",
          "merge": "value",
          "source": "catalogue",
          "sourceTitle": "Curated catalogue",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 70,
          "agreedBy": [
            "catalogue",
            "inventory"
          ],
          "conflicts": []
        },
        "address": {
          "value": "10.10.0.20",
          "merge": "value",
          "source": "inventory",
          "sourceTitle": "Declared inventory",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 65,
          "agreedBy": [
            "inventory"
          ],
          "conflicts": []
        },
        "tier": {
          "value": "critical",
          "merge": "value",
          "source": "inventory",
          "sourceTitle": "Declared inventory",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 65,
          "agreedBy": [
            "inventory"
          ],
          "conflicts": []
        },
        "description": {
          "value": "Bulk storage node. Backing store for media, on-site backups and the offsite sync staging area.",
          "merge": "value",
          "source": "inventory",
          "sourceTitle": "Declared inventory",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 65,
          "agreedBy": [
            "inventory"
          ],
          "conflicts": []
        },
        "owner": {
          "value": "homelab-operator",
          "merge": "value",
          "source": "catalogue",
          "sourceTitle": "Curated catalogue",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 70,
          "agreedBy": [
            "catalogue",
            "inventory"
          ],
          "conflicts": []
        },
        "managementUrl": {
          "value": "/entity/nas",
          "merge": "value",
          "source": "inventory",
          "sourceTitle": "Declared inventory",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 65,
          "agreedBy": [
            "inventory"
          ],
          "conflicts": []
        },
        "node": {
          "value": "nas",
          "merge": "value",
          "source": "catalogue",
          "sourceTitle": "Curated catalogue",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 70,
          "agreedBy": [
            "catalogue"
          ],
          "conflicts": []
        },
        "project": {
          "value": "platform",
          "merge": "value",
          "source": "catalogue",
          "sourceTitle": "Curated catalogue",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 70,
          "agreedBy": [
            "catalogue"
          ],
          "conflicts": []
        },
        "recovery": {
          "value": {
            "runbook": "docs/RECOVERY.md#rb-nas",
            "note": "Not on the tailnet and running no collector, so the catalogue tracks it by declaration only."
          },
          "merge": "value",
          "source": "catalogue",
          "sourceTitle": "Curated catalogue",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 70,
          "agreedBy": [
            "catalogue"
          ],
          "conflicts": []
        }
      },
      "advisory": [],
      "sources": [],
      "conflicts": [],
      "redactions": 0
    },
    {
      "id": "vin",
      "name": "VIN / VPS",
      "kind": "node",
      "entityId": "vin",
      "declared": true,
      "state": "declared-only",
      "freshness": "missing",
      "lastSeenAt": null,
      "node": "vin",
      "project": "platform",
      "domains": [],
      "expect": [
        "tailscale-vin"
      ],
      "note": null,
      "links": {
        "node": "vin",
        "entity": "vin",
        "project": "platform",
        "domains": [],
        "ingress": null,
        "auth": null,
        "healthCheck": null,
        "dependsOn": [],
        "managementUrl": "/entity/vin",
        "recovery": {
          "runbook": "docs/RECOVERY.md#rb-vin",
          "note": "Public edge and the node this console runs on. It is the authority for the catalogue itself."
        }
      },
      "fields": {
        "kind": {
          "value": "node",
          "merge": "value",
          "source": "catalogue",
          "sourceTitle": "Curated catalogue",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 70,
          "agreedBy": [
            "catalogue",
            "inventory"
          ],
          "conflicts": []
        },
        "address": {
          "value": "127.0.0.1",
          "merge": "value",
          "source": "inventory",
          "sourceTitle": "Declared inventory",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 65,
          "agreedBy": [
            "inventory"
          ],
          "conflicts": []
        },
        "tier": {
          "value": "critical",
          "merge": "value",
          "source": "inventory",
          "sourceTitle": "Declared inventory",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 65,
          "agreedBy": [
            "inventory"
          ],
          "conflicts": []
        },
        "description": {
          "value": "Public edge node. Terminates TLS via Caddy, hosts the tunnel endpoint and the warm standby control plane.",
          "merge": "value",
          "source": "inventory",
          "sourceTitle": "Declared inventory",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 65,
          "agreedBy": [
            "inventory"
          ],
          "conflicts": []
        },
        "owner": {
          "value": "homelab-operator",
          "merge": "value",
          "source": "catalogue",
          "sourceTitle": "Curated catalogue",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 70,
          "agreedBy": [
            "catalogue",
            "inventory"
          ],
          "conflicts": []
        },
        "node": {
          "value": "vin",
          "merge": "value",
          "source": "catalogue",
          "sourceTitle": "Curated catalogue",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 70,
          "agreedBy": [
            "catalogue"
          ],
          "conflicts": []
        },
        "project": {
          "value": "platform",
          "merge": "value",
          "source": "catalogue",
          "sourceTitle": "Curated catalogue",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 70,
          "agreedBy": [
            "catalogue"
          ],
          "conflicts": []
        },
        "managementUrl": {
          "value": "/entity/vin",
          "merge": "value",
          "source": "catalogue",
          "sourceTitle": "Curated catalogue",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 70,
          "agreedBy": [
            "catalogue"
          ],
          "conflicts": []
        },
        "recovery": {
          "value": {
            "runbook": "docs/RECOVERY.md#rb-vin",
            "note": "Public edge and the node this console runs on. It is the authority for the catalogue itself."
          },
          "merge": "value",
          "source": "catalogue",
          "sourceTitle": "Curated catalogue",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 70,
          "agreedBy": [
            "catalogue"
          ],
          "conflicts": []
        }
      },
      "advisory": [],
      "sources": [],
      "conflicts": [],
      "redactions": 0
    },
    {
      "id": "entity:vps1",
      "name": "VPS1 / de-james-vps1",
      "kind": "node",
      "entityId": "vps1",
      "declared": false,
      "state": "unknown",
      "freshness": "missing",
      "lastSeenAt": null,
      "node": "vps1",
      "project": null,
      "domains": [],
      "expect": [],
      "note": null,
      "links": {
        "node": "vps1",
        "entity": "vps1",
        "project": null,
        "domains": [],
        "ingress": null,
        "auth": null,
        "healthCheck": null,
        "dependsOn": [],
        "managementUrl": "/entity/vps1",
        "recovery": null
      },
      "fields": {
        "kind": {
          "value": "node",
          "merge": "value",
          "source": "inventory",
          "sourceTitle": "Declared inventory",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 65,
          "agreedBy": [
            "inventory"
          ],
          "conflicts": []
        },
        "address": {
          "value": "de-james-vps1.tail99ba7.ts.net",
          "merge": "value",
          "source": "inventory",
          "sourceTitle": "Declared inventory",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 65,
          "agreedBy": [
            "inventory"
          ],
          "conflicts": []
        },
        "tier": {
          "value": "important",
          "merge": "value",
          "source": "inventory",
          "sourceTitle": "Declared inventory",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 65,
          "agreedBy": [
            "inventory"
          ],
          "conflicts": []
        },
        "description": {
          "value": "Second VPS, in a different provider region from VIN (Hetzner nbg1 against VIN's fsn1), running its own complete Coolify instance. Registered here because it is the estate's only second compute failure domain that has been proven to execute work. It is shared: another operator's watchdog agent has root on it, and it already terminates 13 public hostnames that are not this estate's. Nothing this estate depends on runs here yet.",
          "merge": "value",
          "source": "inventory",
          "sourceTitle": "Declared inventory",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 65,
          "agreedBy": [
            "inventory"
          ],
          "conflicts": []
        },
        "owner": {
          "value": "homelab-operator",
          "merge": "value",
          "source": "inventory",
          "sourceTitle": "Declared inventory",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 65,
          "agreedBy": [
            "inventory"
          ],
          "conflicts": []
        },
        "managementUrl": {
          "value": "/entity/vps1",
          "merge": "value",
          "source": "inventory",
          "sourceTitle": "Declared inventory",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 65,
          "agreedBy": [
            "inventory"
          ],
          "conflicts": []
        }
      },
      "advisory": [],
      "sources": [],
      "conflicts": [],
      "redactions": 0
    },
    {
      "id": "gwscli-s3-offsite",
      "name": "Offsite backup replica",
      "kind": "replica",
      "entityId": "gwscli-s3-offsite",
      "declared": true,
      "state": "declared-only",
      "freshness": "missing",
      "lastSeenAt": null,
      "node": "gwscli-s3",
      "project": "platform",
      "domains": [],
      "expect": [],
      "note": null,
      "links": {
        "node": "gwscli-s3",
        "entity": "gwscli-s3-offsite",
        "project": "platform",
        "domains": [],
        "ingress": null,
        "auth": null,
        "healthCheck": null,
        "dependsOn": [
          "gwscli-s3",
          "nas-backups",
          "isp-uplink"
        ],
        "managementUrl": "/entity/gwscli-s3-offsite",
        "recovery": {
          "runbook": "docs/RECOVERY.md#rb-gwscli-s3-offsite"
        }
      },
      "fields": {
        "kind": {
          "value": "replica",
          "merge": "value",
          "source": "catalogue",
          "sourceTitle": "Curated catalogue",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 70,
          "agreedBy": [
            "catalogue",
            "inventory"
          ],
          "conflicts": []
        },
        "node": {
          "value": "gwscli-s3",
          "merge": "value",
          "source": "catalogue",
          "sourceTitle": "Curated catalogue",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 70,
          "agreedBy": [
            "catalogue",
            "inventory"
          ],
          "conflicts": []
        },
        "dependsOn": {
          "value": [
            "gwscli-s3",
            "nas-backups",
            "isp-uplink"
          ],
          "merge": "union",
          "contributions": [
            {
              "value": "gwscli-s3",
              "sources": [
                "inventory"
              ]
            },
            {
              "value": "nas-backups",
              "sources": [
                "inventory"
              ]
            },
            {
              "value": "isp-uplink",
              "sources": [
                "inventory"
              ]
            }
          ],
          "source": "inventory",
          "sourceTitle": "Declared inventory",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 65,
          "agreedBy": [
            "inventory"
          ],
          "conflicts": []
        },
        "tier": {
          "value": "critical",
          "merge": "value",
          "source": "inventory",
          "sourceTitle": "Declared inventory",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 65,
          "agreedBy": [
            "inventory"
          ],
          "conflicts": []
        },
        "description": {
          "value": "Encrypted offsite copy of nas-backups. The only copy that survives loss of the home rack.",
          "merge": "value",
          "source": "inventory",
          "sourceTitle": "Declared inventory",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 65,
          "agreedBy": [
            "inventory"
          ],
          "conflicts": []
        },
        "owner": {
          "value": "homelab-operator",
          "merge": "value",
          "source": "inventory",
          "sourceTitle": "Declared inventory",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 65,
          "agreedBy": [
            "inventory"
          ],
          "conflicts": []
        },
        "managementUrl": {
          "value": "/entity/gwscli-s3-offsite",
          "merge": "value",
          "source": "inventory",
          "sourceTitle": "Declared inventory",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 65,
          "agreedBy": [
            "inventory"
          ],
          "conflicts": []
        },
        "project": {
          "value": "platform",
          "merge": "value",
          "source": "catalogue",
          "sourceTitle": "Curated catalogue",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 70,
          "agreedBy": [
            "catalogue"
          ],
          "conflicts": []
        },
        "recovery": {
          "value": {
            "runbook": "docs/RECOVERY.md#rb-gwscli-s3-offsite"
          },
          "merge": "value",
          "source": "catalogue",
          "sourceTitle": "Curated catalogue",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 70,
          "agreedBy": [
            "catalogue"
          ],
          "conflicts": []
        }
      },
      "advisory": [],
      "sources": [],
      "conflicts": [],
      "redactions": 0
    },
    {
      "id": "postgres-replica",
      "name": "Postgres (replica)",
      "kind": "replica",
      "entityId": "postgres-replica",
      "declared": true,
      "state": "declared-only",
      "freshness": "missing",
      "lastSeenAt": null,
      "node": "vin",
      "project": "platform",
      "domains": [],
      "expect": [
        "docker-vin",
        "systemd-vin"
      ],
      "note": null,
      "links": {
        "node": "vin",
        "entity": "postgres-replica",
        "project": "platform",
        "domains": [],
        "ingress": null,
        "auth": null,
        "healthCheck": {
          "type": "tcp",
          "ports": [
            5432
          ]
        },
        "dependsOn": [
          "vin",
          "wireguard-tunnel"
        ],
        "managementUrl": "/entity/postgres-replica",
        "recovery": {
          "runbook": "docs/RECOVERY.md#rb-postgres-replica"
        }
      },
      "fields": {
        "kind": {
          "value": "replica",
          "merge": "value",
          "source": "catalogue",
          "sourceTitle": "Curated catalogue",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 70,
          "agreedBy": [
            "catalogue",
            "inventory"
          ],
          "conflicts": []
        },
        "node": {
          "value": "vin",
          "merge": "value",
          "source": "catalogue",
          "sourceTitle": "Curated catalogue",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 70,
          "agreedBy": [
            "catalogue",
            "inventory"
          ],
          "conflicts": []
        },
        "dependsOn": {
          "value": [
            "vin",
            "wireguard-tunnel"
          ],
          "merge": "union",
          "contributions": [
            {
              "value": "vin",
              "sources": [
                "inventory"
              ]
            },
            {
              "value": "wireguard-tunnel",
              "sources": [
                "inventory"
              ]
            }
          ],
          "source": "inventory",
          "sourceTitle": "Declared inventory",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 65,
          "agreedBy": [
            "inventory"
          ],
          "conflicts": []
        },
        "tier": {
          "value": "critical",
          "merge": "value",
          "source": "inventory",
          "sourceTitle": "Declared inventory",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 65,
          "agreedBy": [
            "inventory"
          ],
          "conflicts": []
        },
        "description": {
          "value": "Streaming standby for postgres-primary. Also the read endpoint for reporting queries.",
          "merge": "value",
          "source": "inventory",
          "sourceTitle": "Declared inventory",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 65,
          "agreedBy": [
            "inventory"
          ],
          "conflicts": []
        },
        "owner": {
          "value": "homelab-operator",
          "merge": "value",
          "source": "inventory",
          "sourceTitle": "Declared inventory",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 65,
          "agreedBy": [
            "inventory"
          ],
          "conflicts": []
        },
        "managementUrl": {
          "value": "/entity/postgres-replica",
          "merge": "value",
          "source": "inventory",
          "sourceTitle": "Declared inventory",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 65,
          "agreedBy": [
            "inventory"
          ],
          "conflicts": []
        },
        "project": {
          "value": "platform",
          "merge": "value",
          "source": "catalogue",
          "sourceTitle": "Curated catalogue",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 70,
          "agreedBy": [
            "catalogue"
          ],
          "conflicts": []
        },
        "healthCheck": {
          "value": {
            "type": "tcp",
            "ports": [
              5432
            ]
          },
          "merge": "value",
          "source": "catalogue",
          "sourceTitle": "Curated catalogue",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 70,
          "agreedBy": [
            "catalogue"
          ],
          "conflicts": []
        },
        "recovery": {
          "value": {
            "runbook": "docs/RECOVERY.md#rb-postgres-replica"
          },
          "merge": "value",
          "source": "catalogue",
          "sourceTitle": "Curated catalogue",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 70,
          "agreedBy": [
            "catalogue"
          ],
          "conflicts": []
        }
      },
      "advisory": [],
      "sources": [],
      "conflicts": [],
      "redactions": 0
    },
    {
      "id": "caddy",
      "name": "Caddy (reverse proxy)",
      "kind": "service",
      "entityId": "caddy",
      "declared": true,
      "state": "declared-only",
      "freshness": "missing",
      "lastSeenAt": null,
      "node": "vin",
      "project": "edge",
      "domains": [],
      "expect": [
        "systemd-vin",
        "docker-vin",
        "caddy-vin"
      ],
      "note": null,
      "links": {
        "node": "vin",
        "entity": "caddy",
        "project": "edge",
        "domains": [],
        "ingress": null,
        "auth": null,
        "healthCheck": {
          "type": "tcp",
          "ports": [
            80,
            443
          ]
        },
        "dependsOn": [
          "vin",
          "cloudflare-dns"
        ],
        "managementUrl": "/entity/caddy",
        "recovery": {
          "runbook": "docs/RECOVERY.md#rb-caddy",
          "note": "Every published hostname terminates here. Nothing new is ever published without a route in this proxy."
        }
      },
      "fields": {
        "kind": {
          "value": "service",
          "merge": "value",
          "source": "catalogue",
          "sourceTitle": "Curated catalogue",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 70,
          "agreedBy": [
            "catalogue",
            "inventory"
          ],
          "conflicts": []
        },
        "node": {
          "value": "vin",
          "merge": "value",
          "source": "catalogue",
          "sourceTitle": "Curated catalogue",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 70,
          "agreedBy": [
            "catalogue",
            "inventory"
          ],
          "conflicts": []
        },
        "dependsOn": {
          "value": [
            "vin",
            "cloudflare-dns"
          ],
          "merge": "union",
          "contributions": [
            {
              "value": "vin",
              "sources": [
                "inventory"
              ]
            },
            {
              "value": "cloudflare-dns",
              "sources": [
                "inventory"
              ]
            }
          ],
          "source": "inventory",
          "sourceTitle": "Declared inventory",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 65,
          "agreedBy": [
            "inventory"
          ],
          "conflicts": []
        },
        "tier": {
          "value": "critical",
          "merge": "value",
          "source": "inventory",
          "sourceTitle": "Declared inventory",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 65,
          "agreedBy": [
            "inventory"
          ],
          "conflicts": []
        },
        "description": {
          "value": "TLS termination and public routing. Managed configuration — treated as read-only by JarvisOS tooling.",
          "merge": "value",
          "source": "inventory",
          "sourceTitle": "Declared inventory",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 65,
          "agreedBy": [
            "inventory"
          ],
          "conflicts": []
        },
        "owner": {
          "value": "homelab-operator",
          "merge": "value",
          "source": "catalogue",
          "sourceTitle": "Curated catalogue",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 70,
          "agreedBy": [
            "catalogue",
            "inventory"
          ],
          "conflicts": []
        },
        "project": {
          "value": "edge",
          "merge": "value",
          "source": "catalogue",
          "sourceTitle": "Curated catalogue",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 70,
          "agreedBy": [
            "catalogue"
          ],
          "conflicts": []
        },
        "healthCheck": {
          "value": {
            "type": "tcp",
            "ports": [
              80,
              443
            ]
          },
          "merge": "value",
          "source": "catalogue",
          "sourceTitle": "Curated catalogue",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 70,
          "agreedBy": [
            "catalogue"
          ],
          "conflicts": []
        },
        "managementUrl": {
          "value": "/entity/caddy",
          "merge": "value",
          "source": "catalogue",
          "sourceTitle": "Curated catalogue",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 70,
          "agreedBy": [
            "catalogue"
          ],
          "conflicts": []
        },
        "recovery": {
          "value": {
            "runbook": "docs/RECOVERY.md#rb-caddy",
            "note": "Every published hostname terminates here. Nothing new is ever published without a route in this proxy."
          },
          "merge": "value",
          "source": "catalogue",
          "sourceTitle": "Curated catalogue",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 70,
          "agreedBy": [
            "catalogue"
          ],
          "conflicts": []
        }
      },
      "advisory": [],
      "sources": [],
      "conflicts": [],
      "redactions": 0
    },
    {
      "id": "dockerd",
      "name": "Docker engine (VIN)",
      "kind": "service",
      "entityId": null,
      "declared": true,
      "state": "declared-only",
      "freshness": "missing",
      "lastSeenAt": null,
      "node": "vin",
      "project": "platform",
      "domains": [],
      "expect": [
        "systemd-vin"
      ],
      "note": null,
      "links": {
        "node": "vin",
        "entity": null,
        "project": "platform",
        "domains": [],
        "ingress": null,
        "auth": null,
        "healthCheck": null,
        "dependsOn": [],
        "managementUrl": null,
        "recovery": {
          "note": "Container runtime on VIN; docker-vin cannot collect anything if this is down."
        }
      },
      "fields": {
        "kind": {
          "value": "service",
          "merge": "value",
          "source": "catalogue",
          "sourceTitle": "Curated catalogue",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 70,
          "agreedBy": [
            "catalogue"
          ],
          "conflicts": []
        },
        "node": {
          "value": "vin",
          "merge": "value",
          "source": "catalogue",
          "sourceTitle": "Curated catalogue",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 70,
          "agreedBy": [
            "catalogue"
          ],
          "conflicts": []
        },
        "project": {
          "value": "platform",
          "merge": "value",
          "source": "catalogue",
          "sourceTitle": "Curated catalogue",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 70,
          "agreedBy": [
            "catalogue"
          ],
          "conflicts": []
        },
        "owner": {
          "value": "homelab-operator",
          "merge": "value",
          "source": "catalogue",
          "sourceTitle": "Curated catalogue",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 70,
          "agreedBy": [
            "catalogue"
          ],
          "conflicts": []
        },
        "recovery": {
          "value": {
            "note": "Container runtime on VIN; docker-vin cannot collect anything if this is down."
          },
          "merge": "value",
          "source": "catalogue",
          "sourceTitle": "Curated catalogue",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 70,
          "agreedBy": [
            "catalogue"
          ],
          "conflicts": []
        }
      },
      "advisory": [],
      "sources": [],
      "conflicts": [],
      "redactions": 0
    },
    {
      "id": "jarvis-mcp",
      "name": "JarvisMCP node agent",
      "kind": "service",
      "entityId": null,
      "declared": true,
      "state": "declared-only",
      "freshness": "missing",
      "lastSeenAt": null,
      "node": "vin",
      "project": "jarvisos",
      "domains": [],
      "expect": [
        "systemd-vin"
      ],
      "note": null,
      "links": {
        "node": "vin",
        "entity": null,
        "project": "jarvisos",
        "domains": [],
        "ingress": null,
        "auth": null,
        "healthCheck": null,
        "dependsOn": [],
        "managementUrl": null,
        "recovery": {
          "note": "MCP agent on VIN. Discovered by systemd; no availability class yet."
        }
      },
      "fields": {
        "kind": {
          "value": "service",
          "merge": "value",
          "source": "catalogue",
          "sourceTitle": "Curated catalogue",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 70,
          "agreedBy": [
            "catalogue"
          ],
          "conflicts": []
        },
        "node": {
          "value": "vin",
          "merge": "value",
          "source": "catalogue",
          "sourceTitle": "Curated catalogue",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 70,
          "agreedBy": [
            "catalogue"
          ],
          "conflicts": []
        },
        "project": {
          "value": "jarvisos",
          "merge": "value",
          "source": "catalogue",
          "sourceTitle": "Curated catalogue",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 70,
          "agreedBy": [
            "catalogue"
          ],
          "conflicts": []
        },
        "owner": {
          "value": "homelab-operator",
          "merge": "value",
          "source": "catalogue",
          "sourceTitle": "Curated catalogue",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 70,
          "agreedBy": [
            "catalogue"
          ],
          "conflicts": []
        },
        "recovery": {
          "value": {
            "note": "MCP agent on VIN. Discovered by systemd; no availability class yet."
          },
          "merge": "value",
          "source": "catalogue",
          "sourceTitle": "Curated catalogue",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 70,
          "agreedBy": [
            "catalogue"
          ],
          "conflicts": []
        }
      },
      "advisory": [],
      "sources": [],
      "conflicts": [],
      "redactions": 0
    },
    {
      "id": "jarvisos-control-plane",
      "name": "JarvisOS Control Plane",
      "kind": "service",
      "entityId": "jarvisos-control-plane",
      "declared": true,
      "state": "declared-only",
      "freshness": "missing",
      "lastSeenAt": null,
      "node": "home1",
      "project": "jarvisos",
      "domains": [],
      "expect": [
        "docker-home1"
      ],
      "note": null,
      "links": {
        "node": "home1",
        "entity": "jarvisos-control-plane",
        "project": "jarvisos",
        "domains": [],
        "ingress": null,
        "auth": {
          "provider": "jarvisos-auth",
          "entityId": "jarvisos-auth",
          "method": "session cookie issued by JarvisOS SSO",
          "secretName": "JARVISOS_SESSION_KEY",
          "location": "/etc/jarvisos/config.env on home1"
        },
        "healthCheck": {
          "type": "http",
          "path": "/api/v1/healthz",
          "expect": "200"
        },
        "dependsOn": [
          "home1",
          "postgres-primary",
          "jarvisos-auth"
        ],
        "managementUrl": "/entity/jarvisos-control-plane",
        "recovery": {
          "runbook": "docs/RECOVERY.md#rb-jarvisos-control-plane",
          "note": "Leader election and failover are in docs/CONTROL-PLANE-HA.md."
        }
      },
      "fields": {
        "kind": {
          "value": "service",
          "merge": "value",
          "source": "catalogue",
          "sourceTitle": "Curated catalogue",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 70,
          "agreedBy": [
            "catalogue",
            "inventory"
          ],
          "conflicts": []
        },
        "node": {
          "value": "home1",
          "merge": "value",
          "source": "catalogue",
          "sourceTitle": "Curated catalogue",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 70,
          "agreedBy": [
            "catalogue",
            "inventory"
          ],
          "conflicts": []
        },
        "dependsOn": {
          "value": [
            "home1",
            "postgres-primary",
            "jarvisos-auth"
          ],
          "merge": "union",
          "contributions": [
            {
              "value": "home1",
              "sources": [
                "inventory"
              ]
            },
            {
              "value": "postgres-primary",
              "sources": [
                "inventory"
              ]
            },
            {
              "value": "jarvisos-auth",
              "sources": [
                "inventory"
              ]
            }
          ],
          "source": "inventory",
          "sourceTitle": "Declared inventory",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 65,
          "agreedBy": [
            "inventory"
          ],
          "conflicts": []
        },
        "tier": {
          "value": "critical",
          "merge": "value",
          "source": "inventory",
          "sourceTitle": "Declared inventory",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 65,
          "agreedBy": [
            "inventory"
          ],
          "conflicts": []
        },
        "description": {
          "value": "Dispatches tasks to worker nodes and owns workspace state.",
          "merge": "value",
          "source": "inventory",
          "sourceTitle": "Declared inventory",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 65,
          "agreedBy": [
            "inventory"
          ],
          "conflicts": []
        },
        "owner": {
          "value": "homelab-operator",
          "merge": "value",
          "source": "catalogue",
          "sourceTitle": "Curated catalogue",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 70,
          "agreedBy": [
            "catalogue",
            "inventory"
          ],
          "conflicts": []
        },
        "project": {
          "value": "jarvisos",
          "merge": "value",
          "source": "catalogue",
          "sourceTitle": "Curated catalogue",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 70,
          "agreedBy": [
            "catalogue"
          ],
          "conflicts": []
        },
        "auth": {
          "value": {
            "provider": "jarvisos-auth",
            "entityId": "jarvisos-auth",
            "method": "session cookie issued by JarvisOS SSO",
            "secretName": "JARVISOS_SESSION_KEY",
            "location": "/etc/jarvisos/config.env on home1"
          },
          "merge": "value",
          "source": "catalogue",
          "sourceTitle": "Curated catalogue",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 70,
          "agreedBy": [
            "catalogue"
          ],
          "conflicts": []
        },
        "healthCheck": {
          "value": {
            "type": "http",
            "path": "/api/v1/healthz",
            "expect": "200"
          },
          "merge": "value",
          "source": "catalogue",
          "sourceTitle": "Curated catalogue",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 70,
          "agreedBy": [
            "catalogue"
          ],
          "conflicts": []
        },
        "managementUrl": {
          "value": "/entity/jarvisos-control-plane",
          "merge": "value",
          "source": "catalogue",
          "sourceTitle": "Curated catalogue",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 70,
          "agreedBy": [
            "catalogue"
          ],
          "conflicts": []
        },
        "recovery": {
          "value": {
            "runbook": "docs/RECOVERY.md#rb-jarvisos-control-plane",
            "note": "Leader election and failover are in docs/CONTROL-PLANE-HA.md."
          },
          "merge": "value",
          "source": "catalogue",
          "sourceTitle": "Curated catalogue",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 70,
          "agreedBy": [
            "catalogue"
          ],
          "conflicts": []
        }
      },
      "advisory": [],
      "sources": [],
      "conflicts": [],
      "redactions": 0
    },
    {
      "id": "jarvisos-web-proxy",
      "name": "JarvisOS Web Docker bridge proxy",
      "kind": "service",
      "entityId": null,
      "declared": true,
      "state": "declared-only",
      "freshness": "missing",
      "lastSeenAt": null,
      "node": "vin",
      "project": "jarvisos",
      "domains": [],
      "expect": [
        "systemd-vin"
      ],
      "note": null,
      "links": {
        "node": "vin",
        "entity": null,
        "project": "jarvisos",
        "domains": [],
        "ingress": null,
        "auth": null,
        "healthCheck": null,
        "dependsOn": [],
        "managementUrl": null,
        "recovery": {
          "note": "Bridges the web PWA to the Docker network. Discovered, not declared in the inventory."
        }
      },
      "fields": {
        "kind": {
          "value": "service",
          "merge": "value",
          "source": "catalogue",
          "sourceTitle": "Curated catalogue",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 70,
          "agreedBy": [
            "catalogue"
          ],
          "conflicts": []
        },
        "node": {
          "value": "vin",
          "merge": "value",
          "source": "catalogue",
          "sourceTitle": "Curated catalogue",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 70,
          "agreedBy": [
            "catalogue"
          ],
          "conflicts": []
        },
        "project": {
          "value": "jarvisos",
          "merge": "value",
          "source": "catalogue",
          "sourceTitle": "Curated catalogue",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 70,
          "agreedBy": [
            "catalogue"
          ],
          "conflicts": []
        },
        "owner": {
          "value": "homelab-operator",
          "merge": "value",
          "source": "catalogue",
          "sourceTitle": "Curated catalogue",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 70,
          "agreedBy": [
            "catalogue"
          ],
          "conflicts": []
        },
        "recovery": {
          "value": {
            "note": "Bridges the web PWA to the Docker network. Discovered, not declared in the inventory."
          },
          "merge": "value",
          "source": "catalogue",
          "sourceTitle": "Curated catalogue",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 70,
          "agreedBy": [
            "catalogue"
          ],
          "conflicts": []
        }
      },
      "advisory": [],
      "sources": [],
      "conflicts": [],
      "redactions": 0
    },
    {
      "id": "jarvisos-web",
      "name": "JarvisOS Web PWA",
      "kind": "service",
      "entityId": null,
      "declared": true,
      "state": "declared-only",
      "freshness": "missing",
      "lastSeenAt": null,
      "node": "vin",
      "project": "jarvisos",
      "domains": [],
      "expect": [
        "systemd-vin"
      ],
      "note": null,
      "links": {
        "node": "vin",
        "entity": null,
        "project": "jarvisos",
        "domains": [],
        "ingress": null,
        "auth": null,
        "healthCheck": null,
        "dependsOn": [],
        "managementUrl": null,
        "recovery": {
          "note": "Host service on VIN, not yet in the declared inventory. Discovered by systemd and tracked here so it has an owner and a project."
        }
      },
      "fields": {
        "kind": {
          "value": "service",
          "merge": "value",
          "source": "catalogue",
          "sourceTitle": "Curated catalogue",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 70,
          "agreedBy": [
            "catalogue"
          ],
          "conflicts": []
        },
        "node": {
          "value": "vin",
          "merge": "value",
          "source": "catalogue",
          "sourceTitle": "Curated catalogue",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 70,
          "agreedBy": [
            "catalogue"
          ],
          "conflicts": []
        },
        "project": {
          "value": "jarvisos",
          "merge": "value",
          "source": "catalogue",
          "sourceTitle": "Curated catalogue",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 70,
          "agreedBy": [
            "catalogue"
          ],
          "conflicts": []
        },
        "owner": {
          "value": "homelab-operator",
          "merge": "value",
          "source": "catalogue",
          "sourceTitle": "Curated catalogue",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 70,
          "agreedBy": [
            "catalogue"
          ],
          "conflicts": []
        },
        "recovery": {
          "value": {
            "note": "Host service on VIN, not yet in the declared inventory. Discovered by systemd and tracked here so it has an owner and a project."
          },
          "merge": "value",
          "source": "catalogue",
          "sourceTitle": "Curated catalogue",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 70,
          "agreedBy": [
            "catalogue"
          ],
          "conflicts": []
        }
      },
      "advisory": [],
      "sources": [],
      "conflicts": [],
      "redactions": 0
    },
    {
      "id": "jarvisos-worker",
      "name": "JarvisOS Worker (VIN)",
      "kind": "service",
      "entityId": "jarvisos-worker",
      "declared": true,
      "state": "declared-only",
      "freshness": "missing",
      "lastSeenAt": null,
      "node": "vin",
      "project": "jarvisos",
      "domains": [],
      "expect": [
        "systemd-vin",
        "docker-vin"
      ],
      "note": null,
      "links": {
        "node": "vin",
        "entity": "jarvisos-worker",
        "project": "jarvisos",
        "domains": [],
        "ingress": null,
        "auth": null,
        "healthCheck": {
          "type": "heartbeat",
          "maxAgeSec": 120
        },
        "dependsOn": [
          "vin",
          "jarvisos-control-plane"
        ],
        "managementUrl": "/entity/jarvisos-worker",
        "recovery": {
          "runbook": "docs/RECOVERY.md#rb-jarvisos-worker",
          "note": "Work is dispatched to it by the control plane; see docs/REMOTE-DISPATCH.md."
        }
      },
      "fields": {
        "kind": {
          "value": "service",
          "merge": "value",
          "source": "catalogue",
          "sourceTitle": "Curated catalogue",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 70,
          "agreedBy": [
            "catalogue",
            "inventory"
          ],
          "conflicts": []
        },
        "node": {
          "value": "vin",
          "merge": "value",
          "source": "catalogue",
          "sourceTitle": "Curated catalogue",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 70,
          "agreedBy": [
            "catalogue",
            "inventory"
          ],
          "conflicts": []
        },
        "dependsOn": {
          "value": [
            "vin",
            "jarvisos-control-plane"
          ],
          "merge": "union",
          "contributions": [
            {
              "value": "vin",
              "sources": [
                "inventory"
              ]
            },
            {
              "value": "jarvisos-control-plane",
              "sources": [
                "inventory"
              ]
            }
          ],
          "source": "inventory",
          "sourceTitle": "Declared inventory",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 65,
          "agreedBy": [
            "inventory"
          ],
          "conflicts": []
        },
        "tier": {
          "value": "important",
          "merge": "value",
          "source": "inventory",
          "sourceTitle": "Declared inventory",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 65,
          "agreedBy": [
            "inventory"
          ],
          "conflicts": []
        },
        "description": {
          "value": "Executes dispatched tasks in isolated workspaces on the edge node.",
          "merge": "value",
          "source": "inventory",
          "sourceTitle": "Declared inventory",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 65,
          "agreedBy": [
            "inventory"
          ],
          "conflicts": []
        },
        "owner": {
          "value": "homelab-operator",
          "merge": "value",
          "source": "catalogue",
          "sourceTitle": "Curated catalogue",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 70,
          "agreedBy": [
            "catalogue",
            "inventory"
          ],
          "conflicts": []
        },
        "project": {
          "value": "jarvisos",
          "merge": "value",
          "source": "catalogue",
          "sourceTitle": "Curated catalogue",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 70,
          "agreedBy": [
            "catalogue"
          ],
          "conflicts": []
        },
        "healthCheck": {
          "value": {
            "type": "heartbeat",
            "maxAgeSec": 120
          },
          "merge": "value",
          "source": "catalogue",
          "sourceTitle": "Curated catalogue",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 70,
          "agreedBy": [
            "catalogue"
          ],
          "conflicts": []
        },
        "managementUrl": {
          "value": "/entity/jarvisos-worker",
          "merge": "value",
          "source": "catalogue",
          "sourceTitle": "Curated catalogue",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 70,
          "agreedBy": [
            "catalogue"
          ],
          "conflicts": []
        },
        "recovery": {
          "value": {
            "runbook": "docs/RECOVERY.md#rb-jarvisos-worker",
            "note": "Work is dispatched to it by the control plane; see docs/REMOTE-DISPATCH.md."
          },
          "merge": "value",
          "source": "catalogue",
          "sourceTitle": "Curated catalogue",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 70,
          "agreedBy": [
            "catalogue"
          ],
          "conflicts": []
        }
      },
      "advisory": [],
      "sources": [],
      "conflicts": [],
      "redactions": 0
    },
    {
      "id": "tailscaled",
      "name": "Tailscale daemon (VIN)",
      "kind": "service",
      "entityId": null,
      "declared": true,
      "state": "declared-only",
      "freshness": "missing",
      "lastSeenAt": null,
      "node": "vin",
      "project": "platform",
      "domains": [],
      "expect": [
        "systemd-vin"
      ],
      "note": null,
      "links": {
        "node": "vin",
        "entity": null,
        "project": "platform",
        "domains": [],
        "ingress": null,
        "auth": null,
        "healthCheck": null,
        "dependsOn": [],
        "managementUrl": null,
        "recovery": {
          "note": "The mesh every other collector depends on to reach anything."
        }
      },
      "fields": {
        "kind": {
          "value": "service",
          "merge": "value",
          "source": "catalogue",
          "sourceTitle": "Curated catalogue",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 70,
          "agreedBy": [
            "catalogue"
          ],
          "conflicts": []
        },
        "node": {
          "value": "vin",
          "merge": "value",
          "source": "catalogue",
          "sourceTitle": "Curated catalogue",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 70,
          "agreedBy": [
            "catalogue"
          ],
          "conflicts": []
        },
        "project": {
          "value": "platform",
          "merge": "value",
          "source": "catalogue",
          "sourceTitle": "Curated catalogue",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 70,
          "agreedBy": [
            "catalogue"
          ],
          "conflicts": []
        },
        "owner": {
          "value": "homelab-operator",
          "merge": "value",
          "source": "catalogue",
          "sourceTitle": "Curated catalogue",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 70,
          "agreedBy": [
            "catalogue"
          ],
          "conflicts": []
        },
        "recovery": {
          "value": {
            "note": "The mesh every other collector depends on to reach anything."
          },
          "merge": "value",
          "source": "catalogue",
          "sourceTitle": "Curated catalogue",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 70,
          "agreedBy": [
            "catalogue"
          ],
          "conflicts": []
        }
      },
      "advisory": [],
      "sources": [],
      "conflicts": [],
      "redactions": 0
    },
    {
      "id": "nas-backups",
      "name": "NAS backup dataset",
      "kind": "storage",
      "entityId": "nas-backups",
      "declared": true,
      "state": "declared-only",
      "freshness": "missing",
      "lastSeenAt": null,
      "node": "nas",
      "project": "platform",
      "domains": [],
      "expect": [],
      "note": null,
      "links": {
        "node": "nas",
        "entity": "nas-backups",
        "project": "platform",
        "domains": [],
        "ingress": null,
        "auth": null,
        "healthCheck": null,
        "dependsOn": [
          "nas"
        ],
        "managementUrl": "/entity/nas-backups",
        "recovery": {
          "runbook": "docs/RECOVERY.md#rb-nas-backups"
        }
      },
      "fields": {
        "kind": {
          "value": "storage",
          "merge": "value",
          "source": "catalogue",
          "sourceTitle": "Curated catalogue",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 70,
          "agreedBy": [
            "catalogue",
            "inventory"
          ],
          "conflicts": []
        },
        "node": {
          "value": "nas",
          "merge": "value",
          "source": "catalogue",
          "sourceTitle": "Curated catalogue",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 70,
          "agreedBy": [
            "catalogue",
            "inventory"
          ],
          "conflicts": []
        },
        "dependsOn": {
          "value": [
            "nas"
          ],
          "merge": "union",
          "contributions": [
            {
              "value": "nas",
              "sources": [
                "inventory"
              ]
            }
          ],
          "source": "inventory",
          "sourceTitle": "Declared inventory",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 65,
          "agreedBy": [
            "inventory"
          ],
          "conflicts": []
        },
        "tier": {
          "value": "critical",
          "merge": "value",
          "source": "inventory",
          "sourceTitle": "Declared inventory",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 65,
          "agreedBy": [
            "inventory"
          ],
          "conflicts": []
        },
        "description": {
          "value": "On-site backup target for databases and configuration.",
          "merge": "value",
          "source": "inventory",
          "sourceTitle": "Declared inventory",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 65,
          "agreedBy": [
            "inventory"
          ],
          "conflicts": []
        },
        "owner": {
          "value": "homelab-operator",
          "merge": "value",
          "source": "inventory",
          "sourceTitle": "Declared inventory",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 65,
          "agreedBy": [
            "inventory"
          ],
          "conflicts": []
        },
        "managementUrl": {
          "value": "/entity/nas-backups",
          "merge": "value",
          "source": "inventory",
          "sourceTitle": "Declared inventory",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 65,
          "agreedBy": [
            "inventory"
          ],
          "conflicts": []
        },
        "project": {
          "value": "platform",
          "merge": "value",
          "source": "catalogue",
          "sourceTitle": "Curated catalogue",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 70,
          "agreedBy": [
            "catalogue"
          ],
          "conflicts": []
        },
        "recovery": {
          "value": {
            "runbook": "docs/RECOVERY.md#rb-nas-backups"
          },
          "merge": "value",
          "source": "catalogue",
          "sourceTitle": "Curated catalogue",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 70,
          "agreedBy": [
            "catalogue"
          ],
          "conflicts": []
        }
      },
      "advisory": [],
      "sources": [],
      "conflicts": [],
      "redactions": 0
    },
    {
      "id": "nas-media",
      "name": "NAS media dataset",
      "kind": "storage",
      "entityId": "nas-media",
      "declared": true,
      "state": "declared-only",
      "freshness": "missing",
      "lastSeenAt": null,
      "node": "nas",
      "project": "media",
      "domains": [],
      "expect": [],
      "note": null,
      "links": {
        "node": "nas",
        "entity": "nas-media",
        "project": "media",
        "domains": [],
        "ingress": null,
        "auth": null,
        "healthCheck": null,
        "dependsOn": [
          "nas"
        ],
        "managementUrl": "/entity/nas-media",
        "recovery": {
          "runbook": "docs/RECOVERY.md#rb-nas-media"
        }
      },
      "fields": {
        "kind": {
          "value": "storage",
          "merge": "value",
          "source": "catalogue",
          "sourceTitle": "Curated catalogue",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 70,
          "agreedBy": [
            "catalogue",
            "inventory"
          ],
          "conflicts": []
        },
        "node": {
          "value": "nas",
          "merge": "value",
          "source": "catalogue",
          "sourceTitle": "Curated catalogue",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 70,
          "agreedBy": [
            "catalogue",
            "inventory"
          ],
          "conflicts": []
        },
        "dependsOn": {
          "value": [
            "nas"
          ],
          "merge": "union",
          "contributions": [
            {
              "value": "nas",
              "sources": [
                "inventory"
              ]
            }
          ],
          "source": "inventory",
          "sourceTitle": "Declared inventory",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 65,
          "agreedBy": [
            "inventory"
          ],
          "conflicts": []
        },
        "tier": {
          "value": "standard",
          "merge": "value",
          "source": "inventory",
          "sourceTitle": "Declared inventory",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 65,
          "agreedBy": [
            "inventory"
          ],
          "conflicts": []
        },
        "description": {
          "value": "Bulk media. Large, replaceable, deliberately not offsited.",
          "merge": "value",
          "source": "inventory",
          "sourceTitle": "Declared inventory",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 65,
          "agreedBy": [
            "inventory"
          ],
          "conflicts": []
        },
        "owner": {
          "value": "homelab-operator",
          "merge": "value",
          "source": "inventory",
          "sourceTitle": "Declared inventory",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 65,
          "agreedBy": [
            "inventory"
          ],
          "conflicts": []
        },
        "managementUrl": {
          "value": "/entity/nas-media",
          "merge": "value",
          "source": "inventory",
          "sourceTitle": "Declared inventory",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 65,
          "agreedBy": [
            "inventory"
          ],
          "conflicts": []
        },
        "project": {
          "value": "media",
          "merge": "value",
          "source": "catalogue",
          "sourceTitle": "Curated catalogue",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 70,
          "agreedBy": [
            "catalogue"
          ],
          "conflicts": []
        },
        "recovery": {
          "value": {
            "runbook": "docs/RECOVERY.md#rb-nas-media"
          },
          "merge": "value",
          "source": "catalogue",
          "sourceTitle": "Curated catalogue",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 70,
          "agreedBy": [
            "catalogue"
          ],
          "conflicts": []
        }
      },
      "advisory": [],
      "sources": [],
      "conflicts": [],
      "redactions": 0
    },
    {
      "id": "jarvis-tunnel",
      "name": "Secure MCP tunnel",
      "kind": "tunnel",
      "entityId": null,
      "declared": true,
      "state": "declared-only",
      "freshness": "missing",
      "lastSeenAt": null,
      "node": "vin",
      "project": "jarvisos",
      "domains": [],
      "expect": [
        "systemd-vin"
      ],
      "note": null,
      "links": {
        "node": "vin",
        "entity": null,
        "project": "jarvisos",
        "domains": [],
        "ingress": null,
        "auth": null,
        "healthCheck": null,
        "dependsOn": [],
        "managementUrl": null,
        "recovery": {
          "note": "Outbound tunnel that publishes JarvisMCP. Discovered by systemd, declared nowhere else."
        }
      },
      "fields": {
        "kind": {
          "value": "tunnel",
          "merge": "value",
          "source": "catalogue",
          "sourceTitle": "Curated catalogue",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 70,
          "agreedBy": [
            "catalogue"
          ],
          "conflicts": []
        },
        "node": {
          "value": "vin",
          "merge": "value",
          "source": "catalogue",
          "sourceTitle": "Curated catalogue",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 70,
          "agreedBy": [
            "catalogue"
          ],
          "conflicts": []
        },
        "project": {
          "value": "jarvisos",
          "merge": "value",
          "source": "catalogue",
          "sourceTitle": "Curated catalogue",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 70,
          "agreedBy": [
            "catalogue"
          ],
          "conflicts": []
        },
        "owner": {
          "value": "homelab-operator",
          "merge": "value",
          "source": "catalogue",
          "sourceTitle": "Curated catalogue",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 70,
          "agreedBy": [
            "catalogue"
          ],
          "conflicts": []
        },
        "recovery": {
          "value": {
            "note": "Outbound tunnel that publishes JarvisMCP. Discovered by systemd, declared nowhere else."
          },
          "merge": "value",
          "source": "catalogue",
          "sourceTitle": "Curated catalogue",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 70,
          "agreedBy": [
            "catalogue"
          ],
          "conflicts": []
        }
      },
      "advisory": [],
      "sources": [],
      "conflicts": [],
      "redactions": 0
    },
    {
      "id": "wireguard-tunnel",
      "name": "WireGuard (Home1 <-> VIN)",
      "kind": "tunnel",
      "entityId": "wireguard-tunnel",
      "declared": true,
      "state": "declared-only",
      "freshness": "missing",
      "lastSeenAt": null,
      "node": "vin",
      "project": "platform",
      "domains": [],
      "expect": [
        "systemd-vin"
      ],
      "note": null,
      "links": {
        "node": "vin",
        "entity": "wireguard-tunnel",
        "project": "platform",
        "domains": [],
        "ingress": null,
        "auth": null,
        "healthCheck": null,
        "dependsOn": [
          "vin",
          "isp-uplink"
        ],
        "managementUrl": "/entity/wireguard-tunnel",
        "recovery": {
          "runbook": "docs/RECOVERY.md#rb-wireguard-tunnel",
          "note": "Keys live on each node and are never read by discovery."
        }
      },
      "fields": {
        "kind": {
          "value": "tunnel",
          "merge": "value",
          "source": "catalogue",
          "sourceTitle": "Curated catalogue",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 70,
          "agreedBy": [
            "catalogue",
            "inventory"
          ],
          "conflicts": []
        },
        "dependsOn": {
          "value": [
            "vin",
            "isp-uplink"
          ],
          "merge": "union",
          "contributions": [
            {
              "value": "vin",
              "sources": [
                "inventory"
              ]
            },
            {
              "value": "isp-uplink",
              "sources": [
                "inventory"
              ]
            }
          ],
          "source": "inventory",
          "sourceTitle": "Declared inventory",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 65,
          "agreedBy": [
            "inventory"
          ],
          "conflicts": []
        },
        "tier": {
          "value": "critical",
          "merge": "value",
          "source": "inventory",
          "sourceTitle": "Declared inventory",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 65,
          "agreedBy": [
            "inventory"
          ],
          "conflicts": []
        },
        "description": {
          "value": "Private link carrying replication, control plane traffic and agent heartbeats.",
          "merge": "value",
          "source": "inventory",
          "sourceTitle": "Declared inventory",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 65,
          "agreedBy": [
            "inventory"
          ],
          "conflicts": []
        },
        "owner": {
          "value": "homelab-operator",
          "merge": "value",
          "source": "inventory",
          "sourceTitle": "Declared inventory",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 65,
          "agreedBy": [
            "inventory"
          ],
          "conflicts": []
        },
        "managementUrl": {
          "value": "/entity/wireguard-tunnel",
          "merge": "value",
          "source": "inventory",
          "sourceTitle": "Declared inventory",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 65,
          "agreedBy": [
            "inventory"
          ],
          "conflicts": []
        },
        "node": {
          "value": "vin",
          "merge": "value",
          "source": "catalogue",
          "sourceTitle": "Curated catalogue",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 70,
          "agreedBy": [
            "catalogue"
          ],
          "conflicts": []
        },
        "project": {
          "value": "platform",
          "merge": "value",
          "source": "catalogue",
          "sourceTitle": "Curated catalogue",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 70,
          "agreedBy": [
            "catalogue"
          ],
          "conflicts": []
        },
        "recovery": {
          "value": {
            "runbook": "docs/RECOVERY.md#rb-wireguard-tunnel",
            "note": "Keys live on each node and are never read by discovery."
          },
          "merge": "value",
          "source": "catalogue",
          "sourceTitle": "Curated catalogue",
          "observedAt": null,
          "freshness": "fresh",
          "authority": 70,
          "agreedBy": [
            "catalogue"
          ],
          "conflicts": []
        }
      },
      "advisory": [],
      "sources": [],
      "conflicts": [],
      "redactions": 0
    }
  ],
  "conflicts": [],
  "findings": [
    {
      "severity": "warn",
      "code": "catalog-source-never-collected",
      "title": "Tailnet membership (VIN) has never been collected",
      "detail": "Nothing has run \"tailscale-vin\" on this host. Everything it would claim is absent from the catalogue rather than wrong — run `node scripts/jarvisos-discover.mjs collect --source tailscale-vin`.",
      "sourceId": "tailscale-vin"
    },
    {
      "severity": "warn",
      "code": "catalog-source-never-collected",
      "title": "Docker containers (VIN) has never been collected",
      "detail": "Nothing has run \"docker-vin\" on this host. Everything it would claim is absent from the catalogue rather than wrong — run `node scripts/jarvisos-discover.mjs collect --source docker-vin`.",
      "sourceId": "docker-vin"
    },
    {
      "severity": "warn",
      "code": "catalog-source-never-collected",
      "title": "systemd units (VIN) has never been collected",
      "detail": "Nothing has run \"systemd-vin\" on this host. Everything it would claim is absent from the catalogue rather than wrong — run `node scripts/jarvisos-discover.mjs collect --source systemd-vin`.",
      "sourceId": "systemd-vin"
    },
    {
      "severity": "warn",
      "code": "catalog-source-never-collected",
      "title": "Docker containers (home1) has never been collected",
      "detail": "Nothing has run \"docker-home1\" on this host. Everything it would claim is absent from the catalogue rather than wrong — run `node scripts/jarvisos-discover.mjs collect --source docker-home1`.",
      "sourceId": "docker-home1"
    },
    {
      "severity": "warn",
      "code": "catalog-source-never-collected",
      "title": "Caddy ingress (VIN) has never been collected",
      "detail": "Nothing has run \"caddy-vin\" on this host. Everything it would claim is absent from the catalogue rather than wrong — run `node scripts/jarvisos-discover.mjs collect --source caddy-vin`.",
      "sourceId": "caddy-vin"
    },
    {
      "severity": "warn",
      "code": "catalog-source-never-collected",
      "title": "Coolify applications has never been collected",
      "detail": "Nothing has run \"coolify\" on this host. Everything it would claim is absent from the catalogue rather than wrong — run `node scripts/jarvisos-discover.mjs collect --source coolify`.",
      "sourceId": "coolify"
    },
    {
      "severity": "warn",
      "code": "catalog-source-never-collected",
      "title": "Cloudflare DNS has never been collected",
      "detail": "Nothing has run \"cloudflare-dns\" on this host. Everything it would claim is absent from the catalogue rather than wrong — run `node scripts/jarvisos-discover.mjs collect --source cloudflare-dns`.",
      "sourceId": "cloudflare-dns"
    },
    {
      "severity": "warn",
      "code": "catalog-source-never-collected",
      "title": "JarvisOS health has never been collected",
      "detail": "Nothing has run \"jarvisos-status\" on this host. Everything it would claim is absent from the catalogue rather than wrong — run `node scripts/jarvisos-discover.mjs collect --source jarvisos-status`.",
      "sourceId": "jarvisos-status"
    },
    {
      "severity": "warn",
      "code": "catalog-source-never-collected",
      "title": "Home Assistant telemetry has never been collected",
      "detail": "Nothing has run \"home-assistant\" on this host. Everything it would claim is absent from the catalogue rather than wrong — run `node scripts/jarvisos-discover.mjs collect --source home-assistant`.",
      "sourceId": "home-assistant"
    },
    {
      "severity": "warn",
      "code": "catalog-unverified",
      "title": "JarvisOS Auth (SSO) cannot be verified right now",
      "detail": "The source(s) that would see it (systemd-vin, docker-vin) have not produced a usable reading, so \"missing\" cannot be distinguished from \"not looked at\".",
      "itemId": "jarvisos-auth"
    },
    {
      "severity": "warn",
      "code": "catalog-unverified",
      "title": "Postgres (primary) cannot be verified right now",
      "detail": "The source(s) that would see it (docker-home1) have not produced a usable reading, so \"missing\" cannot be distinguished from \"not looked at\".",
      "itemId": "postgres-primary"
    },
    {
      "severity": "warn",
      "code": "catalog-unverified",
      "title": "Redis (cache / queue) cannot be verified right now",
      "detail": "The source(s) that would see it (docker-home1) have not produced a usable reading, so \"missing\" cannot be distinguished from \"not looked at\".",
      "itemId": "redis"
    },
    {
      "severity": "warn",
      "code": "catalog-unverified",
      "title": "Internal DNS cannot be verified right now",
      "detail": "The source(s) that would see it (docker-home1) have not produced a usable reading, so \"missing\" cannot be distinguished from \"not looked at\".",
      "itemId": "internal-dns"
    },
    {
      "severity": "warn",
      "code": "catalog-unverified",
      "title": "Public DNS cannot be verified right now",
      "detail": "The source(s) that would see it (cloudflare-dns) have not produced a usable reading, so \"missing\" cannot be distinguished from \"not looked at\".",
      "itemId": "cloudflare-dns"
    },
    {
      "severity": "warn",
      "code": "catalog-unverified",
      "title": "Home1 cannot be verified right now",
      "detail": "The source(s) that would see it (tailscale-vin) have not produced a usable reading, so \"missing\" cannot be distinguished from \"not looked at\".",
      "itemId": "home1"
    },
    {
      "severity": "warn",
      "code": "catalog-unverified",
      "title": "VIN / VPS cannot be verified right now",
      "detail": "The source(s) that would see it (tailscale-vin) have not produced a usable reading, so \"missing\" cannot be distinguished from \"not looked at\".",
      "itemId": "vin"
    },
    {
      "severity": "warn",
      "code": "catalog-unverified",
      "title": "Postgres (replica) cannot be verified right now",
      "detail": "The source(s) that would see it (docker-vin, systemd-vin) have not produced a usable reading, so \"missing\" cannot be distinguished from \"not looked at\".",
      "itemId": "postgres-replica"
    },
    {
      "severity": "warn",
      "code": "catalog-unverified",
      "title": "Caddy (reverse proxy) cannot be verified right now",
      "detail": "The source(s) that would see it (systemd-vin, docker-vin, caddy-vin) have not produced a usable reading, so \"missing\" cannot be distinguished from \"not looked at\".",
      "itemId": "caddy"
    },
    {
      "severity": "warn",
      "code": "catalog-unverified",
      "title": "Docker engine (VIN) cannot be verified right now",
      "detail": "The source(s) that would see it (systemd-vin) have not produced a usable reading, so \"missing\" cannot be distinguished from \"not looked at\".",
      "itemId": "dockerd"
    },
    {
      "severity": "warn",
      "code": "catalog-unverified",
      "title": "JarvisMCP node agent cannot be verified right now",
      "detail": "The source(s) that would see it (systemd-vin) have not produced a usable reading, so \"missing\" cannot be distinguished from \"not looked at\".",
      "itemId": "jarvis-mcp"
    },
    {
      "severity": "warn",
      "code": "catalog-unverified",
      "title": "JarvisOS Control Plane cannot be verified right now",
      "detail": "The source(s) that would see it (docker-home1) have not produced a usable reading, so \"missing\" cannot be distinguished from \"not looked at\".",
      "itemId": "jarvisos-control-plane"
    },
    {
      "severity": "warn",
      "code": "catalog-unverified",
      "title": "JarvisOS Web Docker bridge proxy cannot be verified right now",
      "detail": "The source(s) that would see it (systemd-vin) have not produced a usable reading, so \"missing\" cannot be distinguished from \"not looked at\".",
      "itemId": "jarvisos-web-proxy"
    },
    {
      "severity": "warn",
      "code": "catalog-unverified",
      "title": "JarvisOS Web PWA cannot be verified right now",
      "detail": "The source(s) that would see it (systemd-vin) have not produced a usable reading, so \"missing\" cannot be distinguished from \"not looked at\".",
      "itemId": "jarvisos-web"
    },
    {
      "severity": "warn",
      "code": "catalog-unverified",
      "title": "JarvisOS Worker (VIN) cannot be verified right now",
      "detail": "The source(s) that would see it (systemd-vin, docker-vin) have not produced a usable reading, so \"missing\" cannot be distinguished from \"not looked at\".",
      "itemId": "jarvisos-worker"
    },
    {
      "severity": "warn",
      "code": "catalog-unverified",
      "title": "Tailscale daemon (VIN) cannot be verified right now",
      "detail": "The source(s) that would see it (systemd-vin) have not produced a usable reading, so \"missing\" cannot be distinguished from \"not looked at\".",
      "itemId": "tailscaled"
    },
    {
      "severity": "warn",
      "code": "catalog-unverified",
      "title": "Secure MCP tunnel cannot be verified right now",
      "detail": "The source(s) that would see it (systemd-vin) have not produced a usable reading, so \"missing\" cannot be distinguished from \"not looked at\".",
      "itemId": "jarvis-tunnel"
    },
    {
      "severity": "warn",
      "code": "catalog-unverified",
      "title": "WireGuard (Home1 <-> VIN) cannot be verified right now",
      "detail": "The source(s) that would see it (systemd-vin) have not produced a usable reading, so \"missing\" cannot be distinguished from \"not looked at\".",
      "itemId": "wireguard-tunnel"
    },
    {
      "severity": "info",
      "code": "catalog-uncovered",
      "title": "Google OAuth is declared but no collector covers it",
      "detail": "Nothing in the discovery contract claims to be able to see this item, so its absence proves nothing. Give it an \"expect\" source, or accept that it is tracked by declaration only.",
      "itemId": "google-oauth"
    },
    {
      "severity": "info",
      "code": "catalog-uncovered",
      "title": "ISP Uplink is declared but no collector covers it",
      "detail": "Nothing in the discovery contract claims to be able to see this item, so its absence proves nothing. Give it an \"expect\" source, or accept that it is tracked by declaration only.",
      "itemId": "isp-uplink"
    },
    {
      "severity": "info",
      "code": "catalog-uncovered",
      "title": "GWSCLI / S3 is declared but no collector covers it",
      "detail": "Nothing in the discovery contract claims to be able to see this item, so its absence proves nothing. Give it an \"expect\" source, or accept that it is tracked by declaration only.",
      "itemId": "gwscli-s3"
    },
    {
      "severity": "info",
      "code": "catalog-uncovered",
      "title": "NAS is declared but no collector covers it",
      "detail": "Nothing in the discovery contract claims to be able to see this item, so its absence proves nothing. Give it an \"expect\" source, or accept that it is tracked by declaration only.",
      "itemId": "nas"
    },
    {
      "severity": "info",
      "code": "catalog-uncovered",
      "title": "Offsite backup replica is declared but no collector covers it",
      "detail": "Nothing in the discovery contract claims to be able to see this item, so its absence proves nothing. Give it an \"expect\" source, or accept that it is tracked by declaration only.",
      "itemId": "gwscli-s3-offsite"
    },
    {
      "severity": "info",
      "code": "catalog-uncovered",
      "title": "NAS backup dataset is declared but no collector covers it",
      "detail": "Nothing in the discovery contract claims to be able to see this item, so its absence proves nothing. Give it an \"expect\" source, or accept that it is tracked by declaration only.",
      "itemId": "nas-backups"
    },
    {
      "severity": "info",
      "code": "catalog-uncovered",
      "title": "NAS media dataset is declared but no collector covers it",
      "detail": "Nothing in the discovery contract claims to be able to see this item, so its absence proves nothing. Give it an \"expect\" source, or accept that it is tracked by declaration only.",
      "itemId": "nas-media"
    }
  ],
  "source": "/app/config/discovery.json"
}